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