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