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  *
     32  * UNIX shell
     33  *
     34  */
     35 
     36 
     37 #include	"defs.h"
     38 #include	<errno.h>
     39 #include	"sym.h"
     40 #include	"hash.h"
     41 #include	<sys/types.h>
     42 #include	<sys/times.h>
     43 
     44 pid_t parent;
     45 
     46 void execprint(unsigned char **);
     47 
     48 /* ========	command execution	======== */
     49 
     50 /*VARARGS3*/
     51 int
     52 execute(argt, xflags, errorflg, pf1, pf2)
     53 struct trenod *argt;
     54 int xflags, errorflg;
     55 int *pf1, *pf2;
     56 {
     57 	/*
     58 	 * `stakbot' is preserved by this routine
     59 	 */
     60 	struct trenod	*t;
     61 	unsigned char		*sav = savstak();
     62 
     63 	sigchk();
     64 	if (!errorflg)
     65 		flags &= ~errflg;
     66 
     67 	if ((t = argt) && execbrk == 0) {
     68 		int treeflgs;
     69 		unsigned char **com;
     70 		int type;
     71 		short pos;
     72 
     73 		treeflgs = t->tretyp;
     74 		type = treeflgs & COMMSK;
     75 
     76 		switch (type)
     77 		{
     78 		case TFND:
     79 			{
     80 				struct fndnod	*f = fndptr(t);
     81 				struct namnod	*n = lookup(f->fndnam);
     82 
     83 				exitval = 0;
     84 
     85 				if (n->namflg & N_RDONLY)
     86 					failed(n->namid, wtfailed);
     87 
     88 				if (flags & rshflg && (n == &pathnod ||
     89 					eq(n->namid, "SHELL")))
     90 					failed(n->namid, restricted);
     91 				/*
     92 				 * If function of same name is previously
     93 				 * defined, it will no longer be used.
     94 				 */
     95 				if (n->namflg & N_FUNCTN) {
     96 					freefunc(n);
     97 				} else {
     98 					free(n->namval);
     99 					free(n->namenv);
    100 
    101 					n->namval = 0;
    102 					n->namflg &= ~(N_EXPORT | N_ENVCHG);
    103 				}
    104 				/*
    105 				 * If function is defined within function,
    106 				 * we don't want to free it along with the
    107 				 * free of the defining function. If we are
    108 				 * in a loop, fndnod may be reused, so it
    109 				 * should never be freed.
    110 				 */
    111 				if (funcnt != 0 || loopcnt != 0)
    112 					f->fndref++;
    113 
    114 				/*
    115 				 * We hang a fndnod on the namenv so that
    116 				 * ref cnt(fndref) can be increased while
    117 				 * running in the function.
    118 				 */
    119 				n->namenv = (unsigned char *)f;
    120 				attrib(n, N_FUNCTN);
    121 				hash_func(n->namid);
    122 				break;
    123 			}
    124 
    125 		case TCOM:
    126 			{
    127 				unsigned char	*a1, *name;
    128 				int	argn, internal;
    129 				struct argnod	*schain = gchain;
    130 				struct ionod	*io = t->treio;
    131 				short 	cmdhash;
    132 				short	comtype;
    133 
    134 				exitval = 0;
    135 
    136 				gchain = 0;
    137 				argn = getarg(t);
    138 				com = scan(argn);
    139 				a1 = com[1];
    140 				gchain = schain;
    141 
    142 				if (argn != 0)
    143 					cmdhash = pathlook(com[0], 1, comptr(t)->comset);
    144 
    145 				if (argn == 0 || (comtype = hashtype(cmdhash)) == BUILTIN) {
    146 					setlist(comptr(t)->comset, 0);
    147 				}
    148 
    149 				if (argn && (flags&noexec) == 0)
    150 				{
    151 
    152 					/* print command if execpr */
    153 					if (flags & execpr)
    154 						execprint(com);
    155 
    156 					if (comtype == NOTFOUND)
    157 					{
    158 						pos = hashdata(cmdhash);
    159 						if (pos == 1)
    160 							failure(*com, notfound);
    161 						else if (pos == 2)
    162 							failure(*com, badexec);
    163 						else
    164 							failure(*com, badperm);
    165 						break;
    166 					}
    167 
    168 					else if (comtype == PATH_COMMAND)
    169 					{
    170 						pos = -1;
    171 					}
    172 
    173 					else if (comtype & (COMMAND | REL_COMMAND))
    174 					{
    175 						pos = hashdata(cmdhash);
    176 					}
    177 
    178 					else if (comtype == BUILTIN) {
    179 						builtin(hashdata(cmdhash),argn,com,t);
    180 						freejobs();
    181 						break;
    182 					}
    183 					else if (comtype == FUNCTION)
    184 					{
    185 						struct dolnod *olddolh;
    186 						struct namnod *n, *opt;
    187 						struct fndnod *f;
    188 						short index;
    189 						unsigned char **olddolv = dolv;
    190 						int olddolc = dolc;
    191 
    192 						n = findnam(com[0]);
    193 						f = fndptr(n->namenv);
    194 						/* just in case */
    195 						if (f == NULL)
    196 							break;
    197 					/* save current positional parameters */
    198 						olddolh = (struct dolnod *)savargs(funcnt);
    199 						f->fndref++;
    200 						funcnt++;
    201 						index = initio(io, 1);
    202 						setargs(com);
    203 						execute(f->fndval, xflags,
    204 						    errorflg, pf1, pf2);
    205 						execbrk = 0;
    206 						restore(index);
    207 						(void) restorargs(olddolh, funcnt);
    208 						dolv = olddolv;
    209 						dolc = olddolc;
    210 						funcnt--;
    211 						/*
    212 						 * n->namenv may have been
    213 						 * pointing different func.
    214 						 * Therefore, we can't use
    215 						 * freefunc(n).
    216 						 */
    217 						freetree((struct trenod *)f);
    218 
    219 						break;
    220 					}
    221 				}
    222 				else if (t->treio == 0)
    223 				{
    224 					chktrap();
    225 					break;
    226 				}
    227 
    228 			}
    229 
    230 		case TFORK:
    231 		{
    232 			int monitor = 0;
    233 			int linked = 0;
    234 
    235 			exitval = 0;
    236 
    237 			if (!(xflags & XEC_EXECED) || treeflgs&(FPOU|FAMP))
    238 			{
    239 
    240 				int forkcnt = 1;
    241 
    242 				if (!(treeflgs&FPOU))
    243 				{
    244 					monitor = (!(xflags & XEC_NOSTOP)
    245 					  && (flags&(monitorflg|jcflg|jcoff))
    246 					  == (monitorflg|jcflg));
    247 					if (monitor) {
    248 						int savefd;
    249 						unsigned char *savebot;
    250 						savefd = setb(-1);
    251 						savebot = stakbot;
    252 						prcmd(t);
    253 						(void)setb(savefd);
    254 						allocjob(savebot, cwdget(), monitor);
    255 					} else
    256 						allocjob("", "", 0);
    257 
    258 				}
    259 
    260 				if (treeflgs & (FPOU|FAMP)) {
    261 					link_iodocs(iotemp);
    262 					linked = 1;
    263 				}
    264 
    265 				while ((parent = fork()) == -1)
    266 				{
    267 				/*
    268 				 * FORKLIM is the max period between forks -
    269 				 * power of 2 usually.	Currently shell tries
    270 				 * after 2,4,8,16, and 32 seconds and then quits
    271 				 */
    272 
    273 				if ((forkcnt = (forkcnt * 2)) > FORKLIM)
    274 				{
    275 					switch (errno)
    276 					{
    277 					case ENOMEM:
    278 						deallocjob();
    279 						error(noswap);
    280 						break;
    281 					default:
    282 						deallocjob();
    283 						error(nofork);
    284 						break;
    285 					}
    286 				} else if (errno == EPERM) {
    287 					deallocjob();
    288 					error(eacces);
    289 					break;
    290 				}
    291 				sigchk();
    292 				sh_sleep(forkcnt);
    293 				}
    294 
    295 				if (parent) {
    296 					if (monitor)
    297 						setpgid(parent, 0);
    298 					if (treeflgs & FPIN)
    299 						closepipe(pf1);
    300 					if (!(treeflgs&FPOU)) {
    301 						postjob(parent,!(treeflgs&FAMP));
    302 						freejobs();
    303 					}
    304 					chktrap();
    305 					break;
    306 				}
    307 				mypid = getpid();
    308 			}
    309 
    310 			/*
    311 			 * Forked process:  assume it is not a subshell for
    312 			 * now.  If it is, the presence of a left parenthesis
    313 			 * will trigger the jcoff flag to be turned off.
    314 			 * When jcoff is turned on, monitoring is not going on
    315 			 * and waitpid will not look for WUNTRACED.
    316 			 */
    317 
    318 			flags |= (forked|jcoff);
    319 
    320 			fiotemp  = 0;
    321 
    322 			if (linked == 1) {
    323 				swap_iodoc_nm(iotemp);
    324 				xflags |= XEC_LINKED;
    325 			} else if (!(xflags & XEC_LINKED))
    326 				iotemp = 0;
    327 #ifdef ACCT
    328 			suspacct();
    329 #endif
    330 			settmp();
    331 			oldsigs();
    332 
    333 			if (!(treeflgs & FPOU))
    334 				makejob(monitor, !(treeflgs & FAMP));
    335 
    336 			/*
    337 			 * pipe in or out
    338 			 */
    339 			if (treeflgs & FPIN)
    340 			{
    341 				renamef(pf1[INPIPE], 0);
    342 				close(pf1[OTPIPE]);
    343 			}
    344 
    345 			if (treeflgs & FPOU)
    346 			{
    347 				close(pf2[INPIPE]);
    348 				renamef(pf2[OTPIPE], 1);
    349 			}
    350 
    351 			/*
    352 			 * io redirection
    353 			 */
    354 			initio(t->treio, 0);
    355 
    356 			if (type == TFORK)
    357 				execute(forkptr(t)->forktre, xflags | XEC_EXECED, errorflg);
    358 			else if (com[0] != ENDARGS)
    359 			{
    360 				eflag = 0;
    361 				setlist(comptr(t)->comset, N_EXPORT);
    362 				rmtemp(0);
    363 				clearjobs();
    364 				execa(com, pos);
    365 			}
    366 			done(0);
    367 		}
    368 
    369 		case TPAR:
    370 			/* Forked process is subshell:  may want job control */
    371 			flags &= ~jcoff;
    372 			clearjobs();
    373 			execute(parptr(t)->partre, xflags, errorflg);
    374 			done(0);
    375 
    376 		case TFIL:
    377 			{
    378 				int pv[2];
    379 
    380 				chkpipe(pv);
    381 				if (execute(lstptr(t)->lstlef, xflags & XEC_NOSTOP, errorflg, pf1, pv) == 0)
    382 					execute(lstptr(t)->lstrit, xflags, errorflg, pv, pf2);
    383 				else
    384 					closepipe(pv);
    385 			}
    386 			break;
    387 
    388 		case TLST:
    389 			execute(lstptr(t)->lstlef, xflags&XEC_NOSTOP, errorflg);
    390 			/* Update errorflg if set -e is invoked in the sub-sh*/
    391 			execute(lstptr(t)->lstrit, xflags, (errorflg | (eflag & errflg)));
    392 			break;
    393 
    394 		case TAND:
    395 		case TORF:
    396 		{
    397 			int xval;
    398 			xval = execute(lstptr(t)->lstlef, XEC_NOSTOP, 0);
    399 			if ((xval == 0) == (type == TAND))
    400 				execute(lstptr(t)->lstrit, xflags|XEC_NOSTOP, errorflg);
    401 			break;
    402 		}
    403 
    404 		case TFOR:
    405 			{
    406 				struct namnod *n = lookup(forptr(t)->fornam);
    407 				unsigned char	**args;
    408 				struct dolnod *argsav = 0;
    409 
    410 				if (forptr(t)->forlst == 0)
    411 				{
    412 					args = dolv + 1;
    413 					argsav = useargs();
    414 				}
    415 				else
    416 				{
    417 					struct argnod *schain = gchain;
    418 
    419 					gchain = 0;
    420 					args = scan(getarg(forptr(t)->forlst));
    421 					gchain = schain;
    422 				}
    423 				loopcnt++;
    424 				while (*args != ENDARGS && execbrk == 0)
    425 				{
    426 					assign(n, *args++);
    427 					execute(forptr(t)->fortre, XEC_NOSTOP, errorflg);
    428 					if (breakcnt < 0)
    429 						execbrk = (++breakcnt != 0);
    430 				}
    431 				if (breakcnt > 0)
    432 						execbrk = (--breakcnt != 0);
    433 
    434 				loopcnt--;
    435 				if(argsav)
    436 					argfor = (struct dolnod *)freeargs(argsav);
    437 			}
    438 			break;
    439 
    440 		case TWH:
    441 		case TUN:
    442 			{
    443 				int	i = 0;
    444 
    445 				loopcnt++;
    446 				while (execbrk == 0 && (execute(whptr(t)->whtre,
    447 				    XEC_NOSTOP, 0) == 0) == (type == TWH) &&
    448 				    (flags&noexec) == 0)
    449 {
    450 					i = execute(whptr(t)->dotre, XEC_NOSTOP, errorflg);
    451 					if (breakcnt < 0)
    452 						execbrk = (++breakcnt != 0);
    453 				}
    454 				if (breakcnt > 0)
    455 						execbrk = (--breakcnt != 0);
    456 
    457 				loopcnt--;
    458 				exitval = i;
    459 			}
    460 			break;
    461 
    462 		case TIF:
    463 			if (execute(ifptr(t)->iftre, XEC_NOSTOP, 0) == 0)
    464 				execute(ifptr(t)->thtre, xflags|XEC_NOSTOP, errorflg);
    465 			else if (ifptr(t)->eltre)
    466 				execute(ifptr(t)->eltre, xflags|XEC_NOSTOP, errorflg);
    467 			else
    468 				exitval = 0;	/* force zero exit for if-then-fi */
    469 			break;
    470 
    471 		case TSW:
    472 			{
    473 				unsigned char	*r = mactrim(swptr(t)->swarg);
    474 				struct regnod *regp;
    475 
    476 				regp = swptr(t)->swlst;
    477 				while (regp)
    478 				{
    479 					struct argnod *rex = regp->regptr;
    480 
    481 					while (rex)
    482 					{
    483 						unsigned char	*s;
    484 
    485 						if (gmatch(r, s = macro(rex->argval)) || (trim(s), eq(r, s)))
    486 						{
    487 							execute(regp->regcom, XEC_NOSTOP, errorflg);
    488 							regp = 0;
    489 							break;
    490 						}
    491 						else
    492 							rex = rex->argnxt;
    493 					}
    494 					if (regp)
    495 						regp = regp->regnxt;
    496 				}
    497 			}
    498 			break;
    499 		}
    500 		exitset();
    501 	}
    502 	sigchk();
    503 	tdystak(sav);
    504 	flags |= eflag;
    505 	return(exitval);
    506 }
    507 
    508 void
    509 execexp(unsigned char *s, int f)
    510 {
    511 	struct fileblk	fb;
    512 
    513 	push(&fb);
    514 	if (s)
    515 	{
    516 		estabf(s);
    517 		fb.feval = (unsigned char **)(f);
    518 	}
    519 	else if (f >= 0)
    520 		initf(f);
    521 	execute(cmd(NL, NLFLG | MTFLG), 0, (int)(flags & errflg));
    522 	pop();
    523 }
    524 
    525 void
    526 execprint(unsigned char **com)
    527 {
    528 	int 	argn = 0;
    529 	unsigned char	*s;
    530 
    531 	prs(_gettext(execpmsg));
    532 	while(com[argn] != ENDARGS)
    533 	{
    534 		s = com[argn++];
    535 		write(output, s, length(s) - 1);
    536 		blank();
    537 	}
    538 
    539 	newline();
    540 }
    541