xref: /netbsd-src/bin/sh/var.c (revision fdecd6a253f999ae92b139670d9e15cc9df4497c)
1 /*	$NetBSD: var.c,v 1.19 1997/07/04 21:02:25 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Kenneth Almquist.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)var.c	8.3 (Berkeley) 5/4/95";
43 #else
44 __RCSID("$NetBSD: var.c,v 1.19 1997/07/04 21:02:25 christos Exp $");
45 #endif
46 #endif /* not lint */
47 
48 #include <unistd.h>
49 #include <stdlib.h>
50 
51 /*
52  * Shell variables.
53  */
54 
55 #include "shell.h"
56 #include "output.h"
57 #include "expand.h"
58 #include "nodes.h"	/* for other headers */
59 #include "eval.h"	/* defines cmdenviron */
60 #include "exec.h"
61 #include "syntax.h"
62 #include "options.h"
63 #include "mail.h"
64 #include "var.h"
65 #include "memalloc.h"
66 #include "error.h"
67 #include "mystring.h"
68 #include "parser.h"
69 #ifndef SMALL
70 #include "myhistedit.h"
71 #endif
72 
73 
74 #define VTABSIZE 39
75 
76 
77 struct varinit {
78 	struct var *var;
79 	int flags;
80 	char *text;
81 	void (*func) __P((const char *));
82 };
83 
84 
85 #if ATTY
86 struct var vatty;
87 #endif
88 #ifndef SMALL
89 struct var vhistsize;
90 struct var vterm;
91 #endif
92 struct var vifs;
93 struct var vmail;
94 struct var vmpath;
95 struct var vpath;
96 struct var vps1;
97 struct var vps2;
98 struct var vvers;
99 struct var voptind;
100 
101 const struct varinit varinit[] = {
102 #if ATTY
103 	{ &vatty,	VSTRFIXED|VTEXTFIXED|VUNSET,	"ATTY=",
104 	  NULL },
105 #endif
106 #ifndef SMALL
107 	{ &vhistsize,	VSTRFIXED|VTEXTFIXED|VUNSET,	"HISTSIZE=",
108 	  sethistsize },
109 #endif
110 	{ &vifs,	VSTRFIXED|VTEXTFIXED,		"IFS= \t\n",
111 	  NULL },
112 	{ &vmail,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAIL=",
113 	  NULL },
114 	{ &vmpath,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAILPATH=",
115 	  NULL },
116 	{ &vpath,	VSTRFIXED|VTEXTFIXED,		"PATH=/bin:/usr/bin",
117 	  changepath },
118 	/*
119 	 * vps1 depends on uid
120 	 */
121 	{ &vps2,	VSTRFIXED|VTEXTFIXED,		"PS2=> ",
122 	  NULL },
123 #ifndef SMALL
124 	{ &vterm,	VSTRFIXED|VTEXTFIXED|VUNSET,	"TERM=",
125 	  setterm },
126 #endif
127 	{ &voptind,	VSTRFIXED|VTEXTFIXED,		"OPTIND=1",
128 	  getoptsreset },
129 	{ NULL,	0,				NULL,
130 	  NULL }
131 };
132 
133 struct var *vartab[VTABSIZE];
134 
135 STATIC struct var **hashvar __P((char *));
136 STATIC int varequal __P((char *, char *));
137 
138 /*
139  * Initialize the varable symbol tables and import the environment
140  */
141 
142 #ifdef mkinit
143 INCLUDE "var.h"
144 INIT {
145 	char **envp;
146 	extern char **environ;
147 
148 	initvar();
149 	for (envp = environ ; *envp ; envp++) {
150 		if (strchr(*envp, '=')) {
151 			setvareq(*envp, VEXPORT|VTEXTFIXED);
152 		}
153 	}
154 }
155 #endif
156 
157 
158 /*
159  * This routine initializes the builtin variables.  It is called when the
160  * shell is initialized and again when a shell procedure is spawned.
161  */
162 
163 void
164 initvar() {
165 	const struct varinit *ip;
166 	struct var *vp;
167 	struct var **vpp;
168 
169 	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
170 		if ((vp->flags & VEXPORT) == 0) {
171 			vpp = hashvar(ip->text);
172 			vp->next = *vpp;
173 			*vpp = vp;
174 			vp->text = ip->text;
175 			vp->flags = ip->flags;
176 			vp->func = ip->func;
177 		}
178 	}
179 	/*
180 	 * PS1 depends on uid
181 	 */
182 	if ((vps1.flags & VEXPORT) == 0) {
183 		vpp = hashvar("PS1=");
184 		vps1.next = *vpp;
185 		*vpp = &vps1;
186 		vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
187 		vps1.flags = VSTRFIXED|VTEXTFIXED;
188 	}
189 }
190 
191 /*
192  * Safe version of setvar, returns 1 on success 0 on failure.
193  */
194 
195 int
196 setvarsafe(name, val, flags)
197 	char *name, *val;
198 	int flags;
199 {
200 	struct jmploc jmploc;
201 	struct jmploc *volatile savehandler = handler;
202 	int err = 0;
203 #ifdef __GNUC__
204 	(void) &err;
205 #endif
206 
207 	if (setjmp(jmploc.loc))
208 		err = 1;
209 	else {
210 		handler = &jmploc;
211 		setvar(name, val, flags);
212 	}
213 	handler = savehandler;
214 	return err;
215 }
216 
217 /*
218  * Set the value of a variable.  The flags argument is ored with the
219  * flags of the variable.  If val is NULL, the variable is unset.
220  */
221 
222 void
223 setvar(name, val, flags)
224 	char *name, *val;
225 	int flags;
226 {
227 	char *p, *q;
228 	int len;
229 	int namelen;
230 	char *nameeq;
231 	int isbad;
232 
233 	isbad = 0;
234 	p = name;
235 	if (! is_name(*p))
236 		isbad = 1;
237 	p++;
238 	for (;;) {
239 		if (! is_in_name(*p)) {
240 			if (*p == '\0' || *p == '=')
241 				break;
242 			isbad = 1;
243 		}
244 		p++;
245 	}
246 	namelen = p - name;
247 	if (isbad)
248 		error("%.*s: bad variable name", namelen, name);
249 	len = namelen + 2;		/* 2 is space for '=' and '\0' */
250 	if (val == NULL) {
251 		flags |= VUNSET;
252 	} else {
253 		len += strlen(val);
254 	}
255 	p = nameeq = ckmalloc(len);
256 	q = name;
257 	while (--namelen >= 0)
258 		*p++ = *q++;
259 	*p++ = '=';
260 	*p = '\0';
261 	if (val)
262 		scopy(val, p);
263 	setvareq(nameeq, flags);
264 }
265 
266 
267 
268 /*
269  * Same as setvar except that the variable and value are passed in
270  * the first argument as name=value.  Since the first argument will
271  * be actually stored in the table, it should not be a string that
272  * will go away.
273  */
274 
275 void
276 setvareq(s, flags)
277 	char *s;
278 	int flags;
279 {
280 	struct var *vp, **vpp;
281 
282 	vpp = hashvar(s);
283 	for (vp = *vpp ; vp ; vp = vp->next) {
284 		if (varequal(s, vp->text)) {
285 			if (vp->flags & VREADONLY) {
286 				size_t len = strchr(s, '=') - s;
287 				error("%.*s: is read only", len, s);
288 			}
289 			INTOFF;
290 
291 			if (vp->func && (flags & VNOFUNC) == 0)
292 				(*vp->func)(strchr(s, '=') + 1);
293 
294 			if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
295 				ckfree(vp->text);
296 
297 			vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
298 			vp->flags |= flags;
299 			vp->text = s;
300 
301 			/*
302 			 * We could roll this to a function, to handle it as
303 			 * a regular variable function callback, but why bother?
304 			 */
305 			if (vp == &vmpath || (vp == &vmail && ! mpathset()))
306 				chkmail(1);
307 			INTON;
308 			return;
309 		}
310 	}
311 	/* not found */
312 	vp = ckmalloc(sizeof (*vp));
313 	vp->flags = flags;
314 	vp->text = s;
315 	vp->next = *vpp;
316 	vp->func = NULL;
317 	*vpp = vp;
318 }
319 
320 
321 
322 /*
323  * Process a linked list of variable assignments.
324  */
325 
326 void
327 listsetvar(list)
328 	struct strlist *list;
329 	{
330 	struct strlist *lp;
331 
332 	INTOFF;
333 	for (lp = list ; lp ; lp = lp->next) {
334 		setvareq(savestr(lp->text), 0);
335 	}
336 	INTON;
337 }
338 
339 
340 
341 /*
342  * Find the value of a variable.  Returns NULL if not set.
343  */
344 
345 char *
346 lookupvar(name)
347 	char *name;
348 	{
349 	struct var *v;
350 
351 	for (v = *hashvar(name) ; v ; v = v->next) {
352 		if (varequal(v->text, name)) {
353 			if (v->flags & VUNSET)
354 				return NULL;
355 			return strchr(v->text, '=') + 1;
356 		}
357 	}
358 	return NULL;
359 }
360 
361 
362 
363 /*
364  * Search the environment of a builtin command.  If the second argument
365  * is nonzero, return the value of a variable even if it hasn't been
366  * exported.
367  */
368 
369 char *
370 bltinlookup(name, doall)
371 	char *name;
372 	int doall;
373 {
374 	struct strlist *sp;
375 	struct var *v;
376 
377 	for (sp = cmdenviron ; sp ; sp = sp->next) {
378 		if (varequal(sp->text, name))
379 			return strchr(sp->text, '=') + 1;
380 	}
381 	for (v = *hashvar(name) ; v ; v = v->next) {
382 		if (varequal(v->text, name)) {
383 			if ((v->flags & VUNSET)
384 			 || (!doall && (v->flags & VEXPORT) == 0))
385 				return NULL;
386 			return strchr(v->text, '=') + 1;
387 		}
388 	}
389 	return NULL;
390 }
391 
392 
393 
394 /*
395  * Generate a list of exported variables.  This routine is used to construct
396  * the third argument to execve when executing a program.
397  */
398 
399 char **
400 environment() {
401 	int nenv;
402 	struct var **vpp;
403 	struct var *vp;
404 	char **env, **ep;
405 
406 	nenv = 0;
407 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
408 		for (vp = *vpp ; vp ; vp = vp->next)
409 			if (vp->flags & VEXPORT)
410 				nenv++;
411 	}
412 	ep = env = stalloc((nenv + 1) * sizeof *env);
413 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
414 		for (vp = *vpp ; vp ; vp = vp->next)
415 			if (vp->flags & VEXPORT)
416 				*ep++ = vp->text;
417 	}
418 	*ep = NULL;
419 	return env;
420 }
421 
422 
423 /*
424  * Called when a shell procedure is invoked to clear out nonexported
425  * variables.  It is also necessary to reallocate variables of with
426  * VSTACK set since these are currently allocated on the stack.
427  */
428 
429 #ifdef mkinit
430 MKINIT void shprocvar __P((void));
431 
432 SHELLPROC {
433 	shprocvar();
434 }
435 #endif
436 
437 void
438 shprocvar() {
439 	struct var **vpp;
440 	struct var *vp, **prev;
441 
442 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
443 		for (prev = vpp ; (vp = *prev) != NULL ; ) {
444 			if ((vp->flags & VEXPORT) == 0) {
445 				*prev = vp->next;
446 				if ((vp->flags & VTEXTFIXED) == 0)
447 					ckfree(vp->text);
448 				if ((vp->flags & VSTRFIXED) == 0)
449 					ckfree(vp);
450 			} else {
451 				if (vp->flags & VSTACK) {
452 					vp->text = savestr(vp->text);
453 					vp->flags &=~ VSTACK;
454 				}
455 				prev = &vp->next;
456 			}
457 		}
458 	}
459 	initvar();
460 }
461 
462 
463 
464 /*
465  * Command to list all variables which are set.  Currently this command
466  * is invoked from the set command when the set command is called without
467  * any variables.
468  */
469 
470 int
471 showvarscmd(argc, argv)
472 	int argc;
473 	char **argv;
474 {
475 	struct var **vpp;
476 	struct var *vp;
477 
478 	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
479 		for (vp = *vpp ; vp ; vp = vp->next) {
480 			if ((vp->flags & VUNSET) == 0)
481 				out1fmt("%s\n", vp->text);
482 		}
483 	}
484 	return 0;
485 }
486 
487 
488 
489 /*
490  * The export and readonly commands.
491  */
492 
493 int
494 exportcmd(argc, argv)
495 	int argc;
496 	char **argv;
497 {
498 	struct var **vpp;
499 	struct var *vp;
500 	char *name;
501 	char *p;
502 	int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
503 
504 	listsetvar(cmdenviron);
505 	if (argc > 1) {
506 		while ((name = *argptr++) != NULL) {
507 			if ((p = strchr(name, '=')) != NULL) {
508 				p++;
509 			} else {
510 				vpp = hashvar(name);
511 				for (vp = *vpp ; vp ; vp = vp->next) {
512 					if (varequal(vp->text, name)) {
513 						vp->flags |= flag;
514 						goto found;
515 					}
516 				}
517 			}
518 			setvar(name, p, flag);
519 found:;
520 		}
521 	} else {
522 		for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
523 			for (vp = *vpp ; vp ; vp = vp->next) {
524 				if (vp->flags & flag) {
525 					for (p = vp->text ; *p != '=' ; p++)
526 						out1c(*p);
527 					out1c('\n');
528 				}
529 			}
530 		}
531 	}
532 	return 0;
533 }
534 
535 
536 /*
537  * The "local" command.
538  */
539 
540 int
541 localcmd(argc, argv)
542 	int argc;
543 	char **argv;
544 {
545 	char *name;
546 
547 	if (! in_function())
548 		error("Not in a function");
549 	while ((name = *argptr++) != NULL) {
550 		mklocal(name);
551 	}
552 	return 0;
553 }
554 
555 
556 /*
557  * Make a variable a local variable.  When a variable is made local, it's
558  * value and flags are saved in a localvar structure.  The saved values
559  * will be restored when the shell function returns.  We handle the name
560  * "-" as a special case.
561  */
562 
563 void
564 mklocal(name)
565 	char *name;
566 	{
567 	struct localvar *lvp;
568 	struct var **vpp;
569 	struct var *vp;
570 
571 	INTOFF;
572 	lvp = ckmalloc(sizeof (struct localvar));
573 	if (name[0] == '-' && name[1] == '\0') {
574 		lvp->text = ckmalloc(sizeof optlist);
575 		memcpy(lvp->text, optlist, sizeof optlist);
576 		vp = NULL;
577 	} else {
578 		vpp = hashvar(name);
579 		for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
580 		if (vp == NULL) {
581 			if (strchr(name, '='))
582 				setvareq(savestr(name), VSTRFIXED);
583 			else
584 				setvar(name, NULL, VSTRFIXED);
585 			vp = *vpp;	/* the new variable */
586 			lvp->text = NULL;
587 			lvp->flags = VUNSET;
588 		} else {
589 			lvp->text = vp->text;
590 			lvp->flags = vp->flags;
591 			vp->flags |= VSTRFIXED|VTEXTFIXED;
592 			if (strchr(name, '='))
593 				setvareq(savestr(name), 0);
594 		}
595 	}
596 	lvp->vp = vp;
597 	lvp->next = localvars;
598 	localvars = lvp;
599 	INTON;
600 }
601 
602 
603 /*
604  * Called after a function returns.
605  */
606 
607 void
608 poplocalvars() {
609 	struct localvar *lvp;
610 	struct var *vp;
611 
612 	while ((lvp = localvars) != NULL) {
613 		localvars = lvp->next;
614 		vp = lvp->vp;
615 		if (vp == NULL) {	/* $- saved */
616 			memcpy(optlist, lvp->text, sizeof optlist);
617 			ckfree(lvp->text);
618 		} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
619 			(void)unsetvar(vp->text);
620 		} else {
621 			if ((vp->flags & VTEXTFIXED) == 0)
622 				ckfree(vp->text);
623 			vp->flags = lvp->flags;
624 			vp->text = lvp->text;
625 		}
626 		ckfree(lvp);
627 	}
628 }
629 
630 
631 int
632 setvarcmd(argc, argv)
633 	int argc;
634 	char **argv;
635 {
636 	if (argc <= 2)
637 		return unsetcmd(argc, argv);
638 	else if (argc == 3)
639 		setvar(argv[1], argv[2], 0);
640 	else
641 		error("List assignment not implemented");
642 	return 0;
643 }
644 
645 
646 /*
647  * The unset builtin command.  We unset the function before we unset the
648  * variable to allow a function to be unset when there is a readonly variable
649  * with the same name.
650  */
651 
652 int
653 unsetcmd(argc, argv)
654 	int argc;
655 	char **argv;
656 {
657 	char **ap;
658 	int i;
659 	int flg_func = 0;
660 	int flg_var = 0;
661 	int ret = 0;
662 
663 	while ((i = nextopt("vf")) != '\0') {
664 		if (i == 'f')
665 			flg_func = 1;
666 		else
667 			flg_var = 1;
668 	}
669 	if (flg_func == 0 && flg_var == 0)
670 		flg_var = 1;
671 
672 	for (ap = argptr; *ap ; ap++) {
673 		if (flg_func)
674 			ret |= unsetfunc(*ap);
675 		if (flg_var)
676 			ret |= unsetvar(*ap);
677 	}
678 	return ret;
679 }
680 
681 
682 /*
683  * Unset the specified variable.
684  */
685 
686 int
687 unsetvar(s)
688 	char *s;
689 	{
690 	struct var **vpp;
691 	struct var *vp;
692 
693 	vpp = hashvar(s);
694 	for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
695 		if (varequal(vp->text, s)) {
696 			if (vp->flags & VREADONLY)
697 				return (1);
698 			INTOFF;
699 			if (*(strchr(vp->text, '=') + 1) != '\0')
700 				setvar(s, nullstr, 0);
701 			vp->flags &= ~VEXPORT;
702 			vp->flags |= VUNSET;
703 			if ((vp->flags & VSTRFIXED) == 0) {
704 				if ((vp->flags & VTEXTFIXED) == 0)
705 					ckfree(vp->text);
706 				*vpp = vp->next;
707 				ckfree(vp);
708 			}
709 			INTON;
710 			return (0);
711 		}
712 	}
713 
714 	return (1);
715 }
716 
717 
718 
719 /*
720  * Find the appropriate entry in the hash table from the name.
721  */
722 
723 STATIC struct var **
724 hashvar(p)
725 	char *p;
726 	{
727 	unsigned int hashval;
728 
729 	hashval = ((unsigned char) *p) << 4;
730 	while (*p && *p != '=')
731 		hashval += (unsigned char) *p++;
732 	return &vartab[hashval % VTABSIZE];
733 }
734 
735 
736 
737 /*
738  * Returns true if the two strings specify the same varable.  The first
739  * variable name is terminated by '='; the second may be terminated by
740  * either '=' or '\0'.
741  */
742 
743 STATIC int
744 varequal(p, q)
745 	char *p, *q;
746 	{
747 	while (*p == *q++) {
748 		if (*p++ == '=')
749 			return 1;
750 	}
751 	if (*p == '=' && *(q - 1) == '\0')
752 		return 1;
753 	return 0;
754 }
755