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. --- Src/params.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'Src') 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(-) (limited to 'Src') 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 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(-) (limited to 'Src') 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 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(-) (limited to 'Src') 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 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(-) (limited to 'Src') 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 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(-) (limited to 'Src') 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 (limited to 'Src') 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(-) (limited to 'Src') 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(-) (limited to 'Src') 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 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(-) (limited to 'Src') 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 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(-) (limited to 'Src') 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 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(-) (limited to 'Src') 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 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 (limited to 'Src') 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