Home | History | Annotate | Download | only in sh
      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