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