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