1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * A copy of the CDDL is also available via the Internet at
11  * http://www.opensource.org/licenses/cddl1.txt
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 
24 /*
25  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
30 /*	  All Rights Reserved  	*/
31 
32 #if defined(sun)
33 #pragma ident	"@(#)name.c	1.25	06/06/16 SMI"
34 #endif
35 
36 #include "defs.h"
37 
38 /*
39  * Copyright 2008-2020 J. Schilling
40  *
41  * @(#)name.c	1.80 20/05/17 2008-2020 J. Schilling
42  */
43 #ifndef lint
44 static	UConst char sccsid[] =
45 	"@(#)name.c	1.80 20/05/17 2008-2020 J. Schilling";
46 #endif
47 
48 /*
49  * UNIX shell
50  */
51 
52 #ifdef INTERACTIVE
53 #include	<schily/shedit.h>
54 #endif
55 #ifdef	HAVE_STROPTS_H
56 #include	<stropts.h>
57 #endif
58 
59 extern int	mailchk;
60 
61 	int	syslook		__PR((unsigned char *w,
62 					const struct sysnod syswds[], int n));
63 	const struct sysnod *
64 		sysnlook	__PR((unsigned char *w,
65 					const struct sysnod syswds[], int n));
66 	void	setlist		__PR((struct argnod *arg, int xp));
67 	void	setname		__PR((unsigned char *, int));
68 	void	replace		__PR((unsigned char **a, unsigned char *v));
69 	void	dfault		__PR((struct namnod *n, unsigned char *v));
70 	void	assign		__PR((struct namnod *n, unsigned char *v));
71 static void	use		__PR((struct namnod *n));
72 static void	set_builtins_path	__PR((void));
73 static int	patheq		__PR((unsigned char *component, char *dir));
74 	int	readvar		__PR((int namec, unsigned char **names));
75 	void	assnum		__PR((unsigned char **p, long i));
76 unsigned char	*make		__PR((unsigned char *v));
77 struct namnod	*lookup		__PR((unsigned char *nam));
78 static	BOOL	chkid		__PR((unsigned char *nam));
79 	void	namscan		__PR((void (*fn)(struct namnod *n)));
80 static void	namwalk		__PR((struct namnod *));
81 	void	printfunc	__PR((struct namnod *n));
82 	void	printnam	__PR((struct namnod *n));
83 #ifdef	DO_LINENO
84 	unsigned char *linenoval __PR((void));
85 #endif
86 	void	printro		__PR((struct namnod *n));
87 	void	printpro	__PR((struct namnod *n));
88 	void	printexp	__PR((struct namnod *n));
89 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN) || defined(DO_SYSLOCAL)
90 	void	pushval		__PR((struct namnod *nm, void *t));
91 #endif
92 #ifdef	DO_SYSLOCAL
93 	void	poplvars	__PR((void));
94 static void	_poplvars	__PR((struct namnod *n));
95 	void	printlocal	__PR((struct namnod *n));
96 #endif
97 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN)
98 	void	popvars		__PR((void));
99 static void	_popvars	__PR((struct namnod *n));
100 #endif
101 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN) || defined(DO_SYSLOCAL)
102 	void	popval		__PR((struct namnod *n));
103 #endif
104 	void	setup_env	__PR((void));
105 static void	countnam	__PR((struct namnod *n));
106 static void	pushnam		__PR((struct namnod *n));
107 	unsigned char **local_setenv __PR((int flg));
108 	unsigned char **get_envptr __PR((void));
109 	struct namnod *findnam	__PR((unsigned char *nam));
110 	void	unset_name	__PR((unsigned char *name, int uflg));
111 static void	dolocale	__PR((char *nm));
112 
113 #ifndef	HAVE_ISASTREAM
114 static	int	isastream	__PR((int fd));
115 #endif
116 #ifdef INTERACTIVE
117 	char	*getcurenv	__PR((char *name));
118 	void	ev_insert	__PR((char *name));
119 #endif
120 
121 struct namnod ps2nod =			/* PS2= */
122 {
123 	(struct namnod *)NIL,
124 	&acctnod,
125 	(struct namnod *)NIL,
126 	(unsigned char *)ps2name
127 };
128 struct namnod fcenod =			/* FCEDIT= */
129 {
130 	(struct namnod *)NIL,
131 	(struct namnod *)NIL,
132 	(struct namnod *)NIL,
133 	(unsigned char *)fcename
134 };
135 struct namnod envnod =			/* ENV= */
136 {
137 	(struct namnod *)NIL,
138 	&fcenod,
139 	(struct namnod *)NIL,
140 	(unsigned char *)envname
141 };
142 struct namnod cdpnod =			/* CDPATH= */
143 {
144 	(struct namnod *)NIL,
145 	&envnod,
146 	(struct namnod *)NIL,
147 	(unsigned char *)cdpname
148 };
149 struct namnod ppidnod =			/* PPID= */
150 {
151 	(struct namnod *)NIL,
152 	(struct namnod *)NIL,
153 	(struct namnod *)NIL,
154 	(unsigned char *)ppidname
155 };
156 struct namnod pathnod =			/* PATH= */
157 {
158 	&mailpnod,
159 	&ppidnod,
160 	(struct namnod *)NIL,
161 	(unsigned char *)pathname
162 };
163 struct namnod ifsnod =			/* IFS= */
164 {
165 	&homenod,
166 	&mailnod,
167 	(struct namnod *)NIL,
168 	(unsigned char *)ifsname
169 };
170 struct namnod ps1nod =			/* PS1= */
171 {
172 	&pathnod,
173 	&ps2nod,
174 	(struct namnod *)NIL,
175 	(unsigned char *)ps1name
176 };
177 struct namnod ps4nod =			/* PS4= */
178 {
179 	(struct namnod *)NIL,
180 	(struct namnod *)NIL,
181 	(struct namnod *)NIL,
182 	(unsigned char *)ps4name
183 };
184 struct namnod ps3nod =			/* PS3= */
185 {
186 	(struct namnod *)NIL,
187 	&ps4nod,
188 	(struct namnod *)NIL,
189 	(unsigned char *)ps3name
190 };
191 struct namnod homenod =			/* HOME= */
192 {
193 	&cdpnod,
194 	(struct namnod *)NIL,
195 	(struct namnod *)NIL,
196 	(unsigned char *)homename
197 };
198 struct namnod linenonod =		/* LINENO= */
199 {
200 	(struct namnod *)NIL,
201 	(struct namnod *)NIL,
202 	(struct namnod *)NIL,
203 	(unsigned char *)linenoname
204 };
205 struct namnod mailnod =			/* MAIL= */
206 {
207 	&linenonod,
208 	(struct namnod *)NIL,
209 	(struct namnod *)NIL,
210 	(unsigned char *)mailname
211 };
212 struct namnod mchknod =			/* MAILCHECK= */
213 {
214 	&ifsnod,
215 	&ps1nod,
216 	(struct namnod *)NIL,
217 	(unsigned char *)mchkname
218 };
219 struct namnod repnod =			/* REPLY= */
220 {
221 	(struct namnod *)NIL,
222 	(struct namnod *)NIL,
223 	(struct namnod *)NIL,
224 	(unsigned char *)repname,
225 };
226 struct namnod pwdnod =			/* PWD= */
227 {
228 	&ps3nod,
229 	&repnod,
230 	(struct namnod *)NIL,
231 	(unsigned char *)pwdname,
232 };
233 struct namnod opwdnod =			/* OLDPWD= */
234 {
235 	(struct namnod *)NIL,
236 	(struct namnod *)NIL,
237 	(struct namnod *)NIL,
238 	(unsigned char *)opwdname,
239 };
240 struct namnod timefmtnod =		/* TIMEFORMAT= */
241 {
242 	(struct namnod *)NIL,
243 	(struct namnod *)NIL,
244 	(struct namnod *)NIL,
245 	(unsigned char *)timefmtname,
246 };
247 struct namnod acctnod =			/* SHACCT= */
248 {
249 	&pwdnod,
250 	&timefmtnod,
251 	(struct namnod *)NIL,
252 	(unsigned char *)acctname
253 };
254 struct namnod mailpnod =		/* MAILPATH= */
255 {
256 	(struct namnod *)NIL,
257 	&opwdnod,
258 	(struct namnod *)NIL,
259 	(unsigned char *)mailpname
260 };
261 #ifdef	DO_GETOPT_POSIX
262 struct namnod *optindnodep;		/* OPTIND= */
263 #endif
264 
265 
266 struct namnod *namep = &mchknod;
267 
268 /* ========	variable and string handling	======== */
269 
270 /*
271  * Return numeric identifier for reserved words and builtin commands.
272  */
273 int
syslook(w,syswds,n)274 syslook(w, syswds, n)
275 	unsigned char	*w;
276 	const struct sysnod	syswds[];
277 	int		n;
278 {
279 	const struct sysnod	*res = sysnlook(w, syswds, n);
280 
281 	if (res == NULL)
282 		return (0);
283 	return (res->sysval);
284 }
285 
286 /*
287  * Lookup function for reserved words and builtin commands,
288  * return sysnod structure.
289  */
290 const struct sysnod *
sysnlook(w,syswds,n)291 sysnlook(w, syswds, n)
292 	unsigned char	*w;
293 	const struct sysnod	syswds[];
294 	int		n;
295 {
296 	int	low;
297 	int	high;
298 	int	mid;
299 	int	cond;
300 
301 	if (w == 0 || *w == 0)
302 		return (0);
303 
304 	low = 0;
305 	high = n - 1;
306 
307 	while (low <= high) {
308 		mid = (low + high) / 2;
309 
310 		if ((cond = cf(w, (unsigned char *)syswds[mid].sysnam)) < 0)
311 			high = mid - 1;
312 		else if (cond > 0)
313 			low = mid + 1;
314 		else
315 			return (&syswds[mid]);
316 	}
317 	return (0);
318 }
319 
320 /*
321  * Set up the list of local shell variable definitions to be
322  * exported for the next command.
323  */
324 void
setlist(arg,xp)325 setlist(arg, xp)
326 	struct argnod	*arg;
327 	int		xp;
328 {
329 	if (flags & exportflg)
330 		xp |= N_EXPORT;
331 
332 	while (arg) {
333 		unsigned char *s = mactrim(arg->argval);
334 		setname(s, xp);
335 		arg = arg->argnxt;
336 		if (flags & execpr) {
337 #ifdef	DO_PS34
338 			prs(ps_macro(ps4nod.namval?ps4nod.namval:UC execpmsg,
339 								FALSE));
340 #endif
341 			prs(s);
342 			if (arg)
343 				blank();
344 			else
345 				newline();
346 		}
347 	}
348 }
349 
350 /*
351  * does parameter assignments for cases when a NAME=value string exists
352  */
353 void
setname(argi,xp)354 setname(argi, xp)
355 	unsigned char	*argi;
356 	int		xp;
357 {
358 	unsigned char *argscan = argi;
359 	struct namnod *n;
360 
361 	if (letter(*argscan)) {
362 		while (alphanum(*argscan))
363 			argscan++;
364 
365 		if (*argscan == '=') {
366 			*argscan = 0;	/* make name a cohesive string */
367 
368 			n = lookup(argi);
369 			*argscan++ = '=';
370 
371 			if (xp & N_ENVNAM) {
372 				n->namenv = n->namval = argscan;
373 				if (n == &pathnod)
374 					set_builtins_path();
375 			} else {
376 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN)
377 				if (xp & N_PUSHOV)
378 					pushval(n, NULL);
379 #endif
380 				assign(n, argscan);
381 			}
382 			attrib(n, xp);	/* readonly attrib after assignement */
383 
384 			dolocale((char *)n->namid);
385 #ifdef	DO_GETOPT_POSIX
386 			/*
387 			 * make sure that option parsing starts
388 			 * at first character
389 			 */
390 			if (n == optindnodep)
391 				_sp = 1;
392 #endif
393 			return;
394 		}
395 	}
396 }
397 
398 void
replace(a,v)399 replace(a, v)
400 	unsigned char	**a;
401 	unsigned char	*v;
402 {
403 	free(*a);
404 	*a = make(v);
405 }
406 
407 /*
408  * Assign a default value to a shell variable that is currently unset.
409  */
410 void
dfault(n,v)411 dfault(n, v)
412 	struct namnod	*n;
413 	unsigned char	*v;
414 {
415 	if (n->namval == 0)
416 		assign(n, v);
417 }
418 
419 /*
420  * Unconditionally assign a value to a shell variable.
421  */
422 void
assign(n,v)423 assign(n, v)
424 	struct namnod	*n;
425 	unsigned char	*v;
426 {
427 	if (n->namflg & N_RDONLY)
428 		failed(n->namid, wtfailed);
429 
430 #ifndef RES
431 
432 	else if (flags & rshflg) {
433 		if (n == &pathnod || eq(n->namid, "SHELL"))
434 			failed(n->namid, restricted);
435 	}
436 #endif
437 
438 #ifndef	DO_POSIX_UNSET
439 	else if (n->namflg & N_FUNCTN) {
440 		func_unhash(n->namid);
441 		freefunc(n);
442 
443 		n->funcval = 0;
444 		n->namflg = N_DEFAULT;
445 	}
446 #endif
447 	replace(&n->namval, v);
448 	attrib(n, N_ENVCHG);		/* Mark as changed after env inport */
449 #ifdef	DO_ALLEXPORT
450 	if (flags & exportflg)		/* set -a ?		*/
451 		attrib(n, N_EXPORT);	/* Mark for export	*/
452 #endif
453 
454 	use(n);
455 }
456 
457 /*
458  * Let the shell use the new value.
459  */
460 static void
use(n)461 use(n)
462 	struct namnod	*n;
463 {
464 	if (n == &mchknod) {
465 		mailchk = stoi(n->namval);
466 
467 	} else if (n == &pathnod) {
468 		zaphash();
469 		set_dotpath();
470 		set_builtins_path();
471 
472 	} if (flags & prompt) {
473 		if ((n == &mailpnod) ||
474 		    (n == &mailnod && mailpnod.namflg == N_DEFAULT)) {
475 			setmail(n->namval);
476 		}
477 	}
478 }
479 
480 static void
set_builtins_path()481 set_builtins_path()
482 {
483 	unsigned char *path;
484 
485 	ucb_builtins = 0;
486 	path = getpath((unsigned char *)"");
487 	while (path && *path) {
488 		if (patheq(path, "/usr/ucb")) {
489 			ucb_builtins++;
490 			break;
491 		} else if (patheq(path, "/usr/bin"))
492 			break;
493 		else if (patheq(path, "/bin"))
494 			break;
495 		else if (patheq(path, "/usr/5bin"))
496 			break;
497 		path = nextpath(path);
498 	}
499 }
500 
501 static int
patheq(component,dir)502 patheq(component, dir)
503 	unsigned char	*component;
504 	char		*dir;
505 {
506 	unsigned char	c;
507 
508 	for (;;) {
509 		c = *component++;
510 		if (c == COLON)
511 			c = '\0';	/* end of component of path */
512 		if (c != *dir++)
513 			return (0);
514 		if (c == '\0')
515 			return (1);
516 	}
517 }
518 
519 /*
520  * The read(1) builtin.
521  */
522 int
readvar(namec,names)523 readvar(namec, names)
524 	int		namec;
525 	unsigned char	**names;
526 {
527 	struct fileblk	fb;
528 	struct fileblk *f = &fb;
529 	unsigned char	c[MULTI_BYTE_MAX+1];
530 	int	rc = 0;
531 	struct namnod	*n;
532 	unsigned char	*rel;
533 	unsigned char *oldstak;
534 	unsigned char *pc, *rest;
535 	int		d;
536 #ifdef	DO_POSIX_READ
537 	wchar_t		wc;
538 	unsigned char	ifsw[3];	/* Max.: space and tab */
539 #else
540 	unsigned char	*ifsw;
541 #endif
542 	unsigned int	(*nextwchar)__PR((void));
543 	unsigned char	*ifs;
544 	BOOL		ifswhite = FALSE;
545 #ifdef	DO_SELECT
546 	unsigned char	*a[2];
547 #endif
548 
549 	nextwchar = nextwc;
550 
551 #if	defined(DO_READ_R) || defined(DO_SELECT)
552 	if (namec > 1) {
553 		struct optv	optv;
554 		int		ch;
555 
556 		optinit(&optv);
557 
558 		while ((ch = optnext(namec, names, &optv, "r",
559 				    "read [-r] [name ...]")) != -1) {
560 			if (ch == 0)	/* Was -help */
561 				return (1);
562 			else if (ch == 'r')
563 				nextwchar = readwc;
564 		}
565 		namec -= --optv.optind;
566 		names += optv.optind;
567 	}
568 
569 #if	defined(DO_SELECT)
570 	if (namec <= 1) {
571 		a[0] = UC repname;	/* REPLY */
572 		a[1] = NULL;
573 		names = a;
574 	} else
575 #endif
576 #endif
577 		names++;
578 	ifs = ifsnod.namval;
579 	if (ifs == NULL)
580 		ifs = (unsigned char *)sptbnl;
581 
582 #ifdef	DO_POSIX_READ
583 	ifsw[0] = '\0';
584 	ifsw[1] = '\0';
585 	pc = ifsw;
586 	for (rel = ifs; *rel; rel += d) {
587 		if ((d = mbtowc(&wc, C rel, MULTI_BYTE_MAX)) <= 0) {
588 			(void) mbtowc(NULL, NULL, 0);
589 			wc = *rel;
590 		}
591 		if (space(wc)) {
592 			if (ifsw[0] != wc && ifsw[1] != wc)
593 				*pc++ = wc;
594 			ifswhite = TRUE;
595 		}
596 	}
597 	*pc = '\0';
598 #else
599 	ifswhite = TRUE;
600 	ifsw = UC sptbnl;
601 #endif
602 
603 	n = lookup(*names++);		/* done now to avoid storage mess */
604 	rel = (unsigned char *)relstak();
605 
606 	push(f);
607 	initf(dup(STDIN_FILENO));
608 
609 	/*
610 	 * If stdin is a pipe then this lseek(2) will fail with ESPIPE, so
611 	 * the read buffer size is set to 1 because we will not be able
612 	 * lseek(2) back towards the beginning of the file, so we have
613 	 * to read a byte at a time instead
614 	 *
615 	 */
616 	if (lseek(STDIN_FILENO, (off_t)0, SEEK_CUR) == -1)
617 		f->fsiz = 1;
618 
619 	/*
620 	 * If stdin is a socket then this isastream(3C) will return 1, so
621 	 * the read buffer size is set to 1 because we will not be able
622 	 * lseek(2) back towards the beginning of the file, so we have
623 	 * to read a byte at a time instead
624 	 *
625 	 */
626 	if (isastream(STDIN_FILENO) == 1)
627 		f->fsiz = 1;
628 
629 	/*
630 	 * Read first character and
631 	 * strip leading IFS white space characters
632 	 */
633 	c[0] = '\0';
634 	do {
635 		d = nextwchar();
636 		if (eolchar(d))
637 			break;
638 		rest = readw(d);
639 		pc = c;
640 		while ((*pc++ = *rest++) != '\0')
641 			/* LINTED */
642 			;
643 		if (ifswhite && !anys(c, ifsw))
644 			break;
645 	} while (ifswhite);
646 
647 	oldstak = curstak();
648 	for (;;) {
649 		if ((*names && anys(c, ifs)) || eolchar(d)) {
650 			GROWSTAKTOP();
651 			zerostak();
652 			assign(n, absstak(rel));
653 			setstak(rel);
654 			if (*names)
655 				n = lookup(*names++);
656 			else
657 				n = 0;
658 			if (eolchar(d)) {
659 				break;
660 			} else {	/* strip imbedded IFS characters */
661 				c[0] = '\0';
662 				do {
663 					d = nextwchar();
664 					if (eolchar(d))
665 						break;
666 					rest = readw(d);
667 					pc = c;
668 					while ((*pc++ = *rest++) != '\0')
669 						/* LINTED */
670 						;
671 					if (ifswhite && !anys(c, ifsw))
672 						break;
673 				} while (ifswhite);
674 			}
675 		} else {
676 			if (d == '\\' && nextwchar == nextwc) {
677 				d = readwc();
678 				rest = readw(d);
679 				while ((d = *rest++) != '\0') {
680 					GROWSTAKTOP();
681 					pushstak(d);
682 				}
683 				oldstak = staktop;
684 			} else {
685 				pc = c;
686 				while ((d = *pc++) != '\0') {
687 					GROWSTAKTOP();
688 					pushstak(d);
689 				}
690 				if (!anys(c, ifs))
691 					oldstak = staktop;
692 			}
693 			d = nextwchar();
694 
695 			if (eolchar(d)) {
696 				staktop = oldstak;
697 			} else {
698 				rest = readw(d);
699 				pc = c;
700 				while ((*pc++ = *rest++) != '\0')
701 					/* LINTED */
702 					;
703 			}
704 		}
705 	}
706 	while (n) {
707 #ifdef	DO_READ_ALLEXPORT
708 		if (flags & exportflg)
709 			n->namflg |= N_EXPORT;
710 #endif
711 		assign(n, (unsigned char *)nullstr);
712 		if (*names)
713 			n = lookup(*names++);
714 		else
715 			n = 0;
716 	}
717 
718 	if (eof)
719 		rc = 1;
720 
721 	if (isastream(STDIN_FILENO) != 1)
722 		/*
723 		 * If we are reading on a stream do not attempt to
724 		 * lseek(2) back towards the start because this is
725 		 * logically meaningless, but there is nothing in
726 		 * the standards to pervent the stream implementation
727 		 * from attempting it and breaking our code here
728 		 *
729 		 */
730 		lseek(STDIN_FILENO, (off_t)(f->nxtoff - f->endoff), SEEK_CUR);
731 
732 	pop();
733 	return (rc);
734 }
735 
736 void
assnum(p,i)737 assnum(p, i)
738 	unsigned char	**p;
739 	long		i;
740 {
741 	int j = ltos(i);
742 	replace(p, &numbuf[j]);
743 }
744 
745 unsigned char *
make(v)746 make(v)
747 	unsigned char	*v;
748 {
749 	unsigned char	*p;
750 
751 	if (v) {
752 		movstr(v, p = (unsigned char *)alloc(length(v)));
753 		return (p);
754 	} else
755 		return (0);
756 }
757 
758 /*
759  * Lookup a shell variable and allocate a new node if the
760  * variable does not yet exist.
761  */
762 struct namnod *
lookup(nam)763 lookup(nam)
764 	register unsigned char	*nam;
765 {
766 	register struct namnod *nscan = namep;
767 	struct namnod **prev = NULL;	/* Make stupid GCC happy */
768 	int		LR;
769 
770 	if (!chkid(nam))
771 		failed(nam, notid);
772 
773 	while (nscan) {
774 #define	INLINE_CMP
775 #ifdef	INLINE_CMP
776 		{
777 			register unsigned char	*s1 = nam;
778 			register unsigned char	*s2 = nscan->namid;
779 
780 			while (*s1++ == *s2)
781 				if (*s2++ == 0)
782 					return (nscan);
783 			LR = *--s1 - *s2;
784 		}
785 		if (LR < 0)
786 #else
787 		if ((LR = cf(nam, nscan->namid)) == 0)
788 			return (nscan);
789 		else if (LR < 0)
790 #endif
791 			prev = &(nscan->namlft);
792 		else
793 			prev = &(nscan->namrgt);
794 		nscan = *prev;
795 	}
796 	/*
797 	 * add name node
798 	 */
799 	nscan = (struct namnod *)alloc(sizeof (*nscan));
800 	nscan->namlft = nscan->namrgt = nscan->nampush = (struct namnod *)NIL;
801 	nscan->namid = make(nam);
802 	nscan->namval = 0;
803 	nscan->namflg = N_DEFAULT;
804 	nscan->namenv = 0;
805 #ifdef	DO_POSIX_UNSET
806 	nscan->funcval = 0;
807 #endif
808 
809 #ifdef	NAME_DEBUG
810 	/*
811 	 * Allow to set up handcrafted pointers in *nod structures.
812 	 */
813 	printf("prev = %p name '%s' ME %p\n", prev, nam, nscan);
814 #endif
815 	return (*prev = nscan);
816 }
817 
818 /*
819  * A valid shell variable name starts with a letter and
820  * contains only letters or digits.
821  */
822 static BOOL
chkid(nam)823 chkid(nam)
824 	unsigned char	*nam;
825 {
826 	unsigned char	*cp = nam;
827 
828 	if (!letter(*cp))
829 		return (FALSE);
830 	else {
831 		while (*++cp) {
832 			if (!alphanum(*cp))
833 				return (FALSE);
834 		}
835 	}
836 	return (TRUE);
837 }
838 
839 static void (*namfn) __PR((struct namnod *n));
840 static int    namflg;
841 
842 void
843 namscan(fn)
844 	void	(*fn) __PR((struct namnod *n));
845 {
846 	namfn = fn;
847 	namwalk(namep);
848 }
849 
850 static void
namwalk(np)851 namwalk(np)
852 	struct namnod	*np;
853 {
854 	if (np) {
855 		namwalk(np->namlft);
856 		(*namfn)(np);
857 		namwalk(np->namrgt);
858 	}
859 }
860 
861 void
printfunc(n)862 printfunc(n)
863 	struct namnod	*n;
864 {
865 	sigchk();
866 
867 	if (n->namflg & N_FUNCTN) {
868 		struct fndnod *f = fndptr(n->funcval);
869 
870 		prs_buff(n->namid);
871 		prs_buff((unsigned char *)"(){\n");
872 		if (f != NULL)
873 			prf((struct trenod *)f->fndval);
874 		prs_buff((unsigned char *)"\n}\n");
875 	}
876 }
877 
878 void
printnam(n)879 printnam(n)
880 	struct namnod	*n;
881 {
882 	unsigned char	*s;
883 
884 	sigchk();
885 
886 	if (!(flags2 & posixflg) &&
887 	    n->namflg & N_FUNCTN) {
888 		printfunc(n);
889 #ifndef	DO_POSIX_UNSET
890 		return;
891 #endif
892 	}
893 #ifdef	DO_LINENO
894 	if (n == &linenonod) {
895 		prs_buff(n->namid);
896 		prc_buff('=');
897 		prs_buff(linenoval());
898 		prc_buff(NL);
899 	} else
900 #endif
901 	if ((s = n->namval) != NULL) {
902 		prs_buff(n->namid);
903 		prc_buff('=');
904 #ifdef	DO_POSIX_UNSET
905 		qprs_buff(s);
906 #else
907 		prs_buff(s);
908 #endif
909 		prc_buff(NL);
910 	}
911 }
912 
913 #ifdef	DO_LINENO
914 unsigned char *
linenoval()915 linenoval()
916 {
917 	struct fileblk *f = standin;
918 
919 #ifdef	LINENO_DEBUG
920 	while (1) {
921 		printf("F %p des %d\n", f, f->fdes);
922 		if (f->fstak == NULL)
923 			break;
924 		f = f->fstak;
925 	}
926 	f = standin;
927 #endif
928 	if (f->fstak != NULL)
929 		f = f->fstak;
930 	/*
931 	 * Subtract 1 as parsing of the current
932 	 * was already done.
933 	 */
934 	itos(f->flin - 1);
935 	return (numbuf);
936 }
937 #endif
938 
939 static int namec;
940 
941 void
printro(n)942 printro(n)
943 	struct namnod	*n;
944 {
945 	if (n->namflg & N_RDONLY) {
946 		prs_buff(_gettext(readonly));
947 		prc_buff(SPACE);
948 		prs_buff(n->namid);
949 		prc_buff(NL);
950 	}
951 }
952 
953 #ifdef	DO_POSIX_EXPORT
954 void
printpro(n)955 printpro(n)
956 	struct namnod	*n;
957 {
958 	if (n->namflg & N_RDONLY) {
959 		unsigned char	*s;
960 
961 		prs_buff(UC readonly);
962 		prc_buff(SPACE);
963 		prs_buff(n->namid);
964 		if ((s = n->namval) != NULL) {
965 			prs_buff(UC "='");
966 			prs_buff(s);
967 			prc_buff('\'');
968 		}
969 		prc_buff(NL);
970 	}
971 }
972 #endif
973 
974 void
printexp(n)975 printexp(n)
976 	struct namnod	*n;
977 {
978 	if (n->namflg & N_EXPORT) {
979 		prs_buff(_gettext(export));
980 		prc_buff(SPACE);
981 		prs_buff(n->namid);
982 		prc_buff(NL);
983 	}
984 }
985 
986 #ifdef	DO_POSIX_EXPORT
987 void
printpexp(n)988 printpexp(n)
989 	struct namnod	*n;
990 {
991 	if (n->namflg & N_EXPORT) {
992 		unsigned char	*s;
993 
994 		prs_buff(UC export);
995 		prc_buff(SPACE);
996 		prs_buff(n->namid);
997 		if ((s = n->namval) != NULL) {
998 			prs_buff(UC "='");
999 			prs_buff(s);
1000 			prc_buff('\'');
1001 		}
1002 		prc_buff(NL);
1003 	}
1004 }
1005 #endif
1006 
1007 #ifdef	DO_POSIX_EXPORT_ENV
1008 void
exportenv(n)1009 exportenv(n)
1010 	struct namnod	*n;
1011 {
1012 	if (n->namflg & N_ENVNAM)
1013 		n->namflg |= N_EXPORT;
1014 }
1015 void
deexportenv(n)1016 deexportenv(n)
1017 	struct namnod	*n;
1018 {
1019 	if ((n->namflg & (N_ENVNAM|N_EXPORT|N_ENVCHG)) == (N_ENVNAM|N_EXPORT))
1020 		n->namflg &= ~N_EXPORT;
1021 }
1022 #endif
1023 
1024 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN) || defined(DO_SYSLOCAL)
1025 /*
1026  * Push the current value by dulicating the content in
1027  * preparation of a later change of the node value.
1028  */
1029 void
pushval(n,t)1030 pushval(n, t)
1031 	struct namnod	*n;
1032 	void		*t;
1033 {
1034 	struct namnod *nscan = (struct namnod *)alloc(sizeof (*nscan));
1035 
1036 	*nscan = *n;
1037 	n->namval = make(n->namval);
1038 	n->nampush = nscan;
1039 	nscan->funcval = t;
1040 
1041 	attrib(n, t ? N_LOCAL : N_PUSHOV);
1042 }
1043 #endif
1044 
1045 #ifdef	DO_SYSLOCAL
1046 /*
1047  * pop local vars
1048  */
1049 void
poplvars()1050 poplvars()
1051 {
1052 	_poplvars(namep);
1053 }
1054 
1055 static void
_poplvars(np)1056 _poplvars(np)
1057 	struct namnod	*np;
1058 {
1059 	if (np) {
1060 		_poplvars(np->namlft);
1061 		if ((np->namflg & N_LOCAL) != 0) {
1062 			if (localp) {
1063 				while (np->nampush &&
1064 					np->nampush->funcval == localp) {
1065 					popval(np);
1066 				}
1067 			} else {
1068 				do {
1069 					popval(np);
1070 				} while ((np->namflg & N_LOCAL) != 0);
1071 			}
1072 		}
1073 		_poplvars(np->namrgt);
1074 	}
1075 }
1076 
1077 void
printlocal(n)1078 printlocal(n)
1079 	struct namnod	*n;
1080 {
1081 	if (n->namflg & N_LOCAL) {
1082 		unsigned char	*s;
1083 
1084 		prs_buff(UC "local");
1085 		prc_buff(SPACE);
1086 		prs_buff(n->namid);
1087 		if ((s = n->namval) != NULL) {
1088 			prs_buff(UC "='");
1089 			prs_buff(s);
1090 			prc_buff('\'');
1091 		}
1092 		prc_buff(NL);
1093 	}
1094 }
1095 #endif	/* DO_SYSLOCAL */
1096 
1097 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN)
1098 void
popvars()1099 popvars()
1100 {
1101 	_popvars(namep);
1102 }
1103 
1104 static void
_popvars(np)1105 _popvars(np)
1106 	struct namnod	*np;
1107 {
1108 	if (np) {
1109 		_popvars(np->namlft);
1110 		if ((np->namflg & N_PUSHOV) != 0)
1111 			popval(np);
1112 		_popvars(np->namrgt);
1113 	}
1114 }
1115 #endif
1116 
1117 #if !defined(NO_VFORK) || defined(DO_POSIX_SPEC_BLTIN) || defined(DO_SYSLOCAL)
1118 /*
1119  * If the node has a pushed value, restore the original value.
1120  */
1121 void
popval(n)1122 popval(n)
1123 	struct namnod	*n;
1124 {
1125 	if (n->nampush) {
1126 		struct namnod	*p = n->nampush;
1127 
1128 		if (n->namval)
1129 			free(n->namval);
1130 		n->namval = p->namval;
1131 		n->namflg = p->namflg;
1132 		n->nampush = p->nampush;
1133 		free(p);
1134 	} else {
1135 		if (n->namval)
1136 			free(n->namval);
1137 		n->namval = 0;
1138 		n->namflg = N_DEFAULT;
1139 	}
1140 	use(n);
1141 	dolocale((char *)n->namid);
1142 	if (n == &pwdnod) {
1143 		extern	unsigned char	cwdname[];
1144 
1145 		pwdnod.namval = pwdnod.namenv = cwdname;
1146 	}
1147 #ifdef	DO_POSIX_CD
1148 	else if (n == &opwdnod) {
1149 		extern	unsigned char	*ocwdname;
1150 
1151 		opwdnod.namval = opwdnod.namenv = ocwdname;
1152 	}
1153 #endif
1154 }
1155 #endif
1156 
1157 void
setup_env()1158 setup_env()
1159 {
1160 	unsigned char **e = (unsigned char **)environ;
1161 
1162 	while (*e)
1163 		setname(*e++, N_ENVNAM);
1164 }
1165 
1166 
1167 static unsigned char **argnam;
1168 
1169 static void
countnam(n)1170 countnam(n)
1171 	struct namnod	*n;
1172 {
1173 	if (n->namval)
1174 		namec++;
1175 }
1176 
1177 /*
1178  * Set up a single environ entry for a new external command, called only
1179  * local_setenv().
1180  */
1181 static void
pushnam(n)1182 pushnam(n)
1183 	struct namnod	*n;
1184 {
1185 	int	flg = n->namflg;
1186 	unsigned char	*p;
1187 	unsigned char	*namval;
1188 
1189 #ifndef	DO_POSIX_UNSET
1190 	if (((flg & N_ENVCHG) && (flg & N_EXPORT)) || (flg & N_FUNCTN)) {
1191 #else
1192 	if ((flg & N_ENVCHG) && (flg & N_EXPORT)) {
1193 #endif
1194 		namval = n->namval;
1195 	} else {
1196 		/* Discard Local variable in child process */
1197 #ifdef	SUN_EXPORT_BUG
1198 		if (!(flg & ~N_ENVCHG)) {
1199 #else
1200 		if (!(flg & (N_EXPORT | N_ENVNAM))) {
1201 #endif
1202 			if (!(namflg & ENV_NOFREE)) {
1203 				n->namflg = 0;
1204 				n->namenv = 0;
1205 				if (n->namval) {
1206 					/* Release for re-use */
1207 					free(n->namval);
1208 					n->namval = (unsigned char *)NIL;
1209 				}
1210 			}
1211 			namval = (unsigned char *)NIL;
1212 		} else {
1213 			namval = n->namenv;
1214 		}
1215 	}
1216 
1217 	if (namval) {
1218 		p = movstrstak(n->namid, staktop);
1219 		p = movstrstak((unsigned char *)"=", p);
1220 		p = movstrstak(namval, p);
1221 		*argnam++ =
1222 			getstak((Intptr_t)(p + 1 - (unsigned char *)(stakbot)));
1223 	}
1224 }
1225 
1226 /*
1227  * Prepare the environ for a new external command.
1228  * The allocated memory is free()d before starting the next command.
1229  */
1230 unsigned char **
local_setenv(flg)1231 local_setenv(flg)
1232 	int	flg;
1233 {
1234 	unsigned char	**er;
1235 
1236 	namec = 0;
1237 	namscan(countnam);
1238 
1239 	argnam = er = (unsigned char **)getstak((Intptr_t)namec * BYTESPERWORD +
1240 								BYTESPERWORD);
1241 	namflg = flg;
1242 	namscan(pushnam);
1243 	namflg = 0;
1244 	*argnam++ = 0;
1245 	return (er);
1246 }
1247 
1248 /*
1249  * Get a temporary environ, e.g. for a builtin command.
1250  */
1251 unsigned char **
get_envptr()1252 get_envptr()
1253 {
1254 	return (local_setenv(ENV_NOFREE));
1255 }
1256 
1257 struct namnod *
findnam(nam)1258 findnam(nam)
1259 	unsigned char	*nam;
1260 {
1261 	struct namnod	*nscan = namep;
1262 	int		LR;
1263 
1264 	if (!chkid(nam))
1265 		return (0);
1266 	while (nscan) {
1267 		if ((LR = cf(nam, nscan->namid)) == 0)
1268 			return (nscan);
1269 		else if (LR < 0)
1270 			nscan = nscan->namlft;
1271 		else
1272 			nscan = nscan->namrgt;
1273 	}
1274 	return (0);
1275 }
1276 
1277 void
unset_name(name,uflg)1278 unset_name(name, uflg)
1279 	unsigned char	*name;
1280 	int		uflg;
1281 {
1282 	struct namnod	*n;
1283 	unsigned char	call_dolocale = 0;
1284 
1285 	if ((n = findnam(name)) != NULL) {
1286 		if (n->namflg & N_RDONLY) {
1287 #ifdef	DO_POSIX_UNSET
1288 			if (uflg == 0 || uflg == UNSET_VAR)
1289 #endif
1290 				failed(name, wtfailed);
1291 		}
1292 
1293 #ifndef	DO_POSIX_UNSET
1294 		if (n == &pathnod ||
1295 		    n == &ifsnod ||
1296 		    n == &ps1nod ||
1297 		    n == &ps2nod ||
1298 		    n == &mchknod) {
1299 			failed(name, badunset);
1300 		}
1301 #else
1302 		if (n == &mchknod)
1303 			mailchk = 0;
1304 #endif
1305 
1306 #ifndef RES
1307 
1308 		if ((flags & rshflg) && eq(name, "SHELL"))
1309 			failed(name, restricted);
1310 
1311 #endif
1312 
1313 #ifndef	DO_POSIX_UNSET
1314 		if (n->namflg & N_FUNCTN) {
1315 			func_unhash(name);
1316 			freefunc(n);
1317 		} else {
1318 			call_dolocale++;
1319 			free(n->namval);
1320 			free(n->namenv);
1321 		}
1322 		n->namval = n->namenv = 0;
1323 		n->namflg = N_DEFAULT;
1324 #else
1325 		if ((n->namflg & N_FUNCTN) && (uflg & UNSET_FUNC)) {
1326 			func_unhash(name);
1327 			freefunc(n);
1328 			n->funcval = 0;
1329 			n->namflg &= ~N_FUNCTN;
1330 		} else {
1331 			call_dolocale++;
1332 			free(n->namval);
1333 			free(n->namenv);
1334 			n->namval = n->namenv = 0;
1335 			n->namflg &= (N_FUNCTN|N_LOCAL|N_PUSHOV);
1336 		}
1337 #endif
1338 
1339 		if (call_dolocale)
1340 			dolocale((char *)name);
1341 
1342 		if (flags & prompt) {
1343 			if (n == &mailpnod)
1344 				setmail(mailnod.namval);
1345 			else if (n == &mailnod &&
1346 				    (mailpnod.namflg & ~N_FUNCTN) == N_DEFAULT)
1347 				setmail(0);
1348 		}
1349 	}
1350 }
1351 
1352 /*
1353  * The environment variables which affect locale.
1354  * Note: if all names in this list do not begin with 'L',
1355  * you MUST modify dolocale().  Also, be sure that the
1356  * fake_env has the same number of elements as localevar.
1357  */
1358 static char *localevar[] = {
1359 	"LC_ALL",
1360 	"LC_CTYPE",
1361 	"LC_MESSAGES",
1362 	"LC_NUMERIC",
1363 	"LANG",
1364 	0
1365 };
1366 
1367 static char *fake_env[] = {
1368 	0,
1369 	0,
1370 	0,
1371 	0,
1372 	0,
1373 	0
1374 };
1375 
1376 /*
1377  * If name is one of several special variables which affect the locale,
1378  * do a setlocale().
1379  */
1380 static void
dolocale(nm)1381 dolocale(nm)
1382 	char *nm;
1383 {
1384 	char **real_env;
1385 	struct namnod *n;
1386 	int lv, fe;
1387 	int i;
1388 
1389 #ifdef INTERACTIVE
1390 	/*
1391 	 * Only set history size in libshedit if we are
1392 	 * in interactive mode. This allows to avoid  to
1393 	 * load libshedit when interpreting shell scripts.
1394 	 */
1395 	if ((flags & prompt) &&
1396 	    (*nm == 'H') && eq(nm, "HISTORY")) {
1397 			char	*hv = getcurenv(nm);
1398 
1399 		shedit_chghistory(hv ? hv:"0");
1400 	}
1401 #endif
1402 
1403 	/*
1404 	 * Take advantage of fact that names of these vars all start
1405 	 * with 'L' to avoid unnecessary work.
1406 	 * Do locale processing only if /usr is mounted.
1407 	 */
1408 	if ((*nm != 'L') || !localedir_exists ||
1409 	    (!(eq(nm, "LC_ALL") || eq(nm, "LC_CTYPE") ||
1410 	    eq(nm, "LANG") || eq(nm, "LC_MESSAGES") || eq(nm, "LC_NUMERIC"))))
1411 		return;
1412 
1413 	/*
1414 	 * setlocale() has all the smarts built into it, but
1415 	 * it works by examining the environment.  Unfortunately,
1416 	 * when you set an environment variable, the shell does
1417 	 * not modify its own environment; it just remembers that the
1418 	 * variable needs to be exported to any children.  We hack around
1419 	 * this by consing up a fake environment for the use of setlocale()
1420 	 * and substituting it for the real env before calling setlocale().
1421 	 */
1422 
1423 	/*
1424 	 * Build the fake environment.
1425 	 * Look up the value of each of the special environment
1426 	 * variables, and put their value into the fake environment,
1427 	 * if they are exported.
1428 	 */
1429 	for (lv = 0, fe = 0; localevar[lv]; lv++) {
1430 		if ((n = findnam((unsigned char *)localevar[lv]))) {
1431 			char *p, *q;
1432 
1433 			if (!n->namval)
1434 				continue;
1435 
1436 			fake_env[fe++] = p = alloc(length((unsigned char *)
1437 							    localevar[lv])
1438 						+ length(n->namval) + 2);
1439 			/* copy name */
1440 			q = localevar[lv];
1441 			while (*q)
1442 				*p++ = *q++;
1443 
1444 			*p++ = '=';
1445 
1446 			/* copy value */
1447 			q = (char *)(n->namval);
1448 			while (*q)
1449 				*p++ = *q++;
1450 			*p++ = '\0';
1451 		}
1452 	}
1453 	fake_env[fe] = (char *)0;
1454 
1455 	/*
1456 	 * Switch fake env for real and call setlocale().
1457 	 */
1458 	real_env = (char **)environ;
1459 	environ = (char **)fake_env;
1460 
1461 	if (setlocale(LC_ALL, "") == NULL)
1462 		prs(_gettext(badlocale));
1463 
1464 	/*
1465 	 * Switch back and tear down the fake env.
1466 	 */
1467 	environ = (char **)real_env;
1468 	for (i = 0; i < fe; i++) {
1469 		free(fake_env[i]);
1470 		fake_env[i] = (char *)0;
1471 	}
1472 }
1473 
1474 #ifndef	HAVE_ISASTREAM
1475 static int
isastream(fd)1476 isastream(fd)
1477 	int	fd;
1478 {
1479 	int	ret = 0;
1480 
1481 	if (isatty(fd))
1482 		return (1);
1483 
1484 #ifdef	I_CANPUT
1485 	ret = ioctl(fd, I_CANPUT, 0);
1486 	if (ret == -1 && errno == EBADF)
1487 		return (-1);
1488 
1489 	errno = 0;
1490 	if (ret == 0 || ret == 1)
1491 		ret = 1;
1492 #endif
1493 	return (ret);
1494 }
1495 #endif
1496 
1497 #ifdef INTERACTIVE
1498 /*
1499  * Functions needed by the history editor.
1500  */
1501 char *
getcurenv(name)1502 getcurenv(name)
1503 	char	*name;
1504 {
1505 	struct namnod *n;
1506 
1507 	n = findnam((unsigned char *)name);
1508 	return (n ? (char *)n->namval:NULL);
1509 }
1510 
1511 void
ev_insert(name)1512 ev_insert(name)
1513 	char	*name;
1514 {
1515 	struct namnod	*n;
1516 	char		*p = strchr(name, '=');
1517 
1518 	if (p == NULL)
1519 		return;
1520 
1521 	*p = '\0';
1522 	n = lookup((unsigned char *)name);
1523 	*p = '=';
1524 	if (n == 0)
1525 		return;
1526 
1527 	assign(n, (unsigned char *)&p[1]);
1528 
1529 	n->namflg |= N_EXPORT;
1530 }
1531 #endif /* INTERACTIVE */
1532