1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-01 21:51:40 +02:00

Merge remote-tracking branch 'origin/master' into 5.9

* Test/D02glob.ztst:
  On the "unreadable directories can be globbed (users/24619, users/24626)"
  test, resolve conflicts by removing the Cygwin-only skip that has been added
  in master, since the test is passing on this branch.  This effectively reverts
  workers/45492.  See discussion starting in workers/45504.

* origin/master:
  unposted: Remove 'sgi', as that OpenBSD port has been discontinued.
  45509: fix typos in B01cd.ztst
  45490 (+45495 and a test): refactor rlimits.c
  github #49: Fix typo: longson should be loongson
  users/24710: Fix job control problem with sudo.
  45492: skip test added by users/24633 on Cygwin
  45488: COMP_WORDS for bash need "$@"-style quoting
  45487: Missing mod_export declarations for AIX
  45447: Complete vcs_info_hookadd and vcs_info_hookdel. Expose _vcs_info_hooks as a top-level helper function.
  45463: test: kill: Document why we use SIGURG
  45453: builtins: kill: Do not signal current process group when pid is empty
  45452: builtins: kill: Add `kill ''` regression test with explicit sigspec
  45451: builtins: kill: Add basic test suite
  github #48/0002: vcs_info git: properly detect bare repositories
  github #48/0001: vcs_info git: avoid warnings in bare repositories
  unposted: Post-release version bump
  unposted: Release 5.8
  CVE-2019-20044: Update change log for preceding commits
  Update NEWS/README
  Add unsetopt/PRIVILEGED tests
  Clean up error-message white space
  Improve PRIVILEGED fixes (again)
  Improve PRIVILEGED fixes
  Drop privileges securely
  unposted: V01zmodload: Fix failing test from workers/45385
  45423: _su: Improve arg handling, shell look-ups
  unposted: _zip: Recognise '--'
  45385: Add a test for 'zmodload -Fa' preemptively disabling ("blacklisting"?) features.
  unposted: Test release: 5.7.1-test-3
  zsh/system: Fix infinite loop in sysread
  _diff_options: Restore -w completion lost in workers/43351
  unposted: Fix ChangeLog typo.
  45368: Add tests for workers/45367's issue about double slashes in 'cd -P' and /home/daniel/in/zsh.
  45373: Fix ERR_EXIT bug in else branch of if.
  45372: Record a symlink loop bug involving :P
  45365: _git: Fix __git_recent_branches for the case when a commit has an empty message
  45343: Queue signals around arithmetic evaluations
  45344: Document where third-party completion functions should be installed.
  45345: internal: ztst.vim: Fix highlighting of zsh comments in test payload
  unposted: internal: Add some comments and fix indentation.  No functional change.
  45340: internal: Document the difference between paramtab and realparamtab.
  45332: _git: add completion for git-version
  _brace_parameter: add missing \

Conflicts:
	ChangeLog
	Test/D02glob.ztst
	Test/V01zmodload.ztst
This commit is contained in:
Daniel Shahaf 2020-03-07 21:36:46 +00:00
commit 6fc8e8628f
50 changed files with 1288 additions and 676 deletions

1
.gitignore vendored
View file

@ -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

163
ChangeLog
View file

@ -57,6 +57,169 @@
* 45131: Src/exec.c, Test/E02xtrace.ztst: Make a function that
redefines itself preserve its tracedness.
2020-03-06 Daniel Shahaf <danielsh@apache.org>
* unposted: Completion/BSD/Type/_obsd_architectures: Remove
'sgi', as that OpenBSD port has been discontinued.
2020-03-06 Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
* 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:
Refactor rlimits.c.
2020-03-05 Bryan Irvine <sparctacus@gmail.com>
* github #49: Completion/BSD/Type/_obsd_architectures: Fix typo:
longson should be loongson
2020-02-27 Peter Stephenson <p.w.stephenson@ntlworld.com>
* 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 <takimoto-j@kba.biglobe.ne.jp>
* 45492: Test/D02glob.ztst: skip test added by users/24633
on Cygwin.
2020-02-25 Peter Stephenson <p.stephenson@samsung.com>
* 45488: Marc Cornella: Completion/bashcompinit: Need "$@"
quoting for empty words in COMP_WORDS for bash completion.
2020-02-24 Peter Stephenson <p.stephenson@samsung.com>
* 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 <danielsh@apache.org>
* 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 <chris@chrisdown.name>
* 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
* 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 <sandals@crustytoothpaste.net>
* 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
2020-02-14 dana <dana@dana.is>
* 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,
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
* 45423 (tweaked): Completion/Unix/Command/_su: Improve arg
handling, shell look-ups
2020-02-07 dana <dana@dana.is>
* unposted: Completion/Unix/Command/_zip: Recognise '--'
2020-02-06 Daniel Shahaf <danielsh@apache.org>
* 45385: Test/V01zmodload.ztst: Add a test for 'zmodload -Fa'
preemptively disabling ("blacklisting"?) features.
2020-02-06 dana <dana@dana.is>
* unposted: Config/version.mk: Update for 5.7.1-test-3
* 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
2020-02-03 Daniel Shahaf <danielsh@apache.org>
* 45368: Test/B01cd.ztst, Test/D02glob.ztst: Add tests for
workers/45367's issue about double slashes in 'cd -P' and
$PWD.
2020-02-02 Peter Stephenson <p.w.stephenson@ntlworld.com>
* 45373: Src/loop.c, Test/C03traps.ztst: ERR_EXIT failed on
command substitution in else branch.
2020-02-02 Daniel Shahaf <danielsh@apache.org>
* 45372: Etc/BUGS: Record a symlink loop bug involving :P
2020-02-02 WGH <wgh@torlan.ru>
* 45365: Completion/Unix/Command/_git: Fix __git_recent_branches
for the case when a commit has an empty message
2020-01-29 Daniel Shahaf <danielsh@apache.org>
* 45343: Src/exec.c, Src/math.c: Queue signals around arithmetic
evaluations
* 45344: INSTALL: Document where third-party completion functions
should be installed.
2020-01-28 Daniel Shahaf <danielsh@apache.org>
* 45345: Util/ztst-syntax.vim: internal: ztst.vim: Fix
highlighting of zsh comments in test payload
2020-01-26 Daniel Shahaf <danielsh@apache.org>
* unposted: Src/init.c: internal: Add some comments and fix
indentation. No functional change.
2020-01-23 Daniel Shahaf <danielsh@apache.org>
* 45340: Src/params.c: internal: Document the difference between
paramtab and realparamtab.
2020-01-19 Eitan Adler <lists@eitanadler.com>
* 45332: Completion/Unix/Command/_git: add completion for
git-version
2020-01-19 Mikael Magnusson <mikachu@gmail.com>
* unposted: _brace_parameter: add missing \
2020-01-16 Daniel Shahaf <danielsh@apache.org>
* 45305: Test/A01grammar.ztst: Add an XFail test: The

View file

@ -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 sparc64

View file

@ -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'
@ -6655,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

View file

@ -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)$(</etc/passwd)}:#$usr*}##*:}"
shell="${${(M@)${(@f)$(</etc/passwd)}:#${usr}:*}##*:}"
fi
case $state in

View file

@ -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

View file

@ -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]' \

View file

@ -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

View file

@ -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 ''
;;

View file

@ -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'

View file

@ -0,0 +1,2 @@
#autoload
compadd - ${functions[(I)+vi-*]#+vi-}

View file

@ -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} )

View file

@ -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.8.0.1-dev
VERSION_DATE='February 15, 2020'

View file

@ -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
------------------------------------------------------------------------

View file

@ -138,7 +138,11 @@ 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 )
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)

10
INSTALL
View file

@ -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

18
NEWS
View file

@ -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 <samfoxman320@gmail.com>. ]
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.

11
README
View file

@ -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.
@ -60,6 +61,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
-----------------------------------------

View file

@ -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)
}

View file

@ -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;
# include "rlimits.h"
/* 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
};
/* 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; i<sizeof(known_resources)/sizeof(resinfo_T); ++i) {
resinfo[known_resources[i].res] = &known_resources[i];
}
for (i=0; i<RLIM_NLIMITS; ++i) {
if (!resinfo[i]) {
/* unknown resource */
resinfo_T *info = (resinfo_T *)zshcalloc(sizeof(resinfo_T));
char *buf = (char *)zalloc(12);
snprintf(buf, 12, "UNKNOWN-%d", i);
info->res = - 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; i<RLIM_NLIMITS; ++i) {
if (resinfo[i]->res < 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; i<RLIM_NLIMITS; ++i) {
if (resinfo[i]->opt == 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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -404,7 +404,7 @@ scankeys(HashNode hn, UNUSED(int flags))
/**************************/
/**/
Keymap
mod_export Keymap
openkeymap(char *name)
{
KeymapName n = (KeymapName) keymapnamtab->getnode(keymapnamtab, name);

View file

@ -1056,7 +1056,7 @@ getrestchar(int inchar, char *outstr, int *outcount)
#endif
/**/
void
mod_export void
redrawhook(void)
{
Thingy initthingy;

View file

@ -166,7 +166,7 @@ decpos(int *pos)
*/
/**/
char *
mod_export char *
backwardmetafiedchar(char *start, char *endptr, convchar_t *retchr)
{
#ifdef MULTIBYTE_SUPPORT

View file

@ -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;

View file

@ -496,7 +496,7 @@ zgetdir(struct dirsav *d)
*/
/**/
char *
mod_export char *
zgetcwd(void)
{
char *ret = zgetdir(NULL);

View file

@ -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);
@ -5101,7 +5102,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 +5121,6 @@ execarith(Estate state, UNUSED(int do_exec))
fprintf(xtrerr, " ))\n");
fflush(xtrerr);
}
unqueue_signals();
if (errflag) {
errflag &= ~ERRFLAG_ERROR;
return 2;

View file

@ -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

View file

@ -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);
@ -1854,13 +1859,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';
@ -2469,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

View file

@ -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;

View file

@ -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();
}

129
Src/openssh_bsd_setres_id.c Normal file
View file

@ -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 <sys/types.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#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

View file

@ -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,24 @@ 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))
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);
else if(dosetopt(optno, action, 0, opts))
retval |= 1;
} else if (dosetopt(optno, action, 0, opts)) {
zwarnnam(nam, "can't change option: -%c", **args);
retval |= 1;
}
}
}
args++;
@ -625,10 +632,13 @@ 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))
retval |= 1;
} else if (dosetopt(optno, !isun, 0, opts)) {
zwarnnam(nam, "can't change option: %s", args[-1]);
retval |= 1;
}
}
} else {
/* Globbing option (-m) set. */
@ -651,7 +661,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 +671,7 @@ bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun)
}
}
inittyptab();
return 0;
return retval;
}
/* Identify an option name */
@ -769,37 +780,99 @@ 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;
/* 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;
const int orig_euid = geteuid();
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.
*
* 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;
if (setresgid(getgid(), getgid(), getgid())) {
zwarnnam("unsetopt",
"PRIVILEGED: can't drop privileges; failed to change group ID: %e",
errno);
return -1;
}
#else
zwarn("setuid not available");
return -1;
#endif /* not HAVE_SETUID */
# ifdef HAVE_INITGROUPS
/* 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. */
# 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;
}
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;
}
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;
}
if (failed) {
/* A warning message has been printed. */
return -1;
}
#endif /* HAVE_SETRESGID && HAVE_SETRESUID */
#ifdef JOB_CONTROL
} else if (!force && optno == MONITOR && value) {
if (new_opts[optno] == value)

View file

@ -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;

View file

@ -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)) {
/*

View file

@ -1023,7 +1023,7 @@ xsymlinks(char *s, int full)
*/
/**/
char *
mod_export char *
xsymlink(char *s, int heap)
{
if (*s != '/')

View file

@ -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"

View file

@ -468,32 +468,92 @@ 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 */
#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
/* 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
# 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
# include <sys/resource.h>
# if defined(__hpux) && !defined(RLIMIT_CPU)

View file

@ -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
@ -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

86
Test/B11kill.ztst Normal file
View file

@ -0,0 +1,86 @@
# 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
# 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
kill -URG ''
)
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:

10
Test/B12limit.ztst Normal file
View file

@ -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.

View file

@ -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

View file

@ -753,6 +753,10 @@
0:non-directories not globbed as directories
>glob.tmp/not-a-directory ,
() { echo $1:P } ////dev
-f:(workers/45367) modifier ':P' squashes multiple slashes
>/dev
%clean
# Fix unreadable-directory permissions so ztst can clean up properly

View file

@ -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
@ -1391,3 +1399,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

197
Test/P01privileged.ztst Normal file
View file

@ -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

View file

@ -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

View file

@ -389,6 +389,22 @@
0:unloading a module doesn't implicitly unset autoloadable parameters
*>(on|off) *
$ZTST_testdir/../Src/zsh -fc "
MODULE_PATH=${(q)MODULE_PATH}
#
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"

View file

@ -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

View file

@ -1312,6 +1312,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
getlogin getpwent getpwnam getpwuid getgrgid getgrnam \
initgroups nis_list \
setuid seteuid setreuid setresuid setsid \
setgid setegid setregid setresgid \
memcpy memmove strstr strerror strtoul \
getrlimit getrusage \
setlocale \
@ -1928,6 +1929,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)