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