1fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes/*	$OpenBSD: exec.c,v 1.52 2015/09/10 22:48:58 nicm Exp $	*/
25155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
35155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*-
4c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes *		 2011, 2012, 2013, 2014, 2015
6fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes *	mirabilos <m@mirbsd.org>
75155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
85155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Provided that these terms and disclaimer and all copyright notices
95155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * are retained or reproduced in an accompanying document, permission
105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is granted to deal in this work without restriction, including un-
115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * limited rights to use, publicly perform, distribute, sell, modify,
125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * merge, give away, or sublicence.
135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the utmost extent permitted by applicable law, neither express nor
165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * implied; without malicious intent or gross negligence. In no event
175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * may a licensor, author or contributor be held liable for indirect,
185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * direct, other damage, loss, or other issues arising in any way out
195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of dealing in the work, even if advised of the possibility of such
205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * damage or existence of a defect, except proven that it results out
215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of said person's immediate fault when using the work as intended.
225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "sh.h"
255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
26fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.170 2015/12/31 21:03:47 tg Exp $");
275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_DEFAULT_EXECSHELL
2996b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#define MKSH_DEFAULT_EXECSHELL	MKSH_UNIXROOT "/bin/sh"
305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int comexec(struct op *, struct tbl * volatile, const char **,
335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    int volatile, volatile int *);
345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void scriptexec(struct op *, const char **) MKSH_A_NORETURN;
3550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughesstatic int call_builtin(struct tbl *, const char **, const char *, bool);
365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int iosetup(struct ioword *, struct tbl *);
37c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int herein(struct ioword *, char **);
385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *do_selectargs(const char **, bool);
395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic Test_op dbteste_isa(Test_env *, Test_meta);
405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *dbteste_getopnd(Test_env *, Test_op, bool);
415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void dbteste_error(Test_env *, int, const char *);
42c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/* XXX: horrible kludge to fit within the framework */
4396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughesstatic void plain_fmt_entry(char *, size_t, unsigned int, const void *);
4496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughesstatic void select_fmt_entry(char *, size_t, unsigned int, const void *);
455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * execute command tree
485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
5003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraexecute(struct op * volatile t,
5103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* if XEXEC don't fork */
5203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    volatile int flags,
535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    volatile int * volatile xerrok)
545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	volatile int rv = 0, dummy = 0;
575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int pv[2];
5803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	const char ** volatile ap = NULL;
595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char ** volatile up;
6003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	const char *s, *ccp;
615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct ioword **iowp;
625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp = NULL;
6303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *cp;
645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t == NULL)
665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Caller doesn't care if XERROK should propagate. */
695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (xerrok == NULL)
705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		xerrok = &dummy;
715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* run in sub-process */
745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (exchild(t, flags & ~XTIME, xerrok, -1));
755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	newenv(E_EXEC);
775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (trap)
785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		runtraps(0);
795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* we want to run an executable, do some variance checks */
815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->type == TCOM) {
8203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* check if this is 'var=<<EOF' */
8350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/*XXX this is broken, don’t use! */
8450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/*XXX https://bugs.launchpad.net/mksh/+bug/1380389 */
8503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (
8603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* we have zero arguments, i.e. no programme to run */
8703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    t->args[0] == NULL &&
8803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* we have exactly one variable assignment */
8903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    t->vars[0] != NULL && t->vars[1] == NULL &&
9003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* we have exactly one I/O redirection */
9103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    t->ioact != NULL && t->ioact[0] != NULL &&
9203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    t->ioact[1] == NULL &&
9303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* of type "here document" (or "here string") */
94b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		    (t->ioact[0]->ioflag & IOTYPE) == IOHERE &&
9503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* the variable assignment begins with a valid varname */
9603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] &&
9703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* and has no right-hand side (i.e. "varname=") */
9850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    ccp[0] == CHAR && ((ccp[1] == '=' && ccp[2] == EOS) ||
9950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    /* or "varname+=" */ (ccp[1] == '+' && ccp[2] == CHAR &&
10050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    ccp[3] == '=' && ccp[4] == EOS)) &&
10103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* plus we can have a here document content */
102c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    herein(t->ioact[0], &cp) == 0 && cp && *cp) {
10303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			char *sp = cp, *dp;
10450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			size_t n = ccp - t->vars[0] + (ccp[1] == '+' ? 4 : 2);
10550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			size_t z;
10603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
10703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* drop redirection (will be garbage collected) */
10803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			t->ioact = NULL;
10903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
11003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* set variable to its expanded value */
11150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			z = strlen(cp);
11250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			if (notoktomul(z, 2) || notoktoadd(z * 2, n + 1))
113811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				internal_errorf(Toomem, (size_t)-1);
11450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			dp = alloc(z * 2 + n + 1, APERM);
11503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			memcpy(dp, t->vars[0], n);
11603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			t->vars[0] = dp;
11703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			dp += n;
11803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			while (*sp) {
11903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				*dp++ = QCHAR;
12003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				*dp++ = *sp++;
12103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
12203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			*dp = EOS;
12303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* free the expanded value */
12403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			afree(cp, APERM);
12503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
12603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
12703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
12803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Clear subst_exstat before argument expansion. Used by
1295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * null commands (see comexec() and c_eval()) and by c_set().
1305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
1315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		subst_exstat = 0;
1325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* for $LINENO */
13403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		current_lineno = t->lineno;
1355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
13703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * POSIX says expand command words first, then redirections,
1385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * and assignments last..
1395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
1405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		up = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
1415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (flags & XTIME)
1425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* Allow option parsing (bizarre, but POSIX) */
1435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			timex_hook(t, &up);
1445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ap = (const char **)up;
1455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ap[0])
1465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp = findcom(ap[0], FC_BI|FC_FUNC);
1475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	flags &= ~XTIME;
1495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
15103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		e->savefd = alloc2(NUFILE, sizeof(short), ATEMP);
1525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* initialise to not redirected */
1535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memset(e->savefd, 0, NUFILE * sizeof(short));
1545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* mark for replacement later (unless TPIPE) */
15703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	vp_pipest->flag |= INT_L;
15803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* do redirection, to be restored in quitenv() */
1605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->ioact != NULL)
1615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (iowp = t->ioact; *iowp != NULL; iowp++) {
1625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (iosetup(*iowp, tp) < 0) {
1635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				exstat = rv = 1;
16403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/*
16503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				 * Redirection failures for special commands
1665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * cause (non-interactive) shell to exit.
1675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 */
1685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (tp && tp->type == CSHELL &&
1695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    (tp->flag & SPEC_BI))
1705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					errorfz();
1715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* Deal with FERREXIT, quitenv(), etc. */
1725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				goto Break;
1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (t->type) {
1775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TCOM:
1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = comexec(t, tp, (const char **)ap, flags, xerrok);
1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TPAREN:
1825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t->left, flags | XFORK, xerrok);
1835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TPIPE:
1865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags |= XFORK;
1875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags &= ~XEXEC;
1885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->savefd[0] = savefd(0);
1895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->savefd[1] = savefd(1);
1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (t->type == TPIPE) {
1915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			openpipe(pv);
19203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* stdout of curr */
19303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ksh_dup2(pv[1], 1, false);
1945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/**
1955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * Let exchild() close pv[0] in child
1965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * (if this isn't done, commands like
1975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 *	(: ; cat /etc/termcap) | sleep 1
1985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * will hang forever).
1995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
2005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			exchild(t->left, flags | XPIPEO | XCCLOSE,
2015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    NULL, pv[0]);
20203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* stdin of next */
20303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ksh_dup2(pv[0], 0, false);
2045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			closepipe(pv);
2055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flags |= XPIPEI;
2065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t = t->right;
2075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
20803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* stdout of last */
20903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		restfd(1, e->savefd[1]);
21003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* no need to re-restore this */
21103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		e->savefd[1] = 0;
2125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Let exchild() close 0 in parent, after fork, before wait */
21303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		i = exchild(t, flags | XPCLOSE | XPIPEST, xerrok, 0);
2145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(flags&XBGND) && !(flags&XXCOM))
2155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rv = i;
2165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
2175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TLIST:
2195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (t->type == TLIST) {
2205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			execute(t->left, flags & XERROK, NULL);
2215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t = t->right;
2225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t, flags & XERROK, xerrok);
2245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
2255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TCOPROC: {
22703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifndef MKSH_NOPROSPECTOFWORK
2285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sigset_t omask;
2295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
23003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
23103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Block sigchild as we are using things changed in the
2325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * signal handler
2335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
2345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
2355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->type = E_ERRH;
236c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if ((i = kshsetjmp(e->jbuf))) {
2375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sigprocmask(SIG_SETMASK, &omask, NULL);
2385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			quitenv(NULL);
2395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			unwind(i);
2405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* NOTREACHED */
2415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
24203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
2435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Already have a (live) co-process? */
2445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (coproc.job && coproc.write >= 0)
2455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			errorf("coprocess already exists");
2465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Can we re-use the existing co-process pipe? */
2485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		coproc_cleanup(true);
2495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* do this before opening pipes, in case these fail */
2515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->savefd[0] = savefd(0);
2525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->savefd[1] = savefd(1);
2535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		openpipe(pv);
2555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (pv[0] != 0) {
2565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_dup2(pv[0], 0, false);
2575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			close(pv[0]);
2585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		coproc.write = pv[1];
2605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		coproc.job = NULL;
2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (coproc.readw >= 0)
2635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_dup2(coproc.readw, 1, false);
2645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else {
2655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			openpipe(pv);
2665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			coproc.read = pv[0];
2675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_dup2(pv[1], 1, false);
26803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* closed before first read */
26903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			coproc.readw = pv[1];
2705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			coproc.njobs = 0;
2715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* create new coprocess id */
2725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			++coproc.id;
2735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
27403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifndef MKSH_NOPROSPECTOFWORK
2755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sigprocmask(SIG_SETMASK, &omask, NULL);
27603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* no more need for error handler */
27703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		e->type = E_EXEC;
27803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
2795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
28003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
28103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * exchild() closes coproc.* in child after fork,
2825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * will also increment coproc.njobs when the
2835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * job is actually created.
2845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
2855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags &= ~XEXEC;
2865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		exchild(t->left, flags | XBGND | XFORK | XCOPROC | XCCLOSE,
2875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    NULL, coproc.readw);
2885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
2895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TASYNC:
29203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
29303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * XXX non-optimal, I think - "(foo &)", forks for (),
2945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * forks again for async... parent should optimise
2955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * this to "foo &"...
2965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
2975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK, xerrok);
2985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
2995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TOR:
3015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TAND:
3025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t->left, XERROK, xerrok);
3035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((rv == 0) == (t->type == TAND))
304811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			rv = execute(t->right, flags & XERROK, xerrok);
305811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		else {
306811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			flags |= XERROK;
307811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if (xerrok)
308811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				*xerrok = 1;
309811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		}
3105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TBANG:
3135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = !execute(t->right, XERROK, xerrok);
3145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags |= XERROK;
3155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (xerrok)
3165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*xerrok = 1;
3175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TDBRACKET: {
3205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Test_env te;
3215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.flags = TEF_DBRACKET;
3235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.pos.wp = t->args;
3245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.isa = dbteste_isa;
3255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.getopnd = dbteste_getopnd;
3265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.eval = test_eval;
3275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.error = dbteste_error;
3285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = test_parse(&te);
3305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TFOR:
3345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TSELECT: {
3355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		volatile bool is_first = true;
336811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
3375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ap = (t->vars == NULL) ? e->loc->argv + 1 :
3385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (const char **)eval((const char **)t->vars,
3395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    DOBLANK | DOGLOB | DOTILDE);
3405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->type = E_LOOP;
341c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		while ((i = kshsetjmp(e->jbuf))) {
3425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((e->flags&EF_BRKCONT_PASS) ||
3435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (i != LBREAK && i != LCONTIN)) {
3445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				quitenv(NULL);
3455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				unwind(i);
3465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else if (i == LBREAK) {
3475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = 0;
3485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				goto Break;
3495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
35103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* in case of a continue */
35203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		rv = 0;
3535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (t->type == TFOR) {
3545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (*ap != NULL) {
3555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
3565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = execute(t->left, flags & XERROK, xerrok);
3575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
35803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		} else {
35903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* TSELECT */
3605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (;;) {
36103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (!(ccp = do_selectargs(ap, is_first))) {
3625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					rv = 1;
3635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
3645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
3655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				is_first = false;
36603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				setstr(global(t->str), ccp, KSH_UNWIND_ERROR);
3675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				execute(t->left, flags & XERROK, xerrok);
3685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TWHILE:
3745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TUNTIL:
3755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->type = E_LOOP;
376c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		while ((i = kshsetjmp(e->jbuf))) {
3775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((e->flags&EF_BRKCONT_PASS) ||
3785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (i != LBREAK && i != LCONTIN)) {
3795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				quitenv(NULL);
3805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				unwind(i);
3815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else if (i == LBREAK) {
3825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = 0;
3835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				goto Break;
3845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
38603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* in case of a continue */
38703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		rv = 0;
3885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while ((execute(t->left, XERROK, NULL) == 0) ==
3895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (t->type == TWHILE))
3905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rv = execute(t->right, flags & XERROK, xerrok);
3915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TIF:
3945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TELIF:
3955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (t->right == NULL)
39603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* should be error */
39703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			break;
3985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t->left, XERROK, NULL) == 0 ?
3995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    execute(t->right->left, flags & XERROK, xerrok) :
4005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    execute(t->right->right, flags & XERROK, xerrok);
4015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TCASE:
40403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		i = 0;
40550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		ccp = evalstr(t->str, DOTILDE | DOSCALAR);
40603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		for (t = t->left; t != NULL && t->type == TPAT; t = t->right) {
40703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			for (ap = (const char **)t->vars; *ap; ap++) {
40803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (i || ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
40903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    gmatchx(ccp, s, false))) {
41003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					rv = execute(t->left, flags & XERROK,
41103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					    xerrok);
41203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					i = 0;
41303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					switch (t->u.charflag) {
41403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					case '&':
41503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						i = 1;
41603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						/* FALLTHROUGH */
41703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					case '|':
41803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						goto TCASE_next;
41903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					}
42003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					goto TCASE_out;
42103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				}
42203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
42303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			i = 0;
42403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra TCASE_next:
42503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* empty */;
42603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
42703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra TCASE_out:
4285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TBRACE:
4315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t->left, flags & XERROK, xerrok);
4325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TFUNCT:
4355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = define(t->str, t);
4365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TTIME:
43903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
44003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Clear XEXEC so nested execute() call doesn't exit
4415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * (allows "ls -l | time grep foo").
4425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
4435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = timex(t, flags & ~XEXEC, xerrok);
4445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
44603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case TEXEC:
44703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* an eval'd TCOM */
4485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		up = makenv();
4495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		restoresigs();
4505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		cleanup_proc_env();
4515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		{
4525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			union mksh_ccphack cargs;
4535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			cargs.ro = t->args;
4555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			execve(t->str, cargs.rw, up);
4565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rv = errno;
4575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
4585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (rv == ENOEXEC)
4595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			scriptexec(t, (const char **)up);
4605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
46150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			errorf("%s: %s", t->str, cstrerror(rv));
4625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Break:
464c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	exstat = rv & 0xFF;
46503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (vp_pipest->flag & INT_L) {
46603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		unset(vp_pipest, 1);
46703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		vp_pipest->flag = DEFINED | ISSET | INTEGER | RDONLY |
468737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		    ARRAY | INT_U | INT_L;
46903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		vp_pipest->val.i = rv;
47003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
4715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
47203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* restores IO */
47303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	quitenv(NULL);
4745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((flags&XEXEC))
47503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* exit child */
47603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		unwind(LEXIT);
4775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (rv != 0 && !(flags & XERROK) &&
4785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (xerrok == NULL || !*xerrok)) {
479c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (Flag(FERREXIT) & 0x80) {
480c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* inside eval */
481c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			Flag(FERREXIT) = 0;
482c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		} else {
483c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			trapsig(ksh_SIGERR);
484c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (Flag(FERREXIT))
485c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				unwind(LERROR);
486c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
4875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rv);
4895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
4925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * execute simple command
4935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
4945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
49603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condracomexec(struct op *t, struct tbl * volatile tp, const char **ap,
4975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    volatile int flags, volatile int *xerrok)
4985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
5005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	volatile int rv = 0;
5015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *cp;
5025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char **lastp;
50303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* Must be static (XXX but why?) */
50403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	static struct op texec;
5055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int type_flags;
50650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	bool resetspec;
5075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int fcflags = FC_BI|FC_FUNC|FC_PATH;
5085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct block *l_expand, *l_assign;
50950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	int optc;
51050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	const char *exec_argv0 = NULL;
51150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	bool exec_clrenv = false;
5125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
51350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	/* snag the last argument for $_ */
5145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FTALKING) && *(lastp = ap)) {
51550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/*
51650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		 * XXX not the same as AT&T ksh, which only seems to set $_
51750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		 * after a newline (but not in functions/dot scripts, but in
51850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		 * interactive and script) - perhaps save last arg here and
51950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		 * set it in shell()?.
52050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		 */
5215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (*++lastp)
5225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			;
5235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* setstr() can't fail here */
5245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp,
5255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    KSH_RETURN_ERROR);
5265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
52803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/**
52903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Deal with the shell builtins builtin, exec and command since
5305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * they can be followed by other commands. This must be done before
5315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * we know if we should create a local block which must be done
5325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * before we can do a path search (in case the assignments change
5335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * PATH).
5345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * Odd cases:
5355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	FOO=bar exec >/dev/null		FOO is kept but not exported
5365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	FOO=bar exec foobar		FOO is exported
5375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	FOO=bar command exec >/dev/null	FOO is neither kept nor exported
5385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	FOO=bar command			FOO is neither kept nor exported
5395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	PATH=... foobar			use new PATH in foobar search
5405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
54150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	resetspec = false;
5425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while (tp && tp->type == CSHELL) {
54303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* undo effects of command */
54403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		fcflags = FC_BI|FC_FUNC|FC_PATH;
5455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp->val.f == c_builtin) {
54603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if ((cp = *++ap) == NULL ||
54703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    (!strcmp(cp, "--") && (cp = *++ap) == NULL)) {
5485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp = NULL;
5495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
5505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
55103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if ((tp = findcom(cp, FC_BI)) == NULL)
55203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin");
55396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			if (tp->type == CSHELL && (tp->val.f == c_cat
55496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#ifdef MKSH_PRINTF_BUILTIN
55596b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			    || tp->val.f == c_printf
55696b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#endif
55796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			    ))
55896b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				break;
5595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			continue;
5605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (tp->val.f == c_exec) {
5615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (ap[1] == NULL)
5625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
56350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			ksh_getopt_reset(&builtin_opt, GF_ERROR);
56450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			while ((optc = ksh_getopt(ap, &builtin_opt, "a:c")) != -1)
56550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				switch (optc) {
56650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				case 'a':
56750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					exec_argv0 = builtin_opt.optarg;
56850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					break;
56950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				case 'c':
57050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					exec_clrenv = true;
57150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					/* ensure we can actually do this */
57250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					resetspec = true;
57350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					break;
57450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				default:
57550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					rv = 2;
57650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes					goto Leave;
57750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				}
57850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			ap += builtin_opt.optind;
5795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flags |= XEXEC;
5805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (tp->val.f == c_command) {
58150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			bool saw_p = false;
5825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
58303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
58403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * Ugly dealing with options in two places (here
58503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * and in c_command(), but such is life)
5865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
5875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_getopt_reset(&builtin_opt, 0);
5885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) == 'p')
58950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				saw_p = true;
59050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			if (optc != -1)
59103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* command -vV or something */
59203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				break;
5935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* don't look for functions */
5945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			fcflags = FC_BI|FC_PATH;
5955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (saw_p) {
5965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (Flag(FRESTRICTED)) {
59703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					warningf(true, "%s: %s",
59803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					    "command -p", "restricted");
5995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					rv = 1;
6005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					goto Leave;
6015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
6025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				fcflags |= FC_DEFPATH;
6035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
6045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ap += builtin_opt.optind;
60503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
60603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * POSIX says special builtins lose their status
6075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * if accessed using command.
6085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
60950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			resetspec = true;
6105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!ap[0]) {
6115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* ensure command with no args exits with 0 */
6125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				subst_exstat = 0;
6135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
6145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
61503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		} else if (tp->val.f == c_cat) {
61696b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			/* if we have any flags, do not use the builtin */
61703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (ap[1] && ap[1][0] == '-' && ap[1][1] != '\0' &&
61803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    /* argument, begins with -, is not - or -- */
61996b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			    (ap[1][1] != '-' || ap[1][2] != '\0')) {
62096b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				struct tbl *ext_cat;
62196b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes
62296b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				ext_cat = findcom(Tcat, FC_PATH | FC_FUNC);
62396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				if (ext_cat && (ext_cat->type != CTALIAS ||
62496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				    (ext_cat->flag & ISSET)))
62596b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes					tp = ext_cat;
62696b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			}
62796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			break;
62896b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#ifdef MKSH_PRINTF_BUILTIN
62996b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		} else if (tp->val.f == c_printf) {
63096b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			struct tbl *ext_printf;
63196b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes
63296b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			ext_printf = findcom(Tprintf, FC_PATH | FC_FUNC);
63396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			if (ext_printf && (ext_printf->type != CTALIAS ||
63496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			    (ext_printf->flag & ISSET)))
63596b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				tp = ext_printf;
63696b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			break;
63703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
638c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		} else if (tp->val.f == c_trap) {
639c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			t->u.evalflags &= ~DOTCOMEXEC;
640c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			break;
6415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else
6425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
6435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
6445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
645c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (t->u.evalflags & DOTCOMEXEC)
646c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		flags |= XEXEC;
6475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	l_expand = e->loc;
64850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	if (!resetspec && (!ap[0] || (tp && (tp->flag & KEEPASN))))
6495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		type_flags = 0;
6505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else {
6515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* create new variable/function block */
6525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		newblock();
6535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* ksh functions don't keep assignments, POSIX functions do. */
65450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		if (!resetspec && tp && tp->type == CFUNC &&
65550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    !(tp->flag & FKSH))
6565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			type_flags = EXPORT;
65750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		else
6585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			type_flags = LOCAL|LOCAL_COPY|EXPORT;
6595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	l_assign = e->loc;
66150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	if (exec_clrenv)
66250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		l_assign->flags |= BF_STOPENV;
6635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FEXPORT))
6645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		type_flags |= EXPORT;
665811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (Flag(FXTRACE))
666811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(2, false);
6675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (i = 0; t->vars[i]; i++) {
6685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* do NOT lookup in the new var/fn block just created */
6695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->loc = l_expand;
67050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		cp = evalstr(t->vars[i], DOASNTILDE | DOSCALAR);
6715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->loc = l_assign;
6725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (Flag(FXTRACE)) {
673811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			const char *ccp;
674811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
675811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			ccp = skip_varname(cp, true);
676811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if (*ccp == '+')
677811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				++ccp;
678811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if (*ccp == '=')
679811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				++ccp;
680811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			shf_write(cp, ccp - cp, shl_xtrace);
681811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			print_value_quoted(shl_xtrace, ccp);
682811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			shf_putc(' ', shl_xtrace);
6835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
684811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* but assign in there as usual */
6855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		typeset(cp, type_flags, 0, 0, 0);
6865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
688811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (Flag(FXTRACE)) {
689811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(2, false);
690811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		if (ap[rv = 0]) {
691811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser xtrace_ap_loop:
692811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			print_value_quoted(shl_xtrace, ap[rv]);
693811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if (ap[++rv]) {
694811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				shf_putc(' ', shl_xtrace);
695811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				goto xtrace_ap_loop;
696811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			}
697811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		}
698811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(1, false);
699811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	}
700811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
7015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((cp = *ap) == NULL) {
7025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = subst_exstat;
7035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		goto Leave;
7045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (!tp) {
7055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (Flag(FRESTRICTED) && vstrchr(cp, '/')) {
70603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(true, "%s: %s", cp, "restricted");
7075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rv = 1;
7085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto Leave;
7095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
7105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = findcom(cp, fcflags);
7115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
7125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (tp->type) {
71403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
71503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* shell built-in */
71603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case CSHELL:
71796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes do_call_builtin:
71850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		rv = call_builtin(tp, (const char **)ap, null, resetspec);
71950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		if (resetspec && tp->val.f == c_shift) {
720c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			l_expand->argc = l_assign->argc;
721c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			l_expand->argv = l_assign->argv;
722c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
7235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
7245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
72503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* function call */
72603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case CFUNC: {
72703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		volatile uint32_t old_inuse;
72803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		const char * volatile old_kshname;
72996b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		volatile uint8_t old_flags[FNFLAGS];
7305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(tp->flag & ISSET)) {
7325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			struct tbl *ftp;
7335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!tp->u.fpath) {
73503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				rv = (tp->u2.errnov == ENOENT) ? 127 : 126;
73603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				warningf(true, "%s: %s %s: %s", cp,
73703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    "can't find", "function definition file",
738c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    cstrerror(tp->u2.errnov));
7395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
7405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
741c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (include(tp->u.fpath, 0, NULL, false) < 0) {
74296b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				if (!strcmp(cp, Tcat)) {
74396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes no_cat_in_FPATH:
74496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes					tp = findcom(Tcat, FC_BI);
74596b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes					goto do_call_builtin;
74696b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				}
74796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#ifdef MKSH_PRINTF_BUILTIN
74896b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				if (!strcmp(cp, Tprintf)) {
74996b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes no_printf_in_FPATH:
75096b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes					tp = findcom(Tprintf, FC_BI);
75196b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes					goto do_call_builtin;
75296b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				}
75396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#endif
75403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				warningf(true, "%s: %s %s %s: %s", cp,
75503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    "can't open", "function definition file",
756811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				    tp->u.fpath, cstrerror(errno));
7575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = 127;
7585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
7595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
7605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!(ftp = findfunc(cp, hash(cp), false)) ||
7615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    !(ftp->flag & ISSET)) {
76296b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				if (!strcmp(cp, Tcat))
76396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes					goto no_cat_in_FPATH;
76496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#ifdef MKSH_PRINTF_BUILTIN
76596b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				if (!strcmp(cp, Tprintf))
76696b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes					goto no_printf_in_FPATH;
76796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#endif
76803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				warningf(true, "%s: %s %s", cp,
76903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    "function not defined by", tp->u.fpath);
7705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = 127;
7715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
7725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
7735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp = ftp;
7745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
7755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
77603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
77703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * ksh functions set $0 to function name, POSIX
77803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * functions leave $0 unchanged.
7795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
7805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		old_kshname = kshname;
7815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp->flag & FKSH)
7825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			kshname = ap[0];
7835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
7845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ap[0] = kshname;
7855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->loc->argv = ap;
7865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (i = 0; *ap++ != NULL; i++)
7875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			;
7885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->loc->argc = i - 1;
78903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
79003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * ksh-style functions handle getopts sanely,
7915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * Bourne/POSIX functions are insane...
7925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
7935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp->flag & FKSH) {
7945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			e->loc->flags |= BF_DOGETOPTS;
7955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			e->loc->getopts_state = user_opt;
7965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			getopts_reset(1);
7975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
7985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
79996b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		for (type_flags = 0; type_flags < FNFLAGS; ++type_flags)
80096b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			old_flags[type_flags] = shell_flags[type_flags];
80196b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		change_xtrace((Flag(FXTRACEREC) ? Flag(FXTRACE) : 0) |
802811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		    ((tp->flag & TRACE) ? 1 : 0), false);
8035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		old_inuse = tp->flag & FINUSE;
8045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp->flag |= FINUSE;
8055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->type = E_FUNC;
807c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (!(i = kshsetjmp(e->jbuf))) {
808c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			execute(tp->val.t, flags & XERROK, NULL);
8095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			i = LRETURN;
8105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
811811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
8125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		kshname = old_kshname;
81396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		change_xtrace(old_flags[(int)FXTRACE], false);
81496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#ifndef MKSH_LEGACY_MODE
81596b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		if (tp->flag & FKSH) {
81696b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			/* Korn style functions restore Flags on return */
81796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			old_flags[(int)FXTRACE] = Flag(FXTRACE);
81896b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			for (type_flags = 0; type_flags < FNFLAGS; ++type_flags)
81996b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				shell_flags[type_flags] = old_flags[type_flags];
82096b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		}
82196b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#endif
8225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp->flag = (tp->flag & ~FINUSE) | old_inuse;
823811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
82403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
82503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Were we deleted while executing? If so, free the
826b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		 * execution tree.
8275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
8285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
8295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (tp->flag & ALLOC) {
8305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->flag &= ~ALLOC;
8315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tfree(tp->val.t, tp->areap);
8325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag = 0;
8345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		switch (i) {
8365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LRETURN:
8375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LERROR:
838c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			rv = exstat & 0xFF;
8395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
8405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LINTR:
8415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LEXIT:
8425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LLEAVE:
8435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LSHELL:
8445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			quitenv(NULL);
8455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			unwind(i);
8465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* NOTREACHED */
8475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		default:
8485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			quitenv(NULL);
84903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			internal_errorf("%s %d", "CFUNC", i);
8505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
8525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
8535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
85403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* executable command */
85503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case CEXEC:
85603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* tracked alias */
85703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case CTALIAS:
8585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(tp->flag&ISSET)) {
85903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (tp->u2.errnov == ENOENT) {
8605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = 127;
86103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				warningf(true, "%s: %s", cp, "not found");
86203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			} else {
86303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				rv = 126;
86403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				warningf(true, "%s: %s: %s", cp, "can't execute",
865c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    cstrerror(tp->u2.errnov));
8665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
8685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
87050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/* set $_ to program's full path */
8715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* setstr() can't fail here */
872737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		setstr(typeset("_", LOCAL | EXPORT, 0, INTEGER, 0),
8735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    tp->val.s, KSH_RETURN_ERROR);
8745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
87550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/* to fork, we set up a TEXEC node and call execute */
87650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		texec.type = TEXEC;
87750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/* for vistree/dumptree */
87850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		texec.left = t;
87950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		texec.str = tp->val.s;
88050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		texec.args = ap;
88150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes
88250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/* in this case we do not fork, of course */
88350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		if (flags & XEXEC) {
88450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			if (exec_argv0)
88550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes				texec.args[0] = exec_argv0;
8865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			j_exit();
88750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			if (!(flags & XBGND)
8885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_UNEMPLOYED
8895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    || Flag(FMONITOR)
8905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
8915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    ) {
8925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
8935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);
8945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = exchild(&texec, flags, xerrok, -1);
8985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
8995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
9005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Leave:
9015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (flags & XEXEC) {
902c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		exstat = rv & 0xFF;
9035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		unwind(LLEAVE);
9045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
9055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rv);
9065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
9095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruscriptexec(struct op *tp, const char **ap)
9105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *sh;
9125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_SMALL
9135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int fd;
91450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	unsigned char buf[68];
9155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
9165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	union mksh_ccphack args, cap;
9175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sh = str_val(global("EXECSHELL"));
9195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (sh && *sh)
92003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		sh = search_path(sh, path, X_OK, NULL);
9215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!sh || !*sh)
9225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sh = MKSH_DEFAULT_EXECSHELL;
9235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*tp->args-- = tp->str;
9255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_SMALL
92796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes	if ((fd = binopen2(tp->str, O_RDONLY)) >= 0) {
92850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		unsigned char *cp;
92950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		unsigned short m;
93050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		ssize_t n;
93150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes
93250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/* read first couple of octets from file */
93350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		n = read(fd, buf, sizeof(buf) - 1);
9345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(fd);
93550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/* read error or short read? */
93650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		if (n < 5)
93750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			goto nomagic;
93850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/* terminate buffer */
93950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		buf[n] = '\0';
94003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
94103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* skip UTF-8 Byte Order Mark, if present */
94250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		cp = buf + (n = ((buf[0] == 0xEF) && (buf[1] == 0xBB) &&
94350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    (buf[2] == 0xBF)) ? 3 : 0);
94450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes
94550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/* scan for newline or NUL (end of buffer) */
94650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		while (*cp && *cp != '\n')
94750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			++cp;
9485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* if the shebang line is longer than MAXINTERP, bail out */
94950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		if (!*cp)
9505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto noshebang;
95150012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/* replace newline by NUL */
95250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		*cp = '\0';
95303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
95403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* restore begin of shebang position (buf+0 or buf+3) */
95550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		cp = buf + n;
95650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		/* bail out if no shebang magic found */
95796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		if (cp[0] == '#' && cp[1] == '!')
95896b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			cp += 2;
95996b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#ifdef __OS2__
96096b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		else if (!strncmp(cp, Textproc, 7) &&
96196b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		    (cp[7] == ' ' || cp[7] == '\t'))
96296b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			cp += 8;
96396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes#endif
96496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		else
9655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto noshebang;
9665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* skip whitespace before shell name */
9675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (*cp == ' ' || *cp == '\t')
9685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			++cp;
9695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* just whitespace on the line? */
9705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*cp == '\0')
9715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto noshebang;
9725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* no, we actually found an interpreter name */
9735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sh = (char *)cp;
9745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* look for end of shell/interpreter name */
9755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (*cp != ' ' && *cp != '\t' && *cp != '\0')
9765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			++cp;
9775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* any arguments? */
9785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*cp) {
9795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*cp++ = '\0';
9805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* skip spaces before arguments */
9815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (*cp == ' ' || *cp == '\t')
9825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				++cp;
9835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* pass it all in ONE argument (historic reasons) */
9845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (*cp)
9855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*tp->args-- = (char *)cp;
9865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
98750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		goto nomagic;
9885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru noshebang:
98950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		m = buf[0] << 8 | buf[1];
99050012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		if (m == 0x7F45 && buf[2] == 'L' && buf[3] == 'F')
991737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			errorf("%s: not executable: %d-bit ELF file", tp->str,
99250012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			    32 * buf[4]);
99350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		if ((m == /* OMAGIC */ 0407) ||
99450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    (m == /* NMAGIC */ 0410) ||
99550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    (m == /* ZMAGIC */ 0413) ||
99650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    (m == /* QMAGIC */ 0314) ||
99750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    (m == /* ECOFF_I386 */ 0x4C01) ||
99850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    (m == /* ECOFF_M68K */ 0x0150 || m == 0x5001) ||
99950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    (m == /* ECOFF_SH */   0x0500 || m == 0x0005) ||
100096b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		    (m == /* bzip */ 0x425A) || (m == /* "MZ" */ 0x4D5A) ||
100196b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		    (m == /* "NE" */ 0x4E45) || (m == /* "LX" */ 0x4C58) ||
1002fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		    (m == /* ksh93 */ 0x0B13) || (m == /* LZIP */ 0x4C5A) ||
100396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		    (m == /* xz */ 0xFD37 && buf[2] == 'z' && buf[3] == 'X' &&
100496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		    buf[4] == 'Z') || (m == /* 7zip */ 0x377A) ||
100550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    (m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D))
100650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			errorf("%s: not executable: magic %04X", tp->str, m);
100750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes nomagic:
100850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		;
10095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
10115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	args.ro = tp->args;
10125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*args.ro = sh;
10135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	cap.ro = ap;
10155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	execve(args.rw[0], args.rw, cap.rw);
10165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* report both the programme that was run and the bogus interpreter */
1018c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	errorf("%s: %s: %s", tp->str, sh, cstrerror(errno));
10195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
10225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushcomexec(const char **wp)
10235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
10255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp = ktsearch(&builtins, *wp, hash(*wp));
102750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	return (call_builtin(tp, wp, "shcomexec", false));
10285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
10315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Search function tables for a function. If create set, a table entry
10325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is created if none is found.
10335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
10345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct tbl *
10355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querufindfunc(const char *name, uint32_t h, bool create)
10365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct block *l;
10385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp = NULL;
10395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (l = e->loc; l; l = l->next) {
10415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = ktsearch(&l->funs, name, h);
10425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp)
10435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
10445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!l->next && create) {
10455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp = ktenter(&l->funs, name, h);
10465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag = DEFINED;
10475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->type = CFUNC;
10485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->val.t = NULL;
10495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
10505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
10515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (tp);
10535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
10565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * define function. Returns 1 if function is being undefined (t == 0) and
10575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * function did not exist, returns 0 otherwise.
10585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
10595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
10605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudefine(const char *name, struct op *t)
10615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
106203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	uint32_t nhash;
10635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
10645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool was_set = false;
10655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
106603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	nhash = hash(name);
106703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
106803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (/* CONSTCOND */ 1) {
106903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		tp = findfunc(name, nhash, true);
10705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp->flag & ISSET)
10725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			was_set = true;
107303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
107403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * If this function is currently being executed, we zap
107503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * this table entry so findfunc() won't see it
10765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
10775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp->flag & FINUSE) {
10785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->name[0] = '\0';
107903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* ensure it won't be found */
108003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			tp->flag &= ~DEFINED;
10815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag |= FDELETE;
10825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else
10835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
10845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (tp->flag & ALLOC) {
10875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp->flag &= ~(ISSET|ALLOC);
10885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tfree(tp->val.t, tp->areap);
10895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
109103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (t == NULL) {
109203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* undefine */
10935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ktdelete(tp);
10945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (was_set ? 0 : 1);
10955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp->val.t = tcopy(t->left, tp->areap);
10985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp->flag |= (ISSET|ALLOC);
10995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->u.ksh_func)
11005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp->flag |= FKSH;
11015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
11035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * add builtin
11075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
110803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraconst char *
11095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querubuiltin(const char *name, int (*func) (const char **))
11105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
1112811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	uint32_t flag = DEFINED;
11135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* see if any flags should be set for this builtin */
1115811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	while (1) {
111603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (*name == '=')
111703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* command does variable assignment */
11185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flag |= KEEPASN;
111903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		else if (*name == '*')
112003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* POSIX special builtin */
11215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flag |= SPEC_BI;
11225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
11235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
1124811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		name++;
11255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp = ktenter(&builtins, name, hash(name));
1128811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	tp->flag = flag;
11295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp->type = CSHELL;
11305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp->val.f = func;
113103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
113203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (name);
11335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * find command
11375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * either function, hashed command, or built-in (in that order)
11385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
11395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct tbl *
11405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querufindcom(const char *name, int flags)
11415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	static struct tbl temp;
11435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	uint32_t h = hash(name);
11445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp = NULL, *tbi;
114503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* insert if not found */
114603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	unsigned char insert = Flag(FTRACKALL);
114703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* for function autoloading */
114803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *fpath;
11495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	union mksh_cchack npath;
11505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (vstrchr(name, '/')) {
11525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		insert = 0;
11535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* prevent FPATH search below */
11545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags &= ~FC_FUNC;
11555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		goto Search;
11565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL;
115803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
115903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * POSIX says special builtins first, then functions, then
1160811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	 * regular builtins, then search path...
11615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
11625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
11635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = tbi;
11645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!tp && (flags & FC_FUNC)) {
11655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = findfunc(name, h, false);
11665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp && !(tp->flag & ISSET)) {
11675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((fpath = str_val(global("FPATH"))) == null) {
11685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->u.fpath = NULL;
116903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				tp->u2.errnov = ENOENT;
11705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else
117103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				tp->u.fpath = search_path(name, fpath, R_OK,
117203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    &tp->u2.errnov);
11735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1175811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (!tp && (flags & FC_NORMBI) && tbi)
11765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = tbi;
11775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
11785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = ktsearch(&taliases, name, h);
117903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (tp && (tp->flag & ISSET) &&
118003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    ksh_access(tp->val.s, X_OK) != 0) {
11815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (tp->flag & ALLOC) {
11825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->flag &= ~ALLOC;
11835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				afree(tp->val.s, APERM);
11845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
11855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag &= ~ISSET;
11865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Search:
11905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET))) &&
11915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (flags & FC_PATH)) {
11925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!tp) {
11935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (insert && !(flags & FC_DEFPATH)) {
11945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp = ktenter(&taliases, name, h);
11955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->type = CTALIAS;
11965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else {
11975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp = &temp;
11985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->type = CEXEC;
11995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
120003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* make ~ISSET */
120103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			tp->flag = DEFINED;
12025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
120303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		npath.ro = search_path(name,
120403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    (flags & FC_DEFPATH) ? def_path : path,
120503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    X_OK, &tp->u2.errnov);
12065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (npath.ro) {
12075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			strdupx(tp->val.s, npath.ro, APERM);
12085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (npath.ro != name)
12095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				afree(npath.rw, ATEMP);
12105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag |= ISSET|ALLOC;
12115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if ((flags & FC_FUNC) &&
12125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (fpath = str_val(global("FPATH"))) != null &&
121303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    (npath.ro = search_path(name, fpath, R_OK,
121403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    &tp->u2.errnov)) != NULL) {
121503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
121603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * An undocumented feature of AT&T ksh is that
121703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * it searches FPATH if a command is not found,
121803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * even if the command hasn't been set up as an
121903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * autoloaded function (ie, no typeset -uf).
12205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
12215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp = &temp;
12225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->type = CFUNC;
122303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* make ~ISSET */
122403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			tp->flag = DEFINED;
12255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->u.fpath = npath.ro;
12265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
12275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
12285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (tp);
12295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
12325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * flush executable commands with relative paths
123303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * (just relative or all?)
12345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
12355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
123603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraflushcom(bool all)
12375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
12385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
12395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tstate ts;
12405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (ktwalk(&ts, &taliases); (tp = ktnext(&ts)) != NULL; )
124296b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		if ((tp->flag&ISSET) && (all || !mksh_abspath(tp->val.s))) {
12435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (tp->flag&ALLOC) {
12445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->flag &= ~(ALLOC|ISSET);
12455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				afree(tp->val.s, APERM);
12465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
12475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag &= ~ISSET;
12485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
12495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
125103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* check if path is something we want to find */
1252fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughesint
125303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrasearch_access(const char *fn, int mode)
12545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
125503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct stat sb;
125603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
125703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (stat(fn, &sb) < 0)
125803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* file does not exist */
125903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (ENOENT);
126003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* LINTED use of access */
1261fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (access(fn, mode) < 0) {
126203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* file exists, but we can't access it */
1263fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		int eno;
1264fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes
1265fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		eno = errno;
1266fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		return (eno ? eno : EACCES);
1267fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	}
126803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (mode == X_OK && (!S_ISREG(sb.st_mode) ||
126903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    !(sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
127003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* access(2) may say root can execute everything */
127103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (S_ISDIR(sb.st_mode) ? EISDIR : EACCES);
127203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (0);
12735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
12765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * search for command with PATH
12775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
12785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruconst char *
127903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrasearch_path(const char *name, const char *lpath,
128003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* R_OK or X_OK */
128103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    int mode,
128203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* set if candidate found, but not suitable */
128303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    int *errnop)
12845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
12855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *sp, *p;
12865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *xp;
12875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XString xs;
128803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t namelen;
128903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int ec = 0, ev;
12905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (vstrchr(name, '/')) {
129203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((ec = search_access(name, mode)) == 0) {
129303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra search_path_ok:
129403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (errnop)
129503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				*errnop = 0;
12965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (name);
129703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
129803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		goto search_path_err;
12995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	namelen = strlen(name) + 1;
13025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Xinit(xs, xp, 128, ATEMP);
13035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sp = lpath;
13055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while (sp != NULL) {
13065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		xp = Xstring(xs, xp);
130796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		if (!(p = cstrchr(sp, MKSH_PATHSEPC)))
13085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p = sp + strlen(sp);
13095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (p != sp) {
13105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			XcheckN(xs, xp, p - sp);
13115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			memcpy(xp, sp, p - sp);
13125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			xp += p - sp;
13135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*xp++ = '/';
13145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
13155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sp = p;
13165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XcheckN(xs, xp, namelen);
13175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memcpy(xp, name, namelen);
131803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((ev = search_access(Xstring(xs, xp), mode)) == 0) {
131903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			name = Xclose(xs, xp + namelen);
132003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			goto search_path_ok;
132103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
132203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* accumulate non-ENOENT errors only */
132303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (ev != ENOENT && ec == 0)
132403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ec = ev;
13255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*sp++ == '\0')
13265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sp = NULL;
13275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Xfree(xs, xp);
132903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra search_path_err:
133003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (errnop)
133103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		*errnop = ec ? ec : ENOENT;
13325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (NULL);
13335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
13345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
133650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughescall_builtin(struct tbl *tp, const char **wp, const char *where, bool resetspec)
13375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
13385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int rv;
13395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1340c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (!tp)
1341c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		internal_errorf("%s: %s", where, wp[0]);
13425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	builtin_argv0 = wp[0];
1343fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	builtin_spec = tobool(!resetspec &&
1344fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	    /*XXX odd use of KEEPASN */
1345fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	    ((tp->flag & SPEC_BI) || (Flag(FPOSIX) && (tp->flag & KEEPASN))));
13465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf_reopen(1, SHF_WR, shl_stdout);
134703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	shl_stdout_ok = true;
13485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ksh_getopt_reset(&builtin_opt, GF_ERROR);
13495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	rv = (*tp->val.f)(wp);
13505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf_flush(shl_stdout);
135103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	shl_stdout_ok = false;
13525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	builtin_argv0 = NULL;
135350012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	builtin_spec = false;
13545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rv);
13555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
13565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
13585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * set up redirection, saving old fds in e->savefd
13595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
13605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
13615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruiosetup(struct ioword *iop, struct tbl *tp)
13625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
13635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int u = -1;
1364fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	char *cp = iop->ioname;
1365b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	int iotype = iop->ioflag & IOTYPE;
1366fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	bool do_open = true, do_close = false, do_fstat = false;
1367c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int flags = 0;
13685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct ioword iotmp;
13695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct stat statb;
13705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (iotype != IOHERE)
13725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? DOGLOB : 0));
13735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Used for tracing and error messages to print expanded cp */
13755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	iotmp = *iop;
1376fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	iotmp.ioname = (iotype == IOHERE) ? NULL : cp;
1377b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	iotmp.ioflag |= IONAMEXP;
13785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1379811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (Flag(FXTRACE)) {
1380811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(2, false);
1381811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		fptreef(shl_xtrace, 0, "%R", &iotmp);
1382811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(1, false);
1383811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	}
13845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (iotype) {
13865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IOREAD:
13875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags = O_RDONLY;
13885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
13895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IOCAT:
13915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags = O_WRONLY | O_APPEND | O_CREAT;
13925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
13935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IOWRITE:
1395fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB)) {
1396fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			/* >file under set -C */
1397fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			if (stat(cp, &statb)) {
1398fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				/* nonexistent file */
1399fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				flags = O_WRONLY | O_CREAT | O_EXCL;
1400fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			} else if (S_ISREG(statb.st_mode)) {
1401fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				/* regular file, refuse clobbering */
1402fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				goto clobber_refused;
1403fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			} else {
1404fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				/*
1405fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				 * allow redirections to things
1406fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				 * like /dev/null without error
1407fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				 */
1408fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				flags = O_WRONLY;
1409fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				/* but check again after opening */
1410fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				do_fstat = true;
1411fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			}
1412fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		} else {
1413fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			/* >|file or set +C */
1414fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			flags = O_WRONLY | O_CREAT | O_TRUNC;
1415fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		}
14165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
14175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IORDWR:
14195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags = O_RDWR | O_CREAT;
14205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
14215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IOHERE:
1423c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		do_open = false;
14245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* herein() returns -2 if error has been printed */
1425c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		u = herein(iop, NULL);
14265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* cp may have wrong name */
14275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
14285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IODUP: {
14305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		const char *emsg;
14315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1432c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		do_open = false;
143396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		if (ksh_isdash(cp)) {
143403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* prevent error return below */
143503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			u = 1009;
1436c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			do_close = true;
14375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if ((u = check_fd(cp,
1438b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		    X_OK | ((iop->ioflag & IORDUP) ? R_OK : W_OK),
14395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    &emsg)) < 0) {
1440811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			char *sp;
1441811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
14425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			warningf(true, "%s: %s",
1443811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			    (sp = snptreef(NULL, 32, "%R", &iotmp)), emsg);
1444811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			afree(sp, ATEMP);
14455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
14465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1447b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		if (u == (int)iop->unit)
144803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* "dup from" == "dup to" */
144903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			return (0);
14505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1451c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    }
14525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (do_open) {
14555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
145603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(true, "%s: %s", cp, "restricted");
14575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
14585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
145996b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		u = binopen3(cp, flags, 0666);
1460fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		if (do_fstat && u >= 0) {
1461fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			/* prevent race conditions */
1462fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			if (fstat(u, &statb) || S_ISREG(statb.st_mode)) {
1463fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				close(u);
1464fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes clobber_refused:
1465fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				u = -1;
1466fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				errno = EEXIST;
1467fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			}
1468fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		}
14695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (u < 0) {
14715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* herein() may already have printed message */
14725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (u == -1) {
14735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			u = errno;
147403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(true, "can't %s %s: %s",
14755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    iotype == IODUP ? "dup" :
14765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (iotype == IOREAD || iotype == IOHERE) ?
1477c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    "open" : "create", cp, cstrerror(u));
14785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
14795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
14805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Do not save if it has already been redirected (i.e. "cat >x >y"). */
14825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (e->savefd[iop->unit] == 0) {
14835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* If these are the same, it means unit was previously closed */
1484b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		if (u == (int)iop->unit)
14855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			e->savefd[iop->unit] = -1;
14865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
148703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
148803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * c_exec() assumes e->savefd[fd] set for any
14895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * redirections. Ask savefd() not to close iop->unit;
14905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * this allows error messages to be seen if iop->unit
14915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * is 2; also means we can't lose the fd (eg, both
14925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * dup2 below and dup2 in restfd() failing).
14935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
14945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			e->savefd[iop->unit] = savefd(iop->unit);
14955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (do_close)
14985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(iop->unit);
1499b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	else if (u != (int)iop->unit) {
15005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ksh_dup2(u, iop->unit, true) < 0) {
1501c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			int eno;
1502811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			char *sp;
15035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1504c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			eno = errno;
1505fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			warningf(true, "%s %s: %s",
150603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    "can't finish (dup) redirection",
1507811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			    (sp = snptreef(NULL, 32, "%R", &iotmp)),
1508c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    cstrerror(eno));
1509811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			afree(sp, ATEMP);
15105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (iotype != IODUP)
15115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				close(u);
15125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
15135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
15145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (iotype != IODUP)
15155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			close(u);
151603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
151703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Touching any co-process fd in an empty exec
15185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * causes the shell to close its copies
15195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
15205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
1521b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			if (iop->ioflag & IORDUP)
152203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* possible exec <&p */
15235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				coproc_read_close(u);
152403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else
152503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* possible exec >&p */
15265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				coproc_write_close(u);
15275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
15285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
152903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (u == 2)
153003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* Clear any write errors */
15315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_reopen(2, SHF_WR, shl_out);
15325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
15335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
15345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
153603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Process here documents by providing the content, either as
153703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * result (globally allocated) string or in a temp file; if
153803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * unquoted, the string is expanded first.
15395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
15405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
1541fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hugheshereinval(struct ioword *iop, int sub, char **resbuf, struct shf *shf)
154203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
1543fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	const char * volatile ccp = iop->heredoc;
154403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct source *s, *osource;
154503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
154603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	osource = source;
154703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	newenv(E_ERRH);
1548c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (kshsetjmp(e->jbuf)) {
154903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		source = osource;
155003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		quitenv(shf);
155103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to iosetup(): don't print error */
155203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (-2);
155303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
1554fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (iop->ioflag & IOHERESTR) {
1555fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		ccp = evalstr(iop->delim, DOHERESTR | DOSCALAR | DOHEREDOC);
1556fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	} else if (sub) {
155703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* do substitutions on the content of heredoc */
155803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		s = pushs(SSTRING, ATEMP);
1559c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		s->start = s->str = ccp;
156003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		source = s;
1561c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (yylex(sub) != LWORD)
156203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			internal_errorf("%s: %s", "herein", "yylex");
156303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		source = osource;
156450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		ccp = evalstr(yylval.cp, DOSCALAR | DOHEREDOC);
1565c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
156603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
156703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (resbuf == NULL)
156803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shf_puts(ccp, shf);
156903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	else
157003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		strdupx(*resbuf, ccp, APERM);
157103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
157203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	quitenv(NULL);
157303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (0);
157403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
157503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
157603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int
1577c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserherein(struct ioword *iop, char **resbuf)
15785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
157903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int fd = -1;
158003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct shf *shf;
15815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct temp *h;
15825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
15835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
158450012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	/* ksh -c 'cat <<EOF' can cause this... */
1585fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (iop->heredoc == NULL && !(iop->ioflag & IOHERESTR)) {
158603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		warningf(true, "%s missing", "here document");
158703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to iosetup(): don't print error */
158803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (-2);
15895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
15905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1591c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* lexer substitution flags */
1592b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	i = (iop->ioflag & IOEVAL) ? (ONEWORD | HEREDOC) : 0;
1593c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
159403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* skip all the fd setup if we just want the value */
159503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (resbuf != NULL)
1596fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		return (hereinval(iop, i, resbuf, NULL));
159703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
159803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
159903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Create temp file to hold content (done before newenv
160003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * so temp doesn't get removed too soon).
16015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
16025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps);
160396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes	if (!(shf = h->shf) || (fd = binopen3(h->tffn, O_RDONLY, 0)) < 0) {
160403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		i = errno;
16055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		warningf(true, "can't %s temporary file %s: %s",
1606c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    !shf ? "create" : "open", h->tffn, cstrerror(i));
16075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf)
16085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_close(shf);
160903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to iosetup(): don't print error */
161003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (-2);
16115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
16125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1613fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (hereinval(iop, i, NULL, shf) == -2) {
16145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(fd);
161503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to iosetup(): don't print error */
161603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (-2);
16175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
16185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
161950012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	if (shf_close(shf) == -1) {
16205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = errno;
16215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(fd);
1622c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		warningf(true, "can't %s temporary file %s: %s",
1623c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    "write", h->tffn, cstrerror(i));
162403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to iosetup(): don't print error */
162503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (-2);
16265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
16275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (fd);
16295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
16305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
16325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	ksh special - the select command processing section
16335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	print the args in column form - assuming that we can
16345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
16355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *
16365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudo_selectargs(const char **ap, bool print_menu)
16375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
16385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	static const char *read_args[] = {
16395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		"read", "-r", "REPLY", NULL
16405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	};
16415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *s;
16425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i, argct;
16435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (argct = 0; ap[argct]; argct++)
16455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		;
164603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (/* CONSTCOND */ 1) {
164703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*-
164803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Menu is printed if
16495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 *	- this is the first time around the select loop
16505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 *	- the user enters a blank line
16515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 *	- the REPLY parameter is empty
16525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
16535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (print_menu || !*str_val(global("REPLY")))
16545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			pr_menu(ap);
16555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shellf("%s", str_val(global("PS3")));
165650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		if (call_builtin(findcom("read", FC_BI), read_args, Tselect,
165750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		    false))
16585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (NULL);
1659b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		if (*(s = str_val(global("REPLY"))))
1660b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			return ((getn(s, &i) && i >= 1 && i <= argct) ?
1661b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			    ap[i - 1] : null);
1662c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		print_menu = true;
16635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
16645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
16655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct select_menu_info {
16675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char * const *args;
16685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int num_width;
16695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
16705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* format a single select menu item */
167296b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughesstatic void
1673c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserselect_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
16745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
16755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const struct select_menu_info *smi =
16765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (const struct select_menu_info *)arg;
16775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1678c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	shf_snprintf(buf, buflen, "%*u) %s",
16795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    smi->num_width, i + 1, smi->args[i]);
16805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
16815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
16835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	print a select style menu
16845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1685c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaservoid
16865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querupr_menu(const char * const *ap)
16875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
16885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct select_menu_info smi;
16895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char * const *pp;
169003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t acols = 0, aocts = 0, i;
1691c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	unsigned int n;
16925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
16945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * width/column calculations were done once and saved, but this
16955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * means select can't be used recursively so we re-calculate
16965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * each time (could save in a structure that is returned, but
16975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * it's probably not worth the bother)
16985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
16995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
17015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * get dimensions of the list
17025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
17035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (n = 0, pp = ap; *pp; n++, pp++) {
17045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = strlen(*pp);
17055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (i > aocts)
17065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			aocts = i;
17075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = utf_mbswidth(*pp);
17085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (i > acols)
17095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			acols = i;
17105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
17115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
17135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * we will print an index of the form "%d) " in front of
17145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * each entry, so get the maximum width of this
17155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
17165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (i = n, smi.num_width = 1; i >= 10; i /= 10)
17175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		smi.num_width++;
17185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	smi.args = ap;
17205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	print_columns(shl_out, n, select_fmt_entry, (void *)&smi,
17215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    smi.num_width + 2 + aocts, smi.num_width + 2 + acols,
17225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    true);
17235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
17245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
172596b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughesstatic void
1726c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserplain_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
17275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
172803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	strlcpy(buf, ((const char * const *)arg)[i], buflen);
17295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
17305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1731c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaservoid
17325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querupr_list(char * const *ap)
17335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
173403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t acols = 0, aocts = 0, i;
1735c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	unsigned int n;
17365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char * const *pp;
17375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (n = 0, pp = ap; *pp; n++, pp++) {
17395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = strlen(*pp);
17405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (i > aocts)
17415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			aocts = i;
17425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = utf_mbswidth(*pp);
17435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (i > acols)
17445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			acols = i;
17455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
17465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	print_columns(shl_out, n, plain_fmt_entry, (const void *)ap,
17485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    aocts, acols, false);
17495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
17505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
17525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	[[ ... ]] evaluation routines
17535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
17545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
17565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Test if the current token is a whatever. Accepts the current token if
17575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * it is. Returns 0 if it is not, non-zero if it is (in the case of
17585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * TM_UNOP and TM_BINOP, the returned value is a Test_op).
17595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
17605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic Test_op
17615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbteste_isa(Test_env *te, Test_meta meta)
17625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
17635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Test_op ret = TO_NONOP;
1764737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	bool uqword;
17655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *p;
17665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!*te->pos.wp)
17685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (meta == TM_END ? TO_NONNULL : TO_NONOP);
17695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* unquoted word? */
17715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = *te->pos.wp; *p == CHAR; p += 2)
17725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		;
17735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	uqword = *p == EOS;
17745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (meta == TM_UNOP || meta == TM_BINOP) {
17765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (uqword) {
177703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* longer than the longest operator */
177803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			char buf[8];
17795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			char *q = buf;
178003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1781c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			p = *te->pos.wp;
1782c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			while (*p++ == CHAR &&
1783c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    (size_t)(q - buf) < sizeof(buf) - 1)
1784c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				*q++ = *p++;
17855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*q = '\0';
17865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ret = test_isop(meta, buf);
17875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
17885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (meta == TM_END)
17895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = TO_NONOP;
17905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else
17915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = (uqword && !strcmp(*te->pos.wp,
17925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    dbtest_tokens[(int)meta])) ? TO_NONNULL : TO_NONOP;
17935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Accept the token? */
17955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ret != TO_NONOP)
17965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te->pos.wp++;
17975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (ret);
17995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
18005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *
18025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbteste_getopnd(Test_env *te, Test_op op, bool do_eval)
18035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
18045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *s = *te->pos.wp;
180550012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	int flags = DOTILDE | DOSCALAR;
18065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!s)
18085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
18095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	te->pos.wp++;
18115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!do_eval)
18135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (null);
18145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (op == TO_STEQL || op == TO_STNEQ)
181650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		flags |= DOPAT;
18175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
181850012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes	return (evalstr(s, flags));
18195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
18205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
18225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbteste_error(Test_env *te, int offset, const char *msg)
18235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
18245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	te->flags |= TEF_ERROR;
18255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	internal_warningf("dbteste_error: %s (offset %d)", msg, offset);
18265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1827