From 704a9334c8553c86c53e463f309ed6623628b04d Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 03 2015 12:32:34 +0000 Subject: import zsh-5.0.2-7.el7_1.2 --- diff --git a/SOURCES/zsh-5.0.2-ksh-syntax-check.patch b/SOURCES/zsh-5.0.2-ksh-syntax-check.patch new file mode 100644 index 0000000..857085a --- /dev/null +++ b/SOURCES/zsh-5.0.2-ksh-syntax-check.patch @@ -0,0 +1,45 @@ +From 3427fe59c2d76ddbf4b23908c6ae5272734c7c8b Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Wed, 20 May 2015 10:14:04 -0700 +Subject: [PATCH] 35231: make mkevnstr() safe for NULL value + +Upstream-commit: af957f2ed6287f66953742fbca69188cecb98fbf +Signed-off-by: Kamil Dudka +--- + Src/params.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/Src/params.c b/Src/params.c +index 61edc5d..d0ce0a9 100644 +--- a/Src/params.c ++++ b/Src/params.c +@@ -4488,17 +4488,21 @@ addenv(Param pm, char *value) + static char * + mkenvstr(char *name, char *value, int flags) + { +- char *str, *s; +- int len_name, len_value; ++ char *str, *s = value; ++ int len_name, len_value = 0; + + len_name = strlen(name); +- for (len_value = 0, s = value; +- *s && (*s++ != Meta || *s++ != 32); len_value++); ++ if (s) ++ while (*s && (*s++ != Meta || *s++ != 32)) ++ len_value++; + s = str = (char *) zalloc(len_name + len_value + 2); + strcpy(s, name); + s += len_name; + *s = '='; +- copyenvstr(s, value, flags); ++ if (value) ++ copyenvstr(s, value, flags); ++ else ++ *++s = '\0'; + return str; + } + +-- +2.4.1 + diff --git a/SOURCES/zsh-5.0.2-wait-for-exited.patch b/SOURCES/zsh-5.0.2-wait-for-exited.patch new file mode 100644 index 0000000..c550b4f --- /dev/null +++ b/SOURCES/zsh-5.0.2-wait-for-exited.patch @@ -0,0 +1,385 @@ +From 223ac53797d33b0473323efc0d5a44d1dceaf746 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Sun, 26 Oct 2014 17:47:42 +0000 +Subject: [PATCH 1/2] 33531 with additions: retain status of exited background + jobs. + +Add linked list of unwaited-for background jobs. +Truncate at value of _SC_CHILD_MAX discarding oldest. +Remove old lastpid_status mechanism for latest exited process only. +Slightly tighten safety of permanently allocated linked lists so +that this doesn't compromise signal handling. + +Upstream-commit: b4f7ccecd93ca9e64c3c3c774fdaefae83d7204a +Signed-off-by: Kamil Dudka +--- + Doc/Zsh/builtins.yo | 16 ++++++ + Doc/Zsh/options.yo | 8 +-- + Doc/zshoptions.1 | 8 +-- + Src/exec.c | 2 - + Src/init.c | 1 - + Src/jobs.c | 138 ++++++++++++++++++++++++++++++++++++++++++++-------- + Src/linklist.c | 4 ++ + Src/signals.c | 14 +++--- + 8 files changed, 152 insertions(+), 39 deletions(-) + +diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo +index 46f40cc..edc335e 100644 +--- a/Doc/Zsh/builtins.yo ++++ b/Doc/Zsh/builtins.yo +@@ -1905,6 +1905,22 @@ then all currently active child processes are waited for. + Each var(job) can be either a job specification or the process ID + of a job in the job table. + The exit status from this command is that of the job waited for. ++ ++It is possible to wait for recent processes (specified by process ID, ++not by job) that were running in the background even if the process has ++exited. Typically the process ID will be recorded by capturing the ++value of the variable tt($!) immediately after the process has been ++started. There is a limit on the number of process IDs remembered by ++the shell; this is given by the value of the system configuration ++parameter tt(CHILD_MAX). When this limit is reached, older process IDs ++are discarded, least recently started processes first. ++ ++Note there is no protection against the process ID wrapping, i.e. if the ++wait is not executed soon enough there is a chance the process waited ++for is the wrong one. A conflict implies both process IDs have been ++generated by the shell, as other processes are not recorded, and that ++the user is potentially interested in both, so this problem is intrinsic ++to process IDs. + ) + findex(whence) + item(tt(whence) [ tt(-vcwfpams) ] var(name) ...)( +diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo +index 068a253..452b258 100644 +--- a/Doc/Zsh/options.yo ++++ b/Doc/Zsh/options.yo +@@ -1401,10 +1401,10 @@ shell is saved for output within a subshell (for example, within a + pipeline). When the option is set, the output of tt(jobs) is empty + until a job is started within the subshell. + +-When the option is set, it becomes possible to use the tt(wait) builtin to +-wait for the last job started in the background (as given by tt($!)) even +-if that job has already exited. This works even if the option is turned +-on temporarily around the use of the tt(wait) builtin. ++In previous versions of the shell, it was necessary to enable ++tt(POSIX_JOBS) in order for the builtin command tt(wait) to return the ++status of background jobs that had already exited. This is no longer ++the case. + ) + enditem() + +diff --git a/Doc/zshoptions.1 b/Doc/zshoptions.1 +index dc8f2f8..17f9e97 100644 +--- a/Doc/zshoptions.1 ++++ b/Doc/zshoptions.1 +@@ -867,10 +867,10 @@ shell is saved for output within a subshell (for example, within a + pipeline)\&. When the option is set, the output of \fBjobs\fP is empty + until a job is started within the subshell\&. + .PP +-When the option is set, it becomes possible to use the \fBwait\fP builtin to +-wait for the last job started in the background (as given by \fB$!\fP) even +-if that job has already exited\&. This works even if the option is turned +-on temporarily around the use of the \fBwait\fP builtin\&. ++In previous versions of the shell, it was necessary to enable ++\fBPOSIX_JOBS\fP in order for the builtin command \fBwait\fP to return the ++status of background jobs that had already exited\&. This is no longer ++the case\&. + .RE + .RE + .PP +diff --git a/Src/exec.c b/Src/exec.c +index d0fadd6..a9c4688 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -2852,8 +2852,6 @@ execcmd(Estate state, int input, int output, int how, int last1) + #endif + 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; +diff --git a/Src/init.c b/Src/init.c +index c26d887..6666f98 100644 +--- a/Src/init.c ++++ b/Src/init.c +@@ -1018,7 +1018,6 @@ setupvals(void) + bufstack = znewlinklist(); + hsubl = hsubr = NULL; + lastpid = 0; +- lastpid_status = -1L; + + get_usage(); + +diff --git a/Src/jobs.c b/Src/jobs.c +index bd95afb..18bb648 100644 +--- a/Src/jobs.c ++++ b/Src/jobs.c +@@ -104,15 +104,6 @@ int prev_errflag, prev_breaks, errbrk_saved; + /**/ + int numpipestats, pipestats[MAX_PIPESTATS]; + +-/* +- * The status associated with the process lastpid. +- * -1 if not set and no associated lastpid +- * -2 if lastpid is set and status isn't yet +- * else the value returned by wait(). +- */ +-/**/ +-long lastpid_status; +- + /* Diff two timevals for elapsed-time computations */ + + /**/ +@@ -1210,14 +1201,6 @@ addproc(pid_t pid, char *text, int aux, struct timeval *bgtime) + { + Process pn, *pnlist; + +- if (pid == lastpid && lastpid_status != -2L) { +- /* +- * The status for the previous lastpid is invalid. +- * Presumably process numbers have wrapped. +- */ +- lastpid_status = -1L; +- } +- + DPUTS(thisjob == -1, "No valid job in addproc."); + pn = (Process) zshcalloc(sizeof *pn); + pn->pid = pid; +@@ -1826,6 +1809,122 @@ maybeshrinkjobtab(void) + unqueue_signals(); + } + ++/* ++ * Definitions for the background process stuff recorded below. ++ * This would be more efficient as a hash, but ++ * - that's quite heavyweight for something not needed very often ++ * - we need some kind of ordering as POSIX allows us to limit ++ * the size of the list to the value of _SC_CHILD_MAX and clearly ++ * we want to clear the oldest first ++ * - cases with a long list of background jobs where the user doesn't ++ * wait for a large number, and then does wait for one (the only ++ * inefficient case) are rare ++ * - in the context of waiting for an external process, looping ++ * over a list isn't so very inefficient. ++ * Enough excuses already. ++ */ ++ ++/* Data in the link list, a key (process ID) / value (exit status) pair. */ ++struct bgstatus { ++ pid_t pid; ++ int status; ++}; ++typedef struct bgstatus *Bgstatus; ++/* The list of those entries */ ++LinkList bgstatus_list; ++/* Count of entries. Reaches value of _SC_CHILD_MAX and stops. */ ++long bgstatus_count; ++ ++/* ++ * Remove and free a bgstatus entry. ++ */ ++static void rembgstatus(LinkNode node) ++{ ++ zfree(remnode(bgstatus_list, node), sizeof(struct bgstatus)); ++ bgstatus_count--; ++} ++ ++/* ++ * Record the status of a background process that exited so we ++ * can execute the builtin wait for it. ++ * ++ * We can't execute the wait builtin for something that exited in the ++ * foreground as it's not visible to the user, so don't bother recording. ++ */ ++ ++/**/ ++void ++addbgstatus(pid_t pid, int status) ++{ ++ static long child_max; ++ Bgstatus bgstatus_entry; ++ ++ if (!child_max) { ++#ifdef _SC_CHILD_MAX ++ child_max = sysconf(_SC_CHILD_MAX); ++ if (!child_max) /* paranoia */ ++#endif ++ { ++ /* Be inventive */ ++ child_max = 1024L; ++ } ++ } ++ ++ if (!bgstatus_list) { ++ bgstatus_list = znewlinklist(); ++ /* ++ * We're not always robust about memory failures, but ++ * this is pretty deep in the shell basics to be failing owing ++ * to memory, and a failure to wait is reported loudly, so test ++ * and fail silently here. ++ */ ++ if (!bgstatus_list) ++ return; ++ } ++ if (bgstatus_count == child_max) { ++ /* Overflow. List is in order, remove first */ ++ rembgstatus(firstnode(bgstatus_list)); ++ } ++ bgstatus_entry = (Bgstatus)zalloc(sizeof(*bgstatus_entry)); ++ if (!bgstatus_entry) { ++ /* See note above */ ++ return; ++ } ++ bgstatus_entry->pid = pid; ++ bgstatus_entry->status = status; ++ if (!zaddlinknode(bgstatus_list, bgstatus_entry)) { ++ zfree(bgstatus_entry, sizeof(*bgstatus_entry)); ++ return; ++ } ++ bgstatus_count++; ++} ++ ++/* ++ * See if pid has a recorded exit status. ++ * Note we make no guarantee that the PIDs haven't wrapped, so this ++ * may not be the right process. ++ * ++ * This is only used by wait, which must only work on each ++ * pid once, so we need to remove the entry if we find it. ++ */ ++ ++static int getbgstatus(pid_t pid) ++{ ++ LinkNode node; ++ Bgstatus bgstatus_entry; ++ ++ if (!bgstatus_list) ++ return -1; ++ for (node = firstnode(bgstatus_list); node; incnode(node)) { ++ bgstatus_entry = (Bgstatus)getdata(node); ++ if (bgstatus_entry->pid == pid) { ++ int status = bgstatus_entry->status; ++ rembgstatus(node); ++ return status; ++ } ++ } ++ return -1; ++} + + /* bg, disown, fg, jobs, wait: most of the job control commands are * + * here. They all take the same type of argument. Exception: wait can * +@@ -1971,10 +2070,7 @@ bin_fg(char *name, char **argv, Options ops, int func) + } + if (retval == 0) + retval = lastval2; +- } else if (isset(POSIXJOBS) && +- pid == lastpid && lastpid_status >= 0L) { +- retval = (int)lastpid_status; +- } else { ++ } else if ((retval = getbgstatus(pid)) < 0) { + zwarnnam(name, "pid %d is not a child of this shell", pid); + /* presumably lastval2 doesn't tell us a heck of a lot? */ + retval = 1; +diff --git a/Src/linklist.c b/Src/linklist.c +index 1e364fb..3aa8125 100644 +--- a/Src/linklist.c ++++ b/Src/linklist.c +@@ -118,6 +118,8 @@ znewlinklist(void) + LinkList list; + + list = (LinkList) zalloc(sizeof *list); ++ if (!list) ++ return NULL; + list->list.first = NULL; + list->list.last = &list->node; + list->list.flags = 0; +@@ -152,6 +154,8 @@ zinsertlinknode(LinkList list, LinkNode node, void *dat) + + tmp = node->next; + node->next = new = (LinkNode) zalloc(sizeof *tmp); ++ if (!new) ++ return NULL; + new->prev = node; + new->dat = dat; + new->next = tmp; +diff --git a/Src/signals.c b/Src/signals.c +index 2df69f9..e728505 100644 +--- a/Src/signals.c ++++ b/Src/signals.c +@@ -520,14 +520,14 @@ wait_for_processes(void) + get_usage(); + } + /* +- * Remember the status associated with $!, so we can +- * wait for it even if it's exited. This value is +- * only used if we can't find the PID in the job table, +- * so it doesn't matter that the value we save here isn't +- * useful until the process has exited. ++ * Accumulate a list of older jobs. We only do this for ++ * background jobs, which is something in the job table ++ * that's not marked as in the current shell or as shell builtin ++ * and is not equal to the current foreground job. + */ +- if (pn != NULL && pid == lastpid && lastpid_status != -1L) +- lastpid_status = lastval2; ++ if (jn && !(jn->stat & (STAT_CURSH|STAT_BUILTIN)) && ++ jn - jobtab != thisjob) ++ addbgstatus(pid, (int)lastval2); + } + } + +-- +2.1.0 + + +From 2d59469450ba80b69449dc2777f0fc0673e0fbd6 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Sun, 26 Oct 2014 19:04:47 +0000 +Subject: [PATCH 2/2] 33542: test logic for waiting for already exited + processes + +Upstream-commit: 9a551ca85999ff329714fd2cca138ce2f7d3c3d9 +Signed-off-by: Kamil Dudka +--- + Test/A05execution.ztst | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst +index ca97f4f..589815f 100644 +--- a/Test/A05execution.ztst ++++ b/Test/A05execution.ztst +@@ -178,3 +178,28 @@ + kill $! + 0:Status reset by starting a backgrounded command + >0 ++ ++# This tests that we record the status of processes that have already exited ++# for when we wait for them. ++# ++# Actually, we don't guarantee here that the jobs have already exited, but ++# the order of the waits means it's highly likely we do need to recall a ++# previous status, barring accidents which shouldn't happen very often. In ++# other words, we rely on the test working repeatedly rather than just ++# once. The monitor option is irrelevant to the logic, so we'll make ++# our job easier by turning it off. ++ unsetopt monitor ++ (exit 1) & ++ one=$! ++ (exit 2) & ++ two=$! ++ (exit 3) & ++ three=$! ++ wait $three ++ print $? ++ wait $two ++ print $? ++ wait $one ++1:The status of recently exited background jobs is recorded ++>3 ++>2 +-- +2.1.0 + diff --git a/SOURCES/zsh-5.0.2-wildcard-opt.patch b/SOURCES/zsh-5.0.2-wildcard-opt.patch new file mode 100644 index 0000000..bca51a5 --- /dev/null +++ b/SOURCES/zsh-5.0.2-wildcard-opt.patch @@ -0,0 +1,52 @@ +From 941f312444dfda4d0d1d02edcfbae9dc1ec6b95e Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Mon, 8 Sep 2014 16:38:51 +0100 +Subject: [PATCH] users/19059 based on users/19058: remove ineffiency with + multiple * matches + +Upstream-commit: 8bf3595e3a05f0cea7f12c463a0df09e4010cd1c +Signed-off-by: Kamil Dudka +--- + Src/pattern.c | 10 ++++++++++ + Test/D02glob.ztst | 9 ++++++++- + 2 files changed, 18 insertions(+), 1 deletion(-) + +diff --git a/Src/pattern.c b/Src/pattern.c +index 53ada0f..b74a08a 100644 +--- a/Src/pattern.c ++++ b/Src/pattern.c +@@ -2911,6 +2911,16 @@ patmatch(Upat prog) + break; + case P_STAR: + /* Handle specially for speed, although really P_ONEHASH+P_ANY */ ++ while (P_OP(next) == P_STAR) { ++ /* ++ * If there's another * following we can optimise it ++ * out. Chains of *'s can give pathologically bad ++ * performance. ++ */ ++ scan = next; ++ next = PATNEXT(scan); ++ } ++ /*FALLTHROUGH*/ + case P_ONEHASH: + case P_TWOHASH: + /* +diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst +index 0aea261..5709e5c 100644 +--- a/Test/D02glob.ztst ++++ b/Test/D02glob.ztst +@@ -433,3 +433,10 @@ + print glob.tmp/dir5/N<->(N) + 0:Numeric glob is not usurped by process substitution. + >glob.tmp/dir5/N123 ++ ++# The following should not cause excessive slowdown. ++ print glob.tmp/*.* ++ print glob.tmp/**************************.************************* ++0:Optimisation to squeeze multiple *'s used as ordinary glob wildcards. ++>glob.tmp/ra=1.0_et=3.5 ++>glob.tmp/ra=1.0_et=3.5 +-- +2.1.0 + diff --git a/SPECS/zsh.spec b/SPECS/zsh.spec index d34d37b..ed2baa5 100644 --- a/SPECS/zsh.spec +++ b/SPECS/zsh.spec @@ -3,7 +3,7 @@ Summary: Powerful interactive shell Name: zsh Version: 5.0.2 -Release: 7%{?dist}.1 +Release: 7%{?dist}.2 License: MIT URL: http://zsh.sourceforge.net/ Group: System Environment/Shells @@ -17,15 +17,26 @@ Source6: dotzshrc Source7: zshprompt.pl Source8: http://cgit.freedesktop.org/systemd/systemd/plain/shell-completion/systemd-zsh-completion.zsh Patch0: zsh-serial.patch + +# make the wait built-in work for already exited processes (#1150554) +Patch2: zsh-5.0.2-wait-for-exited.patch + Patch4: zsh-4.3.6-8bit-prompts.patch Patch5: zsh-test-C02-dev_fd-mock.patch # fix NOEXEC option in execsimple() optimisation (#1146512) Patch7: zsh-5.0.2-noexec.patch +# optimize matching of multiple * in wildcards (#1130418) +Patch8: zsh-5.0.2-wildcard-opt.patch + # Tmp. Patch11: zsh-5.0.2.texi-itemx.patch Patch12: http://ausil.fedorapeople.org/aarch64/zsh/zsh-aarch64.patch + +# fix SIGSEGV of the syntax check in ksh emulation mode (#1222867) +Patch14: zsh-5.0.2-ksh-syntax-check.patch + BuildRequires: coreutils sed ncurses-devel libcap-devel BuildRequires: texinfo texi2html gawk hostname Requires(post): /sbin/install-info grep @@ -58,13 +69,16 @@ This package contains the Zsh manual in html format. %setup -q %patch0 -p1 -b .serial +%patch2 -p1 %patch4 -p1 %patch5 -p1 %patch7 -p1 +%patch8 -p1 %patch11 -p1 %patch12 -p1 +%patch14 -p1 cp -p %SOURCE7 . @@ -181,6 +195,11 @@ fi %doc Doc/*.html %changelog +* Mon Oct 26 2015 Kamil Dudka - 5.0.2-7.el7_1.2 +- fix SIGSEGV of the syntax check in ksh emulation mode (#1222867) +- make the wait built-in work for already exited processes (#1162198) +- optimize matching of multiple * in wildcards (#1130418) + * Thu Mar 19 2015 Kamil Dudka - 5.0.2-7.el7_1.1 - fix NOEXEC option in execsimple() optimisation (#1146512)