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