xref: /netbsd-src/bin/sh/eval.c (revision b757af438b42b93f8c6571f026d8b8ef3eaf5fc9)
1 /*	$NetBSD: eval.c,v 1.103 2011/11/14 18:24:45 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Kenneth Almquist.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)eval.c	8.9 (Berkeley) 6/8/95";
39 #else
40 __RCSID("$NetBSD: eval.c,v 1.103 2011/11/14 18:24:45 christos Exp $");
41 #endif
42 #endif /* not lint */
43 
44 #include <stdbool.h>
45 #include <stdlib.h>
46 #include <signal.h>
47 #include <stdio.h>
48 #include <errno.h>
49 #include <unistd.h>
50 #include <sys/fcntl.h>
51 #include <sys/times.h>
52 #include <sys/param.h>
53 #include <sys/types.h>
54 #include <sys/wait.h>
55 #include <sys/sysctl.h>
56 
57 /*
58  * Evaluate a command.
59  */
60 
61 #include "shell.h"
62 #include "nodes.h"
63 #include "syntax.h"
64 #include "expand.h"
65 #include "parser.h"
66 #include "jobs.h"
67 #include "eval.h"
68 #include "builtins.h"
69 #include "options.h"
70 #include "exec.h"
71 #include "redir.h"
72 #include "input.h"
73 #include "output.h"
74 #include "trap.h"
75 #include "var.h"
76 #include "memalloc.h"
77 #include "error.h"
78 #include "show.h"
79 #include "mystring.h"
80 #include "main.h"
81 #ifndef SMALL
82 #include "myhistedit.h"
83 #endif
84 
85 
86 /* flags in argument to evaltree */
87 #define EV_EXIT 01		/* exit after evaluating tree */
88 #define EV_TESTED 02		/* exit status is checked; ignore -e flag */
89 #define EV_BACKCMD 04		/* command executing within back quotes */
90 
91 int evalskip;			/* set if we are skipping commands */
92 STATIC int skipcount;		/* number of levels to skip */
93 MKINIT int loopnest;		/* current loop nesting level */
94 int funcnest;			/* depth of function calls */
95 STATIC int builtin_flags;	/* evalcommand flags for builtins */
96 
97 
98 const char *commandname;
99 struct strlist *cmdenviron;
100 int exitstatus;			/* exit status of last command */
101 int back_exitstatus;		/* exit status of backquoted command */
102 
103 
104 STATIC void evalloop(union node *, int);
105 STATIC void evalfor(union node *, int);
106 STATIC void evalcase(union node *, int);
107 STATIC void evalsubshell(union node *, int);
108 STATIC void expredir(union node *);
109 STATIC void evalpipe(union node *);
110 STATIC void evalcommand(union node *, int, struct backcmd *);
111 STATIC void prehash(union node *);
112 
113 
114 /*
115  * Called to reset things after an exception.
116  */
117 
118 #ifdef mkinit
119 INCLUDE "eval.h"
120 
121 RESET {
122 	evalskip = 0;
123 	loopnest = 0;
124 	funcnest = 0;
125 }
126 
127 SHELLPROC {
128 	exitstatus = 0;
129 }
130 #endif
131 
132 static int
133 sh_pipe(int fds[2])
134 {
135 	int nfd;
136 
137 	if (pipe(fds))
138 		return -1;
139 
140 	if (fds[0] < 3) {
141 		nfd = fcntl(fds[0], F_DUPFD, 3);
142 		if (nfd != -1) {
143 			close(fds[0]);
144 			fds[0] = nfd;
145 		}
146 	}
147 
148 	if (fds[1] < 3) {
149 		nfd = fcntl(fds[1], F_DUPFD, 3);
150 		if (nfd != -1) {
151 			close(fds[1]);
152 			fds[1] = nfd;
153 		}
154 	}
155 	return 0;
156 }
157 
158 
159 /*
160  * The eval commmand.
161  */
162 
163 int
164 evalcmd(int argc, char **argv)
165 {
166         char *p;
167         char *concat;
168         char **ap;
169 
170         if (argc > 1) {
171                 p = argv[1];
172                 if (argc > 2) {
173                         STARTSTACKSTR(concat);
174                         ap = argv + 2;
175                         for (;;) {
176                                 while (*p)
177                                         STPUTC(*p++, concat);
178                                 if ((p = *ap++) == NULL)
179                                         break;
180                                 STPUTC(' ', concat);
181                         }
182                         STPUTC('\0', concat);
183                         p = grabstackstr(concat);
184                 }
185                 evalstring(p, builtin_flags & EV_TESTED);
186         }
187         return exitstatus;
188 }
189 
190 
191 /*
192  * Execute a command or commands contained in a string.
193  */
194 
195 void
196 evalstring(char *s, int flag)
197 {
198 	union node *n;
199 	struct stackmark smark;
200 
201 	setstackmark(&smark);
202 	setinputstring(s, 1);
203 
204 	while ((n = parsecmd(0)) != NEOF) {
205 		evaltree(n, flag);
206 		popstackmark(&smark);
207 	}
208 	popfile();
209 	popstackmark(&smark);
210 }
211 
212 
213 
214 /*
215  * Evaluate a parse tree.  The value is left in the global variable
216  * exitstatus.
217  */
218 
219 void
220 evaltree(union node *n, int flags)
221 {
222 	bool do_etest;
223 
224 	do_etest = false;
225 	if (n == NULL) {
226 		TRACE(("evaltree(NULL) called\n"));
227 		exitstatus = 0;
228 		goto out;
229 	}
230 #ifndef SMALL
231 	displayhist = 1;	/* show history substitutions done with fc */
232 #endif
233 	TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
234 	    getpid(), n, n->type, flags));
235 	switch (n->type) {
236 	case NSEMI:
237 		evaltree(n->nbinary.ch1, flags & EV_TESTED);
238 		if (evalskip)
239 			goto out;
240 		evaltree(n->nbinary.ch2, flags);
241 		break;
242 	case NAND:
243 		evaltree(n->nbinary.ch1, EV_TESTED);
244 		if (evalskip || exitstatus != 0)
245 			goto out;
246 		evaltree(n->nbinary.ch2, flags);
247 		break;
248 	case NOR:
249 		evaltree(n->nbinary.ch1, EV_TESTED);
250 		if (evalskip || exitstatus == 0)
251 			goto out;
252 		evaltree(n->nbinary.ch2, flags);
253 		break;
254 	case NREDIR:
255 		expredir(n->nredir.redirect);
256 		redirect(n->nredir.redirect, REDIR_PUSH);
257 		evaltree(n->nredir.n, flags);
258 		popredir();
259 		break;
260 	case NSUBSHELL:
261 		evalsubshell(n, flags);
262 		do_etest = !(flags & EV_TESTED);
263 		break;
264 	case NBACKGND:
265 		evalsubshell(n, flags);
266 		break;
267 	case NIF: {
268 		evaltree(n->nif.test, EV_TESTED);
269 		if (evalskip)
270 			goto out;
271 		if (exitstatus == 0)
272 			evaltree(n->nif.ifpart, flags);
273 		else if (n->nif.elsepart)
274 			evaltree(n->nif.elsepart, flags);
275 		else
276 			exitstatus = 0;
277 		break;
278 	}
279 	case NWHILE:
280 	case NUNTIL:
281 		evalloop(n, flags);
282 		break;
283 	case NFOR:
284 		evalfor(n, flags);
285 		break;
286 	case NCASE:
287 		evalcase(n, flags);
288 		break;
289 	case NDEFUN:
290 		defun(n->narg.text, n->narg.next);
291 		exitstatus = 0;
292 		break;
293 	case NNOT:
294 		evaltree(n->nnot.com, EV_TESTED);
295 		exitstatus = !exitstatus;
296 		break;
297 	case NPIPE:
298 		evalpipe(n);
299 		do_etest = !(flags & EV_TESTED);
300 		break;
301 	case NCMD:
302 		evalcommand(n, flags, NULL);
303 		do_etest = !(flags & EV_TESTED);
304 		break;
305 	default:
306 		out1fmt("Node type = %d\n", n->type);
307 		flushout(&output);
308 		break;
309 	}
310 out:
311 	if (pendingsigs)
312 		dotrap();
313 	if ((flags & EV_EXIT) != 0 || (eflag && exitstatus != 0 && do_etest))
314 		exitshell(exitstatus);
315 }
316 
317 
318 STATIC void
319 evalloop(union node *n, int flags)
320 {
321 	int status;
322 
323 	loopnest++;
324 	status = 0;
325 	for (;;) {
326 		evaltree(n->nbinary.ch1, EV_TESTED);
327 		if (evalskip) {
328 skipping:	  if (evalskip == SKIPCONT && --skipcount <= 0) {
329 				evalskip = 0;
330 				continue;
331 			}
332 			if (evalskip == SKIPBREAK && --skipcount <= 0)
333 				evalskip = 0;
334 			break;
335 		}
336 		if (n->type == NWHILE) {
337 			if (exitstatus != 0)
338 				break;
339 		} else {
340 			if (exitstatus == 0)
341 				break;
342 		}
343 		evaltree(n->nbinary.ch2, flags & EV_TESTED);
344 		status = exitstatus;
345 		if (evalskip)
346 			goto skipping;
347 	}
348 	loopnest--;
349 	exitstatus = status;
350 }
351 
352 
353 
354 STATIC void
355 evalfor(union node *n, int flags)
356 {
357 	struct arglist arglist;
358 	union node *argp;
359 	struct strlist *sp;
360 	struct stackmark smark;
361 	int status = 0;
362 
363 	setstackmark(&smark);
364 	arglist.lastp = &arglist.list;
365 	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
366 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
367 		if (evalskip)
368 			goto out;
369 	}
370 	*arglist.lastp = NULL;
371 
372 	loopnest++;
373 	for (sp = arglist.list ; sp ; sp = sp->next) {
374 		setvar(n->nfor.var, sp->text, 0);
375 		evaltree(n->nfor.body, flags & EV_TESTED);
376 		status = exitstatus;
377 		if (evalskip) {
378 			if (evalskip == SKIPCONT && --skipcount <= 0) {
379 				evalskip = 0;
380 				continue;
381 			}
382 			if (evalskip == SKIPBREAK && --skipcount <= 0)
383 				evalskip = 0;
384 			break;
385 		}
386 	}
387 	loopnest--;
388 	exitstatus = status;
389 out:
390 	popstackmark(&smark);
391 }
392 
393 
394 
395 STATIC void
396 evalcase(union node *n, int flags)
397 {
398 	union node *cp;
399 	union node *patp;
400 	struct arglist arglist;
401 	struct stackmark smark;
402 	int status = 0;
403 
404 	setstackmark(&smark);
405 	arglist.lastp = &arglist.list;
406 	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
407 	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
408 		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
409 			if (casematch(patp, arglist.list->text)) {
410 				if (evalskip == 0) {
411 					evaltree(cp->nclist.body, flags);
412 					status = exitstatus;
413 				}
414 				goto out;
415 			}
416 		}
417 	}
418 out:
419 	exitstatus = status;
420 	popstackmark(&smark);
421 }
422 
423 
424 
425 /*
426  * Kick off a subshell to evaluate a tree.
427  */
428 
429 STATIC void
430 evalsubshell(union node *n, int flags)
431 {
432 	struct job *jp;
433 	int backgnd = (n->type == NBACKGND);
434 
435 	expredir(n->nredir.redirect);
436 	INTOFF;
437 	jp = makejob(n, 1);
438 	if (forkshell(jp, n, backgnd ? FORK_BG : FORK_FG) == 0) {
439 		INTON;
440 		if (backgnd)
441 			flags &=~ EV_TESTED;
442 		redirect(n->nredir.redirect, 0);
443 		/* never returns */
444 		evaltree(n->nredir.n, flags | EV_EXIT);
445 	}
446 	if (! backgnd)
447 		exitstatus = waitforjob(jp);
448 	INTON;
449 }
450 
451 
452 
453 /*
454  * Compute the names of the files in a redirection list.
455  */
456 
457 STATIC void
458 expredir(union node *n)
459 {
460 	union node *redir;
461 
462 	for (redir = n ; redir ; redir = redir->nfile.next) {
463 		struct arglist fn;
464 		fn.lastp = &fn.list;
465 		switch (redir->type) {
466 		case NFROMTO:
467 		case NFROM:
468 		case NTO:
469 		case NCLOBBER:
470 		case NAPPEND:
471 			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
472 			redir->nfile.expfname = fn.list->text;
473 			break;
474 		case NFROMFD:
475 		case NTOFD:
476 			if (redir->ndup.vname) {
477 				expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
478 				fixredir(redir, fn.list->text, 1);
479 			}
480 			break;
481 		}
482 	}
483 }
484 
485 
486 
487 /*
488  * Evaluate a pipeline.  All the processes in the pipeline are children
489  * of the process creating the pipeline.  (This differs from some versions
490  * of the shell, which make the last process in a pipeline the parent
491  * of all the rest.)
492  */
493 
494 STATIC void
495 evalpipe(union node *n)
496 {
497 	struct job *jp;
498 	struct nodelist *lp;
499 	int pipelen;
500 	int prevfd;
501 	int pip[2];
502 
503 	TRACE(("evalpipe(0x%lx) called\n", (long)n));
504 	pipelen = 0;
505 	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
506 		pipelen++;
507 	INTOFF;
508 	jp = makejob(n, pipelen);
509 	prevfd = -1;
510 	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
511 		prehash(lp->n);
512 		pip[1] = -1;
513 		if (lp->next) {
514 			if (sh_pipe(pip) < 0) {
515 				if (prevfd >= 0)
516 					close(prevfd);
517 				error("Pipe call failed");
518 			}
519 		}
520 		if (forkshell(jp, lp->n, n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) {
521 			INTON;
522 			if (prevfd > 0) {
523 				close(0);
524 				copyfd(prevfd, 0, 1);
525 				close(prevfd);
526 			}
527 			if (pip[1] >= 0) {
528 				close(pip[0]);
529 				if (pip[1] != 1) {
530 					close(1);
531 					copyfd(pip[1], 1, 1);
532 					close(pip[1]);
533 				}
534 			}
535 			evaltree(lp->n, EV_EXIT);
536 		}
537 		if (prevfd >= 0)
538 			close(prevfd);
539 		prevfd = pip[0];
540 		close(pip[1]);
541 	}
542 	if (n->npipe.backgnd == 0) {
543 		exitstatus = waitforjob(jp);
544 		TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
545 	}
546 	INTON;
547 }
548 
549 
550 
551 /*
552  * Execute a command inside back quotes.  If it's a builtin command, we
553  * want to save its output in a block obtained from malloc.  Otherwise
554  * we fork off a subprocess and get the output of the command via a pipe.
555  * Should be called with interrupts off.
556  */
557 
558 void
559 evalbackcmd(union node *n, struct backcmd *result)
560 {
561 	int pip[2];
562 	struct job *jp;
563 	struct stackmark smark;		/* unnecessary */
564 
565 	setstackmark(&smark);
566 	result->fd = -1;
567 	result->buf = NULL;
568 	result->nleft = 0;
569 	result->jp = NULL;
570 	if (n == NULL) {
571 		goto out;
572 	}
573 #ifdef notyet
574 	/*
575 	 * For now we disable executing builtins in the same
576 	 * context as the shell, because we are not keeping
577 	 * enough state to recover from changes that are
578 	 * supposed only to affect subshells. eg. echo "`cd /`"
579 	 */
580 	if (n->type == NCMD) {
581 		exitstatus = oexitstatus;
582 		evalcommand(n, EV_BACKCMD, result);
583 	} else
584 #endif
585 	{
586 		INTOFF;
587 		if (sh_pipe(pip) < 0)
588 			error("Pipe call failed");
589 		jp = makejob(n, 1);
590 		if (forkshell(jp, n, FORK_NOJOB) == 0) {
591 			FORCEINTON;
592 			close(pip[0]);
593 			if (pip[1] != 1) {
594 				close(1);
595 				copyfd(pip[1], 1, 1);
596 				close(pip[1]);
597 			}
598 			eflag = 0;
599 			evaltree(n, EV_EXIT);
600 			/* NOTREACHED */
601 		}
602 		close(pip[1]);
603 		result->fd = pip[0];
604 		result->jp = jp;
605 		INTON;
606 	}
607 out:
608 	popstackmark(&smark);
609 	TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
610 		result->fd, result->buf, result->nleft, result->jp));
611 }
612 
613 static const char *
614 syspath(void)
615 {
616 	static char *sys_path = NULL;
617 	static int mib[] = {CTL_USER, USER_CS_PATH};
618 	static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin";
619 	size_t len;
620 
621 	if (sys_path == NULL) {
622 		if (sysctl(mib, 2, 0, &len, 0, 0) != -1 &&
623 		    (sys_path = ckmalloc(len + 5)) != NULL &&
624 		    sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) {
625 			memcpy(sys_path, "PATH=", 5);
626 		} else {
627 			ckfree(sys_path);
628 			/* something to keep things happy */
629 			sys_path = def_path;
630 		}
631 	}
632 	return sys_path;
633 }
634 
635 static int
636 parse_command_args(int argc, char **argv, int *use_syspath)
637 {
638 	int sv_argc = argc;
639 	char *cp, c;
640 
641 	*use_syspath = 0;
642 
643 	for (;;) {
644 		argv++;
645 		if (--argc == 0)
646 			break;
647 		cp = *argv;
648 		if (*cp++ != '-')
649 			break;
650 		if (*cp == '-' && cp[1] == 0) {
651 			argv++;
652 			argc--;
653 			break;
654 		}
655 		while ((c = *cp++)) {
656 			switch (c) {
657 			case 'p':
658 				*use_syspath = 1;
659 				break;
660 			default:
661 				/* run 'typecmd' for other options */
662 				return 0;
663 			}
664 		}
665 	}
666 	return sv_argc - argc;
667 }
668 
669 int vforked = 0;
670 extern char *trap[];
671 
672 /*
673  * Execute a simple command.
674  */
675 
676 STATIC void
677 evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
678 {
679 	struct stackmark smark;
680 	union node *argp;
681 	struct arglist arglist;
682 	struct arglist varlist;
683 	volatile int flags = flgs;
684 	char ** volatile argv;
685 	volatile int argc;
686 	char **envp;
687 	int varflag;
688 	struct strlist *sp;
689 	volatile int mode;
690 	int pip[2];
691 	struct cmdentry cmdentry;
692 	struct job * volatile jp;
693 	struct jmploc jmploc;
694 	struct jmploc *volatile savehandler = NULL;
695 	const char *volatile savecmdname;
696 	volatile struct shparam saveparam;
697 	struct localvar *volatile savelocalvars;
698 	volatile int e;
699 	char * volatile lastarg;
700 	const char * volatile path = pathval();
701 	volatile int temp_path;
702 
703 	vforked = 0;
704 	/* First expand the arguments. */
705 	TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
706 	setstackmark(&smark);
707 	back_exitstatus = 0;
708 
709 	arglist.lastp = &arglist.list;
710 	varflag = 1;
711 	/* Expand arguments, ignoring the initial 'name=value' ones */
712 	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
713 		char *p = argp->narg.text;
714 		if (varflag && is_name(*p)) {
715 			do {
716 				p++;
717 			} while (is_in_name(*p));
718 			if (*p == '=')
719 				continue;
720 		}
721 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
722 		varflag = 0;
723 	}
724 	*arglist.lastp = NULL;
725 
726 	expredir(cmd->ncmd.redirect);
727 
728 	/* Now do the initial 'name=value' ones we skipped above */
729 	varlist.lastp = &varlist.list;
730 	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
731 		char *p = argp->narg.text;
732 		if (!is_name(*p))
733 			break;
734 		do
735 			p++;
736 		while (is_in_name(*p));
737 		if (*p != '=')
738 			break;
739 		expandarg(argp, &varlist, EXP_VARTILDE);
740 	}
741 	*varlist.lastp = NULL;
742 
743 	argc = 0;
744 	for (sp = arglist.list ; sp ; sp = sp->next)
745 		argc++;
746 	argv = stalloc(sizeof (char *) * (argc + 1));
747 
748 	for (sp = arglist.list ; sp ; sp = sp->next) {
749 		TRACE(("evalcommand arg: %s\n", sp->text));
750 		*argv++ = sp->text;
751 	}
752 	*argv = NULL;
753 	lastarg = NULL;
754 	if (iflag && funcnest == 0 && argc > 0)
755 		lastarg = argv[-1];
756 	argv -= argc;
757 
758 	/* Print the command if xflag is set. */
759 	if (xflag) {
760 		char sep = 0;
761 		out2str(ps4val());
762 		for (sp = varlist.list ; sp ; sp = sp->next) {
763 			if (sep != 0)
764 				outc(sep, &errout);
765 			out2shstr(sp->text);
766 			sep = ' ';
767 		}
768 		for (sp = arglist.list ; sp ; sp = sp->next) {
769 			if (sep != 0)
770 				outc(sep, &errout);
771 			out2shstr(sp->text);
772 			sep = ' ';
773 		}
774 		outc('\n', &errout);
775 		flushout(&errout);
776 	}
777 
778 	/* Now locate the command. */
779 	if (argc == 0) {
780 		cmdentry.cmdtype = CMDSPLBLTIN;
781 		cmdentry.u.bltin = bltincmd;
782 	} else {
783 		static const char PATH[] = "PATH=";
784 		int cmd_flags = DO_ERR;
785 
786 		/*
787 		 * Modify the command lookup path, if a PATH= assignment
788 		 * is present
789 		 */
790 		for (sp = varlist.list; sp; sp = sp->next)
791 			if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
792 				path = sp->text + sizeof(PATH) - 1;
793 
794 		do {
795 			int argsused, use_syspath;
796 			find_command(argv[0], &cmdentry, cmd_flags, path);
797 			if (cmdentry.cmdtype == CMDUNKNOWN) {
798 				exitstatus = 127;
799 				flushout(&errout);
800 				goto out;
801 			}
802 
803 			/* implement the 'command' builtin here */
804 			if (cmdentry.cmdtype != CMDBUILTIN ||
805 			    cmdentry.u.bltin != bltincmd)
806 				break;
807 			cmd_flags |= DO_NOFUNC;
808 			argsused = parse_command_args(argc, argv, &use_syspath);
809 			if (argsused == 0) {
810 				/* use 'type' builting to display info */
811 				cmdentry.u.bltin = typecmd;
812 				break;
813 			}
814 			argc -= argsused;
815 			argv += argsused;
816 			if (use_syspath)
817 				path = syspath() + 5;
818 		} while (argc != 0);
819 		if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC)
820 			/* posix mandates that 'command <splbltin>' act as if
821 			   <splbltin> was a normal builtin */
822 			cmdentry.cmdtype = CMDBUILTIN;
823 	}
824 
825 	/* Fork off a child process if necessary. */
826 	if (cmd->ncmd.backgnd || (trap[0] && (flags & EV_EXIT) != 0)
827 	 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
828 	 || ((flags & EV_BACKCMD) != 0
829 	    && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN)
830 		 || cmdentry.u.bltin == dotcmd
831 		 || cmdentry.u.bltin == evalcmd))) {
832 		INTOFF;
833 		jp = makejob(cmd, 1);
834 		mode = cmd->ncmd.backgnd;
835 		if (flags & EV_BACKCMD) {
836 			mode = FORK_NOJOB;
837 			if (sh_pipe(pip) < 0)
838 				error("Pipe call failed");
839 		}
840 #ifdef DO_SHAREDVFORK
841 		/* It is essential that if DO_SHAREDVFORK is defined that the
842 		 * child's address space is actually shared with the parent as
843 		 * we rely on this.
844 		 */
845 		if (cmdentry.cmdtype == CMDNORMAL) {
846 			pid_t	pid;
847 
848 			savelocalvars = localvars;
849 			localvars = NULL;
850 			vforked = 1;
851 			switch (pid = vfork()) {
852 			case -1:
853 				TRACE(("Vfork failed, errno=%d\n", errno));
854 				INTON;
855 				error("Cannot vfork");
856 				break;
857 			case 0:
858 				/* Make sure that exceptions only unwind to
859 				 * after the vfork(2)
860 				 */
861 				if (setjmp(jmploc.loc)) {
862 					if (exception == EXSHELLPROC) {
863 						/* We can't progress with the vfork,
864 						 * so, set vforked = 2 so the parent
865 						 * knows, and _exit();
866 						 */
867 						vforked = 2;
868 						_exit(0);
869 					} else {
870 						_exit(exerrno);
871 					}
872 				}
873 				savehandler = handler;
874 				handler = &jmploc;
875 				listmklocal(varlist.list, VEXPORT | VNOFUNC);
876 				forkchild(jp, cmd, mode, vforked);
877 				break;
878 			default:
879 				handler = savehandler;	/* restore from vfork(2) */
880 				poplocalvars();
881 				localvars = savelocalvars;
882 				if (vforked == 2) {
883 					vforked = 0;
884 
885 					(void)waitpid(pid, NULL, 0);
886 					/* We need to progress in a normal fork fashion */
887 					goto normal_fork;
888 				}
889 				vforked = 0;
890 				forkparent(jp, cmd, mode, pid);
891 				goto parent;
892 			}
893 		} else {
894 normal_fork:
895 #endif
896 			if (forkshell(jp, cmd, mode) != 0)
897 				goto parent;	/* at end of routine */
898 			FORCEINTON;
899 #ifdef DO_SHAREDVFORK
900 		}
901 #endif
902 		if (flags & EV_BACKCMD) {
903 			if (!vforked) {
904 				FORCEINTON;
905 			}
906 			close(pip[0]);
907 			if (pip[1] != 1) {
908 				close(1);
909 				copyfd(pip[1], 1, 1);
910 				close(pip[1]);
911 			}
912 		}
913 		flags |= EV_EXIT;
914 	}
915 
916 	/* This is the child process if a fork occurred. */
917 	/* Execute the command. */
918 	switch (cmdentry.cmdtype) {
919 	case CMDFUNCTION:
920 #ifdef DEBUG
921 		trputs("Shell function:  ");  trargs(argv);
922 #endif
923 		redirect(cmd->ncmd.redirect, REDIR_PUSH);
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 		INTON;
934 		if (setjmp(jmploc.loc)) {
935 			if (exception == EXSHELLPROC) {
936 				freeparam((volatile struct shparam *)
937 				    &saveparam);
938 			} else {
939 				freeparam(&shellparam);
940 				shellparam = saveparam;
941 			}
942 			poplocalvars();
943 			localvars = savelocalvars;
944 			handler = savehandler;
945 			longjmp(handler->loc, 1);
946 		}
947 		savehandler = handler;
948 		handler = &jmploc;
949 		listmklocal(varlist.list, 0);
950 		/* stop shell blowing its stack */
951 		if (++funcnest > 1000)
952 			error("too many nested function calls");
953 		evaltree(cmdentry.u.func, flags & EV_TESTED);
954 		funcnest--;
955 		INTOFF;
956 		poplocalvars();
957 		localvars = savelocalvars;
958 		freeparam(&shellparam);
959 		shellparam = saveparam;
960 		handler = savehandler;
961 		popredir();
962 		INTON;
963 		if (evalskip == SKIPFUNC) {
964 			evalskip = 0;
965 			skipcount = 0;
966 		}
967 		if (flags & EV_EXIT)
968 			exitshell(exitstatus);
969 		break;
970 
971 	case CMDBUILTIN:
972 	case CMDSPLBLTIN:
973 #ifdef DEBUG
974 		trputs("builtin command:  ");  trargs(argv);
975 #endif
976 		mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH;
977 		if (flags == EV_BACKCMD) {
978 			memout.nleft = 0;
979 			memout.nextc = memout.buf;
980 			memout.bufsize = 64;
981 			mode |= REDIR_BACKQ;
982 		}
983 		e = -1;
984 		savehandler = handler;
985 		savecmdname = commandname;
986 		handler = &jmploc;
987 		if (!setjmp(jmploc.loc)) {
988 			/* We need to ensure the command hash table isn't
989 			 * corruped by temporary PATH assignments.
990 			 * However we must ensure the 'local' command works!
991 			 */
992 			if (path != pathval() && (cmdentry.u.bltin == hashcmd ||
993 			    cmdentry.u.bltin == typecmd)) {
994 				savelocalvars = localvars;
995 				localvars = 0;
996 				mklocal(path - 5 /* PATH= */, 0);
997 				temp_path = 1;
998 			} else
999 				temp_path = 0;
1000 			redirect(cmd->ncmd.redirect, mode);
1001 
1002 			/* exec is a special builtin, but needs this list... */
1003 			cmdenviron = varlist.list;
1004 			/* we must check 'readonly' flag for all builtins */
1005 			listsetvar(varlist.list,
1006 				cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET);
1007 			commandname = argv[0];
1008 			/* initialize nextopt */
1009 			argptr = argv + 1;
1010 			optptr = NULL;
1011 			/* and getopt */
1012 			optreset = 1;
1013 			optind = 1;
1014 			builtin_flags = flags;
1015 			exitstatus = cmdentry.u.bltin(argc, argv);
1016 		} else {
1017 			e = exception;
1018 			exitstatus = e == EXINT ? SIGINT + 128 :
1019 					e == EXEXEC ? exerrno : 2;
1020 		}
1021 		handler = savehandler;
1022 		flushall();
1023 		out1 = &output;
1024 		out2 = &errout;
1025 		freestdout();
1026 		if (temp_path) {
1027 			poplocalvars();
1028 			localvars = savelocalvars;
1029 		}
1030 		cmdenviron = NULL;
1031 		if (e != EXSHELLPROC) {
1032 			commandname = savecmdname;
1033 			if (flags & EV_EXIT)
1034 				exitshell(exitstatus);
1035 		}
1036 		if (e != -1) {
1037 			if ((e != EXERROR && e != EXEXEC)
1038 			    || cmdentry.cmdtype == CMDSPLBLTIN)
1039 				exraise(e);
1040 			FORCEINTON;
1041 		}
1042 		if (cmdentry.u.bltin != execcmd)
1043 			popredir();
1044 		if (flags == EV_BACKCMD) {
1045 			backcmd->buf = memout.buf;
1046 			backcmd->nleft = memout.nextc - memout.buf;
1047 			memout.buf = NULL;
1048 		}
1049 		break;
1050 
1051 	default:
1052 #ifdef DEBUG
1053 		trputs("normal command:  ");  trargs(argv);
1054 #endif
1055 		clearredir(vforked);
1056 		redirect(cmd->ncmd.redirect, vforked ? REDIR_VFORK : 0);
1057 		if (!vforked)
1058 			for (sp = varlist.list ; sp ; sp = sp->next)
1059 				setvareq(sp->text, VEXPORT|VSTACK);
1060 		envp = environment();
1061 		shellexec(argv, envp, path, cmdentry.u.index, vforked);
1062 		break;
1063 	}
1064 	goto out;
1065 
1066 parent:	/* parent process gets here (if we forked) */
1067 	if (mode == FORK_FG) {	/* argument to fork */
1068 		exitstatus = waitforjob(jp);
1069 	} else if (mode == FORK_NOJOB) {
1070 		backcmd->fd = pip[0];
1071 		close(pip[1]);
1072 		backcmd->jp = jp;
1073 	}
1074 	FORCEINTON;
1075 
1076 out:
1077 	if (lastarg)
1078 		/* dsl: I think this is intended to be used to support
1079 		 * '_' in 'vi' command mode during line editing...
1080 		 * However I implemented that within libedit itself.
1081 		 */
1082 		setvar("_", lastarg, 0);
1083 	popstackmark(&smark);
1084 }
1085 
1086 
1087 /*
1088  * Search for a command.  This is called before we fork so that the
1089  * location of the command will be available in the parent as well as
1090  * the child.  The check for "goodname" is an overly conservative
1091  * check that the name will not be subject to expansion.
1092  */
1093 
1094 STATIC void
1095 prehash(union node *n)
1096 {
1097 	struct cmdentry entry;
1098 
1099 	if (n && n->type == NCMD && n->ncmd.args)
1100 		if (goodname(n->ncmd.args->narg.text))
1101 			find_command(n->ncmd.args->narg.text, &entry, 0,
1102 				     pathval());
1103 }
1104 
1105 
1106 
1107 /*
1108  * Builtin commands.  Builtin commands whose functions are closely
1109  * tied to evaluation are implemented here.
1110  */
1111 
1112 /*
1113  * No command given.
1114  */
1115 
1116 int
1117 bltincmd(int argc, char **argv)
1118 {
1119 	/*
1120 	 * Preserve exitstatus of a previous possible redirection
1121 	 * as POSIX mandates
1122 	 */
1123 	return back_exitstatus;
1124 }
1125 
1126 
1127 /*
1128  * Handle break and continue commands.  Break, continue, and return are
1129  * all handled by setting the evalskip flag.  The evaluation routines
1130  * above all check this flag, and if it is set they start skipping
1131  * commands rather than executing them.  The variable skipcount is
1132  * the number of loops to break/continue, or the number of function
1133  * levels to return.  (The latter is always 1.)  It should probably
1134  * be an error to break out of more loops than exist, but it isn't
1135  * in the standard shell so we don't make it one here.
1136  */
1137 
1138 int
1139 breakcmd(int argc, char **argv)
1140 {
1141 	int n = argc > 1 ? number(argv[1]) : 1;
1142 
1143 	if (n > loopnest)
1144 		n = loopnest;
1145 	if (n > 0) {
1146 		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
1147 		skipcount = n;
1148 	}
1149 	return 0;
1150 }
1151 
1152 
1153 /*
1154  * The return command.
1155  */
1156 
1157 int
1158 returncmd(int argc, char **argv)
1159 {
1160 	int ret = argc > 1 ? number(argv[1]) : exitstatus;
1161 
1162 	if (funcnest) {
1163 		evalskip = SKIPFUNC;
1164 		skipcount = 1;
1165 		return ret;
1166 	}
1167 	else {
1168 		/* Do what ksh does; skip the rest of the file */
1169 		evalskip = SKIPFILE;
1170 		skipcount = 1;
1171 		return ret;
1172 	}
1173 }
1174 
1175 
1176 int
1177 falsecmd(int argc, char **argv)
1178 {
1179 	return 1;
1180 }
1181 
1182 
1183 int
1184 truecmd(int argc, char **argv)
1185 {
1186 	return 0;
1187 }
1188 
1189 
1190 int
1191 execcmd(int argc, char **argv)
1192 {
1193 	if (argc > 1) {
1194 		struct strlist *sp;
1195 
1196 		iflag = 0;		/* exit on error */
1197 		mflag = 0;
1198 		optschanged();
1199 		for (sp = cmdenviron; sp; sp = sp->next)
1200 			setvareq(sp->text, VEXPORT|VSTACK);
1201 		shellexec(argv + 1, environment(), pathval(), 0, 0);
1202 	}
1203 	return 0;
1204 }
1205 
1206 static int
1207 conv_time(clock_t ticks, char *seconds, size_t l)
1208 {
1209 	static clock_t tpm = 0;
1210 	clock_t mins;
1211 	int i;
1212 
1213 	if (!tpm)
1214 		tpm = sysconf(_SC_CLK_TCK) * 60;
1215 
1216 	mins = ticks / tpm;
1217 	snprintf(seconds, l, "%.4f", (ticks - mins * tpm) * 60.0 / tpm );
1218 
1219 	if (seconds[0] == '6' && seconds[1] == '0') {
1220 		/* 59.99995 got rounded up... */
1221 		mins++;
1222 		strlcpy(seconds, "0.0", l);
1223 		return mins;
1224 	}
1225 
1226 	/* suppress trailing zeros */
1227 	i = strlen(seconds) - 1;
1228 	for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--)
1229 		seconds[i] = 0;
1230 	return mins;
1231 }
1232 
1233 int
1234 timescmd(int argc, char **argv)
1235 {
1236 	struct tms tms;
1237 	int u, s, cu, cs;
1238 	char us[8], ss[8], cus[8], css[8];
1239 
1240 	nextopt("");
1241 
1242 	times(&tms);
1243 
1244 	u = conv_time(tms.tms_utime, us, sizeof(us));
1245 	s = conv_time(tms.tms_stime, ss, sizeof(ss));
1246 	cu = conv_time(tms.tms_cutime, cus, sizeof(cus));
1247 	cs = conv_time(tms.tms_cstime, css, sizeof(css));
1248 
1249 	outfmt(out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n",
1250 		u, us, s, ss, cu, cus, cs, css);
1251 
1252 	return 0;
1253 }
1254