10SN/A/*-
21472SN/A * Copyright (c) 1991, 1993
30SN/A *	The Regents of the University of California.  All rights reserved.
40SN/A * Copyright (c) 1997-2005
50SN/A *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
60SN/A *
70SN/A * This code is derived from software contributed to Berkeley by
80SN/A * Kenneth Almquist.
90SN/A *
100SN/A * Redistribution and use in source and binary forms, with or without
110SN/A * modification, are permitted provided that the following conditions
120SN/A * are met:
130SN/A * 1. Redistributions of source code must retain the above copyright
140SN/A *    notice, this list of conditions and the following disclaimer.
150SN/A * 2. Redistributions in binary form must reproduce the above copyright
160SN/A *    notice, this list of conditions and the following disclaimer in the
170SN/A *    documentation and/or other materials provided with the distribution.
180SN/A * 3. Neither the name of the University nor the names of its contributors
191472SN/A *    may be used to endorse or promote products derived from this software
201472SN/A *    without specific prior written permission.
211472SN/A *
220SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
230SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
240SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
250SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
260SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
270SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
280SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
290SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
300SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
310SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
320SN/A * SUCH DAMAGE.
330SN/A */
340SN/A
350SN/A#include <zircon/paths.h>
360SN/A#include <unistd.h>
370SN/A#include <stdio.h>
380SN/A#include <stdlib.h>
390SN/A#ifdef HAVE_PATHS_H
400SN/A#include <paths.h>
410SN/A#endif
420SN/A
430SN/A/*
440SN/A * Shell variables.
450SN/A */
460SN/A
470SN/A#include "shell.h"
480SN/A#include "output.h"
490SN/A#include "expand.h"
500SN/A#include "nodes.h"	/* for other headers */
510SN/A#include "exec.h"
520SN/A#include "syntax.h"
530SN/A#include "options.h"
540SN/A#include "var.h"
550SN/A#include "memalloc.h"
560SN/A#include "error.h"
570SN/A#include "mystring.h"
580SN/A#include "parser.h"
590SN/A#include "show.h"
600SN/A#include "system.h"
610SN/A
620SN/A
630SN/A#define VTABSIZE 39
640SN/A
65
66struct localvar_list {
67	struct localvar_list *next;
68	struct localvar *lv;
69};
70
71MKINIT struct localvar_list *localvar_stack;
72
73const char defpathvar[] = ZX_SHELL_ENV_PATH;
74#ifdef IFS_BROKEN
75const char defifsvar[] = "IFS= \t\n";
76#else
77const char defifs[] = " \t\n";
78#endif
79MKINIT char defoptindvar[] = "OPTIND=1";
80
81int lineno;
82char linenovar[sizeof("LINENO=")+sizeof(int)*CHAR_BIT/3+1] = "LINENO=";
83
84/* Some macros in var.h depend on the order, add new variables to the end. */
85struct var varinit[] = {
86#if ATTY
87	{ 0,	VSTRFIXED|VTEXTFIXED|VUNSET,	"ATTY\0",	0 },
88#endif
89#ifdef IFS_BROKEN
90	{ 0,	VSTRFIXED|VTEXTFIXED,		defifsvar,	0 },
91#else
92	{ 0,	VSTRFIXED|VTEXTFIXED|VUNSET,	"IFS\0",	0 },
93#endif
94	{ 0,	VSTRFIXED|VTEXTFIXED,		defpathvar,	changepath },
95	{ 0,	VSTRFIXED|VTEXTFIXED,		"PS1=$ ",	0 },
96	{ 0,	VSTRFIXED|VTEXTFIXED,		"PS2=> ",	0 },
97	{ 0,	VSTRFIXED|VTEXTFIXED,		"PS4=+ ",	0 },
98	{ 0,	VSTRFIXED|VTEXTFIXED,		defoptindvar,	getoptsreset },
99#ifdef WITH_LINENO
100	{ 0,	VSTRFIXED|VTEXTFIXED,		linenovar,	0 },
101#endif
102};
103
104STATIC struct var *vartab[VTABSIZE];
105
106STATIC struct var **hashvar(const char *);
107STATIC int vpcmp(const void *, const void *);
108STATIC struct var **findvar(struct var **, const char *);
109
110/*
111 * Initialize the varable symbol tables and import the environment
112 */
113
114#ifdef mkinit
115INCLUDE <unistd.h>
116INCLUDE <sys/types.h>
117INCLUDE <sys/stat.h>
118INCLUDE "cd.h"
119INCLUDE "output.h"
120INCLUDE "var.h"
121MKINIT char **environ;
122INIT {
123	char **envp;
124	static char ppid[32] = "PPID=";
125	const char *p;
126	struct stat st1, st2;
127
128	initvar();
129	for (envp = environ ; *envp ; envp++) {
130		p = endofname(*envp);
131		if (p != *envp && *p == '=') {
132			setvareq(*envp, VEXPORT|VTEXTFIXED);
133		}
134	}
135
136	setvareq(defoptindvar, VTEXTFIXED);
137
138	fmtstr(ppid + 5, sizeof(ppid) - 5, "%ld", (long) getppid());
139	setvareq(ppid, VTEXTFIXED);
140
141	p = lookupvar("PWD");
142	if (p)
143		if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
144		    st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
145			p = 0;
146	setpwd(p, 0);
147}
148
149RESET {
150	unwindlocalvars(0);
151}
152#endif
153
154
155/*
156 * This routine initializes the builtin variables.  It is called when the
157 * shell is initialized.
158 */
159
160void
161initvar(void)
162{
163	struct var *vp;
164	struct var *end;
165	struct var **vpp;
166
167	vp = varinit;
168	end = vp + sizeof(varinit) / sizeof(varinit[0]);
169	do {
170		vpp = hashvar(vp->text);
171		vp->next = *vpp;
172		*vpp = vp;
173	} while (++vp < end);
174	/*
175	 * PS1 depends on uid
176	 */
177	if (!geteuid())
178		vps1.text = "PS1=# ";
179}
180
181/*
182 * Set the value of a variable.  The flags argument is ored with the
183 * flags of the variable.  If val is NULL, the variable is unset.
184 */
185
186struct var *setvar(const char *name, const char *val, int flags)
187{
188	char *p, *q;
189	size_t namelen;
190	char *nameeq;
191	size_t vallen;
192	struct var *vp;
193
194	q = endofname(name);
195	p = strchrnul(q, '=');
196	namelen = p - name;
197	if (!namelen || p != q)
198		sh_error("%.*s: bad variable name", namelen, name);
199	vallen = 0;
200	if (val == NULL) {
201		flags |= VUNSET;
202	} else {
203		vallen = strlen(val);
204	}
205	INTOFF;
206	p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
207	if (val) {
208		*p++ = '=';
209		p = mempcpy(p, val, vallen);
210	}
211	*p = '\0';
212	vp = setvareq(nameeq, flags | VNOSAVE);
213	INTON;
214
215	return vp;
216}
217
218/*
219 * Set the given integer as the value of a variable.  The flags argument is
220 * ored with the flags of the variable.
221 */
222
223intmax_t setvarint(const char *name, intmax_t val, int flags)
224{
225	int len = max_int_length(sizeof(val));
226	char buf[len];
227
228	fmtstr(buf, len, "%" PRIdMAX, val);
229	setvar(name, buf, flags);
230	return val;
231}
232
233
234
235/*
236 * Same as setvar except that the variable and value are passed in
237 * the first argument as name=value.  Since the first argument will
238 * be actually stored in the table, it should not be a string that
239 * will go away.
240 * Called with interrupts off.
241 */
242
243struct var *setvareq(char *s, int flags)
244{
245	struct var *vp, **vpp;
246
247	vpp = hashvar(s);
248	flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
249	vpp = findvar(vpp, s);
250	vp = *vpp;
251	if (vp) {
252		if (vp->flags & VREADONLY) {
253			const char *n;
254
255			if (flags & VNOSAVE)
256				free(s);
257			n = vp->text;
258			sh_error("%.*s: is read only", strchrnul(n, '=') - n,
259				 n);
260		}
261
262		if (flags & VNOSET)
263			goto out;
264
265		if (vp->func && (flags & VNOFUNC) == 0)
266			(*vp->func)(strchrnul(s, '=') + 1);
267
268		if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
269			ckfree(vp->text);
270
271		if (((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) |
272		     (vp->flags & VSTRFIXED)) == VUNSET) {
273			*vpp = vp->next;
274			ckfree(vp);
275out_free:
276			if ((flags & (VTEXTFIXED|VSTACK|VNOSAVE)) == VNOSAVE)
277				ckfree(s);
278			goto out;
279		}
280
281		flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
282	} else {
283		if (flags & VNOSET)
284			goto out;
285		if ((flags & (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
286			goto out_free;
287		/* not found */
288		vp = ckmalloc(sizeof (*vp));
289		vp->next = *vpp;
290		vp->func = NULL;
291		*vpp = vp;
292	}
293	if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
294		s = savestr(s);
295	vp->text = s;
296	vp->flags = flags;
297
298out:
299	return vp;
300}
301
302
303
304/*
305 * Process a linked list of variable assignments.
306 */
307
308void
309listsetvar(struct strlist *list, int flags)
310{
311	struct strlist *lp;
312
313	lp = list;
314	if (!lp)
315		return;
316	INTOFF;
317	do {
318		setvareq(lp->text, flags);
319	} while ((lp = lp->next));
320	INTON;
321}
322
323
324/*
325 * Find the value of a variable.  Returns NULL if not set.
326 */
327
328char *
329lookupvar(const char *name)
330{
331	struct var *v;
332
333	if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
334#ifdef WITH_LINENO
335		if (v == &vlineno && v->text == linenovar) {
336			fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno);
337		}
338#endif
339		return strchrnul(v->text, '=') + 1;
340	}
341	return NULL;
342}
343
344intmax_t lookupvarint(const char *name)
345{
346	return atomax(lookupvar(name) ?: nullstr, 0);
347}
348
349
350
351/*
352 * Generate a list of variables satisfying the given conditions.
353 */
354
355char **
356listvars(int on, int off, char ***end)
357{
358	struct var **vpp;
359	struct var *vp;
360	char **ep;
361	int mask;
362
363	STARTSTACKSTR(ep);
364	vpp = vartab;
365	mask = on | off;
366	do {
367		for (vp = *vpp ; vp ; vp = vp->next)
368			if ((vp->flags & mask) == on) {
369				if (ep == stackstrend())
370					ep = growstackstr();
371				*ep++ = (char *) vp->text;
372			}
373	} while (++vpp < vartab + VTABSIZE);
374	if (ep == stackstrend())
375		ep = growstackstr();
376	if (end)
377		*end = ep;
378	*ep++ = NULL;
379	return grabstackstr(ep);
380}
381
382
383
384/*
385 * POSIX requires that 'set' (but not export or readonly) output the
386 * variables in lexicographic order - by the locale's collating order (sigh).
387 * Maybe we could keep them in an ordered balanced binary tree
388 * instead of hashed lists.
389 * For now just roll 'em through qsort for printing...
390 */
391
392int
393showvars(const char *prefix, int on, int off)
394{
395	const char *sep;
396	char **ep, **epend;
397
398	ep = listvars(on, off, &epend);
399	qsort(ep, epend - ep, sizeof(char *), vpcmp);
400
401	sep = *prefix ? spcstr : prefix;
402
403	for (; ep < epend; ep++) {
404		const char *p;
405		const char *q;
406
407		p = strchrnul(*ep, '=');
408		q = nullstr;
409		if (*p)
410			q = single_quote(++p);
411
412		out1fmt("%s%s%.*s%s\n", prefix, sep, (int)(p - *ep), *ep, q);
413	}
414
415	return 0;
416}
417
418
419
420/*
421 * The export and readonly commands.
422 */
423
424int
425exportcmd(int argc, char **argv)
426{
427	struct var *vp;
428	char *name;
429	const char *p;
430	char **aptr;
431	int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
432	int notp;
433
434	notp = nextopt("p") - 'p';
435	if (notp && ((name = *(aptr = argptr)))) {
436		do {
437			if ((p = strchr(name, '=')) != NULL) {
438				p++;
439			} else {
440				if ((vp = *findvar(hashvar(name), name))) {
441					vp->flags |= flag;
442					continue;
443				}
444			}
445			setvar(name, p, flag);
446		} while ((name = *++aptr) != NULL);
447	} else {
448		showvars(argv[0], flag, 0);
449	}
450	return 0;
451}
452
453
454/*
455 * The "local" command.
456 */
457
458int
459localcmd(int argc, char **argv)
460{
461	char *name;
462
463	if (!localvar_stack)
464		sh_error("not in a function");
465
466	argv = argptr;
467	while ((name = *argv++) != NULL) {
468		mklocal(name);
469	}
470	return 0;
471}
472
473
474/*
475 * Make a variable a local variable.  When a variable is made local, it's
476 * value and flags are saved in a localvar structure.  The saved values
477 * will be restored when the shell function returns.  We handle the name
478 * "-" as a special case.
479 */
480
481void mklocal(char *name)
482{
483	struct localvar *lvp;
484	struct var **vpp;
485	struct var *vp;
486
487	INTOFF;
488	lvp = ckmalloc(sizeof (struct localvar));
489	if (name[0] == '-' && name[1] == '\0') {
490		char *p;
491		p = ckmalloc(sizeof(optlist));
492		lvp->text = memcpy(p, optlist, sizeof(optlist));
493		vp = NULL;
494	} else {
495		char *eq;
496
497		vpp = hashvar(name);
498		vp = *findvar(vpp, name);
499		eq = strchr(name, '=');
500		if (vp == NULL) {
501			if (eq)
502				vp = setvareq(name, VSTRFIXED);
503			else
504				vp = setvar(name, NULL, VSTRFIXED);
505			lvp->flags = VUNSET;
506		} else {
507			lvp->text = vp->text;
508			lvp->flags = vp->flags;
509			vp->flags |= VSTRFIXED|VTEXTFIXED;
510			if (eq)
511				setvareq(name, 0);
512		}
513	}
514	lvp->vp = vp;
515	lvp->next = localvar_stack->lv;
516	localvar_stack->lv = lvp;
517	INTON;
518}
519
520
521/*
522 * Called after a function returns.
523 * Interrupts must be off.
524 */
525
526void
527poplocalvars(int keep)
528{
529	struct localvar_list *ll;
530	struct localvar *lvp, *next;
531	struct var *vp;
532
533	INTOFF;
534	ll = localvar_stack;
535	localvar_stack = ll->next;
536
537	next = ll->lv;
538	ckfree(ll);
539
540	while ((lvp = next) != NULL) {
541		next = lvp->next;
542		vp = lvp->vp;
543		TRACE(("poplocalvar %s\n", vp ? vp->text : "-"));
544		if (keep) {
545			int bits = VSTRFIXED;
546
547			if (lvp->flags != VUNSET) {
548				if (vp->text == lvp->text)
549					bits |= VTEXTFIXED;
550				else if (!(lvp->flags & (VTEXTFIXED|VSTACK)))
551					ckfree(lvp->text);
552			}
553
554			vp->flags &= ~bits;
555			vp->flags |= (lvp->flags & bits);
556
557			if ((vp->flags &
558			     (VEXPORT|VREADONLY|VSTRFIXED|VUNSET)) == VUNSET)
559				unsetvar(vp->text);
560		} else if (vp == NULL) {	/* $- saved */
561			memcpy(optlist, lvp->text, sizeof(optlist));
562			ckfree(lvp->text);
563			optschanged();
564		} else if (lvp->flags == VUNSET) {
565			vp->flags &= ~(VSTRFIXED|VREADONLY);
566			unsetvar(vp->text);
567		} else {
568			if (vp->func)
569				(*vp->func)(strchrnul(lvp->text, '=') + 1);
570			if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
571				ckfree(vp->text);
572			vp->flags = lvp->flags;
573			vp->text = lvp->text;
574		}
575		ckfree(lvp);
576	}
577	INTON;
578}
579
580
581/*
582 * Create a new localvar environment.
583 */
584struct localvar_list *pushlocalvars(void)
585{
586	struct localvar_list *ll;
587
588	INTOFF;
589	ll = ckmalloc(sizeof(*ll));
590	ll->lv = NULL;
591	ll->next = localvar_stack;
592	localvar_stack = ll;
593	INTON;
594
595	return ll->next;
596}
597
598
599void unwindlocalvars(struct localvar_list *stop)
600{
601	while (localvar_stack != stop)
602		poplocalvars(0);
603}
604
605
606/*
607 * The unset builtin command.  We unset the function before we unset the
608 * variable to allow a function to be unset when there is a readonly variable
609 * with the same name.
610 */
611
612int
613unsetcmd(int argc, char **argv)
614{
615	char **ap;
616	int i;
617	int flag = 0;
618
619	while ((i = nextopt("vf")) != '\0') {
620		flag = i;
621	}
622
623	for (ap = argptr; *ap ; ap++) {
624		if (flag != 'f') {
625			unsetvar(*ap);
626			continue;
627		}
628		if (flag != 'v')
629			unsetfunc(*ap);
630	}
631	return 0;
632}
633
634
635/*
636 * Unset the specified variable.
637 */
638
639void unsetvar(const char *s)
640{
641	setvar(s, 0, 0);
642}
643
644
645
646/*
647 * Find the appropriate entry in the hash table from the name.
648 */
649
650STATIC struct var **
651hashvar(const char *p)
652{
653	unsigned int hashval;
654
655	hashval = ((unsigned char) *p) << 4;
656	while (*p && *p != '=')
657		hashval += (unsigned char) *p++;
658	return &vartab[hashval % VTABSIZE];
659}
660
661
662
663/*
664 * Compares two strings up to the first = or '\0'.  The first
665 * string must be terminated by '='; the second may be terminated by
666 * either '=' or '\0'.
667 */
668
669int
670varcmp(const char *p, const char *q)
671{
672	int c, d;
673
674	while ((c = *p) == (d = *q)) {
675		if (!c || c == '=')
676			goto out;
677		p++;
678		q++;
679	}
680	if (c == '=')
681		c = 0;
682	if (d == '=')
683		d = 0;
684out:
685	return c - d;
686}
687
688STATIC int
689vpcmp(const void *a, const void *b)
690{
691	return varcmp(*(const char **)a, *(const char **)b);
692}
693
694STATIC struct var **
695findvar(struct var **vpp, const char *name)
696{
697	for (; *vpp; vpp = &(*vpp)->next) {
698		if (varequal((*vpp)->text, name)) {
699			break;
700		}
701	}
702	return vpp;
703}
704