var.c revision 8855
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.2 1994/09/24 02:58:22 davidg Exp $
37 */
38
39#ifndef lint
40static char sccsid[] = "@(#)var.c	8.1 (Berkeley) 5/31/93";
41#endif /* not lint */
42
43/*
44 * Shell variables.
45 */
46
47#include "shell.h"
48#include "output.h"
49#include "expand.h"
50#include "nodes.h"	/* for other headers */
51#include "eval.h"	/* defines cmdenviron */
52#include "exec.h"
53#include "syntax.h"
54#include "options.h"
55#include "mail.h"
56#include "var.h"
57#include "memalloc.h"
58#include "error.h"
59#include "mystring.h"
60
61
62#define VTABSIZE 39
63
64
65struct varinit {
66	struct var *var;
67	int flags;
68	char *text;
69};
70
71
72#if ATTY
73struct var vatty;
74#endif
75struct var vhistsize;
76struct var vifs;
77struct var vmail;
78struct var vmpath;
79struct var vpath;
80struct var vps1;
81struct var vps2;
82struct var vvers;
83#if ATTY
84struct var vterm;
85#endif
86
87const struct varinit varinit[] = {
88#if ATTY
89	{&vatty,	VSTRFIXED|VTEXTFIXED|VUNSET,	"ATTY="},
90#endif
91	{&vhistsize,	VSTRFIXED|VTEXTFIXED|VUNSET,	"HISTSIZE="},
92	{&vifs,	VSTRFIXED|VTEXTFIXED,		"IFS= \t\n"},
93	{&vmail,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAIL="},
94	{&vmpath,	VSTRFIXED|VTEXTFIXED|VUNSET,	"MAILPATH="},
95	{&vpath,	VSTRFIXED|VTEXTFIXED,		"PATH=:/bin:/usr/bin"},
96	/*
97	 * vps1 depends on uid
98	 */
99	{&vps2,	VSTRFIXED|VTEXTFIXED,		"PS2=> "},
100#if ATTY
101	{&vterm,	VSTRFIXED|VTEXTFIXED|VUNSET,	"TERM="},
102#endif
103	{NULL,	0,				NULL}
104};
105
106struct var *vartab[VTABSIZE];
107
108STATIC int unsetvar __P((char *));
109STATIC struct var **hashvar __P((char *));
110STATIC int varequal __P((char *, char *));
111
112/*
113 * Initialize the varable symbol tables and import the environment
114 */
115
116#ifdef mkinit
117INCLUDE "var.h"
118INIT {
119	char **envp;
120	extern char **environ;
121
122	initvar();
123	for (envp = environ ; *envp ; envp++) {
124		if (strchr(*envp, '=')) {
125			setvareq(*envp, VEXPORT|VTEXTFIXED);
126		}
127	}
128}
129#endif
130
131
132/*
133 * This routine initializes the builtin variables.  It is called when the
134 * shell is initialized and again when a shell procedure is spawned.
135 */
136
137void
138initvar() {
139	const struct varinit *ip;
140	struct var *vp;
141	struct var **vpp;
142
143	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
144		if ((vp->flags & VEXPORT) == 0) {
145			vpp = hashvar(ip->text);
146			vp->next = *vpp;
147			*vpp = vp;
148			vp->text = ip->text;
149			vp->flags = ip->flags;
150		}
151	}
152	/*
153	 * PS1 depends on uid
154	 */
155	if ((vps1.flags & VEXPORT) == 0) {
156		vpp = hashvar("PS1=");
157		vps1.next = *vpp;
158		*vpp = &vps1;
159		vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
160		vps1.flags = VSTRFIXED|VTEXTFIXED;
161	}
162}
163
164/*
165 * Set the value of a variable.  The flags argument is ored with the
166 * flags of the variable.  If val is NULL, the variable is unset.
167 */
168
169void
170setvar(name, val, flags)
171	char *name, *val;
172	{
173	char *p, *q;
174	int len;
175	int namelen;
176	char *nameeq;
177	int isbad;
178
179	isbad = 0;
180	p = name;
181	if (! is_name(*p++))
182		isbad = 1;
183	for (;;) {
184		if (! is_in_name(*p)) {
185			if (*p == '\0' || *p == '=')
186				break;
187			isbad = 1;
188		}
189		p++;
190	}
191	namelen = p - name;
192	if (isbad)
193		error("%.*s: bad variable name", namelen, name);
194	len = namelen + 2;		/* 2 is space for '=' and '\0' */
195	if (val == NULL) {
196		flags |= VUNSET;
197	} else {
198		len += strlen(val);
199	}
200	p = nameeq = ckmalloc(len);
201	q = name;
202	while (--namelen >= 0)
203		*p++ = *q++;
204	*p++ = '=';
205	*p = '\0';
206	if (val)
207		scopy(val, p);
208	setvareq(nameeq, flags);
209}
210
211
212
213/*
214 * Same as setvar except that the variable and value are passed in
215 * the first argument as name=value.  Since the first argument will
216 * be actually stored in the table, it should not be a string that
217 * will go away.
218 */
219
220void
221setvareq(s, flags)
222	char *s;
223	{
224	struct var *vp, **vpp;
225
226	vpp = hashvar(s);
227	for (vp = *vpp ; vp ; vp = vp->next) {
228		if (varequal(s, vp->text)) {
229			if (vp->flags & VREADONLY) {
230				int len = strchr(s, '=') - s;
231				error("%.*s: is read only", len, s);
232			}
233			INTOFF;
234			if (vp == &vpath)
235				changepath(s + 5);	/* 5 = strlen("PATH=") */
236			if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
237				ckfree(vp->text);
238			vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET);
239			vp->flags |= flags;
240			vp->text = s;
241			if (vp == &vmpath || (vp == &vmail && ! mpathset()))
242				chkmail(1);
243			if (vp == &vhistsize)
244				sethistsize();
245			INTON;
246			return;
247		}
248	}
249	/* not found */
250	vp = ckmalloc(sizeof (*vp));
251	vp->flags = flags;
252	vp->text = s;
253	vp->next = *vpp;
254	*vpp = vp;
255}
256
257
258
259/*
260 * Process a linked list of variable assignments.
261 */
262
263void
264listsetvar(list)
265	struct strlist *list;
266	{
267	struct strlist *lp;
268
269	INTOFF;
270	for (lp = list ; lp ; lp = lp->next) {
271		setvareq(savestr(lp->text), 0);
272	}
273	INTON;
274}
275
276
277
278/*
279 * Find the value of a variable.  Returns NULL if not set.
280 */
281
282char *
283lookupvar(name)
284	char *name;
285	{
286	struct var *v;
287
288	for (v = *hashvar(name) ; v ; v = v->next) {
289		if (varequal(v->text, name)) {
290			if (v->flags & VUNSET)
291				return NULL;
292			return strchr(v->text, '=') + 1;
293		}
294	}
295	return NULL;
296}
297
298
299
300/*
301 * Search the environment of a builtin command.  If the second argument
302 * is nonzero, return the value of a variable even if it hasn't been
303 * exported.
304 */
305
306char *
307bltinlookup(name, doall)
308	char *name;
309	{
310	struct strlist *sp;
311	struct var *v;
312
313	for (sp = cmdenviron ; sp ; sp = sp->next) {
314		if (varequal(sp->text, name))
315			return strchr(sp->text, '=') + 1;
316	}
317	for (v = *hashvar(name) ; v ; v = v->next) {
318		if (varequal(v->text, name)) {
319			if (v->flags & VUNSET
320			 || ! doall && (v->flags & VEXPORT) == 0)
321				return NULL;
322			return strchr(v->text, '=') + 1;
323		}
324	}
325	return NULL;
326}
327
328
329
330/*
331 * Generate a list of exported variables.  This routine is used to construct
332 * the third argument to execve when executing a program.
333 */
334
335char **
336environment() {
337	int nenv;
338	struct var **vpp;
339	struct var *vp;
340	char **env, **ep;
341
342	nenv = 0;
343	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
344		for (vp = *vpp ; vp ; vp = vp->next)
345			if (vp->flags & VEXPORT)
346				nenv++;
347	}
348	ep = env = stalloc((nenv + 1) * sizeof *env);
349	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
350		for (vp = *vpp ; vp ; vp = vp->next)
351			if (vp->flags & VEXPORT)
352				*ep++ = vp->text;
353	}
354	*ep = NULL;
355	return env;
356}
357
358
359/*
360 * Called when a shell procedure is invoked to clear out nonexported
361 * variables.  It is also necessary to reallocate variables of with
362 * VSTACK set since these are currently allocated on the stack.
363 */
364
365#ifdef mkinit
366MKINIT void shprocvar();
367
368SHELLPROC {
369	shprocvar();
370}
371#endif
372
373void
374shprocvar() {
375	struct var **vpp;
376	struct var *vp, **prev;
377
378	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
379		for (prev = vpp ; (vp = *prev) != NULL ; ) {
380			if ((vp->flags & VEXPORT) == 0) {
381				*prev = vp->next;
382				if ((vp->flags & VTEXTFIXED) == 0)
383					ckfree(vp->text);
384				if ((vp->flags & VSTRFIXED) == 0)
385					ckfree(vp);
386			} else {
387				if (vp->flags & VSTACK) {
388					vp->text = savestr(vp->text);
389					vp->flags &=~ VSTACK;
390				}
391				prev = &vp->next;
392			}
393		}
394	}
395	initvar();
396}
397
398
399
400/*
401 * Command to list all variables which are set.  Currently this command
402 * is invoked from the set command when the set command is called without
403 * any variables.
404 */
405
406int
407showvarscmd(argc, argv)  char **argv; {
408	struct var **vpp;
409	struct var *vp;
410
411	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
412		for (vp = *vpp ; vp ; vp = vp->next) {
413			if ((vp->flags & VUNSET) == 0)
414				out1fmt("%s\n", vp->text);
415		}
416	}
417	return 0;
418}
419
420
421
422/*
423 * The export and readonly commands.
424 */
425
426int
427exportcmd(argc, argv)  char **argv; {
428	struct var **vpp;
429	struct var *vp;
430	char *name;
431	char *p;
432	int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
433
434	listsetvar(cmdenviron);
435	if (argc > 1) {
436		while ((name = *argptr++) != NULL) {
437			if ((p = strchr(name, '=')) != NULL) {
438				p++;
439			} else {
440				vpp = hashvar(name);
441				for (vp = *vpp ; vp ; vp = vp->next) {
442					if (varequal(vp->text, name)) {
443						vp->flags |= flag;
444						goto found;
445					}
446				}
447			}
448			setvar(name, p, flag);
449found:;
450		}
451	} else {
452		for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
453			for (vp = *vpp ; vp ; vp = vp->next) {
454				if (vp->flags & flag) {
455					for (p = vp->text ; *p != '=' ; p++)
456						out1c(*p);
457					out1c('\n');
458				}
459			}
460		}
461	}
462	return 0;
463}
464
465
466/*
467 * The "local" command.
468 */
469
470localcmd(argc, argv)  char **argv; {
471	char *name;
472
473	if (! in_function())
474		error("Not in a function");
475	while ((name = *argptr++) != NULL) {
476		mklocal(name);
477	}
478	return 0;
479}
480
481
482/*
483 * Make a variable a local variable.  When a variable is made local, it's
484 * value and flags are saved in a localvar structure.  The saved values
485 * will be restored when the shell function returns.  We handle the name
486 * "-" as a special case.
487 */
488
489void
490mklocal(name)
491	char *name;
492	{
493	struct localvar *lvp;
494	struct var **vpp;
495	struct var *vp;
496
497	INTOFF;
498	lvp = ckmalloc(sizeof (struct localvar));
499	if (name[0] == '-' && name[1] == '\0') {
500		lvp->text = ckmalloc(sizeof optlist);
501		bcopy(optlist, lvp->text, sizeof optlist);
502		vp = NULL;
503	} else {
504		vpp = hashvar(name);
505		for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
506		if (vp == NULL) {
507			if (strchr(name, '='))
508				setvareq(savestr(name), VSTRFIXED);
509			else
510				setvar(name, NULL, VSTRFIXED);
511			vp = *vpp;	/* the new variable */
512			lvp->text = NULL;
513			lvp->flags = VUNSET;
514		} else {
515			lvp->text = vp->text;
516			lvp->flags = vp->flags;
517			vp->flags |= VSTRFIXED|VTEXTFIXED;
518			if (strchr(name, '='))
519				setvareq(savestr(name), 0);
520		}
521	}
522	lvp->vp = vp;
523	lvp->next = localvars;
524	localvars = lvp;
525	INTON;
526}
527
528
529/*
530 * Called after a function returns.
531 */
532
533void
534poplocalvars() {
535	struct localvar *lvp;
536	struct var *vp;
537
538	while ((lvp = localvars) != NULL) {
539		localvars = lvp->next;
540		vp = lvp->vp;
541		if (vp == NULL) {	/* $- saved */
542			bcopy(lvp->text, optlist, sizeof optlist);
543			ckfree(lvp->text);
544		} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
545			(void)unsetvar(vp->text);
546		} else {
547			if ((vp->flags & VTEXTFIXED) == 0)
548				ckfree(vp->text);
549			vp->flags = lvp->flags;
550			vp->text = lvp->text;
551		}
552		ckfree(lvp);
553	}
554}
555
556
557setvarcmd(argc, argv)  char **argv; {
558	if (argc <= 2)
559		return unsetcmd(argc, argv);
560	else if (argc == 3)
561		setvar(argv[1], argv[2], 0);
562	else
563		error("List assignment not implemented");
564	return 0;
565}
566
567
568/*
569 * The unset builtin command.  We unset the function before we unset the
570 * variable to allow a function to be unset when there is a readonly variable
571 * with the same name.
572 */
573
574unsetcmd(argc, argv)  char **argv; {
575	char **ap;
576	int i;
577	int flg_func = 0;
578	int flg_var = 0;
579	int ret = 0;
580
581	while ((i = nextopt("vf")) != '\0') {
582		if (i == 'f')
583			flg_func = 1;
584		else
585			flg_var = 1;
586	}
587	if (flg_func == 0 && flg_var == 0)
588		flg_var = 1;
589
590	for (ap = argptr; *ap ; ap++) {
591		if (flg_func)
592			ret |= unsetfunc(*ap);
593		if (flg_var)
594			ret |= unsetvar(*ap);
595	}
596	return ret;
597}
598
599
600/*
601 * Unset the specified variable.
602 */
603
604STATIC int
605unsetvar(s)
606	char *s;
607	{
608	struct var **vpp;
609	struct var *vp;
610
611	vpp = hashvar(s);
612	for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
613		if (varequal(vp->text, s)) {
614			if (vp->flags & VREADONLY)
615				return (1);
616			INTOFF;
617			if (*(strchr(vp->text, '=') + 1) != '\0')
618				setvar(s, nullstr, 0);
619			vp->flags &=~ VEXPORT;
620			vp->flags |= VUNSET;
621			if ((vp->flags & VSTRFIXED) == 0) {
622				if ((vp->flags & VTEXTFIXED) == 0)
623					ckfree(vp->text);
624				*vpp = vp->next;
625				ckfree(vp);
626			}
627			INTON;
628			return (0);
629		}
630	}
631
632	return (1);
633}
634
635
636
637/*
638 * Find the appropriate entry in the hash table from the name.
639 */
640
641STATIC struct var **
642hashvar(p)
643	register char *p;
644	{
645	unsigned int hashval;
646
647	hashval = *p << 4;
648	while (*p && *p != '=')
649		hashval += *p++;
650	return &vartab[hashval % VTABSIZE];
651}
652
653
654
655/*
656 * Returns true if the two strings specify the same varable.  The first
657 * variable name is terminated by '='; the second may be terminated by
658 * either '=' or '\0'.
659 */
660
661STATIC int
662varequal(p, q)
663	register char *p, *q;
664	{
665	while (*p == *q++) {
666		if (*p++ == '=')
667			return 1;
668	}
669	if (*p == '=' && *(q - 1) == '\0')
670		return 1;
671	return 0;
672}
673