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
38static 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
91int evalskip;			/* set if we are skipping commands */
92STATIC int skipcount;		/* number of levels to skip */
93MKINIT int loopnest;		/* current loop nesting level */
94int funcnest;			/* depth of function calls */
95STATIC int builtin_flags;	/* evalcommand flags for builtins */
96
97
98const char *commandname;
99struct strlist *cmdenviron;
100int exitstatus;			/* exit status of last command */
101int back_exitstatus;		/* exit status of backquoted command */
102
103
104STATIC void evalloop(union node *, int);
105STATIC void evalfor(union node *, int);
106STATIC void evalcase(union node *, int);
107STATIC void evalsubshell(union node *, int);
108STATIC void expredir(union node *);
109STATIC void evalpipe(union node *);
110STATIC void evalcommand(union node *, int, struct backcmd *);
111STATIC void prehash(union node *);
112
113
114/*
115 * Called to reset things after an exception.
116 */
117
118#ifdef mkinit
119INCLUDE "eval.h"
120
121RESET {
122	evalskip = 0;
123	loopnest = 0;
124	funcnest = 0;
125}
126
127SHELLPROC {
128	exitstatus = 0;
129}
130#endif
131
132static int
133sh_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
163int
164evalcmd(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
195void
196evalstring(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
219void
220evaltree(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	}
310out:
311	if (pendingsigs)
312		dotrap();
313	if ((flags & EV_EXIT) != 0 || (eflag && exitstatus != 0 && do_etest))
314		exitshell(exitstatus);
315}
316
317
318STATIC void
319evalloop(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) {
328skipping:	  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
354STATIC void
355evalfor(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;
389out:
390	popstackmark(&smark);
391}
392
393
394
395STATIC void
396evalcase(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	}
418out:
419	exitstatus = status;
420	popstackmark(&smark);
421}
422
423
424
425/*
426 * Kick off a subshell to evaluate a tree.
427 */
428
429STATIC void
430evalsubshell(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
457STATIC void
458expredir(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
494STATIC void
495evalpipe(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
558void
559evalbackcmd(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	}
607out:
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
613static const char *
614syspath(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
635static int
636parse_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
669int vforked = 0;
670extern char *trap[];
671
672/*
673 * Execute a simple command.
674 */
675
676STATIC void
677evalcommand(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 {
894normal_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
1066parent:	/* 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
1076out:
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
1094STATIC void
1095prehash(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
1116int
1117bltincmd(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
1138int
1139breakcmd(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
1157int
1158returncmd(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
1176int
1177falsecmd(int argc, char **argv)
1178{
1179	return 1;
1180}
1181
1182
1183int
1184truecmd(int argc, char **argv)
1185{
1186	return 0;
1187}
1188
1189
1190int
1191execcmd(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
1206static int
1207conv_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
1233int
1234timescmd(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