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:
commit
6fc8e8628f
50 changed files with 1288 additions and 676 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -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
163
ChangeLog
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]' \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ''
|
||||
;;
|
||||
|
||||
|
|
31
Completion/Zsh/Function/_vcs_info
Normal file
31
Completion/Zsh/Function/_vcs_info
Normal 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'
|
2
Completion/Zsh/Type/_vcs_info_hooks
Normal file
2
Completion/Zsh/Type/_vcs_info_hooks
Normal file
|
@ -0,0 +1,2 @@
|
|||
#autoload
|
||||
compadd - ${functions[(I)+vi-*]#+vi-}
|
|
@ -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} )
|
||||
|
|
|
@ -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'
|
||||
|
|
2
Etc/BUGS
2
Etc/BUGS
|
@ -29,3 +29,5 @@ skipped when STTY=... is set for that command
|
|||
44007 - Martijn - exit in trap executes rest of function
|
||||
See test case in Test/C03traps.ztst.
|
||||
------------------------------------------------------------------------
|
||||
45282: ${${:-foo}:P} where foo is a symlink that points to itself segfaults
|
||||
------------------------------------------------------------------------
|
||||
|
|
|
@ -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
10
INSTALL
|
@ -251,6 +251,16 @@ source code in the directory that "configure" is in. For example,
|
|||
Note that this is mutually exclusive with using the source directories
|
||||
as make can become confused by build files created in the source directories.
|
||||
|
||||
Writing third-party autoloadable functions
|
||||
------------------------------------------
|
||||
|
||||
Third-party autoloadable functions, including but not limited to completion
|
||||
functions, should be installed into the share/zsh/site-functions/ directory
|
||||
under the respective installation prefix. That would typically be written as
|
||||
$(DESTDIR)$(PREFIX)/share/zsh/site-functions/ in a makefile. If the
|
||||
third-party tool's $(PREFIX) is not the same as zsh's prefix, then that
|
||||
directory should be added to $fpath in zsh's initialization files.
|
||||
|
||||
|
||||
================================
|
||||
AUTOMATIC NEW USER CONFIGURATION
|
||||
|
|
18
NEWS
18
NEWS
|
@ -4,8 +4,22 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
|
|||
|
||||
Note also the list of incompatibilities in the README file.
|
||||
|
||||
Changes since 5.7.1
|
||||
-------------------
|
||||
Changes since 5.7.1-test-3
|
||||
--------------------------
|
||||
|
||||
CVE-2019-20044: When unsetting the PRIVILEGED option, the shell sets its
|
||||
effective user and group IDs to match their respective real IDs. On some
|
||||
platforms (including Linux and macOS, but not FreeBSD), when the RUID and
|
||||
EUID were both non-zero, it was possible to regain the shell's former
|
||||
privileges by e.g. assigning to the EUID or EGID parameter. In the course
|
||||
of investigating this issue, it was also found that the setopt built-in
|
||||
did not correctly report errors when unsetting the option, which
|
||||
prevented users from handling them as the documentation recommended.
|
||||
setopt now returns non-zero if it is unable to safely drop privileges.
|
||||
[ Reported by Sam Foxman <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
11
README
|
@ -5,8 +5,9 @@ THE Z SHELL (ZSH)
|
|||
Version
|
||||
-------
|
||||
|
||||
This is version 5.8 of the shell. This is a stable release. There are
|
||||
a few visible improvements since 5.7 as well as many bugfixes.
|
||||
This is version 5.8 of the shell. This is a security and feature release.
|
||||
There are a few visible improvements since 5.7, as well as many bugfixes.
|
||||
All zsh installations are encouraged to upgrade as soon as possible.
|
||||
|
||||
Note in particular the changes highlighted under "Incompatibilities since
|
||||
5.7.1" below. See NEWS for more information.
|
||||
|
@ -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
|
||||
-----------------------------------------
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -404,7 +404,7 @@ scankeys(HashNode hn, UNUSED(int flags))
|
|||
/**************************/
|
||||
|
||||
/**/
|
||||
Keymap
|
||||
mod_export Keymap
|
||||
openkeymap(char *name)
|
||||
{
|
||||
KeymapName n = (KeymapName) keymapnamtab->getnode(keymapnamtab, name);
|
||||
|
|
|
@ -1056,7 +1056,7 @@ getrestchar(int inchar, char *outstr, int *outcount)
|
|||
#endif
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
redrawhook(void)
|
||||
{
|
||||
Thingy initthingy;
|
||||
|
|
|
@ -166,7 +166,7 @@ decpos(int *pos)
|
|||
*/
|
||||
|
||||
/**/
|
||||
char *
|
||||
mod_export char *
|
||||
backwardmetafiedchar(char *start, char *endptr, convchar_t *retchr)
|
||||
{
|
||||
#ifdef MULTIBYTE_SUPPORT
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -496,7 +496,7 @@ zgetdir(struct dirsav *d)
|
|||
*/
|
||||
|
||||
/**/
|
||||
char *
|
||||
mod_export char *
|
||||
zgetcwd(void)
|
||||
{
|
||||
char *ret = zgetdir(NULL);
|
||||
|
|
|
@ -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;
|
||||
|
|
15
Src/init.c
15
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
|
||||
|
|
19
Src/jobs.c
19
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);
|
||||
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
15
Src/math.c
15
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();
|
||||
}
|
||||
|
|
129
Src/openssh_bsd_setres_id.c
Normal file
129
Src/openssh_bsd_setres_id.c
Normal 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
|
141
Src/options.c
141
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,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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
/*
|
||||
|
|
|
@ -1023,7 +1023,7 @@ xsymlinks(char *s, int full)
|
|||
*/
|
||||
|
||||
/**/
|
||||
char *
|
||||
mod_export char *
|
||||
xsymlink(char *s, int heap)
|
||||
{
|
||||
if (*s != '/')
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
86
Test/B11kill.ztst
Normal 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
10
Test/B12limit.ztst
Normal 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.
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
197
Test/P01privileged.ztst
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue