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