eval.c revision 60592
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 60592 2000-05-15 12:33:17Z 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	int do_clearcmdentry;
616#if __GNUC__
617	/* Avoid longjmp clobbering */
618	(void) &argv;
619	(void) &argc;
620	(void) &lastarg;
621	(void) &flags;
622	(void) &do_clearcmdentry;
623#endif
624
625	/* First expand the arguments. */
626	TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
627	setstackmark(&smark);
628	arglist.lastp = &arglist.list;
629	varlist.lastp = &varlist.list;
630	varflag = 1;
631	do_clearcmdentry = 0;
632	oexitstatus = exitstatus;
633	exitstatus = 0;
634	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
635		char *p = argp->narg.text;
636		if (varflag && is_name(*p)) {
637			do {
638				p++;
639			} while (is_in_name(*p));
640			if (*p == '=') {
641				expandarg(argp, &varlist, EXP_VARTILDE);
642				continue;
643			}
644		}
645		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
646		varflag = 0;
647	}
648	*arglist.lastp = NULL;
649	*varlist.lastp = NULL;
650	expredir(cmd->ncmd.redirect);
651	argc = 0;
652	for (sp = arglist.list ; sp ; sp = sp->next)
653		argc++;
654	argv = stalloc(sizeof (char *) * (argc + 1));
655
656	for (sp = arglist.list ; sp ; sp = sp->next) {
657		TRACE(("evalcommand arg: %s\n", sp->text));
658		*argv++ = sp->text;
659	}
660	*argv = NULL;
661	lastarg = NULL;
662	if (iflag && funcnest == 0 && argc > 0)
663		lastarg = argv[-1];
664	argv -= argc;
665
666	/* Print the command if xflag is set. */
667	if (xflag) {
668		outc('+', &errout);
669		for (sp = varlist.list ; sp ; sp = sp->next) {
670			outc(' ', &errout);
671			out2str(sp->text);
672		}
673		for (sp = arglist.list ; sp ; sp = sp->next) {
674			outc(' ', &errout);
675			out2str(sp->text);
676		}
677		outc('\n', &errout);
678		flushout(&errout);
679	}
680
681	/* Now locate the command. */
682	if (argc == 0) {
683		cmdentry.cmdtype = CMDBUILTIN;
684		cmdentry.u.index = BLTINCMD;
685	} else {
686		static const char PATH[] = "PATH=";
687		char *path = pathval();
688
689		/*
690		 * Modify the command lookup path, if a PATH= assignment
691		 * is present
692		 */
693		for (sp = varlist.list ; sp ; sp = sp->next)
694			if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) {
695				path = sp->text + sizeof(PATH) - 1;
696				/*
697				 * On `PATH=... command`, we need to make
698				 * sure that the command isn't using the
699				 * non-updated hash table of the outer PATH
700				 * setting and we need to make sure that
701				 * the hash table isn't filled with items
702				 * from the temporary setting.
703				 *
704				 * It would be better to forbit using and
705				 * updating the table while this command
706				 * runs, by the command finding mechanism
707				 * is heavily integrated with hash handling,
708				 * so we just delete the hash before and after
709				 * the command runs. Partly deleting like
710				 * changepatch() does doesn't seem worth the
711				 * bookinging effort, since most such runs add
712				 * diretories in front of the new PATH.
713				 */
714				clearcmdentry(0);
715				do_clearcmdentry = 1;
716			}
717
718		find_command(argv[0], &cmdentry, 1, path);
719		if (cmdentry.cmdtype == CMDUNKNOWN) {	/* command not found */
720			exitstatus = 127;
721			flushout(&errout);
722			return;
723		}
724		/* implement the bltin builtin here */
725		if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
726			for (;;) {
727				argv++;
728				if (--argc == 0)
729					break;
730				if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
731					outfmt(&errout, "%s: not found\n", *argv);
732					exitstatus = 127;
733					flushout(&errout);
734					return;
735				}
736				if (cmdentry.u.index != BLTINCMD)
737					break;
738			}
739		}
740	}
741
742	/* Fork off a child process if necessary. */
743	if (cmd->ncmd.backgnd
744	 || (cmdentry.cmdtype == CMDNORMAL
745	    && ((flags & EV_EXIT) == 0 || Tflag))
746	 || ((flags & EV_BACKCMD) != 0
747	    && (cmdentry.cmdtype != CMDBUILTIN
748		 || cmdentry.u.index == CDCMD
749		 || cmdentry.u.index == DOTCMD
750		 || cmdentry.u.index == EVALCMD))) {
751		jp = makejob(cmd, 1);
752		mode = cmd->ncmd.backgnd;
753		if (flags & EV_BACKCMD) {
754			mode = FORK_NOJOB;
755			if (pipe(pip) < 0)
756				error("Pipe call failed: %s", strerror(errno));
757		}
758		if (forkshell(jp, cmd, mode) != 0)
759			goto parent;	/* at end of routine */
760		if (flags & EV_BACKCMD) {
761			FORCEINTON;
762			close(pip[0]);
763			if (pip[1] != 1) {
764				close(1);
765				copyfd(pip[1], 1);
766				close(pip[1]);
767			}
768		}
769		flags |= EV_EXIT;
770	}
771
772	/* This is the child process if a fork occurred. */
773	/* Execute the command. */
774	if (cmdentry.cmdtype == CMDFUNCTION) {
775#ifdef DEBUG
776		trputs("Shell function:  ");  trargs(argv);
777#endif
778		redirect(cmd->ncmd.redirect, REDIR_PUSH);
779		saveparam = shellparam;
780		shellparam.malloc = 0;
781		shellparam.reset = 1;
782		shellparam.nparam = argc - 1;
783		shellparam.p = argv + 1;
784		shellparam.optnext = NULL;
785		INTOFF;
786		savelocalvars = localvars;
787		localvars = NULL;
788		INTON;
789		if (setjmp(jmploc.loc)) {
790			if (exception == EXSHELLPROC)
791				freeparam((struct shparam *)&saveparam);
792			else {
793				freeparam(&shellparam);
794				shellparam = saveparam;
795			}
796			poplocalvars();
797			localvars = savelocalvars;
798			handler = savehandler;
799			longjmp(handler->loc, 1);
800		}
801		savehandler = handler;
802		handler = &jmploc;
803		for (sp = varlist.list ; sp ; sp = sp->next)
804			mklocal(sp->text);
805		funcnest++;
806		if (flags & EV_TESTED)
807			evaltree(cmdentry.u.func, EV_TESTED);
808		else
809			evaltree(cmdentry.u.func, 0);
810		funcnest--;
811		INTOFF;
812		poplocalvars();
813		localvars = savelocalvars;
814		freeparam(&shellparam);
815		shellparam = saveparam;
816		handler = savehandler;
817		popredir();
818		INTON;
819		if (evalskip == SKIPFUNC) {
820			evalskip = 0;
821			skipcount = 0;
822		}
823		if (flags & EV_EXIT)
824			exitshell(exitstatus);
825	} else if (cmdentry.cmdtype == CMDBUILTIN) {
826#ifdef DEBUG
827		trputs("builtin command:  ");  trargs(argv);
828#endif
829		mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
830		if (flags == EV_BACKCMD) {
831			memout.nleft = 0;
832			memout.nextc = memout.buf;
833			memout.bufsize = 64;
834			mode |= REDIR_BACKQ;
835		}
836		redirect(cmd->ncmd.redirect, mode);
837		savecmdname = commandname;
838		cmdenviron = varlist.list;
839		e = -1;
840		if (setjmp(jmploc.loc)) {
841			e = exception;
842			exitstatus = (e == EXINT)? SIGINT+128 : 2;
843			goto cmddone;
844		}
845		savehandler = handler;
846		handler = &jmploc;
847		commandname = argv[0];
848		argptr = argv + 1;
849		optptr = NULL;			/* initialize nextopt */
850		exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
851		flushall();
852cmddone:
853		cmdenviron = NULL;
854		out1 = &output;
855		out2 = &errout;
856		freestdout();
857		if (e != EXSHELLPROC) {
858			commandname = savecmdname;
859			if (flags & EV_EXIT) {
860				exitshell(exitstatus);
861			}
862		}
863		handler = savehandler;
864		if (e != -1) {
865			if ((e != EXERROR && e != EXEXEC)
866			   || cmdentry.u.index == BLTINCMD
867			   || cmdentry.u.index == DOTCMD
868			   || cmdentry.u.index == EVALCMD
869#ifndef NO_HISTORY
870			   || cmdentry.u.index == HISTCMD
871#endif
872			   || cmdentry.u.index == EXECCMD)
873				exraise(e);
874			FORCEINTON;
875		}
876		if (cmdentry.u.index != EXECCMD)
877			popredir();
878		if (flags == EV_BACKCMD) {
879			backcmd->buf = memout.buf;
880			backcmd->nleft = memout.nextc - memout.buf;
881			memout.buf = NULL;
882		}
883	} else {
884#ifdef DEBUG
885		trputs("normal command:  ");  trargs(argv);
886#endif
887		clearredir();
888		redirect(cmd->ncmd.redirect, 0);
889		for (sp = varlist.list ; sp ; sp = sp->next)
890			setvareq(sp->text, VEXPORT|VSTACK);
891		envp = environment();
892		shellexec(argv, envp, pathval(), cmdentry.u.index);
893		/*NOTREACHED*/
894	}
895	goto out;
896
897parent:	/* parent process gets here (if we forked) */
898	if (mode == 0) {	/* argument to fork */
899		INTOFF;
900		exitstatus = waitforjob(jp, &realstatus);
901		INTON;
902		if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) {
903			evalskip = SKIPBREAK;
904			skipcount = loopnest;
905		}
906	} else if (mode == 2) {
907		backcmd->fd = pip[0];
908		close(pip[1]);
909		backcmd->jp = jp;
910	}
911
912out:
913	if (lastarg)
914		setvar("_", lastarg, 0);
915	if (do_clearcmdentry)
916		clearcmdentry(0);
917	popstackmark(&smark);
918}
919
920
921
922/*
923 * Search for a command.  This is called before we fork so that the
924 * location of the command will be available in the parent as well as
925 * the child.  The check for "goodname" is an overly conservative
926 * check that the name will not be subject to expansion.
927 */
928
929STATIC void
930prehash(n)
931	union node *n;
932{
933	struct cmdentry entry;
934
935	if (n->type == NCMD && n->ncmd.args)
936		if (goodname(n->ncmd.args->narg.text))
937			find_command(n->ncmd.args->narg.text, &entry, 0,
938				     pathval());
939}
940
941
942
943/*
944 * Builtin commands.  Builtin commands whose functions are closely
945 * tied to evaluation are implemented here.
946 */
947
948/*
949 * No command given, or a bltin command with no arguments.  Set the
950 * specified variables.
951 */
952
953int
954bltincmd(argc, argv)
955	int argc __unused;
956	char **argv __unused;
957{
958	listsetvar(cmdenviron);
959	/*
960	 * Preserve exitstatus of a previous possible redirection
961	 * as POSIX mandates
962	 */
963	return exitstatus;
964}
965
966
967/*
968 * Handle break and continue commands.  Break, continue, and return are
969 * all handled by setting the evalskip flag.  The evaluation routines
970 * above all check this flag, and if it is set they start skipping
971 * commands rather than executing them.  The variable skipcount is
972 * the number of loops to break/continue, or the number of function
973 * levels to return.  (The latter is always 1.)  It should probably
974 * be an error to break out of more loops than exist, but it isn't
975 * in the standard shell so we don't make it one here.
976 */
977
978int
979breakcmd(argc, argv)
980	int argc;
981	char **argv;
982{
983	int n = argc > 1 ? number(argv[1]) : 1;
984
985	if (n > loopnest)
986		n = loopnest;
987	if (n > 0) {
988		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
989		skipcount = n;
990	}
991	return 0;
992}
993
994
995/*
996 * The return command.
997 */
998
999int
1000returncmd(argc, argv)
1001	int argc;
1002	char **argv;
1003{
1004	int ret = argc > 1 ? number(argv[1]) : oexitstatus;
1005
1006	if (funcnest) {
1007		evalskip = SKIPFUNC;
1008		skipcount = 1;
1009	} else {
1010		/* skip the rest of the file */
1011		evalskip = SKIPFILE;
1012		skipcount = 1;
1013	}
1014	return ret;
1015}
1016
1017
1018int
1019falsecmd(argc, argv)
1020	int argc __unused;
1021	char **argv __unused;
1022{
1023	return 1;
1024}
1025
1026
1027int
1028truecmd(argc, argv)
1029	int argc __unused;
1030	char **argv __unused;
1031{
1032	return 0;
1033}
1034
1035
1036int
1037execcmd(argc, argv)
1038	int argc;
1039	char **argv;
1040{
1041	if (argc > 1) {
1042		struct strlist *sp;
1043
1044		iflag = 0;		/* exit on error */
1045		mflag = 0;
1046		optschanged();
1047		for (sp = cmdenviron; sp ; sp = sp->next)
1048			setvareq(sp->text, VEXPORT|VSTACK);
1049		shellexec(argv + 1, environment(), pathval(), 0);
1050
1051	}
1052	return 0;
1053}
1054