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