xref: /original-bsd/bin/sh/eval.c (revision b3c06cab)
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.4 (Berkeley) 05/04/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 = 0;
207 
208 		evaltree(n->nif.test, EV_TESTED);
209 		if (evalskip)
210 			goto out;
211 		if (exitstatus == 0) {
212 			evaltree(n->nif.ifpart, flags);
213 			status = exitstatus;
214 		} else if (n->nif.elsepart) {
215 			evaltree(n->nif.elsepart, flags);
216 			status = exitstatus;
217 		}
218 		exitstatus = status;
219 		break;
220 	}
221 	case NWHILE:
222 	case NUNTIL:
223 		evalloop(n);
224 		break;
225 	case NFOR:
226 		evalfor(n);
227 		break;
228 	case NCASE:
229 		evalcase(n, flags);
230 		break;
231 	case NDEFUN:
232 		defun(n->narg.text, n->narg.next);
233 		exitstatus = 0;
234 		break;
235 	case NNOT:
236 		evaltree(n->nnot.com, EV_TESTED);
237 		exitstatus = !exitstatus;
238 		break;
239 
240 	case NPIPE:
241 		evalpipe(n);
242 		break;
243 	case NCMD:
244 		evalcommand(n, flags, (struct backcmd *)NULL);
245 		break;
246 	default:
247 		out1fmt("Node type = %d\n", n->type);
248 		flushout(&output);
249 		break;
250 	}
251 out:
252 	if (pendingsigs)
253 		dotrap();
254 	if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED)))
255 		exitshell(exitstatus);
256 }
257 
258 
259 STATIC void
260 evalloop(n)
261 	union node *n;
262 	{
263 	int status;
264 
265 	loopnest++;
266 	status = 0;
267 	for (;;) {
268 		evaltree(n->nbinary.ch1, EV_TESTED);
269 		if (evalskip) {
270 skipping:	  if (evalskip == SKIPCONT && --skipcount <= 0) {
271 				evalskip = 0;
272 				continue;
273 			}
274 			if (evalskip == SKIPBREAK && --skipcount <= 0)
275 				evalskip = 0;
276 			break;
277 		}
278 		if (n->type == NWHILE) {
279 			if (exitstatus != 0)
280 				break;
281 		} else {
282 			if (exitstatus == 0)
283 				break;
284 		}
285 		evaltree(n->nbinary.ch2, 0);
286 		status = exitstatus;
287 		if (evalskip)
288 			goto skipping;
289 	}
290 	loopnest--;
291 	exitstatus = status;
292 }
293 
294 
295 
296 STATIC void
297 evalfor(n)
298 	union node *n;
299 	{
300 	struct arglist arglist;
301 	union node *argp;
302 	struct strlist *sp;
303 	struct stackmark smark;
304 
305 	setstackmark(&smark);
306 	arglist.lastp = &arglist.list;
307 	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
308 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
309 		if (evalskip)
310 			goto out;
311 	}
312 	*arglist.lastp = NULL;
313 
314 	exitstatus = 0;
315 	loopnest++;
316 	for (sp = arglist.list ; sp ; sp = sp->next) {
317 		setvar(n->nfor.var, sp->text, 0);
318 		evaltree(n->nfor.body, 0);
319 		if (evalskip) {
320 			if (evalskip == SKIPCONT && --skipcount <= 0) {
321 				evalskip = 0;
322 				continue;
323 			}
324 			if (evalskip == SKIPBREAK && --skipcount <= 0)
325 				evalskip = 0;
326 			break;
327 		}
328 	}
329 	loopnest--;
330 out:
331 	popstackmark(&smark);
332 }
333 
334 
335 
336 STATIC void
337 evalcase(n, flags)
338 	union node *n;
339 	int flags;
340 {
341 	union node *cp;
342 	union node *patp;
343 	struct arglist arglist;
344 	struct stackmark smark;
345 
346 	setstackmark(&smark);
347 	arglist.lastp = &arglist.list;
348 	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
349 	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
350 		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
351 			if (casematch(patp, arglist.list->text)) {
352 				if (evalskip == 0) {
353 					evaltree(cp->nclist.body, flags);
354 				}
355 				goto out;
356 			}
357 		}
358 	}
359 out:
360 	popstackmark(&smark);
361 }
362 
363 
364 
365 /*
366  * Kick off a subshell to evaluate a tree.
367  */
368 
369 STATIC void
370 evalsubshell(n, flags)
371 	union node *n;
372 	int flags;
373 {
374 	struct job *jp;
375 	int backgnd = (n->type == NBACKGND);
376 
377 	expredir(n->nredir.redirect);
378 	jp = makejob(n, 1);
379 	if (forkshell(jp, n, backgnd) == 0) {
380 		if (backgnd)
381 			flags &=~ EV_TESTED;
382 		redirect(n->nredir.redirect, 0);
383 		evaltree(n->nredir.n, flags | EV_EXIT);	/* never returns */
384 	}
385 	if (! backgnd) {
386 		INTOFF;
387 		exitstatus = waitforjob(jp);
388 		INTON;
389 	}
390 }
391 
392 
393 
394 /*
395  * Compute the names of the files in a redirection list.
396  */
397 
398 STATIC void
399 expredir(n)
400 	union node *n;
401 	{
402 	register union node *redir;
403 
404 	for (redir = n ; redir ; redir = redir->nfile.next) {
405 		struct arglist fn;
406 		fn.lastp = &fn.list;
407 		switch (redir->type) {
408 		case NFROM:
409 		case NTO:
410 		case NAPPEND:
411 			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
412 			redir->nfile.expfname = fn.list->text;
413 			break;
414 		case NFROMFD:
415 		case NTOFD:
416 			if (redir->ndup.vname) {
417 				expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
418 				fixredir(redir, fn.list->text, 1);
419 			}
420 			break;
421 		}
422 	}
423 }
424 
425 
426 
427 /*
428  * Evaluate a pipeline.  All the processes in the pipeline are children
429  * of the process creating the pipeline.  (This differs from some versions
430  * of the shell, which make the last process in a pipeline the parent
431  * of all the rest.)
432  */
433 
434 STATIC void
435 evalpipe(n)
436 	union node *n;
437 	{
438 	struct job *jp;
439 	struct nodelist *lp;
440 	int pipelen;
441 	int prevfd;
442 	int pip[2];
443 
444 	TRACE(("evalpipe(0x%lx) called\n", (long)n));
445 	pipelen = 0;
446 	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
447 		pipelen++;
448 	INTOFF;
449 	jp = makejob(n, pipelen);
450 	prevfd = -1;
451 	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
452 		prehash(lp->n);
453 		pip[1] = -1;
454 		if (lp->next) {
455 			if (pipe(pip) < 0) {
456 				close(prevfd);
457 				error("Pipe call failed");
458 			}
459 		}
460 		if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
461 			INTON;
462 			if (prevfd > 0) {
463 				close(0);
464 				copyfd(prevfd, 0);
465 				close(prevfd);
466 			}
467 			if (pip[1] >= 0) {
468 				close(pip[0]);
469 				if (pip[1] != 1) {
470 					close(1);
471 					copyfd(pip[1], 1);
472 					close(pip[1]);
473 				}
474 			}
475 			evaltree(lp->n, EV_EXIT);
476 		}
477 		if (prevfd >= 0)
478 			close(prevfd);
479 		prevfd = pip[0];
480 		close(pip[1]);
481 	}
482 	INTON;
483 	if (n->npipe.backgnd == 0) {
484 		INTOFF;
485 		exitstatus = waitforjob(jp);
486 		TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
487 		INTON;
488 	}
489 }
490 
491 
492 
493 /*
494  * Execute a command inside back quotes.  If it's a builtin command, we
495  * want to save its output in a block obtained from malloc.  Otherwise
496  * we fork off a subprocess and get the output of the command via a pipe.
497  * Should be called with interrupts off.
498  */
499 
500 void
501 evalbackcmd(n, result)
502 	union node *n;
503 	struct backcmd *result;
504 	{
505 	int pip[2];
506 	struct job *jp;
507 	struct stackmark smark;		/* unnecessary */
508 
509 	setstackmark(&smark);
510 	result->fd = -1;
511 	result->buf = NULL;
512 	result->nleft = 0;
513 	result->jp = NULL;
514 	exitstatus = 0;
515 	if (n == NULL)
516 		goto out;
517 	if (n->type == NCMD) {
518 		evalcommand(n, EV_BACKCMD, result);
519 	} else {
520 		if (pipe(pip) < 0)
521 			error("Pipe call failed");
522 		jp = makejob(n, 1);
523 		if (forkshell(jp, n, FORK_NOJOB) == 0) {
524 			FORCEINTON;
525 			close(pip[0]);
526 			if (pip[1] != 1) {
527 				close(1);
528 				copyfd(pip[1], 1);
529 				close(pip[1]);
530 			}
531 			evaltree(n, EV_EXIT);
532 		}
533 		close(pip[1]);
534 		result->fd = pip[0];
535 		result->jp = jp;
536 	}
537 out:
538 	popstackmark(&smark);
539 	TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
540 		result->fd, result->buf, result->nleft, result->jp));
541 }
542 
543 
544 
545 /*
546  * Execute a simple command.
547  */
548 
549 STATIC void
550 evalcommand(cmd, flags, backcmd)
551 	union node *cmd;
552 	int flags;
553 	struct backcmd *backcmd;
554 {
555 	struct stackmark smark;
556 	union node *argp;
557 	struct arglist arglist;
558 	struct arglist varlist;
559 	char **argv;
560 	int argc;
561 	char **envp;
562 	int varflag;
563 	struct strlist *sp;
564 	int mode;
565 	int pip[2];
566 	struct cmdentry cmdentry;
567 	struct job *jp;
568 	struct jmploc jmploc;
569 	struct jmploc *volatile savehandler;
570 	char *volatile savecmdname;
571 	volatile struct shparam saveparam;
572 	struct localvar *volatile savelocalvars;
573 	volatile int e;
574 	char *lastarg;
575 #if __GNUC__
576 	/* Avoid longjmp clobbering */
577 	(void) &argv;
578 	(void) &argc;
579 	(void) &lastarg;
580 	(void) &flags;
581 #endif
582 
583 	/* First expand the arguments. */
584 	TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
585 	setstackmark(&smark);
586 	arglist.lastp = &arglist.list;
587 	varlist.lastp = &varlist.list;
588 	varflag = 1;
589 	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
590 		char *p = argp->narg.text;
591 		if (varflag && is_name(*p)) {
592 			do {
593 				p++;
594 			} while (is_in_name(*p));
595 			if (*p == '=') {
596 				expandarg(argp, &varlist, EXP_VARTILDE);
597 				continue;
598 			}
599 		}
600 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
601 		varflag = 0;
602 	}
603 	*arglist.lastp = NULL;
604 	*varlist.lastp = NULL;
605 	expredir(cmd->ncmd.redirect);
606 	argc = 0;
607 	for (sp = arglist.list ; sp ; sp = sp->next)
608 		argc++;
609 	argv = stalloc(sizeof (char *) * (argc + 1));
610 
611 	for (sp = arglist.list ; sp ; sp = sp->next) {
612 		TRACE(("evalcommand arg: %s\n", sp->text));
613 		*argv++ = sp->text;
614 	}
615 	*argv = NULL;
616 	lastarg = NULL;
617 	if (iflag && funcnest == 0 && argc > 0)
618 		lastarg = argv[-1];
619 	argv -= argc;
620 
621 	/* Print the command if xflag is set. */
622 	if (xflag) {
623 		outc('+', &errout);
624 		for (sp = varlist.list ; sp ; sp = sp->next) {
625 			outc(' ', &errout);
626 			out2str(sp->text);
627 		}
628 		for (sp = arglist.list ; sp ; sp = sp->next) {
629 			outc(' ', &errout);
630 			out2str(sp->text);
631 		}
632 		outc('\n', &errout);
633 		flushout(&errout);
634 	}
635 
636 	/* Now locate the command. */
637 	if (argc == 0) {
638 		cmdentry.cmdtype = CMDBUILTIN;
639 		cmdentry.u.index = BLTINCMD;
640 	} else {
641 		find_command(argv[0], &cmdentry, 1);
642 		if (cmdentry.cmdtype == CMDUNKNOWN) {	/* command not found */
643 			exitstatus = 2;
644 			flushout(&errout);
645 			return;
646 		}
647 		/* implement the bltin builtin here */
648 		if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
649 			for (;;) {
650 				argv++;
651 				if (--argc == 0)
652 					break;
653 				if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
654 					outfmt(&errout, "%s: not found\n", *argv);
655 					exitstatus = 2;
656 					flushout(&errout);
657 					return;
658 				}
659 				if (cmdentry.u.index != BLTINCMD)
660 					break;
661 			}
662 		}
663 	}
664 
665 	/* Fork off a child process if necessary. */
666 	if (cmd->ncmd.backgnd
667 	 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
668 	 || ((flags & EV_BACKCMD) != 0
669 	    && (cmdentry.cmdtype != CMDBUILTIN
670 		 || cmdentry.u.index == DOTCMD
671 		 || cmdentry.u.index == EVALCMD))) {
672 		jp = makejob(cmd, 1);
673 		mode = cmd->ncmd.backgnd;
674 		if (flags & EV_BACKCMD) {
675 			mode = FORK_NOJOB;
676 			if (pipe(pip) < 0)
677 				error("Pipe call failed");
678 		}
679 		if (forkshell(jp, cmd, mode) != 0)
680 			goto parent;	/* at end of routine */
681 		if (flags & EV_BACKCMD) {
682 			FORCEINTON;
683 			close(pip[0]);
684 			if (pip[1] != 1) {
685 				close(1);
686 				copyfd(pip[1], 1);
687 				close(pip[1]);
688 			}
689 		}
690 		flags |= EV_EXIT;
691 	}
692 
693 	/* This is the child process if a fork occurred. */
694 	/* Execute the command. */
695 	if (cmdentry.cmdtype == CMDFUNCTION) {
696 		trputs("Shell function:  ");  trargs(argv);
697 		redirect(cmd->ncmd.redirect, REDIR_PUSH);
698 		saveparam = shellparam;
699 		shellparam.malloc = 0;
700 		shellparam.nparam = argc - 1;
701 		shellparam.p = argv + 1;
702 		shellparam.optnext = NULL;
703 		INTOFF;
704 		savelocalvars = localvars;
705 		localvars = NULL;
706 		INTON;
707 		if (setjmp(jmploc.loc)) {
708 			if (exception == EXSHELLPROC)
709 				freeparam((struct shparam *)&saveparam);
710 			else {
711 				freeparam(&shellparam);
712 				shellparam = saveparam;
713 			}
714 			poplocalvars();
715 			localvars = savelocalvars;
716 			handler = savehandler;
717 			longjmp(handler->loc, 1);
718 		}
719 		savehandler = handler;
720 		handler = &jmploc;
721 		for (sp = varlist.list ; sp ; sp = sp->next)
722 			mklocal(sp->text);
723 		funcnest++;
724 		evaltree(cmdentry.u.func, 0);
725 		funcnest--;
726 		INTOFF;
727 		poplocalvars();
728 		localvars = savelocalvars;
729 		freeparam(&shellparam);
730 		shellparam = saveparam;
731 		handler = savehandler;
732 		popredir();
733 		INTON;
734 		if (evalskip == SKIPFUNC) {
735 			evalskip = 0;
736 			skipcount = 0;
737 		}
738 		if (flags & EV_EXIT)
739 			exitshell(exitstatus);
740 	} else if (cmdentry.cmdtype == CMDBUILTIN) {
741 		trputs("builtin command:  ");  trargs(argv);
742 		mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
743 		if (flags == EV_BACKCMD) {
744 			memout.nleft = 0;
745 			memout.nextc = memout.buf;
746 			memout.bufsize = 64;
747 			mode |= REDIR_BACKQ;
748 		}
749 		redirect(cmd->ncmd.redirect, mode);
750 		savecmdname = commandname;
751 		cmdenviron = varlist.list;
752 		e = -1;
753 		if (setjmp(jmploc.loc)) {
754 			e = exception;
755 			exitstatus = (e == EXINT)? SIGINT+128 : 2;
756 			goto cmddone;
757 		}
758 		savehandler = handler;
759 		handler = &jmploc;
760 		commandname = argv[0];
761 		argptr = argv + 1;
762 		optptr = NULL;			/* initialize nextopt */
763 		exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
764 		flushall();
765 cmddone:
766 		out1 = &output;
767 		out2 = &errout;
768 		freestdout();
769 		if (e != EXSHELLPROC) {
770 			commandname = savecmdname;
771 			if (flags & EV_EXIT) {
772 				exitshell(exitstatus);
773 			}
774 		}
775 		handler = savehandler;
776 		if (e != -1) {
777 			if (e != EXERROR || cmdentry.u.index == BLTINCMD
778 					       || cmdentry.u.index == DOTCMD
779 					       || cmdentry.u.index == EVALCMD
780 #ifndef NO_HISTORY
781 					       || cmdentry.u.index == HISTCMD
782 #endif
783 					       || cmdentry.u.index == EXECCMD)
784 				exraise(e);
785 			FORCEINTON;
786 		}
787 		if (cmdentry.u.index != EXECCMD)
788 			popredir();
789 		if (flags == EV_BACKCMD) {
790 			backcmd->buf = memout.buf;
791 			backcmd->nleft = memout.nextc - memout.buf;
792 			memout.buf = NULL;
793 		}
794 	} else {
795 		trputs("normal command:  ");  trargs(argv);
796 		clearredir();
797 		redirect(cmd->ncmd.redirect, 0);
798 		for (sp = varlist.list ; sp ; sp = sp->next)
799 			setvareq(sp->text, VEXPORT|VSTACK);
800 		envp = environment();
801 		shellexec(argv, envp, pathval(), cmdentry.u.index);
802 		/*NOTREACHED*/
803 	}
804 	goto out;
805 
806 parent:	/* parent process gets here (if we forked) */
807 	if (mode == 0) {	/* argument to fork */
808 		INTOFF;
809 		exitstatus = waitforjob(jp);
810 		INTON;
811 	} else if (mode == 2) {
812 		backcmd->fd = pip[0];
813 		close(pip[1]);
814 		backcmd->jp = jp;
815 	}
816 
817 out:
818 	if (lastarg)
819 		setvar("_", lastarg, 0);
820 	popstackmark(&smark);
821 }
822 
823 
824 
825 /*
826  * Search for a command.  This is called before we fork so that the
827  * location of the command will be available in the parent as well as
828  * the child.  The check for "goodname" is an overly conservative
829  * check that the name will not be subject to expansion.
830  */
831 
832 STATIC void
833 prehash(n)
834 	union node *n;
835 	{
836 	struct cmdentry entry;
837 
838 	if (n->type == NCMD && n->ncmd.args)
839 		if (goodname(n->ncmd.args->narg.text))
840 			find_command(n->ncmd.args->narg.text, &entry, 0);
841 }
842 
843 
844 
845 /*
846  * Builtin commands.  Builtin commands whose functions are closely
847  * tied to evaluation are implemented here.
848  */
849 
850 /*
851  * No command given, or a bltin command with no arguments.  Set the
852  * specified variables.
853  */
854 
855 int
856 bltincmd(argc, argv)
857 	int argc;
858 	char **argv;
859 {
860 	listsetvar(cmdenviron);
861 	return 0;
862 }
863 
864 
865 /*
866  * Handle break and continue commands.  Break, continue, and return are
867  * all handled by setting the evalskip flag.  The evaluation routines
868  * above all check this flag, and if it is set they start skipping
869  * commands rather than executing them.  The variable skipcount is
870  * the number of loops to break/continue, or the number of function
871  * levels to return.  (The latter is always 1.)  It should probably
872  * be an error to break out of more loops than exist, but it isn't
873  * in the standard shell so we don't make it one here.
874  */
875 
876 int
877 breakcmd(argc, argv)
878 	int argc;
879 	char **argv;
880 {
881 	int n;
882 
883 	n = 1;
884 	if (argc > 1)
885 		n = number(argv[1]);
886 	if (n > loopnest)
887 		n = loopnest;
888 	if (n > 0) {
889 		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
890 		skipcount = n;
891 	}
892 	return 0;
893 }
894 
895 
896 /*
897  * The return command.
898  */
899 
900 int
901 returncmd(argc, argv)
902 	int argc;
903 	char **argv;
904 {
905 	int ret;
906 
907 	ret = exitstatus;
908 	if (argc > 1)
909 		ret = number(argv[1]);
910 	if (funcnest) {
911 		evalskip = SKIPFUNC;
912 		skipcount = 1;
913 	}
914 	return ret;
915 }
916 
917 
918 int
919 falsecmd(argc, argv)
920 	int argc;
921 	char **argv;
922 {
923 	return 1;
924 }
925 
926 
927 int
928 truecmd(argc, argv)
929 	int argc;
930 	char **argv;
931 {
932 	return 0;
933 }
934 
935 
936 int
937 execcmd(argc, argv)
938 	int argc;
939 	char **argv;
940 {
941 	if (argc > 1) {
942 		struct strlist *sp;
943 
944 		iflag = 0;		/* exit on error */
945 		mflag = 0;
946 		optschanged();
947 		for (sp = cmdenviron; sp ; sp = sp->next)
948 			setvareq(sp->text, VEXPORT|VSTACK);
949 		shellexec(argv + 1, environment(), pathval(), 0);
950 
951 	}
952 	return 0;
953 }
954