diff options
Diffstat (limited to 'Src/exec.c')
-rw-r--r-- | Src/exec.c | 239 |
1 files changed, 177 insertions, 62 deletions
diff --git a/Src/exec.c b/Src/exec.c index d0fadd69a..6a8b35a36 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -59,7 +59,7 @@ mod_export int noerrs; /**/ int nohistsave; -/* error/break flag */ +/* error flag: bits from enum errflag_bits */ /**/ mod_export int errflag; @@ -217,7 +217,7 @@ parse_string(char *s, int reset_lineno) Eprog p; zlong oldlineno; - lexsave(); + zcontext_save(); inpush(s, INP_LINENO, NULL); strinbeg(0); oldlineno = lineno; @@ -229,7 +229,7 @@ parse_string(char *s, int reset_lineno) lastval = 1; strinend(); inpop(); - lexrestore(); + zcontext_restore(); return p; } @@ -250,6 +250,7 @@ zsetlimit(int limnum, char *nam) if (setrlimit(limnum, limits + limnum)) { if (nam) zwarnnam(nam, "setrlimit failed: %e", errno); + limits[limnum] = current_limits[limnum]; return -1; } current_limits[limnum] = limits[limnum]; @@ -1145,7 +1146,8 @@ execlist(Estate state, int dont_change_job, int exiting) Wordcode next; wordcode code; int ret, cj, csp, ltype; - int old_pline_level, old_list_pipe; + int old_pline_level, old_list_pipe, old_list_pipe_job; + char *old_list_pipe_text; zlong oldlineno; /* * ERREXIT only forces the shell to exit if the last command in a && @@ -1158,10 +1160,17 @@ execlist(Estate state, int dont_change_job, int exiting) cj = thisjob; old_pline_level = pline_level; old_list_pipe = list_pipe; + old_list_pipe_job = list_pipe_job; + if (*list_pipe_text) + old_list_pipe_text = ztrdup(list_pipe_text); + else + old_list_pipe_text = NULL; oldlineno = lineno; - if (sourcelevel && unset(SHINSTDIN)) - pline_level = list_pipe = 0; + if (sourcelevel && unset(SHINSTDIN)) { + pline_level = list_pipe = list_pipe_job = 0; + *list_pipe_text = '\0'; + } /* Loop over all sets of comands separated by newline, * * semi-colon or ampersand (`sublists'). */ @@ -1396,6 +1405,13 @@ sublist_done: } pline_level = old_pline_level; list_pipe = old_list_pipe; + list_pipe_job = old_list_pipe_job; + if (old_list_pipe_text) { + strcpy(list_pipe_text, old_list_pipe_text); + zsfree(old_list_pipe_text); + } else { + *list_pipe_text = '\0'; + } lineno = oldlineno; if (dont_change_job) thisjob = cj; @@ -1600,7 +1616,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) (killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1); list_pipe_pid = pid; list_pipe_start = bgtime; - nowait = errflag = 1; + nowait = 1; + errflag |= ERRFLAG_ERROR; breaks = loops; close(synch[1]); read_loop(synch[0], &dummy, 1); @@ -1633,7 +1650,10 @@ execpline(Estate state, wordcode slcode, int how, int last1) list_pipe_child = 1; opts[INTERACTIVE] = 0; if (errbrk_saved) { - errflag = prev_errflag; + /* + * Keep any user interrupt bit in errflag. + */ + errflag = prev_errflag | (errflag & ERRFLAG_INT); breaks = prev_breaks; } break; @@ -1718,12 +1738,14 @@ execpline2(Estate state, wordcode pcode, if (pipe(synch) < 0) { zerr("pipe failed: %e", errno); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if ((pid = zfork(&bgtime)) == -1) { close(synch[0]); close(synch[1]); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if (pid) { char dummy, *text; @@ -2242,8 +2264,16 @@ addvars(Estate state, Wordcode pc, int addflags) state->pc = opc; return; } - if (isset(GLOBASSIGN) || !isstr) + if (!isstr || (isset(GLOBASSIGN) && + haswilds((char *)getdata(firstnode(vl))))) { globlist(vl, 0); + /* Unset the parameter to force it to be recreated + * as either scalar or array depending on how many + * matches were found for the glob. + */ + if (isset(GLOBASSIGN)) + unsetparam(name); + } if (errflag) { state->pc = opc; return; @@ -2279,6 +2309,8 @@ addvars(Estate state, Wordcode pc, int addflags) } allexp = opts[ALLEXPORT]; opts[ALLEXPORT] = 1; + if (isset(KSHARRAYS)) + unsetparam(name); pm = assignsparam(name, val, myflags); opts[ALLEXPORT] = allexp; } else @@ -2290,13 +2322,13 @@ addvars(Estate state, Wordcode pc, int addflags) continue; } if (vl) { - ptr = arr = (char **) zalloc(sizeof(char **) * + ptr = arr = (char **) zalloc(sizeof(char *) * (countlinknodes(vl) + 1)); while (nonempty(vl)) *ptr++ = ztrdup((char *) ugetnode(vl)); } else - ptr = arr = (char **) zalloc(sizeof(char **)); + ptr = arr = (char **) zalloc(sizeof(char *)); *ptr = NULL; if (xtr) { @@ -2320,6 +2352,7 @@ addvars(Estate state, Wordcode pc, int addflags) void setunderscore(char *str) { + queue_signals(); if (str && *str) { int l = strlen(str) + 1, nl = (l + 31) & ~31; @@ -2337,6 +2370,7 @@ setunderscore(char *str) *zunderscore = '\0'; underscoreused = 1; } + unqueue_signals(); } /* These describe the type of expansions that need to be done on the words @@ -2551,7 +2585,8 @@ execcmd(Estate state, int input, int output, int how, int last1) while (next && *next == '-' && strlen(next) >= 2) { if (!firstnode(args)) { zerr("exec requires a command to execute"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } uremnode(args, firstnode(args)); @@ -2568,12 +2603,14 @@ execcmd(Estate state, int input, int output, int how, int last1) } else { if (!firstnode(args)) { zerr("exec requires a command to execute"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } if (!nextnode(firstnode(args))) { zerr("exec flag -a requires a parameter"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } exec_argv0 = (char *) @@ -2589,7 +2626,8 @@ execcmd(Estate state, int input, int output, int how, int last1) break; default: zerr("unknown exec flag -%c", *cmdopt); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } } @@ -2613,6 +2651,10 @@ execcmd(Estate state, int input, int output, int how, int last1) } } + /* if we get this far, it is OK to pay attention to lastval again */ + if (noerrexit == 2 && !is_shfunc) + noerrexit = 0; + /* Do prefork substitutions */ esprefork = (assign || isset(MAGICEQUALSUBST)) ? PREFORK_TYPESET : 0; if (args && htok) @@ -2652,7 +2694,8 @@ execcmd(Estate state, int input, int output, int how, int last1) } else if (!nullcmd || !*nullcmd || opts[CSHNULLCMD] || (cflags & BINF_PREFIX)) { zerr("redirection with no command"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) { if (!args) @@ -2682,7 +2725,7 @@ execcmd(Estate state, int input, int output, int how, int last1) if (varspc) addvars(state, varspc, 0); if (errflag) - lastval = errflag; + lastval = 1; else lastval = cmdoutval; if (isset(XTRACE)) { @@ -2758,9 +2801,14 @@ execcmd(Estate state, int input, int output, int how, int last1) else text = NULL; - /* Set up special parameter $_ */ - - setunderscore((args && nonempty(args)) ? ((char *) getdata(lastnode(args))) : ""); + /* + * Set up special parameter $_ + * For execfuncdef we may need to take account of an + * anonymous function with arguments. + */ + if (type != WC_FUNCDEF) + setunderscore((args && nonempty(args)) ? + ((char *) getdata(lastnode(args))) : ""); /* Warn about "rm *" */ if (type == WC_SIMPLE && interact && unset(RMSTARSILENT) && @@ -2786,7 +2834,7 @@ execcmd(Estate state, int input, int output, int how, int last1) } } if (!nextnode(firstnode(args))) - errflag = 1; + errflag |= ERRFLAG_ERROR; } if (type == WC_FUNCDEF) { @@ -2882,6 +2930,7 @@ execcmd(Estate state, int input, int output, int how, int last1) * is a directory we should AUTOCD to. */ if (!hn && trycd && (s = cancd(peekfirst(args)))) { peekfirst(args) = (void *) s; + pushnode(args, dupstring("--")); pushnode(args, dupstring("cd")); if ((hn = builtintab->getnode(builtintab, "cd"))) is_builtin = 1; @@ -2931,7 +2980,8 @@ execcmd(Estate state, int input, int output, int how, int last1) } else if ((pid = zfork(&bgtime)) == -1) { close(synch[0]); close(synch[1]); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto fatal; } if (pid) { @@ -2941,8 +2991,6 @@ execcmd(Estate state, int input, int output, int how, int last1) close(synch[0]); if (how & Z_ASYNC) { lastpid = (zlong) pid; - /* indicate it's possible to set status for lastpid */ - lastpid_status = -2L; } else if (!jobtab[thisjob].stty_in_env && varspc) { /* search for STTY=... */ Wordcode p = varspc; @@ -2996,6 +3044,15 @@ execcmd(Estate state, int input, int output, int how, int last1) * Note that any form of exec means that the subshell is fake * * (but we may be in a subshell already). */ is_exec = 1; + /* + * If we are in a subshell environment anyway, say we're forked, + * even if we're actually not forked because we know the + * subshell is exiting. This ensures SHLVL reflects the current + * shell, and also optimises out any save/restore we'd need to + * do if we were returning to the main shell. + */ + if (type == WC_SUBSH) + forked = 1; } if ((esglob = !(cflags & BINF_NOGLOB)) && args && htok) { @@ -3169,7 +3226,12 @@ execcmd(Estate state, int input, int output, int how, int last1) } if (fn->fd1 < 10) closemn(mfds, fn->fd1, REDIR_CLOSE); - if (!closed && zclose(fn->fd1) < 0) { + /* + * Only report failures to close file descriptors + * if they're under user control as we don't know + * what the previous status of others was. + */ + if (!closed && zclose(fn->fd1) < 0 && fn->varid) { zwarn("failed to close file descriptor %d: %e", fn->fd1, errno); } @@ -3259,6 +3321,20 @@ execcmd(Estate state, int input, int output, int how, int last1) closemn(mfds, i, REDIR_CLOSE); if (nullexec) { + /* + * If nullexec is 2, we have variables to add with the redirections + * in place. If nullexec is 1, we may have variables but they + * need the standard restore logic. + */ + if (varspc) { + LinkList restorelist = 0, removelist = 0; + if (!isset(POSIXBUILTINS) && nullexec != 2) + save_params(state, varspc, &restorelist, &removelist); + addvars(state, varspc, 0); + if (restorelist) + restore_params(restorelist, removelist); + } + lastval = errflag ? errflag : cmdoutval; if (nullexec == 1) { /* * If nullexec is 1 we specifically *don't* restore the original @@ -3269,13 +3345,6 @@ execcmd(Estate state, int input, int output, int how, int last1) zclose(save[i]); goto done; } - /* - * If nullexec is 2, we have variables to add with the redirections - * in place. - */ - if (varspc) - addvars(state, varspc, 0); - lastval = errflag ? errflag : cmdoutval; if (isset(XTRACE)) { fputc('\n', xtrerr); fflush(xtrerr); @@ -3315,14 +3384,14 @@ execcmd(Estate state, int input, int output, int how, int last1) * The copy uses the wordcode parsing area, so save and * restore state. */ - lexsave(); + zcontext_save(); redir_prog = eccopyredirs(&s); - lexrestore(); + zcontext_restore(); } else redir_prog = NULL; - + lastval = execfuncdef(state, redir_prog); - } + } else if (type >= WC_CURSH) { if (last1 == 1) do_exec = 1; @@ -3338,14 +3407,28 @@ execcmd(Estate state, int input, int output, int how, int last1) LinkList restorelist = 0, removelist = 0; /* builtin or shell function */ - if (!forked && ((cflags & BINF_COMMAND) || - (unset(POSIXBUILTINS) && !assign) || - (isset(POSIXBUILTINS) && !is_shfunc && - !(hn->flags & BINF_PSPECIAL)))) { - if (varspc) + if (!forked && varspc) { + int do_save = 0; + if (isset(POSIXBUILTINS)) { + /* + * If it's a function or special builtin --- save + * if it's got "command" in front. + * If it's a normal command --- save. + */ + if (is_shfunc || (hn->flags & BINF_PSPECIAL)) + do_save = (orig_cflags & BINF_COMMAND); + else + do_save = 1; + } else { + /* + * Save if it's got "command" in front or it's + * not a magic-equals assignment. + */ + if ((cflags & BINF_COMMAND) || !assign) + do_save = 1; + } + if (do_save) save_params(state, varspc, &restorelist, &removelist); - else - restorelist = removelist = NULL; } if (varspc) { /* Export this if the command is a shell function, @@ -3513,7 +3596,7 @@ execcmd(Estate state, int input, int output, int how, int last1) else exit(1); } - errflag = 1; + errflag |= ERRFLAG_ERROR; } } if (newxtrerr) { @@ -3738,17 +3821,20 @@ gethere(char **strp, int typ) *bptr++ = '\n'; } *t = '\0'; + s = buf; + buf = dupstring(buf); + zfree(s, bsiz); if (!qt) { int ef = errflag; - parsestr(buf); + parsestr(&buf); - if (!errflag) - errflag = ef; + if (!errflag) { + /* Retain any user interrupt error */ + errflag = ef | (errflag & ERRFLAG_INT); + } } - s = dupstring(buf); - zfree(buf, bsiz); - return s; + return buf; } /* open here string fd */ @@ -3832,13 +3918,13 @@ getoutput(char *cmd, int qt) return NULL; untokenize(s); if ((stream = open(unmeta(s), O_RDONLY | O_NOCTTY)) == -1) { - zerr("%e: %s", errno, s); - return NULL; + zwarn("%e: %s", errno, s); + return newlinklist(); } return readoutput(stream, qt); } if (mpipe(pipes) < 0) { - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdoutpid = 0; return NULL; } @@ -3848,7 +3934,7 @@ getoutput(char *cmd, int qt) /* fork error */ zclose(pipes[0]); zclose(pipes[1]); - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdoutpid = 0; child_unblock(); return NULL; @@ -4258,7 +4344,7 @@ execcond(Estate state, UNUSED(int do_exec)) * into a shell error. */ if (stat == 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdpop(); if (isset(XTRACE)) { fprintf(xtrerr, " ]]\n"); @@ -4298,7 +4384,7 @@ execarith(Estate state, UNUSED(int do_exec)) fflush(xtrerr); } if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; return 2; } /* should test for fabs(val.u.d) < epsilon? */ @@ -4332,7 +4418,7 @@ execfuncdef(Estate state, Eprog redir_prog) Shfunc shf; char *s = NULL; int signum, nprg, sbeg, nstrs, npats, len, plen, i, htok = 0, ret = 0; - int nfunc = 0; + int nfunc = 0, anon_func = 0; Wordcode beg = state->pc, end; Eprog prog; Patprog *pp; @@ -4414,10 +4500,12 @@ execfuncdef(Estate state, Eprog redir_prog) if (!names) { /* * Anonymous function, execute immediately. - * Function name is "(anon)", parameter list is empty. + * Function name is "(anon)". */ LinkList args; + anon_func = 1; + state->pc = end; end += *state->pc++; args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok); @@ -4425,11 +4513,19 @@ execfuncdef(Estate state, Eprog redir_prog) if (htok && args) { execsubst(args); if (errflag) { + freeeprog(shf->funcdef); + if (shf->redir) /* shouldn't be */ + freeeprog(shf->redir); + zsfree(shf->filename); + zfree(shf, sizeof(*shf)); state->pc = end; return 1; } } + setunderscore((args && nonempty(args)) ? + ((char *) getdata(lastnode(args))) : ""); + if (!args) args = newlinklist(); shf->node.nam = "(anon)"; @@ -4438,6 +4534,16 @@ execfuncdef(Estate state, Eprog redir_prog) execshfunc(shf, args); ret = lastval; + if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) && + lastval) { +#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) + fprintf(stderr, "zsh: exit %lld\n", lastval); +#else + fprintf(stderr, "zsh: exit %ld\n", (long)lastval); +#endif + fflush(stderr); + } + freeeprog(shf->funcdef); if (shf->redir) /* shouldn't be */ freeeprog(shf->redir); @@ -4450,6 +4556,7 @@ execfuncdef(Estate state, Eprog redir_prog) (signum = getsignum(s + 4)) != -1) { if (settrap(signum, NULL, ZSIG_FUNC)) { freeeprog(shf->funcdef); + zsfree(shf->filename); zfree(shf, sizeof(*shf)); state->pc = end; return 1; @@ -4464,6 +4571,8 @@ execfuncdef(Estate state, Eprog redir_prog) shfunctab->addnode(shfunctab, ztrdup(s), shf); } } + if (!anon_func) + setunderscore(""); if (!nfunc && redir_prog) { /* For completeness, shouldn't happen */ freeeprog(redir_prog); @@ -4547,6 +4656,7 @@ execshfunc(Shfunc shf, LinkList args) fputc('\n', xtrerr); fflush(xtrerr); } + queue_signals(); ocs = cmdstack; ocsp = cmdsp; cmdstack = (unsigned char *) zalloc(CMDSTACKSZ); @@ -4554,7 +4664,11 @@ execshfunc(Shfunc shf, LinkList args) if ((osfc = sfcontext) == SFC_NONE) sfcontext = SFC_DIRECT; xtrerr = stderr; + unqueue_signals(); + doshfunc(shf, args, 0); + + queue_signals(); sfcontext = osfc; free(cmdstack); cmdstack = ocs; @@ -4562,6 +4676,7 @@ execshfunc(Shfunc shf, LinkList args) if (!list_pipe) deletefilelist(last_file_list, 0); + unqueue_signals(); } /* @@ -4910,7 +5025,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) (name = fname)))) { zwarn("%s: function not defined by file", name); if (noreturnval) - errflag = 1; + errflag |= ERRFLAG_ERROR; else lastval = 1; goto doneshfunc; @@ -5243,7 +5358,7 @@ execsave(void) { struct execstack *es; - es = (struct execstack *) malloc(sizeof(struct execstack)); + es = (struct execstack *) zalloc(sizeof(struct execstack)); es->list_pipe_pid = list_pipe_pid; es->nowait = nowait; es->pline_level = pline_level; |