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