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