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