Home | History | Annotate | Line # | Download | only in sh
eval.c revision 1.27
      1 /*	$NetBSD: eval.c,v 1.27 1995/09/11 17:05:41 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Kenneth Almquist.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the University of
     21  *	California, Berkeley and its contributors.
     22  * 4. Neither the name of the University nor the names of its contributors
     23  *    may be used to endorse or promote products derived from this software
     24  *    without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  * SUCH DAMAGE.
     37  */
     38 
     39 #ifndef lint
     40 #if 0
     41 static char sccsid[] = "@(#)eval.c	8.9 (Berkeley) 6/8/95";
     42 #else
     43 static char sccsid[] = "$NetBSD: eval.c,v 1.27 1995/09/11 17:05:41 christos Exp $";
     44 #endif
     45 #endif /* not lint */
     46 
     47 #include <signal.h>
     48 #include <unistd.h>
     49 
     50 /*
     51  * Evaluate a command.
     52  */
     53 
     54 #include "shell.h"
     55 #include "nodes.h"
     56 #include "syntax.h"
     57 #include "expand.h"
     58 #include "parser.h"
     59 #include "jobs.h"
     60 #include "eval.h"
     61 #include "builtins.h"
     62 #include "options.h"
     63 #include "exec.h"
     64 #include "redir.h"
     65 #include "input.h"
     66 #include "output.h"
     67 #include "trap.h"
     68 #include "var.h"
     69 #include "memalloc.h"
     70 #include "error.h"
     71 #include "show.h"
     72 #include "mystring.h"
     73 #ifndef NO_HISTORY
     74 #include "myhistedit.h"
     75 #endif
     76 
     77 
     78 /* flags in argument to evaltree */
     79 #define EV_EXIT 01		/* exit after evaluating tree */
     80 #define EV_TESTED 02		/* exit status is checked; ignore -e flag */
     81 #define EV_BACKCMD 04		/* command executing within back quotes */
     82 
     83 MKINIT int evalskip;		/* set if we are skipping commands */
     84 STATIC int skipcount;		/* number of levels to skip */
     85 MKINIT int loopnest;		/* current loop nesting level */
     86 int funcnest;			/* depth of function calls */
     87 
     88 
     89 char *commandname;
     90 struct strlist *cmdenviron;
     91 int exitstatus;			/* exit status of last command */
     92 int oexitstatus;		/* saved exit status */
     93 
     94 
     95 STATIC void evalloop __P((union node *));
     96 STATIC void evalfor __P((union node *));
     97 STATIC void evalcase __P((union node *, int));
     98 STATIC void evalsubshell __P((union node *, int));
     99 STATIC void expredir __P((union node *));
    100 STATIC void evalpipe __P((union node *));
    101 STATIC void evalcommand __P((union node *, int, struct backcmd *));
    102 STATIC void prehash __P((union node *));
    103 
    104 
    105 /*
    106  * Called to reset things after an exception.
    107  */
    108 
    109 #ifdef mkinit
    110 INCLUDE "eval.h"
    111 
    112 RESET {
    113 	evalskip = 0;
    114 	loopnest = 0;
    115 	funcnest = 0;
    116 }
    117 
    118 SHELLPROC {
    119 	exitstatus = 0;
    120 }
    121 #endif
    122 
    123 
    124 
    125 /*
    126  * The eval commmand.
    127  */
    128 
    129 int
    130 evalcmd(argc, argv)
    131 	int argc;
    132 	char **argv;
    133 {
    134         char *p;
    135         char *concat;
    136         char **ap;
    137 
    138         if (argc > 1) {
    139                 p = argv[1];
    140                 if (argc > 2) {
    141                         STARTSTACKSTR(concat);
    142                         ap = argv + 2;
    143                         for (;;) {
    144                                 while (*p)
    145                                         STPUTC(*p++, concat);
    146                                 if ((p = *ap++) == NULL)
    147                                         break;
    148                                 STPUTC(' ', concat);
    149                         }
    150                         STPUTC('\0', concat);
    151                         p = grabstackstr(concat);
    152                 }
    153                 evalstring(p);
    154         }
    155         return exitstatus;
    156 }
    157 
    158 
    159 /*
    160  * Execute a command or commands contained in a string.
    161  */
    162 
    163 void
    164 evalstring(s)
    165 	char *s;
    166 	{
    167 	union node *n;
    168 	struct stackmark smark;
    169 
    170 	setstackmark(&smark);
    171 	setinputstring(s, 1);
    172 	while ((n = parsecmd(0)) != NEOF) {
    173 		evaltree(n, 0);
    174 		popstackmark(&smark);
    175 	}
    176 	popfile();
    177 	popstackmark(&smark);
    178 }
    179 
    180 
    181 
    182 /*
    183  * Evaluate a parse tree.  The value is left in the global variable
    184  * exitstatus.
    185  */
    186 
    187 void
    188 evaltree(n, flags)
    189 	union node *n;
    190 	int flags;
    191 {
    192 	if (n == NULL) {
    193 		TRACE(("evaltree(NULL) called\n"));
    194 		exitstatus = 0;
    195 		goto out;
    196 	}
    197 #ifndef NO_HISTORY
    198 	displayhist = 1;	/* show history substitutions done with fc */
    199 #endif
    200 	TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
    201 	switch (n->type) {
    202 	case NSEMI:
    203 		evaltree(n->nbinary.ch1, 0);
    204 		if (evalskip)
    205 			goto out;
    206 		evaltree(n->nbinary.ch2, flags);
    207 		break;
    208 	case NAND:
    209 		evaltree(n->nbinary.ch1, EV_TESTED);
    210 		if (evalskip || exitstatus != 0)
    211 			goto out;
    212 		evaltree(n->nbinary.ch2, flags);
    213 		break;
    214 	case NOR:
    215 		evaltree(n->nbinary.ch1, EV_TESTED);
    216 		if (evalskip || exitstatus == 0)
    217 			goto out;
    218 		evaltree(n->nbinary.ch2, flags);
    219 		break;
    220 	case NREDIR:
    221 		expredir(n->nredir.redirect);
    222 		redirect(n->nredir.redirect, REDIR_PUSH);
    223 		evaltree(n->nredir.n, flags);
    224 		popredir();
    225 		break;
    226 	case NSUBSHELL:
    227 		evalsubshell(n, flags);
    228 		break;
    229 	case NBACKGND:
    230 		evalsubshell(n, flags);
    231 		break;
    232 	case NIF: {
    233 		int status;
    234 
    235 		evaltree(n->nif.test, EV_TESTED);
    236 		status = exitstatus;
    237 		exitstatus = 0;
    238 		if (evalskip)
    239 			goto out;
    240 		if (status == 0)
    241 			evaltree(n->nif.ifpart, flags);
    242 		else if (n->nif.elsepart)
    243 			evaltree(n->nif.elsepart, flags);
    244 		break;
    245 	}
    246 	case NWHILE:
    247 	case NUNTIL:
    248 		evalloop(n);
    249 		break;
    250 	case NFOR:
    251 		evalfor(n);
    252 		break;
    253 	case NCASE:
    254 		evalcase(n, flags);
    255 		break;
    256 	case NDEFUN:
    257 		defun(n->narg.text, n->narg.next);
    258 		exitstatus = 0;
    259 		break;
    260 	case NNOT:
    261 		evaltree(n->nnot.com, EV_TESTED);
    262 		exitstatus = !exitstatus;
    263 		break;
    264 
    265 	case NPIPE:
    266 		evalpipe(n);
    267 		break;
    268 	case NCMD:
    269 		evalcommand(n, flags, (struct backcmd *)NULL);
    270 		break;
    271 	default:
    272 		out1fmt("Node type = %d\n", n->type);
    273 		flushout(&output);
    274 		break;
    275 	}
    276 out:
    277 	if (pendingsigs)
    278 		dotrap();
    279 	if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED)))
    280 		exitshell(exitstatus);
    281 }
    282 
    283 
    284 STATIC void
    285 evalloop(n)
    286 	union node *n;
    287 {
    288 	int status;
    289 
    290 	loopnest++;
    291 	status = 0;
    292 	for (;;) {
    293 		evaltree(n->nbinary.ch1, EV_TESTED);
    294 		if (evalskip) {
    295 skipping:	  if (evalskip == SKIPCONT && --skipcount <= 0) {
    296 				evalskip = 0;
    297 				continue;
    298 			}
    299 			if (evalskip == SKIPBREAK && --skipcount <= 0)
    300 				evalskip = 0;
    301 			break;
    302 		}
    303 		if (n->type == NWHILE) {
    304 			if (exitstatus != 0)
    305 				break;
    306 		} else {
    307 			if (exitstatus == 0)
    308 				break;
    309 		}
    310 		evaltree(n->nbinary.ch2, 0);
    311 		status = exitstatus;
    312 		if (evalskip)
    313 			goto skipping;
    314 	}
    315 	loopnest--;
    316 	exitstatus = status;
    317 }
    318 
    319 
    320 
    321 STATIC void
    322 evalfor(n)
    323     union node *n;
    324 {
    325 	struct arglist arglist;
    326 	union node *argp;
    327 	struct strlist *sp;
    328 	struct stackmark smark;
    329 
    330 	setstackmark(&smark);
    331 	arglist.lastp = &arglist.list;
    332 	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
    333 		oexitstatus = exitstatus;
    334 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
    335 		if (evalskip)
    336 			goto out;
    337 	}
    338 	*arglist.lastp = NULL;
    339 
    340 	exitstatus = 0;
    341 	loopnest++;
    342 	for (sp = arglist.list ; sp ; sp = sp->next) {
    343 		setvar(n->nfor.var, sp->text, 0);
    344 		evaltree(n->nfor.body, 0);
    345 		if (evalskip) {
    346 			if (evalskip == SKIPCONT && --skipcount <= 0) {
    347 				evalskip = 0;
    348 				continue;
    349 			}
    350 			if (evalskip == SKIPBREAK && --skipcount <= 0)
    351 				evalskip = 0;
    352 			break;
    353 		}
    354 	}
    355 	loopnest--;
    356 out:
    357 	popstackmark(&smark);
    358 }
    359 
    360 
    361 
    362 STATIC void
    363 evalcase(n, flags)
    364 	union node *n;
    365 	int flags;
    366 {
    367 	union node *cp;
    368 	union node *patp;
    369 	struct arglist arglist;
    370 	struct stackmark smark;
    371 
    372 	setstackmark(&smark);
    373 	arglist.lastp = &arglist.list;
    374 	oexitstatus = exitstatus;
    375 	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
    376 	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
    377 		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
    378 			if (casematch(patp, arglist.list->text)) {
    379 				if (evalskip == 0) {
    380 					evaltree(cp->nclist.body, flags);
    381 				}
    382 				goto out;
    383 			}
    384 		}
    385 	}
    386 out:
    387 	popstackmark(&smark);
    388 }
    389 
    390 
    391 
    392 /*
    393  * Kick off a subshell to evaluate a tree.
    394  */
    395 
    396 STATIC void
    397 evalsubshell(n, flags)
    398 	union node *n;
    399 	int flags;
    400 {
    401 	struct job *jp;
    402 	int backgnd = (n->type == NBACKGND);
    403 
    404 	expredir(n->nredir.redirect);
    405 	jp = makejob(n, 1);
    406 	if (forkshell(jp, n, backgnd) == 0) {
    407 		if (backgnd)
    408 			flags &=~ EV_TESTED;
    409 		redirect(n->nredir.redirect, 0);
    410 		evaltree(n->nredir.n, flags | EV_EXIT);	/* never returns */
    411 	}
    412 	if (! backgnd) {
    413 		INTOFF;
    414 		exitstatus = waitforjob(jp);
    415 		INTON;
    416 	}
    417 }
    418 
    419 
    420 
    421 /*
    422  * Compute the names of the files in a redirection list.
    423  */
    424 
    425 STATIC void
    426 expredir(n)
    427 	union node *n;
    428 {
    429 	register union node *redir;
    430 
    431 	for (redir = n ; redir ; redir = redir->nfile.next) {
    432 		struct arglist fn;
    433 		fn.lastp = &fn.list;
    434 		oexitstatus = exitstatus;
    435 		switch (redir->type) {
    436 		case NFROM:
    437 		case NTO:
    438 		case NAPPEND:
    439 			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
    440 			redir->nfile.expfname = fn.list->text;
    441 			break;
    442 		case NFROMFD:
    443 		case NTOFD:
    444 			if (redir->ndup.vname) {
    445 				expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
    446 				fixredir(redir, fn.list->text, 1);
    447 			}
    448 			break;
    449 		}
    450 	}
    451 }
    452 
    453 
    454 
    455 /*
    456  * Evaluate a pipeline.  All the processes in the pipeline are children
    457  * of the process creating the pipeline.  (This differs from some versions
    458  * of the shell, which make the last process in a pipeline the parent
    459  * of all the rest.)
    460  */
    461 
    462 STATIC void
    463 evalpipe(n)
    464 	union node *n;
    465 {
    466 	struct job *jp;
    467 	struct nodelist *lp;
    468 	int pipelen;
    469 	int prevfd;
    470 	int pip[2];
    471 
    472 	TRACE(("evalpipe(0x%lx) called\n", (long)n));
    473 	pipelen = 0;
    474 	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
    475 		pipelen++;
    476 	INTOFF;
    477 	jp = makejob(n, pipelen);
    478 	prevfd = -1;
    479 	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
    480 		prehash(lp->n);
    481 		pip[1] = -1;
    482 		if (lp->next) {
    483 			if (pipe(pip) < 0) {
    484 				close(prevfd);
    485 				error("Pipe call failed");
    486 			}
    487 		}
    488 		if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
    489 			INTON;
    490 			if (prevfd > 0) {
    491 				close(0);
    492 				copyfd(prevfd, 0);
    493 				close(prevfd);
    494 			}
    495 			if (pip[1] >= 0) {
    496 				close(pip[0]);
    497 				if (pip[1] != 1) {
    498 					close(1);
    499 					copyfd(pip[1], 1);
    500 					close(pip[1]);
    501 				}
    502 			}
    503 			evaltree(lp->n, EV_EXIT);
    504 		}
    505 		if (prevfd >= 0)
    506 			close(prevfd);
    507 		prevfd = pip[0];
    508 		close(pip[1]);
    509 	}
    510 	INTON;
    511 	if (n->npipe.backgnd == 0) {
    512 		INTOFF;
    513 		exitstatus = waitforjob(jp);
    514 		TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
    515 		INTON;
    516 	}
    517 }
    518 
    519 
    520 
    521 /*
    522  * Execute a command inside back quotes.  If it's a builtin command, we
    523  * want to save its output in a block obtained from malloc.  Otherwise
    524  * we fork off a subprocess and get the output of the command via a pipe.
    525  * Should be called with interrupts off.
    526  */
    527 
    528 void
    529 evalbackcmd(n, result)
    530 	union node *n;
    531 	struct backcmd *result;
    532 {
    533 	int pip[2];
    534 	struct job *jp;
    535 	struct stackmark smark;		/* unnecessary */
    536 
    537 	setstackmark(&smark);
    538 	result->fd = -1;
    539 	result->buf = NULL;
    540 	result->nleft = 0;
    541 	result->jp = NULL;
    542 	if (n == NULL) {
    543 		exitstatus = 0;
    544 		goto out;
    545 	}
    546 	if (n->type == NCMD) {
    547 		exitstatus = oexitstatus;
    548 		evalcommand(n, EV_BACKCMD, result);
    549 	} else {
    550 		exitstatus = 0;
    551 		if (pipe(pip) < 0)
    552 			error("Pipe call failed");
    553 		jp = makejob(n, 1);
    554 		if (forkshell(jp, n, FORK_NOJOB) == 0) {
    555 			FORCEINTON;
    556 			close(pip[0]);
    557 			if (pip[1] != 1) {
    558 				close(1);
    559 				copyfd(pip[1], 1);
    560 				close(pip[1]);
    561 			}
    562 			evaltree(n, EV_EXIT);
    563 		}
    564 		close(pip[1]);
    565 		result->fd = pip[0];
    566 		result->jp = jp;
    567 	}
    568 out:
    569 	popstackmark(&smark);
    570 	TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
    571 		result->fd, result->buf, result->nleft, result->jp));
    572 }
    573 
    574 
    575 
    576 /*
    577  * Execute a simple command.
    578  */
    579 
    580 STATIC void
    581 evalcommand(cmd, flags, backcmd)
    582 	union node *cmd;
    583 	int flags;
    584 	struct backcmd *backcmd;
    585 {
    586 	struct stackmark smark;
    587 	union node *argp;
    588 	struct arglist arglist;
    589 	struct arglist varlist;
    590 	char **argv;
    591 	int argc;
    592 	char **envp;
    593 	int varflag;
    594 	struct strlist *sp;
    595 	int mode;
    596 	int pip[2];
    597 	struct cmdentry cmdentry;
    598 	struct job *jp;
    599 	struct jmploc jmploc;
    600 	struct jmploc *volatile savehandler;
    601 	char *volatile savecmdname;
    602 	volatile struct shparam saveparam;
    603 	struct localvar *volatile savelocalvars;
    604 	volatile int e;
    605 	char *lastarg;
    606 #if __GNUC__
    607 	/* Avoid longjmp clobbering */
    608 	(void) &argv;
    609 	(void) &argc;
    610 	(void) &lastarg;
    611 	(void) &flags;
    612 #endif
    613 
    614 	/* First expand the arguments. */
    615 	TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
    616 	setstackmark(&smark);
    617 	arglist.lastp = &arglist.list;
    618 	varlist.lastp = &varlist.list;
    619 	varflag = 1;
    620 	oexitstatus = exitstatus;
    621 	exitstatus = 0;
    622 	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
    623 		char *p = argp->narg.text;
    624 		if (varflag && is_name(*p)) {
    625 			do {
    626 				p++;
    627 			} while (is_in_name(*p));
    628 			if (*p == '=') {
    629 				expandarg(argp, &varlist, EXP_VARTILDE);
    630 				continue;
    631 			}
    632 		}
    633 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
    634 		varflag = 0;
    635 	}
    636 	*arglist.lastp = NULL;
    637 	*varlist.lastp = NULL;
    638 	expredir(cmd->ncmd.redirect);
    639 	argc = 0;
    640 	for (sp = arglist.list ; sp ; sp = sp->next)
    641 		argc++;
    642 	argv = stalloc(sizeof (char *) * (argc + 1));
    643 
    644 	for (sp = arglist.list ; sp ; sp = sp->next) {
    645 		TRACE(("evalcommand arg: %s\n", sp->text));
    646 		*argv++ = sp->text;
    647 	}
    648 	*argv = NULL;
    649 	lastarg = NULL;
    650 	if (iflag && funcnest == 0 && argc > 0)
    651 		lastarg = argv[-1];
    652 	argv -= argc;
    653 
    654 	/* Print the command if xflag is set. */
    655 	if (xflag) {
    656 		outc('+', &errout);
    657 		for (sp = varlist.list ; sp ; sp = sp->next) {
    658 			outc(' ', &errout);
    659 			out2str(sp->text);
    660 		}
    661 		for (sp = arglist.list ; sp ; sp = sp->next) {
    662 			outc(' ', &errout);
    663 			out2str(sp->text);
    664 		}
    665 		outc('\n', &errout);
    666 		flushout(&errout);
    667 	}
    668 
    669 	/* Now locate the command. */
    670 	if (argc == 0) {
    671 		cmdentry.cmdtype = CMDBUILTIN;
    672 		cmdentry.u.index = BLTINCMD;
    673 	} else {
    674 		static const char PATH[] = "PATH=";
    675 		char *path = pathval();
    676 
    677 		/*
    678 		 * Modify the command lookup path, if a PATH= assignment
    679 		 * is present
    680 		 */
    681 		for (sp = varlist.list ; sp ; sp = sp->next)
    682 			if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
    683 				path = sp->text + sizeof(PATH) - 1;
    684 
    685 		find_command(argv[0], &cmdentry, 1, path);
    686 		if (cmdentry.cmdtype == CMDUNKNOWN) {	/* command not found */
    687 			exitstatus = 1;
    688 			flushout(&errout);
    689 			return;
    690 		}
    691 		/* implement the bltin builtin here */
    692 		if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
    693 			for (;;) {
    694 				argv++;
    695 				if (--argc == 0)
    696 					break;
    697 				if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
    698 					outfmt(&errout, "%s: not found\n", *argv);
    699 					exitstatus = 1;
    700 					flushout(&errout);
    701 					return;
    702 				}
    703 				if (cmdentry.u.index != BLTINCMD)
    704 					break;
    705 			}
    706 		}
    707 	}
    708 
    709 	/* Fork off a child process if necessary. */
    710 	if (cmd->ncmd.backgnd
    711 	 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
    712 	 || ((flags & EV_BACKCMD) != 0
    713 	    && (cmdentry.cmdtype != CMDBUILTIN
    714 		 || cmdentry.u.index == DOTCMD
    715 		 || cmdentry.u.index == EVALCMD))) {
    716 		jp = makejob(cmd, 1);
    717 		mode = cmd->ncmd.backgnd;
    718 		if (flags & EV_BACKCMD) {
    719 			mode = FORK_NOJOB;
    720 			if (pipe(pip) < 0)
    721 				error("Pipe call failed");
    722 		}
    723 		if (forkshell(jp, cmd, mode) != 0)
    724 			goto parent;	/* at end of routine */
    725 		if (flags & EV_BACKCMD) {
    726 			FORCEINTON;
    727 			close(pip[0]);
    728 			if (pip[1] != 1) {
    729 				close(1);
    730 				copyfd(pip[1], 1);
    731 				close(pip[1]);
    732 			}
    733 		}
    734 		flags |= EV_EXIT;
    735 	}
    736 
    737 	/* This is the child process if a fork occurred. */
    738 	/* Execute the command. */
    739 	if (cmdentry.cmdtype == CMDFUNCTION) {
    740 		trputs("Shell function:  ");  trargs(argv);
    741 		redirect(cmd->ncmd.redirect, REDIR_PUSH);
    742 		saveparam = shellparam;
    743 		shellparam.malloc = 0;
    744 		shellparam.nparam = argc - 1;
    745 		shellparam.p = argv + 1;
    746 		shellparam.optnext = NULL;
    747 		INTOFF;
    748 		savelocalvars = localvars;
    749 		localvars = NULL;
    750 		INTON;
    751 		if (setjmp(jmploc.loc)) {
    752 			if (exception == EXSHELLPROC)
    753 				freeparam((struct shparam *)&saveparam);
    754 			else {
    755 				freeparam(&shellparam);
    756 				shellparam = saveparam;
    757 			}
    758 			poplocalvars();
    759 			localvars = savelocalvars;
    760 			handler = savehandler;
    761 			longjmp(handler->loc, 1);
    762 		}
    763 		savehandler = handler;
    764 		handler = &jmploc;
    765 		for (sp = varlist.list ; sp ; sp = sp->next)
    766 			mklocal(sp->text);
    767 		funcnest++;
    768 		evaltree(cmdentry.u.func, 0);
    769 		funcnest--;
    770 		INTOFF;
    771 		poplocalvars();
    772 		localvars = savelocalvars;
    773 		freeparam(&shellparam);
    774 		shellparam = saveparam;
    775 		handler = savehandler;
    776 		popredir();
    777 		INTON;
    778 		if (evalskip == SKIPFUNC) {
    779 			evalskip = 0;
    780 			skipcount = 0;
    781 		}
    782 		if (flags & EV_EXIT)
    783 			exitshell(exitstatus);
    784 	} else if (cmdentry.cmdtype == CMDBUILTIN) {
    785 		trputs("builtin command:  ");  trargs(argv);
    786 		mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
    787 		if (flags == EV_BACKCMD) {
    788 			memout.nleft = 0;
    789 			memout.nextc = memout.buf;
    790 			memout.bufsize = 64;
    791 			mode |= REDIR_BACKQ;
    792 		}
    793 		redirect(cmd->ncmd.redirect, mode);
    794 		savecmdname = commandname;
    795 		cmdenviron = varlist.list;
    796 		e = -1;
    797 		if (setjmp(jmploc.loc)) {
    798 			e = exception;
    799 			exitstatus = (e == EXINT)? SIGINT+128 : 2;
    800 			goto cmddone;
    801 		}
    802 		savehandler = handler;
    803 		handler = &jmploc;
    804 		commandname = argv[0];
    805 		argptr = argv + 1;
    806 		optptr = NULL;			/* initialize nextopt */
    807 		exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
    808 		flushall();
    809 cmddone:
    810 		out1 = &output;
    811 		out2 = &errout;
    812 		freestdout();
    813 		if (e != EXSHELLPROC) {
    814 			commandname = savecmdname;
    815 			if (flags & EV_EXIT) {
    816 				exitshell(exitstatus);
    817 			}
    818 		}
    819 		handler = savehandler;
    820 		if (e != -1) {
    821 			if (e != EXERROR || cmdentry.u.index == BLTINCMD
    822 					       || cmdentry.u.index == DOTCMD
    823 					       || cmdentry.u.index == EVALCMD
    824 #ifndef NO_HISTORY
    825 					       || cmdentry.u.index == HISTCMD
    826 #endif
    827 					       || cmdentry.u.index == EXECCMD)
    828 				exraise(e);
    829 			FORCEINTON;
    830 		}
    831 		if (cmdentry.u.index != EXECCMD)
    832 			popredir();
    833 		if (flags == EV_BACKCMD) {
    834 			backcmd->buf = memout.buf;
    835 			backcmd->nleft = memout.nextc - memout.buf;
    836 			memout.buf = NULL;
    837 		}
    838 	} else {
    839 		trputs("normal command:  ");  trargs(argv);
    840 		clearredir();
    841 		redirect(cmd->ncmd.redirect, 0);
    842 		for (sp = varlist.list ; sp ; sp = sp->next)
    843 			setvareq(sp->text, VEXPORT|VSTACK);
    844 		envp = environment();
    845 		shellexec(argv, envp, pathval(), cmdentry.u.index);
    846 		/*NOTREACHED*/
    847 	}
    848 	goto out;
    849 
    850 parent:	/* parent process gets here (if we forked) */
    851 	if (mode == 0) {	/* argument to fork */
    852 		INTOFF;
    853 		exitstatus = waitforjob(jp);
    854 		INTON;
    855 	} else if (mode == 2) {
    856 		backcmd->fd = pip[0];
    857 		close(pip[1]);
    858 		backcmd->jp = jp;
    859 	}
    860 
    861 out:
    862 	if (lastarg)
    863 		setvar("_", lastarg, 0);
    864 	popstackmark(&smark);
    865 }
    866 
    867 
    868 
    869 /*
    870  * Search for a command.  This is called before we fork so that the
    871  * location of the command will be available in the parent as well as
    872  * the child.  The check for "goodname" is an overly conservative
    873  * check that the name will not be subject to expansion.
    874  */
    875 
    876 STATIC void
    877 prehash(n)
    878 	union node *n;
    879 {
    880 	struct cmdentry entry;
    881 
    882 	if (n->type == NCMD && n->ncmd.args)
    883 		if (goodname(n->ncmd.args->narg.text))
    884 			find_command(n->ncmd.args->narg.text, &entry, 0,
    885 				     pathval());
    886 }
    887 
    888 
    889 
    890 /*
    891  * Builtin commands.  Builtin commands whose functions are closely
    892  * tied to evaluation are implemented here.
    893  */
    894 
    895 /*
    896  * No command given, or a bltin command with no arguments.  Set the
    897  * specified variables.
    898  */
    899 
    900 int
    901 bltincmd(argc, argv)
    902 	int argc;
    903 	char **argv;
    904 {
    905 	listsetvar(cmdenviron);
    906 	/*
    907 	 * Preserve exitstatus of a previous possible redirection
    908 	 * as POSIX mandates
    909 	 */
    910 	return exitstatus;
    911 }
    912 
    913 
    914 /*
    915  * Handle break and continue commands.  Break, continue, and return are
    916  * all handled by setting the evalskip flag.  The evaluation routines
    917  * above all check this flag, and if it is set they start skipping
    918  * commands rather than executing them.  The variable skipcount is
    919  * the number of loops to break/continue, or the number of function
    920  * levels to return.  (The latter is always 1.)  It should probably
    921  * be an error to break out of more loops than exist, but it isn't
    922  * in the standard shell so we don't make it one here.
    923  */
    924 
    925 int
    926 breakcmd(argc, argv)
    927 	int argc;
    928 	char **argv;
    929 {
    930 	int n;
    931 
    932 	n = 1;
    933 	if (argc > 1)
    934 		n = number(argv[1]);
    935 	if (n > loopnest)
    936 		n = loopnest;
    937 	if (n > 0) {
    938 		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
    939 		skipcount = n;
    940 	}
    941 	return 0;
    942 }
    943 
    944 
    945 /*
    946  * The return command.
    947  */
    948 
    949 int
    950 returncmd(argc, argv)
    951 	int argc;
    952 	char **argv;
    953 {
    954 	int ret;
    955 
    956 	ret = exitstatus;
    957 	if (argc > 1)
    958 		ret = number(argv[1]);
    959 	if (funcnest) {
    960 		evalskip = SKIPFUNC;
    961 		skipcount = 1;
    962 		return ret;
    963 	}
    964 	else {
    965 		/* Do what ksh does; skip the rest of the file */
    966 		evalskip = SKIPFILE;
    967 		skipcount = 1;
    968 		return ret;
    969 	}
    970 }
    971 
    972 
    973 int
    974 falsecmd(argc, argv)
    975 	int argc;
    976 	char **argv;
    977 {
    978 	return 1;
    979 }
    980 
    981 
    982 int
    983 truecmd(argc, argv)
    984 	int argc;
    985 	char **argv;
    986 {
    987 	return 0;
    988 }
    989 
    990 
    991 int
    992 execcmd(argc, argv)
    993 	int argc;
    994 	char **argv;
    995 {
    996 	if (argc > 1) {
    997 		struct strlist *sp;
    998 
    999 		iflag = 0;		/* exit on error */
   1000 		mflag = 0;
   1001 		optschanged();
   1002 		for (sp = cmdenviron; sp ; sp = sp->next)
   1003 			setvareq(sp->text, VEXPORT|VSTACK);
   1004 		shellexec(argv + 1, environment(), pathval(), 0);
   1005 
   1006 	}
   1007 	return 0;
   1008 }
   1009