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