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  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 /*
32  * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
33  *
34  * Sccsid @(#)name.c	1.15 (gritter) 7/3/05
35  */
36 /* from OpenSolaris "name.c	1.23	05/06/08 SMI" */
37 /*
38  * UNIX shell
39  */
40 
41 #include	"defs.h"
42 #ifdef	__sun
43 #include	<stropts.h>
44 #endif
45 
46 extern char	**environ;
47 extern int	mailchk;
48 
49 static void set_builtins_path(void);
50 static int patheq(register unsigned char *, register char *);
51 static void namwalk(register struct namnod *);
52 static void countnam(struct namnod *);
53 static void pushnam(register struct namnod *);
54 static void dolocale(char *);
55 
56 struct namnod ps2nod =
57 {
58 	(struct namnod *)NIL,
59 	&acctnod,
60 	(unsigned char *)ps2name
61 };
62 struct namnod cdpnod =
63 {
64 	(struct namnod *)NIL,
65 	(struct namnod *)NIL,
66 	(unsigned char *)cdpname
67 };
68 struct namnod pathnod =
69 {
70 	&mailpnod,
71 	(struct namnod *)NIL,
72 	(unsigned char *)pathname
73 };
74 struct namnod ifsnod =
75 {
76 	&homenod,
77 	&mailnod,
78 	(unsigned char *)ifsname
79 };
80 struct namnod ps1nod =
81 {
82 	&pathnod,
83 	&ps2nod,
84 	(unsigned char *)ps1name
85 };
86 struct namnod homenod =
87 {
88 	&cdpnod,
89 	(struct namnod *)NIL,
90 	(unsigned char *)homename
91 };
92 struct namnod mailnod =
93 {
94 	(struct namnod *)NIL,
95 	(struct namnod *)NIL,
96 	(unsigned char *)mailname
97 };
98 struct namnod mchknod =
99 {
100 	&ifsnod,
101 	&ps1nod,
102 	(unsigned char *)mchkname
103 };
104 struct namnod acctnod =
105 {
106 	(struct namnod *)NIL,
107 	&timeoutnod,
108 	(unsigned char *)acctname
109 };
110 struct namnod mailpnod =
111 {
112 	(struct namnod *)NIL,
113 	(struct namnod *)NIL,
114 	(unsigned char *)mailpname
115 };
116 struct namnod timeoutnod =
117 {
118 	(struct namnod *)NIL,
119 	(struct namnod *)NIL,
120 	(unsigned char *)timeoutname
121 };
122 
123 
124 struct namnod *namep = &mchknod;
125 
126 /* ========	variable and string handling	======== */
127 
128 int
syslook(register unsigned char * w,register const struct sysnod syswds[],int n)129 syslook(register unsigned char *w, register const struct sysnod syswds[], int n)
130 {
131 	int	low;
132 	int	high;
133 	int	mid;
134 	register int cond;
135 
136 	if (w == 0 || *w == 0)
137 		return(0);
138 
139 	low = 0;
140 	high = n - 1;
141 
142 	while (low <= high)
143 	{
144 		mid = (low + high) / 2;
145 
146 		if ((cond = cf(w, syswds[mid].sysnam)) < 0)
147 			high = mid - 1;
148 		else if (cond > 0)
149 			low = mid + 1;
150 		else
151 			return(syswds[mid].sysval);
152 	}
153 	return(0);
154 }
155 
156 void
setlist(register struct argnod * arg,int xp)157 setlist(register struct argnod *arg, int xp)
158 {
159 	if (flags & exportflg)
160 		xp |= N_EXPORT;
161 
162 	while (arg)
163 	{
164 		register unsigned char *s = mactrim(arg->argval);
165 		setname(s, xp);
166 		arg = arg->argnxt;
167 		if (flags & execpr)
168 		{
169 			prs(s);
170 			if (arg)
171 				blank();
172 			else
173 				newline();
174 		}
175 	}
176 }
177 
178 
179 void
setname(unsigned char * argi,int xp)180 setname (	/* does parameter assignments */
181     unsigned char *argi,
182     int xp
183 )
184 {
185 	register unsigned char *argscan = argi;
186 	register struct namnod *n;
187 
188 	if (letter(*argscan))
189 	{
190 		while (alphanum(*argscan))
191 			argscan++;
192 
193 		if (*argscan == '=')
194 		{
195 			*argscan = 0;	/* make name a cohesive string */
196 
197 			n = lookup(argi);
198 			*argscan++ = '=';
199 			attrib(n, xp);
200 			if (xp & N_ENVNAM)
201 			{
202 				n->namenv = n->namval = argscan;
203 				if (n == &pathnod)
204 					set_builtins_path();
205 			}
206 			else
207 				assign(n, argscan);
208 
209 			dolocale(n->namid);
210 			return;
211 		}
212 	}
213 }
214 
215 void
replace(register unsigned char ** a,const unsigned char * v)216 replace(register unsigned char **a, const unsigned char *v)
217 {
218 	free(*a);
219 	*a = make(v);
220 }
221 
222 void
dfault(struct namnod * n,const unsigned char * v)223 dfault(struct namnod *n, const unsigned char *v)
224 {
225 	if (n->namval == 0)
226 		assign(n, v);
227 }
228 
229 void
assign(struct namnod * n,const unsigned char * v)230 assign(struct namnod *n, const unsigned char *v)
231 {
232 	if (n->namflg & N_RDONLY)
233 		failed(n->namid, wtfailed);
234 
235 #ifndef RES
236 
237 	else if (flags & rshflg)
238 	{
239 		if (n == &pathnod || eq(n->namid,"SHELL"))
240 			failed(n->namid, restricted);
241 	}
242 #endif
243 
244 	else if (n->namflg & N_FUNCTN)
245 	{
246 		func_unhash(n->namid);
247 		freefunc(n);
248 
249 		n->namenv = 0;
250 		n->namflg = N_DEFAULT;
251 	}
252 
253 	if (n == &mchknod)
254 	{
255 		mailchk = stoi(v);
256 	}
257 
258 	replace(&n->namval, v);
259 	attrib(n, N_ENVCHG);
260 
261 	if (n == &pathnod)
262 	{
263 		zaphash();
264 		set_dotpath();
265 		set_builtins_path();
266 		return;
267 	}
268 
269 	if (flags & prompt)
270 	{
271 		if ((n == &mailpnod) || (n == &mailnod && mailpnod.namflg == N_DEFAULT))
272 			setmail(n->namval);
273 	}
274 }
275 
276 static void
set_builtins_path(void)277 set_builtins_path(void)
278 {
279         register unsigned char *path;
280 
281         ucb_builtins = 0;
282         path = getpath("");
283         while (path && *path)
284         {
285                 if (patheq(path, "/usr/ucb"))
286                 {
287                         ucb_builtins++;
288                         break;
289                 }
290                 else if (patheq(path, "/usr/bin"))
291                         break;
292                 else if (patheq(path, "/bin"))
293                         break;
294                 else if (patheq(path, "/usr/5bin"))
295                         break;
296                 path = nextpath(path);
297         }
298 }
299 
300 static int
patheq(register unsigned char * component,register char * dir)301 patheq(register unsigned char *component, register char *dir)
302 {
303         register unsigned char   c;
304 
305         for (;;)
306         {
307                 c = *component++;
308                 if (c == COLON)
309                         c = '\0';       /* end of component of path */
310                 if (c != *dir++)
311                         return(0);
312                 if (c == '\0')
313                         return(1);
314         }
315 }
316 
317 int
readvar(unsigned char ** names)318 readvar(unsigned char **names)
319 {
320 	struct fileblk	fb;
321 	register struct fileblk *f = &fb;
322 	unsigned char	c[MULTI_BYTE_MAX+1];
323 	register int	rc = 0;
324 	struct namnod *n;
325 	unsigned char	*rel;
326 	unsigned char *oldstak;
327 	register unsigned char *pc, *rest;
328 	int		d;
329 	unsigned int	(*newwc)(void);
330 	extern const char	badargs[];
331 
332 	if (eq(*names, "-r")) {
333 		if (*++names == NULL)
334 			error(badargs);
335 		newwc = readwc;
336 	} else
337 		newwc = nextwc;
338 	n = lookup(*names++);	/* done now to avoid storage mess */
339 	rel = (unsigned char *)relstak();
340 	push(f);
341 	initf(dup(0));
342 
343 	/*
344 	 * If stdin is a pipe then this lseek(2) will fail with ESPIPE, so
345 	 * the read buffer size is set to 1 because we will not be able
346 	 * lseek(2) back towards the beginning of the file, so we have
347 	 * to read a byte at a time instead
348 	 *
349 	 */
350 	if (lseek(0, (off_t)0, SEEK_CUR) == -1)
351 		f->fsiz = 1;
352 
353 #ifdef	__sun
354 	/*
355 	 * If stdin is a socket then this isastream(3C) will return 1, so
356 	 * the read buffer size is set to 1 because we will not be able
357 	 * lseek(2) back towards the beginning of the file, so we have
358 	 * to read a byte at a time instead
359 	 *
360 	 */
361 	if (isastream(0) == 1)
362 		f->fsiz = 1;
363 #endif
364 
365 	/*
366 	 * strip leading IFS characters
367 	 */
368 	for (;;)
369 	{
370 		d = newwc();
371 		if(eolchar(d))
372 			break;
373 		rest = readw(d);
374 		pc = c;
375 		while(*pc++ = *rest++);
376 		if(!anys(c, ifsnod.namval))
377 			break;
378 	}
379 
380 	oldstak = curstak();
381 	for (;;)
382 	{
383 		if ((*names && anys(c, ifsnod.namval)) || eolchar(d))
384 		{
385 			if (staktop >= brkend)
386 				growstak(staktop);
387 			zerostak();
388 			assign(n, absstak(rel));
389 			setstak(rel);
390 			if (*names)
391 				n = lookup(*names++);
392 			else
393 				n = 0;
394 			if (eolchar(d))
395 			{
396 				break;
397 			}
398 			else		/* strip imbedded IFS characters */
399 				while(1) {
400 					d = newwc();
401 					if(eolchar(d))
402 						break;
403 					rest = readw(d);
404 					pc = c;
405 					while(*pc++ = *rest++);
406 					if(!anys(c, ifsnod.namval))
407 						break;
408 				}
409 		}
410 		else
411 		{
412 			if(d == '\\' && newwc == nextwc) {
413 				d = newwc();
414 				rest = readw(d);
415 				while(d = *rest++) {
416 					if (staktop >= brkend)
417 						growstak(staktop);
418 					pushstak(d);
419 				}
420 				oldstak = staktop;
421 			}
422 			else
423 			{
424 				pc = c;
425 				while(d = *pc++) {
426 					if (staktop >= brkend)
427 						growstak(staktop);
428 					pushstak(d);
429 				}
430 				if(!anys(c, ifsnod.namval))
431 					oldstak = staktop;
432 			}
433 			d = newwc();
434 
435 			if (eolchar(d))
436 				staktop = oldstak;
437 			else
438 			{
439 				rest = readw(d);
440 				pc = c;
441 				while(*pc++ = *rest++);
442 			}
443 		}
444 	}
445 	while (n)
446 	{
447 		assign(n, nullstr);
448 		if (*names)
449 			n = lookup(*names++);
450 		else
451 			n = 0;
452 	}
453 
454 	if (eof)
455 		rc = 1;
456 
457 #ifdef	__sun
458 	if (isastream(0) != 1)
459 #endif
460 		/*
461 		 * If we are reading on a stream do not attempt to
462 		 * lseek(2) back towards the start because this is
463 		 * logically meaningless, but there is nothing in
464 		 * the standards to pervent the stream implementation
465 		 * from attempting it and breaking our code here
466 		 *
467 		 */
468 		lseek(0, (off_t)(f->nxtoff - f->endoff), SEEK_CUR);
469 
470 	pop();
471 	return(rc);
472 }
473 
474 void
assnum(unsigned char ** p,long i)475 assnum(unsigned char **p, long i)
476 {
477 	int j = ltos(i);
478 	replace(p, &numbuf[j]);
479 }
480 
481 unsigned char *
make(const unsigned char * v)482 make(const unsigned char *v)
483 {
484 	register unsigned char	*p;
485 
486 	if (v)
487 	{
488 		movstr(v, p = (unsigned char *)alloc(length(v)));
489 		return(p);
490 	}
491 	else
492 		return(0);
493 }
494 
495 
496 struct namnod *
lookup(register unsigned char * nam)497 lookup(register unsigned char *nam)
498 {
499 	register struct namnod *nscan = namep;
500 	register struct namnod **prev = NULL;
501 	int		LR;
502 
503 	if (!chkid(nam))
504 		failed(nam, notid);
505 
506 	while (nscan)
507 	{
508 		if ((LR = cf(nam, nscan->namid)) == 0)
509 			return(nscan);
510 
511 		else if (LR < 0)
512 			prev = &(nscan->namlft);
513 		else
514 			prev = &(nscan->namrgt);
515 		nscan = *prev;
516 	}
517 	/*
518 	 * add name node
519 	 */
520 	nscan = (struct namnod *)alloc(sizeof *nscan);
521 	nscan->namlft = nscan->namrgt = (struct namnod *)NIL;
522 	nscan->namid = make(nam);
523 	nscan->namval = 0;
524 	nscan->namflg = N_DEFAULT;
525 	nscan->namenv = 0;
526 
527 	return(*prev = nscan);
528 }
529 
530 BOOL
chkid(unsigned char * nam)531 chkid(unsigned char *nam)
532 {
533 	register unsigned char *cp = nam;
534 
535 	if (!letter(*cp))
536 		return(FALSE);
537 	else
538 	{
539 		while (*++cp)
540 		{
541 			if (!alphanum(*cp))
542 				return(FALSE);
543 		}
544 	}
545 	return(TRUE);
546 }
547 
548 static void (*namfn)(struct namnod *);
549 void
namscan(void (* fn)(struct namnod *))550 namscan(void (*fn)(struct namnod *))
551 {
552 	namfn = fn;
553 	namwalk(namep);
554 }
555 
556 static void
namwalk(register struct namnod * np)557 namwalk(register struct namnod *np)
558 {
559 	if (np)
560 	{
561 		namwalk(np->namlft);
562 		(*namfn)(np);
563 		namwalk(np->namrgt);
564 	}
565 }
566 
567 void
printnam(struct namnod * n)568 printnam(struct namnod *n)
569 {
570 	register unsigned char	*s;
571 
572 	sigchk();
573 
574 	if (n->namflg & N_FUNCTN)
575 	{
576 		prs_buff(n->namid);
577 		prs_buff("(){\n");
578 		prf((struct trenod *)n->namenv);
579 		prs_buff("\n}\n");
580 	}
581 	else if (s = n->namval)
582 	{
583 		prs_buff(n->namid);
584 		prc_buff('=');
585 		prs_buff(s);
586 		prc_buff(NL);
587 	}
588 }
589 
590 static int namec;
591 
592 void
exname(register struct namnod * n)593 exname(register struct namnod *n)
594 {
595 	register int 	flg = n->namflg;
596 
597 	if (flg & N_ENVCHG)
598 	{
599 
600 		if (flg & N_EXPORT)
601 		{
602 			free(n->namenv);
603 			n->namenv = make(n->namval);
604 		}
605 		else
606 		{
607 			free(n->namval);
608 			n->namval = make(n->namenv);
609 		}
610 	}
611 
612 
613 	if (!(flg & N_FUNCTN))
614 		n->namflg = N_DEFAULT;
615 
616 	if (n->namval)
617 		namec++;
618 
619 }
620 
621 void
printro(register struct namnod * n)622 printro(register struct namnod *n)
623 {
624 	if (n->namflg & N_RDONLY)
625 	{
626 		prs_buff(readonly);
627 		prc_buff(SPACE);
628 		prs_buff(n->namid);
629 		prc_buff(NL);
630 	}
631 }
632 
633 void
printexp(register struct namnod * n)634 printexp(register struct namnod *n)
635 {
636 	if (n->namflg & N_EXPORT)
637 	{
638 		prs_buff(export);
639 		prc_buff(SPACE);
640 		prs_buff(n->namid);
641 		prc_buff(NL);
642 	}
643 }
644 
645 void
setup_env(void)646 setup_env(void)
647 {
648 	register char **e = environ;
649 
650 	while (*e)
651 		setname(*e++, N_ENVNAM);
652 }
653 
654 
655 static unsigned char **argnam;
656 
657 static void
countnam(struct namnod * n)658 countnam(struct namnod *n)
659 {
660 	if (n->namval)
661 		namec++;
662 }
663 
664 static void
pushnam(register struct namnod * n)665 pushnam(register struct namnod *n)
666 {
667 	register int 	flg = n->namflg;
668 	register unsigned char	*p;
669 	register unsigned char	*namval;
670 
671 	if (((flg & N_ENVCHG) && (flg & N_EXPORT)) || (flg & N_FUNCTN))
672 		namval = n->namval;
673 	else {
674 		/* Discard Local variable in child process */
675 		if (!(flg & ~N_ENVCHG)) {
676 			n->namflg = 0;
677 			n->namenv = 0;
678 			if (n->namval) {
679 				/* Release for re-use */
680 				free(n->namval);
681 				n->namval = (unsigned char *)NIL;
682 			}
683 		}
684 		namval = n->namenv;
685 	}
686 
687 	if (namval)
688 	{
689 		p = movstrstak(n->namid, staktop);
690 		p = movstrstak("=", p);
691 		p = movstrstak(namval, p);
692 		*argnam++ = getstak(p + 1 - (unsigned char *)(stakbot));
693 	}
694 }
695 
696 unsigned char **
local_setenv(void)697 local_setenv(void)
698 {
699 	register unsigned char	**er;
700 
701 	namec = 0;
702 	namscan(countnam);
703 
704 	argnam = er = (unsigned char **)getstak(namec * BYTESPERWORD + BYTESPERWORD);
705 	namscan(pushnam);
706 	*argnam++ = 0;
707 	return(er);
708 }
709 
710 void
setvars(void)711 setvars(void)
712 {
713 	namscan(exname);
714 }
715 
716 struct namnod *
findnam(register unsigned char * nam)717 findnam(register unsigned char *nam)
718 {
719 	register struct namnod *nscan = namep;
720 	int		LR;
721 
722 	if (!chkid(nam))
723 		return(0);
724 	while (nscan)
725 	{
726 		if ((LR = cf(nam, nscan->namid)) == 0)
727 			return(nscan);
728 		else if (LR < 0)
729 			nscan = nscan->namlft;
730 		else
731 			nscan = nscan->namrgt;
732 	}
733 	return(0);
734 }
735 
736 
737 void
unset_name(register unsigned char * name)738 unset_name(register unsigned char *name)
739 {
740 	register struct namnod	*n;
741 	register unsigned char 	call_dolocale = 0;
742 
743 	if (n = findnam(name))
744 	{
745 		if (n->namflg & N_RDONLY)
746 			failed(name, wtfailed);
747 
748 		if (n == &pathnod ||
749 		    n == &ifsnod ||
750 		    n == &ps1nod ||
751 		    n == &ps2nod ||
752 		    n == &mchknod)
753 		{
754 			failed(name, badunset);
755 		}
756 
757 #ifndef RES
758 
759 		if ((flags & rshflg) && eq(name, "SHELL"))
760 			failed(name, restricted);
761 
762 #endif
763 
764 		if (n->namflg & N_FUNCTN)
765 		{
766 			func_unhash(name);
767 			freefunc(n);
768 		}
769 		else
770 		{
771 			call_dolocale++;
772 			free(n->namval);
773 			free(n->namenv);
774 		}
775 
776 		n->namval = n->namenv = 0;
777 		n->namflg = N_DEFAULT;
778 
779 		if (call_dolocale)
780 			dolocale(name);
781 
782 		if (flags & prompt)
783 		{
784 			if (n == &mailpnod)
785 				setmail(mailnod.namval);
786 			else if (n == &mailnod && mailpnod.namflg == N_DEFAULT)
787 				setmail(0);
788 		}
789 	}
790 }
791 
792 /*
793  * The environment variables which affect locale.
794  * Note: if all names in this list do not begin with 'L',
795  * you MUST modify dolocale().  Also, be sure that the
796  * fake_env has the same number of elements as localevar.
797  */
798 static char *localevar[] = {
799 	"LC_ALL",
800 	"LC_CTYPE",
801 	"LANG",
802 	0
803 };
804 
805 static char *fake_env[] = {
806 	0,
807 	0,
808 	0,
809 	0,
810 	0
811 };
812 
813 /*
814  * If name is one of several special variables which affect the locale,
815  * do a setlocale().
816  */
817 static void
dolocale(char * nm)818 dolocale(char *nm)
819 {
820 	char **real_env;
821 	struct namnod *n;
822 	int lv, fe;
823 	int i;
824 
825 	/*
826 	 * Take advantage of fact that names of these vars all start
827 	 * with 'L' to avoid unnecessary work.
828 	 */
829 	if ((*nm != 'L') ||
830 	    (!(eq(nm, "LC_ALL") || eq(nm, "LC_CTYPE") || eq(nm, "LANG"))))
831 		return;
832 
833 	/*
834 	 * setlocale() has all the smarts built into it, but
835 	 * it works by examining the environment.  Unfortunately,
836 	 * when you set an environment variable, the shell does
837 	 * not modify its own environment; it just remembers that the
838 	 * variable needs to be exported to any children.  We hack around
839 	 * this by consing up a fake environment for the use of setlocale()
840 	 * and substituting it for the real env before calling setlocale().
841 	 */
842 
843 	/*
844 	 * Build the fake environment.
845 	 * Look up the value of each of the special environment
846 	 * variables, and put their value into the fake environment,
847 	 * if they are exported.
848 	 */
849 	for (lv = 0, fe = 0; localevar[lv]; lv++) {
850 		if ((n = findnam(localevar[lv]))) {
851 			register char *p, *q;
852 
853 			if (!n->namval)
854 				continue;
855 
856 			fake_env[fe++] = p = alloc(length(localevar[lv])
857 					       + length(n->namval) + 2);
858 			/* copy name */
859 			q = localevar[lv];
860 			while (*q)
861 				*p++ = *q++;
862 
863 			*p++ = '=';
864 
865 			/* copy value */
866 			q = (char*)(n->namval);
867 			while (*q)
868 				*p++ = *q++;
869 			*p++ = '\0';
870 		}
871 	}
872 	fake_env[fe] = (char *)0;
873 
874 	/*
875 	 * Switch fake env for real and call setlocale().
876 	 */
877 	real_env = (char **)environ;
878 	environ = fake_env;
879 
880 	setlocale(LC_CTYPE, "");
881 
882 	/*
883 	 * Switch back and tear down the fake env.
884 	 */
885 	environ = real_env;
886 	for (i = 0; i < fe; i++) {
887 		free(fake_env[i]);
888 		fake_env[i] = (char *)0;
889 	}
890 	mb_cur_max = MB_CUR_MAX;
891 }
892 
893 int	mb_cur_max = 1;
894