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