From 387247864e1689a71fecf9301fc2bbc49e630cb1 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Sun, 19 Jan 2020 16:00:14 +0100 Subject: _brace_parameter: add missing \ --- Completion/Zsh/Context/_brace_parameter | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Completion/Zsh/Context/_brace_parameter b/Completion/Zsh/Context/_brace_parameter index c6e74bf7b..6960cec9b 100644 --- a/Completion/Zsh/Context/_brace_parameter +++ b/Completion/Zsh/Context/_brace_parameter @@ -38,7 +38,7 @@ if [[ $PREFIX = *'${('[^\)]# ]]; then case $char in (g) compset -P '*' - flags=('o:octal escapes' 'c:expand ^X etc.' 'e:expand \M-t etc.') + flags=('o:octal escapes' 'c:expand ^X etc.' 'e:expand \\M-t etc.') _describe -t format 'format option' flags -Q -S '' ;; -- cgit v1.2.3 From e626f57613ad2dacd7fe7244f6a33de5c8f03f9e Mon Sep 17 00:00:00 2001 From: Eitan Adler Date: Sun, 19 Jan 2020 21:31:56 +0000 Subject: 45332: _git: add completion for git-version Signed-off-by: Eitan Adler --- ChangeLog | 9 +++++++++ Completion/Unix/Command/_git | 9 ++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 2de3f73d5..71bdf9593 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2020-01-19 Eitan Adler + + * 45332: Completion/Unix/Command/_git: add completion for + git-version + +2020-01-19 Mikael Magnusson + + * unposted: _brace_parameter: add missing \ + 2020-01-16 Daniel Shahaf * 45305: Test/A01grammar.ztst: Add an XFail test: The diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git index 7f2c206c1..ba1852699 100644 --- a/Completion/Unix/Command/_git +++ b/Completion/Unix/Command/_git @@ -407,6 +407,12 @@ _git-bundle () { return ret } +(( $+functions[_git-version] )) || +_git-version () { + _arguments -S $endopt \ + '--build-options[also print build options]' +} + (( $+functions[_git-check-ignore] )) || _git-check-ignore () { _arguments -s -S $endopt \ @@ -5951,7 +5957,8 @@ _git_commands () { show-branch:'show branches and their commits' verify-commit:'check GPG signature of commits' verify-tag:'check GPG signature of tags' - whatchanged:'show commit-logs and differences they introduce') + whatchanged:'show commit-logs and differences they introduce' + version:'show git version') interaction_commands=( archimport:'import an Arch repository into git' -- cgit v1.2.3 From 5e843a3721ff53a9a2c0c8a3611cba829640716c Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 23 Jan 2020 03:14:45 +0000 Subject: 45340: internal: Document the difference between paramtab and realparamtab. --- ChangeLog | 5 +++++ Src/params.c | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 71bdf9593..625e4a639 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-01-23 Daniel Shahaf + + * 45340: Src/params.c: internal: Document the difference between + paramtab and realparamtab. + 2020-01-19 Eitan Adler * 45332: Completion/Unix/Command/_git: add completion for diff --git a/Src/params.c b/Src/params.c index 5eaafe34e..863b32600 100644 --- a/Src/params.c +++ b/Src/params.c @@ -478,7 +478,13 @@ static initparam argvparam_pm = IPDEF9("", &pparams, NULL, \ static Param argvparam; -/* hash table containing the parameters */ +/* "parameter table" - hash table containing the parameters + * + * realparamtab always points to the shell's global table. paramtab is sometimes + * temporarily changed to point at another table, while dealing with the keys + * of an associative array (for example, see makecompparams() which initializes + * the associative array ${compstate}). + */ /**/ mod_export HashTable paramtab, realparamtab; -- cgit v1.2.3 From 35111697316f1b2d48144c58e0e345770bb3fb71 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 16 Jan 2020 20:23:50 +0000 Subject: unposted: internal: Add some comments and fix indentation. No functional change. --- ChangeLog | 5 +++++ Src/init.c | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 625e4a639..870588391 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-01-26 Daniel Shahaf + + * unposted: Src/init.c: internal: Add some comments and fix + indentation. No functional change. + 2020-01-23 Daniel Shahaf * 45340: Src/params.c: internal: Document the difference between diff --git a/Src/init.c b/Src/init.c index 2e2ef881c..04a5856ff 100644 --- a/Src/init.c +++ b/Src/init.c @@ -882,7 +882,7 @@ setupvals(char *cmd, char *runscript, char *zsh_name) char *ptr; int i, j; #if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined (ADDITIONAL_FPATH) || defined(FIXED_FPATH_DIR) -#define FPATH_NEEDS_INIT 1 +# define FPATH_NEEDS_INIT 1 char **fpathptr; # if defined(FPATH_DIR) && defined(FPATH_SUBDIRS) char *fpath_subdirs[] = FPATH_SUBDIRS; @@ -994,18 +994,29 @@ setupvals(char *cmd, char *runscript, char *zsh_name) # endif /* ADDITONAL_FPATH */ fpath = fpathptr = (char **)zalloc((fpathlen+1)*sizeof(char *)); # ifdef FIXED_FPATH_DIR + /* Zeroth: /usr/local/share/zsh/site-functions */ *fpathptr++ = ztrdup(FIXED_FPATH_DIR); fpathlen--; # endif # ifdef SITEFPATH_DIR + /* First: the directory from --enable-site-fndir + * + * default: /usr/local/share/zsh/site-functions + * (but changeable by passing --prefix or --datadir to configure) */ *fpathptr++ = ztrdup(SITEFPATH_DIR); fpathlen--; # endif /* SITEFPATH_DIR */ # if defined(ADDITIONAL_FPATH) + /* Second: the directories from --enable-additional-fpath + * + * default: empty list */ for (j = 0; j < more_fndirs_len; j++) *fpathptr++ = ztrdup(more_fndirs[j]); # endif # ifdef FPATH_DIR + /* Third: The directory from --enable-fndir + * + * default: /usr/local/share/zsh/${ZSH_VERSION}/functions */ # ifdef FPATH_SUBDIRS # ifdef ADDITIONAL_FPATH for (j = more_fndirs_len; j < fpathlen; j++) @@ -1013,7 +1024,7 @@ setupvals(char *cmd, char *runscript, char *zsh_name) # else for (j = 0; j < fpathlen; j++) *fpathptr++ = tricat(FPATH_DIR, "/", fpath_subdirs[j]); -#endif +# endif # else *fpathptr++ = ztrdup(FPATH_DIR); # endif -- cgit v1.2.3 From a06143bb30921b780a9fb0999aebd068b02b2a6c Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Sun, 26 Jan 2020 03:58:09 +0000 Subject: 45345: internal: ztst.vim: Fix highlighting of zsh comments in test payload --- ChangeLog | 5 +++++ Util/ztst-syntax.vim | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 870588391..4b6955b67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-01-28 Daniel Shahaf + + * 45345: Util/ztst-syntax.vim: internal: ztst.vim: Fix + highlighting of zsh comments in test payload + 2020-01-26 Daniel Shahaf * unposted: Src/init.c: internal: Add some comments and fix diff --git a/Util/ztst-syntax.vim b/Util/ztst-syntax.vim index 01e4dae31..a39fe3fbb 100644 --- a/Util/ztst-syntax.vim +++ b/Util/ztst-syntax.vim @@ -25,7 +25,13 @@ syn clear syn include @zsh syntax/zsh.vim -syn match ztstPayload /^\s\+\zs.*/ contains=@zsh +" Note that we don't do /^\s\zs.*/ here. If we did that, lines that start +" with " #" (a space and a hash sign) would not be highlighted as comments, +" because zshComment's patterns won't match unless the '#' is preceded by +" a space or start-of-line. See: +" +" https://github.com/chrisbra/vim-zsh/issues/21#issuecomment-577738791 +syn match ztstPayload /^\s.*/ contains=@zsh syn match ztstExitCode /^\d\+\|^-/ nextgroup=ztstFlags syn match ztstFlags /[.dDqf]*:/ contained nextgroup=ztstTestName contains=ztstColon -- cgit v1.2.3 From 8dab5bc03726168356f76c708919ed011adbaf95 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Sun, 26 Jan 2020 03:35:22 +0000 Subject: 45344: Document where third-party completion functions should be installed. --- ChangeLog | 5 +++++ INSTALL | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/ChangeLog b/ChangeLog index 4b6955b67..f15cfbe56 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-01-29 Daniel Shahaf + + * 45344: INSTALL: Document where third-party completion functions + should be installed. + 2020-01-28 Daniel Shahaf * 45345: Util/ztst-syntax.vim: internal: ztst.vim: Fix diff --git a/INSTALL b/INSTALL index cf70893a7..f347a4480 100644 --- a/INSTALL +++ b/INSTALL @@ -251,6 +251,16 @@ source code in the directory that "configure" is in. For example, Note that this is mutually exclusive with using the source directories as make can become confused by build files created in the source directories. +Writing third-party autoloadable functions +------------------------------------------ + +Third-party autoloadable functions, including but not limited to completion +functions, should be installed into the share/zsh/site-functions/ directory +under the respective installation prefix. That would typically be written as +$(DESTDIR)$(PREFIX)/share/zsh/site-functions/ in a makefile. If the +third-party tool's $(PREFIX) is not the same as zsh's prefix, then that +directory should be added to $fpath in zsh's initialization files. + ================================ AUTOMATIC NEW USER CONFIGURATION -- cgit v1.2.3 From 581585dfc66e2bb18434cdd1ad2f5899b12a86dd Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Sun, 26 Jan 2020 01:17:00 +0000 Subject: 45343: Queue signals around arithmetic evaluations The queueing added in execarith() in 45083 is reverted since the callee does this now. --- ChangeLog | 3 +++ Src/exec.c | 3 --- Src/math.c | 15 +++++++++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index f15cfbe56..95a94db07 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2020-01-29 Daniel Shahaf + * 45343: Src/exec.c, Src/math.c: Queue signals around arithmetic + evaluations + * 45344: INSTALL: Document where third-party completion functions should be installed. diff --git a/Src/exec.c b/Src/exec.c index fac095d64..50027654a 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -5101,7 +5101,6 @@ execarith(Estate state, UNUSED(int do_exec)) mnumber val = zero_mnumber; int htok = 0; - queue_signals(); if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "(("); @@ -5121,8 +5120,6 @@ execarith(Estate state, UNUSED(int do_exec)) fprintf(xtrerr, " ))\n"); fflush(xtrerr); } - unqueue_signals(); - if (errflag) { errflag &= ~ERRFLAG_ERROR; return 2; diff --git a/Src/math.c b/Src/math.c index a38770073..905b910ec 100644 --- a/Src/math.c +++ b/Src/math.c @@ -1133,8 +1133,7 @@ notzero(mnumber a) /* macro to pop three values off the value stack */ -/**/ -void +static void op(int what) { mnumber a, b, c, *spval; @@ -1569,14 +1568,19 @@ mathparse(int pc) if (errflag) return; + queue_signals(); mtok = zzlex(); /* Handle empty input */ - if (pc == TOPPREC && mtok == EOI) + if (pc == TOPPREC && mtok == EOI) { + unqueue_signals(); return; + } checkunary(mtok, optr); while (prec[mtok] <= pc) { - if (errflag) + if (errflag) { + unqueue_signals(); return; + } switch (mtok) { case NUM: push(yyval, NULL, 0); @@ -1595,6 +1599,7 @@ mathparse(int pc) if (mtok != M_OUTPAR) { if (!errflag) zerr("bad math expression: ')' expected"); + unqueue_signals(); return; } break; @@ -1613,6 +1618,7 @@ mathparse(int pc) if (mtok != COLON) { if (!errflag) zerr("bad math expression: ':' expected"); + unqueue_signals(); return; } if (q) @@ -1636,4 +1642,5 @@ mathparse(int pc) mtok = zzlex(); checkunary(mtok, optr); } + unqueue_signals(); } -- cgit v1.2.3 From e71ba9704f86a4a3ec1f0ddabbb1f2296fe421fe Mon Sep 17 00:00:00 2001 From: WGH Date: Sun, 2 Feb 2020 07:31:36 +0000 Subject: 45365: _git: Fix __git_recent_branches for the case when a commit has an empty message --- ChangeLog | 5 +++++ Completion/Unix/Command/_git | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 95a94db07..698e21592 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-02-02 WGH + + * 45365: Completion/Unix/Command/_git: Fix __git_recent_branches + for the case when a commit has an empty message + 2020-01-29 Daniel Shahaf * 45343: Src/exec.c, Src/math.c: Queue signals around arithmetic diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git index ba1852699..97ab26512 100644 --- a/Completion/Unix/Command/_git +++ b/Completion/Unix/Command/_git @@ -6662,8 +6662,8 @@ __git_recent_branches() { # 4. Obtain log messages for all of them in one shot. # TODO: we'd really like --sort=none here... but git doesn't support such a thing. - # The \n removal is because for-each-ref prints a \n after each entry. - descriptions=( ${(0)"$(_call_program all-descriptions "git --no-pager for-each-ref --format='%(refname)%00%(subject)%00'" refs/heads/${(q)^branches} "--")"//$'\n'} ) + local z=$'\0' + descriptions=( "${(0)"$(_call_program all-descriptions "git --no-pager for-each-ref --format='%(refname)%00%(subject)'" refs/heads/${(q)^branches} "--")"//$'\n'/$z}" ) # 5. Synthesize the data structure _describe wants. local -a branches_colon_descriptions -- cgit v1.2.3 From 7a9467e430eb331d28065a21c6427714634eeaa5 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Sun, 2 Feb 2020 07:36:36 +0000 Subject: 45372: Record a symlink loop bug involving :P --- ChangeLog | 4 ++++ Etc/BUGS | 2 ++ 2 files changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 698e21592..d4dbb2e12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2020-02-02 Daniel Shahaf + + * 45372: Etc/BUGS: Record a symlink loop bug involving :P + 2020-02-02 WGH * 45365: Completion/Unix/Command/_git: Fix __git_recent_branches diff --git a/Etc/BUGS b/Etc/BUGS index 8112299f5..99a0d9753 100644 --- a/Etc/BUGS +++ b/Etc/BUGS @@ -29,3 +29,5 @@ skipped when STTY=... is set for that command 44007 - Martijn - exit in trap executes rest of function See test case in Test/C03traps.ztst. ------------------------------------------------------------------------ +45282: ${${:-foo}:P} where foo is a symlink that points to itself segfaults +------------------------------------------------------------------------ -- cgit v1.2.3 From e01223a26cb7afd9f44805f067c4dcdad06039b0 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 2 Feb 2020 18:05:47 +0000 Subject: 45373: Fix ERR_EXIT bug in else branch of if. The flags need resetting for this branch otherwise e.g. command substitution with non-zero status doesn't cause exit. --- ChangeLog | 5 +++++ Src/loop.c | 2 +- Test/C03traps.ztst | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d4dbb2e12..663b3e88f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-02-02 Peter Stephenson + + * 45373: Src/loop.c, Test/C03traps.ztst: ERR_EXIT failed on + command substitution in else branch. + 2020-02-02 Daniel Shahaf * 45372: Etc/BUGS: Record a symlink loop bug involving :P diff --git a/Src/loop.c b/Src/loop.c index 538afb8dc..01abc6cc9 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -570,7 +570,7 @@ execif(Estate state, int do_exec) if (run) { /* we need to ignore lastval until we reach execcmd() */ - if (olderrexit) + if (olderrexit || run == 2) noerrexit = olderrexit; else if (lastval) noerrexit |= NOERREXIT_EXIT | NOERREXIT_RETURN | NOERREXIT_UNTIL_EXEC; diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst index e661aabd5..6f84e5db2 100644 --- a/Test/C03traps.ztst +++ b/Test/C03traps.ztst @@ -500,6 +500,15 @@ >Succeed 2 >Succeed 3 + (set -e + if false; then + else + a=$(false) + print This should not appear + fi + ) +1:ERREXIT is triggered in an else block after a cmd subst returning false + fn() { emulate -L zsh setopt errreturn -- cgit v1.2.3 From 3bcf9641eb2a8d39deda166579294ef515172d85 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Mon, 3 Feb 2020 07:08:54 +0000 Subject: 45368: Add tests for workers/45367's issue about double slashes in 'cd -P' and /home/daniel/in/zsh. --- ChangeLog | 6 ++++++ Test/B01cd.ztst | 4 ++++ Test/D02glob.ztst | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/ChangeLog b/ChangeLog index 663b3e88f..af4055964 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2020-02-03 Daniel Shahaf + + * 45368: Test/B01cd.ztst, Test/D02glob.ztst: Add tests for + workers/45367's issue about double slashes in 'cd -P' and + /home/daniel/in/zsh. + 2020-02-02 Peter Stephenson * 45373: Src/loop.c, Test/C03traps.ztst: ERR_EXIT failed on diff --git a/Test/B01cd.ztst b/Test/B01cd.ztst index 3312f8707..d903b7462 100644 --- a/Test/B01cd.ztst +++ b/Test/B01cd.ztst @@ -145,6 +145,10 @@ F:something is broken. But you already knew that. 1:Implicit cd with unset HOME. ?zsh:cd:1: HOME not set + $ZTST_testdir/../Src/zsh -fc 'cd -P ////dev && pwd' +-f:(workers/45367) cd -P squashes multiple leading slashes +>/dev + %clean # This optional section cleans up after the test, if necessary, # e.g. killing processes etc. This is in addition to the removal of *.tmp diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst index 3d7df94c9..b0650c8c8 100644 --- a/Test/D02glob.ztst +++ b/Test/D02glob.ztst @@ -742,6 +742,10 @@ >glob.tmp/secret-s111/ glob.tmp/secret-s111 >glob.tmp/secret-s444/ glob.tmp/secret-s444 + () { echo $1:P } ////dev +-f:(workers/45367) modifier ':P' squashes multiple slashes +>/dev + %clean # Fix unreadable-directory permissions so ztst can clean up properly -- cgit v1.2.3 From 8a12bd81aaa11eb2aa3e95c8b7b95fb8e2a9bebc Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 6 Feb 2020 05:55:05 +0000 Subject: unposted: Fix ChangeLog typo. --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index af4055964..2b0d1d4de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,7 +2,7 @@ * 45368: Test/B01cd.ztst, Test/D02glob.ztst: Add tests for workers/45367's issue about double slashes in 'cd -P' and - /home/daniel/in/zsh. + $PWD. 2020-02-02 Peter Stephenson -- cgit v1.2.3 From 1f238665f6a4f9fce9232d305a95c58f13ed0c5a Mon Sep 17 00:00:00 2001 From: Martin von Wittich Date: Thu, 6 Feb 2020 13:24:00 -0600 Subject: _diff_options: Restore -w completion lost in workers/43351 --- ChangeLog | 6 ++++++ Completion/Unix/Type/_diff_options | 1 + 2 files changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2b0d1d4de..0116724b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2020-02-06 dana + + * Martin von Wittich: 45388 (tweaked): + Completion/Unix/Type/_diff_options: Restore -w completion lost + in workers/43351 + 2020-02-03 Daniel Shahaf * 45368: Test/B01cd.ztst, Test/D02glob.ztst: Add tests for diff --git a/Completion/Unix/Type/_diff_options b/Completion/Unix/Type/_diff_options index 4fd27442e..440913dff 100644 --- a/Completion/Unix/Type/_diff_options +++ b/Completion/Unix/Type/_diff_options @@ -92,6 +92,7 @@ if _pick_variant -r variant -c $cmd gnu=GNU unix -v || [[ $OSTYPE = freebsd<12-> '--ignore-file-name-case[ignore case when comparing file names]' \ '!(--ignore-file-name-case)--no-ignore-file-name-case' \ '(-b --ignore-space-change)'{-b,--ignore-space-change}'[ignore changes in the amount of white space]' \ + '(-w --ignore-all-space)'{-w,--ignore-all-space}'[ignore all white space]' \ '(-B --ignore-blank-lines)'{-B,--ignore-blank-lines}'[ignore lines that are all blank]' \ '(-I --ignore-matching-lines)'{-I+,--ignore-matching-lines=}'[ignore lines that match regex]:line exclusion regex:' \ '--strip-trailing-cr[strip trailing carriage return on input]' \ -- cgit v1.2.3 From 754fdc6580192e81ecc0628349102308868b4857 Mon Sep 17 00:00:00 2001 From: Roman Perepelitsa Date: Thu, 6 Feb 2020 13:42:32 -0600 Subject: zsh/system: Fix infinite loop in sysread --- ChangeLog | 3 +++ Src/Modules/system.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 0116724b1..5b9ed5271 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2020-02-06 dana + * Roman Perepelitsa: 45382: Src/Modules/system.c: Fix infinite + loop in sysread + * Martin von Wittich: 45388 (tweaked): Completion/Unix/Type/_diff_options: Restore -w completion lost in workers/43351 diff --git a/Src/Modules/system.c b/Src/Modules/system.c index 50de59cf9..fb3d80773 100644 --- a/Src/Modules/system.c +++ b/Src/Modules/system.c @@ -174,7 +174,7 @@ bin_sysread(char *nam, char **args, Options ops, UNUSED(int func)) } while ((ret = select(infd+1, (SELECT_ARG_2_T) &fds, - NULL, NULL,&select_tv)) < 1) { + NULL, NULL,&select_tv)) < 0) { if (errno != EINTR || errflag || retflag || breaks || contflag) break; } -- cgit v1.2.3 From 643de931640e01aa246723d2038328ef33737965 Mon Sep 17 00:00:00 2001 From: dana Date: Thu, 6 Feb 2020 14:01:53 -0600 Subject: unposted: Test release: 5.7.1-test-3 --- ChangeLog | 2 ++ Config/version.mk | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5b9ed5271..d13fb6e0f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2020-02-06 dana + * unposted: Config/version.mk: Update for 5.7.1-test-3 + * Roman Perepelitsa: 45382: Src/Modules/system.c: Fix infinite loop in sysread diff --git a/Config/version.mk b/Config/version.mk index 99d8f965c..2ddb92388 100644 --- a/Config/version.mk +++ b/Config/version.mk @@ -27,5 +27,5 @@ # This must also serve as a shell script, so do not add spaces around the # `=' signs. -VERSION=5.7.1-test-2 -VERSION_DATE='December 21, 2019' +VERSION=5.7.1-test-3 +VERSION_DATE='February 6, 2020' -- cgit v1.2.3 From 699dfdd0ea25d01177f603461473f4e0c88f7378 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 6 Feb 2020 12:47:39 +0000 Subject: 45385: Add a test for 'zmodload -Fa' preemptively disabling ("blacklisting"?) features. --- ChangeLog | 5 +++++ Test/V01zmodload.ztst | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/ChangeLog b/ChangeLog index d13fb6e0f..ea80ad5bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-02-06 Daniel Shahaf + + * 45385: Test/V01zmodload.ztst: Add a test for 'zmodload -Fa' + preemptively disabling ("blacklisting"?) features. + 2020-02-06 dana * unposted: Config/version.mk: Update for 5.7.1-test-3 diff --git a/Test/V01zmodload.ztst b/Test/V01zmodload.ztst index 1bd8c1900..6a4e34d2d 100644 --- a/Test/V01zmodload.ztst +++ b/Test/V01zmodload.ztst @@ -348,6 +348,20 @@ ?(eval):6: unknown function: systell ?(eval):9: file descriptor out of range + $ZTST_testdir/../Src/zsh -fc ' + zmodload zsh/zutil + zmodload -Fal zsh/zutil | grep parse + zmodload -u zsh/zutil + # + zmodload -Fa zsh/zutil -b:zregexparse + zmodload zsh/zutil + zmodload -Fal zsh/zutil | grep parse >&2 + ' +0:zmodload -Fa can disable features from being loaded +>b:zparseopts +>b:zregexparse +?b:zparseopts + %clean eval "$deps" -- cgit v1.2.3 From 8037462895b4de98528a6b56c2f35d606150d3f3 Mon Sep 17 00:00:00 2001 From: dana Date: Fri, 7 Feb 2020 14:05:48 -0600 Subject: unposted: _zip: Recognise '--' --- ChangeLog | 4 ++++ Completion/Unix/Command/_zip | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index ea80ad5bc..b71c1bd8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2020-02-07 dana + + * unposted: Completion/Unix/Command/_zip: Recognise '--' + 2020-02-06 Daniel Shahaf * 45385: Test/V01zmodload.ztst: Add a test for 'zmodload -Fa' diff --git a/Completion/Unix/Command/_zip b/Completion/Unix/Command/_zip index 1b1b6c315..bc9aab1a5 100644 --- a/Completion/Unix/Command/_zip +++ b/Completion/Unix/Command/_zip @@ -82,7 +82,7 @@ case $service in '*:file:->files' && ret=0 ;; unzip) - _arguments -C -s \ + _arguments -C -s -S \ '(-Z)-M[page output]' \ - unzip \ '(-f -u -l -t -z -d -p)-c[extract files to stdout including file names]' \ @@ -130,7 +130,7 @@ esac [[ $state == zipinfo ]] && uzi="-Z[zipinfo mode]" if [[ $service == zipinfo ]] || [[ -n $uzi ]]; then - _arguments -C -s \ + _arguments -C -s -S \ $uzi \ '(-2 -s -m -l -v -h -t -T -z)-1[filenames only]' \ '(-1 -s -m -l -v -T)-2[just filenames but allow -h/-t/-z]' \ @@ -170,7 +170,7 @@ case $state in fi 2>/dev/null if [[ $zipfile != $_zip_cache_name ]]; then _zip_cache_name="$zipfile" - _zip_cache_list=( ${(f)"$(zipinfo -1 $_zip_cache_name)"} ) + _zip_cache_list=( ${(f)"$(zipinfo -1 -- $_zip_cache_name)"} ) fi _wanted files expl 'file from archive' \ _multi_parts / _zip_cache_list && return -- cgit v1.2.3 From dd523255cc67780f2e073136d7f44978f96534a7 Mon Sep 17 00:00:00 2001 From: dana Date: Fri, 14 Feb 2020 09:42:12 -0600 Subject: 45423: _su: Improve arg handling, shell look-ups Differences from ML post: * Properly fix escaping issue with $usr (needs unescaped first) * Make $shell emptiness check easier to read (per feedback) --- ChangeLog | 5 +++++ Completion/Unix/Command/_su | 45 +++++++++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index b71c1bd8c..f23a956b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-02-14 dana + + * 45423 (tweaked): Completion/Unix/Command/_su: Improve arg + handling, shell look-ups + 2020-02-07 dana * unposted: Completion/Unix/Command/_zip: Recognise '--' diff --git a/Completion/Unix/Command/_su b/Completion/Unix/Command/_su index 900905632..032f867f4 100644 --- a/Completion/Unix/Command/_su +++ b/Completion/Unix/Command/_su @@ -9,36 +9,44 @@ local shell usr (( $words[(i)-(l|-login)] < CURRENT )) || args=( '-[use a login shell]' ) case $OSTYPE in linux*) + # Some of these options only apply to util-linux, not shadow-utils args=( -S $args - '(-c --command --session-command *)'{-c,--command=}'[pass command to shell]:command string:_cmdstring' + '(-c --command --session-command *)'{-c+,--command=}'[pass command to shell]:command string:_cmdstring' "(-c --command *)--session-command=[pass command to shell and don't create a new session]:command string:_cmdstring" '(--fast -f)'{-f,--fast}'[pass -f to shell]' '(-l --login -m -p --preserve-environment)'{-l,--login}'[use a login shell]' '(-l --login -m -p --preserve-environment)'{-m,-p,--preserve-environment}"[don't reset environment]" - '(-s --shell)'{-s,--shell=}'[run the specified shell]:shell:->shells' + '(-s --shell)'{-s+,--shell=}'[run the specified shell]:shell:->shells' '(-)--help[display help information]' '(-)--version[display version information]' ) - (( EUID )) || args+=( - '(-g --group)'{-g,--group=}'[specify primary group]:group:_groups' - \*{-G,--supp-group=}'[specify supplemental group]:group:_groups' + (( $#_comp_priv_prefix || EUID == 0 )) && args+=( + '(-g --group)'{-g+,--group=}'[specify primary group]:group:_groups' + \*{-G+,--supp-group=}'[specify supplemental group]:group:_groups' ) first="(--help --version)${first#???}" ;; *bsd*|darwin*|dragonfly*) args+=( - '-c[use settings from specified login class]:class' '-f[if the invoked shell is csh, prevent it from reading .cshrc]' '(-m)-l[use a login shell]' "(-l)-m[don't reset environment]" ) ;| + *bsd*|dragonfly*) + args+=( + '-c+[use settings from specified login class]:class' + ) + ;| freebsd*) args+=( '-s[set the MAC label]' ) ;; openbsd*) args+=( - '(-K)-a[specify authentication type]:authentication type' + # See login.conf(5) + '(-K)-a+[specify authentication type]:authentication type:( + activ chpass crypto lchpass passwd radius reject skey snk token yubikey + )' '(-a)-K[shorthand for -a passwd]' - '-s[run the specified shell]:shell:->shells' + '-s+[run the specified shell]:shell:->shells' '-L[loop until login succeeds]' ) ;; @@ -57,13 +65,26 @@ fi _arguments $args ${(e)first} "*:shell arguments:= ->rest" && return -usr=${line[norm]/--/root} -if (( $#opt_args[(i)-(s|-shell)] )); then +usr=${${(Q)line[norm]}/--/root} +# OpenBSD supports appending a log-in method to the user name, as in usr:radius +[[ $OSTYPE == openbsd* ]] && usr=${usr%:*} + +# Normal users generally don't appear in passwd on macOS; try the Directory +# Service first +if [[ $OSTYPE == darwin* ]] && (( $+commands[dscl] )); then + shell=${"$( + _call_program shells dscl . -read /Users/${(q)usr} UserShell + )"#UserShell: } +fi + +if [[ -n $shell ]]; then + : # Found above +elif (( ${#${(@M)args:#*-s[+\[]*:*}} && $#opt_args[(i)-(s|-shell)] )); then shell=${(v)opt_args[(i)-(s|-shell)]} elif (( ${+commands[getent]} )); then - shell="${$(_call_program shells getent passwd $usr)##*:}" + shell="${$(_call_program shells getent passwd ${(q)usr})##*:}" else - shell="${${(M@)${(@f)$( Date: Fri, 14 Feb 2020 15:55:52 -0600 Subject: unposted: V01zmodload: Fix failing test from workers/45385 --- ChangeLog | 3 +++ Test/V01zmodload.ztst | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index f23a956b0..2e76e04a7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2020-02-14 dana + * unposted: Test/V01zmodload.ztst: Fix failing test from + workers/45385 + * 45423 (tweaked): Completion/Unix/Command/_su: Improve arg handling, shell look-ups diff --git a/Test/V01zmodload.ztst b/Test/V01zmodload.ztst index 6a4e34d2d..55c3c314b 100644 --- a/Test/V01zmodload.ztst +++ b/Test/V01zmodload.ztst @@ -348,7 +348,9 @@ ?(eval):6: unknown function: systell ?(eval):9: file descriptor out of range - $ZTST_testdir/../Src/zsh -fc ' + $ZTST_testdir/../Src/zsh -fc " + MODULE_PATH=${(q)MODULE_PATH} + # zmodload zsh/zutil zmodload -Fal zsh/zutil | grep parse zmodload -u zsh/zutil @@ -356,7 +358,7 @@ zmodload -Fa zsh/zutil -b:zregexparse zmodload zsh/zutil zmodload -Fal zsh/zutil | grep parse >&2 - ' + " 0:zmodload -Fa can disable features from being loaded >b:zparseopts >b:zregexparse -- cgit v1.2.3 From 24e993db62cf146fb76ebcf677a4a7aa3766fc74 Mon Sep 17 00:00:00 2001 From: Sam Foxman Date: Sun, 22 Dec 2019 17:30:28 -0500 Subject: Drop privileges securely --- Src/options.c | 161 +++++++++++++++++++++++++++++++++++++++++++--------------- configure.ac | 4 +- 2 files changed, 124 insertions(+), 41 deletions(-) diff --git a/Src/options.c b/Src/options.c index 48c14c179..328cf318b 100644 --- a/Src/options.c +++ b/Src/options.c @@ -577,6 +577,7 @@ int bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) { int action, optno, match = 0; + int retval = 0; /* With no arguments or options, display options. */ if (!*args) { @@ -604,18 +605,28 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) inittyptab(); return 1; } - if(!(optno = optlookup(*args))) + if(!(optno = optlookup(*args))) { zwarnnam(nam, "no such option: %s", *args); - else if(dosetopt(optno, action, 0, opts)) - zwarnnam(nam, "can't change option: %s", *args); + retval = 1; + } else { + retval = !!dosetopt(optno, action, 0, opts); + if (retval) { + zwarnnam(nam, "can't change option: %s", *args); + } + } break; } else if(**args == 'm') { match = 1; } else { - if (!(optno = optlookupc(**args))) + if (!(optno = optlookupc(**args))) { zwarnnam(nam, "bad option: -%c", **args); - else if(dosetopt(optno, action, 0, opts)) - zwarnnam(nam, "can't change option: -%c", **args); + retval = 1; + } else { + retval = !!dosetopt(optno, action, 0, opts); + if (retval) { + zwarnnam(nam, "can't change option: -%c", **args); + } + } } } args++; @@ -625,10 +636,15 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) if (!match) { /* Not globbing the arguments -- arguments are simply option names. */ while (*args) { - if(!(optno = optlookup(*args++))) + if(!(optno = optlookup(*args++))) { zwarnnam(nam, "no such option: %s", args[-1]); - else if(dosetopt(optno, !isun, 0, opts)) - zwarnnam(nam, "can't change option: %s", args[-1]); + retval = 1; + } else { + retval = !!dosetopt(optno, !isun, 0, opts); + if (retval) { + zwarnnam(nam, "can't change option: %s", args[-1]); + } + } } } else { /* Globbing option (-m) set. */ @@ -651,7 +667,8 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) tokenize(s); if (!(pprog = patcompile(s, PAT_HEAPDUP, NULL))) { zwarnnam(nam, "bad pattern: %s", *args); - continue; + retval = 1; + break; } /* Loop over expansions. */ scanmatchtable(optiontab, pprog, 0, 0, OPT_ALIAS, @@ -660,7 +677,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) } } inittyptab(); - return 0; + return retval; } /* Identify an option name */ @@ -769,37 +786,101 @@ dosetopt(int optno, int value, int force, char *new_opts) return -1; } else if(optno == PRIVILEGED && !value) { /* unsetting PRIVILEGED causes the shell to make itself unprivileged */ -#ifdef HAVE_SETUID - int ignore_err; - errno = 0; - /* - * Set the GID first as if we set the UID to non-privileged it - * might be impossible to restore the GID. - * - * Some OSes (possibly no longer around) have been known to - * fail silently the first time, so we attempt the change twice. - * If it fails we are guaranteed to pick this up the second - * time, so ignore the first time. - * - * Some versions of gcc make it hard to ignore the results the - * first time, hence the following. (These are probably not - * systems that require the doubled calls.) - */ - ignore_err = setgid(getgid()); - (void)ignore_err; - ignore_err = setuid(getuid()); - (void)ignore_err; - if (setgid(getgid())) { - zwarn("failed to change group ID: %e", errno); - return -1; - } else if (setuid(getuid())) { - zwarn("failed to change user ID: %e", errno); - return -1; + + int skip_setuid = 0; + int skip_setgid = 0; + +#if defined(HAVE_GETEGID) && defined(HAVE_SETGID) && defined(HAVE_GETUID) + int orig_egid = getegid(); +#endif + +#if defined(HAVE_GETEUID) && defined(HAVE_GETUID) + if (geteuid() == getuid()) { + skip_setuid = 1; + } +#endif + +#if defined(HAVE_GETEGID) && defined(HAVE_GETGID) + if (getegid() == getgid()) { + skip_setgid = 1; } +#endif + + if (!skip_setgid) { + int setgid_err; +#ifdef HAVE_SETRESGID + setgid_err = setresgid(getgid(), getgid(), getgid()); +#elif defined(HAVE_SETREGID) +#if defined(HAVE_GETEGID) && defined(HAVE_SETGID) && defined(HAVE_GETUID) + setgid_err = setregid(getgid(), getgid()); #else - zwarn("setuid not available"); - return -1; -#endif /* not HAVE_SETUID */ + zwarnnam("unsetopt", + "PRIVILEGED: can't drop privileges; setregid available, but cannot check if saved gid changed"); + return -1; +#endif +#else + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresgid and setregid not available"); + return -1; +#endif + if (setgid_err) { + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change group ID: %e", errno); + return -1; + } + } + + if (!skip_setuid) { +#if defined(HAVE_GETEUID) && defined(HAVE_SETUID) + int orig_euid = geteuid(); +#endif + int setuid_err; +#if defined(HAVE_GETEUID) && defined(HAVE_INITGROUPS) && defined(HAVE_GETPWUID) + if (geteuid() == 0) { + struct passwd *pw = getpwuid(getuid()); + if (pw == NULL) { + zwarnnam("unsetopt", "can't drop privileges; failed to get user information for uid %d: %e", + getuid(), errno); + return -1; + } + if (initgroups(pw->pw_name, pw->pw_gid)) { + zwarnnam("unsetopt", "can't drop privileges; failed to set supplementary group list: %e", errno); + return -1; + } + } +#endif + +#ifdef HAVE_SETRESUID + setuid_err = setresuid(getuid(), getuid(), getuid()); +#elif defined(HAVE_SETREUID) +#if defined(HAVE_GETEUID) && defined(HAVE_SETUID) && defined(HAVE_GETUID) + setuid_err = setreuid(getuid(), getuid()); +#else + zwarnnam("unsetopt", + "PRIVILEGED: can't drop privileges; setreuid available, but cannot check if saved uid changed"); + return -1; +#endif +#else + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresuid and setreuid not available"); + return -1; +#endif + if (setuid_err) { + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change user ID: %e", errno); + return -1; + } +#if defined(HAVE_GETEUID) && defined(HAVE_SETUID) && defined(HAVE_GETUID) + if (getuid() != 0 && !setuid(orig_euid)) { + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the euid"); + return -1; + } +#endif + } + +#if defined(HAVE_GETEGID) && defined(HAVE_SETGID) && defined(HAVE_GETUID) + if (getuid() != 0 && !skip_setgid && !setgid(orig_egid)) { + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the egid"); + return -1; + } +#endif + #ifdef JOB_CONTROL } else if (!force && optno == MONITOR && value) { if (new_opts[optno] == value) diff --git a/configure.ac b/configure.ac index c8885cac5..2474c270e 100644 --- a/configure.ac +++ b/configure.ac @@ -1310,7 +1310,9 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \ inet_aton inet_pton inet_ntop \ getlogin getpwent getpwnam getpwuid getgrgid getgrnam \ initgroups nis_list \ - setuid seteuid setreuid setresuid setsid \ + getuid setuid seteuid setreuid setresuid setsid \ + getgid setgid setegid setregid setresgid \ + geteuid getegid \ memcpy memmove strstr strerror strtoul \ getrlimit getrusage \ setlocale \ -- cgit v1.2.3 From 8250c5c168f07549ed646e6848e6dda118271e23 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Thu, 26 Dec 2019 09:16:19 +0000 Subject: Improve PRIVILEGED fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix retval handling in bin_setopt() - Don't skip_setuid / skip_setgid. It's not our place to optimize away noops (that might not even _be_ noops; they might change the saved uid…). - Remove HAVE_* guard checks around functions that are used unguarded elsewhere. - Use bsd-setres_id.c from OpenSSH to provide setresuid() / setresgid() everywhere, and thus simplify the ifdef soup. Fix some preëxisting bugs in the macro definitions of setuid() (do we still need that one?). - Fix zwarning() format codes for variadic arguments type safety - Restored a comment from HEAD - Fix failure modes around initgroups() - Compared privilege restoration code with OpenSSH's permanently_drop_uid() and updated as needed - Add E01 PRIVILEGED sanity checks --- Src/openssh_bsd_setres_id.c | 129 ++++++++++++++++++++++++++++++++++++++ Src/options.c | 148 ++++++++++++++++++++------------------------ Src/zsh.mdd | 3 +- Src/zsh_system.h | 94 +++++++++++++++++++++++----- Test/E01options.ztst | 15 +++++ configure.ac | 5 +- 6 files changed, 292 insertions(+), 102 deletions(-) create mode 100644 Src/openssh_bsd_setres_id.c diff --git a/Src/openssh_bsd_setres_id.c b/Src/openssh_bsd_setres_id.c new file mode 100644 index 000000000..65e91a40c --- /dev/null +++ b/Src/openssh_bsd_setres_id.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2012 Darren Tucker (dtucker at zip com au). + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * openssh_bsd_setres_id.c - setresuid() and setresgid() wrappers + * + * This file is part of zsh, the Z shell. + * + * It is based on the file openbsd-compat/bsd-setres_id.c in OpenSSH 7.9p1, + * which is subject to the copyright notice above. The zsh modifications are + * licensed as follows: + * + * Copyright (c) 2019 Daniel Shahaf + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Daniel Shahaf or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Daniel Shahaf and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Daniel Shahaf and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Daniel Shahaf and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + + +#include + +#include +#include +#include + +#include "zsh.mdh" + +#if defined(ZSH_IMPLEMENT_SETRESGID) || defined(BROKEN_SETRESGID) +int +setresgid(gid_t rgid, gid_t egid, gid_t sgid) +{ + int ret = 0, saved_errno; + + if (rgid != sgid) { + errno = ENOSYS; + return -1; + } +#if defined(ZSH_HAVE_NATIVE_SETREGID) && !defined(BROKEN_SETREGID) + if (setregid(rgid, egid) < 0) { + saved_errno = errno; + zwarnnam("setregid", "to gid %L: %e", (long)rgid, errno); + errno = saved_errno; + ret = -1; + } +#else + if (setegid(egid) < 0) { + saved_errno = errno; + zwarnnam("setegid", "to gid %L: %e", (long)(unsigned int)egid, errno); + errno = saved_errno; + ret = -1; + } + if (setgid(rgid) < 0) { + saved_errno = errno; + zwarnnam("setgid", "to gid %L: %e", (long)rgid, errno); + errno = saved_errno; + ret = -1; + } +#endif + return ret; +} +#endif + +#if defined(ZSH_IMPLEMENT_SETRESUID) || defined(BROKEN_SETRESUID) +int +setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + int ret = 0, saved_errno; + + if (ruid != suid) { + errno = ENOSYS; + return -1; + } +#if defined(ZSH_HAVE_NATIVE_SETREUID) && !defined(BROKEN_SETREUID) + if (setreuid(ruid, euid) < 0) { + saved_errno = errno; + zwarnnam("setreuid", "to uid %L: %e", (long)ruid, errno); + errno = saved_errno; + ret = -1; + } +#else + +# ifndef SETEUID_BREAKS_SETUID + if (seteuid(euid) < 0) { + saved_errno = errno; + zwarnnam("seteuid", "to uid %L: %e", (long)euid, errno); + errno = saved_errno; + ret = -1; + } +# endif + if (setuid(ruid) < 0) { + saved_errno = errno; + zwarnnam("setuid", "to uid %L: %e", (long)ruid, errno); + errno = saved_errno; + ret = -1; + } +#endif + return ret; +} +#endif diff --git a/Src/options.c b/Src/options.c index 328cf318b..425e27dc2 100644 --- a/Src/options.c +++ b/Src/options.c @@ -607,25 +607,21 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) } if(!(optno = optlookup(*args))) { zwarnnam(nam, "no such option: %s", *args); - retval = 1; - } else { - retval = !!dosetopt(optno, action, 0, opts); - if (retval) { - zwarnnam(nam, "can't change option: %s", *args); - } + retval |= 1; + } else if (dosetopt(optno, action, 0, opts)) { + zwarnnam(nam, "can't change option: %s", *args); + retval |= 1; } break; } else if(**args == 'm') { match = 1; } else { - if (!(optno = optlookupc(**args))) { + if (!(optno = optlookupc(**args))) { zwarnnam(nam, "bad option: -%c", **args); - retval = 1; - } else { - retval = !!dosetopt(optno, action, 0, opts); - if (retval) { - zwarnnam(nam, "can't change option: -%c", **args); - } + retval |= 1; + } else if (dosetopt(optno, action, 0, opts)) { + zwarnnam(nam, "can't change option: -%c", **args); + retval |= 1; } } } @@ -638,12 +634,10 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) while (*args) { if(!(optno = optlookup(*args++))) { zwarnnam(nam, "no such option: %s", args[-1]); - retval = 1; - } else { - retval = !!dosetopt(optno, !isun, 0, opts); - if (retval) { - zwarnnam(nam, "can't change option: %s", args[-1]); - } + retval |= 1; + } else if (dosetopt(optno, !isun, 0, opts)) { + zwarnnam(nam, "can't change option: %s", args[-1]); + retval |= 1; } } } else { @@ -667,7 +661,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) tokenize(s); if (!(pprog = patcompile(s, PAT_HEAPDUP, NULL))) { zwarnnam(nam, "bad pattern: %s", *args); - retval = 1; + retval |= 1; break; } /* Loop over expansions. */ @@ -787,100 +781,92 @@ dosetopt(int optno, int value, int force, char *new_opts) } else if(optno == PRIVILEGED && !value) { /* unsetting PRIVILEGED causes the shell to make itself unprivileged */ - int skip_setuid = 0; - int skip_setgid = 0; - -#if defined(HAVE_GETEGID) && defined(HAVE_SETGID) && defined(HAVE_GETUID) - int orig_egid = getegid(); -#endif + /* If set, return -1 so lastval will be non-zero. */ + int failed = 0; -#if defined(HAVE_GETEUID) && defined(HAVE_GETUID) - if (geteuid() == getuid()) { - skip_setuid = 1; - } +#ifdef HAVE_SETUID + const int orig_euid = geteuid(); #endif + const int orig_egid = getegid(); -#if defined(HAVE_GETEGID) && defined(HAVE_GETGID) - if (getegid() == getgid()) { - skip_setgid = 1; - } -#endif - - if (!skip_setgid) { - int setgid_err; -#ifdef HAVE_SETRESGID - setgid_err = setresgid(getgid(), getgid(), getgid()); -#elif defined(HAVE_SETREGID) -#if defined(HAVE_GETEGID) && defined(HAVE_SETGID) && defined(HAVE_GETUID) - setgid_err = setregid(getgid(), getgid()); -#else - zwarnnam("unsetopt", - "PRIVILEGED: can't drop privileges; setregid available, but cannot check if saved gid changed"); + /* + * Set the GID first as if we set the UID to non-privileged it + * might be impossible to restore the GID. + */ + { +#ifndef HAVE_SETRESGID + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresgid() and friends not available"); return -1; -#endif #else - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresgid and setregid not available"); - return -1; -#endif + int setgid_err; + setgid_err = setresgid(getgid(), getgid(), getgid()); if (setgid_err) { zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change group ID: %e", errno); return -1; } +#endif } - if (!skip_setuid) { -#if defined(HAVE_GETEUID) && defined(HAVE_SETUID) - int orig_euid = geteuid(); -#endif + /* Set the UID second. */ + { +#ifndef HAVE_SETRESUID + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresuid() and friends not available"); + return -1; +#else int setuid_err; -#if defined(HAVE_GETEUID) && defined(HAVE_INITGROUPS) && defined(HAVE_GETPWUID) + +# ifdef HAVE_INITGROUPS + /* Set the supplementary groups list. */ if (geteuid() == 0) { struct passwd *pw = getpwuid(getuid()); if (pw == NULL) { - zwarnnam("unsetopt", "can't drop privileges; failed to get user information for uid %d: %e", - getuid(), errno); - return -1; - } - if (initgroups(pw->pw_name, pw->pw_gid)) { + zwarnnam("unsetopt", "can't drop privileges; failed to get user information for uid %L: %e", + (long)getuid(), errno); + failed = 1; + } else if (initgroups(pw->pw_name, pw->pw_gid)) { zwarnnam("unsetopt", "can't drop privileges; failed to set supplementary group list: %e", errno); return -1; } + } else if (getuid() != 0 && + (geteuid() != getuid() || orig_egid != getegid())) { + zwarnnam("unsetopt", "PRIVILEGED: supplementary group list not changed due to lack of permissions: EUID=%L", + (long)geteuid()); + failed = 1; } -#endif +# else + /* initgroups() isn't in POSIX. If it's not available on the system, + * we silently skip it. */ +# endif -#ifdef HAVE_SETRESUID setuid_err = setresuid(getuid(), getuid(), getuid()); -#elif defined(HAVE_SETREUID) -#if defined(HAVE_GETEUID) && defined(HAVE_SETUID) && defined(HAVE_GETUID) - setuid_err = setreuid(getuid(), getuid()); -#else - zwarnnam("unsetopt", - "PRIVILEGED: can't drop privileges; setreuid available, but cannot check if saved uid changed"); - return -1; -#endif -#else - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresuid and setreuid not available"); - return -1; -#endif if (setuid_err) { zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change user ID: %e", errno); return -1; } -#if defined(HAVE_GETEUID) && defined(HAVE_SETUID) && defined(HAVE_GETUID) - if (getuid() != 0 && !setuid(orig_euid)) { - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the euid"); - return -1; - } #endif } -#if defined(HAVE_GETEGID) && defined(HAVE_SETGID) && defined(HAVE_GETUID) - if (getuid() != 0 && !skip_setgid && !setgid(orig_egid)) { +#ifdef HAVE_SETGID + if (getuid() != 0 && orig_egid != getegid() && + (setgid(orig_egid) != -1 || setegid(orig_egid) != -1)) { zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the egid"); return -1; } #endif +#ifdef HAVE_SETUID + if (getuid() != 0 && orig_euid != geteuid() && + (setuid(orig_euid) != -1 || seteuid(orig_euid) != -1)) { + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the euid"); + return -1; + } +#endif + + if (failed) { + /* A warning message has been printed. */ + return -1; + } + #ifdef JOB_CONTROL } else if (!force && optno == MONITOR && value) { if (new_opts[optno] == value) diff --git a/Src/zsh.mdd b/Src/zsh.mdd index 3e5788af5..9bcaccae5 100644 --- a/Src/zsh.mdd +++ b/Src/zsh.mdd @@ -13,7 +13,8 @@ objects="builtin.o compat.o cond.o context.o \ exec.o glob.o hashtable.o hashnameddir.o \ hist.o init.o input.o jobs.o lex.o linklist.o loop.o math.o \ mem.o module.o options.o params.o parse.o pattern.o prompt.o signals.o \ -signames.o sort.o string.o subst.o text.o utils.o watch.o" +signames.o sort.o string.o subst.o text.o utils.o watch.o \ +openssh_bsd_setres_id.o" headers="../config.h zsh_system.h zsh.h sigcount.h signals.h \ prototypes.h hashtable.h ztype.h" diff --git a/Src/zsh_system.h b/Src/zsh_system.h index 85e198f2e..161b073b4 100644 --- a/Src/zsh_system.h +++ b/Src/zsh_system.h @@ -468,30 +468,90 @@ struct timespec { # define setpgrp setpgid #endif -/* can we set the user/group id of a process */ +/* compatibility wrappers */ -#ifndef HAVE_SETUID +/* Our strategy is as follows: + * + * - Ensure that either setre[ug]id() or set{e,}[ug]id() is available. + * - If setres[ug]id() are missing, provide them in terms of either + * setre[ug]id() or set{e,}[ug]id(), whichever is available. + * - Provide replacement setre[ug]id() or set{e,}[ug]id() if they are not + * available natively. + * + * There isn't a circular dependency because, right off the bat, we check that + * there's an end condition, and #error out otherwise. + */ +#if !defined(HAVE_SETREUID) && !(defined(HAVE_SETEUID) && defined(HAVE_SETUID)) + /* + * If you run into this error, you have two options: + * - Teach zsh how to do the equivalent of setreuid() on your system + * - Remove support for PRIVILEGED option, and then remove the #error. + */ +# error "Don't know how to change UID" +#endif +#if !defined(HAVE_SETREGID) && !(defined(HAVE_SETEGID) && defined(HAVE_SETGID)) + /* See above comment. */ +# error "Don't know how to change GID" +#endif + +/* Provide setresuid(). */ +#ifndef HAVE_SETRESUID +int setresuid(uid_t, uid_t, uid_t); +# define HAVE_SETRESUID +# define ZSH_IMPLEMENT_SETRESUID # ifdef HAVE_SETREUID -# define setuid(X) setreuid(X,X) -# define setgid(X) setregid(X,X) -# define HAVE_SETUID +# define ZSH_HAVE_NATIVE_SETREUID # endif #endif -/* can we set the effective user/group id of a process */ +/* Provide setresgid(). */ +#ifndef HAVE_SETRESGID +int setresgid(gid_t, gid_t, gid_t); +# define HAVE_SETRESGID +# define ZSH_IMPLEMENT_SETRESGID +# ifdef HAVE_SETREGID +# define ZSH_HAVE_NATIVE_SETREGID +# endif +#endif +/* Provide setreuid(). */ +#ifndef HAVE_SETREUID +# define setreuid(X, Y) setresuid((X), (Y), -1) +# define HAVE_SETREUID +#endif + +/* Provide setregid(). */ +#ifndef HAVE_SETREGID +# define setregid(X, Y) setresgid((X), (Y), -1) +# define HAVE_SETREGID +#endif + +/* Provide setuid(). */ +/* ### TODO: Either remove this (this function has been standard since 1985), + * ### or rewrite this without multiply-evaluating the argument */ +#ifndef HAVE_SETUID +# define setuid(X) setreuid((X), (X)) +# define HAVE_SETUID +#endif + +/* Provide setgid(). */ +#ifndef HAVE_SETGID +/* ### TODO: Either remove this (this function has been standard since 1985), + * ### or rewrite this without multiply-evaluating the argument */ +# define setgid(X) setregid((X), (X)) +# define HAVE_SETGID +#endif + +/* Provide seteuid(). */ #ifndef HAVE_SETEUID -# ifdef HAVE_SETREUID -# define seteuid(X) setreuid(-1,X) -# define setegid(X) setregid(-1,X) -# define HAVE_SETEUID -# else -# ifdef HAVE_SETRESUID -# define seteuid(X) setresuid(-1,X,-1) -# define setegid(X) setresgid(-1,X,-1) -# define HAVE_SETEUID -# endif -# endif +# define seteuid(X) setreuid(-1, (X)) +# define HAVE_SETEUID +#endif + +/* Provide setegid(). */ +#ifndef HAVE_SETEGID +# define setegid(X) setregid(-1, (X)) +# define HAVE_SETEGID #endif #ifdef HAVE_SYS_RESOURCE_H diff --git a/Test/E01options.ztst b/Test/E01options.ztst index c4b101bdb..680f49082 100644 --- a/Test/E01options.ztst +++ b/Test/E01options.ztst @@ -1391,3 +1391,18 @@ F:Regression test for workers/41811 ?(anon):4: `break' active at end of function scope ?(anon):4: `break' active at end of function scope ?(anon):4: `break' active at end of function scope + +# There are further tests for PRIVILEGED in P01privileged.ztst. + if [[ -o privileged ]]; then + unsetopt privileged + fi + unsetopt privileged +0:PRIVILEGED sanity check: unsetting is idempotent +F:If this test fails at the first unsetopt, refer to P01privileged.ztst. + + if [[ -o privileged ]]; then + (( UID != EUID )) + else + (( UID == EUID )) + fi +0:PRIVILEGED sanity check: default value is correct diff --git a/configure.ac b/configure.ac index 2474c270e..f2d65ecfc 100644 --- a/configure.ac +++ b/configure.ac @@ -1310,9 +1310,8 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \ inet_aton inet_pton inet_ntop \ getlogin getpwent getpwnam getpwuid getgrgid getgrnam \ initgroups nis_list \ - getuid setuid seteuid setreuid setresuid setsid \ - getgid setgid setegid setregid setresgid \ - geteuid getegid \ + setuid seteuid setreuid setresuid setsid \ + setgid setegid setregid setresgid \ memcpy memmove strstr strerror strtoul \ getrlimit getrusage \ setlocale \ -- cgit v1.2.3 From 26d02efa7a9b0a6b32e1a8bbc6aca6c544b94211 Mon Sep 17 00:00:00 2001 From: dana Date: Sun, 29 Dec 2019 02:41:11 +0000 Subject: Improve PRIVILEGED fixes (again) * Pass RGID instead of passwd GID to initgroups() * Clean up #ifdefs, avoid unnecessary checks * Flatten conditions --- Src/options.c | 92 ++++++++++++++++++++++++++++------------------------------- 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/Src/options.c b/Src/options.c index 425e27dc2..e9577c863 100644 --- a/Src/options.c +++ b/Src/options.c @@ -781,91 +781,85 @@ dosetopt(int optno, int value, int force, char *new_opts) } else if(optno == PRIVILEGED && !value) { /* unsetting PRIVILEGED causes the shell to make itself unprivileged */ +/* For simplicity's sake, require both setresgid() and setresuid() up-front. */ +#if !defined(HAVE_SETRESGID) + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresgid() and friends not available"); + return -1; +#elif !defined(HAVE_SETRESUID) + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresuid() and friends not available"); + return -1; +#else /* If set, return -1 so lastval will be non-zero. */ int failed = 0; - -#ifdef HAVE_SETUID const int orig_euid = geteuid(); -#endif const int orig_egid = getegid(); /* * Set the GID first as if we set the UID to non-privileged it * might be impossible to restore the GID. */ - { -#ifndef HAVE_SETRESGID - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresgid() and friends not available"); + if (setresgid(getgid(), getgid(), getgid())) { + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change group ID: %e", errno); return -1; -#else - int setgid_err; - setgid_err = setresgid(getgid(), getgid(), getgid()); - if (setgid_err) { - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change group ID: %e", errno); - return -1; - } -#endif } - /* Set the UID second. */ - { -#ifndef HAVE_SETRESUID - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresuid() and friends not available"); - return -1; -#else - int setuid_err; - # ifdef HAVE_INITGROUPS - /* Set the supplementary groups list. */ - if (geteuid() == 0) { - struct passwd *pw = getpwuid(getuid()); - if (pw == NULL) { - zwarnnam("unsetopt", "can't drop privileges; failed to get user information for uid %L: %e", - (long)getuid(), errno); - failed = 1; - } else if (initgroups(pw->pw_name, pw->pw_gid)) { - zwarnnam("unsetopt", "can't drop privileges; failed to set supplementary group list: %e", errno); - return -1; - } - } else if (getuid() != 0 && - (geteuid() != getuid() || orig_egid != getegid())) { - zwarnnam("unsetopt", "PRIVILEGED: supplementary group list not changed due to lack of permissions: EUID=%L", - (long)geteuid()); + /* Set the supplementary groups list. + * + * Note that on macOS, FreeBSD, and possibly some other platforms, + * initgroups() resets the EGID to its second argument (see setgroups(2) for + * details). This has the potential to leave the EGID in an unexpected + * state. However, it seems common in other projects that do this dance to + * simply re-use the same GID that's going to become the EGID anyway, in + * which case it doesn't matter. That's what we do here. It's therefore + * possible, in some probably uncommon cases, that the shell ends up not + * having the privileges of the RUID user's primary/passwd group. */ + if (geteuid() == 0) { + struct passwd *pw = getpwuid(getuid()); + if (pw == NULL) { + zwarnnam("unsetopt", "can't drop privileges; failed to get user information for uid %L: %e", + (long)getuid(), errno); failed = 1; + /* This may behave strangely in the unlikely event that the same user + * name appears with multiple UIDs in the passwd database */ + } else if (initgroups(pw->pw_name, getgid())) { + zwarnnam("unsetopt", "can't drop privileges; failed to set supplementary group list: %e", errno); + return -1; } + } else if (getuid() != 0 && + (geteuid() != getuid() || orig_egid != getegid())) { + zwarnnam("unsetopt", "PRIVILEGED: supplementary group list not changed due to lack of permissions: EUID=%L", + (long)geteuid()); + failed = 1; + } # else - /* initgroups() isn't in POSIX. If it's not available on the system, - * we silently skip it. */ + /* initgroups() isn't in POSIX. If it's not available on the system, + * we silently skip it. */ # endif - setuid_err = setresuid(getuid(), getuid(), getuid()); - if (setuid_err) { - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change user ID: %e", errno); - return -1; - } -#endif + /* Set the UID second. */ + if (setresuid(getuid(), getuid(), getuid())) { + zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change user ID: %e", errno); + return -1; } -#ifdef HAVE_SETGID if (getuid() != 0 && orig_egid != getegid() && (setgid(orig_egid) != -1 || setegid(orig_egid) != -1)) { zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the egid"); return -1; } -#endif -#ifdef HAVE_SETUID if (getuid() != 0 && orig_euid != geteuid() && (setuid(orig_euid) != -1 || seteuid(orig_euid) != -1)) { zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the euid"); return -1; } -#endif if (failed) { /* A warning message has been printed. */ return -1; } +#endif /* HAVE_SETRESGID && HAVE_SETRESUID */ #ifdef JOB_CONTROL } else if (!force && optno == MONITOR && value) { -- cgit v1.2.3 From 4ce66857b71b40a0661df3780ff557f2b0f4cb13 Mon Sep 17 00:00:00 2001 From: dana Date: Sun, 29 Dec 2019 02:43:14 +0000 Subject: Clean up error-message white space --- Src/options.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/Src/options.c b/Src/options.c index e9577c863..08ba71917 100644 --- a/Src/options.c +++ b/Src/options.c @@ -783,10 +783,12 @@ dosetopt(int optno, int value, int force, char *new_opts) /* For simplicity's sake, require both setresgid() and setresuid() up-front. */ #if !defined(HAVE_SETRESGID) - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresgid() and friends not available"); + zwarnnam("unsetopt", + "PRIVILEGED: can't drop privileges; setresgid() and friends not available"); return -1; #elif !defined(HAVE_SETRESUID) - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; setresuid() and friends not available"); + zwarnnam("unsetopt", + "PRIVILEGED: can't drop privileges; setresuid() and friends not available"); return -1; #else /* If set, return -1 so lastval will be non-zero. */ @@ -799,7 +801,9 @@ dosetopt(int optno, int value, int force, char *new_opts) * might be impossible to restore the GID. */ if (setresgid(getgid(), getgid(), getgid())) { - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change group ID: %e", errno); + zwarnnam("unsetopt", + "PRIVILEGED: can't drop privileges; failed to change group ID: %e", + errno); return -1; } @@ -817,18 +821,22 @@ dosetopt(int optno, int value, int force, char *new_opts) if (geteuid() == 0) { struct passwd *pw = getpwuid(getuid()); if (pw == NULL) { - zwarnnam("unsetopt", "can't drop privileges; failed to get user information for uid %L: %e", + zwarnnam("unsetopt", + "can't drop privileges; failed to get user information for uid %L: %e", (long)getuid(), errno); failed = 1; /* This may behave strangely in the unlikely event that the same user * name appears with multiple UIDs in the passwd database */ } else if (initgroups(pw->pw_name, getgid())) { - zwarnnam("unsetopt", "can't drop privileges; failed to set supplementary group list: %e", errno); + zwarnnam("unsetopt", + "can't drop privileges; failed to set supplementary group list: %e", + errno); return -1; } } else if (getuid() != 0 && (geteuid() != getuid() || orig_egid != getegid())) { - zwarnnam("unsetopt", "PRIVILEGED: supplementary group list not changed due to lack of permissions: EUID=%L", + zwarnnam("unsetopt", + "PRIVILEGED: supplementary group list not changed due to lack of permissions: EUID=%L", (long)geteuid()); failed = 1; } @@ -839,19 +847,23 @@ dosetopt(int optno, int value, int force, char *new_opts) /* Set the UID second. */ if (setresuid(getuid(), getuid(), getuid())) { - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; failed to change user ID: %e", errno); + zwarnnam("unsetopt", + "PRIVILEGED: can't drop privileges; failed to change user ID: %e", + errno); return -1; } if (getuid() != 0 && orig_egid != getegid() && (setgid(orig_egid) != -1 || setegid(orig_egid) != -1)) { - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the egid"); + zwarnnam("unsetopt", + "PRIVILEGED: can't drop privileges; was able to restore the egid"); return -1; } if (getuid() != 0 && orig_euid != geteuid() && (setuid(orig_euid) != -1 || seteuid(orig_euid) != -1)) { - zwarnnam("unsetopt", "PRIVILEGED: can't drop privileges; was able to restore the euid"); + zwarnnam("unsetopt", + "PRIVILEGED: can't drop privileges; was able to restore the euid"); return -1; } -- cgit v1.2.3 From b15bd4aa590db8087d1e8f2eb1af2874f5db814d Mon Sep 17 00:00:00 2001 From: dana Date: Sat, 28 Dec 2019 20:45:55 -0600 Subject: Add unsetopt/PRIVILEGED tests --- Test/E01options.ztst | 10 ++- Test/P01privileged.ztst | 197 ++++++++++++++++++++++++++++++++++++++++++++++++ Test/README | 1 + 3 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 Test/P01privileged.ztst diff --git a/Test/E01options.ztst b/Test/E01options.ztst index 680f49082..cfe2c75cc 100644 --- a/Test/E01options.ztst +++ b/Test/E01options.ztst @@ -74,7 +74,6 @@ # HASH_LIST_ALL ) # PRINT_EXIT_STATUS haven't worked out what this does yet, although # Bart suggested a fix. -# PRIVILEGED (similar to GLOBAL_RCS) # RCS ( " " " " ) # SH_OPTION_LETTERS even I found this too dull to set up a test for # SINGLE_COMMAND kills shell @@ -95,6 +94,15 @@ %test + # setopt should move on to the next operation in the face of an error, but + # preserve the >0 return code + unsetopt aliases + setopt not_a_real_option aliases && return 2 + print -r - $options[aliases] +0:setopt error handling +?(eval):setopt:4: no such option: not_a_real_option +>on + alias echo='print foo' unsetopt aliases # use eval else aliases are all parsed at start diff --git a/Test/P01privileged.ztst b/Test/P01privileged.ztst new file mode 100644 index 000000000..c54112bb6 --- /dev/null +++ b/Test/P01privileged.ztst @@ -0,0 +1,197 @@ +# This file contains tests related to the PRIVILEGED option. In order to run, +# it requires that the test process itself have super-user privileges (or that +# one of the environment variables described below be set). This can be achieved +# via, e.g., `sudo make check TESTNUM=P`. +# +# Optionally, the environment variables ZSH_TEST_UNPRIVILEGED_UID and/or +# ZSH_TEST_UNPRIVILEGED_GID may be set to UID:EUID or GID:EGID pairs, where the +# two IDs in each pair are different, non-0 IDs valid on the system being used +# to run the tests. (The UIDs must both be non-0 to effectively test downgrading +# of privileges, and they must be non-matching to test auto-enabling of +# PRIVILEGED and to ensure that disabling PRIVILEGED correctly resets the saved +# UID. Technically GID 0 is not special, but for simplicity's sake we apply the +# same requirements here.) +# +# If either of the aforementioned environment variables is not set, the test +# script will try to pick the first two >0 IDs from the passwd/group databases +# on the current system. +# +# If either variable is set, the tests will run, but they will likely fail +# without super-user privileges. + +%prep + + # Mind your empty lines here. The logic in this %prep section is somewhat + # complex compared to most others; to avoid lots of nested/duplicated + # conditions we need to make sure that this all gets executed as a single + # function from which we can return early + [[ $EUID == 0 || -n $ZSH_TEST_UNPRIVILEGED_UID$ZSH_TEST_UNPRIVILEGED_GID ]] || { + ZTST_unimplemented='PRIVILEGED tests require super-user privileges (or env var)' + return 1 + } + (( $+commands[perl] )) || { # @todo Eliminate this dependency with a C wrapper? + ZTST_unimplemented='PRIVILEGED tests require Perl' + return 1 + } + grep -qE '#define HAVE_SETRES?UID' $ZTST_testdir/../config.h || { + ZTST_unimplemented='PRIVILEGED tests require setreuid()/setresuid()' + return 1 + } + # + ruid= euid= rgid= egid= + # + if [[ -n $ZSH_TEST_UNPRIVILEGED_UID ]]; then + ruid=${ZSH_TEST_UNPRIVILEGED_UID%%:*} + euid=${ZSH_TEST_UNPRIVILEGED_UID##*:} + else + print -ru$ZTST_fd 'Selecting unprivileged UID:EUID pair automatically' + local tmp=$( getent passwd 2> /dev/null || < /etc/passwd ) + # Note: Some awks require -v and its argument to be separate + ruid=$( awk -F: '$3 > 0 { print $3; exit; }' <<< $tmp ) + euid=$( awk -F: -v u=$ruid '$3 > u { print $3; exit; }' <<< $tmp ) + fi + # + if [[ -n $ZSH_TEST_UNPRIVILEGED_GID ]]; then + rgid=${ZSH_TEST_UNPRIVILEGED_GID%%:*} + egid=${ZSH_TEST_UNPRIVILEGED_GID##*:} + else + print -ru$ZTST_fd 'Selecting unprivileged GID:EGID pair automatically' + local tmp=$( getent group 2> /dev/null || < /etc/group ) + # Note: Some awks require -v and its argument to be separate + rgid=$( awk -F: '$3 > 0 { print $3; exit; }' <<< $tmp ) + egid=$( awk -F: -v g=$rgid '$3 > g { print $3; exit; }' <<< $tmp ) + fi + # + [[ $ruid/$euid == <1->/<1-> && $ruid != $euid ]] || ruid= euid= + [[ $rgid/$egid == <1->/<1-> && $rgid != $egid ]] || rgid= egid= + # + [[ -n $ruid && -n $euid ]] || { + ZTST_unimplemented='PRIVILEGED tests require unprivileged UID:EUID' + return 1 + } + [[ -n $rgid || -n $egid ]] || { + ZTST_unimplemented='PRIVILEGED tests require unprivileged GID:EGID' + return 1 + } + # + print -ru$ZTST_fd \ + "Using unprivileged UID $ruid, EUID $euid, GID $rgid, EGID $egid" + # + # Execute process with specified UID and EUID + # $1 => Real UID + # $2 => Effective UID + # $3 => Real GID + # $4 => Effective GID + # $5 ... => Command + args to execute (must NOT be a shell command string) + re_exec() { + perl -e ' + die("re_exec: not enough arguments") unless (@ARGV >= 5); + my ($ruid, $euid, $rgid, $egid, @cmd) = @ARGV; + foreach my $id ($ruid, $euid, $rgid, $egid) { + die("re_exec: invalid ID: $id") unless ($id =~ /^(-1|\d+)$/a); + } + $< = 0 + $ruid if ($ruid >= 0); + $> = 0 + $euid if ($euid >= 0); + $( = 0 + $rgid if ($rgid >= 0); + $) = 0 + $egid if ($egid >= 0); + exec(@cmd); + die("re_exec: exec failed: $!"); + ' -- "$@" + } + # + # Convenience wrapper for re_exec to call `zsh -c` + # -* ... => (optional) Command-line options to zsh + # $1 => Real UID + # $2 => Effective UID + # $3 => Real GID + # $4 => Effective GID + # $5 ... => zsh command string; multiple strings are joined by \n + re_zsh() { + local -a opts + while [[ $1 == -[A-Za-z-]* ]]; do + opts+=( $1 ) + shift + done + re_exec "$1" "$2" "$3" "$4" $ZTST_exe $opts -fc \ + "MODULE_PATH=${(q)MODULE_PATH}; ${(F)@[5,-1]}" + } + # + # Return one or more random unused UIDs + # $1 ... => Names of parameters to store UIDs in + get_unused_uid() { + while (( $# )); do + local i_=0 uid_= + until [[ -n $uid_ ]]; do + (( ++i_ > 99 )) && return 1 + uid_=$RANDOM + id $uid_ &> /dev/null || break + uid_= + done + : ${(P)1::=$uid_} + shift + done + } + +%test + + re_zsh $ruid $ruid -1 -1 'echo $UID/$EUID $options[privileged]' + re_zsh $euid $euid -1 -1 'echo $UID/$EUID $options[privileged]' + re_zsh $ruid $euid -1 -1 'echo $UID/$EUID $options[privileged]' +0q:PRIVILEGED automatically enabled when RUID != EUID +>$ruid/$ruid off +>$euid/$euid off +>$ruid/$euid on + + re_zsh -1 -1 $rgid $rgid 'echo $GID/$EGID $options[privileged]' + re_zsh -1 -1 $egid $egid 'echo $GID/$EGID $options[privileged]' + re_zsh -1 -1 $rgid $egid 'echo $GID/$EGID $options[privileged]' +0q:PRIVILEGED automatically enabled when RGID != EGID +>$rgid/$rgid off +>$egid/$egid off +>$rgid/$egid on + + re_zsh $ruid $euid -1 -1 'unsetopt privileged; echo $UID/$EUID' +0q:EUID set to RUID after disabling PRIVILEGED +*?zsh:unsetopt:1: PRIVILEGED: supplementary group list not changed * +*?zsh:unsetopt:1: can't change option: privileged +>$ruid/$ruid + + re_zsh 0 $euid -1 -1 'unsetopt privileged && echo $UID/$EUID' +0:RUID/EUID set to 0/0 when privileged after disabling PRIVILEGED +>0/0 + + re_zsh $ruid $euid -1 -1 "unsetopt privileged; UID=$euid" || + re_zsh $ruid $euid -1 -1 "unsetopt privileged; EUID=$euid" +1:not possible to regain EUID when unprivileged after disabling PRIVILEGED +*?zsh:unsetopt:1: PRIVILEGED: supplementary group list not changed * +*?zsh:unsetopt:1: can't change option: privileged +*?zsh:1: failed to change user ID: * +*?zsh:unsetopt:1: PRIVILEGED: supplementary group list not changed * +*?zsh:unsetopt:1: can't change option: privileged +*?zsh:1: failed to change effective user ID: * + + re_zsh -1 -1 $rgid $egid 'unsetopt privileged && echo $GID/$EGID' +0q:EGID set to RGID after disabling PRIVILEGED +>$rgid/$rgid + +# This test also confirms that we can't revert to the original EUID's primary +# GID, which initgroups() may reset the EGID to on some systems + re_zsh $ruid 0 $rgid 0 'unsetopt privileged; GID=0' || + re_zsh $ruid 0 $rgid 0 'unsetopt privileged; EGID=0' +1:not possible to regain EGID when unprivileged after disabling PRIVILEGED +*?zsh:1: failed to change group ID: * +*?zsh:1: failed to change effective group ID: * + + local rruid + grep -qF '#define HAVE_INITGROUPS' $ZTST_testdir/../config.h || { + ZTST_skip='initgroups() not available' + return 1 + } + get_unused_uid rruid || { + ZTST_skip="Can't get unused UID" + return 1 + } + re_zsh $rruid 0 -1 -1 'unsetopt privileged' +1:getpwuid() fails with non-existent RUID and 0 EUID +*?zsh:unsetopt:1: can't drop privileges; failed to get user information * +*?zsh:unsetopt:1: can't change option: privileged diff --git a/Test/README b/Test/README index d012277ce..726d68e72 100644 --- a/Test/README +++ b/Test/README @@ -6,6 +6,7 @@ scripts names: C: shell commands with special syntax D: substititution E: options + P: privileged (needs super-user privileges) V: modules W: builtin interactive commands and constructs X: line editing -- cgit v1.2.3 From 048f40b68b05fdd5f3f8d60cda4e69fce2611331 Mon Sep 17 00:00:00 2001 From: dana Date: Tue, 31 Dec 2019 03:41:28 -0600 Subject: Update NEWS/README --- NEWS | 18 ++++++++++++++++-- README | 11 +++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index af59cb4e6..964e1633f 100644 --- a/NEWS +++ b/NEWS @@ -4,8 +4,22 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH Note also the list of incompatibilities in the README file. -Changes since 5.7.1 -------------------- +Changes since 5.7.1-test-3 +-------------------------- + +CVE-2019-20044: When unsetting the PRIVILEGED option, the shell sets its +effective user and group IDs to match their respective real IDs. On some +platforms (including Linux and macOS, but not FreeBSD), when the RUID and +EUID were both non-zero, it was possible to regain the shell's former +privileges by e.g. assigning to the EUID or EGID parameter. In the course +of investigating this issue, it was also found that the setopt built-in +did not correctly report errors when unsetting the option, which +prevented users from handling them as the documentation recommended. +setopt now returns non-zero if it is unable to safely drop privileges. +[ Reported by Sam Foxman . ] + +Changes from 5.7.1 to 5.7.1-test-3 +---------------------------------- The zsh/zutil module's zparseopts builtin learnt an -F option to abort parsing when an unrecognised option-like parameter is encountered. diff --git a/README b/README index a3701abe5..7f1dd5f92 100644 --- a/README +++ b/README @@ -5,8 +5,9 @@ THE Z SHELL (ZSH) Version ------- -This is version 5.8 of the shell. This is a stable release. There are -a few visible improvements since 5.7 as well as many bugfixes. +This is version 5.8 of the shell. This is a security and feature release. +There are a few visible improvements since 5.7, as well as many bugfixes. +All zsh installations are encouraged to upgrade as soon as possible. Note in particular the changes highlighted under "Incompatibilities since 5.7.1" below. See NEWS for more information. @@ -56,6 +57,12 @@ This only affects you if you override that function in your dotfiles. The cd and chdir builtins no longer interpret operands like -1 and +2 as stack entries when POSIX_CD is enabled. +Dropping privileges with `unsetopt privileged` may fail (with an error +message) on some older and uncommon platforms due to library dependency +changes made in the course of fixing CVE-2019-20044. Please report this +to the zsh-workers mailing list if your system is affected. See NEWS for +more. + Incompatibilities between 5.6.2 and 5.7.1 ----------------------------------------- -- cgit v1.2.3 From 4bec892059cf3e95ab256c3fcbc85daaa648c2d9 Mon Sep 17 00:00:00 2001 From: dana Date: Fri, 14 Feb 2020 11:26:58 -0600 Subject: CVE-2019-20044: Update change log for preceding commits --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2e76e04a7..b66514c37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2020-02-14 dana + * Sam Foxman, Daniel Shahaf, dana: CVE-2019-20044: NEWS, + README, Src/openssh_bsd_setres_id.c, Src/options.c, Src/zsh.mdd, + Src/zsh_system.h, Test/E01options.ztst, Test/P01privileged.ztst, + Test/README, configure.ac: Fix insecure dropping of privileges + when unsetting PRIVILEGED option + * unposted: Test/V01zmodload.ztst: Fix failing test from workers/45385 -- cgit v1.2.3 From 77d203f3fbbd76386bf197f9776269a1de580bb5 Mon Sep 17 00:00:00 2001 From: dana Date: Fri, 14 Feb 2020 11:30:56 -0600 Subject: unposted: Release 5.8 --- ChangeLog | 2 ++ Config/version.mk | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index b66514c37..8d7dfc169 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2020-02-14 dana + * unposted: Config/version.mk: Update for 5.8 + * Sam Foxman, Daniel Shahaf, dana: CVE-2019-20044: NEWS, README, Src/openssh_bsd_setres_id.c, Src/options.c, Src/zsh.mdd, Src/zsh_system.h, Test/E01options.ztst, Test/P01privileged.ztst, diff --git a/Config/version.mk b/Config/version.mk index 2ddb92388..264c11c6b 100644 --- a/Config/version.mk +++ b/Config/version.mk @@ -27,5 +27,5 @@ # This must also serve as a shell script, so do not add spaces around the # `=' signs. -VERSION=5.7.1-test-3 -VERSION_DATE='February 6, 2020' +VERSION=5.8 +VERSION_DATE='February 14, 2020' -- cgit v1.2.3 From 459e2be810b7b01e79c832ee05d7ca7333c7c5fe Mon Sep 17 00:00:00 2001 From: dana Date: Fri, 14 Feb 2020 11:36:15 -0600 Subject: unposted: Post-release version bump --- ChangeLog | 2 ++ Config/version.mk | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8d7dfc169..1b95409a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2020-02-14 dana + * unposted: Config/version.mk: Post-release version bump + * unposted: Config/version.mk: Update for 5.8 * Sam Foxman, Daniel Shahaf, dana: CVE-2019-20044: NEWS, diff --git a/Config/version.mk b/Config/version.mk index 264c11c6b..6540e4b98 100644 --- a/Config/version.mk +++ b/Config/version.mk @@ -27,5 +27,5 @@ # This must also serve as a shell script, so do not add spaces around the # `=' signs. -VERSION=5.8 -VERSION_DATE='February 14, 2020' +VERSION=5.8.0.1-dev +VERSION_DATE='February 15, 2020' -- cgit v1.2.3 From bacad965238158b9ae6ff438ba923725ec128020 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Sun, 16 Feb 2020 00:03:13 +0000 Subject: github #48/0001: vcs_info git: avoid warnings in bare repositories Git 2.25 introduced a change to how git rev-parse --show-toplevel behaves. Traditionally, it succeeded with no output if the user was in a bare repository. Now it dies, printing an error to standard error. Consequently, when the user is in a bare repository with a newer Git, vcs_info prints noisily to standard error. While this is functionally harmless, it is annoying for the shell to print messages from Git every time the prompt is printed, so let's silence the error message. --- ChangeLog | 6 ++++++ Functions/VCS_Info/Backends/VCS_INFO_get_data_git | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 1b95409a8..75751a547 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2020-02-17 brian m. carlson + + * github #48/0001: + Functions/VCS_Info/Backends/VCS_INFO_get_data_git: vcs_info git: + avoid warnings in bare repositories + 2020-02-14 dana * unposted: Config/version.mk: Post-release version bump diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git index ceb4f978a..0128c0981 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git @@ -138,7 +138,7 @@ VCS_INFO_git_handle_patches () { gitdir=${vcs_comm[gitdir]} VCS_INFO_git_getbranch ${gitdir} -gitbase=$( ${vcs_comm[cmd]} rev-parse --show-toplevel ) +gitbase=$( ${vcs_comm[cmd]} rev-parse --show-toplevel 2> /dev/null ) rrn=${gitbase:t} if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-revision ; then gitsha1=$(${vcs_comm[cmd]} rev-parse --quiet --verify HEAD) -- cgit v1.2.3 From 51260963703bbc91944434648ae71a05addbcb05 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Sun, 16 Feb 2020 20:54:12 +0000 Subject: github #48/0002: vcs_info git: properly detect bare repositories We currently detect Git repositories by finding the top level of the working tree, and if we fail to detect it, assume that we're not in a repository. However, there's a case we don't consider: a bare repository. Let's detect if the user is in a bare repository by checking if gitdir is set, and if so, using that if there is no working tree. We now detect bare Git repositories with vcs_info, as expected. --- ChangeLog | 4 ++++ Functions/VCS_Info/Backends/VCS_INFO_get_data_git | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 75751a547..290f1c6af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2020-02-17 brian m. carlson + * github #48/0002: + Functions/VCS_Info/Backends/VCS_INFO_get_data_git: vcs_info git: + properly detect bare repositories + * github #48/0001: Functions/VCS_Info/Backends/VCS_INFO_get_data_git: vcs_info git: avoid warnings in bare repositories diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git index 0128c0981..5ddce72a6 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_git +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_git @@ -139,6 +139,10 @@ VCS_INFO_git_handle_patches () { gitdir=${vcs_comm[gitdir]} VCS_INFO_git_getbranch ${gitdir} gitbase=$( ${vcs_comm[cmd]} rev-parse --show-toplevel 2> /dev/null ) +if [[ -z ${gitbase} ]]; then + # Bare repository + gitbase=${gitdir:P} +fi rrn=${gitbase:t} if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-revision ; then gitsha1=$(${vcs_comm[cmd]} rev-parse --quiet --verify HEAD) -- cgit v1.2.3 From cb5d8bfe8621c8029f97647ec543ce6e7c41fa58 Mon Sep 17 00:00:00 2001 From: Chris Down Date: Mon, 17 Feb 2020 10:11:46 -0500 Subject: 45451: builtins: kill: Add basic test suite This is not totally comprehensive, but at least it's a start for the core functionality. In the next commits, we'll also use this base to add some regression tests. --- ChangeLog | 4 ++++ Test/B11kill.ztst | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 Test/B11kill.ztst diff --git a/ChangeLog b/ChangeLog index 290f1c6af..4d48d787c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2020-02-18 Chris Down + + * 45451: Test/B11kill.ztst: builtins: kill: Add basic test suite + 2020-02-17 brian m. carlson * github #48/0002: diff --git a/Test/B11kill.ztst b/Test/B11kill.ztst new file mode 100644 index 000000000..26d7a11fe --- /dev/null +++ b/Test/B11kill.ztst @@ -0,0 +1,60 @@ +# Tests for the kill builtin. +# +# The exit codes 11 and 19 in this file don't mean anything special; they're +# just exit codes which are specific enough that the failure of `kill` itself +# can be differentiated from exiting due to executing a trap. + +%test + +# Correct invocation + + if zmodload zsh/system &>/dev/null; then + ( + trap 'exit 19' TERM + kill $sysparams[pid] + ) + else + ZTST_skip='Cannot zmodload zsh/system, skipping kill with no sigspec' + fi +19:kill with no sigspec + + + if zmodload zsh/system &>/dev/null; then + ( + trap 'exit 11' USR1 + kill -USR1 $sysparams[pid] + ) + else + ZTST_skip='Cannot zmodload zsh/system, skipping kill with sigspec' + fi +11:kill with sigspec + +# Incorrect invocation + + ( + kill a b c + ) +3:kill with multiple wrong inputs should increment status +?(eval):kill:2: illegal pid: a +?(eval):kill:2: illegal pid: b +?(eval):kill:2: illegal pid: c + + ( + kill -INT a b c + ) +3:kill with sigspec and wrong inputs should increment status +?(eval):kill:2: illegal pid: a +?(eval):kill:2: illegal pid: b +?(eval):kill:2: illegal pid: c + + ( + kill + ) +1:kill with no arguments +?(eval):kill:2: not enough arguments + + ( + kill -INT + ) +1:kill with sigspec only +?(eval):kill:2: not enough arguments -- cgit v1.2.3 From 59258252b501159c2988de3a2d87a18dc17e98b1 Mon Sep 17 00:00:00 2001 From: Chris Down Date: Mon, 17 Feb 2020 10:12:02 -0500 Subject: 45452: builtins: kill: Add `kill ''` regression test with explicit sigspec The version without a sigspec can't be added yet because it would still kill the test runner even in expected-to-fail mode; see workers/45449 for discussion. For the same reason, we use a signal which is non-fatal by default and unlikely to be sent by someone else, SIGURG, to do the expected-to-fail case prior to the fix. --- ChangeLog | 3 +++ Test/B11kill.ztst | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/ChangeLog b/ChangeLog index 4d48d787c..162bde6b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2020-02-18 Chris Down + * 45452: Test/B11kill.ztst: builtins: kill: Add `kill ''` + regression test with explicit sigspec + * 45451: Test/B11kill.ztst: builtins: kill: Add basic test suite 2020-02-17 brian m. carlson diff --git a/Test/B11kill.ztst b/Test/B11kill.ztst index 26d7a11fe..957a7b385 100644 --- a/Test/B11kill.ztst +++ b/Test/B11kill.ztst @@ -58,3 +58,12 @@ ) 1:kill with sigspec only ?(eval):kill:2: not enough arguments + +# Regression tests: `kill ''` should not result in `kill 0`. + + ( + trap 'exit 11' URG + kill -URG '' + ) +1f:kill with empty pid and sigspec should not send signal to current process group +?(eval):kill:3: illegal pid: -- cgit v1.2.3 From 5c55b3fb50bbfe602fcfa55fa6258e398ecc6b20 Mon Sep 17 00:00:00 2001 From: Chris Down Date: Mon, 17 Feb 2020 10:12:11 -0500 Subject: 45453: builtins: kill: Do not signal current process group when pid is empty The following case was encountered in the wild: % zsh; echo "$?" % trap 'exit 5' TERM % kill '' 5 This behaviour seems more likely to be the result of bugs in programs (e.g. `kill -9 "$unsetvar") rather than being desirable behaviour to me. It also seems unintentional judging by the code and documentation, since it comes about as a result of the fact that: - `isanum` returns true for empty strings (since an empty string technically only consists of digits and minuses...); - `atoi`, when passed a pointer to an invalid number, returns 0; - `kill(0, signal)` sends the signal in question to all processes in the current process group. There are (at least) two ways to solve this issue: 1. Add special handling to `kill` to avoid this case. See this patch[0] for a version that does that. 2. Change how isanum behaves. Since the only two call sites that use it both seem like they should handle the case where the input char array is empty, that seems like a reasonable overall change to me.[1] After this patch: % trap 'exit 5' TERM % kill '' kill: illegal pid: The regression test for `kill` without a sigspec is also included in this commit, as previously it's not possible to test it trivially as it would still kill the test runner in expected-to-fail mode; see discussion in workers/45449. 0: workers/45426: https://www.zsh.org/mla/workers/2020/msg00251.html 1: The other call site using isanum() is the fg builtin, but in that case we just fail later since we can't find any job named '', so no big deal either way. It's the kill case which is more concerning. --- ChangeLog | 3 +++ Src/jobs.c | 5 +++-- Test/B11kill.ztst | 10 +++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 162bde6b0..9a7ca36a0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2020-02-18 Chris Down + * 45453: Src/jobs.c, Test/B11kill.ztst: builtins: kill: Do not + signal current process group when pid is empty + * 45452: Test/B11kill.ztst: builtins: kill: Add `kill ''` regression test with explicit sigspec diff --git a/Src/jobs.c b/Src/jobs.c index e7438251e..0485f2c7c 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -1854,13 +1854,14 @@ scanjobs(void) /* This simple function indicates whether or not s may represent * * a number. It returns true iff s consists purely of digits and * - * minuses. Note that minus may appear more than once, and the empty * - * string will produce a `true' response. */ + * minuses. Note that minus may appear more than once. */ /**/ static int isanum(char *s) { + if (*s == '\0') + return 0; while (*s == '-' || idigit(*s)) s++; return *s == '\0'; diff --git a/Test/B11kill.ztst b/Test/B11kill.ztst index 957a7b385..40dd99cd3 100644 --- a/Test/B11kill.ztst +++ b/Test/B11kill.ztst @@ -65,5 +65,13 @@ trap 'exit 11' URG kill -URG '' ) -1f:kill with empty pid and sigspec should not send signal to current process group +1:kill with empty pid and sigspec should not send signal to current process group ?(eval):kill:3: illegal pid: + + ( + trap 'exit 19' TERM + kill '' + ) +1:Plain kill with empty pid should not send signal to current process group +?(eval):kill:3: illegal pid: + -- cgit v1.2.3 From 69c247de2ff3ca41be93cd90af539926418d023d Mon Sep 17 00:00:00 2001 From: Chris Down Date: Tue, 18 Feb 2020 13:54:37 -0500 Subject: 45463: test: kill: Document why we use SIGURG See discussion in workers/45460. --- ChangeLog | 3 +++ Test/B11kill.ztst | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/ChangeLog b/ChangeLog index 9a7ca36a0..5fabad45c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2020-02-18 Chris Down + * 45463: Test/B11kill.ztst: test: kill: Document why we use + SIGURG + * 45453: Src/jobs.c, Test/B11kill.ztst: builtins: kill: Do not signal current process group when pid is empty diff --git a/Test/B11kill.ztst b/Test/B11kill.ztst index 40dd99cd3..dc6bf9b89 100644 --- a/Test/B11kill.ztst +++ b/Test/B11kill.ztst @@ -60,6 +60,15 @@ ?(eval):kill:2: not enough arguments # Regression tests: `kill ''` should not result in `kill 0`. +# +# We use SIGURG where an explicit sigspec can be provided as: +# +# 1. By default it's non-terminal, so even if we regress, we won't kill the +# test runner and other processes in the process group since we'll stop +# running this test before we get to the plain kill (and thus SIGTERM) +# cases; +# 2. It's also unlikely to be sent for any other reason during the process +# lifetime, so the test shouldn't be flaky. ( trap 'exit 11' URG -- cgit v1.2.3 From 50df0e0bb9309319af9a3ee59a31766d3f1ba6bf Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Mon, 17 Feb 2020 09:56:54 +0000 Subject: 45447: Complete vcs_info_hookadd and vcs_info_hookdel. Expose _vcs_info_hooks as a top-level helper function. --- ChangeLog | 8 ++++++++ Completion/Zsh/Command/_zstyle | 3 --- Completion/Zsh/Function/_vcs_info | 31 +++++++++++++++++++++++++++++++ Completion/Zsh/Type/_vcs_info_hooks | 2 ++ 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 Completion/Zsh/Function/_vcs_info create mode 100644 Completion/Zsh/Type/_vcs_info_hooks diff --git a/ChangeLog b/ChangeLog index 5fabad45c..1dea4c9d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2020-02-19 Daniel Shahaf + + * 45447: Completion/Zsh/Command/_zstyle, + Completion/Zsh/Function/_vcs_info, + Completion/Zsh/Type/_vcs_info_hooks: Complete vcs_info_hookadd + and vcs_info_hookdel. Expose _vcs_info_hooks as a top-level + helper function. + 2020-02-18 Chris Down * 45463: Test/B11kill.ztst: test: kill: Document why we use diff --git a/Completion/Zsh/Command/_zstyle b/Completion/Zsh/Command/_zstyle index 7db73c0c0..07b60605f 100644 --- a/Completion/Zsh/Command/_zstyle +++ b/Completion/Zsh/Command/_zstyle @@ -5,9 +5,6 @@ local nm=$compstate[nmatches] taglist patterns contexts MATCH integer MBEGIN MEND typeset -A opt_args styles -_vcs_info_hooks() { - compadd - ${functions[(I)+vi-*]#+vi-} -} # Assoc array of styles; the values give the possible top-level # contexts: # c completion diff --git a/Completion/Zsh/Function/_vcs_info b/Completion/Zsh/Function/_vcs_info new file mode 100644 index 000000000..fdb28de6a --- /dev/null +++ b/Completion/Zsh/Function/_vcs_info @@ -0,0 +1,31 @@ +#compdef vcs_info_hookadd vcs_info_hookdel + +local -a hook_types=( + gen-applied-string + gen-hg-bookmark-string + gen-mqguards-string + gen-unapplied-string + no-vcs + post-backend + post-quilt + pre-addon-quilt + pre-get-data + set-branch-format + set-hgrev-format + set-message + set-patch-format + start-up +) + +local -a specs +case $service in + (vcs_info_hookdel) + specs=( '-a[remove all occurrences, not just the first]' ) + ;; +esac + +# TODO: for vcs_info_hookdel complete only functions installed for that hook +_arguments : \ + $specs \ + ":hook type:($hook_types)" \ + '*:hook function:_vcs_info_hooks' diff --git a/Completion/Zsh/Type/_vcs_info_hooks b/Completion/Zsh/Type/_vcs_info_hooks new file mode 100644 index 000000000..bad915000 --- /dev/null +++ b/Completion/Zsh/Type/_vcs_info_hooks @@ -0,0 +1,2 @@ +#autoload +compadd - ${functions[(I)+vi-*]#+vi-} -- cgit v1.2.3 From a6a1b28b9807c8c19d5fef424a86b86ddf33bc7f Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 24 Feb 2020 10:55:48 +0000 Subject: 45487: Missing mod_export declarations for AIX --- ChangeLog | 6 ++++++ Src/Zle/zle_keymap.c | 2 +- Src/Zle/zle_main.c | 2 +- Src/Zle/zle_move.c | 2 +- Src/builtin.c | 2 +- Src/compat.c | 2 +- Src/utils.c | 2 +- 7 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1dea4c9d3..f85d6f47e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2020-02-24 Peter Stephenson + + * 45487: Src/Zle/zle_keymap.c, Src/Zle/zle_main.c, + Src/Zle/zle_move.c, Src/builtin.c, Src/compat.c, Src/utils.c: + Add missing mod_export for AIX compilation. + 2020-02-19 Daniel Shahaf * 45447: Completion/Zsh/Command/_zstyle, diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index d13aed594..2389ab754 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -404,7 +404,7 @@ scankeys(HashNode hn, UNUSED(int flags)) /**************************/ /**/ -Keymap +mod_export Keymap openkeymap(char *name) { KeymapName n = (KeymapName) keymapnamtab->getnode(keymapnamtab, name); diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index be68f4722..8c0534708 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1056,7 +1056,7 @@ getrestchar(int inchar, char *outstr, int *outcount) #endif /**/ -void +mod_export void redrawhook(void) { Thingy initthingy; diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c index 155fda80d..3bafff3f1 100644 --- a/Src/Zle/zle_move.c +++ b/Src/Zle/zle_move.c @@ -166,7 +166,7 @@ decpos(int *pos) */ /**/ -char * +mod_export char * backwardmetafiedchar(char *start, char *endptr, convchar_t *retchr) { #ifdef MULTIBYTE_SUPPORT diff --git a/Src/builtin.c b/Src/builtin.c index aa5767cf1..407cad159 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -2597,7 +2597,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), */ /**/ -int +mod_export int bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) { Param pm; diff --git a/Src/compat.c b/Src/compat.c index 8ab335aa1..74e426fba 100644 --- a/Src/compat.c +++ b/Src/compat.c @@ -496,7 +496,7 @@ zgetdir(struct dirsav *d) */ /**/ -char * +mod_export char * zgetcwd(void) { char *ret = zgetdir(NULL); diff --git a/Src/utils.c b/Src/utils.c index f5667f389..f9c2d4a2b 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1023,7 +1023,7 @@ xsymlinks(char *s, int full) */ /**/ -char * +mod_export char * xsymlink(char *s, int heap) { if (*s != '/') -- cgit v1.2.3 From f7c6a0008b105c945ba3935d7ecb8c87fe0cd0e5 Mon Sep 17 00:00:00 2001 From: Marc Date: Mon, 24 Feb 2020 18:50:33 +0000 Subject: 45488: COMP_WORDS for bash need "$@"-style quoting --- ChangeLog | 5 +++++ Completion/bashcompinit | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index f85d6f47e..340de5b43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-02-25 Peter Stephenson + + * 45488: Marc Cornella: Completion/bashcompinit: Need "$@" + quoting for empty words in COMP_WORDS for bash completion. + 2020-02-24 Peter Stephenson * 45487: Src/Zle/zle_keymap.c, Src/Zle/zle_main.c, diff --git a/Completion/bashcompinit b/Completion/bashcompinit index 02290a16f..b278ac8f4 100644 --- a/Completion/bashcompinit +++ b/Completion/bashcompinit @@ -10,7 +10,7 @@ _bash_complete() { (( COMP_POINT = 1 + ${#${(j. .)words[1,CURRENT-1]}} + $#QIPREFIX + $#IPREFIX + $#PREFIX )) (( COMP_CWORD = CURRENT - 1)) - COMP_WORDS=( $words ) + COMP_WORDS=( "${words[@]}" ) BASH_VERSINFO=( 2 05b 0 1 release ) savejobstates=( ${(kv)jobstates} ) -- cgit v1.2.3 From fe516fccb4754833f850cb62f6607226370bbf53 Mon Sep 17 00:00:00 2001 From: Jun-ichi Takimoto Date: Thu, 27 Feb 2020 16:08:13 +0900 Subject: 45492: skip test added by users/24633 on Cygwin --- ChangeLog | 5 +++++ Test/D02glob.ztst | 14 +++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 340de5b43..218970ff6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-02-27 Jun-ichi Takimoto + + * 45492: Test/D02glob.ztst: skip test added by users/24633 + on Cygwin. + 2020-02-25 Peter Stephenson * 45488: Marc Cornella: Completion/bashcompinit: Need "$@" diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst index b0650c8c8..973dc2207 100644 --- a/Test/D02glob.ztst +++ b/Test/D02glob.ztst @@ -729,11 +729,15 @@ >not/exist >exist - mkdir -m 000 glob.tmp/secret-d000 - mkdir -m 111 glob.tmp/secret-d111 - mkdir -m 444 glob.tmp/secret-d444 - for 1 in 000 111 444 ; do ln -s secret-d$1 glob.tmp/secret-s$1; done - print -rC 2 -- glob.tmp/secret-*/ glob.tmp/secret-*(-/) + if [[ $OSTYPE = cygwin* ]]; then + ZTST_skip='Cygwin ignores search permission of directories' + else + mkdir -m 000 glob.tmp/secret-d000 + mkdir -m 111 glob.tmp/secret-d111 + mkdir -m 444 glob.tmp/secret-d444 + for 1 in 000 111 444 ; do ln -s secret-d$1 glob.tmp/secret-s$1; done + print -rC 2 -- glob.tmp/secret-*/ glob.tmp/secret-*(-/) + fi -f:unreadable directories can be globbed (users/24619, users/24626) >glob.tmp/secret-d000/ glob.tmp/secret-d000 >glob.tmp/secret-d111/ glob.tmp/secret-d111 -- cgit v1.2.3 From 14ea665a903b26a658ef1d2ca974a9b48e09eff1 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 27 Feb 2020 20:42:16 +0000 Subject: users/24710: Fix job control problem with sudo. If we use kill to test for continued existence of a process group, we should check on failure that the error is ESRCH, as EPERM indicates the group still has memebers but running privileged so should be left alone. --- ChangeLog | 7 +++++++ Src/exec.c | 3 ++- Src/jobs.c | 14 ++++++++++---- Src/signals.c | 3 ++- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 218970ff6..0b42a7cf8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2020-02-27 Peter Stephenson + + * users/24710: Src/exec.c, Src/jobs.c, Src/signals.c: when using + kill or killpg to test for continued existince of a process + group, check errono is ESRCH on failure as EPERM indicates + processes exist but under a different UID. + 2020-02-27 Jun-ichi Takimoto * 45492: Test/D02glob.ztst: skip test added by users/24633 diff --git a/Src/exec.c b/Src/exec.c index 50027654a..cf99051f0 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1036,7 +1036,8 @@ entersubsh(int flags, struct entersubsh_ret *retp) } else if (thisjob != -1 && (flags & ESUB_PGRP)) { if (jobtab[list_pipe_job].gleader && (list_pipe || list_pipe_child)) { if (setpgrp(0L, jobtab[list_pipe_job].gleader) == -1 || - killpg(jobtab[list_pipe_job].gleader, 0) == -1) { + (killpg(jobtab[list_pipe_job].gleader, 0) == -1 && + errno == ESRCH)) { jobtab[list_pipe_job].gleader = jobtab[thisjob].gleader = (list_pipe_child ? mypgrp : getpid()); setpgrp(0L, jobtab[list_pipe_job].gleader); diff --git a/Src/jobs.c b/Src/jobs.c index 0485f2c7c..8353f1152 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -283,7 +283,8 @@ handle_sub(int job, int fg) if ((cp = ((WIFEXITED(jn->procs->status) || WIFSIGNALED(jn->procs->status)) && - killpg(jn->gleader, 0) == -1))) { + (killpg(jn->gleader, 0) == -1 && + errno == ESRCH)))) { Process p; for (p = jn->procs; p->next; p = p->next); jn->gleader = p->pid; @@ -541,9 +542,13 @@ update_job(Job jn) /* is this job in the foreground of an interactive shell? */ if (mypgrp != pgrp && inforeground && - (jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) { + (jn->gleader == pgrp || + (pgrp > 1 && + (kill(-pgrp, 0) == -1 && errno == ESRCH)))) { if (list_pipe) { - if (somestopped || (pgrp > 1 && kill(-pgrp, 0) == -1)) { + if (somestopped || (pgrp > 1 && + kill(-pgrp, 0) == -1 && + errno == ESRCH)) { attachtty(mypgrp); /* check window size and adjust if necessary */ adjustwinsize(0); @@ -2470,7 +2475,8 @@ bin_fg(char *name, char **argv, Options ops, int func) if ((jobtab[job].stat & STAT_SUPERJOB) && ((!jobtab[job].procs->next || (jobtab[job].stat & STAT_SUBLEADER) || - killpg(jobtab[job].gleader, 0) == -1)) && + (killpg(jobtab[job].gleader, 0) == -1 && + errno == ESRCH))) && jobtab[jobtab[job].other].gleader) attachtty(jobtab[jobtab[job].other].gleader); else diff --git a/Src/signals.c b/Src/signals.c index 96ff9e9b3..4adf03202 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -539,7 +539,8 @@ wait_for_processes(void) #endif if (WIFEXITED(status) && pn->pid == jn->gleader && - killpg(pn->pid, 0) == -1) { + killpg(pn->pid, 0) == -1 && + errno == ESRCH) { if (last_attached_pgrp == jn->gleader && !(jn->stat & STAT_NOSTTY)) { /* -- cgit v1.2.3 From 2f419b332d9cf28eaad0523b3404ab8ce52a82e0 Mon Sep 17 00:00:00 2001 From: Bryan Irvine Date: Wed, 4 Mar 2020 23:50:37 -0600 Subject: github #49: Fix typo: longson should be loongson --- ChangeLog | 5 +++++ Completion/BSD/Type/_obsd_architectures | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 0b42a7cf8..7632153d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-03-05 Bryan Irvine + + * github #49: Completion/BSD/Type/_obsd_architectures: Fix typo: + longson should be loongson + 2020-02-27 Peter Stephenson * users/24710: Src/exec.c, Src/jobs.c, Src/signals.c: when using diff --git a/Completion/BSD/Type/_obsd_architectures b/Completion/BSD/Type/_obsd_architectures index ca3e0e12f..18ee2854c 100644 --- a/Completion/BSD/Type/_obsd_architectures +++ b/Completion/BSD/Type/_obsd_architectures @@ -3,4 +3,4 @@ local expl _description architectures expl 'architecture' -compadd "$@" "$expl[@]" alpha amd64 arm64 armv7 hppa i386 landisk longson luna88k macppc octeon sgi sparc64 +compadd "$@" "$expl[@]" alpha amd64 arm64 armv7 hppa i386 landisk loongson luna88k macppc octeon sgi sparc64 -- cgit v1.2.3 From 273da6cc5f58c4a99399c37ad5faf09924119fea Mon Sep 17 00:00:00 2001 From: Jun-ichi Takimoto Date: Fri, 6 Mar 2020 20:12:06 +0900 Subject: 45490 (+45495 and a test): refactor rlimits.c Use a table of known resouces instead of generating rlimits.h by rlimits.awk. --- .gitignore | 1 - ChangeLog | 7 + Src/Builtins/rlimits.awk | 116 -------- Src/Builtins/rlimits.c | 692 ++++++++++++++++++----------------------------- Src/Builtins/rlimits.mdd | 15 - Test/B12limit.ztst | 10 + configure.ac | 1 + 7 files changed, 281 insertions(+), 561 deletions(-) delete mode 100644 Src/Builtins/rlimits.awk create mode 100644 Test/B12limit.ztst diff --git a/.gitignore b/.gitignore index e46f8517e..ec2f56642 100644 --- a/.gitignore +++ b/.gitignore @@ -123,7 +123,6 @@ Src/Builtins/*.mdh Src/Builtins/*.mdhi Src/Builtins/*.mdhs Src/Builtins/*.mdh.tmp -Src/Builtins/rlimits.h Src/Modules/Makefile.in Src/Modules/*.export diff --git a/ChangeLog b/ChangeLog index 7632153d4..6735e224b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2020-03-06 Jun-ichi Takimoto + + * 45490 (+45495 and a test): .gitignore, + Src/Builtins/rlimits.awk, Src/Builtins/rlimits.c, + Src/Builtins/rlimits.mdd, Test/B12limit.ztst, configure.ac: + Refactor rlimits.c. + 2020-03-05 Bryan Irvine * github #49: Completion/BSD/Type/_obsd_architectures: Fix typo: diff --git a/Src/Builtins/rlimits.awk b/Src/Builtins/rlimits.awk deleted file mode 100644 index e9c576c66..000000000 --- a/Src/Builtins/rlimits.awk +++ /dev/null @@ -1,116 +0,0 @@ -# -# rlimits.awk: {g,n}awk script to generate rlimits.h -# -# NB: On SunOS 4.1.3 - user-functions don't work properly, also \" problems -# Without 0 + hacks some nawks compare numbers as strings -# -BEGIN {limidx = 0} - -/^[\t ]*(#[\t ]*define[\t _]*RLIMIT_[A-Z_]*[\t ]*[0-9][0-9]*|RLIMIT_[A-Z_]*,[\t ]*|_*RLIMIT_[A-Z_]*[\t ]*=[\t ]*[0-9][0-9]*,[\t ]*)/ { - limindex = index($0, "RLIMIT_") - limtail = substr($0, limindex, 80) - split(limtail, tmp) - limnam = substr(tmp[1], 8, 20) - limnum = tmp[2] - # in this case I assume GNU libc resourcebits.h - if (limnum == "") { - limnum = limidx++ - limindex = index($0, ",") - limnam = substr(limnam, 1, limindex-1) - } - if (limnum == "=") { - if (tmp[3] ~ /^[0-9]/) { - limnum = tmp[3] + 0 - } else { - limnum = limidx++ - } - limindex = index($0, ",") - limnam = substr(limnam, 1, limindex-1) - } - limrev[limnam] = limnum - if (lim[limnum] == "") { - lim[limnum] = limnam - if (limnum ~ /^[0-9]*$/) { - if (limnam == "AIO_MEM") { msg[limnum] = "Maiomemorylocked" } - if (limnam == "AIO_OPS") { msg[limnum] = "Naiooperations" } - if (limnam == "AS") { msg[limnum] = "Maddressspace" } - if (limnam == "CORE") { msg[limnum] = "Mcoredumpsize" } - if (limnam == "CPU") { msg[limnum] = "Tcputime" } - if (limnam == "DATA") { msg[limnum] = "Mdatasize" } - if (limnam == "FSIZE") { msg[limnum] = "Mfilesize" } - if (limnam == "LOCKS") { msg[limnum] = "Nmaxfilelocks" } - if (limnam == "MEMLOCK") { msg[limnum] = "Mmemorylocked" } - if (limnam == "NOFILE") { msg[limnum] = "Ndescriptors" } - if (limnam == "NPROC") { msg[limnum] = "Nmaxproc" } - if (limnam == "NTHR") { msg[limnum] = "Nmaxpthreads" } - if (limnam == "OFILE") { msg[limnum] = "Ndescriptors" } - if (limnam == "PTHREAD") { msg[limnum] = "Nmaxpthreads" } - if (limnam == "RSS") { msg[limnum] = "Mresident" } - if (limnam == "SBSIZE") { msg[limnum] = "Msockbufsize" } - if (limnam == "STACK") { msg[limnum] = "Mstacksize" } - if (limnam == "TCACHE") { msg[limnum] = "Ncachedthreads" } - if (limnam == "VMEM") { msg[limnum] = "Mvmemorysize" } - if (limnam == "SIGPENDING") { msg[limnum] = "Nsigpending" } - if (limnam == "MSGQUEUE") { msg[limnum] = "Nmsgqueue" } - if (limnam == "NICE") { msg[limnum] = "Nnice" } - if (limnam == "RTPRIO") { msg[limnum] = "Nrt_priority" } - if (limnam == "RTTIME") { msg[limnum] = "Urt_time" } - if (limnam == "POSIXLOCKS") { msg[limnum] = "Nposixlocks" } - if (limnam == "NPTS") { msg[limnum] = "Npseudoterminals" } - if (limnam == "SWAP") { msg[limnum] = "Mswapsize" } - if (limnam == "KQUEUES") { msg[limnum] = "Nkqueues" } - if (limnam == "UMTXP") { msg[limnum] = "Numtxp" } - } - } -} -/^[\t ]*#[\t ]*define[\t _]*RLIM_NLIMITS[\t ]*[0-9][0-9]*/ { - limindex = index($0, "RLIM_") - limtail = substr($0, limindex, 80) - split(limtail, tmp) - nlimits = tmp[2] -} -# in case of GNU libc -/^[\t ]*RLIM_NLIMITS[\t ]*=[\t ]*RLIMIT_NLIMITS/ { - if(!nlimits) { nlimits = limidx } -} -/^[\t _]*RLIM(IT)?_NLIMITS[\t ]*=[\t ]*[0-9][0-9]*/ { - limindex = index($0, "=") - limtail = substr($0, limindex, 80) - split(limtail, tmp) - nlimits = tmp[2] -} - -END { - if (limrev["MEMLOCK"] != "") { - irss = limrev["RSS"] - msg[irss] = "Mmemoryuse" - } - ps = "%s" - - printf("%s\n%s\n\n", "/** rlimits.h **/", "/** architecture-customized limits for zsh **/") - printf("#define ZSH_NLIMITS %d\n\nstatic char const *recs[ZSH_NLIMITS] = {\n", 0 + nlimits) - - for (i = 0; i < 0 + nlimits; i++) - if (msg[i] == "") - printf("\t%c%s%c,\n", 34, lim[i], 34) - else - printf("\t%c%s%c,\n", 34, substr(msg[i], 2, 30), 34) - print "};" - print "" - print "static int limtype[ZSH_NLIMITS] = {" - for (i = 0; i < 0 + nlimits; i++) { - if (msg[i] == "") - limtype = "UNKNOWN" - else { - limtype = substr(msg[i], 1, 1) - if(limtype == "M") { limtype = "MEMORY" } - if(limtype == "N") { limtype = "NUMBER" } - if(limtype == "T") { limtype = "TIME" } - if(limtype == "U") { limtype = "MICROSECONDS" } - } - printf("\tZLIMTYPE_%s,\n", limtype) - } - print "};" - - exit(0) -} diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c index 6b552f3a9..b9128433f 100644 --- a/Src/Builtins/rlimits.c +++ b/Src/Builtins/rlimits.c @@ -32,20 +32,7 @@ #if defined(HAVE_GETRLIMIT) && defined(RLIM_INFINITY) -#if defined(HAVE_RLIMIT_POSIXLOCKS) && !defined(HAVE_RLIMIT_LOCKS) -# define RLIMIT_LOCKS RLIMIT_POSIXLOCKS -# define HAVE_RLIMIT_LOCKS 1 -#endif - -#if defined(HAVE_RLIMIT_NTHR) && !defined(HAVE_RLIMIT_PTHREAD) -# define RLIMIT_PTHREAD RLIMIT_NTHR -# define HAVE_RLIMIT_PTHREAD 1 -# define THREAD_FMT "-T: threads " -#else -# define THREAD_FMT "-T: threads per process " -#endif - -enum { +enum zlimtype { ZLIMTYPE_MEMORY, ZLIMTYPE_NUMBER, ZLIMTYPE_TIME, @@ -53,11 +40,214 @@ enum { ZLIMTYPE_UNKNOWN }; -/* Generated rec array containing limits required for the limit builtin. * - * They must appear in this array in numerical order of the RLIMIT_* macros. */ +typedef struct resinfo_T { + int res; /* RLIMIT_XXX */ + char* name; /* used by limit builtin */ + enum zlimtype type; + int unit; /* 1, 512, or 1024 */ + char opt; /* option character */ + char* descr; /* used by ulimit builtin */ +} resinfo_T; + +/* table of known resources */ +static const resinfo_T known_resources[] = { + {RLIMIT_CPU, "cputime", ZLIMTYPE_TIME, 1, + 't', "cpu time (seconds)"}, + {RLIMIT_FSIZE, "filesize", ZLIMTYPE_MEMORY, 512, + 'f', "file size (blocks)"}, + {RLIMIT_DATA, "datasize", ZLIMTYPE_MEMORY, 1024, + 'd', "data seg size (kbytes)"}, + {RLIMIT_STACK, "stacksize", ZLIMTYPE_MEMORY, 1024, + 's', "stack size (kbytes)"}, + {RLIMIT_CORE, "coredumpsize", ZLIMTYPE_MEMORY, 512, + 'c', "core file size (blocks)"}, +# ifdef HAVE_RLIMIT_NOFILE + {RLIMIT_NOFILE, "descriptors", ZLIMTYPE_NUMBER, 1, + 'n', "file descriptors"}, +# endif +# if defined(HAVE_RLIMIT_AS) && !defined(RLIMIT_VMEM_IS_AS) + {RLIMIT_AS, "addressspace", ZLIMTYPE_MEMORY, 1024, + 'v', "address space (kbytes)"}, +# endif +# if defined(HAVE_RLIMIT_RSS) && !defined(RLIMIT_VMEM_IS_RSS) && !defined(RLIMIT_RSS_IS_AS) + {RLIMIT_RSS, "resident", ZLIMTYPE_MEMORY, 1024, + 'm', "resident set size (kbytes)"}, +# endif +# if defined(HAVE_RLIMIT_VMEM) + {RLIMIT_VMEM, +# if defined(RLIMIT_VMEM_IS_RSS) + "resident", ZLIMTYPE_MEMORY, 1024, + 'm', "memory size (kbytes)"}, +# else + "vmemorysize", ZLIMTYPE_MEMORY, 1024, + 'v', "virtual memory size (kbytes)"}, +# endif +# endif +# ifdef HAVE_RLIMIT_NPROC + {RLIMIT_NPROC, "maxproc", ZLIMTYPE_NUMBER, 1, + 'u', "processes"}, +# endif +# ifdef HAVE_RLIMIT_MEMLOCK + {RLIMIT_MEMLOCK, "memorylocked", ZLIMTYPE_MEMORY, 1024, + 'l', "locked-in-memory size (kbytes)"}, +# endif + /* Linux */ +# ifdef HAVE_RLIMIT_LOCKS + {RLIMIT_LOCKS, "maxfilelocks", ZLIMTYPE_NUMBER, 1, + 'x', "file locks"}, +# endif +# ifdef HAVE_RLIMIT_SIGPENDING + {RLIMIT_SIGPENDING, "sigpending", ZLIMTYPE_NUMBER, 1, + 'i', "pending signals"}, +# endif +# ifdef HAVE_RLIMIT_MSGQUEUE + {RLIMIT_MSGQUEUE, "msgqueue", ZLIMTYPE_NUMBER, 1, + 'q', "bytes in POSIX msg queues"}, +# endif +# ifdef HAVE_RLIMIT_NICE + {RLIMIT_NICE, "nice", ZLIMTYPE_NUMBER, 1, + 'e', "max nice"}, +# endif +# ifdef HAVE_RLIMIT_RTPRIO + {RLIMIT_RTPRIO, "rt_priority", ZLIMTYPE_NUMBER, 1, + 'r', "max rt priority"}, +# endif +# ifdef HAVE_RLIMIT_RTTIME + {RLIMIT_RTTIME, "rt_time", ZLIMTYPE_MICROSECONDS, 1, + 'N', "rt cpu time (microseconds)"}, +# endif + /* BSD */ +# ifdef HAVE_RLIMIT_SBSIZE + {RLIMIT_SBSIZE, "sockbufsize", ZLIMTYPE_MEMORY, 1, + 'b', "socket buffer size (bytes)"}, +# endif +# ifdef HAVE_RLIMIT_KQUEUES /* FreeBSD */ + {RLIMIT_KQUEUES, "kqueues", ZLIMTYPE_NUMBER, 1, + 'k', "kqueues"}, +# endif +# ifdef HAVE_RLIMIT_NPTS /* FreeBSD */ + {RLIMIT_NPTS, "pseudoterminals", ZLIMTYPE_NUMBER, 1, + 'p', "pseudo-terminals"}, +# endif +# ifdef HAVE_RLIMIT_SWAP /* FreeBSD */ + {RLIMIT_SWAP, "swapsize", ZLIMTYPE_MEMORY, 1024, + 'w', "swap size (kbytes)"}, +# endif +# ifdef HAVE_RLIMIT_UMTXP /* FreeBSD */ + {RLIMIT_UMTXP, "umtxp", ZLIMTYPE_NUMBER, 1, + 'o', "umtx shared locks"}, +# endif + +# ifdef HAVE_RLIMIT_POSIXLOCKS /* DragonFly */ + {RLIMIT_POSIXLOCKS, "posixlocks", ZLIMTYPE_NUMBER, 1, + 'x', "number of POSIX locks"}, +# endif +# if defined(HAVE_RLIMIT_NTHR) && !defined(HAVE_RLIMIT_RTPRIO) /* Net/OpenBSD */ + {RLIMIT_NTHR, "maxpthreads", ZLIMTYPE_NUMBER, 1, + 'r', "threads"}, +# endif + /* others */ +# if defined(HAVE_RLIMIT_PTHREAD) && !defined(HAVE_RLIMIT_NTHR) /* IRIX ? */ + {RLIMIT_PTHREAD, "maxpthreads", ZLIMTYPE_NUMBER, 1, + 'T', "threads per process"}, +# endif +# ifdef HAVE_RLIMIT_AIO_MEM /* HP-UX ? */ + {RLIMIT_AIO_MEM, "aiomemorylocked", ZLIMTYPE_MEMORY, 1024, + 'N', "AIO locked-in-memory (kbytes)"}, +# endif +# ifdef HAVE_RLIMIT_AIO_OPS /* HP-UX ? */ + {RLIMIT_AIO_OPS, "aiooperations", ZLIMTYPE_NUMBER, 1, + 'N', "AIO operations"}, +# endif +# ifdef HAVE_RLIMIT_TCACHE /* HP-UX ? */ + {RLIMIT_TCACHE, "cachedthreads", ZLIMTYPE_NUMBER, 1, + 'N', "cached threads"}, +# endif +}; -# include "rlimits.h" +/* resinfo[RLIMIT_XXX] points to the corresponding entry + * in known_resources[] */ +static const resinfo_T **resinfo; +/**/ +static void +set_resinfo(void) +{ + int i; + + resinfo = (const resinfo_T **)zshcalloc(RLIM_NLIMITS*sizeof(resinfo_T *)); + + for (i=0; ires = - 1; /* negative value indicates "unknown" */ + info->name = buf; + info->type = ZLIMTYPE_UNKNOWN; + info->unit = 1; + info->opt = 'N'; + info->descr = buf; + resinfo[i] = info; + } + } +} + +/**/ +static void +free_resinfo(void) +{ + int i; + for (i=0; ires < 0) { /* unknown resource */ + free(resinfo[i]->name); + free((void*)resinfo[i]); + } + } + free(resinfo); + resinfo = NULL; +} + +/* Find resource by its option character */ + +/**/ +static int +find_resource(char c) +{ + int i; + for (i=0; iopt == c) + return i; + } + return -1; +} + +/* Print a value of type rlim_t */ + +/**/ +static void +printrlim(rlim_t val, const char *unit) +{ +# ifdef RLIM_T_IS_QUAD_T + printf("%qd%s", val, unit); +# else +# ifdef RLIM_T_IS_LONG_LONG + printf("%lld%s", val, unit); +# else +# ifdef RLIM_T_IS_UNSIGNED + printf("%lu%s", (unsigned long)val, unit); +# else + printf("%ld%s", (long)val, unit); +# endif /* RLIM_T_IS_UNSIGNED */ +# endif /* RLIM_T_IS_LONG_LONG */ +# endif /* RLIM_T_IS_QUAD_T */ +} + +/**/ static rlim_t zstrtorlimt(const char *s, char **t, int base) { @@ -97,8 +287,8 @@ static void showlimitvalue(int lim, rlim_t val) { /* display limit for resource number lim */ - if (lim < ZSH_NLIMITS) - printf("%-16s", recs[lim]); + if (lim < RLIM_NLIMITS) + printf("%-16s", resinfo[lim]->name); else { /* Unknown limit, hence unknown units. */ @@ -106,81 +296,25 @@ showlimitvalue(int lim, rlim_t val) } if (val == RLIM_INFINITY) printf("unlimited\n"); - else if (lim >= ZSH_NLIMITS) - { -# ifdef RLIM_T_IS_QUAD_T - printf("%qd\n", val); -# else -# ifdef RLIM_T_IS_LONG_LONG - printf("%lld\n", val); -# else -# ifdef RLIM_T_IS_UNSIGNED - printf("%lu\n", (unsigned long)val); -# else - printf("%ld\n", (long)val); -# endif /* RLIM_T_IS_UNSIGNED */ -# endif /* RLIM_T_IS_LONG_LONG */ -# endif /* RLIM_T_IS_QUAD_T */ - } - else if (limtype[lim] == ZLIMTYPE_TIME) { + else if (lim >= RLIM_NLIMITS) + printrlim(val, "\n"); + else if (resinfo[lim]->type == ZLIMTYPE_TIME) { /* time-type resource -- display as hours, minutes and seconds. */ printf("%d:%02d:%02d\n", (int)(val / 3600), (int)(val / 60) % 60, (int)(val % 60)); - } else if (limtype[lim] == ZLIMTYPE_MICROSECONDS) { - /* microseconds */ -# ifdef RLIM_T_IS_QUAD_T - printf("%qdus\n", val); -# else -# ifdef RLIM_T_IS_LONG_LONG - printf("%lldus\n", val); -# else -# ifdef RLIM_T_IS_UNSIGNED - printf("%luus\n", (unsigned long)val); -# else - printf("%ldus\n", (long)val); -# endif /* RLIM_T_IS_UNSIGNED */ -# endif /* RLIM_T_IS_LONG_LONG */ -# endif /* RLIM_T_IS_QUAD_T */ - } else if (limtype[lim] == ZLIMTYPE_NUMBER || - limtype[lim] == ZLIMTYPE_UNKNOWN) { - /* pure numeric resource */ -# ifdef RLIM_T_IS_QUAD_T - printf("%qd\n", val); -# else -# ifdef RLIM_T_IS_LONG_LONG - printf("%lld\n", val); -# else -# ifdef RLIM_T_IS_UNSIGNED - printf("%lu\n", (unsigned long)val); -# else - printf("%ld\n", (long)val); -# endif /* RLIM_T_IS_UNSIGNED */ -# endif /* RLIM_T_IS_LONG_LONG */ -# endif /* RLIM_T_IS_QUAD_T */ - } else if (val >= 1024L * 1024L) - /* memory resource -- display with `K' or `M' modifier */ -# ifdef RLIM_T_IS_QUAD_T - printf("%qdMB\n", val / (1024L * 1024L)); - else - printf("%qdkB\n", val / 1024L); -# else -# ifdef RLIM_T_IS_LONG_LONG - printf("%lldMB\n", val / (1024L * 1024L)); - else - printf("%lldkB\n", val / 1024L); -# else -# ifdef RLIM_T_IS_UNSIGNED - printf("%luMB\n", (unsigned long)(val / (1024L * 1024L))); - else - printf("%lukB\n", (unsigned long)(val / 1024L)); -# else - printf("%ldMB\n", (long)val / (1024L * 1024L)); - else - printf("%ldkB\n", (long)val / 1024L); -# endif /* RLIM_T_IS_UNSIGNED */ -# endif /* RLIM_T_IS_LONG_LONG */ -# endif /* RLIM_T_IS_QUAD_T */ + } else if (resinfo[lim]->type == ZLIMTYPE_MICROSECONDS) + printrlim(val, "us\n"); /* microseconds */ + else if (resinfo[lim]->type == ZLIMTYPE_NUMBER || + resinfo[lim]->type == ZLIMTYPE_UNKNOWN) + printrlim(val, "\n"); /* pure numeric resource */ + else { + /* memory resource -- display with `k' or `M' modifier */ + if (val >= 1024L * 1024L) + printrlim(val/(1024L * 1024L), "MB\n"); + else + printrlim(val/1024L, "kB\n"); + } } /* Display resource limits. hard indicates whether `hard' or `soft' * @@ -193,7 +327,7 @@ showlimits(char *nam, int hard, int lim) { int rt; - if (lim >= ZSH_NLIMITS) + if (lim >= RLIM_NLIMITS) { /* * Not configured into the shell. Ask the OS @@ -215,7 +349,7 @@ showlimits(char *nam, int hard, int lim) else { /* main loop over resource types */ - for (rt = 0; rt != ZSH_NLIMITS; rt++) + for (rt = 0; rt != RLIM_NLIMITS; rt++) showlimitvalue(rt, (hard) ? limits[rt].rlim_max : limits[rt].rlim_cur); } @@ -234,7 +368,7 @@ printulimit(char *nam, int lim, int hard, int head) rlim_t limit; /* get the limit in question */ - if (lim >= ZSH_NLIMITS) + if (lim >= RLIM_NLIMITS) { struct rlimit vals; @@ -248,199 +382,25 @@ printulimit(char *nam, int lim, int hard, int head) else limit = (hard) ? limits[lim].rlim_max : limits[lim].rlim_cur; /* display the appropriate heading */ - switch (lim) { - case RLIMIT_CORE: - if (head) - printf("-c: core file size (blocks) "); - if (limit != RLIM_INFINITY) - limit /= 512; - break; - case RLIMIT_DATA: - if (head) - printf("-d: data seg size (kbytes) "); - if (limit != RLIM_INFINITY) - limit /= 1024; - break; - case RLIMIT_FSIZE: - if (head) - printf("-f: file size (blocks) "); - if (limit != RLIM_INFINITY) - limit /= 512; - break; -# ifdef HAVE_RLIMIT_SIGPENDING - case RLIMIT_SIGPENDING: - if (head) - printf("-i: pending signals "); - break; -# endif -# ifdef HAVE_RLIMIT_MEMLOCK - case RLIMIT_MEMLOCK: - if (head) - printf("-l: locked-in-memory size (kbytes) "); - if (limit != RLIM_INFINITY) - limit /= 1024; - break; -# endif /* HAVE_RLIMIT_MEMLOCK */ -/* If RLIMIT_VMEM and RLIMIT_RSS are defined and equal, avoid * - * duplicate case statement. Observed on QNX Neutrino 6.1.0. */ -# if defined(HAVE_RLIMIT_RSS) && !defined(RLIMIT_VMEM_IS_RSS) && !defined(RLIMIT_RSS_IS_AS) - case RLIMIT_RSS: - if (head) - printf("-m: resident set size (kbytes) "); - if (limit != RLIM_INFINITY) - limit /= 1024; - break; -# endif /* HAVE_RLIMIT_RSS */ -# if defined(HAVE_RLIMIT_VMEM) && defined(HAVE_RLIMIT_RSS) && defined(RLIMIT_VMEM_IS_RSS) - case RLIMIT_VMEM: - if (head) - printf("-m: memory size (kbytes) "); - if (limit != RLIM_INFINITY) - limit /= 1024; - break; -# endif /* HAVE_RLIMIT_VMEM */ -# ifdef HAVE_RLIMIT_NOFILE - case RLIMIT_NOFILE: - if (head) - printf("-n: file descriptors "); - break; -# endif /* HAVE_RLIMIT_NOFILE */ -# ifdef HAVE_RLIMIT_MSGQUEUE - case RLIMIT_MSGQUEUE: - if (head) - printf("-q: bytes in POSIX msg queues "); - break; -# endif - case RLIMIT_STACK: - if (head) - printf("-s: stack size (kbytes) "); - if (limit != RLIM_INFINITY) - limit /= 1024; - break; - case RLIMIT_CPU: - if (head) - printf("-t: cpu time (seconds) "); - break; -# ifdef HAVE_RLIMIT_NPROC - case RLIMIT_NPROC: - if (head) - printf("-u: processes "); - break; -# endif /* HAVE_RLIMIT_NPROC */ -# if defined(HAVE_RLIMIT_VMEM) && (!defined(HAVE_RLIMIT_RSS) || !defined(RLIMIT_VMEM_IS_RSS)) - case RLIMIT_VMEM: - if (head) - printf("-v: virtual memory size (kbytes) "); - if (limit != RLIM_INFINITY) - limit /= 1024; - break; -# endif /* HAVE_RLIMIT_VMEM */ -# if defined HAVE_RLIMIT_AS && !defined(RLIMIT_VMEM_IS_AS) - case RLIMIT_AS: - if (head) - printf("-v: address space (kbytes) "); - if (limit != RLIM_INFINITY) - limit /= 1024; - break; -# endif /* HAVE_RLIMIT_AS */ -# ifdef HAVE_RLIMIT_LOCKS - case RLIMIT_LOCKS: - if (head) - printf("-x: file locks "); - break; -# endif /* HAVE_RLIMIT_LOCKS */ -# ifdef HAVE_RLIMIT_AIO_MEM - case RLIMIT_AIO_MEM: - if (head) - printf("-N %2d: AIO locked-in-memory (kbytes)", RLIMIT_AIO_MEM); - if (limit != RLIM_INFINITY) - limit /= 1024; - break; -# endif /* HAVE_RLIMIT_AIO_MEM */ -# ifdef HAVE_RLIMIT_AIO_OPS - case RLIMIT_AIO_OPS: - if (head) - printf("-N %2d: AIO operations ", RLIMIT_AIO_OPS); - break; -# endif /* HAVE_RLIMIT_AIO_OPS */ -# ifdef HAVE_RLIMIT_TCACHE - case RLIMIT_TCACHE: - if (head) - printf("-N %2d: cached threads ", RLIMIT_TCACHE); - break; -# endif /* HAVE_RLIMIT_TCACHE */ -# ifdef HAVE_RLIMIT_SBSIZE - case RLIMIT_SBSIZE: - if (head) - printf("-b: socket buffer size (bytes) "); - break; -# endif /* HAVE_RLIMIT_SBSIZE */ -# ifdef HAVE_RLIMIT_PTHREAD - case RLIMIT_PTHREAD: - if (head) - printf("%s", THREAD_FMT); - break; -# endif /* HAVE_RLIMIT_PTHREAD */ -# ifdef HAVE_RLIMIT_NICE - case RLIMIT_NICE: - if (head) - printf("-e: max nice "); - break; -# endif /* HAVE_RLIMIT_NICE */ -# ifdef HAVE_RLIMIT_RTPRIO - case RLIMIT_RTPRIO: - if (head) - printf("-r: max rt priority "); - break; -# endif /* HAVE_RLIMIT_RTPRIO */ -# ifdef HAVE_RLIMIT_NPTS - case RLIMIT_NPTS: - if (head) - printf("-p: pseudo-terminals "); - break; -# endif /* HAVE_RLIMIT_NPTS */ -# ifdef HAVE_RLIMIT_SWAP - case RLIMIT_SWAP: - if (head) - printf("-w: swap size (kbytes) "); - if (limit != RLIM_INFINITY) - limit /= 1024; - break; -# endif /* HAVE_RLIMIT_SWAP */ -# ifdef HAVE_RLIMIT_KQUEUES - case RLIMIT_KQUEUES: - if (head) - printf("-k: kqueues "); - break; -# endif /* HAVE_RLIMIT_KQUEUES */ -# ifdef HAVE_RLIMIT_UMTXP - case RLIMIT_UMTXP: - if (head) - printf("-o: umtx shared locks "); - break; -# endif /* HAVE_RLIMIT_UMTXP */ - default: - if (head) - printf("-N %2d: ", lim); - break; + if (head) { + if (lim < RLIM_NLIMITS) { + const resinfo_T *info = resinfo[lim]; + if (info->opt == 'N') + printf("-N %2d: %-29s", lim, info->descr); + else + printf("-%c: %-32s", info->opt, info->descr); + } + else + printf("-N %2d: %-29s", lim, ""); } /* display the limit */ if (limit == RLIM_INFINITY) printf("unlimited\n"); else { -# ifdef RLIM_T_IS_QUAD_T - printf("%qd\n", limit); -# else -# ifdef RLIM_T_IS_LONG_LONG - printf("%lld\n", limit); -# else -# ifdef RLIM_T_IS_UNSIGNED - printf("%lu\n", (unsigned long)limit); -# else - printf("%ld\n", (long)limit); -# endif /* RLIM_T_IS_UNSIGNED */ -# endif /* RLIM_T_IS_LONG_LONG */ -# endif /* RLIM_T_IS_QUAD_T */ + if (lim < RLIM_NLIMITS) + printrlim(limit/resinfo[lim]->unit, "\n"); + else + printrlim(limit, "\n"); } return 0; @@ -450,7 +410,7 @@ printulimit(char *nam, int lim, int hard, int head) static int do_limit(char *nam, int lim, rlim_t val, int hard, int soft, int set) { - if (lim >= ZSH_NLIMITS) { + if (lim >= RLIM_NLIMITS) { struct rlimit vals; if (getrlimit(lim, &vals) < 0) { @@ -558,8 +518,8 @@ bin_limit(char *nam, char **argv, Options ops, UNUSED(int func)) lim = (int)zstrtol(s, NULL, 10); } else - for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++) - if (!strncmp(recs[limnum], s, strlen(s))) { + for (lim = -1, limnum = 0; limnum < RLIM_NLIMITS; limnum++) + if (!strncmp(resinfo[limnum]->name, s, strlen(s))) { if (lim != -1) lim = -2; else @@ -576,7 +536,7 @@ bin_limit(char *nam, char **argv, Options ops, UNUSED(int func)) /* without value for limit, display the current limit */ if (!(s = *argv++)) return showlimits(nam, hard, lim); - if (lim >= ZSH_NLIMITS) + if (lim >= RLIM_NLIMITS) { val = zstrtorlimt(s, &s, 10); if (*s) @@ -586,7 +546,7 @@ bin_limit(char *nam, char **argv, Options ops, UNUSED(int func)) return 1; } } - else if (limtype[lim] == ZLIMTYPE_TIME) { + else if (resinfo[lim]->type == ZLIMTYPE_TIME) { /* time-type resource -- may be specified as seconds, or minutes or * * hours with the `m' and `h' modifiers, and `:' may be used to add * * together more than one of these. It's easier to understand from * @@ -604,9 +564,9 @@ bin_limit(char *nam, char **argv, Options ops, UNUSED(int func)) return 1; } } - } else if (limtype[lim] == ZLIMTYPE_NUMBER || - limtype[lim] == ZLIMTYPE_UNKNOWN || - limtype[lim] == ZLIMTYPE_MICROSECONDS) { + } else if (resinfo[lim]->type == ZLIMTYPE_NUMBER || + resinfo[lim]->type == ZLIMTYPE_UNKNOWN || + resinfo[lim]->type == ZLIMTYPE_MICROSECONDS) { /* pure numeric resource -- only a straight decimal number is permitted. */ char *t = s; @@ -642,7 +602,7 @@ static int do_unlimit(char *nam, int lim, int hard, int soft, int set, int euid) { /* remove specified limit */ - if (lim >= ZSH_NLIMITS) { + if (lim >= RLIM_NLIMITS) { struct rlimit vals; if (getrlimit(lim, &vals) < 0) { @@ -718,8 +678,8 @@ bin_unlimit(char *nam, char **argv, Options ops, UNUSED(int func)) if (idigit(**argv)) { lim = (int)zstrtol(*argv, NULL, 10); } else { - for (lim = -1, limnum = 0; limnum < ZSH_NLIMITS; limnum++) - if (!strncmp(recs[limnum], *argv, strlen(*argv))) { + for (lim = -1, limnum = 0; limnum < RLIM_NLIMITS; limnum++) + if (!strncmp(resinfo[limnum]->name, *argv, strlen(*argv))) { if (lim != -1) lim = -2; else @@ -800,116 +760,14 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) resmask = (1 << RLIM_NLIMITS) - 1; nres = RLIM_NLIMITS; continue; - case 't': - res = RLIMIT_CPU; - break; - case 'f': - res = RLIMIT_FSIZE; - break; - case 'd': - res = RLIMIT_DATA; - break; - case 's': - res = RLIMIT_STACK; - break; - case 'c': - res = RLIMIT_CORE; - break; -# ifdef HAVE_RLIMIT_SBSIZE - case 'b': - res = RLIMIT_SBSIZE; - break; -# endif /* HAVE_RLIMIT_SBSIZE */ -# ifdef HAVE_RLIMIT_MEMLOCK - case 'l': - res = RLIMIT_MEMLOCK; - break; -# endif /* HAVE_RLIMIT_MEMLOCK */ -# ifdef HAVE_RLIMIT_RSS - case 'm': - res = RLIMIT_RSS; - break; -# endif /* HAVE_RLIMIT_RSS */ -# ifdef HAVE_RLIMIT_NOFILE - case 'n': - res = RLIMIT_NOFILE; - break; -# endif /* HAVE_RLIMIT_NOFILE */ -# ifdef HAVE_RLIMIT_NPROC - case 'u': - res = RLIMIT_NPROC; - break; -# endif /* HAVE_RLIMIT_NPROC */ -# if defined(HAVE_RLIMIT_VMEM) || defined(HAVE_RLIMIT_AS) - case 'v': -# ifdef HAVE_RLIMIT_VMEM - res = RLIMIT_VMEM; -# else - res = RLIMIT_AS; -# endif - break; -# endif /* HAVE_RLIMIT_VMEM */ -# ifdef HAVE_RLIMIT_LOCKS - case 'x': - res = RLIMIT_LOCKS; - break; -# endif -# ifdef HAVE_RLIMIT_SIGPENDING - case 'i': - res = RLIMIT_SIGPENDING; - break; -# endif -# ifdef HAVE_RLIMIT_MSGQUEUE - case 'q': - res = RLIMIT_MSGQUEUE; - break; -# endif -# ifdef HAVE_RLIMIT_NICE - case 'e': - res = RLIMIT_NICE; - break; -# endif -# ifdef HAVE_RLIMIT_RTPRIO - case 'r': - res = RLIMIT_RTPRIO; - break; -# else -# ifdef HAVE_RLIMIT_NTHR - /* For compatibility with sh on NetBSD */ - case 'r': - res = RLIMIT_NTHR; - break; -# endif /* HAVE_RLIMIT_NTHR */ -# endif -# ifdef HAVE_RLIMIT_NPTS - case 'p': - res = RLIMIT_NPTS; - break; -# endif -# ifdef HAVE_RLIMIT_SWAP - case 'w': - res = RLIMIT_SWAP; - break; -# endif -# ifdef HAVE_RLIMIT_KQUEUES - case 'k': - res = RLIMIT_KQUEUES; - break; -# endif -# ifdef HAVE_RLIMIT_PTHREAD - case 'T': - res = RLIMIT_PTHREAD; - break; -# endif -# ifdef HAVE_RLIMIT_UMTXP - case 'o': - res = RLIMIT_UMTXP; - break; -# endif default: - /* unrecognised limit */ - zwarnnam(name, "bad option: -%c", *options); - return 1; + res = find_resource(*options); + if (res < 0) { + /* unrecognised limit */ + zwarnnam(name, "bad option: -%c", *options); + return 1; + } + break; } if (options[1]) { resmask |= 1 << res; @@ -961,34 +819,8 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) return 1; } /* scale appropriately */ - switch (res) { - case RLIMIT_FSIZE: - case RLIMIT_CORE: - limit *= 512; - break; - case RLIMIT_DATA: - case RLIMIT_STACK: -# ifdef HAVE_RLIMIT_RSS - case RLIMIT_RSS: -# endif /* HAVE_RLIMIT_RSS */ -# ifdef HAVE_RLIMIT_MEMLOCK - case RLIMIT_MEMLOCK: -# endif /* HAVE_RLIMIT_MEMLOCK */ -/* If RLIMIT_VMEM and RLIMIT_RSS are defined and equal, avoid * - * duplicate case statement. Observed on QNX Neutrino 6.1.0. */ -# if defined(HAVE_RLIMIT_VMEM) && !defined(RLIMIT_VMEM_IS_RSS) - case RLIMIT_VMEM: -# endif /* HAVE_RLIMIT_VMEM */ -/* ditto RLIMIT_VMEM and RLIMIT_AS */ -# if defined(HAVE_RLIMIT_AS) && !defined(RLIMIT_VMEM_IS_AS) && !defined(RLIMIT_RSS_IS_AS) - case RLIMIT_AS: -# endif /* HAVE_RLIMIT_AS */ -# ifdef HAVE_RLIMIT_AIO_MEM - case RLIMIT_AIO_MEM: -# endif /* HAVE_RLIMIT_AIO_MEM */ - limit *= 1024; - break; - } + if (res < RLIM_NLIMITS) + limit *= resinfo[res]->unit; } if (do_limit(name, res, limit, hard, soft, 1)) ret++; @@ -1052,6 +884,7 @@ enables_(Module m, int **enables) int boot_(UNUSED(Module m)) { + set_resinfo(); return 0; } @@ -1059,6 +892,7 @@ boot_(UNUSED(Module m)) int cleanup_(Module m) { + free_resinfo(); return setfeatureenables(m, &module_features, NULL); } diff --git a/Src/Builtins/rlimits.mdd b/Src/Builtins/rlimits.mdd index 9e6e9e598..06c9e9c7f 100644 --- a/Src/Builtins/rlimits.mdd +++ b/Src/Builtins/rlimits.mdd @@ -6,18 +6,3 @@ autofeatures="b:limit b:ulimit b:unlimit" autofeatures_emu="b:ulimit" objects="rlimits.o" - -:<<\Make -rlimits.o rlimits..o: rlimits.h - -# this file will not be made if limits are unavailable -rlimits.h: rlimits.awk @RLIMITS_INC_H@ - $(AWK) -f $(sdir)/rlimits.awk @RLIMITS_INC_H@ /dev/null > rlimits.h - @if grep ZLIMTYPE_UNKNOWN rlimits.h >/dev/null; then \ - echo >&2 WARNING: unknown limits: mail Src/Builtins/rlimits.h to developers; \ - else :; fi - -clean-here: clean.rlimits -clean.rlimits: - rm -f rlimits.h -Make diff --git a/Test/B12limit.ztst b/Test/B12limit.ztst new file mode 100644 index 000000000..5dd7afdbe --- /dev/null +++ b/Test/B12limit.ztst @@ -0,0 +1,10 @@ +# check if there is unknown resouce(s) + +%test + + limit | grep UNKNOWN || print OK +0:Check if there is unknown resouce(s) in the system +>OK +F:A failure here does not indicate any error in zsh. It just means there +F:is a resource in your system that is unknown to zsh developers. Please +F:report this to zsh-workers mailing list. diff --git a/configure.ac b/configure.ac index f2d65ecfc..2f1e0c41e 100644 --- a/configure.ac +++ b/configure.ac @@ -1928,6 +1928,7 @@ zsh_LIMIT_PRESENT(RLIMIT_SIGPENDING) zsh_LIMIT_PRESENT(RLIMIT_MSGQUEUE) zsh_LIMIT_PRESENT(RLIMIT_NICE) zsh_LIMIT_PRESENT(RLIMIT_RTPRIO) +zsh_LIMIT_PRESENT(RLIMIT_RTTIME) zsh_LIMIT_PRESENT(RLIMIT_POSIXLOCKS) zsh_LIMIT_PRESENT(RLIMIT_NPTS) zsh_LIMIT_PRESENT(RLIMIT_SWAP) -- cgit v1.2.3 From dd85abe825065f95ad568a235be1f280855100ab Mon Sep 17 00:00:00 2001 From: Jun-ichi Takimoto Date: Fri, 6 Mar 2020 20:14:21 +0900 Subject: 45509: fix typos in B01cd.ztst --- ChangeLog | 2 ++ Test/B01cd.ztst | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6735e224b..8113dd29d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2020-03-06 Jun-ichi Takimoto + * 45509: Test/B01cd.ztst: Fix typos. + * 45490 (+45495 and a test): .gitignore, Src/Builtins/rlimits.awk, Src/Builtins/rlimits.c, Src/Builtins/rlimits.mdd, Test/B12limit.ztst, configure.ac: diff --git a/Test/B01cd.ztst b/Test/B01cd.ztst index d903b7462..21e751dcb 100644 --- a/Test/B01cd.ztst +++ b/Test/B01cd.ztst @@ -70,7 +70,7 @@ # the expected status returned by the code when run, or - if it is # irrelevant. An optional set of single-letter flags follows the status # or -. The following are understood: -# . d Don't diff stdout against the expected stdout. +# d Don't diff stdout against the expected stdout. # D Don't diff stderr against the expected stderr. # q All redirection lines given in the test script (not the lines # actually produced by the test) are subject to ordinary quoted shell @@ -96,8 +96,8 @@ # itself. (The example below isn't particularly useful as errors with # `cd' are unusual.) # -# A couple of features aren't used in this file, but are usefuil in cases -# where features may not be available so should not be tested. They boh +# A couple of features aren't used in this file, but are useful in cases +# where features may not be available so should not be tested. They both # take the form of variables. Note that to keep the test framework simple # there is no magic in setting the variables: the chunk of code being # executed needs to avoid executing any test code by appropriate structure -- cgit v1.2.3 From dd50f125b5eb65896642d2ff664adefd33f1004c Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Fri, 6 Mar 2020 14:00:29 +0000 Subject: unposted: Remove 'sgi', as that OpenBSD port has been discontinued. See https://www.openbsd.org/sgi.html and discussion on github PR #49. --- ChangeLog | 5 +++++ Completion/BSD/Type/_obsd_architectures | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 8113dd29d..2824bf69a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-03-06 Daniel Shahaf + + * unposted: Completion/BSD/Type/_obsd_architectures: Remove + 'sgi', as that OpenBSD port has been discontinued. + 2020-03-06 Jun-ichi Takimoto * 45509: Test/B01cd.ztst: Fix typos. diff --git a/Completion/BSD/Type/_obsd_architectures b/Completion/BSD/Type/_obsd_architectures index 18ee2854c..cec000a08 100644 --- a/Completion/BSD/Type/_obsd_architectures +++ b/Completion/BSD/Type/_obsd_architectures @@ -3,4 +3,4 @@ local expl _description architectures expl 'architecture' -compadd "$@" "$expl[@]" alpha amd64 arm64 armv7 hppa i386 landisk loongson luna88k macppc octeon sgi sparc64 +compadd "$@" "$expl[@]" alpha amd64 arm64 armv7 hppa i386 landisk loongson luna88k macppc octeon sparc64 -- cgit v1.2.3