eval.c revision 228015
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 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)eval.c	8.9 (Berkeley) 6/8/95";
36#endif
37#endif /* not lint */
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD: head/bin/sh/eval.c 228015 2011-11-27 00:09:59Z jilles $");
40
41#include <paths.h>
42#include <signal.h>
43#include <stdlib.h>
44#include <unistd.h>
45#include <sys/resource.h>
46#include <sys/wait.h> /* For WIFSIGNALED(status) */
47#include <errno.h>
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
77int evalskip;			/* set if we are skipping commands */
78static int skipcount;		/* number of levels to skip */
79MKINIT int loopnest;		/* current loop nesting level */
80int funcnest;			/* depth of function calls */
81static int builtin_flags;	/* evalcommand flags for builtins */
82
83
84char *commandname;
85struct strlist *cmdenviron;
86int exitstatus;			/* exit status of last command */
87int oexitstatus;		/* saved exit status */
88
89
90static void evalloop(union node *, int);
91static void evalfor(union node *, int);
92static union node *evalcase(union node *, int);
93static void evalsubshell(union node *, int);
94static void evalredir(union node *, int);
95static void expredir(union node *);
96static void evalpipe(union node *);
97static int is_valid_fast_cmdsubst(union node *n);
98static void evalcommand(union node *, int, struct backcmd *);
99static void prehash(union node *);
100
101
102/*
103 * Called to reset things after an exception.
104 */
105
106#ifdef mkinit
107INCLUDE "eval.h"
108
109RESET {
110	evalskip = 0;
111	loopnest = 0;
112	funcnest = 0;
113}
114#endif
115
116
117
118/*
119 * The eval command.
120 */
121
122int
123evalcmd(int argc, char **argv)
124{
125        char *p;
126        char *concat;
127        char **ap;
128
129        if (argc > 1) {
130                p = argv[1];
131                if (argc > 2) {
132                        STARTSTACKSTR(concat);
133                        ap = argv + 2;
134                        for (;;) {
135                                STPUTS(p, concat);
136                                if ((p = *ap++) == NULL)
137                                        break;
138                                STPUTC(' ', concat);
139                        }
140                        STPUTC('\0', concat);
141                        p = grabstackstr(concat);
142                }
143                evalstring(p, builtin_flags);
144        } else
145                exitstatus = 0;
146        return exitstatus;
147}
148
149
150/*
151 * Execute a command or commands contained in a string.
152 */
153
154void
155evalstring(char *s, int flags)
156{
157	union node *n;
158	struct stackmark smark;
159	int flags_exit;
160	int any;
161
162	flags_exit = flags & EV_EXIT;
163	flags &= ~EV_EXIT;
164	any = 0;
165	setstackmark(&smark);
166	setinputstring(s, 1);
167	while ((n = parsecmd(0)) != NEOF) {
168		if (n != NULL && !nflag) {
169			if (flags_exit && preadateof())
170				evaltree(n, flags | EV_EXIT);
171			else
172				evaltree(n, flags);
173			any = 1;
174		}
175		popstackmark(&smark);
176	}
177	popfile();
178	popstackmark(&smark);
179	if (!any)
180		exitstatus = 0;
181	if (flags_exit)
182		exraise(EXEXIT);
183}
184
185
186/*
187 * Evaluate a parse tree.  The value is left in the global variable
188 * exitstatus.
189 */
190
191void
192evaltree(union node *n, int flags)
193{
194	int do_etest;
195	union node *next;
196
197	do_etest = 0;
198	if (n == NULL) {
199		TRACE(("evaltree(NULL) called\n"));
200		exitstatus = 0;
201		goto out;
202	}
203	do {
204		next = NULL;
205#ifndef NO_HISTORY
206		displayhist = 1;	/* show history substitutions done with fc */
207#endif
208		TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type));
209		switch (n->type) {
210		case NSEMI:
211			evaltree(n->nbinary.ch1, flags & ~EV_EXIT);
212			if (evalskip)
213				goto out;
214			next = n->nbinary.ch2;
215			break;
216		case NAND:
217			evaltree(n->nbinary.ch1, EV_TESTED);
218			if (evalskip || exitstatus != 0) {
219				goto out;
220			}
221			next = n->nbinary.ch2;
222			break;
223		case NOR:
224			evaltree(n->nbinary.ch1, EV_TESTED);
225			if (evalskip || exitstatus == 0)
226				goto out;
227			next = n->nbinary.ch2;
228			break;
229		case NREDIR:
230			evalredir(n, flags);
231			break;
232		case NSUBSHELL:
233			evalsubshell(n, flags);
234			do_etest = !(flags & EV_TESTED);
235			break;
236		case NBACKGND:
237			evalsubshell(n, flags);
238			break;
239		case NIF: {
240			evaltree(n->nif.test, EV_TESTED);
241			if (evalskip)
242				goto out;
243			if (exitstatus == 0)
244				next = n->nif.ifpart;
245			else if (n->nif.elsepart)
246				next = n->nif.elsepart;
247			else
248				exitstatus = 0;
249			break;
250		}
251		case NWHILE:
252		case NUNTIL:
253			evalloop(n, flags & ~EV_EXIT);
254			break;
255		case NFOR:
256			evalfor(n, flags & ~EV_EXIT);
257			break;
258		case NCASE:
259			next = evalcase(n, flags);
260			break;
261		case NDEFUN:
262			defun(n->narg.text, n->narg.next);
263			exitstatus = 0;
264			break;
265		case NNOT:
266			evaltree(n->nnot.com, EV_TESTED);
267			exitstatus = !exitstatus;
268			break;
269
270		case NPIPE:
271			evalpipe(n);
272			do_etest = !(flags & EV_TESTED);
273			break;
274		case NCMD:
275			evalcommand(n, flags, (struct backcmd *)NULL);
276			do_etest = !(flags & EV_TESTED);
277			break;
278		default:
279			out1fmt("Node type = %d\n", n->type);
280			flushout(&output);
281			break;
282		}
283		n = next;
284	} while (n != NULL);
285out:
286	if (pendingsigs)
287		dotrap();
288	if (eflag && exitstatus != 0 && do_etest)
289		exitshell(exitstatus);
290	if (flags & EV_EXIT)
291		exraise(EXEXIT);
292}
293
294
295static void
296evalloop(union node *n, int flags)
297{
298	int status;
299
300	loopnest++;
301	status = 0;
302	for (;;) {
303		evaltree(n->nbinary.ch1, EV_TESTED);
304		if (evalskip) {
305skipping:	  if (evalskip == SKIPCONT && --skipcount <= 0) {
306				evalskip = 0;
307				continue;
308			}
309			if (evalskip == SKIPBREAK && --skipcount <= 0)
310				evalskip = 0;
311			if (evalskip == SKIPFUNC || evalskip == SKIPFILE)
312				status = exitstatus;
313			break;
314		}
315		if (n->type == NWHILE) {
316			if (exitstatus != 0)
317				break;
318		} else {
319			if (exitstatus == 0)
320				break;
321		}
322		evaltree(n->nbinary.ch2, flags);
323		status = exitstatus;
324		if (evalskip)
325			goto skipping;
326	}
327	loopnest--;
328	exitstatus = status;
329}
330
331
332
333static void
334evalfor(union node *n, int flags)
335{
336	struct arglist arglist;
337	union node *argp;
338	struct strlist *sp;
339	struct stackmark smark;
340
341	setstackmark(&smark);
342	arglist.lastp = &arglist.list;
343	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
344		oexitstatus = exitstatus;
345		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
346	}
347	*arglist.lastp = NULL;
348
349	exitstatus = 0;
350	loopnest++;
351	for (sp = arglist.list ; sp ; sp = sp->next) {
352		setvar(n->nfor.var, sp->text, 0);
353		evaltree(n->nfor.body, flags);
354		if (evalskip) {
355			if (evalskip == SKIPCONT && --skipcount <= 0) {
356				evalskip = 0;
357				continue;
358			}
359			if (evalskip == SKIPBREAK && --skipcount <= 0)
360				evalskip = 0;
361			break;
362		}
363	}
364	loopnest--;
365	popstackmark(&smark);
366}
367
368
369
370static union node *
371evalcase(union node *n, 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	exitstatus = 0;
382	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
383	for (cp = n->ncase.cases ; cp ; cp = cp->nclist.next) {
384		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
385			if (casematch(patp, arglist.list->text)) {
386				popstackmark(&smark);
387				while (cp->nclist.next &&
388				    cp->type == NCLISTFALLTHRU) {
389					evaltree(cp->nclist.body,
390					    flags & ~EV_EXIT);
391					if (evalskip != 0)
392						return (NULL);
393					cp = cp->nclist.next;
394				}
395				return (cp->nclist.body);
396			}
397		}
398	}
399	popstackmark(&smark);
400	return (NULL);
401}
402
403
404
405/*
406 * Kick off a subshell to evaluate a tree.
407 */
408
409static void
410evalsubshell(union node *n, int flags)
411{
412	struct job *jp;
413	int backgnd = (n->type == NBACKGND);
414
415	oexitstatus = exitstatus;
416	expredir(n->nredir.redirect);
417	if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
418			forkshell(jp = makejob(n, 1), n, backgnd) == 0) {
419		if (backgnd)
420			flags &=~ EV_TESTED;
421		redirect(n->nredir.redirect, 0);
422		evaltree(n->nredir.n, flags | EV_EXIT);	/* never returns */
423	} else if (! backgnd) {
424		INTOFF;
425		exitstatus = waitforjob(jp, (int *)NULL);
426		INTON;
427	} else
428		exitstatus = 0;
429}
430
431
432/*
433 * Evaluate a redirected compound command.
434 */
435
436static void
437evalredir(union node *n, int flags)
438{
439	struct jmploc jmploc;
440	struct jmploc *savehandler;
441	volatile int in_redirect = 1;
442
443	oexitstatus = exitstatus;
444	expredir(n->nredir.redirect);
445	savehandler = handler;
446	if (setjmp(jmploc.loc)) {
447		int e;
448
449		handler = savehandler;
450		e = exception;
451		popredir();
452		if (e == EXERROR || e == EXEXEC) {
453			if (in_redirect) {
454				exitstatus = 2;
455				return;
456			}
457		}
458		longjmp(handler->loc, 1);
459	} else {
460		INTOFF;
461		handler = &jmploc;
462		redirect(n->nredir.redirect, REDIR_PUSH);
463		in_redirect = 0;
464		INTON;
465		evaltree(n->nredir.n, flags);
466	}
467	INTOFF;
468	handler = savehandler;
469	popredir();
470	INTON;
471}
472
473
474/*
475 * Compute the names of the files in a redirection list.
476 */
477
478static void
479expredir(union node *n)
480{
481	union node *redir;
482
483	for (redir = n ; redir ; redir = redir->nfile.next) {
484		struct arglist fn;
485		fn.lastp = &fn.list;
486		switch (redir->type) {
487		case NFROM:
488		case NTO:
489		case NFROMTO:
490		case NAPPEND:
491		case NCLOBBER:
492			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
493			redir->nfile.expfname = fn.list->text;
494			break;
495		case NFROMFD:
496		case NTOFD:
497			if (redir->ndup.vname) {
498				expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
499				fixredir(redir, fn.list->text, 1);
500			}
501			break;
502		}
503	}
504}
505
506
507
508/*
509 * Evaluate a pipeline.  All the processes in the pipeline are children
510 * of the process creating the pipeline.  (This differs from some versions
511 * of the shell, which make the last process in a pipeline the parent
512 * of all the rest.)
513 */
514
515static void
516evalpipe(union node *n)
517{
518	struct job *jp;
519	struct nodelist *lp;
520	int pipelen;
521	int prevfd;
522	int pip[2];
523
524	TRACE(("evalpipe(%p) called\n", (void *)n));
525	pipelen = 0;
526	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
527		pipelen++;
528	INTOFF;
529	jp = makejob(n, pipelen);
530	prevfd = -1;
531	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
532		prehash(lp->n);
533		pip[1] = -1;
534		if (lp->next) {
535			if (pipe(pip) < 0) {
536				close(prevfd);
537				error("Pipe call failed: %s", strerror(errno));
538			}
539		}
540		if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
541			INTON;
542			if (prevfd > 0) {
543				dup2(prevfd, 0);
544				close(prevfd);
545			}
546			if (pip[1] >= 0) {
547				if (!(prevfd >= 0 && pip[0] == 0))
548					close(pip[0]);
549				if (pip[1] != 1) {
550					dup2(pip[1], 1);
551					close(pip[1]);
552				}
553			}
554			evaltree(lp->n, EV_EXIT);
555		}
556		if (prevfd >= 0)
557			close(prevfd);
558		prevfd = pip[0];
559		if (pip[1] != -1)
560			close(pip[1]);
561	}
562	INTON;
563	if (n->npipe.backgnd == 0) {
564		INTOFF;
565		exitstatus = waitforjob(jp, (int *)NULL);
566		TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
567		INTON;
568	} else
569		exitstatus = 0;
570}
571
572
573
574static int
575is_valid_fast_cmdsubst(union node *n)
576{
577
578	return (n->type == NCMD);
579}
580
581/*
582 * Execute a command inside back quotes.  If it's a builtin command, we
583 * want to save its output in a block obtained from malloc.  Otherwise
584 * we fork off a subprocess and get the output of the command via a pipe.
585 * Should be called with interrupts off.
586 */
587
588void
589evalbackcmd(union node *n, struct backcmd *result)
590{
591	int pip[2];
592	struct job *jp;
593	struct stackmark smark;		/* unnecessary */
594	struct jmploc jmploc;
595	struct jmploc *savehandler;
596	struct localvar *savelocalvars;
597
598	setstackmark(&smark);
599	result->fd = -1;
600	result->buf = NULL;
601	result->nleft = 0;
602	result->jp = NULL;
603	if (n == NULL) {
604		exitstatus = 0;
605		goto out;
606	}
607	if (is_valid_fast_cmdsubst(n)) {
608		exitstatus = oexitstatus;
609		savelocalvars = localvars;
610		localvars = NULL;
611		forcelocal++;
612		savehandler = handler;
613		if (setjmp(jmploc.loc)) {
614			if (exception == EXERROR || exception == EXEXEC)
615				exitstatus = 2;
616			else if (exception != 0) {
617				handler = savehandler;
618				forcelocal--;
619				poplocalvars();
620				localvars = savelocalvars;
621				longjmp(handler->loc, 1);
622			}
623		} else {
624			handler = &jmploc;
625			evalcommand(n, EV_BACKCMD, result);
626		}
627		handler = savehandler;
628		forcelocal--;
629		poplocalvars();
630		localvars = savelocalvars;
631	} else {
632		exitstatus = 0;
633		if (pipe(pip) < 0)
634			error("Pipe call failed: %s", strerror(errno));
635		jp = makejob(n, 1);
636		if (forkshell(jp, n, FORK_NOJOB) == 0) {
637			FORCEINTON;
638			close(pip[0]);
639			if (pip[1] != 1) {
640				dup2(pip[1], 1);
641				close(pip[1]);
642			}
643			evaltree(n, EV_EXIT);
644		}
645		close(pip[1]);
646		result->fd = pip[0];
647		result->jp = jp;
648	}
649out:
650	popstackmark(&smark);
651	TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
652		result->fd, result->buf, result->nleft, result->jp));
653}
654
655/*
656 * Check if a builtin can safely be executed in the same process,
657 * even though it should be in a subshell (command substitution).
658 * Note that jobid, jobs, times and trap can show information not
659 * available in a child process; this is deliberate.
660 * The arguments should already have been expanded.
661 */
662static int
663safe_builtin(int idx, int argc, char **argv)
664{
665	if (idx == BLTINCMD || idx == COMMANDCMD || idx == ECHOCMD ||
666	    idx == FALSECMD || idx == JOBIDCMD || idx == JOBSCMD ||
667	    idx == KILLCMD || idx == PRINTFCMD || idx == PWDCMD ||
668	    idx == TESTCMD || idx == TIMESCMD || idx == TRUECMD ||
669	    idx == TYPECMD)
670		return (1);
671	if (idx == EXPORTCMD || idx == TRAPCMD || idx == ULIMITCMD ||
672	    idx == UMASKCMD)
673		return (argc <= 1 || (argc == 2 && argv[1][0] == '-'));
674	if (idx == SETCMD)
675		return (argc <= 1 || (argc == 2 && (argv[1][0] == '-' ||
676		    argv[1][0] == '+') && argv[1][1] == 'o' &&
677		    argv[1][2] == '\0'));
678	return (0);
679}
680
681/*
682 * Execute a simple command.
683 * Note: This may or may not return if (flags & EV_EXIT).
684 */
685
686static void
687evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
688{
689	struct stackmark smark;
690	union node *argp;
691	struct arglist arglist;
692	struct arglist varlist;
693	char **argv;
694	int argc;
695	char **envp;
696	int varflag;
697	struct strlist *sp;
698	int mode;
699	int pip[2];
700	struct cmdentry cmdentry;
701	struct job *jp;
702	struct jmploc jmploc;
703	struct jmploc *savehandler;
704	char *savecmdname;
705	struct shparam saveparam;
706	struct localvar *savelocalvars;
707	struct parsefile *savetopfile;
708	volatile int e;
709	char *lastarg;
710	int realstatus;
711	int do_clearcmdentry;
712	const char *path = pathval();
713
714	/* First expand the arguments. */
715	TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
716	setstackmark(&smark);
717	arglist.lastp = &arglist.list;
718	varlist.lastp = &varlist.list;
719	varflag = 1;
720	jp = NULL;
721	do_clearcmdentry = 0;
722	oexitstatus = exitstatus;
723	exitstatus = 0;
724	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
725		if (varflag && isassignment(argp->narg.text)) {
726			expandarg(argp, &varlist, EXP_VARTILDE);
727			continue;
728		}
729		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
730		varflag = 0;
731	}
732	*arglist.lastp = NULL;
733	*varlist.lastp = NULL;
734	expredir(cmd->ncmd.redirect);
735	argc = 0;
736	for (sp = arglist.list ; sp ; sp = sp->next)
737		argc++;
738	/* Add one slot at the beginning for tryexec(). */
739	argv = stalloc(sizeof (char *) * (argc + 2));
740	argv++;
741
742	for (sp = arglist.list ; sp ; sp = sp->next) {
743		TRACE(("evalcommand arg: %s\n", sp->text));
744		*argv++ = sp->text;
745	}
746	*argv = NULL;
747	lastarg = NULL;
748	if (iflag && funcnest == 0 && argc > 0)
749		lastarg = argv[-1];
750	argv -= argc;
751
752	/* Print the command if xflag is set. */
753	if (xflag) {
754		char sep = 0;
755		const char *p, *ps4;
756		ps4 = expandstr(ps4val());
757		out2str(ps4 != NULL ? ps4 : ps4val());
758		for (sp = varlist.list ; sp ; sp = sp->next) {
759			if (sep != 0)
760				out2c(' ');
761			p = strchr(sp->text, '=');
762			if (p != NULL) {
763				p++;
764				outbin(sp->text, p - sp->text, out2);
765				out2qstr(p);
766			} else
767				out2qstr(sp->text);
768			sep = ' ';
769		}
770		for (sp = arglist.list ; sp ; sp = sp->next) {
771			if (sep != 0)
772				out2c(' ');
773			/* Disambiguate command looking like assignment. */
774			if (sp == arglist.list &&
775					strchr(sp->text, '=') != NULL &&
776					strchr(sp->text, '\'') == NULL) {
777				out2c('\'');
778				out2str(sp->text);
779				out2c('\'');
780			} else
781				out2qstr(sp->text);
782			sep = ' ';
783		}
784		out2c('\n');
785		flushout(&errout);
786	}
787
788	/* Now locate the command. */
789	if (argc == 0) {
790		/* Variable assignment(s) without command */
791		cmdentry.cmdtype = CMDBUILTIN;
792		cmdentry.u.index = BLTINCMD;
793		cmdentry.special = 0;
794	} else {
795		static const char PATH[] = "PATH=";
796		int cmd_flags = 0, bltinonly = 0;
797
798		/*
799		 * Modify the command lookup path, if a PATH= assignment
800		 * is present
801		 */
802		for (sp = varlist.list ; sp ; sp = sp->next)
803			if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) {
804				path = sp->text + sizeof(PATH) - 1;
805				/*
806				 * On `PATH=... command`, we need to make
807				 * sure that the command isn't using the
808				 * non-updated hash table of the outer PATH
809				 * setting and we need to make sure that
810				 * the hash table isn't filled with items
811				 * from the temporary setting.
812				 *
813				 * It would be better to forbit using and
814				 * updating the table while this command
815				 * runs, by the command finding mechanism
816				 * is heavily integrated with hash handling,
817				 * so we just delete the hash before and after
818				 * the command runs. Partly deleting like
819				 * changepatch() does doesn't seem worth the
820				 * bookinging effort, since most such runs add
821				 * directories in front of the new PATH.
822				 */
823				clearcmdentry();
824				do_clearcmdentry = 1;
825			}
826
827		for (;;) {
828			if (bltinonly) {
829				cmdentry.u.index = find_builtin(*argv, &cmdentry.special);
830				if (cmdentry.u.index < 0) {
831					cmdentry.u.index = BLTINCMD;
832					argv--;
833					argc++;
834					break;
835				}
836			} else
837				find_command(argv[0], &cmdentry, cmd_flags, path);
838			/* implement the bltin and command builtins here */
839			if (cmdentry.cmdtype != CMDBUILTIN)
840				break;
841			if (cmdentry.u.index == BLTINCMD) {
842				if (argc == 1)
843					break;
844				argv++;
845				argc--;
846				bltinonly = 1;
847			} else if (cmdentry.u.index == COMMANDCMD) {
848				if (argc == 1)
849					break;
850				if (!strcmp(argv[1], "-p")) {
851					if (argc == 2)
852						break;
853					if (argv[2][0] == '-') {
854						if (strcmp(argv[2], "--"))
855							break;
856						if (argc == 3)
857							break;
858						argv += 3;
859						argc -= 3;
860					} else {
861						argv += 2;
862						argc -= 2;
863					}
864					path = _PATH_STDPATH;
865					clearcmdentry();
866					do_clearcmdentry = 1;
867				} else if (!strcmp(argv[1], "--")) {
868					if (argc == 2)
869						break;
870					argv += 2;
871					argc -= 2;
872				} else if (argv[1][0] == '-')
873					break;
874				else {
875					argv++;
876					argc--;
877				}
878				cmd_flags |= DO_NOFUNC;
879				bltinonly = 0;
880			} else
881				break;
882		}
883		/*
884		 * Special builtins lose their special properties when
885		 * called via 'command'.
886		 */
887		if (cmd_flags & DO_NOFUNC)
888			cmdentry.special = 0;
889	}
890
891	/* Fork off a child process if necessary. */
892	if (((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
893	    && ((flags & EV_EXIT) == 0 || have_traps()))
894	 || ((flags & EV_BACKCMD) != 0
895	    && (cmdentry.cmdtype != CMDBUILTIN ||
896		 !safe_builtin(cmdentry.u.index, argc, argv)))) {
897		jp = makejob(cmd, 1);
898		mode = FORK_FG;
899		if (flags & EV_BACKCMD) {
900			mode = FORK_NOJOB;
901			if (pipe(pip) < 0)
902				error("Pipe call failed: %s", strerror(errno));
903		}
904		if (forkshell(jp, cmd, mode) != 0)
905			goto parent;	/* at end of routine */
906		if (flags & EV_BACKCMD) {
907			FORCEINTON;
908			close(pip[0]);
909			if (pip[1] != 1) {
910				dup2(pip[1], 1);
911				close(pip[1]);
912			}
913			flags &= ~EV_BACKCMD;
914		}
915		flags |= EV_EXIT;
916	}
917
918	/* This is the child process if a fork occurred. */
919	/* Execute the command. */
920	if (cmdentry.cmdtype == CMDFUNCTION) {
921#ifdef DEBUG
922		trputs("Shell function:  ");  trargs(argv);
923#endif
924		saveparam = shellparam;
925		shellparam.malloc = 0;
926		shellparam.reset = 1;
927		shellparam.nparam = argc - 1;
928		shellparam.p = argv + 1;
929		shellparam.optnext = NULL;
930		INTOFF;
931		savelocalvars = localvars;
932		localvars = NULL;
933		reffunc(cmdentry.u.func);
934		savehandler = handler;
935		if (setjmp(jmploc.loc)) {
936			freeparam(&shellparam);
937			shellparam = saveparam;
938			popredir();
939			unreffunc(cmdentry.u.func);
940			poplocalvars();
941			localvars = savelocalvars;
942			funcnest--;
943			handler = savehandler;
944			longjmp(handler->loc, 1);
945		}
946		handler = &jmploc;
947		funcnest++;
948		redirect(cmd->ncmd.redirect, REDIR_PUSH);
949		INTON;
950		for (sp = varlist.list ; sp ; sp = sp->next)
951			mklocal(sp->text);
952		exitstatus = oexitstatus;
953		evaltree(getfuncnode(cmdentry.u.func),
954		    flags & (EV_TESTED | EV_EXIT));
955		INTOFF;
956		unreffunc(cmdentry.u.func);
957		poplocalvars();
958		localvars = savelocalvars;
959		freeparam(&shellparam);
960		shellparam = saveparam;
961		handler = savehandler;
962		funcnest--;
963		popredir();
964		INTON;
965		if (evalskip == SKIPFUNC) {
966			evalskip = 0;
967			skipcount = 0;
968		}
969		if (jp)
970			exitshell(exitstatus);
971	} else if (cmdentry.cmdtype == CMDBUILTIN) {
972#ifdef DEBUG
973		trputs("builtin command:  ");  trargs(argv);
974#endif
975		mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
976		if (flags == EV_BACKCMD) {
977			memout.nleft = 0;
978			memout.nextc = memout.buf;
979			memout.bufsize = 64;
980			mode |= REDIR_BACKQ;
981			cmdentry.special = 0;
982		}
983		savecmdname = commandname;
984		savetopfile = getcurrentfile();
985		cmdenviron = varlist.list;
986		e = -1;
987		savehandler = handler;
988		if (setjmp(jmploc.loc)) {
989			e = exception;
990			if (e == EXINT)
991				exitstatus = SIGINT+128;
992			else if (e != EXEXIT)
993				exitstatus = 2;
994			goto cmddone;
995		}
996		handler = &jmploc;
997		redirect(cmd->ncmd.redirect, mode);
998		/*
999		 * If there is no command word, redirection errors should
1000		 * not be fatal but assignment errors should.
1001		 */
1002		if (argc == 0 && !(flags & EV_BACKCMD))
1003			cmdentry.special = 1;
1004		listsetvar(cmdenviron, cmdentry.special ? 0 : VNOSET);
1005		if (argc > 0)
1006			bltinsetlocale();
1007		commandname = argv[0];
1008		argptr = argv + 1;
1009		nextopt_optptr = NULL;		/* initialize nextopt */
1010		builtin_flags = flags;
1011		exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
1012		flushall();
1013cmddone:
1014		if (argc > 0)
1015			bltinunsetlocale();
1016		cmdenviron = NULL;
1017		out1 = &output;
1018		out2 = &errout;
1019		freestdout();
1020		handler = savehandler;
1021		commandname = savecmdname;
1022		if (jp)
1023			exitshell(exitstatus);
1024		if (flags == EV_BACKCMD) {
1025			backcmd->buf = memout.buf;
1026			backcmd->nleft = memout.nextc - memout.buf;
1027			memout.buf = NULL;
1028		}
1029		if (cmdentry.u.index != EXECCMD)
1030			popredir();
1031		if (e != -1) {
1032			if ((e != EXERROR && e != EXEXEC)
1033			    || cmdentry.special)
1034				exraise(e);
1035			popfilesupto(savetopfile);
1036			if (flags != EV_BACKCMD)
1037				FORCEINTON;
1038		}
1039	} else {
1040#ifdef DEBUG
1041		trputs("normal command:  ");  trargs(argv);
1042#endif
1043		redirect(cmd->ncmd.redirect, 0);
1044		for (sp = varlist.list ; sp ; sp = sp->next)
1045			setvareq(sp->text, VEXPORT|VSTACK);
1046		envp = environment();
1047		shellexec(argv, envp, path, cmdentry.u.index);
1048		/*NOTREACHED*/
1049	}
1050	goto out;
1051
1052parent:	/* parent process gets here (if we forked) */
1053	if (mode == FORK_FG) {	/* argument to fork */
1054		INTOFF;
1055		exitstatus = waitforjob(jp, &realstatus);
1056		INTON;
1057		if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) {
1058			evalskip = SKIPBREAK;
1059			skipcount = loopnest;
1060		}
1061	} else if (mode == FORK_NOJOB) {
1062		backcmd->fd = pip[0];
1063		close(pip[1]);
1064		backcmd->jp = jp;
1065	}
1066
1067out:
1068	if (lastarg)
1069		setvar("_", lastarg, 0);
1070	if (do_clearcmdentry)
1071		clearcmdentry();
1072	popstackmark(&smark);
1073}
1074
1075
1076
1077/*
1078 * Search for a command.  This is called before we fork so that the
1079 * location of the command will be available in the parent as well as
1080 * the child.  The check for "goodname" is an overly conservative
1081 * check that the name will not be subject to expansion.
1082 */
1083
1084static void
1085prehash(union node *n)
1086{
1087	struct cmdentry entry;
1088
1089	if (n && n->type == NCMD && n->ncmd.args)
1090		if (goodname(n->ncmd.args->narg.text))
1091			find_command(n->ncmd.args->narg.text, &entry, 0,
1092				     pathval());
1093}
1094
1095
1096
1097/*
1098 * Builtin commands.  Builtin commands whose functions are closely
1099 * tied to evaluation are implemented here.
1100 */
1101
1102/*
1103 * No command given, a bltin command with no arguments, or a bltin command
1104 * with an invalid name.
1105 */
1106
1107int
1108bltincmd(int argc, char **argv)
1109{
1110	if (argc > 1) {
1111		out2fmt_flush("%s: not found\n", argv[1]);
1112		return 127;
1113	}
1114	/*
1115	 * Preserve exitstatus of a previous possible redirection
1116	 * as POSIX mandates
1117	 */
1118	return exitstatus;
1119}
1120
1121
1122/*
1123 * Handle break and continue commands.  Break, continue, and return are
1124 * all handled by setting the evalskip flag.  The evaluation routines
1125 * above all check this flag, and if it is set they start skipping
1126 * commands rather than executing them.  The variable skipcount is
1127 * the number of loops to break/continue, or the number of function
1128 * levels to return.  (The latter is always 1.)  It should probably
1129 * be an error to break out of more loops than exist, but it isn't
1130 * in the standard shell so we don't make it one here.
1131 */
1132
1133int
1134breakcmd(int argc, char **argv)
1135{
1136	int n = argc > 1 ? number(argv[1]) : 1;
1137
1138	if (n > loopnest)
1139		n = loopnest;
1140	if (n > 0) {
1141		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
1142		skipcount = n;
1143	}
1144	return 0;
1145}
1146
1147/*
1148 * The `command' command.
1149 */
1150int
1151commandcmd(int argc, char **argv)
1152{
1153	const char *path;
1154	int ch;
1155	int cmd = -1;
1156
1157	path = bltinlookup("PATH", 1);
1158
1159	optind = optreset = 1;
1160	opterr = 0;
1161	while ((ch = getopt(argc, argv, "pvV")) != -1) {
1162		switch (ch) {
1163		case 'p':
1164			path = _PATH_STDPATH;
1165			break;
1166		case 'v':
1167			cmd = TYPECMD_SMALLV;
1168			break;
1169		case 'V':
1170			cmd = TYPECMD_BIGV;
1171			break;
1172		case '?':
1173		default:
1174			error("unknown option: -%c", optopt);
1175		}
1176	}
1177	argc -= optind;
1178	argv += optind;
1179
1180	if (cmd != -1) {
1181		if (argc != 1)
1182			error("wrong number of arguments");
1183		return typecmd_impl(2, argv - 1, cmd, path);
1184	}
1185	if (argc != 0)
1186		error("commandcmd bad call");
1187
1188	/*
1189	 * Do nothing successfully if no command was specified;
1190	 * ksh also does this.
1191	 */
1192	return 0;
1193}
1194
1195
1196/*
1197 * The return command.
1198 */
1199
1200int
1201returncmd(int argc, char **argv)
1202{
1203	int ret = argc > 1 ? number(argv[1]) : oexitstatus;
1204
1205	if (funcnest) {
1206		evalskip = SKIPFUNC;
1207		skipcount = 1;
1208	} else {
1209		/* skip the rest of the file */
1210		evalskip = SKIPFILE;
1211		skipcount = 1;
1212	}
1213	return ret;
1214}
1215
1216
1217int
1218falsecmd(int argc __unused, char **argv __unused)
1219{
1220	return 1;
1221}
1222
1223
1224int
1225truecmd(int argc __unused, char **argv __unused)
1226{
1227	return 0;
1228}
1229
1230
1231int
1232execcmd(int argc, char **argv)
1233{
1234	/*
1235	 * Because we have historically not supported any options,
1236	 * only treat "--" specially.
1237	 */
1238	if (argc > 1 && strcmp(argv[1], "--") == 0)
1239		argc--, argv++;
1240	if (argc > 1) {
1241		struct strlist *sp;
1242
1243		iflag = 0;		/* exit on error */
1244		mflag = 0;
1245		optschanged();
1246		for (sp = cmdenviron; sp ; sp = sp->next)
1247			setvareq(sp->text, VEXPORT|VSTACK);
1248		shellexec(argv + 1, environment(), pathval(), 0);
1249
1250	}
1251	return 0;
1252}
1253
1254
1255int
1256timescmd(int argc __unused, char **argv __unused)
1257{
1258	struct rusage ru;
1259	long shumins, shsmins, chumins, chsmins;
1260	double shusecs, shssecs, chusecs, chssecs;
1261
1262	if (getrusage(RUSAGE_SELF, &ru) < 0)
1263		return 1;
1264	shumins = ru.ru_utime.tv_sec / 60;
1265	shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
1266	shsmins = ru.ru_stime.tv_sec / 60;
1267	shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
1268	if (getrusage(RUSAGE_CHILDREN, &ru) < 0)
1269		return 1;
1270	chumins = ru.ru_utime.tv_sec / 60;
1271	chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
1272	chsmins = ru.ru_stime.tv_sec / 60;
1273	chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
1274	out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins,
1275	    shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs);
1276	return 0;
1277}
1278