From a4020e10a33f3f78681a2e18fb7add56338d4e81 Mon Sep 17 00:00:00 2001 From: Jun-ichi Takimoto Date: Wed, 3 Feb 2016 01:24:56 +0900 Subject: 37868: add 'static' to file local variables --- Src/exec.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'Src/exec.c') diff --git a/Src/exec.c b/Src/exec.c index 352615c83..b60fc90bd 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4518,8 +4518,6 @@ spawnpipes(LinkList l, int nullexec) } } -extern int tracingcond; - /* evaluate a [[ ... ]] */ /**/ -- cgit v1.2.3 From f4dfca490cb6d4b4fc7c6b977db56ab0d718de21 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 8 Mar 2016 18:18:05 +0000 Subject: 38114: Fix hang using ^Z with command subst. In subshells started to perform substitutions disable signals that require interactive handling. --- ChangeLog | 5 +++++ Src/exec.c | 13 +++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 6c77de2c7..be61bd073 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-03-08 Peter Stephenson + + * 38114: Src/exec.c: In substitutions involving subshells, disable + signals that require interactive handling. + 2016-03-09 Jun-ichi Takimoto * unposted: .gitignore: update for 38108 diff --git a/Src/exec.c b/Src/exec.c index b60fc90bd..50eff72cb 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -994,9 +994,18 @@ entersubsh(int flags) if ((flags & ESUB_REVERTPGRP) && getpid() == mypgrp) release_pgrp(); shout = NULL; - if (!job_control_ok) { + if (flags & ESUB_NOMONITOR) { /* - * If this process is not goign to be doing job control, + * Allowing any form of interactive signalling here is + * actively harmful as we are in a context where there is no + * control over the process. + */ + signal_ignore(SIGTTOU); + signal_ignore(SIGTTIN); + signal_ignore(SIGTSTP); + } else if (!job_control_ok) { + /* + * If this process is not going to be doing job control, * we don't want to do special things with the corresponding * signals. If it is, we need to keep the special behaviour: * see note about attachtty() above. -- cgit v1.2.3 From 5ee05cf9353b36e2dbe4149717ec239d074d1f21 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Tue, 26 Apr 2016 10:40:56 -0700 Subject: 38350 (cf. Glenn Smith: 38348): Remove-all warning should warn about the root directory as well --- ChangeLog | 5 +++++ Src/exec.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 03eba5fcc..b8eba08f6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-04-26 Barton E. Schaefer + + * 38350 (cf. Glenn Smith: 38348): Src/exec.c: Remove-all warning + should warn about the root directory as well + 2016-04-23 Daniel Shahaf * 38316: Completion/Unix/Command/_git: _git-rebase: Complete diff --git a/Src/exec.c b/Src/exec.c index 50eff72cb..2dcd5bcf5 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -2902,11 +2902,11 @@ execcmd(Estate state, int input, int output, int how, int last1) if (s[0] == Star && !s[1]) { if (!checkrmall(pwd)) uremnode(args, node); - } else if (l > 2 && s[l - 2] == '/' && s[l - 1] == Star) { + } else if (l >= 2 && s[l - 2] == '/' && s[l - 1] == Star) { char t = s[l - 2]; s[l - 2] = 0; - if (!checkrmall(s)) + if (!checkrmall(*s ? s : "/")) uremnode(args, node); s[l - 2] = t; } -- cgit v1.2.3 From 7badf262c1a33c8c5f7ee8ccc152733fcb5a05f7 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Fri, 10 Jun 2016 17:37:02 +0000 Subject: 38653 + 38657: 'functions -T' tracing: recurse into anonymous functions. --- ChangeLog | 4 ++++ Doc/Zsh/builtins.yo | 3 ++- Src/exec.c | 12 +++++++++--- Test/E02xtrace.ztst | 17 +++++++++++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index b31543b4f..f6e70e50e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2016-06-13 Daniel Shahaf + * 38653 + 38657: Doc/Zsh/builtins.yo, Src/exec.c, + Test/E02xtrace.ztst: 'functions -T' tracing: recurse into + anonymous functions. + * 38651: Completion/Unix/Command/_git: Escape parameter arguments to _call_program. diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 1ca1f24a8..5c33cd1cf 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -2028,7 +2028,8 @@ The names refer to functions rather than parameters. No assignments can be made, and the only other valid flags are tt(-t), tt(-T), tt(-k), tt(-u), tt(-U) and tt(-z). The flag tt(-t) turns on execution tracing for this function; the flag tt(-T) does the same, but turns off tracing -on any function called from the present one, unless that function also +for any named (not anonymous) function called from the present one, +unless that function also has the tt(-t) or tt(-T) flag. The tt(-u) and tt(-U) flags cause the function to be marked for autoloading; tt(-U) also causes alias expansion to be suppressed when the function is loaded. See the diff --git a/Src/exec.c b/Src/exec.c index 2dcd5bcf5..515406f33 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4615,6 +4615,8 @@ exectime(Estate state, UNUSED(int do_exec)) /* Define a shell function */ +static const char *const ANONYMOUS_FUNCTION_NAME = "(anon)"; + /**/ static int execfuncdef(Estate state, Eprog redir_prog) @@ -4732,7 +4734,7 @@ execfuncdef(Estate state, Eprog redir_prog) if (!args) args = newlinklist(); - shf->node.nam = "(anon)"; + shf->node.nam = (char *) ANONYMOUS_FUNCTION_NAME; pushnode(args, shf->node.nam); execshfunc(shf, args); @@ -5165,8 +5167,12 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) if (flags & (PM_TAGGED|PM_TAGGED_LOCAL)) opts[XTRACE] = 1; - else if (oflags & PM_TAGGED_LOCAL) - opts[XTRACE] = 0; + else if (oflags & PM_TAGGED_LOCAL) { + if (shfunc->node.nam == ANONYMOUS_FUNCTION_NAME /* pointer comparison */) + flags |= PM_TAGGED_LOCAL; + else + opts[XTRACE] = 0; + } ooflags = oflags; /* * oflags is static, because we compare it on the next recursive diff --git a/Test/E02xtrace.ztst b/Test/E02xtrace.ztst index 093a587bd..6e425e703 100644 --- a/Test/E02xtrace.ztst +++ b/Test/E02xtrace.ztst @@ -127,3 +127,20 @@ ?+(eval):2> [[ 'f o' == f\ x* || 'b r' != z\ o && 'squashy sound' < 'squishy sound' ]] ?+(eval):3> [[ -e nonexistentfile || -z '' && -t 3 ]] ?+(eval):4> set +x + + # Part 1: Recurses into nested anonymous functions + fn() { + () { () { true } } + } + functions -T fn + fn + # Part 2: Doesn't recurse into named functions + gn() { true } + fn() { gn } + functions -T fn + fn +0:tracing recurses into anonymous functions +?+fn:1> '(anon)' +?+(anon):0> '(anon)' +?+(anon):0> true +?+fn:0> gn -- cgit v1.2.3 From f026a4dc12d93518fded8df4f14fb3161ab1db98 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 4 Aug 2016 15:53:27 +0000 Subject: 38991: Make 'whence -v autoloaded-function' shows the defining filename. This may also fix a problem whereby the %x prompt escape evaluated to a function name rather than a filename, since %x is also backed by scriptfilename. --- ChangeLog | 3 +++ Src/exec.c | 3 ++- Test/C04funcdef.ztst | 10 ++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 71d4052fb..dc06dbe50 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2016-08-05 Daniel Shahaf + * 38991: Src/exec.c, Test/C04funcdef.ztst: Make 'whence -v + autoloaded-function' shows the defining filename. + * 38990: Completion/Debian/Type/_debbugs_bugnumber: Track bts's data dir migration. diff --git a/Src/exec.c b/Src/exec.c index 515406f33..ea9214d04 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4915,7 +4915,8 @@ execautofn_basic(Estate state, UNUSED(int do_exec)) oldscriptname = scriptname; oldscriptfilename = scriptfilename; - scriptname = scriptfilename = dupstring(shf->node.nam); + scriptname = dupstring(shf->node.nam); + scriptfilename = dupstring(shf->filename); execode(shf->funcdef, 1, 0, "loadautofunc"); scriptname = oldscriptname; scriptfilename = oldscriptfilename; diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst index 496577f6c..9f15e04ff 100644 --- a/Test/C04funcdef.ztst +++ b/Test/C04funcdef.ztst @@ -321,6 +321,16 @@ > print oops was successfully autoloaded >} + ( + fpath=(.) + printf '%s\n' 'oops(){}' 'ninjas-earring(){}' 'oops "$@"' >oops + autoload oops + oops + whence -v oops + ) +0:whence -v of zsh-style autoload +>oops is a shell function from ./oops + %clean rm -f file.in file.out -- cgit v1.2.3 From b312abc93b3b8eae8feb4a9884b22f519a137c7f Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Fri, 26 Aug 2016 15:05:15 -0700 Subject: 39104: do not hash relative paths in findcmd() --- ChangeLog | 4 ++++ Src/exec.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index b85cc1f92..f8c6e907e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2016-08-26 Barton E. Schaefer + + * 39104: Src/exec.c: do not hash relative paths in findcmd() + 2016-08-25 Daniel Shahaf * 39102: Completion/Unix/Command/_git: __git_recent_branches: diff --git a/Src/exec.c b/Src/exec.c index ea9214d04..9b24d388e 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -772,7 +772,7 @@ findcmd(char *arg0, int docopy) Cmdnam cn; cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0); - if (!cn && isset(HASHCMDS)) + if (!cn && isset(HASHCMDS) && !isrelative(arg0)) cn = hashcmd(arg0, path); if ((int) strlen(arg0) > PATH_MAX) return NULL; -- cgit v1.2.3 From 8ce98c75f5330eecfa474e342146b8d057abcefc Mon Sep 17 00:00:00 2001 From: Stephane Chazelas Date: Tue, 30 Aug 2016 13:44:26 +0100 Subject: 39125: More care needed decrementing SHLVL on exec. Not needed in subshell. --- ChangeLog | 5 +++++ Src/exec.c | 11 +++++++---- Test/D04parameter.ztst | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 2f8f5b7a9..c1ef1044c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-08-31 Peter Stephenson + + * Stephane: 39125: Src/exec.c, Test/D04parameter.ztst: More care + decrementing SHLVL on exec; not needed in subshells. + 2016-08-31 Daniel Shahaf * 39122: Completion/Unix/Command/_git: __git_recent_branches: diff --git a/Src/exec.c b/Src/exec.c index 9b24d388e..2e251b939 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -3694,12 +3694,15 @@ execcmd(Estate state, int input, int output, int how, int last1) restore_params(restorelist, removelist); } else { - if (!forked) - setiparam("SHLVL", --shlvl); - if (do_exec) { + if (!subsh) { + /* for either implicit or explicit "exec", decrease $SHLVL + * as we're now done as a shell */ + if (!forked) + setiparam("SHLVL", --shlvl); + /* If we are exec'ing a command, and we are not * * in a subshell, then save the history file. */ - if (!subsh && isset(RCS) && interact && !nohistsave) + if (do_exec && isset(RCS) && interact && !nohistsave) savehistfile(NULL, 1, HFILE_USE_OPTIONS); } if (type == WC_SIMPLE || type == WC_TYPESET) { diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index 063007956..75ace5a9b 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -1716,6 +1716,24 @@ $ZTST_testdir/../Src/zsh -fc '(echo $SHLVL)' 0:SHLVL appears sensible when about to exit shell >2 +>2 + + SHLVL=1 + $ZTST_testdir/../Src/zsh -fc 'sh -c "echo \$SHLVL"' + $ZTST_testdir/../Src/zsh -fc '(sh -c "echo \$SHLVL")' + $ZTST_testdir/../Src/zsh -fc '( (sh -c "echo \$SHLVL"))' +0:SHLVL decremented upon implicit exec optimisation +>1 +>1 +>1 + + SHLVL=1 + $ZTST_testdir/../Src/zsh -fc '(sh -c "echo \$SHLVL"); exit' + $ZTST_testdir/../Src/zsh -fc '(exec sh -c "echo \$SHLVL"); exit' + $ZTST_testdir/../Src/zsh -fc '( (sh -c "echo \$SHLVL"); exit)' +0:SHLVL not decremented upon exec in subshells +>2 +>2 >2 # The following tests the return behaviour of parsestr/parsestrnoerr -- cgit v1.2.3 From 23c1c774b95861209fe97d1436b6563d5946f939 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 13 Sep 2016 09:37:49 +0100 Subject: 39305: Fix error handling after parse for here document. Keep the error status the same as before, but also retain the interrupt status if that was non-zero. --- ChangeLog | 5 +++++ Src/exec.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 6af28f976..145e9fbc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-09-13 Peter Stephenson + + * 39305: Src/exec.c: error handling on substitution for here + document was illogical. + 2016-09-12 Oliver Kiddle * 39295: Completion/Unix/Type/_remote_files: allow '--' to diff --git a/Src/exec.c b/Src/exec.c index 2e251b939..cfd633add 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4034,7 +4034,7 @@ gethere(char **strp, int typ) parsestr(&buf); - if (!errflag) { + if (!(errflag & ERRFLAG_ERROR)) { /* Retain any user interrupt error */ errflag = ef | (errflag & ERRFLAG_INT); } -- cgit v1.2.3 From 01ae64c0d74c17e36bfe6f52394a59754b8e8c92 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 15 Sep 2016 11:42:28 +0100 Subject: 39331: Reparent subjob on fork with exited superjob. Fixes case of v() { { vim - } always { true } } ls | v ^Z fg Tentative fix: still a race at exit where zsh forked by ^Z is stopped when restarted. --- ChangeLog | 7 +++++++ Src/exec.c | 19 ++++++++++++++++++- Src/jobs.c | 11 +++++++++-- Src/zsh.h | 5 ++++- 4 files changed, 38 insertions(+), 4 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 0d130b040..29796ed01 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2016-09-16 Peter Stephenson + + * 39331: Src/exec.c, Src/jobs.c, Src/zsh.h: Partially fix problem + occurring when a subjop in the RHS of a pipeline needs to be + picked up by a forked zsh after ^Z when the original superjob + (LHS of pipeline) has already exited. Still race-prone. + 2016-09-16 Daniel Shahaf * unposted: Completion/Unix/Command/_postfix: Correct quoting diff --git a/Src/exec.c b/Src/exec.c index cfd633add..21270c82d 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1570,6 +1570,7 @@ execpline(Estate state, wordcode slcode, int how, int last1) if (nowait) { if(!pline_level) { + int jobsub; struct process *pn, *qn; curjob = newjob; @@ -1582,6 +1583,20 @@ execpline(Estate state, wordcode slcode, int how, int last1) if (!jn->procs->next || lpforked == 2) { jn->gleader = list_pipe_pid; jn->stat |= STAT_SUBLEADER; + /* + * Pick up any subjob that's still lying around + * as it's now our responsibility. + * If we find it we're a SUPERJOB. + */ + for (jobsub = 1; jobsub <= maxjob; jobsub++) { + Job jnsub = jobtab + jobsub; + if (jnsub->stat & STAT_SUBJOB_ORPHANED) { + jn->other = jobsub; + jn->stat |= STAT_SUPERJOB; + jnsub->stat &= ~STAT_SUBJOB_ORPHANED; + jnsub->other = list_pipe_pid; + } + } } for (pn = jobtab[jn->other].procs; pn; pn = pn->next) if (WIFSTOPPED(pn->status)) @@ -1593,7 +1608,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) } jn->stat &= ~(STAT_DONE | STAT_NOPRINT); - jn->stat |= STAT_STOPPED | STAT_CHANGED | STAT_LOCKED; + jn->stat |= STAT_STOPPED | STAT_CHANGED | STAT_LOCKED | + STAT_INUSE; printjob(jn, !!isset(LONGLISTJOBS), 1); } else if (newjob != list_pipe_job) @@ -1669,6 +1685,7 @@ execpline(Estate state, wordcode slcode, int how, int last1) jobtab[list_pipe_job].stat |= STAT_SUPERJOB; jn->stat |= STAT_SUBJOB | STAT_NOPRINT; jn->other = pid; + jn->gleader = jobtab[list_pipe_job].gleader; } if ((list_pipe || last1) && hasprocs(list_pipe_job)) killpg(jobtab[list_pipe_job].gleader, SIGSTOP); diff --git a/Src/jobs.c b/Src/jobs.c index 6bc361609..9284c7124 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -128,7 +128,7 @@ makerunning(Job jn) Process pn; jn->stat &= ~STAT_STOPPED; - for (pn = jn->procs; pn; pn = pn->next) + for (pn = jn->procs; pn; pn = pn->next) { #if 0 if (WIFSTOPPED(pn->status) && (!(jn->stat & STAT_SUPERJOB) || pn->next)) @@ -136,6 +136,7 @@ makerunning(Job jn) #endif if (WIFSTOPPED(pn->status)) pn->status = SP_RUNNING; + } if (jn->stat & STAT_SUPERJOB) makerunning(jobtab + jn->other); @@ -236,7 +237,7 @@ handle_sub(int job, int fg) if ((sj->stat & STAT_DONE) || (!sj->procs && !sj->auxprocs)) { struct process *p; - for (p = sj->procs; p; p = p->next) + for (p = sj->procs; p; p = p->next) { if (WIFSIGNALED(p->status)) { if (jn->gleader != mypgrp && jn->procs->next) killpg(jn->gleader, WTERMSIG(p->status)); @@ -246,6 +247,7 @@ handle_sub(int job, int fg) kill(sj->other, WTERMSIG(p->status)); break; } + } if (!p) { int cp; @@ -1316,6 +1318,11 @@ deletejob(Job jn, int disowning) attachtty(mypgrp); adjustwinsize(0); } + if (jn->stat & STAT_SUPERJOB) { + Job jno = jobtab + jn->other; + if (jno->stat & STAT_SUBJOB) + jno->stat |= STAT_SUBJOB_ORPHANED; + } freejob(jn, 1); } diff --git a/Src/zsh.h b/Src/zsh.h index 2dc5e7e2a..bb8ce130c 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -983,7 +983,8 @@ struct jobfile { struct job { pid_t gleader; /* process group leader of this job */ - pid_t other; /* subjob id or subshell pid */ + pid_t other; /* subjob id (SUPERJOB) + * or subshell pid (SUBJOB) */ int stat; /* see STATs below */ char *pwd; /* current working dir of shell when * * this job was spawned */ @@ -1015,6 +1016,8 @@ struct job { #define STAT_SUBLEADER (0x2000) /* is super-job, but leader is sub-shell */ #define STAT_BUILTIN (0x4000) /* job at tail of pipeline is a builtin */ +#define STAT_SUBJOB_ORPHANED (0x8000) + /* STAT_SUBJOB with STAT_SUPERJOB exited */ #define SP_RUNNING -1 /* fake status for jobs currently running */ -- cgit v1.2.3 From 327f3dd3adfc8fdd6c356722d093a340b81190a7 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 16 Sep 2016 09:34:17 +0100 Subject: 39359: Fix remaining race with orphaned subjob. When shell is forked to run right hand side of pipieline it should use its own PID as process group if the left hand side of the pipeline has already exited. --- ChangeLog | 4 ++++ Src/exec.c | 44 +++++++++++++++++++++++++++++++++++++++++++- Src/jobs.c | 3 ++- Src/signals.c | 16 +++++++++++++--- 4 files changed, 62 insertions(+), 5 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 29796ed01..add2ad6a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2016-09-16 Peter Stephenson + * 39359: Src/exec.c, Src/jobs.c, Src/signals.c: Further fix on + top of 39331 for remaining race. Ensure process group of forked + superjob is sane. + * 39331: Src/exec.c, Src/jobs.c, Src/zsh.h: Partially fix problem occurring when a subjop in the RHS of a pipeline needs to be picked up by a forked zsh after ^Z when the original superjob diff --git a/Src/exec.c b/Src/exec.c index 21270c82d..0755d55cd 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1652,7 +1652,13 @@ execpline(Estate state, wordcode slcode, int how, int last1) int synch[2]; struct timeval bgtime; + /* + * A pipeline with the shell handling the right + * hand side was stopped. We'll fork to allow + * it to continue. + */ if (pipe(synch) < 0 || (pid = zfork(&bgtime)) == -1) { + /* Failure */ if (pid < 0) { close(synch[0]); close(synch[1]); @@ -1666,6 +1672,18 @@ execpline(Estate state, wordcode slcode, int how, int last1) thisjob = newjob; } else if (pid) { + /* + * Parent: job control is here. If the job + * started for the RHS of the pipeline is still + * around, then its a SUBJOB and the job for + * earlier parts of the pipeeline is its SUPERJOB. + * The newly forked shell isn't recorded as a + * separate job here, just as list_pipe_pid. + * If the superjob exits (it may already have + * done so, see child branch below), we'll use + * list_pipe_pid to form the basis of a + * replacement job --- see SUBLEADER code above. + */ char dummy; lpforked = @@ -1692,9 +1710,33 @@ execpline(Estate state, wordcode slcode, int how, int last1) break; } else { + Job pjn = jobtab + list_pipe_job; close(synch[0]); entersubsh(ESUB_ASYNC); - if (jobtab[list_pipe_job].procs) { + /* + * At this point, we used to attach this process + * to the process group of list_pipe_job (the + * new superjob) any time that was still available. + * That caused problems when the fork happened + * early enough that the subjob is in that + * process group, since then we will stop this + * job when we signal the subjob, and we have + * no way here to know that we shouldn't also + * send STOP to itself, resulting in two stops. + * So don't do that if the original + * list_pipe_job has exited. + * + * The choice here needs to match the assumption + * made when handling SUBLEADER above that the + * process group is our own PID. I'm not sure + * if there's a potential race for that. But + * setting up a new process group if the + * superjob is still functioning seems the wrong + * thing to do. + */ + if (pjn->procs && + (pjn->stat & STAT_INUSE) && + !(pjn->stat & STAT_DONE)) { if (setpgrp(0L, mypgrp = jobtab[list_pipe_job].gleader) == -1) { setpgrp(0L, mypgrp = getpid()); diff --git a/Src/jobs.c b/Src/jobs.c index 9284c7124..d1b98ac4d 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -232,11 +232,12 @@ super_job(int sub) static int handle_sub(int job, int fg) { + /* job: superjob; sj: subjob. */ Job jn = jobtab + job, sj = jobtab + jn->other; if ((sj->stat & STAT_DONE) || (!sj->procs && !sj->auxprocs)) { struct process *p; - + for (p = sj->procs; p; p = p->next) { if (WIFSIGNALED(p->status)) { if (jn->gleader != mypgrp && jn->procs->next) diff --git a/Src/signals.c b/Src/signals.c index 2eefc07de..30dde713f 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -723,7 +723,7 @@ killjb(Job jn, int sig) { Process pn; int err = 0; - + if (jobbing) { if (jn->stat & STAT_SUPERJOB) { if (sig == SIGCONT) { @@ -731,11 +731,21 @@ killjb(Job jn, int sig) if (killpg(pn->pid, sig) == -1) if (kill(pn->pid, sig) == -1 && errno != ESRCH) err = -1; - + + /* + * Note this does not kill the last process, + * which is assumed to be the one controlling the + * subjob, i.e. the forked zsh that was originally + * list_pipe_pid... + */ for (pn = jn->procs; pn->next; pn = pn->next) if (kill(pn->pid, sig) == -1 && errno != ESRCH) err = -1; + /* + * ...we only continue that once the external processes + * currently associated with the subjob are finished. + */ if (!jobtab[jn->other].procs && pn) if (kill(pn->pid, sig) == -1 && errno != ESRCH) err = -1; @@ -744,7 +754,7 @@ killjb(Job jn, int sig) } if (killpg(jobtab[jn->other].gleader, sig) == -1 && errno != ESRCH) err = -1; - + if (killpg(jn->gleader, sig) == -1 && errno != ESRCH) err = -1; -- cgit v1.2.3 From c355a5f41f4cd0fd3892aa8815aab08ac0a2f921 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 16 Sep 2016 21:55:55 +0100 Subject: 39362: another race with pipeline handling. When forking the shell to control the right hand side, the forked subshell now always starts its own process group, to avoid getting a spurious additional SIGSTOP. --- ChangeLog | 5 +++++ Src/exec.c | 34 +++++++++------------------------- 2 files changed, 14 insertions(+), 25 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index add2ad6a5..fa6d00a1c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-09-16 Peter Stephenson + + * 39362: Src/exec.c: forked zsh in pipeline handling always + starts a new process group, avoiding double STOP. + 2016-09-16 Peter Stephenson * 39359: Src/exec.c, Src/jobs.c, Src/signals.c: Further fix on diff --git a/Src/exec.c b/Src/exec.c index 0755d55cd..9a7234e5f 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1710,39 +1710,23 @@ execpline(Estate state, wordcode slcode, int how, int last1) break; } else { - Job pjn = jobtab + list_pipe_job; close(synch[0]); entersubsh(ESUB_ASYNC); /* * At this point, we used to attach this process * to the process group of list_pipe_job (the * new superjob) any time that was still available. - * That caused problems when the fork happened - * early enough that the subjob is in that - * process group, since then we will stop this - * job when we signal the subjob, and we have - * no way here to know that we shouldn't also - * send STOP to itself, resulting in two stops. - * So don't do that if the original - * list_pipe_job has exited. + * That caused problems in at least two + * cases because this forked shell was then + * suspended with the right hand side of the + * pipeline, and the SIGSTOP below suspended + * it a second time when it was continued. * - * The choice here needs to match the assumption - * made when handling SUBLEADER above that the - * process group is our own PID. I'm not sure - * if there's a potential race for that. But - * setting up a new process group if the - * superjob is still functioning seems the wrong - * thing to do. + * It's therefore not clear entirely why you'd ever + * do anything other than the following, but no + * doubt we'll find out... */ - if (pjn->procs && - (pjn->stat & STAT_INUSE) && - !(pjn->stat & STAT_DONE)) { - if (setpgrp(0L, mypgrp = jobtab[list_pipe_job].gleader) - == -1) { - setpgrp(0L, mypgrp = getpid()); - } - } else - setpgrp(0L, mypgrp = getpid()); + setpgrp(0L, mypgrp = getpid()); close(synch[1]); kill(getpid(), SIGSTOP); list_pipe = 0; -- cgit v1.2.3 From c8de0af35935602370cc79193d0e0d53971250d4 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Mon, 19 Sep 2016 00:25:13 -0700 Subject: 39381: handle save/restore of variable values when "typeset"-related reserved words are prefixed by an assignment --- ChangeLog | 5 +++++ Src/exec.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index e92c7b24d..f9592dd8b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-09-19 Barton E. Schaefer + + * 39381: Src/exec.c: handle save/restore of variable values when + "typeset"-related reserved words are prefixed by an assignment + 2016-09-19 Mikael Magnusson * 39351: Functions/Zle/bracketed-paste-url-magic: Handle magnet diff --git a/Src/exec.c b/Src/exec.c index 9a7234e5f..d924148d6 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -3543,7 +3543,7 @@ execcmd(Estate state, int input, int output, int how, int last1) * if it's got "command" in front. * If it's a normal command --- save. */ - if (is_shfunc || (hn->flags & BINF_PSPECIAL)) + if (is_shfunc || (hn->flags & (BINF_PSPECIAL|BINF_ASSIGN))) do_save = (orig_cflags & BINF_COMMAND); else do_save = 1; @@ -3552,7 +3552,7 @@ execcmd(Estate state, int input, int output, int how, int last1) * Save if it's got "command" in front or it's * not a magic-equals assignment. */ - if ((cflags & BINF_COMMAND) || !assign) + if ((cflags & (BINF_COMMAND|BINF_ASSIGN)) || !assign) do_save = 1; } if (do_save && varspc) -- cgit v1.2.3 From 759e5912fdb783e70b3e0d50fa0bc63e441a848b Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 25 Sep 2016 17:14:24 +0100 Subject: 39435: Further fix for pgrp of funny pipelines. Don't set gleader of SUBJOB at the point of creation if the SUPERJOB has no processes yet. --- ChangeLog | 5 +++++ Src/exec.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index c43272ecf..967c63170 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-09-25 Peter Stephenson + + * 39435: Src/exec.c: Don't set gleader of SUBJOB immediately if + SUPERJOB has no processes. + 2016-09-24 Daniel Shahaf * 39423: Completion/Zsh/Command/_zed: Support the '--' diff --git a/Src/exec.c b/Src/exec.c index d924148d6..a5086c33c 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1703,7 +1703,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) jobtab[list_pipe_job].stat |= STAT_SUPERJOB; jn->stat |= STAT_SUBJOB | STAT_NOPRINT; jn->other = pid; - jn->gleader = jobtab[list_pipe_job].gleader; + if (hasprocs(list_pipe_job)) + jn->gleader = jobtab[list_pipe_job].gleader; } if ((list_pipe || last1) && hasprocs(list_pipe_job)) killpg(jobtab[list_pipe_job].gleader, SIGSTOP); -- cgit v1.2.3 From e35dcae40fca1baebc202561040f5c6eec421613 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 25 Sep 2016 19:18:43 +0100 Subject: 39436: Pass on status of SIGINT better. Set lastval to 128 + SIGINT on interrupt. Don't execute builtin if already interrupted at that point. --- ChangeLog | 3 +++ Src/exec.c | 3 ++- Src/signals.c | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 967c63170..f2404aeba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2016-09-25 Peter Stephenson + * 39436: Src/exec.c, Src/signals.c: Don't execute builtin if + interrupted; set lastval to 128 + SIGINT on interrupt. + * 39435: Src/exec.c: Don't set gleader of SUBJOB immediately if SUPERJOB has no processes. diff --git a/Src/exec.c b/Src/exec.c index a5086c33c..4e8934061 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -3701,7 +3701,8 @@ execcmd(Estate state, int input, int output, int how, int last1) state->pc = opc; } dont_queue_signals(); - lastval = execbuiltin(args, assigns, (Builtin) hn); + if (!errflag) + lastval = execbuiltin(args, assigns, (Builtin) hn); if (do_save & BINF_COMMAND) errflag &= ~ERRFLAG_ERROR; restore_queue_signals(q); diff --git a/Src/signals.c b/Src/signals.c index 30dde713f..e2587dc72 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -646,6 +646,7 @@ zhandler(int sig) inerrflush(); check_cursh_sig(SIGINT); } + lastval = 128 + SIGINT; } break; -- cgit v1.2.3 From 3b6002e53d82746634536cd2fda8a9dd354aaf7e Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Tue, 27 Sep 2016 08:47:18 -0700 Subject: 39437: use list_pipe_pid in assignment for clarity --- ChangeLog | 6 +++++- Src/exec.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 890779515..dda4ec48d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2016-09-27 Barton E. Schaefer + + * 39437: Src/exec.c: use list_pipe_pid in assignment for clarity + 2016-09-26 Peter Stephenson * Martijn Dekker: 39448: Src/loop.c: reset REPLY in select when @@ -36,7 +40,7 @@ * unposted: Completion/Unix/Command/_gpg: Correct typo -2016-09-21 Barton E. Schaefer +2016-09-21 Barton E. Schaefer * unposted: Completion/Darwin/Type/_retrieve_mac_apps: add missing final colon in zstyle context lookup diff --git a/Src/exec.c b/Src/exec.c index 4e8934061..c27c41c1b 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1702,7 +1702,7 @@ execpline(Estate state, wordcode slcode, int how, int last1) jobtab[list_pipe_job].other = newjob; jobtab[list_pipe_job].stat |= STAT_SUPERJOB; jn->stat |= STAT_SUBJOB | STAT_NOPRINT; - jn->other = pid; + jn->other = list_pipe_pid; /* see zsh.h */ if (hasprocs(list_pipe_job)) jn->gleader = jobtab[list_pipe_job].gleader; } -- cgit v1.2.3 From 07c8fbe59632be71e4ad5bfafbf6aa4884cd04c4 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 29 Sep 2016 11:00:44 +0100 Subject: 34943: Fixes for "command" with multiple options. These need to combine properly, and alos "command -p" with either -v or -V needs to search for builtins and then using the default system path. --- ChangeLog | 7 +++ Src/builtin.c | 10 +++- Src/exec.c | 153 ++++++++++++++++++++++++++++++++++++++------------- Src/subst.c | 2 +- Test/A01grammar.ztst | 10 ++++ 5 files changed, 143 insertions(+), 39 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 5dc281a6f..35dfae0d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2016-09-29 Peter Stephenson + + * 39493: Src/builtin.c, Src/exec.c, Src/subst.c, + Test/A01grammar.ztst: make "command" with multiple options work + better and ensure "command -p" with "-v" or "-V" checks for a + builtin and then using the system default command path. + 2016-09-28 Peter Stephenson * Martijn Dekker: 39463: configure.ac: another way of getting diff --git a/Src/builtin.c b/Src/builtin.c index 248f929d7..c78fd9b3a 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3643,7 +3643,15 @@ bin_whence(char *nam, char **argv, Options ops, int func) returnval = 1; } popheap(); - } else if ((cnam = findcmd(*argv, 1))) { + } else if (func == BIN_COMMAND && + (hn = builtintab->getnode(builtintab, *argv))) { + /* + * Special case for "command -p[vV]" which needs to + * show a builtin in preference to an external command. + */ + builtintab->printnode(hn, printflags); + informed = 1; + } else if ((cnam = findcmd(*argv, 1, func == BIN_COMMAND))) { /* Found external command. */ if (wd) { printf("%s: command\n", *argv); diff --git a/Src/exec.c b/Src/exec.c index c27c41c1b..c79a27895 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -207,7 +207,7 @@ static int (*execfuncs[WC_COUNT-WC_CURSH]) _((Estate, int)) = { /* structure for command builtin for when it is used with -v or -V */ static struct builtin commandbn = - BUILTIN(0, 0, bin_whence, 0, -1, BIN_COMMAND, "vV", NULL); + BUILTIN("command", 0, bin_whence, 0, -1, BIN_COMMAND, "pvV", NULL); /* parse string into a list */ @@ -575,6 +575,41 @@ commandnotfound(char *arg0, LinkList args) return doshfunc(shf, args, 1); } +/* + * Search the default path for cmd. + * pbuf of length plen is the buffer to use. + * Return NULL if not found. + */ + +static char * +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) { + pe = strchr(ps, ':'); + if (*ps == '/') { + s = pbuf; + if (pe) { + if (pe - ps >= plen) + continue; + struncpy(&s, ps, pe-ps); + } else { + if (strlen(ps) >= plen) + continue; + strucpy(&s, ps); + } + *s++ = '/'; + if ((s - pbuf) + strlen(cmd) >= plen) + continue; + strucpy(&s, cmd); + if (iscom(pbuf)) + return pbuf; + } + } + return NULL; +} + /* execute an external command */ /**/ @@ -663,27 +698,10 @@ execute(LinkList args, int flags, int defpath) /* for command -p, search the default path */ if (defpath) { - char *s, pbuf[PATH_MAX]; - char *dptr, *pe, *ps = DEFAULT_PATH; - - for(;ps;ps = pe ? pe+1 : NULL) { - pe = strchr(ps, ':'); - if (*ps == '/') { - s = pbuf; - if (pe) - struncpy(&s, ps, pe-ps); - else - strucpy(&s, ps); - *s++ = '/'; - if ((s - pbuf) + strlen(arg0) >= PATH_MAX) - continue; - strucpy(&s, arg0); - if (iscom(pbuf)) - break; - } - } + char pbuf[PATH_MAX]; + char *dptr; - if (!ps) { + if (!search_defpath(arg0, pbuf, PATH_MAX)) { if (commandnotfound(arg0, args) == 0) _exit(0); zerr("command not found: %s", arg0); @@ -760,17 +778,26 @@ execute(LinkList args, int flags, int defpath) /* * Get the full pathname of an external command. * If the second argument is zero, return the first argument if found; - * if non-zero, return the path using heap memory. (RET_IF_COM(X), above). + * if non-zero, return the path using heap memory. (RET_IF_COM(X), + * above). + * If the third argument is non-zero, use the system default path + * instead of the current path. */ /**/ mod_export char * -findcmd(char *arg0, int docopy) +findcmd(char *arg0, int docopy, int default_path) { char **pp; char *z, *s, buf[MAXCMDLEN]; Cmdnam cn; + if (default_path) + { + if (search_defpath(arg0, buf, MAXCMDLEN)) + return docopy ? dupstring(buf) : arg0; + return NULL; + } cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0); if (!cn && isset(HASHCMDS) && !isrelative(arg0)) cn = hashcmd(arg0, path); @@ -2662,24 +2689,76 @@ execcmd(Estate state, int input, int output, int how, int last1) } checked = 0; if ((cflags & BINF_COMMAND) && nextnode(firstnode(args))) { - /* check for options to command builtin */ - char *next = (char *) getdata(nextnode(firstnode(args))); + /* + * Check for options to "command". + * If just -p, this is handled here: use the default + * path to execute. + * If -v or -V, possibly with -p, dispatch to bin_whence + * but with flag to indicate special handling of -p. + * Otherwise, just leave marked as BINF_COMMAND + * modifier with no additional action. + */ + LinkNode argnode = nextnode(firstnode(args)); + char *argdata = (char *) getdata(argnode); char *cmdopt; - if (next && *next == '-' && strlen(next) == 2 && - (cmdopt = strchr("pvV", next[1]))) - { - if (*cmdopt == 'p') { - uremnode(args, firstnode(args)); - use_defpath = 1; - if (nextnode(firstnode(args))) - next = (char *) getdata(nextnode(firstnode(args))); - } else { - hn = &commandbn.node; - is_builtin = 1; + int has_p = 0, has_vV = 0, has_other = 0; + while (*argdata == '-') { + /* Just to be definite, stop on single "-", too, */ + if (!argdata[1] || (argdata[1] == '-' && !argdata[2])) + break; + for (cmdopt = argdata+1; *cmdopt; cmdopt++) { + switch (*cmdopt) { + case 'p': + /* + * If we've got this multiple times (command + * -p -p) we'll treat the second -p as a + * command because we only remove one below. + * Don't think that's a big issue, and it's + * also traditional behaviour. + */ + has_p = 1; + break; + case 'v': + case 'V': + has_vV = 1; + break; + default: + has_other = 1; + break; + } + } + if (has_other) { + /* Don't know how to handle this, so don't */ + has_p = has_vV = 0; break; } + + argnode = nextnode(argnode); + if (!argnode) + break; + argdata = (char *) getdata(argnode); } - if (!strcmp(next, "--")) + if (has_vV) { + /* Leave everything alone, dispatch to whence */ + hn = &commandbn.node; + is_builtin = 1; + break; + } else if (has_p) { + /* Use default path; absorb command and option. */ + uremnode(args, firstnode(args)); + use_defpath = 1; + if ((argnode = nextnode(firstnode(args)))) + argdata = (char *) getdata(argnode); + } + /* + * Else just absorb command and any trailing + * end-of-options marker. This can only occur + * if we just had -p or something including more + * than just -p, -v and -V, in which case we behave + * as if this is command [non-option-stuff]. This + * isn't a good place for standard option handling. + */ + if (!strcmp(argdata, "--")) uremnode(args, firstnode(args)); } if ((cflags & BINF_EXEC) && nextnode(firstnode(args))) { diff --git a/Src/subst.c b/Src/subst.c index 92fde4598..ecd74879f 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -627,7 +627,7 @@ equalsubstr(char *str, int assign, int nomatch) cmdstr = dupstrpfx(str, pp-str); untokenize(cmdstr); remnulargs(cmdstr); - if (!(cnam = findcmd(cmdstr, 1))) { + if (!(cnam = findcmd(cmdstr, 1, 0))) { if (nomatch) zerr("%s not found", cmdstr); return NULL; diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst index 394480c19..921ff99a4 100644 --- a/Test/A01grammar.ztst +++ b/Test/A01grammar.ztst @@ -113,6 +113,16 @@ External command cat executed + command -pv cat + command -pv echo + command -p -V cat + command -p -V -- echo +0:command -p in combination +*>*/cat +>echo +>cat is /*/cat +>echo is a shell builtin + cd() { echo Not cd at all; } builtin cd . && unfunction cd 0:`builtin' precommand modifier -- cgit v1.2.3 From 6ce696f35236dc4c1b6249c6f1e7f64cc95a6046 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 29 Sep 2016 17:29:58 +0100 Subject: 39502: Fork for assignment in LHS of pipeline. foo=bar | stuff left the value of foo set to bar as we didn't realise we needed to fork. --- ChangeLog | 3 +++ Src/exec.c | 3 ++- Test/A01grammar.ztst | 7 +++++++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 883ff0230..ca9d23b57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2016-09-29 Peter Stephenson + * 39502: Src/exec.c, Test/A01grammar.ztst: need to fork for + assignment in LHS of pipeline. + * unposted: Src/Zle/compctl.c, Src/Zle/zle_tricky.c: update findcmd() call here, too. diff --git a/Src/exec.c b/Src/exec.c index c79a27895..e3915ddfe 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1844,7 +1844,8 @@ execpline2(Estate state, wordcode pcode, /* if we are doing "foo | bar" where foo is a current * * shell command, do foo in a subshell and do the * * rest of the pipeline in the current shell. */ - if (wc_code(code) >= WC_CURSH && (how & Z_SYNC)) { + if ((wc_code(code) >= WC_CURSH || wc_code(code) == WC_ASSIGN) + && (how & Z_SYNC)) { int synch[2]; struct timeval bgtime; diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst index 921ff99a4..0b1085c3e 100644 --- a/Test/A01grammar.ztst +++ b/Test/A01grammar.ztst @@ -756,3 +756,10 @@ > print Stuff here >} >Stuff here + + x=1 + x=2 | echo $x + echo $x +0:Assignment-only current shell commands in LHS of pipelin +>1 +>1 -- cgit v1.2.3 From e61ed2b80d60ca095006d7512f90c07e6c572ee0 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Thu, 29 Sep 2016 11:16:24 -0700 Subject: 39470: failure to open a supposedly unique temp file name should result in an error Also band-aid for signal-related race conditions in temp file name generation --- ChangeLog | 6 ++++++ Src/exec.c | 16 +++++++++++----- Src/utils.c | 4 ++++ 3 files changed, 21 insertions(+), 5 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index ca9d23b57..f93bdb10a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-09-29 Barton E. Schaefer + + * 39470: Src/exec.c, Src/utils.c: failure to open a supposedly + unique temp file name should result in an error; band-aid for + signal-related race conditions in temp file name generation + 2016-09-29 Peter Stephenson * 39502: Src/exec.c, Test/A01grammar.ztst: need to fork for diff --git a/Src/exec.c b/Src/exec.c index e3915ddfe..04868bd37 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4412,11 +4412,17 @@ getoutputfile(char *cmd, char **eptr) untokenize(s); } - addfilelist(nam, 0); + if (!s) /* Unclear why we need to do this before open() */ + child_block(); /* but it has been so for a long time: leave it */ - if (!s) - child_block(); - fd = open(nam, O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0600); + if ((fd = open(nam, O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0600)) < 0) { + zerr("process substitution failed: %e", errno); + free(nam); + if (!s) + child_unblock(); + return NULL; + } + addfilelist(nam, 0); if (s) { /* optimised here-string */ @@ -4427,7 +4433,7 @@ getoutputfile(char *cmd, char **eptr) return nam; } - if (fd < 0 || (cmdoutpid = pid = zfork(NULL)) == -1) { + if ((cmdoutpid = pid = zfork(NULL)) == -1) { /* fork or open error */ child_unblock(); return nam; diff --git a/Src/utils.c b/Src/utils.c index b434821e5..db4352908 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -2164,6 +2164,7 @@ gettempfile(const char *prefix, int use_heap, char **tempname) #if HAVE_MKSTEMP char *suffix = prefix ? ".XXXXXX" : "XXXXXX"; + queue_signals(); if (!prefix && !(prefix = getsparam("TMPPREFIX"))) prefix = DEFAULT_TMPPREFIX; if (use_heap) @@ -2180,6 +2181,7 @@ gettempfile(const char *prefix, int use_heap, char **tempname) #else int failures = 0; + queue_signals(); do { if (!(fn = gettempname(prefix, use_heap))) { fd = -1; @@ -2193,6 +2195,8 @@ gettempfile(const char *prefix, int use_heap, char **tempname) } while (errno == EEXIST && ++failures < 16); #endif *tempname = fn; + + unqueue_signals(); return fd; } -- cgit v1.2.3 From 736eb433bae71a162f8b5adbd42710bb718a3c91 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Thu, 29 Sep 2016 14:55:49 -0700 Subject: 39507: TMPSUFFIX for =(...) --- ChangeLog | 2 ++ Doc/Zsh/params.yo | 9 +++++++++ Src/exec.c | 9 +++++++++ 3 files changed, 20 insertions(+) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index f93bdb10a..3fe3165ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2016-09-29 Barton E. Schaefer + * 39507: Doc/Zsh/params.yo, Src/exec.c: TMPSUFFIX for =(...) + * 39470: Src/exec.c, Src/utils.c: failure to open a supposedly unique temp file name should result in an error; band-aid for signal-related race conditions in temp file name generation diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 03625ce24..c7d84b9a8 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -1547,6 +1547,15 @@ A pathname prefix which the shell will use for all temporary files. Note that this should include an initial part for the file name as well as any directory names. The default is `tt(/tmp/zsh)'. ) +vindex(TMPSUFFIX) +item(tt(TMPSUFFIX))( +A filename suffix which the shell will use for temporary files created +by process substitutions (e.g., `tt(=LPAR()var(list)RPAR())'). +Note that the value should include a leading dot `tt(.)' if intended +to be interpreted as a file extension. The default is not to append +any suffix, thus this parameter should be assigned only when needed +and then unset again. +) vindex(watch) vindex(WATCH) item(tt(watch) (tt(WATCH) ))( diff --git a/Src/exec.c b/Src/exec.c index 04868bd37..e253d7b9e 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -4421,6 +4421,15 @@ getoutputfile(char *cmd, char **eptr) if (!s) child_unblock(); return NULL; + } else { + char *suffix = getsparam("TMPSUFFIX"); + if (suffix && *suffix && !strstr(suffix, "/")) { + suffix = dyncat(nam, unmeta(suffix)); + if (link(nam, suffix) == 0) { + addfilelist(nam, 0); + nam = ztrdup(suffix); + } + } } addfilelist(nam, 0); -- cgit v1.2.3 From bb2bbcc944e5b2a089f27e9b988e1740a517cedd Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 30 Sep 2016 11:34:15 +0100 Subject: 39517: back off 39502 (WC_ASSIGN causes fork in pipe). This isn't a robust fix as WC_ASSIGNs simply precede the main wordcode. --- ChangeLog | 2 ++ Src/exec.c | 2 +- Test/A01grammar.ztst | 15 +++++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index d6db9d982..ce891fc6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2016-09-30 Peter Stephenson + * 39517: back off 39502, this isn't a robust fix. + * 39498: Src/parmas.c,Src/zsh.h: use PRIVILEGED option to decide on problematic parameter imports. diff --git a/Src/exec.c b/Src/exec.c index e253d7b9e..2714edbcb 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1844,7 +1844,7 @@ execpline2(Estate state, wordcode pcode, /* if we are doing "foo | bar" where foo is a current * * shell command, do foo in a subshell and do the * * rest of the pipeline in the current shell. */ - if ((wc_code(code) >= WC_CURSH || wc_code(code) == WC_ASSIGN) + if ((wc_code(code) >= WC_CURSH) && (how & Z_SYNC)) { int synch[2]; struct timeval bgtime; diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst index 0b1085c3e..1ad73c599 100644 --- a/Test/A01grammar.ztst +++ b/Test/A01grammar.ztst @@ -757,9 +757,12 @@ >} >Stuff here - x=1 - x=2 | echo $x - echo $x -0:Assignment-only current shell commands in LHS of pipelin ->1 ->1 +## This problem is hard to fix without significant changes to how +## the shell forks for a pipeline. +# +# x=1 +# x=2 | echo $x +# echo $x +# 0:Assignment-only current shell commands in LHS of pipelin +# >1 +# >1 -- cgit v1.2.3 From 6b2585147b842c69faecb136c17dbdda79b3e4b4 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 2 Oct 2016 19:16:03 +0100 Subject: 39540: "! command" should suppress ERR_EXIT and ERR_RETURN --- ChangeLog | 5 +++++ Src/exec.c | 8 ++++++-- Test/C03traps.ztst | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index b1b000025..1cda59e07 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-10-02 Peter Stephenson + + * 39540: Src/exec.c, Test/C03traps.ztst: "! command" should + suppress ERR_EXIT and ERR_RETURN. + 2016-09-30 Daniel Shahaf * 39495: Doc/Zsh/contrib.yo, Functions/Misc/add-zle-hook-widget: diff --git a/Src/exec.c b/Src/exec.c index 2714edbcb..906cf6cca 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1226,6 +1226,7 @@ execlist(Estate state, int dont_change_job, int exiting) } while (wc_code(code) == WC_LIST && !breaks && !retflag && !errflag) { int donedebug; + int this_noerrexit = 0; ltype = WC_LIST_TYPE(code); csp = cmdsp; @@ -1309,9 +1310,12 @@ execlist(Estate state, int dont_change_job, int exiting) goto sublist_done; } while (wc_code(code) == WC_SUBLIST) { + int isend = (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END); next = state->pc + WC_SUBLIST_SKIP(code); if (!oldnoerrexit) - noerrexit = (WC_SUBLIST_TYPE(code) != WC_SUBLIST_END); + noerrexit = !isend; + if ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT) && isend) + this_noerrexit = 1; switch (WC_SUBLIST_TYPE(code)) { case WC_SUBLIST_END: /* End of sublist; just execute, ignoring status. */ @@ -1427,7 +1431,7 @@ sublist_done: /* Check whether we are suppressing traps/errexit * * (typically in init scripts) and if we haven't * * already performed them for this sublist. */ - if (!noerrexit && !donetrap) { + if (!noerrexit && !this_noerrexit && !donetrap) { if (sigtrapped[SIGZERR] && lastval) { dotrap(SIGZERR); donetrap = 1; diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst index 83c05aa08..3a65b2876 100644 --- a/Test/C03traps.ztst +++ b/Test/C03traps.ztst @@ -519,6 +519,43 @@ >Yes F:Must be tested with a top-level script rather than source or function + fn() { + emulate -L zsh + setopt errreturn + print before + false + print after + } + fn +1:ERRRETURN, basic case +>before + + fn() { + emulate -L zsh + setopt errreturn + print before + ! true + ! false + print after + } + fn +0:ERRETURN with "!" +>before +>after + + fn() { + emulate -L zsh + setopt errreturn + print before + ! true + ! false + false + print after + } + fn +1:ERRETURN with "!" and a following false +>before + %clean rm -f TRAPEXIT -- cgit v1.2.3 From 36a11804b467d7553f8fdaed9320869d8d984f77 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 3 Oct 2016 09:59:01 +0100 Subject: 39521: Refactor start of execcmd(). By splitting into _analyse and _exec execpline2() has easier access to the state at the start of execution. Use this to ensure we fork if this is a builtin with no arguments. --- ChangeLog | 6 +++ Src/exec.c | 127 ++++++++++++++++++++++++++++++++------------------- Src/zsh.h | 16 +++++++ Test/A01grammar.ztst | 15 +++--- 4 files changed, 109 insertions(+), 55 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 1cda59e07..a1c4e60e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-10-03 Peter Stephenson + + * 39521: Src/exec.c, Src/zsh.h, Test/A01grammar.ztst: Refactor + start of execcmd(). This allows execpline2() easier access to + the state at the start of execuation. + 2016-10-02 Peter Stephenson * 39540: Src/exec.c, Test/C03traps.ztst: "! command" should diff --git a/Src/exec.c b/Src/exec.c index 906cf6cca..a4294288b 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1812,6 +1812,7 @@ execpline2(Estate state, wordcode pcode, { pid_t pid; int pipes[2]; + struct execcmd_params eparams; if (breaks || retflag) return; @@ -1829,17 +1830,16 @@ execpline2(Estate state, wordcode pcode, else list_pipe_text[0] = '\0'; } - if (WC_PIPE_TYPE(pcode) == WC_PIPE_END) - execcmd(state, input, output, how, last1 ? 1 : 2); - else { + if (WC_PIPE_TYPE(pcode) == WC_PIPE_END) { + execcmd_analyse(state, &eparams); + execcmd_exec(state, &eparams, input, output, how, last1 ? 1 : 2); + } else { int old_list_pipe = list_pipe; int subsh_close = -1; - Wordcode next = state->pc + (*state->pc), pc; - wordcode code; + Wordcode next = state->pc + (*state->pc), start_pc; - state->pc++; - for (pc = state->pc; wc_code(code = *pc) == WC_REDIR; - pc += WC_REDIR_WORDS(code)); + start_pc = ++state->pc; + execcmd_analyse(state, &eparams); if (mpipe(pipes) < 0) { /* FIXME */ @@ -1848,7 +1848,7 @@ execpline2(Estate state, wordcode pcode, /* if we are doing "foo | bar" where foo is a current * * shell command, do foo in a subshell and do the * * rest of the pipeline in the current shell. */ - if ((wc_code(code) >= WC_CURSH) + if ((eparams.type >= WC_CURSH || !eparams.args) && (how & Z_SYNC)) { int synch[2]; struct timeval bgtime; @@ -1867,7 +1867,7 @@ execpline2(Estate state, wordcode pcode, } else if (pid) { char dummy, *text; - text = getjobtext(state->prog, state->pc); + text = getjobtext(state->prog, start_pc); addproc(pid, text, 0, &bgtime); close(synch[1]); read_loop(synch[0], &dummy, 1); @@ -1878,14 +1878,14 @@ execpline2(Estate state, wordcode pcode, entersubsh(((how & Z_ASYNC) ? ESUB_ASYNC : 0) | ESUB_PGRP | ESUB_KEEPTRAP); close(synch[1]); - execcmd(state, input, pipes[1], how, 1); + execcmd_exec(state, &eparams, input, pipes[1], how, 1); _exit(lastval); } } else { /* otherwise just do the pipeline normally. */ addfilelist(NULL, pipes[0]); subsh_close = pipes[0]; - execcmd(state, input, pipes[1], how, 0); + execcmd_exec(state, &eparams, input, pipes[1], how, 0); } zclose(pipes[1]); state->pc = next; @@ -2541,55 +2541,51 @@ resolvebuiltin(const char *cmdarg, HashNode hn) return hn; } +/* + * We are about to execute a command at the lowest level of the + * hierarchy. Analyse the parameters from the wordcode. + */ + /**/ static void -execcmd(Estate state, int input, int output, int how, int last1) +execcmd_analyse(Estate state, Execcmd_params eparams) { - HashNode hn = NULL; - LinkList args, filelist = NULL; - LinkNode node; - Redir fn; - struct multio *mfds[10]; - char *text; - int save[10]; - int fil, dfil, is_cursh, type, do_exec = 0, redir_err = 0, i, htok = 0; - int nullexec = 0, assign = 0, forked = 0, postassigns = 0; - int is_shfunc = 0, is_builtin = 0, is_exec = 0, use_defpath = 0; - /* Various flags to the command. */ - int cflags = 0, orig_cflags = 0, checked = 0, oautocont = -1; - LinkList redir; wordcode code; - Wordcode beg = state->pc, varspc, assignspc = (Wordcode)0; - FILE *oxtrerr = xtrerr, *newxtrerr = NULL; + int i; - doneps4 = 0; - redir = (wc_code(*state->pc) == WC_REDIR ? ecgetredirs(state) : NULL); + eparams->beg = state->pc; + eparams->redir = + (wc_code(*state->pc) == WC_REDIR ? ecgetredirs(state) : NULL); if (wc_code(*state->pc) == WC_ASSIGN) { cmdoutval = 0; - varspc = state->pc; + eparams->varspc = state->pc; while (wc_code((code = *state->pc)) == WC_ASSIGN) state->pc += (WC_ASSIGN_TYPE(code) == WC_ASSIGN_SCALAR ? 3 : WC_ASSIGN_NUM(code) + 2); } else - varspc = NULL; + eparams->varspc = NULL; code = *state->pc++; - type = wc_code(code); + eparams->type = wc_code(code); + eparams->postassigns = 0; /* It would be nice if we could use EC_DUPTOK instead of EC_DUP here. * But for that we would need to check/change all builtins so that * they don't modify their argument strings. */ - switch (type) { + switch (eparams->type) { case WC_SIMPLE: - args = ecgetlist(state, WC_SIMPLE_ARGC(code), EC_DUP, &htok); + eparams->args = ecgetlist(state, WC_SIMPLE_ARGC(code), EC_DUP, + &eparams->htok); + eparams->assignspc = NULL; break; case WC_TYPESET: - args = ecgetlist(state, WC_TYPESET_ARGC(code), EC_DUP, &htok); - postassigns = *state->pc++; - assignspc = state->pc; - for (i = 0; i < postassigns; i++) { + eparams->args = ecgetlist(state, WC_TYPESET_ARGC(code), EC_DUP, + &eparams->htok); + eparams->postassigns = *state->pc++; + eparams->assignspc = state->pc; + for (i = 0; i < eparams->postassigns; i++) { code = *state->pc; DPUTS(wc_code(code) != WC_ASSIGN, "BUG: miscounted typeset assignments"); @@ -2599,8 +2595,45 @@ execcmd(Estate state, int input, int output, int how, int last1) break; default: - args = NULL; + eparams->args = NULL; + eparams->assignspc = NULL; + eparams->htok = 0; + break; } +} + +/* + * Execute a command at the lowest level of the hierarchy. + */ + +/**/ +static void +execcmd_exec(Estate state, Execcmd_params eparams, + int input, int output, int how, int last1) +{ + HashNode hn = NULL; + LinkList filelist = NULL; + LinkNode node; + Redir fn; + struct multio *mfds[10]; + char *text; + int save[10]; + int fil, dfil, is_cursh, do_exec = 0, redir_err = 0, i; + int nullexec = 0, assign = 0, forked = 0; + int is_shfunc = 0, is_builtin = 0, is_exec = 0, use_defpath = 0; + /* Various flags to the command. */ + int cflags = 0, orig_cflags = 0, checked = 0, oautocont = -1; + FILE *oxtrerr = xtrerr, *newxtrerr = NULL; + /* + * Retrieve parameters for quick reference (they are unique + * to us so we can modify the structure if we want). + */ + LinkList args = eparams->args; + LinkList redir = eparams->redir; + Wordcode varspc = eparams->varspc; + int type = eparams->type; + + doneps4 = 0; /* * If assignment but no command get the status from variable @@ -2858,7 +2891,7 @@ execcmd(Estate state, int input, int output, int how, int last1) /* Do prefork substitutions */ esprefork = (assign || isset(MAGICEQUALSUBST)) ? PREFORK_TYPESET : 0; - if (args && htok) + if (args && eparams->htok) prefork(args, esprefork, NULL); if (type == WC_SIMPLE || type == WC_TYPESET) { @@ -3003,7 +3036,7 @@ execcmd(Estate state, int input, int output, int how, int last1) /* Get the text associated with this command. */ if ((how & Z_ASYNC) || (!sfcontext && !sourcelevel && (jobbing || (how & Z_TIMED)))) - text = getjobtext(state->prog, beg); + text = getjobtext(state->prog, eparams->beg); else text = NULL; @@ -3262,7 +3295,7 @@ execcmd(Estate state, int input, int output, int how, int last1) forked = 1; } - if ((esglob = !(cflags & BINF_NOGLOB)) && args && htok) { + if ((esglob = !(cflags & BINF_NOGLOB)) && args && eparams->htok) { LinkList oargs = args; globlist(args, 0); args = oargs; @@ -3576,7 +3609,7 @@ execcmd(Estate state, int input, int output, int how, int last1) } if (type == WC_FUNCDEF) { Eprog redir_prog; - if (!redir && wc_code(*beg) == WC_REDIR) { + if (!redir && wc_code(*eparams->beg) == WC_REDIR) { /* * We're not using a redirection from the currently * parsed environment, which is what we'd do for an @@ -3586,7 +3619,7 @@ execcmd(Estate state, int input, int output, int how, int last1) struct estate s; s.prog = state->prog; - s.pc = beg; + s.pc = eparams->beg; s.strs = state->prog->strs; /* @@ -3670,13 +3703,15 @@ execcmd(Estate state, int input, int output, int how, int last1) } else { /* It's a builtin */ LinkList assigns = (LinkList)0; + int postassigns = eparams->postassigns; if (forked) closem(FDT_INTERNAL); if (postassigns) { Wordcode opc = state->pc; - state->pc = assignspc; + state->pc = eparams->assignspc; assigns = newlinklist(); while (postassigns--) { + int htok; wordcode ac = *state->pc++; char *name = ecgetstr(state, EC_DUPTOK, &htok); Asgment asg; diff --git a/Src/zsh.h b/Src/zsh.h index 79747d624..a5d4455e3 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -489,6 +489,7 @@ typedef struct complist *Complist; typedef struct conddef *Conddef; typedef struct dirsav *Dirsav; typedef struct emulation_options *Emulation_options; +typedef struct execcmd_params *Execcmd_params; typedef struct features *Features; typedef struct feature_enables *Feature_enables; typedef struct funcstack *Funcstack; @@ -1391,6 +1392,21 @@ struct builtin { */ #define BINF_ASSIGN (1<<19) +/** + * Parameters passed to execcmd(). + * These are not opaque --- they are also used by the pipeline manager. + */ +struct execcmd_params { + LinkList args; /* All command prefixes, arguments & options */ + LinkList redir; /* Redirections */ + Wordcode beg; /* The code at the start of the command */ + Wordcode varspc; /* The code for assignment parsed as such */ + Wordcode assignspc; /* The code for assignment parsed as typeset */ + int type; /* The WC_* type of the command */ + int postassigns; /* The number of assignspc assiguments */ + int htok; /* tokens in parameter list */ +}; + struct module { struct hashnode node; union { diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst index 1ad73c599..0b1085c3e 100644 --- a/Test/A01grammar.ztst +++ b/Test/A01grammar.ztst @@ -757,12 +757,9 @@ >} >Stuff here -## This problem is hard to fix without significant changes to how -## the shell forks for a pipeline. -# -# x=1 -# x=2 | echo $x -# echo $x -# 0:Assignment-only current shell commands in LHS of pipelin -# >1 -# >1 + x=1 + x=2 | echo $x + echo $x +0:Assignment-only current shell commands in LHS of pipelin +>1 +>1 -- cgit v1.2.3 From 4ab3fcc90d928d200f9e70c81189079c3316b42d Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 3 Oct 2016 13:43:20 +0100 Subject: 39545: Add some missing unqueue_signals(). All of these are added simply to fit existing logic in other branches. --- ChangeLog | 5 +++++ Src/Zle/computil.c | 1 + Src/Zle/zle_main.c | 1 + Src/builtin.c | 3 +++ Src/exec.c | 3 +++ Src/hist.c | 1 + Src/init.c | 4 +++- Src/mem.c | 8 ++++++-- Src/module.c | 1 + Src/params.c | 2 ++ Src/prompt.c | 4 +++- 11 files changed, 29 insertions(+), 4 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index a1c4e60e3..a68dfaf59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2016-10-03 Peter Stephenson + * 39545: Src/builtin.c, Src/exec.c, Src/hist.c, Src/init.c, + Src/mem.c, Src/module.c, Src/params.c, Src/prompt.c, + Src/Zle/computil.c, Src/Zle/zle_main.c: Add some missing + unqueue_signals(). + * 39521: Src/exec.c, Src/zsh.h, Test/A01grammar.ztst: Refactor start of execcmd(). This allows execpline2() easier access to the state at the start of execuation. diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index 27b78cd61..e9bad1cab 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -4865,6 +4865,7 @@ bin_compfiles(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } queue_signals(); if (!(tmp = getaparam(args[1]))) { + unqueue_signals(); zwarnnam(nam, "unknown parameter: %s", args[1]); return 0; } diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 0bdd82ba4..0b3b1fcf4 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1631,6 +1631,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func)) return 1; } else if (v) { if (*s) { + unqueue_signals(); zwarnnam(name, "not an identifier: `%s'", args[0]); return 1; } diff --git a/Src/builtin.c b/Src/builtin.c index 60dc07f25..a274ff791 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1489,6 +1489,7 @@ bin_fc(char *nam, char **argv, Options ops, int func) } if (zleactive) { + unqueue_signals(); zwarnnam(nam, "no interactive history within ZLE"); return 1; } @@ -2808,6 +2809,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) return 0; } if (off & PM_TIED) { + unqueue_signals(); zerrnam(name, "use unset to remove tied variables"); return 1; } @@ -3138,6 +3140,7 @@ bin_functions(char *name, char **argv, Options ops, int func) queue_signals(); for (q = mathfuncs; q; q = q->next) { if (!strcmp(q->name, funcname)) { + unqueue_signals(); zwarnnam(name, "-M %s: function already exists", funcname); zsfree(p->name); diff --git a/Src/exec.c b/Src/exec.c index a4294288b..9890286b2 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1795,6 +1795,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) deletejob(jn, 0); thisjob = pj; } + else + unqueue_signals(); if ((slflags & WC_SUBLIST_NOT) && !errflag) lastval = !lastval; } @@ -5556,6 +5558,7 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) if (!cont) { if (ou) zfree(ou, ouu); + unqueue_signals(); return; } wrap = wrap->next; diff --git a/Src/hist.c b/Src/hist.c index 5fc40bd67..eebd7dcde 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -653,6 +653,7 @@ histsubchar(int c) (c == '}' || c == ';' || c == '\'' || c == '"' || c == '`')) { /* Neither event nor word designator, no expansion */ safeinungetc(c); + unqueue_signals(); return bangchar; } *ptr = 0; diff --git a/Src/init.c b/Src/init.c index 3dea179b9..c12043b88 100644 --- a/Src/init.c +++ b/Src/init.c @@ -1442,8 +1442,10 @@ sourcehome(char *s) queue_signals(); if (EMULATION(EMULATE_SH|EMULATE_KSH) || !(h = getsparam_u("ZDOTDIR"))) { h = home; - if (!h) + if (!h) { + unqueue_signals(); return; + } } { diff --git a/Src/mem.c b/Src/mem.c index 021dad573..db311efbd 100644 --- a/Src/mem.c +++ b/Src/mem.c @@ -903,11 +903,15 @@ memory_validate(Heapid heap_id) queue_signals(); for (h = heaps; h; h = h->next) { - if (h->heap_id == heap_id) + if (h->heap_id == heap_id) { + unqueue_signals(); return 0; + } for (hs = heaps->sp; hs; hs = hs->next) { - if (hs->heap_id == heap_id) + if (hs->heap_id == heap_id) { + unqueue_signals(); return 0; + } } } diff --git a/Src/module.c b/Src/module.c index 46a7d7746..41f142adb 100644 --- a/Src/module.c +++ b/Src/module.c @@ -2242,6 +2242,7 @@ load_module(char const *name, Feature_enables enablesarr, int silent) return 0; } if (m->node.flags & MOD_BUSY) { + unqueue_signals(); zerr("circular dependencies for module ;%s", name); return 1; } diff --git a/Src/params.c b/Src/params.c index e11510246..1418021aa 100644 --- a/Src/params.c +++ b/Src/params.c @@ -2803,6 +2803,7 @@ assignsparam(char *s, char *val, int flags) zerr("read-only variable: %s", v->pm->node.nam); *ss = '['; zsfree(val); + unqueue_signals(); return NULL; } flags &= ~ASSPM_WARN_CREATE; @@ -3117,6 +3118,7 @@ setnparam(char *s, mnumber val) if (!(v = getvalue(&vbuf, &t, 1))) { DPUTS(!v, "BUG: value not found for new parameter"); /* errflag |= ERRFLAG_ERROR; */ + unqueue_signals(); return NULL; } if (!was_unset && isset(WARNCREATEGLOBAL) && locallevel > forklevel) diff --git a/Src/prompt.c b/Src/prompt.c index d4f389809..ee77c8bc8 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -491,8 +491,10 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep) if (!arg) arg++; queue_signals(); - if (!(hostnam = getsparam("HOST"))) + if (!(hostnam = getsparam("HOST"))) { + unqueue_signals(); break; + } if (arg < 0) { for (ss = hostnam + strlen(hostnam); ss > hostnam; ss--) if (ss[-1] == '.' && !++arg) -- cgit v1.2.3 From dc517212caf3a8263cea9587bc6e96f7ff129b59 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 5 Oct 2016 12:14:43 +0100 Subject: 39566: Improve usefulness of command_not_found_handler. Don't behave as if command not found if return status is non-zero as this may simply be the return status of the replacement command. Let the function report a command not found instead. --- Doc/Zsh/exec.yo | 15 ++++++++------- README | 9 +++++++++ Src/exec.c | 13 ++++++++----- Test/C04funcdef.ztst | 5 ++--- 4 files changed, 27 insertions(+), 15 deletions(-) (limited to 'Src/exec.c') diff --git a/Doc/Zsh/exec.yo b/Doc/Zsh/exec.yo index 30e4a61a2..5f79967de 100644 --- a/Doc/Zsh/exec.yo +++ b/Doc/Zsh/exec.yo @@ -28,10 +28,11 @@ not handle this executable format in the kernel. If no external command is found but a function tt(command_not_found_handler) exists the shell executes this function with all -command line arguments. The function should return status zero if it -successfully handled the command, or non-zero status if it failed. -In the latter case the standard handling is applied: `command not -found' is printed to standard error and the shell exits with status 127. -Note that the handler is executed in a subshell forked to execute -an external command, hence changes to directories, shell parameters, -etc. have no effect on the main shell. +command line arguments. The return status of the function becomes the +status of the command. If the function wishes to mimic the +behaviour of the shell when the command is not found, it should +print the message `tt(command not found:) var(cmd)' to standard error +and return status 127. Note that the handler is executed in a +subshell forked to execute an external command, hence changes to +directories, shell parameters, etc. have no effect on the main shell. + diff --git a/README b/README index d146d4b16..ed2183d8d 100644 --- a/README +++ b/README @@ -101,6 +101,15 @@ For the more common case of non-repeatable options that take a single argument, completion functions now have to unescape not only colons but also backslashes when obtaining the option's argument from $opt_args. +6) Previously, if the function command_not_found_handler was run +in place of a command-not-found error, and the function returned +non-zero status, zsh set the status to 127 and printed an error message +anyway. Now, the status from the handler is retained and no additional +message is printed. The main reasons for this change are that it was not +possible to return a non-zero status to the parent shell from a command +executed as a replacement, and the new implementation is more consistent +with other shells. + Incompatibilities between 5.0.8 and 5.2 --------------------------------------- diff --git a/Src/exec.c b/Src/exec.c index 9890286b2..f248ca288 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -568,11 +568,14 @@ commandnotfound(char *arg0, LinkList args) Shfunc shf = (Shfunc) shfunctab->getnode(shfunctab, "command_not_found_handler"); - if (!shf) - return 127; + if (!shf) { + lastval = 127; + return 1; + } pushnode(args, arg0); - return doshfunc(shf, args, 1); + lastval = doshfunc(shf, args, 1); + return 0; } /* @@ -703,7 +706,7 @@ execute(LinkList args, int flags, int defpath) if (!search_defpath(arg0, pbuf, PATH_MAX)) { if (commandnotfound(arg0, args) == 0) - _exit(0); + _exit(lastval); zerr("command not found: %s", arg0); _exit(127); } @@ -767,7 +770,7 @@ execute(LinkList args, int flags, int defpath) if (eno) zerr("%e: %s", eno, arg0); else if (commandnotfound(arg0, args) == 0) - _exit(0); + _exit(lastval); else zerr("command not found: %s", arg0); _exit((eno == EACCES || eno == ENOEXEC) ? 126 : 127); diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst index 9f15e04ff..ab7b42928 100644 --- a/Test/C04funcdef.ztst +++ b/Test/C04funcdef.ztst @@ -120,14 +120,13 @@ print "Your command:" >&2 print "$1" >&2 print "has gone down the tubes. Sorry." >&2 - return 1 + return 42 } ThisCommandDoesNotExistEither -127:Command not found handler, failure +42:Command not found handler, failure ?Your command: ?ThisCommandDoesNotExistEither ?has gone down the tubes. Sorry. -?(eval):7: command not found: ThisCommandDoesNotExistEither local variable=outside print "I am $variable" -- cgit v1.2.3 From 0854ee56bc559d7fd614eb7d59b61da84a9ce51f Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 5 Oct 2016 13:52:31 +0100 Subject: 39568: "! " suppresses ERR_EXIT --- ChangeLog | 3 +++ Src/exec.c | 9 +++++++-- Test/C03traps.ztst | 27 +++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index ea3eed8a4..318c8df33 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2016-10-05 Peter Stephenson + * 39568: Src/exec.c, Test/C03traps.ztst: "! " + should suppress ERR_EXIT inside the complex command. + * 39566: README, Doc/Zsh/exec.yo, Src/exec.c, Test/C04funcdef.ztst: change the behaviour of command_not_found_handler to make it easier to handle a non-zero diff --git a/Src/exec.c b/Src/exec.c index f248ca288..741c80e30 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1317,8 +1317,13 @@ execlist(Estate state, int dont_change_job, int exiting) next = state->pc + WC_SUBLIST_SKIP(code); if (!oldnoerrexit) noerrexit = !isend; - if ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT) && isend) - this_noerrexit = 1; + if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT) { + /* suppress errexit for "! this_command" */ + if (isend) + this_noerrexit = 1; + /* suppress errexit for ! */ + noerrexit = 1; + } switch (WC_SUBLIST_TYPE(code)) { case WC_SUBLIST_END: /* End of sublist; just execute, ignoring status. */ diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst index 3a65b2876..0faec02e9 100644 --- a/Test/C03traps.ztst +++ b/Test/C03traps.ztst @@ -554,6 +554,33 @@ F:Must be tested with a top-level script rather than source or function } fn 1:ERRETURN with "!" and a following false +>before + + fn() { + emulate -L zsh + setopt errreturn + print before + ! if true; then + false + fi + print after + } + fn +0:ERRETURN with "!" suppressed inside complex structure +>before +>after + + fn() { + emulate -L zsh + setopt errreturn + print before + if true; then + false + fi + print after + } + fn +1:ERRETURN with no "!" suppression (control case) >before %clean -- cgit v1.2.3 From bcb52460f3069e2e4e3b05f966a2efd40471e366 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 5 Oct 2016 17:46:42 +0100 Subject: 39571: Fix ERR_EXIT bug with && and function. "foo && bar" inside a function could cause the code outside the function not to perform ERR_EXIT or ERR_RETURN when needed. --- ChangeLog | 3 +++ Src/exec.c | 12 ++++++------ Test/C03traps.ztst | 31 ++++++++++++++++++++++--------- 3 files changed, 31 insertions(+), 15 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index 318c8df33..1d1d8f9f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2016-10-05 Peter Stephenson + * 39571: Src/exec.c, Test/C03traps.ztst: "&&" inside a shell + function could mess up ERR_EXIT outside. + * 39568: Src/exec.c, Test/C03traps.ztst: "! " should suppress ERR_EXIT inside the complex command. diff --git a/Src/exec.c b/Src/exec.c index 741c80e30..c0ed2c475 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1229,7 +1229,7 @@ execlist(Estate state, int dont_change_job, int exiting) } while (wc_code(code) == WC_LIST && !breaks && !retflag && !errflag) { int donedebug; - int this_noerrexit = 0; + int this_noerrexit = 0, this_donetrap = 0; ltype = WC_LIST_TYPE(code); csp = cmdsp; @@ -1353,10 +1353,10 @@ execlist(Estate state, int dont_change_job, int exiting) /* We've skipped to the end of the list, not executing * * the final pipeline, so don't perform error handling * * for this sublist. */ - donetrap = 1; + this_donetrap = 1; goto sublist_done; } else if (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END) { - donetrap = 1; + this_donetrap = 1; /* * Treat this in the same way as if we reached * the end of the sublist normally. @@ -1386,10 +1386,10 @@ execlist(Estate state, int dont_change_job, int exiting) /* We've skipped to the end of the list, not executing * * the final pipeline, so don't perform error handling * * for this sublist. */ - donetrap = 1; + this_donetrap = 1; goto sublist_done; } else if (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END) { - donetrap = 1; + this_donetrap = 1; /* * Treat this in the same way as if we reached * the end of the sublist normally. @@ -1439,7 +1439,7 @@ sublist_done: /* Check whether we are suppressing traps/errexit * * (typically in init scripts) and if we haven't * * already performed them for this sublist. */ - if (!noerrexit && !this_noerrexit && !donetrap) { + if (!noerrexit && !this_noerrexit && !donetrap && !this_donetrap) { if (sigtrapped[SIGZERR] && lastval) { dotrap(SIGZERR); donetrap = 1; diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst index 0faec02e9..5057dcf6e 100644 --- a/Test/C03traps.ztst +++ b/Test/C03traps.ztst @@ -476,7 +476,7 @@ fi } fn -0:ERRRETURN not triggered in if condition +0:ERR_RETURN not triggered in if condition >Oh, yes fn() { @@ -490,7 +490,7 @@ fi } fn -1:ERRRETURN in "if" +1:ERR_RETURN in "if" fn() { emulate -L zsh @@ -503,7 +503,7 @@ fi } fn -1:ERRRETURN in "else" branch (regression test) +1:ERR_RETURN in "else" branch (regression test) $ZTST_testdir/../Src/zsh -f =(<<<" if false; then @@ -515,7 +515,7 @@ print Yes fi ") -0:ERRRETURN when false "if" is the first statement in an "else" (regression) +0:ERR_RETURN when false "if" is the first statement in an "else" (regression) >Yes F:Must be tested with a top-level script rather than source or function @@ -527,7 +527,7 @@ F:Must be tested with a top-level script rather than source or function print after } fn -1:ERRRETURN, basic case +1:ERR_RETURN, basic case >before fn() { @@ -539,7 +539,7 @@ F:Must be tested with a top-level script rather than source or function print after } fn -0:ERRETURN with "!" +0:ERR_RETURN with "!" >before >after @@ -553,7 +553,7 @@ F:Must be tested with a top-level script rather than source or function print after } fn -1:ERRETURN with "!" and a following false +1:ERR_RETURN with "!" and a following false >before fn() { @@ -566,7 +566,7 @@ F:Must be tested with a top-level script rather than source or function print after } fn -0:ERRETURN with "!" suppressed inside complex structure +0:ERR_RETURN with "!" suppressed inside complex structure >before >after @@ -580,9 +580,22 @@ F:Must be tested with a top-level script rather than source or function print after } fn -1:ERRETURN with no "!" suppression (control case) +1:ERR_RETURN with no "!" suppression (control case) >before + (setopt err_return + fn() { + print before-in + false && false + } + print before-out + fn + print after-out + ) +1:ERR_RETURN with "&&" in function (regression test) +>before-out +>before-in + %clean rm -f TRAPEXIT -- cgit v1.2.3 From 5f1700755f12677b608adef88c39e08df99c41f2 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 10 Nov 2016 10:37:27 +0000 Subject: 39901: No EXIT trap on LHS of pipeline. There is a special case if the LHS is a shell construct. Add unit tests for both cases. --- ChangeLog | 5 +++++ Src/exec.c | 4 ++++ Test/C03traps.ztst | 17 +++++++++++++++++ 3 files changed, 26 insertions(+) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index d7dc2d0a4..a9c47878b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-11-10 Peter Stephenson + + * 39901: Src/exec.c, Test/C03traps.ztst: Exiting the left hand + side of a pipeline shouldn't trigger EXIT trap. + 2016-11-09 Oliver Kiddle * 39890: Completion/Debian/Command/_git-buildpackage, diff --git a/Src/exec.c b/Src/exec.c index c0ed2c475..a01a633db 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1888,6 +1888,10 @@ execpline2(Estate state, wordcode pcode, entersubsh(((how & Z_ASYNC) ? ESUB_ASYNC : 0) | ESUB_PGRP | ESUB_KEEPTRAP); close(synch[1]); + if (sigtrapped[SIGEXIT]) + { + unsettrap(SIGEXIT); + } execcmd_exec(state, &eparams, input, pipes[1], how, 1); _exit(lastval); } diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst index 828a3d10f..c3bedb06c 100644 --- a/Test/C03traps.ztst +++ b/Test/C03traps.ztst @@ -641,6 +641,23 @@ F:Must be tested with a top-level script rather than source or function >TERM >EXIT + # Should not get "hello" in the single quotes. + ( + trap "echo hello" EXIT; + { :; } | { read line; print "'$line'"; } + ) +0:EXIT trap not called in LHS of pipeline: Shell construct on LHS +>'' +>hello + + ( + trap "echo hello" EXIT; + cat '' +>hello + %clean rm -f TRAPEXIT -- cgit v1.2.3 From c392e6c620163b84798e705dfd6608d6429b9677 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Fri, 11 Nov 2016 02:25:21 +0000 Subject: 39915: whence: Honor PATH_DIRS option for arguments that start with './' or '../'. While here, add some docstrings. --- ChangeLog | 5 +++++ Src/exec.c | 23 ++++++++++++++++------- Test/E01options.ztst | 4 ++++ 3 files changed, 25 insertions(+), 7 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index f51d1a0de..d278e4709 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-11-17 Daniel Shahaf + + * 39915: Src/exec.c, Test/E01options.ztst: whence: Honor + PATH_DIRS option for arguments that start with './' or '../'. + 2016-11-17 Oliver Kiddle * 39962: Src/Zle/zle_keymap.c: bind vi case conversion widgets diff --git a/Src/exec.c b/Src/exec.c index a01a633db..ad80dd059 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -806,14 +806,13 @@ findcmd(char *arg0, int docopy, int default_path) cn = hashcmd(arg0, path); if ((int) strlen(arg0) > PATH_MAX) return NULL; - for (s = arg0; *s; s++) - if (*s == '/') { - RET_IF_COM(arg0); - if (arg0 == s || unset(PATHDIRS)) { - return NULL; - } - break; + if ((s = strchr(arg0, '/'))) { + RET_IF_COM(arg0); + if (arg0 == s || unset(PATHDIRS) || !strncmp(arg0, "./", 2) || + !strncmp(arg0, "../", 3)) { + return NULL; } + } if (cn) { char nn[PATH_MAX]; @@ -848,6 +847,11 @@ findcmd(char *arg0, int docopy, int default_path) return NULL; } +/* + * Return TRUE if the given path denotes an executable regular file, or a + * symlink to one. + */ + /**/ int iscom(char *s) @@ -877,6 +881,11 @@ isreallycom(Cmdnam cn) return iscom(fullnam); } +/* + * Return TRUE if the given path contains a dot or dot-dot component + * and does not start with a slash. + */ + /**/ int isrelative(char *s) diff --git a/Test/E01options.ztst b/Test/E01options.ztst index 40e96afc9..45df9f572 100644 --- a/Test/E01options.ztst +++ b/Test/E01options.ztst @@ -784,6 +784,10 @@ >unsetting option... ?(eval):14: no such file or directory: pathtestdir/findme + (setopt pathdirs; path+=( /usr/bin ); type ./env) +1:whence honours PATH_DIRS option +>./env not found + setopt posixbuiltins PATH= command -v print PATH= command -V print -- cgit v1.2.3 From a62e1640bcafbb82d86ea8d8ce057a83c4683d60 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 17 Nov 2016 19:49:17 +0000 Subject: 39958: Add extra byte to PATH_MAX allocations. This ensures we've got enough space for a null, although this isn't always needed. --- ChangeLog | 6 ++++++ Src/Zle/compctl.c | 2 +- Src/builtin.c | 2 +- Src/compat.c | 6 +++--- Src/exec.c | 16 ++++++++-------- Src/glob.c | 4 ++-- Src/hist.c | 2 +- Src/utils.c | 12 ++++++------ 8 files changed, 28 insertions(+), 22 deletions(-) (limited to 'Src/exec.c') diff --git a/ChangeLog b/ChangeLog index aa3b57bf0..f3dbffcc0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-11-17 Peter Stephenson + + * 39958: Src/Zle/compctl.c, Src/builtin.c, Src/compat.c, + Src/exec.c, Src/glob.c, Src/hist.c, Src/utils.c: Add spare byte + to PATH_MAX allocation to allow for possible null. + 2016-11-17 Daniel Shahaf * 39921: Completion/Unix/Command/_git: __git_recent_branches: diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 09e590569..52c6f1233 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -2135,7 +2135,7 @@ gen_matches_files(int dirs, int execs, int all) { DIR *d; struct stat buf; - char *n, p[PATH_MAX], *q = NULL, *e, *pathpref; + char *n, p[PATH_MAX+1], *q = NULL, *e, *pathpref; LinkList l = NULL; int ns = 0, ng = opts[NULLGLOB], test, aw = addwhat, pathpreflen; diff --git a/Src/builtin.c b/Src/builtin.c index 696971944..d3c628592 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -973,7 +973,7 @@ cd_do_chdir(char *cnam, char *dest, int hard) * Normalize path under Cygwin to avoid messing with * DOS style names with drives in them */ - static char buf[PATH_MAX]; + static char buf[PATH_MAX+1]; #ifdef HAVE_CYGWIN_CONV_PATH cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, dest, buf, PATH_MAX); diff --git a/Src/compat.c b/Src/compat.c index 9041c0bed..81afd4dfd 100644 --- a/Src/compat.c +++ b/Src/compat.c @@ -270,7 +270,7 @@ zgetdir(struct dirsav *d) int len; #endif - buf = zhalloc(bufsiz = PATH_MAX); + buf = zhalloc(bufsiz = PATH_MAX+1); pos = bufsiz - 1; buf[pos] = '\0'; strcpy(nbuf, "../"); @@ -439,11 +439,11 @@ zgetcwd(void) free(cwd); } #else - char *cwdbuf = zalloc(PATH_MAX); + char *cwdbuf = zalloc(PATH_MAX+1); ret = getcwd(cwdbuf, PATH_MAX); if (ret) ret = dupstring(ret); - zfree(cwdbuf, PATH_MAX); + zfree(cwdbuf, PATH_MAX+1); #endif /* GETCWD_CALLS_MALLOC */ } #endif /* HAVE_GETCWD */ diff --git a/Src/exec.c b/Src/exec.c index ad80dd059..f544a33e7 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -437,7 +437,7 @@ static int zexecve(char *pth, char **argv, char **newenvp) { int eno; - static char buf[PATH_MAX * 2]; + static char buf[PATH_MAX * 2+1]; char **eep; unmetafy(pth, NULL); @@ -620,7 +620,7 @@ static void execute(LinkList args, int flags, int defpath) { Cmdnam cn; - char buf[MAXCMDLEN], buf2[MAXCMDLEN]; + char buf[MAXCMDLEN+1], buf2[MAXCMDLEN+1]; char *s, *z, *arg0; char **argv, **pp, **newenvp = NULL; int eno = 0, ee; @@ -701,7 +701,7 @@ execute(LinkList args, int flags, int defpath) /* for command -p, search the default path */ if (defpath) { - char pbuf[PATH_MAX]; + char pbuf[PATH_MAX+1]; char *dptr; if (!search_defpath(arg0, pbuf, PATH_MAX)) { @@ -721,7 +721,7 @@ execute(LinkList args, int flags, int defpath) } else { if ((cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0))) { - char nn[PATH_MAX], *dptr; + char nn[PATH_MAX+1], *dptr; if (cn->node.flags & HASHED) strcpy(nn, cn->u.cmd); @@ -814,7 +814,7 @@ findcmd(char *arg0, int docopy, int default_path) } } if (cn) { - char nn[PATH_MAX]; + char nn[PATH_MAX+1]; if (cn->node.flags & HASHED) strcpy(nn, cn->u.cmd); @@ -905,7 +905,7 @@ mod_export Cmdnam hashcmd(char *arg0, char **pp) { Cmdnam cn; - char *s, buf[PATH_MAX]; + char *s, buf[PATH_MAX+1]; char **pq; for (; *pp; pp++) @@ -5602,7 +5602,7 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) Eprog getfpfunc(char *s, int *ksh, char **fname) { - char **pp, buf[PATH_MAX]; + char **pp, buf[PATH_MAX+1]; off_t len; off_t rlen; char *d; @@ -5732,7 +5732,7 @@ cancd(char *s) char *t; if (*s != '/') { - char sbuf[PATH_MAX], **cp; + char sbuf[PATH_MAX+1], **cp; if (cancd2(s)) return s; diff --git a/Src/glob.c b/Src/glob.c index 50f6dceb3..33bf2ae18 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -283,7 +283,7 @@ addpath(char *s, int l) static int statfullpath(const char *s, struct stat *st, int l) { - char buf[PATH_MAX]; + char buf[PATH_MAX+1]; DPUTS(strlen(s) + !*s + pathpos - pathbufcwd >= PATH_MAX, "BUG: statfullpath(): pathname too long"); @@ -779,7 +779,7 @@ parsepat(char *str) /* Now there is no (#X) in front, we can check the path. */ if (!pathbuf) - pathbuf = zalloc(pathbufsz = PATH_MAX); + pathbuf = zalloc(pathbufsz = PATH_MAX+1); DPUTS(pathbufcwd, "BUG: glob changed directory"); if (*str == '/') { /* pattern has absolute path */ str++; diff --git a/Src/hist.c b/Src/hist.c index eebd7dcde..5be7d2524 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -1843,7 +1843,7 @@ chrealpath(char **junkptr) # ifdef REALPATH_ACCEPTS_NULL char *lastpos, *nonreal, *real; # else - char *lastpos, *nonreal, pathbuf[PATH_MAX]; + char *lastpos, *nonreal, pathbuf[PATH_MAX+1]; char *real = pathbuf; # endif #endif diff --git a/Src/utils.c b/Src/utils.c index 151e9e4eb..7bbd5887f 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -845,7 +845,7 @@ ispwd(char *s) return 0; } -static char xbuf[PATH_MAX*2]; +static char xbuf[PATH_MAX*2+1]; /**/ static char ** @@ -884,7 +884,7 @@ static int xsymlinks(char *s, int full) { char **pp, **opp; - char xbuf2[PATH_MAX*3], xbuf3[PATH_MAX*2]; + char xbuf2[PATH_MAX*3+1], xbuf3[PATH_MAX*2+1]; int t0, ret = 0; zulong xbuflen = strlen(xbuf); @@ -1003,7 +1003,7 @@ print_if_link(char *s, int all) *xbuf = '\0'; if (all) { char *start = s + 1; - char xbuflink[PATH_MAX]; + char xbuflink[PATH_MAX+1]; for (;;) { if (xsymlinks(start, 0) > 0) { printf(" -> "); @@ -1140,7 +1140,7 @@ finddir(char *s) if(homenode.diff==1) homenode.diff = 0; if(!finddir_full) - finddir_full = zalloc(ffsz = PATH_MAX); + finddir_full = zalloc(ffsz = PATH_MAX+1); finddir_full[0] = 0; return finddir_last = NULL; } @@ -1644,7 +1644,7 @@ checkmailpath(char **s) } else if (S_ISDIR(st.st_mode)) { LinkList l; DIR *lock = opendir(unmeta(*s)); - char buf[PATH_MAX * 2], **arr, **ap; + char buf[PATH_MAX * 2 + 1], **arr, **ap; int ct = 1; if (lock) { @@ -6916,7 +6916,7 @@ strsfx(char *s, char *t) static int upchdir(int n) { - char buf[PATH_MAX]; + char buf[PATH_MAX+1]; char *s; int err = -1; -- cgit v1.2.3