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