summaryrefslogtreecommitdiffstats
path: root/Src/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/exec.c')
-rw-r--r--Src/exec.c264
1 files changed, 164 insertions, 100 deletions
diff --git a/Src/exec.c b/Src/exec.c
index 2c730b910..a9ef66477 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -263,6 +263,11 @@ static int doneps4;
static char *STTYval;
static char *blank_env[] = { NULL };
+/* total allocated elements in zsh_eval_context array */
+static int zsh_eval_context_len;
+/* number of in-use elements in zsh_eval_context array */
+static int zsh_eval_context_alen;
+
/* Execution functions. */
static int (*execfuncs[WC_COUNT-WC_CURSH]) (Estate, int) = {
@@ -547,10 +552,11 @@ zexecve(char *pth, char **argv, char **newenvp)
for (t0 = 0; t0 != ct; t0++)
if (execvebuf[t0] == '\n')
break;
- if (t0 == ct)
+ if (t0 == ct) {
zerr("%s: bad interpreter: %s: %e", pth,
metafy(execvebuf + 2, -1, META_STATIC), eno);
- else {
+ _exit(126);
+ } else {
while (inblank(execvebuf[t0]))
execvebuf[t0--] = '\0';
for (ptr = execvebuf + 2; *ptr && *ptr == ' '; ptr++);
@@ -574,6 +580,7 @@ zexecve(char *pth, char **argv, char **newenvp)
}
zerr("%s: bad interpreter: %s: %e", pth,
metafy(ptr2, -1, META_STATIC), eno);
+ _exit(126);
} else if (*ptr) {
*ptr = '\0';
argv[-2] = ptr2;
@@ -693,7 +700,7 @@ search_defpath(char *cmd, char *pbuf, int plen)
{
char *ps = DEFAULT_PATH, *pe = NULL, *s;
- for (ps = DEFAULT_PATH; ps; ps = pe ? pe+1 : NULL) {
+ for (; ps; ps = pe ? pe+1 : NULL) {
pe = strchr(ps, ':');
if (*ps == '/') {
s = pbuf;
@@ -724,7 +731,7 @@ static void
execute(LinkList args, int flags, int defpath)
{
Cmdnam cn;
- char buf[MAXCMDLEN+1], buf2[MAXCMDLEN+1];
+ char buf[MAXCMDLEN], buf2[MAXCMDLEN];
char *s, *z, *arg0;
char **argv, **pp, **newenvp = NULL;
int eno = 0, ee;
@@ -748,10 +755,12 @@ execute(LinkList args, int flags, int defpath)
zsfree(s);
}
+ argv = makecline(args, flags & BINF_DASH);
+
/* If ARGV0 is in the commands environment, we use *
* that as argv[0] for this external command */
if ((z = zgetenv("ARGV0"))) {
- setdata(firstnode(args), (void *) ztrdup(z));
+ argv[0] = ztrdup(z);
/*
* Note we don't do anything with the parameter structure
* for ARGV0: that's OK since we're about to exec or exit
@@ -766,10 +775,9 @@ execute(LinkList args, int flags, int defpath)
/* Else if the pre-command `-' was given, we add `-' *
* to the front of argv[0] for this command. */
sprintf(buf2, "-%s", arg0);
- setdata(firstnode(args), (void *) ztrdup(buf2));
+ argv[0] = ztrdup(buf2);
}
- argv = makecline(args);
if (flags & BINF_CLEARENV)
newenvp = blank_env;
@@ -785,9 +793,9 @@ execute(LinkList args, int flags, int defpath)
}
#endif
child_unblock();
- if ((int) strlen(arg0) >= PATH_MAX) {
+ if ((int) ztrlen(arg0) >= PATH_MAX) {
zerr("command too long: %s", arg0);
- _exit(1);
+ _exit(127);
}
for (s = arg0; *s; s++)
if (*s == '/') {
@@ -803,10 +811,10 @@ execute(LinkList args, int flags, int defpath)
/* for command -p, search the default path */
if (defpath) {
- char pbuf[PATH_MAX+1];
+ char pbuf[MAXCMDLEN];
char *dptr;
- if (!search_defpath(arg0, pbuf, PATH_MAX)) {
+ if (!search_defpath(arg0, pbuf, MAXCMDLEN)) {
if (commandnotfound(arg0, args) == 0)
_realexit();
zerr("command not found: %s", arg0);
@@ -823,28 +831,43 @@ execute(LinkList args, int flags, int defpath)
} else {
if ((cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0))) {
- char nn[PATH_MAX+1], *dptr;
+ char nn[MAXCMDLEN], *dptr;
- if (cn->node.flags & HASHED)
- strcpy(nn, cn->u.cmd);
- else {
- for (pp = path; pp < cn->u.name; pp++)
+ if (cn->node.flags & HASHED) {
+ if (snprintf(nn, sizeof(nn), "%s", cn->u.cmd) >= (int)sizeof(nn) ||
+ ztrlen(nn) >= PATH_MAX)
+ {
+ zerr("command too long: %s", arg0);
+ _exit(127);
+ }
+ } else {
+ for (pp = path; pp < cn->u.name; pp++) {
if (!**pp || (**pp == '.' && (*pp)[1] == '\0')) {
ee = zexecve(arg0, argv, newenvp);
if (isgooderr(ee, *pp))
eno = ee;
} else if (**pp != '/') {
z = buf;
- strucpy(&z, *pp);
+ struncpy(&z, *pp, sizeof(buf) - 1);
*z++ = '/';
+ if ((z - buf) + strlen(arg0) >= sizeof(buf))
+ continue;
strcpy(z, arg0);
+ if (ztrlen(buf) >= PATH_MAX)
+ continue;
ee = zexecve(buf, argv, newenvp);
if (isgooderr(ee, *pp))
eno = ee;
}
- strcpy(nn, cn->u.name ? *(cn->u.name) : "");
- strcat(nn, "/");
- strcat(nn, cn->node.nam);
+ }
+ if (snprintf(nn, sizeof(nn), "%s/%s",
+ cn->u.name ? *(cn->u.name) : "",
+ cn->node.nam) >= (int)sizeof(nn) ||
+ ztrlen(nn) >= PATH_MAX)
+ {
+ eno = ENAMETOOLONG;
+ goto execute_skip_exec;
+ }
}
ee = zexecve(nn, argv, newenvp);
@@ -853,6 +876,7 @@ execute(LinkList args, int flags, int defpath)
if (isgooderr(ee, *nn ? nn : "/"))
eno = ee;
}
+execute_skip_exec:
for (pp = path; *pp; pp++)
if (!(*pp)[0] || ((*pp)[0] == '.' && !(*pp)[1])) {
ee = zexecve(arg0, argv, newenvp);
@@ -860,9 +884,13 @@ execute(LinkList args, int flags, int defpath)
eno = ee;
} else {
z = buf;
- strucpy(&z, *pp);
+ struncpy(&z, *pp, sizeof(buf) - 1);
*z++ = '/';
+ if ((z - buf) + strlen(arg0) >= sizeof(buf))
+ continue;
strcpy(z, arg0);
+ if (ztrlen(buf) >= PATH_MAX)
+ continue;
ee = zexecve(buf, argv, newenvp);
if (isgooderr(ee, *pp))
eno = ee;
@@ -908,9 +936,9 @@ findcmd(char *arg0, int docopy, int default_path)
return NULL;
}
cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0);
- if (!cn && isset(HASHCMDS) && !isrelative(arg0))
+ if (!cn && isset(HASHCMDS))
cn = hashcmd(arg0, path);
- if ((int) strlen(arg0) > PATH_MAX)
+ if ((int) ztrlen(arg0) >= PATH_MAX)
return NULL;
if ((s = strchr(arg0, '/'))) {
RET_IF_COM(arg0);
@@ -920,32 +948,42 @@ findcmd(char *arg0, int docopy, int default_path)
}
}
if (cn) {
- char nn[PATH_MAX+1];
+ char nn[MAXCMDLEN];
- if (cn->node.flags & HASHED)
- strcpy(nn, cn->u.cmd);
- else {
- for (pp = path; pp < cn->u.name; pp++)
+ if (cn->node.flags & HASHED) {
+ if (snprintf(nn, sizeof(nn), "%s", cn->u.cmd) >= (int)sizeof(nn)) {
+ nn[0] = '\0';
+ }
+ } else {
+ for (pp = path; pp < cn->u.name; pp++) {
if (**pp != '/') {
z = buf;
if (**pp) {
- strucpy(&z, *pp);
+ struncpy(&z, *pp, sizeof(buf) - 1);
*z++ = '/';
+ if ((z - buf) + strlen(arg0) >= sizeof(buf))
+ continue;
}
strcpy(z, arg0);
RET_IF_COM(buf);
}
- strcpy(nn, cn->u.name ? *(cn->u.name) : "");
- strcat(nn, "/");
- strcat(nn, cn->node.nam);
+ }
+ if (snprintf(nn, sizeof(nn), "%s/%s",
+ cn->u.name ? *(cn->u.name) : "",
+ cn->node.nam) >= (int)sizeof(nn))
+ {
+ nn[0] = '\0';
+ }
}
RET_IF_COM(nn);
}
for (pp = path; *pp; pp++) {
z = buf;
if (**pp) {
- strucpy(&z, *pp);
+ struncpy(&z, *pp, sizeof(buf) - 1);
*z++ = '/';
+ if ((z - buf) + strlen(arg0) >= sizeof(buf))
+ continue;
}
strcpy(z, arg0);
RET_IF_COM(buf);
@@ -975,14 +1013,16 @@ isreallycom(Cmdnam cn)
{
char fullnam[MAXCMDLEN];
- if (cn->node.flags & HASHED)
- strcpy(fullnam, cn->u.cmd);
- else if (!cn->u.name)
+ if (cn->node.flags & HASHED) {
+ if (snprintf(fullnam, sizeof(fullnam), "%s", cn->u.cmd)
+ >= (int)sizeof(fullnam))
+ return 0;
+ } else if (!cn->u.name) {
return 0;
- else {
- strcpy(fullnam, *(cn->u.name));
- strcat(fullnam, "/");
- strcat(fullnam, cn->node.nam);
+ } else {
+ if (snprintf(fullnam, sizeof(fullnam), "%s/%s",
+ *(cn->u.name), cn->node.nam) >= (int)sizeof(fullnam))
+ return 0;
}
return iscom(fullnam);
}
@@ -1011,17 +1051,17 @@ mod_export Cmdnam
hashcmd(char *arg0, char **pp)
{
Cmdnam cn;
- char *s, buf[PATH_MAX+1];
+ char *s, buf[MAXCMDLEN];
char **pq;
- if (*arg0 == '/')
+ if ((*arg0 == '/') || !strncmp(arg0, "./", 2) || !strncmp(arg0, "../", 3))
return NULL;
for (; *pp; pp++)
if (**pp == '/') {
s = buf;
- struncpy(&s, *pp, PATH_MAX);
+ struncpy(&s, *pp, sizeof(buf) - 1);
*s++ = '/';
- if ((s - buf) + strlen(arg0) >= PATH_MAX)
+ if ((s - buf) + strlen(arg0) >= sizeof(buf))
continue;
strcpy(s, arg0);
if (iscom(buf))
@@ -1241,30 +1281,44 @@ execstring(char *s, int dont_change_job, int exiting, char *context)
popheap();
}
+/* append a context to the zsh_eval_context array */
+
/**/
mod_export void
-execode(Eprog p, int dont_change_job, int exiting, char *context)
+zsh_eval_context_push(char *context)
{
- struct estate s;
- static int zsh_eval_context_len;
- int alen;
-
if (!zsh_eval_context_len) {
zsh_eval_context_len = 16;
- alen = 0;
+ zsh_eval_context_alen = 0;
zsh_eval_context = (char **)zalloc(zsh_eval_context_len *
sizeof(*zsh_eval_context));
- } else {
- alen = arrlen(zsh_eval_context);
- if (zsh_eval_context_len == alen + 1) {
- zsh_eval_context_len *= 2;
- zsh_eval_context = zrealloc(zsh_eval_context,
- zsh_eval_context_len *
- sizeof(*zsh_eval_context));
- }
+ } else if (zsh_eval_context_len == zsh_eval_context_alen + 1) {
+ zsh_eval_context_len *= 2;
+ zsh_eval_context = zrealloc(zsh_eval_context,
+ zsh_eval_context_len *
+ sizeof(*zsh_eval_context));
}
- zsh_eval_context[alen] = context;
- zsh_eval_context[alen+1] = NULL;
+ zsh_eval_context[zsh_eval_context_alen] = context;
+ zsh_eval_context[++zsh_eval_context_alen] = NULL;
+}
+
+/* remove the last context from the zsh_eval_context array */
+
+/**/
+mod_export void
+zsh_eval_context_pop(void)
+{
+ if (zsh_eval_context_alen)
+ zsh_eval_context[--zsh_eval_context_alen] = NULL;
+}
+
+/**/
+mod_export void
+execode(Eprog p, int dont_change_job, int exiting, char *context)
+{
+ struct estate s;
+
+ zsh_eval_context_push(context);
s.prog = p;
s.pc = p->prog;
@@ -1279,7 +1333,7 @@ execode(Eprog p, int dont_change_job, int exiting, char *context)
* zsh_eval_context may have been altered by a recursive
* call, but that's OK since we're using the global value.
*/
- zsh_eval_context[alen] = NULL;
+ zsh_eval_context_pop();
}
/* Execute a simplified command. This is used to execute things that
@@ -1500,9 +1554,9 @@ execlist(Estate state, int dont_change_job, int exiting)
case WC_SUBLIST_AND:
/* If the return code is non-zero, we skip pipelines until *
* we find a sublist followed by ORNEXT. */
- if ((ret = ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ?
+ if (((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ?
execsimple(state) :
- execpline(state, code, Z_SYNC, 0))) || breaks) {
+ execpline(state, code, Z_SYNC, 0)) || breaks) {
state->pc = next;
code = *state->pc++;
next = state->pc + WC_SUBLIST_SKIP(code);
@@ -1533,7 +1587,7 @@ execlist(Estate state, int dont_change_job, int exiting)
case WC_SUBLIST_OR:
/* If the return code is zero, we skip pipelines until *
* we find a sublist followed by ANDNEXT. */
- if (!(ret = ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ?
+ if (!(((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) ?
execsimple(state) :
execpline(state, code, Z_SYNC, 0))) || breaks) {
state->pc = next;
@@ -2047,7 +2101,7 @@ execpline2(Estate state, wordcode pcode,
/**/
static char **
-makecline(LinkList list)
+makecline(LinkList list, int dash)
{
LinkNode node;
char **argv, **ptr;
@@ -2060,6 +2114,7 @@ makecline(LinkList list)
if (!doneps4)
printprompt4();
+ if (dash) fputs("- ", xtrerr);
for (node = firstnode(list); node; incnode(node)) {
*ptr++ = (char *)getdata(node);
quotedzputs(getdata(node), xtrerr);
@@ -2689,11 +2744,8 @@ execsubst(LinkList strs)
{
if (strs) {
prefork(strs, esprefork, NULL);
- if (esglob && !errflag) {
- LinkList ostrs = strs;
+ if (esglob && !errflag)
globlist(strs, 0);
- strs = ostrs;
- }
}
}
@@ -3250,14 +3302,17 @@ execcmd_exec(Estate state, Execcmd_params eparams,
cflags |= BINF_DASH;
break;
default:
- zerr("unknown exec flag -%c", *cmdopt);
- lastval = 1;
- errflag |= ERRFLAG_ERROR;
- if (forked)
- _realexit();
- if (how & Z_TIMED)
- shelltime(&shti, &chti, &then, 1);
- return;
+ {
+ convchar_t opt = unmeta_one(cmdopt, NULL);
+ zerr("unknown exec flag -%c", opt);
+ lastval = 1;
+ errflag |= ERRFLAG_ERROR;
+ if (forked)
+ _realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
+ return;
+ }
}
}
if (!argnode)
@@ -3832,10 +3887,12 @@ execcmd_exec(Estate state, Execcmd_params eparams,
bad = 1;
}
if (!bad && fn->fd1 <= max_zsh_fd) {
- if (fn->fd1 >= 10 &&
- (fdtable[fn->fd1] & FDT_TYPE_MASK) ==
- FDT_INTERNAL)
- bad = 3;
+ int fdt = fdtable[fn->fd1] & FDT_TYPE_MASK;
+ if ((fn->fd1 >= 10 && fdt == FDT_INTERNAL) ||
+ fdt == FDT_MODULE)
+ {
+ bad = 3 + (fdt == FDT_MODULE);
+ }
}
}
}
@@ -3843,7 +3900,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
const char *bad_msg[] = {
"parameter %s does not contain a file descriptor",
"can't close file descriptor from readonly parameter %s",
- "file descriptor %d used by shell, not closed"
+ "file descriptor %d used by shell, not closed",
+ "file descriptor %d used by module, not closed",
};
if (bad > 2)
zwarn(bad_msg[bad-1], fn->fd1);
@@ -3894,6 +3952,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
*/
(fn->fd2 <= max_zsh_fd &&
((fdtable[fn->fd2] != FDT_UNUSED &&
+ fdtable[fn->fd2] != FDT_MODULE &&
fdtable[fn->fd2] != FDT_EXTERNAL) ||
fn->fd2 == coprocin ||
fn->fd2 == coprocout))) {
@@ -4414,14 +4473,16 @@ static void
save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p)
{
Param pm;
- char *s;
wordcode ac;
*restore_p = newlinklist();
*remove_p = newlinklist();
while (wc_code(ac = *pc) == WC_ASSIGN) {
- s = ecrawstr(state->prog, pc + 1, NULL);
+ char *s = ecrawstr(state->prog, pc + 1, NULL);
+ char *ss = itype_end(s, INAMESPC, 0);
+ int slen = *ss == '[' || *ss == Inbrack ? ss - s : strlen(s);
+ addlinknode(*remove_p, s = dupstring_wlen(s, slen));
if ((pm = (Param) paramtab->getnode(paramtab, s))) {
Param tpm = NULL;
if (pm->env)
@@ -4450,11 +4511,9 @@ save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p)
tpm->node.nam = pm->node.nam;
copyparam(tpm, pm, 1);
}
- addlinknode(*remove_p, dupstring(s));
if (tpm)
addlinknode(*restore_p, tpm);
- } else
- addlinknode(*remove_p, dupstring(s));
+ }
pc += (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR ?
3 : WC_ASSIGN_NUM(ac) + 2);
@@ -5240,7 +5299,7 @@ static int
execarith(Estate state, UNUSED(int do_exec))
{
char *e;
- mnumber val = zero_mnumber;
+ mnumber val;
int htok = 0;
if (isset(XTRACE)) {
@@ -6227,29 +6286,34 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name)
Eprog
getfpfunc(char *s, int *ksh, char **fdir, char **alt_path, int test_only)
{
- char **pp, buf[PATH_MAX+1];
+ char **pp, buf[PATH_MAX];
off_t len;
off_t rlen;
char *d;
Eprog r;
int fd;
+ char *su = unmeta(s);
+ if (su != s) su = dupstring(su);
pp = alt_path ? alt_path : fpath;
+ char *ppu = "";
for (; *pp; pp++) {
if (**pp) {
- if (snprintf(buf, PATH_MAX, "%s/%s", *pp, s) >= PATH_MAX)
+ ppu = unmeta(*pp);
+ if (ppu != *pp) ppu = dupstring(ppu);
+ if (snprintf(buf, PATH_MAX, "%s/%s", ppu, su) >= PATH_MAX)
continue;
- } else if (strlen(s) >= PATH_MAX) {
+ } else if (strlen(su) >= PATH_MAX) {
continue;
} else {
- strcpy(buf, s);
+ strcpy(buf, su);
+ ppu = "";
}
- if ((r = try_dump_file(*pp, s, buf, ksh, test_only))) {
+ if ((r = try_dump_file(ppu, s, buf, ksh, test_only))) {
if (fdir)
- *fdir = *pp;
+ *fdir = ppu;
return r;
}
- unmetafy(buf, NULL);
if (!access(buf, R_OK) && (fd = open(buf, O_RDONLY | O_NOCTTY)) != -1) {
struct stat st;
if (!fstat(fd, &st) && S_ISREG(st.st_mode) &&
@@ -6257,7 +6321,7 @@ getfpfunc(char *s, int *ksh, char **fdir, char **alt_path, int test_only)
if (test_only) {
close(fd);
if (fdir)
- *fdir = *pp;
+ *fdir = ppu;
return &dummy_eprog;
}
d = (char *) zalloc(len + 1);
@@ -6274,7 +6338,7 @@ getfpfunc(char *s, int *ksh, char **fdir, char **alt_path, int test_only)
scriptname = oldscriptname;
if (fdir)
- *fdir = *pp;
+ *fdir = ppu;
zfree(d, len + 1);
@@ -6383,7 +6447,7 @@ cancd(char *s)
char *t;
if (*s != '/') {
- char sbuf[PATH_MAX+1], **cp;
+ char sbuf[MAXCMDLEN], **cp;
if (cancd2(s))
return s;
@@ -6392,9 +6456,9 @@ cancd(char *s)
if (!nocdpath)
for (cp = cdpath; *cp; cp++) {
if (**cp) {
- if (snprintf(sbuf, PATH_MAX, "%s/%s", *cp, s) >= PATH_MAX)
+ if (snprintf(sbuf, sizeof(sbuf), "%s/%s", *cp, s) >= sizeof(sbuf))
continue;
- } else if (strlen(s) >= PATH_MAX) {
+ } else if (ztrlen(s) >= PATH_MAX) {
continue;
} else {
strcpy(sbuf, s);