1/*-
2 * Copyright (c) 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1997-2005
5 *	Herbert Xu <herbert@gondor.apana.org.au>.  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 <zircon/process.h>
36#include <zircon/status.h>
37#include <zircon/syscalls.h>
38#include <stdlib.h>
39#include <signal.h>
40#include <unistd.h>
41#include <sys/types.h>
42
43/*
44 * Evaluate a command.
45 */
46
47#include "process.h"
48#include "shell.h"
49#include "nodes.h"
50#include "syntax.h"
51#include "expand.h"
52#include "parser.h"
53#include "jobs.h"
54#include "eval.h"
55#include "builtins.h"
56#include "options.h"
57#include "exec.h"
58#include "redir.h"
59#include "input.h"
60#include "output.h"
61#include "trap.h"
62#include "var.h"
63#include "memalloc.h"
64#include "error.h"
65#include "show.h"
66#include "mystring.h"
67
68
69int evalskip;			/* set if we are skipping commands */
70STATIC int skipcount;		/* number of levels to skip */
71MKINIT int loopnest;		/* current loop nesting level */
72static int funcline;		/* starting line number of current function, or 0 if not in a function */
73
74
75char *commandname;
76int exitstatus;			/* exit status of last command */
77int back_exitstatus;		/* exit status of backquoted command */
78int savestatus = -1;		/* exit status of last command outside traps */
79
80
81STATIC int evalloop(union node *, int);
82STATIC int evalfor(union node *, int);
83STATIC int evalcase(union node *, int);
84STATIC int evalsubshell(union node *, int);
85STATIC void expredir(union node *);
86STATIC int evalpipe(union node *, int);
87#ifdef notyet
88STATIC int evalcommand(union node *, int, struct backcmd *);
89#else
90STATIC int evalcommand(union node *, int);
91#endif
92STATIC int evalbltin(const struct builtincmd *, int, char **, int);
93STATIC int evalfun(struct funcnode *, int, char **, int);
94STATIC void prehash(union node *);
95STATIC int eprintlist(struct output *, struct strlist *, int);
96STATIC int bltincmd(int, char **);
97
98
99STATIC const struct builtincmd bltin = {
100	name: nullstr,
101	builtin: bltincmd
102};
103
104
105/*
106 * Called to reset things after an exception.
107 */
108
109#ifdef mkinit
110INCLUDE "eval.h"
111
112RESET {
113	evalskip = 0;
114	loopnest = 0;
115	if (savestatus >= 0) {
116		exitstatus = savestatus;
117		savestatus = -1;
118	}
119}
120#endif
121
122
123/*
124 * The eval commmand.
125 */
126
127static int evalcmd(int argc, char **argv, int flags)
128{
129        char *p;
130        char *concat;
131        char **ap;
132
133        if (argc > 1) {
134                p = argv[1];
135                if (argc > 2) {
136                        STARTSTACKSTR(concat);
137                        ap = argv + 2;
138                        for (;;) {
139                        	concat = stputs(p, concat);
140                                if ((p = *ap++) == NULL)
141                                        break;
142                                STPUTC(' ', concat);
143                        }
144                        STPUTC('\0', concat);
145                        p = grabstackstr(concat);
146                }
147                return evalstring(p, flags & EV_TESTED);
148        }
149        return 0;
150}
151
152
153/*
154 * Execute a command or commands contained in a string.
155 */
156
157int
158evalstring(char *s, int flags)
159{
160	union node *n;
161	struct stackmark smark;
162	int status;
163
164	s = sstrdup(s);
165	setinputstring(s);
166	setstackmark(&smark);
167
168	status = 0;
169	for (; (n = parsecmd(0)) != NEOF; popstackmark(&smark)) {
170		int i;
171
172		i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT));
173		if (n)
174			status = i;
175
176		if (evalskip)
177			break;
178	}
179	popstackmark(&smark);
180	popfile();
181	stunalloc(s);
182
183	return status;
184}
185
186
187
188/*
189 * Evaluate a parse tree.  The value is left in the global variable
190 * exitstatus.
191 */
192
193int
194evaltree(union node *n, int flags)
195{
196	int checkexit = 0;
197	int (*evalfn)(union node *, int);
198	unsigned isor;
199	int status = 0;
200	if (n == NULL) {
201		TRACE(("evaltree(NULL) called\n"));
202		goto out;
203	}
204
205	dotrap();
206
207	TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
208	    getpid(), n, n->type, flags));
209	switch (n->type) {
210	default:
211#ifdef DEBUG
212		out1fmt("Node type = %d\n", n->type);
213#ifndef USE_GLIBC_STDIO
214		flushout(out1);
215#endif
216		break;
217#endif
218	case NNOT:
219		status = !evaltree(n->nnot.com, EV_TESTED);
220		goto setstatus;
221	case NREDIR:
222		errlinno = lineno = n->nredir.linno;
223		if (funcline)
224			lineno -= funcline - 1;
225		expredir(n->nredir.redirect);
226		pushredir(n->nredir.redirect);
227		status = redirectsafe(n->nredir.redirect, REDIR_PUSH) ?:
228			 evaltree(n->nredir.n, flags & EV_TESTED);
229		if (n->nredir.redirect)
230			popredir(0);
231		goto setstatus;
232	case NCMD:
233#ifdef notyet
234		if (eflag && !(flags & EV_TESTED))
235			checkexit = ~0;
236		status = evalcommand(n, flags, (struct backcmd *)NULL);
237		goto setstatus;
238#else
239		evalfn = evalcommand;
240checkexit:
241		if (eflag && !(flags & EV_TESTED))
242			checkexit = ~0;
243		goto calleval;
244#endif
245	case NFOR:
246		evalfn = evalfor;
247		goto calleval;
248	case NWHILE:
249	case NUNTIL:
250		evalfn = evalloop;
251		goto calleval;
252	case NSUBSHELL:
253	case NBACKGND:
254		evalfn = evalsubshell;
255		goto checkexit;
256	case NPIPE:
257		evalfn = evalpipe;
258		goto checkexit;
259	case NCASE:
260		evalfn = evalcase;
261		goto calleval;
262	case NAND:
263	case NOR:
264	case NSEMI:
265#if NAND + 1 != NOR
266#error NAND + 1 != NOR
267#endif
268#if NOR + 1 != NSEMI
269#error NOR + 1 != NSEMI
270#endif
271		isor = n->type - NAND;
272		status = evaltree(n->nbinary.ch1,
273				  (flags | ((isor >> 1) - 1)) & EV_TESTED);
274		if (!status == isor || evalskip)
275			break;
276		n = n->nbinary.ch2;
277evaln:
278		evalfn = evaltree;
279calleval:
280		status = evalfn(n, flags);
281		goto setstatus;
282	case NIF:
283		status = evaltree(n->nif.test, EV_TESTED);
284		if (evalskip)
285			break;
286		if (!status) {
287			n = n->nif.ifpart;
288			goto evaln;
289		} else if (n->nif.elsepart) {
290			n = n->nif.elsepart;
291			goto evaln;
292		}
293		status = 0;
294		goto setstatus;
295	case NDEFUN:
296		defun(n);
297setstatus:
298		exitstatus = status;
299		break;
300	}
301out:
302	if (checkexit & status)
303		goto exexit;
304
305	dotrap();
306
307	if (flags & EV_EXIT) {
308exexit:
309		exraise(EXEXIT);
310	}
311
312	return exitstatus;
313}
314
315
316void evaltreenr(union node *n, int flags)
317#ifdef HAVE_ATTRIBUTE_ALIAS
318	__attribute__ ((alias("evaltree")));
319#else
320{
321	evaltree(n, flags);
322	abort();
323}
324#endif
325
326
327static int skiploop(void)
328{
329	int skip = evalskip;
330
331	switch (skip) {
332	case 0:
333		break;
334
335	case SKIPBREAK:
336	case SKIPCONT:
337		if (likely(--skipcount <= 0)) {
338			evalskip = 0;
339			break;
340		}
341
342		skip = SKIPBREAK;
343		break;
344	}
345
346	return skip;
347}
348
349
350STATIC int
351evalloop(union node *n, int flags)
352{
353	int skip;
354	int status;
355
356	loopnest++;
357	status = 0;
358	flags &= EV_TESTED;
359	do {
360		int i;
361
362		i = evaltree(n->nbinary.ch1, EV_TESTED);
363		skip = skiploop();
364		if (skip == SKIPFUNC)
365			status = i;
366		if (skip)
367			continue;
368		if (n->type != NWHILE)
369			i = !i;
370		if (i != 0)
371			break;
372		status = evaltree(n->nbinary.ch2, flags);
373		if (status == ZX_ERR_CANCELED) {
374			evalskip = SKIPBREAK;
375		}
376		skip = skiploop();
377	} while (!(skip & ~SKIPCONT));
378	loopnest--;
379
380	return status;
381}
382
383
384
385STATIC int
386evalfor(union node *n, int flags)
387{
388	struct arglist arglist;
389	union node *argp;
390	struct strlist *sp;
391	struct stackmark smark;
392	int status;
393
394	errlinno = lineno = n->nfor.linno;
395	if (funcline)
396		lineno -= funcline - 1;
397
398	setstackmark(&smark);
399	arglist.lastp = &arglist.list;
400	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
401		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
402	}
403	*arglist.lastp = NULL;
404
405	status = 0;
406	loopnest++;
407	flags &= EV_TESTED;
408	for (sp = arglist.list ; sp ; sp = sp->next) {
409		setvar(n->nfor.var, sp->text, 0);
410		status = evaltree(n->nfor.body, flags);
411		if (status == ZX_ERR_CANCELED) {
412			evalskip = SKIPBREAK;
413		}
414		if (skiploop() & ~SKIPCONT)
415			break;
416	}
417	loopnest--;
418	popstackmark(&smark);
419
420	return status;
421}
422
423
424
425STATIC int
426evalcase(union node *n, int flags)
427{
428	union node *cp;
429	union node *patp;
430	struct arglist arglist;
431	struct stackmark smark;
432	int status = 0;
433
434	errlinno = lineno = n->ncase.linno;
435	if (funcline)
436		lineno -= funcline - 1;
437
438	setstackmark(&smark);
439	arglist.lastp = &arglist.list;
440	expandarg(n->ncase.expr, &arglist, EXP_TILDE);
441	for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
442		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
443			if (casematch(patp, arglist.list->text)) {
444				/* Ensure body is non-empty as otherwise
445				 * EV_EXIT may prevent us from setting the
446				 * exit status.
447				 */
448				if (evalskip == 0 && cp->nclist.body) {
449					status = evaltree(cp->nclist.body,
450							  flags);
451				}
452				goto out;
453			}
454		}
455	}
456out:
457	popstackmark(&smark);
458
459	return status;
460}
461
462
463
464/*
465 * Kick off a subshell to evaluate a tree.
466 */
467
468STATIC int
469evalsubshell(union node *n, int flags)
470{
471	struct job *jp;
472	int backgnd = (n->type == NBACKGND);
473	int status;
474
475	errlinno = lineno = n->nredir.linno;
476	if (funcline)
477		lineno -= funcline - 1;
478
479	expredir(n->nredir.redirect);
480	if (!backgnd && flags & EV_EXIT && !have_traps()) {
481		redirect(n->nredir.redirect, 0);
482		evaltreenr(n->nredir.n, flags);
483		/* never returns */
484	}
485	INTOFF;
486	jp = makejob(n, 1);
487	zx_handle_t process;
488	const char* const* envp = (const char* const*)environment();
489
490	// Run in the foreground (of the subshell running in the background)
491	if (backgnd)
492		n->type = NSUBSHELL;
493
494	char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
495	zx_status_t exec_result = process_subshell(n, envp, &process, jp->zx_job_hndl, NULL, err_msg);
496        if (exec_result == ZX_OK) {
497		/* Process-tracking management */
498		forkparent(jp, n, backgnd, process);
499        } else {
500		sh_error("Failed to create subshell: %d (%s): %s", exec_result, zx_status_get_string(exec_result), err_msg);
501		return exec_result;
502	}
503	status = 0;
504	if (! backgnd) {
505		status = process_await_termination(process, jp->zx_job_hndl, true);
506		zx_handle_close(process);
507	}
508	INTON;
509	return status;
510}
511
512
513/*
514 * Compute the names of the files in a redirection list.
515 */
516
517STATIC void
518expredir(union node *n)
519{
520	union node *redir;
521
522	for (redir = n ; redir ; redir = redir->nfile.next) {
523		struct arglist fn;
524		fn.lastp = &fn.list;
525		switch (redir->type) {
526		case NFROMTO:
527		case NFROM:
528		case NTO:
529		case NCLOBBER:
530		case NAPPEND:
531			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
532			redir->nfile.expfname = fn.list->text;
533			break;
534		case NFROMFD:
535		case NTOFD:
536			if (redir->ndup.vname) {
537				expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
538				fixredir(redir, fn.list->text, 1);
539			}
540			break;
541		}
542	}
543}
544
545
546
547/*
548 * Evaluate a pipeline.  All the processes in the pipeline are children
549 * of the process creating the pipeline.  (This differs from some versions
550 * of the shell, which make the last process in a pipeline the parent
551 * of all the rest.)
552 */
553
554STATIC int
555evalpipe(union node *n, int flags)
556{
557	struct job *jp;
558	struct nodelist *lp;
559	int pipelen;
560	int fds[3] = { STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO };
561	int pip[2] = { -1, -1 };
562	int status = 0;
563
564	TRACE(("evalpipe(0x%lx) called\n", (long)n));
565	pipelen = 0;
566	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
567		pipelen++;
568	flags |= EV_EXIT;
569	INTOFF;
570	jp = makejob(n, pipelen);
571
572	const size_t processes_size = pipelen * sizeof(zx_handle_t);
573	zx_handle_t* processes = ckmalloc(processes_size);
574	memset(processes, 0, processes_size);
575
576	size_t idx = 0u;
577	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next, ++idx) {
578		prehash(lp->n);
579		if (pip[0] > 0)
580			fds[0] = pip[0];
581		if (lp->next) {
582			if (pipe(pip) < 0)
583				sh_error("Pipe call failed");
584			fds[1] = pip[1];
585		} else {
586			fds[1] = STDOUT_FILENO;
587		}
588		char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
589		const char* const* envp = (const char* const*)environment();
590		zx_status_t status = process_subshell(lp->n, envp, &processes[idx], jp->zx_job_hndl, fds, err_msg);
591		if (fds[0] != STDIN_FILENO)
592			close(fds[0]);
593		if (fds[1] != STDOUT_FILENO)
594			close(fds[1]);
595		if (status == ZX_OK) {
596			/* Process-tracking management */
597			forkparent(jp, lp->n, FORK_NOJOB, processes[idx]);
598		} else {
599			freejob(jp);
600			sh_error("Failed to create shell: %d (%s): %s", status, zx_status_get_string(status), err_msg);
601		}
602	}
603
604	if (n->npipe.backgnd == 0) {
605		status = waitforjob(jp);
606		TRACE(("evalpipe:  job done exit status: %d (%s)\n", status, zx_status_get_string(status)));
607	}
608	INTON;
609
610	zx_handle_close_many(processes, pipelen);
611	ckfree(processes);
612
613	return status;
614}
615
616
617
618/*
619 * Execute a command inside back quotes.  If it's a builtin command, we
620 * want to save its output in a block obtained from malloc.  Otherwise
621 * we fork off a subprocess and get the output of the command via a pipe.
622 * Should be called with interrupts off.
623 */
624
625void
626evalbackcmd(union node *n, struct backcmd *result)
627{
628	int pip[2];
629	struct job *jp;
630
631	result->fd = -1;
632	result->buf = NULL;
633	result->nleft = 0;
634	result->jp = NULL;
635	if (n == NULL) {
636		goto out;
637	}
638
639	if (pipe(pip) < 0)
640		sh_error("Pipe call failed");
641	jp = makejob(n, 1);
642	zx_handle_t process;
643	char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
644	const char* const* envp = (const char* const*)environment();
645	int fds[3] = { STDIN_FILENO, pip[1], STDERR_FILENO };
646	zx_status_t status = process_subshell(n, envp, &process, jp->zx_job_hndl, &fds[0], err_msg);
647        close(pip[1]);
648	if (status != ZX_OK) {
649		freejob(jp);
650		sh_error("Failed to create subshell: %d (%s): %s", status, zx_status_get_string(status), err_msg);
651	} else {
652                /* Process-tracking management */
653		forkparent(jp, n, FORK_NOJOB, process);
654		result->fd = pip[0];
655		result->jp = jp;
656	}
657
658out:
659	TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
660		result->fd, result->buf, result->nleft, result->jp));
661}
662
663static char **
664parse_command_args(char **argv, const char **path)
665{
666	char *cp, c;
667
668	for (;;) {
669		cp = *++argv;
670		if (!cp)
671			return 0;
672		if (*cp++ != '-')
673			break;
674		if (!(c = *cp++))
675			break;
676		if (c == '-' && !*cp) {
677			if (!*++argv)
678				return 0;
679			break;
680		}
681		do {
682			switch (c) {
683			case 'p':
684				*path = defpath;
685				break;
686			default:
687				/* run 'typecmd' for other options */
688				return 0;
689			}
690		} while ((c = *cp++));
691	}
692	return argv;
693}
694
695
696
697/*
698 * Execute a simple command.
699 */
700
701STATIC int
702#ifdef notyet
703evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
704#else
705evalcommand(union node *cmd, int flags)
706#endif
707{
708	struct localvar_list *localvar_stop;
709	struct redirtab *redir_stop;
710	struct stackmark smark;
711	union node *argp;
712	struct arglist arglist;
713	struct arglist varlist;
714	char **argv;
715	int argc;
716	struct strlist *sp;
717#ifdef notyet
718	int pip[2];
719#endif
720	struct cmdentry cmdentry;
721	char *lastarg;
722	const char *path;
723	int spclbltin;
724	int execcmd;
725	int status;
726	char **nargv;
727
728	errlinno = lineno = cmd->ncmd.linno;
729	if (funcline)
730		lineno -= funcline - 1;
731
732	/* First expand the arguments. */
733	TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
734	setstackmark(&smark);
735	localvar_stop = pushlocalvars();
736	back_exitstatus = 0;
737
738	cmdentry.cmdtype = CMDBUILTIN;
739	cmdentry.u.cmd = &bltin;
740	varlist.lastp = &varlist.list;
741	*varlist.lastp = NULL;
742	arglist.lastp = &arglist.list;
743	*arglist.lastp = NULL;
744
745	argc = 0;
746	for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
747		struct strlist **spp;
748
749		spp = arglist.lastp;
750		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
751		for (sp = *spp; sp; sp = sp->next)
752			argc++;
753	}
754
755	/* Reserve one extra spot at the front for shellexec. */
756	nargv = stalloc(sizeof (char *) * (argc + 2));
757	argv = ++nargv;
758	for (sp = arglist.list ; sp ; sp = sp->next) {
759		TRACE(("evalcommand arg: %s\n", sp->text));
760		*nargv++ = sp->text;
761	}
762	*nargv = NULL;
763
764	lastarg = NULL;
765	if (iflag && funcline == 0 && argc > 0)
766		lastarg = nargv[-1];
767
768	preverrout.fd = 2;
769	expredir(cmd->ncmd.redirect);
770	redir_stop = pushredir(cmd->ncmd.redirect);
771	status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
772
773	path = vpath.text;
774	for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
775		struct strlist **spp;
776		char *p;
777
778		spp = varlist.lastp;
779		expandarg(argp, &varlist, EXP_VARTILDE);
780
781		mklocal((*spp)->text);
782
783		/*
784		 * Modify the command lookup path, if a PATH= assignment
785		 * is present
786		 */
787		p = (*spp)->text;
788		if (varequal(p, path))
789			path = p;
790	}
791
792	/* Print the command if xflag is set. */
793	if (xflag) {
794		struct output *out;
795		int sep;
796
797		out = &preverrout;
798		outstr(expandstr(ps4val()), out);
799		sep = 0;
800		sep = eprintlist(out, varlist.list, sep);
801		eprintlist(out, arglist.list, sep);
802		outcslow('\n', out);
803#ifdef FLUSHERR
804		flushout(out);
805#endif
806	}
807
808	execcmd = 0;
809	spclbltin = -1;
810
811	/* Now locate the command. */
812	if (argc) {
813		const char *oldpath;
814		int cmd_flag = DO_ERR;
815
816		path += 5;
817		oldpath = path;
818		for (;;) {
819			find_command(argv[0], &cmdentry, cmd_flag, path);
820			if (cmdentry.cmdtype == CMDUNKNOWN) {
821				status = 127;
822#ifdef FLUSHERR
823				flushout(&errout);
824#endif
825				goto bail;
826			}
827
828			/* implement bltin and command here */
829			if (cmdentry.cmdtype != CMDBUILTIN)
830				break;
831			if (spclbltin < 0)
832				spclbltin =
833					cmdentry.u.cmd->flags &
834					BUILTIN_SPECIAL
835				;
836			if (cmdentry.u.cmd == EXECCMD)
837				execcmd++;
838			if (cmdentry.u.cmd != COMMANDCMD)
839				break;
840
841			path = oldpath;
842			nargv = parse_command_args(argv, &path);
843			if (!nargv)
844				break;
845			argc -= nargv - argv;
846			argv = nargv;
847			cmd_flag |= DO_NOFUNC;
848		}
849	}
850
851	if (status) {
852bail:
853		exitstatus = status;
854
855		/* We have a redirection error. */
856		if (spclbltin > 0)
857			exraise(EXERROR);
858
859		goto out;
860	}
861
862	/* Execute the command. */
863	switch (cmdentry.cmdtype) {
864	default: {
865		zx_handle_t process = ZX_HANDLE_INVALID;
866		zx_handle_t zx_job_hndl;
867		zx_status_t zx_status = zx_job_create(zx_job_default(), 0, &zx_job_hndl);
868		if (zx_status != ZX_OK) {
869			sh_error("Cannot create child process: %d (%s)", zx_status, zx_status_get_string(zx_status));
870			break;
871		}
872		char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
873		status = process_launch((const char* const*)argv, path, cmdentry.u.index, &process, zx_job_hndl, &zx_status, err_msg);
874		if (status) {
875			sh_error("Cannot create child process: %d (%s): %s", zx_status, zx_status_get_string(zx_status), err_msg);
876			break;
877		}
878		settitle(argv[0]);
879		status = process_await_termination(process, zx_job_hndl, true);
880		zx_handle_close(process);
881		zx_handle_close(zx_job_hndl);
882		settitle("sh");
883		break;
884	}
885	case CMDBUILTIN:
886		if (spclbltin > 0 || argc == 0) {
887			poplocalvars(1);
888			if (execcmd && argc > 1)
889				listsetvar(varlist.list, VEXPORT);
890		}
891		if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
892			if (exception == EXERROR && spclbltin <= 0) {
893				FORCEINTON;
894				goto readstatus;
895			}
896raise:
897			longjmp(handler->loc, 1);
898		}
899		goto readstatus;
900
901	case CMDFUNCTION:
902		poplocalvars(1);
903		if (evalfun(cmdentry.u.func, argc, argv, flags))
904			goto raise;
905readstatus:
906		status = exitstatus;
907		break;
908	}
909
910out:
911	if (cmd->ncmd.redirect)
912		popredir(execcmd);
913	unwindredir(redir_stop);
914	unwindlocalvars(localvar_stop);
915	if (lastarg)
916		/* dsl: I think this is intended to be used to support
917		 * '_' in 'vi' command mode during line editing...
918		 * However I implemented that within libedit itself.
919		 */
920		setvar("_", lastarg, 0);
921	popstackmark(&smark);
922
923	return status;
924}
925
926STATIC int
927evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
928{
929	char *volatile savecmdname;
930	struct jmploc *volatile savehandler;
931	struct jmploc jmploc;
932	int status;
933	int i;
934
935	savecmdname = commandname;
936	savehandler = handler;
937	if ((i = setjmp(jmploc.loc)))
938		goto cmddone;
939	handler = &jmploc;
940	commandname = argv[0];
941	argptr = argv + 1;
942	optptr = NULL;			/* initialize nextopt */
943	if (cmd == EVALCMD)
944		status = evalcmd(argc, argv, flags);
945	else
946		status = (*cmd->builtin)(argc, argv);
947	flushall();
948	status |= outerr(out1);
949	exitstatus = status;
950cmddone:
951	freestdout();
952	commandname = savecmdname;
953	handler = savehandler;
954
955	return i;
956}
957
958STATIC int
959evalfun(struct funcnode *func, int argc, char **argv, int flags)
960{
961	volatile struct shparam saveparam;
962	struct jmploc *volatile savehandler;
963	struct jmploc jmploc;
964	int e;
965	int savefuncline;
966	int saveloopnest;
967
968	saveparam = shellparam;
969	savefuncline = funcline;
970	saveloopnest = loopnest;
971	savehandler = handler;
972	if ((e = setjmp(jmploc.loc))) {
973		goto funcdone;
974	}
975	INTOFF;
976	handler = &jmploc;
977	shellparam.malloc = 0;
978	func->count++;
979	funcline = func->n.ndefun.linno;
980	loopnest = 0;
981	INTON;
982	shellparam.nparam = argc - 1;
983	shellparam.p = argv + 1;
984	shellparam.optind = 1;
985	shellparam.optoff = -1;
986	pushlocalvars();
987	evaltree(func->n.ndefun.body, flags & EV_TESTED);
988	poplocalvars(0);
989funcdone:
990	INTOFF;
991	loopnest = saveloopnest;
992	funcline = savefuncline;
993	freefunc(func);
994	freeparam(&shellparam);
995	shellparam = saveparam;
996	handler = savehandler;
997	INTON;
998	evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
999	return e;
1000}
1001
1002
1003/*
1004 * Search for a command.  This is called before we fork so that the
1005 * location of the command will be available in the parent as well as
1006 * the child.  The check for "goodname" is an overly conservative
1007 * check that the name will not be subject to expansion.
1008 */
1009
1010STATIC void
1011prehash(union node *n)
1012{
1013	struct cmdentry entry;
1014
1015	if (n->type == NCMD && n->ncmd.args)
1016		if (goodname(n->ncmd.args->narg.text))
1017			find_command(n->ncmd.args->narg.text, &entry, 0,
1018				     pathval());
1019}
1020
1021
1022
1023/*
1024 * Builtin commands.  Builtin commands whose functions are closely
1025 * tied to evaluation are implemented here.
1026 */
1027
1028/*
1029 * No command given.
1030 */
1031
1032STATIC int
1033bltincmd(int argc, char **argv)
1034{
1035	/*
1036	 * Preserve exitstatus of a previous possible redirection
1037	 * as POSIX mandates
1038	 */
1039	return back_exitstatus;
1040}
1041
1042
1043/*
1044 * Handle break and continue commands.  Break, continue, and return are
1045 * all handled by setting the evalskip flag.  The evaluation routines
1046 * above all check this flag, and if it is set they start skipping
1047 * commands rather than executing them.  The variable skipcount is
1048 * the number of loops to break/continue, or the number of function
1049 * levels to return.  (The latter is always 1.)  It should probably
1050 * be an error to break out of more loops than exist, but it isn't
1051 * in the standard shell so we don't make it one here.
1052 */
1053
1054int
1055breakcmd(int argc, char **argv)
1056{
1057	int n = argc > 1 ? number(argv[1]) : 1;
1058
1059	if (n <= 0)
1060		badnum(argv[1]);
1061	if (n > loopnest)
1062		n = loopnest;
1063	if (n > 0) {
1064		evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
1065		skipcount = n;
1066	}
1067	return 0;
1068}
1069
1070
1071/*
1072 * The return command.
1073 */
1074
1075int
1076returncmd(int argc, char **argv)
1077{
1078	int skip;
1079	int status;
1080
1081	/*
1082	 * If called outside a function, do what ksh does;
1083	 * skip the rest of the file.
1084	 */
1085	if (argv[1]) {
1086		skip = SKIPFUNC;
1087		status = number(argv[1]);
1088	} else {
1089		skip = SKIPFUNCDEF;
1090		status = exitstatus;
1091	}
1092	evalskip = skip;
1093
1094	return status;
1095}
1096
1097
1098int
1099falsecmd(int argc, char **argv)
1100{
1101	return 1;
1102}
1103
1104
1105int
1106truecmd(int argc, char **argv)
1107{
1108	return 0;
1109}
1110
1111
1112int
1113execcmd(int argc, char **argv)
1114{
1115	if (argc > 1) {
1116		iflag = 0;		/* exit on error */
1117		mflag = 0;
1118		optschanged();
1119		shellexec(argv + 1, pathval(), 0);
1120	}
1121	return 0;
1122}
1123
1124
1125STATIC int
1126eprintlist(struct output *out, struct strlist *sp, int sep)
1127{
1128	while (sp) {
1129		const char *p;
1130
1131		p = " %s" + (1 - sep);
1132		sep |= 1;
1133		outfmt(out, p, sp->text);
1134		sp = sp->next;
1135	}
1136
1137	return sep;
1138}
1139