1811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser/*	$OpenBSD: exec.c,v 1.50 2013/06/10 21:09:27 millert Exp $	*/
25155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
35155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*-
4c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes *		 2011, 2012, 2013, 2014
65155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	Thorsten Glaser <tg@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
26b4542e99ca8562aa584e15df8ef35356ff8c10feElliott Hughes__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.133 2014/10/03 17:32:11 tg Exp $");
275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_DEFAULT_EXECSHELL
295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define MKSH_DEFAULT_EXECSHELL	"/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;
35c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int call_builtin(struct tbl *, const char **, const char *);
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 *);
4203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int search_access(const char *, int);
43c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/* XXX: horrible kludge to fit within the framework */
44c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic char *plain_fmt_entry(char *, size_t, unsigned int, const void *);
45c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic char *select_fmt_entry(char *, size_t, unsigned int, const void *);
465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * execute command tree
495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
5103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraexecute(struct op * volatile t,
5203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* if XEXEC don't fork */
5303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    volatile int flags,
545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    volatile int * volatile xerrok)
555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	volatile int rv = 0, dummy = 0;
585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int pv[2];
5903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	const char ** volatile ap = NULL;
605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char ** volatile up;
6103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	const char *s, *ccp;
625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct ioword **iowp;
635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp = NULL;
6403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *cp;
655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t == NULL)
675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Caller doesn't care if XERROK should propagate. */
705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (xerrok == NULL)
715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		xerrok = &dummy;
725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* run in sub-process */
755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (exchild(t, flags & ~XTIME, xerrok, -1));
765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	newenv(E_EXEC);
785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (trap)
795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		runtraps(0);
805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* we want to run an executable, do some variance checks */
825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->type == TCOM) {
8303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* check if this is 'var=<<EOF' */
8403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (
8503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* we have zero arguments, i.e. no programme to run */
8603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    t->args[0] == NULL &&
8703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* we have exactly one variable assignment */
8803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    t->vars[0] != NULL && t->vars[1] == NULL &&
8903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* we have exactly one I/O redirection */
9003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    t->ioact != NULL && t->ioact[0] != NULL &&
9103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    t->ioact[1] == NULL &&
9203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* of type "here document" (or "here string") */
9303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    (t->ioact[0]->flag & IOTYPE) == IOHERE &&
9403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* the variable assignment begins with a valid varname */
9503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] &&
9603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* and has no right-hand side (i.e. "varname=") */
9703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    ccp[0] == CHAR && ccp[1] == '=' && ccp[2] == EOS &&
9803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* plus we can have a here document content */
99c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    herein(t->ioact[0], &cp) == 0 && cp && *cp) {
10003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			char *sp = cp, *dp;
10103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			size_t n = ccp - t->vars[0] + 2, z;
10203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
10303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* drop redirection (will be garbage collected) */
10403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			t->ioact = NULL;
10503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
10603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* set variable to its expanded value */
10703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			z = strlen(cp) + 1;
10803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (notoktomul(z, 2) || notoktoadd(z * 2, n))
109811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				internal_errorf(Toomem, (size_t)-1);
11003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			dp = alloc(z * 2 + n, ATEMP);
11103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			memcpy(dp, t->vars[0], n);
11203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			t->vars[0] = dp;
11303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			dp += n;
11403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			while (*sp) {
11503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				*dp++ = QCHAR;
11603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				*dp++ = *sp++;
11703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
11803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			*dp = EOS;
11903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* free the expanded value */
12003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			afree(cp, APERM);
12103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
12203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
12303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
12403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Clear subst_exstat before argument expansion. Used by
1255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * null commands (see comexec() and c_eval()) and by c_set().
1265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
1275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		subst_exstat = 0;
1285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* for $LINENO */
13003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		current_lineno = t->lineno;
1315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
13303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * POSIX says expand command words first, then redirections,
1345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * and assignments last..
1355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
1365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		up = eval(t->args, t->u.evalflags | DOBLANK | DOGLOB | DOTILDE);
1375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (flags & XTIME)
1385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* Allow option parsing (bizarre, but POSIX) */
1395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			timex_hook(t, &up);
1405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ap = (const char **)up;
1415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ap[0])
1425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp = findcom(ap[0], FC_BI|FC_FUNC);
1435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	flags &= ~XTIME;
1455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->ioact != NULL || t->type == TPIPE || t->type == TCOPROC) {
14703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		e->savefd = alloc2(NUFILE, sizeof(short), ATEMP);
1485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* initialise to not redirected */
1495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memset(e->savefd, 0, NUFILE * sizeof(short));
1505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* mark for replacement later (unless TPIPE) */
15303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	vp_pipest->flag |= INT_L;
15403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* do redirection, to be restored in quitenv() */
1565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->ioact != NULL)
1575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (iowp = t->ioact; *iowp != NULL; iowp++) {
1585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (iosetup(*iowp, tp) < 0) {
1595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				exstat = rv = 1;
16003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/*
16103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				 * Redirection failures for special commands
1625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * cause (non-interactive) shell to exit.
1635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 */
1645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (tp && tp->type == CSHELL &&
1655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    (tp->flag & SPEC_BI))
1665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					errorfz();
1675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* Deal with FERREXIT, quitenv(), etc. */
1685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				goto Break;
1695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
1705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (t->type) {
1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TCOM:
1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = comexec(t, tp, (const char **)ap, flags, xerrok);
1755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TPAREN:
1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t->left, flags | XFORK, xerrok);
1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TPIPE:
1825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags |= XFORK;
1835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags &= ~XEXEC;
1845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->savefd[0] = savefd(0);
1855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->savefd[1] = savefd(1);
1865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (t->type == TPIPE) {
1875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			openpipe(pv);
18803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* stdout of curr */
18903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ksh_dup2(pv[1], 1, false);
1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/**
1915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * Let exchild() close pv[0] in child
1925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * (if this isn't done, commands like
1935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 *	(: ; cat /etc/termcap) | sleep 1
1945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * will hang forever).
1955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
1965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			exchild(t->left, flags | XPIPEO | XCCLOSE,
1975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    NULL, pv[0]);
19803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* stdin of next */
19903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ksh_dup2(pv[0], 0, false);
2005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			closepipe(pv);
2015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flags |= XPIPEI;
2025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t = t->right;
2035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
20403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* stdout of last */
20503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		restfd(1, e->savefd[1]);
20603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* no need to re-restore this */
20703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		e->savefd[1] = 0;
2085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Let exchild() close 0 in parent, after fork, before wait */
20903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		i = exchild(t, flags | XPCLOSE | XPIPEST, xerrok, 0);
2105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(flags&XBGND) && !(flags&XXCOM))
2115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rv = i;
2125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
2135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TLIST:
2155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (t->type == TLIST) {
2165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			execute(t->left, flags & XERROK, NULL);
2175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t = t->right;
2185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t, flags & XERROK, xerrok);
2205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
2215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TCOPROC: {
22303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifndef MKSH_NOPROSPECTOFWORK
2245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sigset_t omask;
2255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
22603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
22703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Block sigchild as we are using things changed in the
2285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * signal handler
2295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
2305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);
2315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->type = E_ERRH;
232c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if ((i = kshsetjmp(e->jbuf))) {
2335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sigprocmask(SIG_SETMASK, &omask, NULL);
2345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			quitenv(NULL);
2355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			unwind(i);
2365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* NOTREACHED */
2375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
23803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
2395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Already have a (live) co-process? */
2405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (coproc.job && coproc.write >= 0)
2415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			errorf("coprocess already exists");
2425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Can we re-use the existing co-process pipe? */
2445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		coproc_cleanup(true);
2455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* do this before opening pipes, in case these fail */
2475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->savefd[0] = savefd(0);
2485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->savefd[1] = savefd(1);
2495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		openpipe(pv);
2515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (pv[0] != 0) {
2525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_dup2(pv[0], 0, false);
2535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			close(pv[0]);
2545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		coproc.write = pv[1];
2565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		coproc.job = NULL;
2575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (coproc.readw >= 0)
2595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_dup2(coproc.readw, 1, false);
2605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else {
2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			openpipe(pv);
2625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			coproc.read = pv[0];
2635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_dup2(pv[1], 1, false);
26403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* closed before first read */
26503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			coproc.readw = pv[1];
2665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			coproc.njobs = 0;
2675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* create new coprocess id */
2685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			++coproc.id;
2695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
27003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifndef MKSH_NOPROSPECTOFWORK
2715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sigprocmask(SIG_SETMASK, &omask, NULL);
27203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* no more need for error handler */
27303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		e->type = E_EXEC;
27403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
2755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
27603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
27703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * exchild() closes coproc.* in child after fork,
2785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * will also increment coproc.njobs when the
2795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * job is actually created.
2805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
2815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags &= ~XEXEC;
2825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		exchild(t->left, flags | XBGND | XFORK | XCOPROC | XCCLOSE,
2835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    NULL, coproc.readw);
2845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
2855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TASYNC:
28803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
28903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * XXX non-optimal, I think - "(foo &)", forks for (),
2905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * forks again for async... parent should optimise
2915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * this to "foo &"...
2925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
2935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t->left, (flags&~XEXEC)|XBGND|XFORK, xerrok);
2945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
2955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TOR:
2975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TAND:
2985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t->left, XERROK, xerrok);
2995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((rv == 0) == (t->type == TAND))
300811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			rv = execute(t->right, flags & XERROK, xerrok);
301811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		else {
302811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			flags |= XERROK;
303811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if (xerrok)
304811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				*xerrok = 1;
305811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		}
3065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TBANG:
3095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = !execute(t->right, XERROK, xerrok);
3105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags |= XERROK;
3115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (xerrok)
3125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*xerrok = 1;
3135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TDBRACKET: {
3165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Test_env te;
3175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.flags = TEF_DBRACKET;
3195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.pos.wp = t->args;
3205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.isa = dbteste_isa;
3215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.getopnd = dbteste_getopnd;
3225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.eval = test_eval;
3235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te.error = dbteste_error;
3245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = test_parse(&te);
3265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TFOR:
3305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TSELECT: {
3315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		volatile bool is_first = true;
332811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
3335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ap = (t->vars == NULL) ? e->loc->argv + 1 :
3345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (const char **)eval((const char **)t->vars,
3355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    DOBLANK | DOGLOB | DOTILDE);
3365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->type = E_LOOP;
337c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		while ((i = kshsetjmp(e->jbuf))) {
3385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((e->flags&EF_BRKCONT_PASS) ||
3395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (i != LBREAK && i != LCONTIN)) {
3405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				quitenv(NULL);
3415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				unwind(i);
3425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else if (i == LBREAK) {
3435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = 0;
3445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				goto Break;
3455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
34703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* in case of a continue */
34803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		rv = 0;
3495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (t->type == TFOR) {
3505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (*ap != NULL) {
3515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				setstr(global(t->str), *ap++, KSH_UNWIND_ERROR);
3525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = execute(t->left, flags & XERROK, xerrok);
3535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
35403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		} else {
35503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* TSELECT */
3565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (;;) {
35703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (!(ccp = do_selectargs(ap, is_first))) {
3585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					rv = 1;
3595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
3605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
3615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				is_first = false;
36203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				setstr(global(t->str), ccp, KSH_UNWIND_ERROR);
3635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				execute(t->left, flags & XERROK, xerrok);
3645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TWHILE:
3705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TUNTIL:
3715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->type = E_LOOP;
372c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		while ((i = kshsetjmp(e->jbuf))) {
3735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((e->flags&EF_BRKCONT_PASS) ||
3745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (i != LBREAK && i != LCONTIN)) {
3755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				quitenv(NULL);
3765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				unwind(i);
3775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else if (i == LBREAK) {
3785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = 0;
3795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				goto Break;
3805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
38203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* in case of a continue */
38303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		rv = 0;
3845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while ((execute(t->left, XERROK, NULL) == 0) ==
3855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (t->type == TWHILE))
3865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rv = execute(t->right, flags & XERROK, xerrok);
3875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TIF:
3905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TELIF:
3915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (t->right == NULL)
39203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* should be error */
39303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			break;
3945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t->left, XERROK, NULL) == 0 ?
3955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    execute(t->right->left, flags & XERROK, xerrok) :
3965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    execute(t->right->right, flags & XERROK, xerrok);
3975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TCASE:
40003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		i = 0;
40103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		ccp = evalstr(t->str, DOTILDE);
40203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		for (t = t->left; t != NULL && t->type == TPAT; t = t->right) {
40303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			for (ap = (const char **)t->vars; *ap; ap++) {
40403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (i || ((s = evalstr(*ap, DOTILDE|DOPAT)) &&
40503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    gmatchx(ccp, s, false))) {
40603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					rv = execute(t->left, flags & XERROK,
40703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					    xerrok);
40803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					i = 0;
40903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					switch (t->u.charflag) {
41003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					case '&':
41103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						i = 1;
41203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						/* FALLTHROUGH */
41303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					case '|':
41403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						goto TCASE_next;
41503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					}
41603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					goto TCASE_out;
41703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				}
41803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
41903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			i = 0;
42003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra TCASE_next:
42103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* empty */;
42203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
42303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra TCASE_out:
4245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TBRACE:
4275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = execute(t->left, flags & XERROK, xerrok);
4285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TFUNCT:
4315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = define(t->str, t);
4325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TTIME:
43503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
43603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Clear XEXEC so nested execute() call doesn't exit
4375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * (allows "ls -l | time grep foo").
4385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
4395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = timex(t, flags & ~XEXEC, xerrok);
4405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
44203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case TEXEC:
44303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* an eval'd TCOM */
4445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = t->args[0];
4455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		up = makenv();
4465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		restoresigs();
4475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		cleanup_proc_env();
4485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		{
4495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			union mksh_ccphack cargs;
4505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			cargs.ro = t->args;
4525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			execve(t->str, cargs.rw, up);
4535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rv = errno;
4545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
4555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (rv == ENOEXEC)
4565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			scriptexec(t, (const char **)up);
4575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
458c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			errorf("%s: %s", s, cstrerror(rv));
4595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Break:
461c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	exstat = rv & 0xFF;
46203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (vp_pipest->flag & INT_L) {
46303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		unset(vp_pipest, 1);
46403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		vp_pipest->flag = DEFINED | ISSET | INTEGER | RDONLY |
465427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes		    ARRAY | INT_U | INT_L;
46603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		vp_pipest->val.i = rv;
46703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
4685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
46903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* restores IO */
47003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	quitenv(NULL);
4715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((flags&XEXEC))
47203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* exit child */
47303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		unwind(LEXIT);
4745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (rv != 0 && !(flags & XERROK) &&
4755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (xerrok == NULL || !*xerrok)) {
476c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (Flag(FERREXIT) & 0x80) {
477c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* inside eval */
478c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			Flag(FERREXIT) = 0;
479c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		} else {
480c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			trapsig(ksh_SIGERR);
481c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (Flag(FERREXIT))
482c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				unwind(LERROR);
483c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
4845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rv);
4865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
4895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * execute simple command
4905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
4915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
49303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condracomexec(struct op *t, struct tbl * volatile tp, const char **ap,
4945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    volatile int flags, volatile int *xerrok)
4955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
4975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	volatile int rv = 0;
4985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *cp;
4995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char **lastp;
50003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* Must be static (XXX but why?) */
50103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	static struct op texec;
5025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int type_flags;
503c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	bool keepasn_ok;
5045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int fcflags = FC_BI|FC_FUNC|FC_PATH;
5055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool bourne_function_call = false;
5065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct block *l_expand, *l_assign;
5075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
50803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
50903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * snag the last argument for $_ XXX not the same as AT&T ksh,
5105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * which only seems to set $_ after a newline (but not in
5115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * functions/dot scripts, but in interactive and script) -
5125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * perhaps save last arg here and set it in shell()?.
5135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
5145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FTALKING) && *(lastp = ap)) {
5155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (*++lastp)
5165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			;
5175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* setstr() can't fail here */
5185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setstr(typeset("_", LOCAL, 0, INTEGER, 0), *--lastp,
5195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    KSH_RETURN_ERROR);
5205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
52203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/**
52303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Deal with the shell builtins builtin, exec and command since
5245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * they can be followed by other commands. This must be done before
5255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * we know if we should create a local block which must be done
5265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * before we can do a path search (in case the assignments change
5275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * PATH).
5285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * Odd cases:
5295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	FOO=bar exec >/dev/null		FOO is kept but not exported
5305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	FOO=bar exec foobar		FOO is exported
5315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	FOO=bar command exec >/dev/null	FOO is neither kept nor exported
5325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	FOO=bar command			FOO is neither kept nor exported
5335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	PATH=... foobar			use new PATH in foobar search
5345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
535c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	keepasn_ok = true;
5365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while (tp && tp->type == CSHELL) {
53703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* undo effects of command */
53803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		fcflags = FC_BI|FC_FUNC|FC_PATH;
5395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp->val.f == c_builtin) {
54003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if ((cp = *++ap) == NULL ||
54103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    (!strcmp(cp, "--") && (cp = *++ap) == NULL)) {
5425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp = NULL;
5435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
5445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
54503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if ((tp = findcom(cp, FC_BI)) == NULL)
54603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin");
5475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			continue;
5485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (tp->val.f == c_exec) {
5495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (ap[1] == NULL)
5505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
5515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ap++;
5525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flags |= XEXEC;
5535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (tp->val.f == c_command) {
5545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			int optc, saw_p = 0;
5555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
55603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
55703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * Ugly dealing with options in two places (here
55803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * and in c_command(), but such is life)
5595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
5605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_getopt_reset(&builtin_opt, 0);
5615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) == 'p')
5625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				saw_p = 1;
5635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (optc != EOF)
56403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* command -vV or something */
56503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				break;
5665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* don't look for functions */
5675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			fcflags = FC_BI|FC_PATH;
5685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (saw_p) {
5695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (Flag(FRESTRICTED)) {
57003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					warningf(true, "%s: %s",
57103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					    "command -p", "restricted");
5725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					rv = 1;
5735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					goto Leave;
5745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
5755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				fcflags |= FC_DEFPATH;
5765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
5775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ap += builtin_opt.optind;
57803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
57903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * POSIX says special builtins lose their status
5805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * if accessed using command.
5815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
582c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			keepasn_ok = false;
5835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!ap[0]) {
5845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* ensure command with no args exits with 0 */
5855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				subst_exstat = 0;
5865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
5875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
58803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifndef MKSH_NO_EXTERNAL_CAT
58903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		} else if (tp->val.f == c_cat) {
59003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
59103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * if we have any flags, do not use the builtin
59203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * in theory, we could allow -u, but that would
59303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * mean to use ksh_getopt here and possibly ad-
59403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * ded complexity and more code and isn't worth
59503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * additional hassle (and the builtin must call
59603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * ksh_getopt already but can't come back here)
59703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 */
59803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (ap[1] && ap[1][0] == '-' && ap[1][1] != '\0' &&
59903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    /* argument, begins with -, is not - or -- */
60003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    (ap[1][1] != '-' || ap[1][2] != '\0'))
60103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* don't look for builtins or functions */
60203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				fcflags = FC_PATH;
60303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else
60403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* go on, use the builtin */
60503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				break;
60603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
607c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		} else if (tp->val.f == c_trap) {
608c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			t->u.evalflags &= ~DOTCOMEXEC;
609c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			break;
6105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else
6115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
6125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
6135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
614c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (t->u.evalflags & DOTCOMEXEC)
615c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		flags |= XEXEC;
6165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	l_expand = e->loc;
6175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))
6185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		type_flags = 0;
6195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else {
6205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* create new variable/function block */
6215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		newblock();
6225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* ksh functions don't keep assignments, POSIX functions do. */
6235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (keepasn_ok && tp && tp->type == CFUNC &&
6245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    !(tp->flag & FKSH)) {
6255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			bourne_function_call = true;
6265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			type_flags = EXPORT;
6275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else
6285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			type_flags = LOCAL|LOCAL_COPY|EXPORT;
6295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	l_assign = e->loc;
6315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FEXPORT))
6325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		type_flags |= EXPORT;
633811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (Flag(FXTRACE))
634811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(2, false);
6355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (i = 0; t->vars[i]; i++) {
6365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* do NOT lookup in the new var/fn block just created */
6375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->loc = l_expand;
638b4542e99ca8562aa584e15df8ef35356ff8c10feElliott Hughes		cp = evalstr(t->vars[i], DOASNTILDE | DOASNFIELD);
6395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->loc = l_assign;
6405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (Flag(FXTRACE)) {
641811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			const char *ccp;
642811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
643811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			ccp = skip_varname(cp, true);
644811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if (*ccp == '+')
645811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				++ccp;
646811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if (*ccp == '=')
647811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				++ccp;
648811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			shf_write(cp, ccp - cp, shl_xtrace);
649811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			print_value_quoted(shl_xtrace, ccp);
650811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			shf_putc(' ', shl_xtrace);
6515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
652811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* but assign in there as usual */
6535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		typeset(cp, type_flags, 0, 0, 0);
6545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (bourne_function_call && !(type_flags & EXPORT))
655427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes			typeset(cp, LOCAL | LOCAL_COPY | EXPORT, 0, 0, 0);
6565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
658811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (Flag(FXTRACE)) {
659811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(2, false);
660811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		if (ap[rv = 0]) {
661811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser xtrace_ap_loop:
662811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			print_value_quoted(shl_xtrace, ap[rv]);
663811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if (ap[++rv]) {
664811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				shf_putc(' ', shl_xtrace);
665811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				goto xtrace_ap_loop;
666811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			}
667811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		}
668811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(1, false);
669811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	}
670811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
6715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((cp = *ap) == NULL) {
6725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = subst_exstat;
6735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		goto Leave;
6745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (!tp) {
6755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (Flag(FRESTRICTED) && vstrchr(cp, '/')) {
67603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(true, "%s: %s", cp, "restricted");
6775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rv = 1;
6785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto Leave;
6795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
6805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = findcom(cp, fcflags);
6815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (tp->type) {
68403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
68503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* shell built-in */
68603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case CSHELL:
687c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		rv = call_builtin(tp, (const char **)ap, null);
688c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (!keepasn_ok && tp->val.f == c_shift) {
689c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			l_expand->argc = l_assign->argc;
690c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			l_expand->argv = l_assign->argv;
691c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
6925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
6935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
69403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* function call */
69503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case CFUNC: {
6965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		volatile unsigned char old_xflag;
69703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		volatile uint32_t old_inuse;
69803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		const char * volatile old_kshname;
6995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(tp->flag & ISSET)) {
7015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			struct tbl *ftp;
7025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!tp->u.fpath) {
70403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				rv = (tp->u2.errnov == ENOENT) ? 127 : 126;
70503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				warningf(true, "%s: %s %s: %s", cp,
70603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    "can't find", "function definition file",
707c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    cstrerror(tp->u2.errnov));
7085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
7095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
710c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (include(tp->u.fpath, 0, NULL, false) < 0) {
71103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				warningf(true, "%s: %s %s %s: %s", cp,
71203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    "can't open", "function definition file",
713811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				    tp->u.fpath, cstrerror(errno));
7145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = 127;
7155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
7165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
7175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!(ftp = findfunc(cp, hash(cp), false)) ||
7185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    !(ftp->flag & ISSET)) {
71903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				warningf(true, "%s: %s %s", cp,
72003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    "function not defined by", tp->u.fpath);
7215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = 127;
7225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
7235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
7245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp = ftp;
7255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
7265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
72703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
72803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * ksh functions set $0 to function name, POSIX
72903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * functions leave $0 unchanged.
7305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
7315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		old_kshname = kshname;
7325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp->flag & FKSH)
7335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			kshname = ap[0];
7345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
7355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ap[0] = kshname;
7365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->loc->argv = ap;
7375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (i = 0; *ap++ != NULL; i++)
7385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			;
7395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->loc->argc = i - 1;
74003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
74103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * ksh-style functions handle getopts sanely,
7425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * Bourne/POSIX functions are insane...
7435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
7445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp->flag & FKSH) {
7455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			e->loc->flags |= BF_DOGETOPTS;
7465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			e->loc->getopts_state = user_opt;
7475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			getopts_reset(1);
7485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
7495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
750811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		old_xflag = Flag(FXTRACE) ? 1 : 0;
751811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace((Flag(FXTRACEREC) ? old_xflag : 0) |
752811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		    ((tp->flag & TRACE) ? 1 : 0), false);
7535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		old_inuse = tp->flag & FINUSE;
7545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp->flag |= FINUSE;
7555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		e->type = E_FUNC;
757c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (!(i = kshsetjmp(e->jbuf))) {
758c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			execute(tp->val.t, flags & XERROK, NULL);
7595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			i = LRETURN;
7605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
761811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
7625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		kshname = old_kshname;
763811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(old_xflag, false);
7645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp->flag = (tp->flag & ~FINUSE) | old_inuse;
765811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
76603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
76703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Were we deleted while executing? If so, free the
76803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * execution tree. TODO: Unfortunately, the table entry
76903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * is never re-used until the lookup table is expanded.
7705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
7715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
7725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (tp->flag & ALLOC) {
7735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->flag &= ~ALLOC;
7745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tfree(tp->val.t, tp->areap);
7755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
7765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag = 0;
7775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
7785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		switch (i) {
7795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LRETURN:
7805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LERROR:
781c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			rv = exstat & 0xFF;
7825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
7835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LINTR:
7845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LEXIT:
7855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LLEAVE:
7865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LSHELL:
7875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			quitenv(NULL);
7885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			unwind(i);
7895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* NOTREACHED */
7905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		default:
7915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			quitenv(NULL);
79203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			internal_errorf("%s %d", "CFUNC", i);
7935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
7945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
7955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
7965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
79703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* executable command */
79803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case CEXEC:
79903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* tracked alias */
80003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case CTALIAS:
8015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(tp->flag&ISSET)) {
80203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (tp->u2.errnov == ENOENT) {
8035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				rv = 127;
80403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				warningf(true, "%s: %s", cp, "not found");
80503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			} else {
80603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				rv = 126;
80703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				warningf(true, "%s: %s: %s", cp, "can't execute",
808c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    cstrerror(tp->u2.errnov));
8095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
8115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* set $_ to programme's full path */
8145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* setstr() can't fail here */
815427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes		setstr(typeset("_", LOCAL | EXPORT, 0, INTEGER, 0),
8165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    tp->val.s, KSH_RETURN_ERROR);
8175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (flags&XEXEC) {
8195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			j_exit();
8205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!(flags&XBGND)
8215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_UNEMPLOYED
8225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    || Flag(FMONITOR)
8235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
8245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    ) {
8255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG);
8265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG);
8275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* to fork we set up a TEXEC node and call execute */
8315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		texec.type = TEXEC;
83203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* for tprint */
83303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		texec.left = t;
8345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		texec.str = tp->val.s;
8355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		texec.args = ap;
8365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rv = exchild(&texec, flags, xerrok, -1);
8375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
8385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
8395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Leave:
8405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (flags & XEXEC) {
841c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		exstat = rv & 0xFF;
8425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		unwind(LLEAVE);
8435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
8445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rv);
8455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
8485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruscriptexec(struct op *tp, const char **ap)
8495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *sh;
8515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_SMALL
8525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	unsigned char *cp;
85303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* 64 == MAXINTERP in MirBSD <sys/param.h> */
85403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char buf[64];
8555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int fd;
8565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
8575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	union mksh_ccphack args, cap;
8585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sh = str_val(global("EXECSHELL"));
8605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (sh && *sh)
86103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		sh = search_path(sh, path, X_OK, NULL);
8625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!sh || !*sh)
8635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sh = MKSH_DEFAULT_EXECSHELL;
8645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*tp->args-- = tp->str;
8665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_SMALL
868427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes	if ((fd = open(tp->str, O_RDONLY | O_BINARY)) >= 0) {
8695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* read first MAXINTERP octets from file */
8705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (read(fd, buf, sizeof(buf)) <= 0)
8715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* read error -> no good */
8725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			buf[0] = '\0';
8735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(fd);
87403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
87503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* skip UTF-8 Byte Order Mark, if present */
8765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		cp = (unsigned char *)buf;
87703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((cp[0] == 0xEF) && (cp[1] == 0xBB) && (cp[2] == 0xBF))
87803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			cp += 3;
87903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* save begin of shebang for later */
88003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		fd = (char *)cp - buf;		/* either 0 or (if BOM) 3 */
88103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
88203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* scan for newline (or CR) or NUL _before_ end of buffer */
883427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes		while ((size_t)((char *)cp - buf) < sizeof(buf))
8845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (*cp == '\0' || *cp == '\n' || *cp == '\r') {
8855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*cp = '\0';
8865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
8875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else
8885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				++cp;
8895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* if the shebang line is longer than MAXINTERP, bail out */
890427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes		if ((size_t)((char *)cp - buf) >= sizeof(buf))
8915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto noshebang;
89203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
89303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* restore begin of shebang position (buf+0 or buf+3) */
89403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		cp = (unsigned char *)(buf + fd);
8955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* bail out if read error (above) or no shebang */
8965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((cp[0] != '#') || (cp[1] != '!'))
8975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto noshebang;
89803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
8995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		cp += 2;
9005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* skip whitespace before shell name */
9015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (*cp == ' ' || *cp == '\t')
9025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			++cp;
9035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* just whitespace on the line? */
9045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*cp == '\0')
9055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto noshebang;
9065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* no, we actually found an interpreter name */
9075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sh = (char *)cp;
9085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* look for end of shell/interpreter name */
9095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (*cp != ' ' && *cp != '\t' && *cp != '\0')
9105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			++cp;
9115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* any arguments? */
9125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*cp) {
9135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*cp++ = '\0';
9145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* skip spaces before arguments */
9155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (*cp == ' ' || *cp == '\t')
9165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				++cp;
9175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* pass it all in ONE argument (historic reasons) */
9185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (*cp)
9195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*tp->args-- = (char *)cp;
9205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
9215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru noshebang:
922427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes		if (buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' &&
923427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes		    buf[3] == 'F')
924427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes			errorf("%s: not executable: %d-bit ELF file", tp->str,
925427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes			    32 * ((uint8_t)buf[4]));
9265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		fd = buf[0] << 8 | buf[1];
9275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((fd == /* OMAGIC */ 0407) ||
9285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (fd == /* NMAGIC */ 0410) ||
9295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (fd == /* ZMAGIC */ 0413) ||
9305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (fd == /* QMAGIC */ 0314) ||
9315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (fd == /* ECOFF_I386 */ 0x4C01) ||
9325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (fd == /* ECOFF_M68K */ 0x0150 || fd == 0x5001) ||
9335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (fd == /* ECOFF_SH */   0x0500 || fd == 0x0005) ||
9345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (fd == /* "MZ" */ 0x4D5A) ||
9355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (fd == /* gzip */ 0x1F8B))
9365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			errorf("%s: not executable: magic %04X", tp->str, fd);
9375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
9385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
9395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	args.ro = tp->args;
9405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*args.ro = sh;
9415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	cap.ro = ap;
9435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	execve(args.rw[0], args.rw, cap.rw);
9445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* report both the programme that was run and the bogus interpreter */
946c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	errorf("%s: %s: %s", tp->str, sh, cstrerror(errno));
9475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
9505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querushcomexec(const char **wp)
9515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
9535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp = ktsearch(&builtins, *wp, hash(*wp));
955c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	return (call_builtin(tp, wp, "shcomexec"));
9565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
9595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Search function tables for a function. If create set, a table entry
9605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is created if none is found.
9615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
9625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct tbl *
9635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querufindfunc(const char *name, uint32_t h, bool create)
9645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct block *l;
9665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp = NULL;
9675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (l = e->loc; l; l = l->next) {
9695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = ktsearch(&l->funs, name, h);
9705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp)
9715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
9725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!l->next && create) {
9735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp = ktenter(&l->funs, name, h);
9745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag = DEFINED;
9755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->type = CFUNC;
9765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->val.t = NULL;
9775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
9785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
9795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
9805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (tp);
9815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
9845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * define function. Returns 1 if function is being undefined (t == 0) and
9855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * function did not exist, returns 0 otherwise.
9865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
9875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
9885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudefine(const char *name, struct op *t)
9895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
99003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	uint32_t nhash;
9915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
9925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool was_set = false;
9935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
99403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	nhash = hash(name);
99503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
99603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (t != NULL && !tobool(t->u.ksh_func)) {
99703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* drop same-name aliases for POSIX functions */
99803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((tp = ktsearch(&aliases, name, nhash)))
99903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ktdelete(tp);
100003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
100103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
100203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (/* CONSTCOND */ 1) {
100303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		tp = findfunc(name, nhash, true);
1004c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* because findfunc:create=true */
1005c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		mkssert(tp != NULL);
10065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp->flag & ISSET)
10085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			was_set = true;
100903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
101003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * If this function is currently being executed, we zap
101103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * this table entry so findfunc() won't see it
10125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
10135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp->flag & FINUSE) {
10145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->name[0] = '\0';
101503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* ensure it won't be found */
101603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			tp->flag &= ~DEFINED;
10175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag |= FDELETE;
10185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else
10195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
10205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (tp->flag & ALLOC) {
10235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp->flag &= ~(ISSET|ALLOC);
10245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tfree(tp->val.t, tp->areap);
10255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
102703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (t == NULL) {
102803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* undefine */
10295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ktdelete(tp);
10305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (was_set ? 0 : 1);
10315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp->val.t = tcopy(t->left, tp->areap);
10345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp->flag |= (ISSET|ALLOC);
10355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->u.ksh_func)
10365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp->flag |= FKSH;
10375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
10395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
10425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * add builtin
10435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
104403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraconst char *
10455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querubuiltin(const char *name, int (*func) (const char **))
10465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
1048811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	uint32_t flag = DEFINED;
10495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* see if any flags should be set for this builtin */
1051811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	while (1) {
105203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (*name == '=')
105303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* command does variable assignment */
10545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flag |= KEEPASN;
105503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		else if (*name == '*')
105603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* POSIX special builtin */
10575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flag |= SPEC_BI;
10585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
10595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
1060811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		name++;
10615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp = ktenter(&builtins, name, hash(name));
1064811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	tp->flag = flag;
10655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp->type = CSHELL;
10665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp->val.f = func;
106703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
106803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (name);
10695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
10725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * find command
10735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * either function, hashed command, or built-in (in that order)
10745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
10755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct tbl *
10765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querufindcom(const char *name, int flags)
10775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	static struct tbl temp;
10795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	uint32_t h = hash(name);
10805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp = NULL, *tbi;
108103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* insert if not found */
108203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	unsigned char insert = Flag(FTRACKALL);
108303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* for function autoloading */
108403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *fpath;
10855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	union mksh_cchack npath;
10865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (vstrchr(name, '/')) {
10885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		insert = 0;
10895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* prevent FPATH search below */
10905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags &= ~FC_FUNC;
10915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		goto Search;
10925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL;
109403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
109503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * POSIX says special builtins first, then functions, then
1096811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	 * regular builtins, then search path...
10975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
10985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
10995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = tbi;
11005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!tp && (flags & FC_FUNC)) {
11015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = findfunc(name, h, false);
11025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tp && !(tp->flag & ISSET)) {
11035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((fpath = str_val(global("FPATH"))) == null) {
11045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->u.fpath = NULL;
110503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				tp->u2.errnov = ENOENT;
11065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else
110703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				tp->u.fpath = search_path(name, fpath, R_OK,
110803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    &tp->u2.errnov);
11095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1111811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (!tp && (flags & FC_NORMBI) && tbi)
11125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = tbi;
11135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
11145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = ktsearch(&taliases, name, h);
111503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (tp && (tp->flag & ISSET) &&
111603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    ksh_access(tp->val.s, X_OK) != 0) {
11175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (tp->flag & ALLOC) {
11185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->flag &= ~ALLOC;
11195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				afree(tp->val.s, APERM);
11205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
11215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag &= ~ISSET;
11225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Search:
11265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET))) &&
11275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (flags & FC_PATH)) {
11285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!tp) {
11295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (insert && !(flags & FC_DEFPATH)) {
11305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp = ktenter(&taliases, name, h);
11315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->type = CTALIAS;
11325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else {
11335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp = &temp;
11345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->type = CEXEC;
11355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
113603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* make ~ISSET */
113703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			tp->flag = DEFINED;
11385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
113903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		npath.ro = search_path(name,
114003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    (flags & FC_DEFPATH) ? def_path : path,
114103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    X_OK, &tp->u2.errnov);
11425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (npath.ro) {
11435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			strdupx(tp->val.s, npath.ro, APERM);
11445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (npath.ro != name)
11455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				afree(npath.rw, ATEMP);
11465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag |= ISSET|ALLOC;
11475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if ((flags & FC_FUNC) &&
11485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (fpath = str_val(global("FPATH"))) != null &&
114903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    (npath.ro = search_path(name, fpath, R_OK,
115003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    &tp->u2.errnov)) != NULL) {
115103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
115203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * An undocumented feature of AT&T ksh is that
115303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * it searches FPATH if a command is not found,
115403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * even if the command hasn't been set up as an
115503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * autoloaded function (ie, no typeset -uf).
11565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
11575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp = &temp;
11585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->type = CFUNC;
115903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* make ~ISSET */
116003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			tp->flag = DEFINED;
11615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->u.fpath = npath.ro;
11625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (tp);
11655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * flush executable commands with relative paths
116903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * (just relative or all?)
11705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
11715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
117203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraflushcom(bool all)
11735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
11755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tstate ts;
11765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (ktwalk(&ts, &taliases); (tp = ktnext(&ts)) != NULL; )
11785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
11795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (tp->flag&ALLOC) {
11805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tp->flag &= ~(ALLOC|ISSET);
11815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				afree(tp->val.s, APERM);
11825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
11835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tp->flag &= ~ISSET;
11845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
118703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* check if path is something we want to find */
118803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int
118903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrasearch_access(const char *fn, int mode)
11905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
119103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct stat sb;
119203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
119303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (stat(fn, &sb) < 0)
119403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* file does not exist */
119503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (ENOENT);
119603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* LINTED use of access */
119703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (access(fn, mode) < 0)
119803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* file exists, but we can't access it */
119903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (errno);
120003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (mode == X_OK && (!S_ISREG(sb.st_mode) ||
120103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    !(sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
120203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* access(2) may say root can execute everything */
120303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (S_ISDIR(sb.st_mode) ? EISDIR : EACCES);
120403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (0);
12055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
12085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * search for command with PATH
12095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
12105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruconst char *
121103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrasearch_path(const char *name, const char *lpath,
121203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* R_OK or X_OK */
121303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    int mode,
121403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* set if candidate found, but not suitable */
121503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    int *errnop)
12165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
12175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *sp, *p;
12185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *xp;
12195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XString xs;
122003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t namelen;
122103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int ec = 0, ev;
12225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (vstrchr(name, '/')) {
122403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((ec = search_access(name, mode)) == 0) {
122503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra search_path_ok:
122603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (errnop)
122703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				*errnop = 0;
12285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (name);
122903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
123003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		goto search_path_err;
12315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
12325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	namelen = strlen(name) + 1;
12345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Xinit(xs, xp, 128, ATEMP);
12355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	sp = lpath;
12375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while (sp != NULL) {
12385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		xp = Xstring(xs, xp);
12395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(p = cstrchr(sp, ':')))
12405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p = sp + strlen(sp);
12415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (p != sp) {
12425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			XcheckN(xs, xp, p - sp);
12435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			memcpy(xp, sp, p - sp);
12445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			xp += p - sp;
12455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*xp++ = '/';
12465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
12475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sp = p;
12485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XcheckN(xs, xp, namelen);
12495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memcpy(xp, name, namelen);
125003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((ev = search_access(Xstring(xs, xp), mode)) == 0) {
125103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			name = Xclose(xs, xp + namelen);
125203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			goto search_path_ok;
125303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
125403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* accumulate non-ENOENT errors only */
125503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (ev != ENOENT && ec == 0)
125603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ec = ev;
12575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*sp++ == '\0')
12585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			sp = NULL;
12595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
12605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Xfree(xs, xp);
126103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra search_path_err:
126203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (errnop)
126303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		*errnop = ec ? ec : ENOENT;
12645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (NULL);
12655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
1268c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasercall_builtin(struct tbl *tp, const char **wp, const char *where)
12695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
12705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int rv;
12715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1272c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (!tp)
1273c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		internal_errorf("%s: %s", where, wp[0]);
12745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	builtin_argv0 = wp[0];
12755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	builtin_flag = tp->flag;
12765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf_reopen(1, SHF_WR, shl_stdout);
127703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	shl_stdout_ok = true;
12785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ksh_getopt_reset(&builtin_opt, GF_ERROR);
12795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	rv = (*tp->val.f)(wp);
12805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf_flush(shl_stdout);
128103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	shl_stdout_ok = false;
12825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	builtin_flag = 0;
12835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	builtin_argv0 = NULL;
12845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rv);
12855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
12885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * set up redirection, saving old fds in e->savefd
12895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
12905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
12915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruiosetup(struct ioword *iop, struct tbl *tp)
12925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
12935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int u = -1;
12945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *cp = iop->name;
12955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int iotype = iop->flag & IOTYPE;
1296c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	bool do_open = true, do_close = false;
1297c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int flags = 0;
12985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct ioword iotmp;
12995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct stat statb;
13005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (iotype != IOHERE)
13025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		cp = evalonestr(cp, DOTILDE|(Flag(FTALKING_I) ? DOGLOB : 0));
13035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Used for tracing and error messages to print expanded cp */
13055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	iotmp = *iop;
13065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	iotmp.name = (iotype == IOHERE) ? NULL : cp;
13075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	iotmp.flag |= IONAMEXP;
13085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1309811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (Flag(FXTRACE)) {
1310811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(2, false);
1311811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		fptreef(shl_xtrace, 0, "%R", &iotmp);
1312811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		change_xtrace(1, false);
1313811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	}
13145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (iotype) {
13165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IOREAD:
13175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags = O_RDONLY;
13185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
13195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IOCAT:
13215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags = O_WRONLY | O_APPEND | O_CREAT;
13225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
13235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IOWRITE:
13255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags = O_WRONLY | O_CREAT | O_TRUNC;
132603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
132703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * The stat() is here to allow redirections to
13285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * things like /dev/null without error.
13295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
13305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) &&
13315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
13325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			flags |= O_EXCL;
13335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
13345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IORDWR:
13365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		flags = O_RDWR | O_CREAT;
13375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
13385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IOHERE:
1340c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		do_open = false;
13415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* herein() returns -2 if error has been printed */
1342c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		u = herein(iop, NULL);
13435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* cp may have wrong name */
13445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
13455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IODUP: {
13475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		const char *emsg;
13485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1349c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		do_open = false;
13505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*cp == '-' && !cp[1]) {
135103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* prevent error return below */
135203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			u = 1009;
1353c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			do_close = true;
13545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if ((u = check_fd(cp,
13555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
13565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    &emsg)) < 0) {
1357811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			char *sp;
1358811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser
13595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			warningf(true, "%s: %s",
1360811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			    (sp = snptreef(NULL, 32, "%R", &iotmp)), emsg);
1361811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			afree(sp, ATEMP);
13625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
13635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
13645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (u == iop->unit)
136503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* "dup from" == "dup to" */
136603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			return (0);
13675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1368c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    }
13695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (do_open) {
13725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (Flag(FRESTRICTED) && (flags & O_CREAT)) {
137303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(true, "%s: %s", cp, "restricted");
13745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
13755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1376427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes		u = open(cp, flags | O_BINARY, 0666);
13775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (u < 0) {
13795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* herein() may already have printed message */
13805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (u == -1) {
13815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			u = errno;
138203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(true, "can't %s %s: %s",
13835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    iotype == IODUP ? "dup" :
13845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (iotype == IOREAD || iotype == IOHERE) ?
1385c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    "open" : "create", cp, cstrerror(u));
13865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
13875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
13885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Do not save if it has already been redirected (i.e. "cat >x >y"). */
13905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (e->savefd[iop->unit] == 0) {
13915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* If these are the same, it means unit was previously closed */
13925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (u == iop->unit)
13935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			e->savefd[iop->unit] = -1;
13945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
139503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
139603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * c_exec() assumes e->savefd[fd] set for any
13975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * redirections. Ask savefd() not to close iop->unit;
13985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * this allows error messages to be seen if iop->unit
13995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * is 2; also means we can't lose the fd (eg, both
14005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 * dup2 below and dup2 in restfd() failing).
14015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
14025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			e->savefd[iop->unit] = savefd(iop->unit);
14035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (do_close)
14065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(iop->unit);
14075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (u != iop->unit) {
14085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ksh_dup2(u, iop->unit, true) < 0) {
1409c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			int eno;
1410811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			char *sp;
14115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1412c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			eno = errno;
141303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(true, "%s %s %s",
141403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    "can't finish (dup) redirection",
1415811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			    (sp = snptreef(NULL, 32, "%R", &iotmp)),
1416c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    cstrerror(eno));
1417811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			afree(sp, ATEMP);
14185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (iotype != IODUP)
14195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				close(u);
14205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
14215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
14225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (iotype != IODUP)
14235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			close(u);
142403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
142503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Touching any co-process fd in an empty exec
14265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * causes the shell to close its copies
14275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
14285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
142903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (iop->flag & IORDUP)
143003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* possible exec <&p */
14315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				coproc_read_close(u);
143203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else
143303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* possible exec >&p */
14345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				coproc_write_close(u);
14355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
14365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
143703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (u == 2)
143803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* Clear any write errors */
14395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_reopen(2, SHF_WR, shl_out);
14405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
14415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
14425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
144403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Process here documents by providing the content, either as
144503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * result (globally allocated) string or in a temp file; if
144603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * unquoted, the string is expanded first.
14475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
14485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
144903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrahereinval(const char *content, int sub, char **resbuf, struct shf *shf)
145003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
1451c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	const char * volatile ccp = content;
145203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct source *s, *osource;
145303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
145403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	osource = source;
145503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	newenv(E_ERRH);
1456c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (kshsetjmp(e->jbuf)) {
145703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		source = osource;
145803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		quitenv(shf);
145903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to iosetup(): don't print error */
146003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (-2);
146103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
146203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (sub) {
146303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* do substitutions on the content of heredoc */
146403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		s = pushs(SSTRING, ATEMP);
1465c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		s->start = s->str = ccp;
146603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		source = s;
1467c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (yylex(sub) != LWORD)
146803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			internal_errorf("%s: %s", "herein", "yylex");
146903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		source = osource;
147003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		ccp = evalstr(yylval.cp, 0);
1471c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
147203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
147303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (resbuf == NULL)
147403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shf_puts(ccp, shf);
147503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	else
147603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		strdupx(*resbuf, ccp, APERM);
147703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
147803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	quitenv(NULL);
147903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (0);
148003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
148103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
148203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int
1483c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserherein(struct ioword *iop, char **resbuf)
14845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
148503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int fd = -1;
148603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct shf *shf;
14875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct temp *h;
14885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i;
14895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* ksh -c 'cat << EOF' can cause this... */
1491c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (iop->heredoc == NULL) {
149203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		warningf(true, "%s missing", "here document");
149303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to iosetup(): don't print error */
149403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (-2);
14955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1497c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* lexer substitution flags */
1498c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	i = (iop->flag & IOEVAL) ? (ONEWORD | HEREDOC) : 0;
1499c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
150003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* skip all the fd setup if we just want the value */
150103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (resbuf != NULL)
1502c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return (hereinval(iop->heredoc, i, resbuf, NULL));
150303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
150403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
150503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Create temp file to hold content (done before newenv
150603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * so temp doesn't get removed too soon).
15075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
15085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps);
1509427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes	if (!(shf = h->shf) || (fd = open(h->tffn, O_RDONLY | O_BINARY, 0)) < 0) {
151003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		i = errno;
15115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		warningf(true, "can't %s temporary file %s: %s",
1512c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    !shf ? "create" : "open", h->tffn, cstrerror(i));
15135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (shf)
15145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_close(shf);
151503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to iosetup(): don't print error */
151603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (-2);
15175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
15185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1519c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (hereinval(iop->heredoc, i, NULL, shf) == -2) {
15205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(fd);
152103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to iosetup(): don't print error */
152203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (-2);
15235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
15245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (shf_close(shf) == EOF) {
15265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = errno;
15275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(fd);
1528c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		warningf(true, "can't %s temporary file %s: %s",
1529c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    "write", h->tffn, cstrerror(i));
153003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to iosetup(): don't print error */
153103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (-2);
15325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
15335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (fd);
15355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
15365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
15385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	ksh special - the select command processing section
15395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	print the args in column form - assuming that we can
15405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
15415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *
15425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudo_selectargs(const char **ap, bool print_menu)
15435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
15445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	static const char *read_args[] = {
15455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		"read", "-r", "REPLY", NULL
15465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	};
15475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *s;
15485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i, argct;
15495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (argct = 0; ap[argct]; argct++)
15515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		;
155203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (/* CONSTCOND */ 1) {
155303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*-
155403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Menu is printed if
15555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 *	- this is the first time around the select loop
15565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 *	- the user enters a blank line
15575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 *	- the REPLY parameter is empty
15585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
15595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (print_menu || !*str_val(global("REPLY")))
15605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			pr_menu(ap);
15615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shellf("%s", str_val(global("PS3")));
1562c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (call_builtin(findcom("read", FC_BI), read_args, Tselect))
15635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (NULL);
15645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = str_val(global("REPLY"));
1565811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		if (*s && getn(s, &i))
15665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return ((i >= 1 && i <= argct) ? ap[i - 1] : null);
1567c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		print_menu = true;
15685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
15695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
15705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct select_menu_info {
15725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char * const *args;
15735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int num_width;
15745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
15755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* format a single select menu item */
15775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char *
1578c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserselect_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
15795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
15805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const struct select_menu_info *smi =
15815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (const struct select_menu_info *)arg;
15825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1583c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	shf_snprintf(buf, buflen, "%*u) %s",
15845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    smi->num_width, i + 1, smi->args[i]);
15855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (buf);
15865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
15875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
15895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	print a select style menu
15905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1591c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaservoid
15925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querupr_menu(const char * const *ap)
15935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
15945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct select_menu_info smi;
15955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char * const *pp;
159603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t acols = 0, aocts = 0, i;
1597c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	unsigned int n;
15985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
16005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * width/column calculations were done once and saved, but this
16015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * means select can't be used recursively so we re-calculate
16025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * each time (could save in a structure that is returned, but
16035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * it's probably not worth the bother)
16045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
16055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
16075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * get dimensions of the list
16085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
16095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (n = 0, pp = ap; *pp; n++, pp++) {
16105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = strlen(*pp);
16115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (i > aocts)
16125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			aocts = i;
16135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = utf_mbswidth(*pp);
16145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (i > acols)
16155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			acols = i;
16165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
16175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
16195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * we will print an index of the form "%d) " in front of
16205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * each entry, so get the maximum width of this
16215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
16225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (i = n, smi.num_width = 1; i >= 10; i /= 10)
16235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		smi.num_width++;
16245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	smi.args = ap;
16265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	print_columns(shl_out, n, select_fmt_entry, (void *)&smi,
16275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    smi.num_width + 2 + aocts, smi.num_width + 2 + acols,
16285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    true);
16295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
16305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char *
1632c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserplain_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
16335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
163403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	strlcpy(buf, ((const char * const *)arg)[i], buflen);
16355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (buf);
16365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
16375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1638c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaservoid
16395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querupr_list(char * const *ap)
16405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
164103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t acols = 0, aocts = 0, i;
1642c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	unsigned int n;
16435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char * const *pp;
16445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (n = 0, pp = ap; *pp; n++, pp++) {
16465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = strlen(*pp);
16475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (i > aocts)
16485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			aocts = i;
16495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = utf_mbswidth(*pp);
16505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (i > acols)
16515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			acols = i;
16525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
16535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	print_columns(shl_out, n, plain_fmt_entry, (const void *)ap,
16555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    aocts, acols, false);
16565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
16575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
16595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	[[ ... ]] evaluation routines
16605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
16615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
16635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Test if the current token is a whatever. Accepts the current token if
16645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * it is. Returns 0 if it is not, non-zero if it is (in the case of
16655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * TM_UNOP and TM_BINOP, the returned value is a Test_op).
16665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
16675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic Test_op
16685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbteste_isa(Test_env *te, Test_meta meta)
16695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
16705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Test_op ret = TO_NONOP;
1671427d76ccc44aea287b51b233f0254a6107b2b3d1Elliott Hughes	bool uqword;
16725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *p;
16735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!*te->pos.wp)
16755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (meta == TM_END ? TO_NONNULL : TO_NONOP);
16765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* unquoted word? */
16785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = *te->pos.wp; *p == CHAR; p += 2)
16795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		;
16805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	uqword = *p == EOS;
16815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (meta == TM_UNOP || meta == TM_BINOP) {
16835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (uqword) {
168403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* longer than the longest operator */
168503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			char buf[8];
16865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			char *q = buf;
168703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1688c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			p = *te->pos.wp;
1689c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			while (*p++ == CHAR &&
1690c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    (size_t)(q - buf) < sizeof(buf) - 1)
1691c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				*q++ = *p++;
16925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*q = '\0';
16935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ret = test_isop(meta, buf);
16945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
16955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (meta == TM_END)
16965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = TO_NONOP;
16975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else
16985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = (uqword && !strcmp(*te->pos.wp,
16995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    dbtest_tokens[(int)meta])) ? TO_NONNULL : TO_NONOP;
17005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Accept the token? */
17025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ret != TO_NONOP)
17035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		te->pos.wp++;
17045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (ret);
17065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
17075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *
17095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbteste_getopnd(Test_env *te, Test_op op, bool do_eval)
17105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
17115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *s = *te->pos.wp;
17125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!s)
17145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
17155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	te->pos.wp++;
17175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!do_eval)
17195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (null);
17205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (op == TO_STEQL || op == TO_STNEQ)
17225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = evalstr(s, DOTILDE | DOPAT);
17235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else
17245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = evalstr(s, DOTILDE);
17255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (s);
17275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
17285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
17295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
17305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbteste_error(Test_env *te, int offset, const char *msg)
17315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
17325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	te->flags |= TEF_ERROR;
17335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	internal_warningf("dbteste_error: %s (offset %d)", msg, offset);
17345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1735