diff options
Diffstat (limited to 'Src/exec.c')
| -rw-r--r-- | Src/exec.c | 264 |
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); |
