From f686d72fc5ebf74519e16effe77de2c9f42ab87d Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 01 2019 20:00:29 +0000 Subject: import zsh-5.0.2-34.el7 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1e455a7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/zsh-5.0.2.tar.bz2 diff --git a/.zsh.metadata b/.zsh.metadata new file mode 100644 index 0000000..1b94ba9 --- /dev/null +++ b/.zsh.metadata @@ -0,0 +1 @@ +9f55ecaaae7cdc1495f91237ba2ec087777a4ad9 SOURCES/zsh-5.0.2.tar.bz2 diff --git a/SOURCES/dotzshrc b/SOURCES/dotzshrc new file mode 100644 index 0000000..9935bec --- /dev/null +++ b/SOURCES/dotzshrc @@ -0,0 +1,34 @@ +# +# .zshrc is sourced in interactive shells. +# It should contain commands to set up aliases, +# functions, options, key bindings, etc. +# + +autoload -U compinit +compinit + +#allow tab completion in the middle of a word +setopt COMPLETE_IN_WORD + +## keep background processes at full speed +#setopt NOBGNICE +## restart running processes on exit +#setopt HUP + +## history +#setopt APPEND_HISTORY +## for sharing history between zsh processes +#setopt INC_APPEND_HISTORY +#setopt SHARE_HISTORY + +## never ever beep ever +#setopt NO_BEEP + +## automatically decide when to page a list of completions +#LISTMAX=0 + +## disable mail checking +#MAILCHECK=0 + +# autoload -U colors +#colors diff --git a/SOURCES/systemd-zsh-completion.zsh b/SOURCES/systemd-zsh-completion.zsh new file mode 100644 index 0000000..1ab1311 --- /dev/null +++ b/SOURCES/systemd-zsh-completion.zsh @@ -0,0 +1,1102 @@ +#compdef systemctl loginctl journalctl hostnamectl localectl timedatectl systemd-coredumpctl udevadm systemd-analyze systemd-cat systemd-ask-password systemd-cgls systemd-cgtop systemd-delta systemd-detect-virt systemd-inhibit systemd-machine-id-setup systemd-notify systemd-nspawn systemd-tmpfiles systemd-tty-ask-password-agent machinectl + +_ctls() +{ + local curcontext="$curcontext" state lstate line + case "$service" in + systemctl) + # -s for aggregated options like -aP + _arguments -s \ + {-h,--help}'[Show help]' \ + '--version[Show package version]' \ + {-t,--type=}'[List only units of a particular type]:unit type:(automount device mount path service snapshot socket swap target timer)' \ + \*{-p,--property=}'[Show only properties by specific name]:unit property' \ + {-a,--all}'[Show all units/properties, including dead/empty ones]' \ + '--reverse[Show reverse dependencies]' \ + '--after[Show units ordered after]' \ + '--before[Show units ordered before]' \ + '--failed[Show only failed units]' \ + {-l,--full}"[Don't ellipsize unit names on output]" \ + '--fail[When queueing a new job, fail if conflicting jobs are pending]' \ + '--ignore-dependencies[When queueing a new job, ignore all its dependencies]' \ + '--kill-who=[Who to send signal to]:killwho:(main control all)' \ + {-s,--signal=}'[Which signal to send]:signal:_signals' \ + {-H,--host=}'[Show information for remote host]:userathost:_hosts_or_user_at_host' \ + {-P,--privileged}'[Acquire privileges before execution]' \ + {-q,--quiet}'[Suppress output]' \ + '--no-block[Do not wait until operation finished]' \ + "--no-wall[Don't send wall message before halt/power-off/reboot]" \ + "--no-reload[When enabling/disabling unit files, don't reload daemon configuration]" \ + '--no-legend[Do not print a legend, i.e. the column headers and the footer with hints]' \ + '--no-pager[Do not pipe output into a pager]' \ + '--no-ask-password[Do not ask for system passwords]' \ + '--system[Connect to system manager]' \ + '--user[Connect to user service manager]' \ + '--global[Enable/disable unit files globally]' \ + {-f,--force}'[When enabling unit files, override existing symlinks. When shutting down, execute action immediately]' \ + '--root=[Enable unit files in the specified root directory]:directory:_directories' \ + '--runtime[Enable unit files only temporarily until next reboot]' \ + {-n,--lines=}'[Journal entries to show]:number of entries' \ + {-o,--output=}'[Change journal output mode]:modes:_outputmodes' \ + '*::systemctl command:_systemctl_command' + ;; + loginctl) + _arguments -s \ + {-h,--help}'[Show help]' \ + '--version[Show package version]' \ + \*{-p,--property=}'[Show only properties by this name]:unit property' \ + {-a,--all}'[Show all properties, including empty ones]' \ + '--kill-who=[Who to send signal to]:killwho:(main control all)' \ + {-s,--signal=}'[Which signal to send]:signal:_signals' \ + '--no-ask-password[Do not ask for system passwords]' \ + {-H,--host=}'[Show information for remote host]:userathost:_hosts_or_user_at_host' \ + {-P,--privileged}'[Acquire privileges before execution]' \ + '--no-pager[Do not pipe output into a pager]' \ + '*::loginctl command:_loginctl_command' + ;; + + hostnamectl) + _arguments -s \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--transient[Only set transient hostname]' \ + '--static[Only set static hostname]' \ + '--pretty[Only set pretty hostname]' \ + '--no-ask-password[Do not prompt for password]' \ + {-H,--host=}'[Operate on remote host]:userathost:_hosts_or_user_at_host' \ + '*::hostnamectl commands:_hostnamectl_command' + ;; + journalctl) + _arguments -s \ + '--since=[Start showing entries newer or of the specified date]:YYYY-MM-DD HH\:MM\:SS' \ + '--until=[Stop showing entries older or of the specified date]:YYYY-MM-DD HH\:MM\:SS' \ + {-c,--cursor=}'[Start showing entries from specified cursor]:cursors:_journal_fields __CURSORS' \ + '--system[Show system and kernel messages]' \ + '--user[Show messages from user services]' \ + {-b,--this-boot}'[Show data only from current boot]' \ + {-u,--unit=}'[Show data only from the specified unit]:units:_journal_fields _SYSTEMD_UNIT' \ + '--user-unit[Show data only from the specified user session unit]:units:_journal_fields _SYSTEMD_USER_UNIT' \ + {-p,--priority=}'[Show only messages within the specified priority range]:priority:_journal_fields PRIORITY' \ + {-f,--follow}'[Follow journal]' \ + {-n,--lines=}'[Number of journal entries to show]:integer' \ + '--no-tail[Show all lines, even in follow mode]' \ + {-o,--output=}'[Change journal output mode]:output modes:_outputmodes' \ + {-l,--full}'[Show long fields in full]' \ + {-a,--all}'[Show all fields, including long and unprintable]' \ + {-q,--quiet}"[Don't show privilege warning]" \ + '--no-pager[Do not pipe output into a pager]' \ + {-m,--merge}'[Show entries from all available journals]' \ + {-D,--directory=}'[Show journal files from directory]:directories:_directories' \ + '--interval=[Time interval for changing the FSS sealing key]:time interval' \ + '--verify-key=[Specify FSS verification key]:FSS key' \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--new-id128[Generate a new 128 Bit ID]' \ + '--header[Show journal header information]' \ + '--disk-usage[Show total disk usage]' \ + {-F,--field=}'[List all values a certain field takes]:Fields:_list_fields' \ + '--setup-keys[Generate new FSS key pair]' \ + '--verify[Verify journal file consistency]' \ + '--list-catalog[List messages in catalog]' \ + '--update-catalog[Update binary catalog database]' \ + '*::default: _journal_none' + ;; + localectl) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + "--no-convert[Don't convert keyboard mappings]" \ + '--no-pager[Do not pipe output into a pager]' \ + '--no-ask-password[Do not prompt for password]' \ + {-H,--host=}'[Operate on remote host]:userathost:_hosts_or_user_at_host' \ + '*::localectl commands:_localectl_command' + ;; + systemd-coredumpctl) + _arguments \ + {-o,--output=}'[Write output to FILE]:output file:_files' \ + '--no-pager[Do not pipe output into a pager]' \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '*::systemd-coredumpctl commands:_systemd-coredumpctl_command' + + ;; + timedatectl) + _arguments -s \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--adjust-system-clock[Adjust system clock when changing local RTC mode]' \ + '--no-pager[Do not pipe output into a pager]' \ + '--no-ask-password[Do not prompt for password]' \ + {-H,--host=}'[Operate on remote host]:userathost:_hosts_or_user_at_host' \ + '*::timedatectl commands:_timedatectl_command' + ;; + udevadm) + _arguments \ + '--debug[Print debug messages to stderr]' \ + '--version[Print version number]' \ + '--help[Print help text]' \ + '*::udevadm commands:_udevadm_command' + ;; + systemd-analyze) + _arguments \ + {-h,--help}'[Show help text.]' \ + '--user[Shows performance data of user sessions instead of the system manager.]' \ + '--order[When generating graph for dot, show only order]' \ + '--require[When generating graph for dot, show only requirement]' \ + '*::systemd-analyze commands:_systemd_analyze_command' + ;; + systemd-ask-password) + _arguments \ + {-h,--help}'[Show this help]' \ + '--icon=[Icon name]' \ + '--timeout=[Timeout in sec]' \ + '--no-tty[Ask question via agent even on TTY]' \ + '--accept-cached[Accept cached passwords]' \ + '--multiple[List multiple passwords if available]' + ;; + systemd-cat) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version.]' \ + {-t,--identifier=}'[Set syslog identifier.]' \ + {-p,--priority=}'[Set priority value.]:value:({0..7})' \ + '--level-prefix=[Control whether level prefix shall be parsed.]:boolean:(1 0)' \ + ':Message' + ;; + systemd-cgls) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--no-pager[Do not pipe output into a pager]' \ + {-a,--all}'[Show all groups, including empty]' \ + '-k[Include kernel threads in output]' \ + ':cgroups:(cpuset cpu cpuacct memory devices freezer net_cls blkio)' + ;; + systemd-cgtop) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Print version and exit]' \ + '(-c -m -i -t)-p[Order by path]' \ + '(-c -p -m -i)-t[Order by number of tasks]' \ + '(-m -p -i -t)-c[Order by CPU load]' \ + '(-c -p -i -t)-m[Order by memory load]' \ + '(-c -m -p -t)-i[Order by IO load]' \ + {-d,--delay=}'[Specify delay]' \ + {-n,--iterations=}'[Run for N iterations before exiting]' \ + {-b,--batch}'[Run in batch mode, accepting no input]' \ + '--depth=[Maximum traversal depth]' + ;; + systemd-delta) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--no-pager[Do not pipe output into a pager]' \ + '--diff=[Show a diff when overridden files differ]:boolean:(1 0)' \ + {-t,--type=}'[Only display a selected set of override types]:types:(masked equivalent redirected overridden unchanged)' \ + ':SUFFIX:(tmpfiles.d sysctl.d systemd/system)' + ;; + systemd-detect-virt) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + {-c,--container}'[Only detect whether we are run in a container]' \ + {-v,--vm}'[Only detect whether we are run in a VM]' \ + {-q,--quiet}"[Don't output anything, just set return value]" + ;; + systemd-inhibit) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--what=[Operations to inhibit]:options:(shutdown sleep idle handle-power-key handle-suspend-key handle-hibernate-key handle-lid-switch)' \ + '--who=[A descriptive string who is inhibiting]' \ + '--why=[A descriptive string why is being inhibited]' \ + '--mode=[One of block or delay]' \ + '--list[List active inhibitors]' \ + '*:commands:_systemd_inhibit_command' + ;; + systemd-machine-id-setup) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' + ;; + systemd-notify) + _arguments \ + {-h,--help}'[Show this help]' \ + '--version[Show package version]' \ + '--ready[Inform the init system about service start-up completion.]' \ + '--pid=[Inform the init system about the main PID of the daemon]' \ + '--status=[Send a free-form status string for the daemon to the init systemd]' \ + '--booted[Returns 0 if the system was booted up with systemd]' \ + '--readahead=[Controls disk read-ahead operations]:arguments:(cancel done noreply)' + ;; + systemd-nspawn) + _arguments \ + {-h,--help}'[Show this help]' \ + {--directory=,-D}'[Directory to use as file system root for the namespace container. If omitted the current directory will be used.]:directories:_directories' \ + {--boot,-b}'[Automatically search for an init binary and invoke it instead of a shell or a user supplied program.]' \ + {--user=,-u}'[Run the command under specified user, create home directory and cd into it.]' \ + '--uuid=[Set the specified uuid for the container.]' \ + {--controllers=,-C}'[Makes the container appear in other hierarchies than the name=systemd:/ one. Takes a comma-separated list of controllers.]' \ + '--private-network[Turn off networking in the container. This makes all network interfaces unavailable in the container, with the exception of the loopback device.]' \ + '--read-only[Mount the root file system read only for the container.]' \ + '--capability=[List one or more additional capabilities to grant the container.]:capabilities:_systemd-nspawn' \ + "--link-journal=[Control whether the container's journal shall be made visible to the host system.]:options:(no, host, guest, auto)" \ + '-j[Equivalent to --link-journal=guest.]' + ;; + systemd-tmpfiles) + _arguments \ + '--create[Create, set ownership/permissions based on the config files.]' \ + '--clean[Clean up all files and directories with an age parameter configured.]' \ + '--remove[All files and directories marked with r, R in the configuration files are removed.]' \ + '--prefix=[Only apply rules that apply to paths with the specified prefix.]' \ + '--exclude-prefix=[Ignore rules that apply to paths with the specified prefix.]' \ + '--help[Prints a short help text and exits.]' \ + '*::files:_files' + ;; + systemd-tty-ask-password-agent) + _arguments \ + {-h,--help}'[Prints a short help text and exits.]' \ + '--version[Prints a short version string and exits.]' \ + '--list[Lists all currently pending system password requests.]' \ + '--query[Process all currently pending system password requests by querying the user on the calling TTY.]' \ + '--watch[Continuously process password requests.]' \ + '--wall[Forward password requests to wall(1).]' \ + '--plymouth[Ask question with plymouth(8).]' \ + '--console[Ask question on /dev/console.]' + ;; + machinectl) + _arguments \ + {-h,--help}'[Prints a short help text and exits.]' \ + '--version[Prints a short version string and exits.]' \ + {-p,--property=}'[Limit output to specified property.]:property:(Name Id Timestamp TimestampMonotonic Service Scope Leader Class State RootDirectory)' \ + {-a,--all}'[Show all proerties]' \ + (-l,--full)'[Do not ellipsize cgroup members]' \ + '--no-pager[Do not pipe output into a pager]' \ + '--no-ask-password[Do not ask for system passwords]' \ + '--kill-who=[Who to send signal to]:killwho:(leader all)' \ + {-s,--signal=}'[Which signal to send]:signal:_signals' \ + {-H,--host=}'[Show information for remote host]:userathost:_hosts_or_user_at_host' \ + {-P,--privileged}'[Acquire privileges before execution]' \ + '*::machinectl command:_machinectl_command' + ;; + *) _message 'eh?' ;; + esac +} + +_systemd-nspawn(){ + local -a _caps + _caps=( CAP_CHOWN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH + CAP_FOWNER CAP_FSETID CAP_IPC_OWNER CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE + CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETGID CAP_SETFCAP CAP_SETPCAP + CAP_SETUID CAP_SYS_ADMIN CAP_SYS_CHROOT CAP_SYS_NICE CAP_SYS_PTRACE CAP_SYS_TTY_CONFIG + CAP_SYS_RESOURCE CAP_SYS_BOOT ) + _values -s , 'capabilities' "$_caps[@]" +} + +_systemd_inhibit_command(){ + if (( CURRENT == 1 )); then + compset -q + _normal + else + local n=${words[(b:2:i)[^-]*]} + if (( n <= CURRENT )); then + compset -n $n + _alternative \ + 'files:file:_files' \ + 'commands:command:_normal' && return 0 + fi + _default + fi + +} + +_systemd_analyze_command(){ + local -a _systemd_analyze_cmds + # Descriptions taken from systemd-analyze --help. + _systemd_analyze_cmds=( + 'time:Print time spent in the kernel before reaching userspace' + 'blame:Print list of running units ordered by time to init' + 'critical-chain:Print a tree of the time critical chain of units' + 'plot:Output SVG graphic showing service initialization' + 'dot:Dump dependency graph (in dot(1) format)' + ) + + if (( CURRENT == 1 )); then + _describe "options" _systemd_analyze_cmds + else + _message "no more options" + fi +} + +_hosts_or_user_at_host() +{ + _alternative \ + 'users-hosts:: _user_at_host' \ + 'hosts:: _hosts' +} + +_outputmodes() { + local -a _output_opts + _output_opts=(short short-monotonic verbose export json json-pretty json-see cat) + _describe -t output 'output mode' _output_opts || compadd "$@" +} + + +(( $+functions[_systemctl_command] )) || _systemctl_command() +{ + local -a _systemctl_cmds + _systemctl_cmds=( + "list-units:List units" + "start:Start (activate) one or more units" + "stop:Stop (deactivate) one or more units" + "reload:Reload one or more units" + "restart:Start or restart one or more units" + "condrestart:Restart one or more units if active" + "try-restart:Restart one or more units if active" + "reload-or-restart:Reload one or more units if possible, otherwise start or restart" + "force-reload:Reload one or more units if possible, otherwise restart if active" + "hibernate:Hibernate the system" + "hybrid-sleep:Hibernate and suspend the system" + "reload-or-try-restart:Reload one or more units if possible, otherwise restart if active" + "isolate:Start one unit and stop all others" + "kill:Send signal to processes of a unit" + "is-active:Check whether units are active" + "is-failed:Check whether units are failed" + "status:Show runtime status of one or more units" + "show:Show properties of one or more units/jobs or the manager" + "reset-failed:Reset failed state for all, one, or more units" + "load:Load one or more units" + "list-unit-files:List installed unit files" + "enable:Enable one or more unit files" + "disable:Disable one or more unit files" + "reenable:Reenable one or more unit files" + "preset:Enable/disable one or more unit files based on preset configuration" + "help:Show documentation for specified units" + "list-dependencies:Show unit dependency tree" + "mask:Mask one or more units" + "unmask:Unmask one or more units" + "link:Link one or more units files into the search path" + "is-enabled:Check whether unit files are enabled" + "list-jobs:List jobs" + "cancel:Cancel all, one, or more jobs" + "dump:Dump server status" + "snapshot:Create a snapshot" + "delete:Remove one or more snapshots" + "show-environment:Dump environment" + "set-environment:Set one or more environment variables" + "unset-environment:Unset one or more environment variables" + "daemon-reload:Reload systemd manager configuration" + "daemon-reexec:Reexecute systemd manager" + "default:Enter system default mode" + "rescue:Enter system rescue mode" + "emergency:Enter system emergency mode" + "halt:Shut down and halt the system" + "suspend:Suspend the system" + "poweroff:Shut down and power-off the system" + "reboot:Shut down and reboot the system" + "kexec:Shut down and reboot the system with kexec" + "exit:Ask for user instance termination" + ) + + if (( CURRENT == 1 )); then + _describe -t commands 'systemctl command' _systemctl_cmds || compadd "$@" + else + local curcontext="$curcontext" + + cmd="${${_systemctl_cmds[(r)$words[1]:*]%%:*}}" + # Deal with any aliases + case $cmd in + condrestart) cmd="try-restart";; + force-reload) cmd="reload-or-try-restart";; + esac + + if (( $#cmd )); then + curcontext="${curcontext%:*:*}:systemctl-${cmd}:" + + local update_policy + zstyle -s ":completion:${curcontext}:" cache-policy update_policy + if [[ -z "$update_policy" ]]; then + zstyle ":completion:${curcontext}:" cache-policy _systemctl_caching_policy + fi + + _call_function ret _systemctl_$cmd || _message 'no more arguments' + else + _message "unknown systemctl command: $words[1]" + fi + return ret + fi +} + +__systemctl() +{ + local -a _modes + _modes=("--user" "--system") + systemctl ${words:*_modes} --full --no-legend --no-pager "$@" +} + + +# Fills the unit list +_systemctl_all_units() +{ + if ( [[ ${+_sys_all_units} -eq 0 ]] || _cache_invalid SYS_ALL_UNITS ) && + ! _retrieve_cache SYS_ALL_UNITS; + then + _sys_all_units=( $(__systemctl list-units --all | { while read a b; do echo " $a"; done; }) ) + _store_cache SYS_ALL_UNITS _sys_all_units + fi +} + +# Fills the unit list including all file units +_systemctl_really_all_units() +{ + local -a all_unit_files; + local -a really_all_units; + if ( [[ ${+_sys_really_all_units} -eq 0 ]] || _cache_invalid SYS_REALLY_ALL_UNITS ) && + ! _retrieve_cache SYS_REALLY_ALL_UNITS; + then + all_unit_files=( $(__systemctl list-unit-files | { while read a b; do echo " $a"; done; }) ) + _systemctl_all_units + really_all_units=($_sys_all_units $all_unit_files) + _sys_really_all_units=(${(u)really_all_units}) + _store_cache SYS_REALLY_ALL_UNITS _sys_really_all_units + fi +} + +_filter_units_by_property() { + local property=$1 value=$2 ; shift ; shift + local -a units ; units=($*) + local prop unit + for ((i=1; $i <= ${#units[*]}; i++)); do + # FIXME: "Failed to issue method call: Unknown unit" errors are ignored for + # now (related to DBUS_ERROR_UNKNOWN_OBJECT). in the future, we need to + # revert to calling 'systemctl show' once for all units, which is way + # faster + unit=${units[i]} + prop=${(f)"$(_call_program units "$service show --no-pager --property="$property" ${unit} 2>/dev/null")"} + if [[ "${prop}" = "$property=$value" ]]; then + echo " ${unit}" + fi + done +} + +_systemctl_active_units() {_sys_active_units=( $(__systemctl list-units | { while read a b; do echo " $a"; done; }) )} +_systemctl_inactive_units(){_sys_inactive_units=($(__systemctl list-units --all | { while read a b c d; do [[ $c == "inactive" || $c == "failed" ]] && echo " $a"; done; }) )} +_systemctl_failed_units() {_sys_failed_units=( $(__systemctl list-units --failed | { while read a b; do echo " $a"; done; }) )} +_systemctl_enabled_units() {_sys_enabled_units=( $(__systemctl list-unit-files | { while read a b; do [[ $b == "enabled" ]] && echo " $a"; done; }) )} +_systemctl_disabled_units(){_sys_disabled_units=($(__systemctl list-unit-files | { while read a b; do [[ $b == "disabled" ]] && echo " $a"; done; }) )} +_systemctl_masked_units() {_sys_masked_units=( $(__systemctl list-unit-files | { while read a b; do [[ $b == "masked" ]] && echo " $a"; done; }) )} + +# Completion functions for ALL_UNITS +for fun in is-active is-failed is-enabled status show mask preset help list-dependencies ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + _systemctl_really_all_units + compadd "$@" -a - _sys_really_all_units + } +done + +# Completion functions for ENABLED_UNITS +for fun in disable reenable ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + _systemctl_enabled_units + _systemctl_disabled_units + compadd "$@" -a - _sys_enabled_units _sys_disabled_units + } +done + +# Completion functions for DISABLED_UNITS +(( $+functions[_systemctl_enable] )) || _systemctl_enable() +{ + _systemctl_disabled_units + compadd "$@" -a - _sys_disabled_units +} + +# Completion functions for FAILED_UNITS +(( $+functions[_systemctl_reset-failed] )) || _systemctl_reset-failed() +{ + _systemctl_failed_units + compadd "$@" -a - _sys_failed_units || _message "no failed unit found" +} + +# Completion functions for STARTABLE_UNITS +(( $+functions[_systemctl_start] )) || _systemctl_start() +{ + _systemctl_inactive_units + compadd "$@" -a - _sys_inactive_units +} + +# Completion functions for STOPPABLE_UNITS +for fun in stop kill try-restart condrestart ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + _systemctl_active_units + compadd "$@" - $( _filter_units_by_property CanStop yes \ + ${_sys_active_units[*]} ) + } +done + +# Completion functions for ISOLATABLE_UNITS +(( $+functions[_systemctl_isolate] )) || _systemctl_isolate() +{ + _systemctl_all_units + compadd "$@" - $( _filter_units_by_property AllowIsolate yes \ + ${_sys_all_units[*]} ) +} + +# Completion functions for RELOADABLE_UNITS +for fun in reload reload-or-try-restart force-reload ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + _systemctl_active_units + compadd "$@" - $( _filter_units_by_property CanReload yes \ + ${_sys_active_units[*]} ) + } +done + +# Completion functions for RESTARTABLE_UNITS +for fun in restart reload-or-restart ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + _systemctl_all_units + compadd "$@" - $( _filter_units_by_property CanStart yes \ + ${_sys_all_units[*]} | while read line; do \ + [[ "$line" =~ \.device$ ]] || echo " $line"; \ + done ) + } +done + +# Completion functions for MASKED_UNITS +(( $+functions[_systemctl_unmask] )) || _systemctl_unmask() +{ + _systemctl_masked_units + compadd "$@" -a - _sys_masked_units || _message "no masked unit found" +} + +# Completion functions for JOBS +(( $+functions[_systemctl_cancel] )) || _systemctl_cancel() +{ + compadd "$@" - $(__systemctl list-jobs \ + | cut -d' ' -f1 2>/dev/null ) || _message "no job found" +} + +# Completion functions for SNAPSHOTS +(( $+functions[_systemctl_delete] )) || _systemctl_delete() +{ + compadd "$@" - $(__systemctl list-units --type snapshot --all \ + | cut -d' ' -f1 2>/dev/null ) || _message "no snapshot found" +} + +# Completion functions for ENVS +for fun in set-environment unset-environment ; do + (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() + { + local fun=$0 ; fun=${fun##_systemctl_} + local suf + if [[ "${fun}" = "set-environment" ]]; then + suf='-S=' + fi + + compadd "$@" ${suf} - $(systemctl show-environment \ + | while read line; do echo " ${line%%\=}";done ) + } +done + +(( $+functions[_systemctl_link] )) || _systemctl_link() { _files } + +# no systemctl completion for: +# [STANDALONE]='daemon-reexec daemon-reload default dump +# emergency exit halt kexec list-jobs list-units +# list-unit-files poweroff reboot rescue show-environment' +# [NAME]='snapshot load' + +_systemctl_caching_policy() +{ + local _sysunits + local -a oldcache + + # rebuild if cache is more than a day old + oldcache=( "$1"(mh+1) ) + (( $#oldcache )) && return 0 + + _sysunits=($(__systemctl --all | cut -d' ' -f1)) + + if (( $#_sysunits )); then + for unit in $_sysunits; do + [[ "$unit" -nt "$1" ]] && return 0 + done + fi + + return 1 +} + +_list_fields() { + local -a journal_fields + journal_fields=(MESSAGE{,_ID} PRIORITY CODE_{FILE,LINE,FUNC} + ERRNO SYSLOG_{FACILITY,IDENTIFIER,PID} + _{P,U,G}ID _COMM _EXE _CMDLINE + _AUDIT_{SESSION,LOGINUID} + _SYSTEMD_{CGROUP,SESSION,UNIT,OWNER_UID} + _SYSTEMD_USER_UNIT + _SELINUX_CONTEXT _SOURCE_REALTIME_TIMESTAMP + _{BOOT,MACHINE}_ID _HOSTNAME _TRANSPORT + _KERNEL_{DEVICE,SUBSYSTEM} + _UDEV_{SYSNAME,DEVNODE,DEVLINK} + __CURSOR __{REALTIME,MONOTONIC}_TIMESTAMP) + _describe 'possible fields' journal_fields +} + +_journal_none() { + local -a _commands _files + _commands=( ${(f)"$(_call_program commands "$service" -F _EXE 2>/dev/null)"} ) + _alternative : \ + 'files:/dev files:_files -W /dev -P /dev/' \ + "commands:commands:($_commands[@])" \ + 'fields:fields:_list_fields' +} + +_journal_fields() { + local -a _fields cmd + cmd=("journalctl" "-F ${@[-1]}" "2>/dev/null" ) + _fields=( ${(f)"$(_call_program fields $cmd[@])"} ) + typeset -U _fields + _describe 'possible values' _fields +} + + +_loginctl_all_sessions(){_sys_all_sessions=($(loginctl list-sessions | { while read a b; do echo " $a"; done; }) )} +_loginctl_all_users() {_sys_all_users=( $(loginctl list-users | { while read a b; do echo " $a"; done; }) )} +_loginctl_all_seats() {_sys_all_seats=( $(loginctl list-seats | { while read a b; do echo " $a"; done; }) )} + +# Completion functions for SESSIONS +for fun in session-status show-session activate lock-session unlock-session terminate-session kill-session ; do + (( $+functions[_loginctl_$fun] )) || _loginctl_$fun() + { + _loginctl_all_sessions + compadd "$@" -a - _sys_all_sessions + } +done + +# Completion functions for USERS +for fun in user-status show-user enable-linger disable-linger terminate-user kill-user ; do + (( $+functions[_loginctl_$fun] )) || _loginctl_$fun() + { + _loginctl_all_users + compadd "$@" -a - _sys_all_users + } +done + +# Completion functions for SEATS +(( $+functions[_loginctl_seats] )) || _loginctl_seats() +{ + _loginctl_all_seats + compadd "$@" -a - _sys_all_seats +} +for fun in seat-status show-seat terminate-seat ; do + (( $+functions[_loginctl_$fun] )) || _loginctl_$fun() + { _loginctl_seats } +done + +# Completion functions for ATTACH +(( $+functions[_loginctl_attach] )) || _loginctl_attach() +{ + _loginctl_all_seats + + _arguments -w -C -S -s \ + ':seat:_loginctl_seats' \ + '*:device:_files' +} + +# no loginctl completion for: +# [STANDALONE]='list-sessions list-users list-seats flush-devices' + +(( $+functions[_loginctl_command] )) || _loginctl_command() +{ + local -a _loginctl_cmds + _loginctl_cmds=( + "list-sessions:List sessions" + "session-status:Show session status" + "show-session:Show properties of one or more sessions" + "activate:Activate a session" + "lock-session:Screen lock one or more sessions" + "unlock-session:Screen unlock one or more sessions" + "terminate-session:Terminate one or more sessions" + "kill-session:Send signal to processes of a session" + "list-users:List users" + "user-status:Show user status" + "show-user:Show properties of one or more users" + "enable-linger:Enable linger state of one or more users" + "disable-linger:Disable linger state of one or more users" + "terminate-user:Terminate all sessions of one or more users" + "kill-user:Send signal to processes of a user" + "list-seats:List seats" + "seat-status:Show seat status" + "show-seat:Show properties of one or more seats" + "attach:Attach one or more devices to a seat" + "flush-devices:Flush all device associations" + "terminate-seat:Terminate all sessions on one or more seats" + ) + + if (( CURRENT == 1 )); then + _describe -t commands 'loginctl command' _loginctl_cmds || compadd "$@" + else + local curcontext="$curcontext" + + cmd="${${_loginctl_cmds[(r)$words[1]:*]%%:*}}" + + if (( $#cmd )); then + curcontext="${curcontext%:*:*}:loginctl-${cmd}:" + + _call_function ret _loginctl_$cmd || _message 'no more arguments' + else + _message "unknown loginctl command: $words[1]" + fi + return ret + fi +} + +_hostnamectl_command() { + local -a _hostnamectl_cmds + _hostnamectl_cmds=( + "status:Show current hostname settings" + "set-hostname:Set system hostname" + "set-icon-name:Set icon name for host" + ) + if (( CURRENT == 1 )); then + _describe -t commands 'hostnamectl commands' _hostnamectl_cmds || compadd "$@" + else + local curcontext="$curcontext" + cmd="${${_hostnamectl_cmds[(r)$words[1]:*]%%:*}}" + if (( $#cmd )); then + [[ $cmd == status ]] && msg="no options" || msg="options for $cmd" + _message "$msg" + else + _message "unknown hostnamectl command: $words[1]" + fi + fi +} + +_localectl_set-locale() { + local -a _confs _locales + local expl suf + _locales=( ${(f)"$(_call_program locales "$service" list-locales)"} ) + _confs=( ${${(f)"$(_call_program confs "locale 2>/dev/null")"}%\=*} ) + if [[ -prefix 1 *\= ]]; then + local conf=${PREFIX%%\=*} + compset -P1 '*=' + _wanted locales expl "locales configs" \ + _combination localeconfs confs=$conf locales "$@" - + else + compadd -S '=' $_confs + fi +} + +_localectl_set-keymap() { + local -a _keymaps + _keymaps=( ${(f)"$(_call_program locales "$service" list-keymaps)"} ) + if (( CURRENT <= 3 )); then + _describe keymaps _keymaps + else + _message "no more options" + fi +} + +_localectl_set-x11-keymap() { + if (( $+commands[pkg-config] )); then + local -a _file _layout _model _variant _options + local _xorg_lst + _xorg_lst=${"$($commands[pkg-config] xkeyboard-config --variable=xkb_base)"} + _file=( ${(ps:\n\!:)"$(<$_xorg_lst/rules/xorg.lst)"} ) + _layout=( ${${${(M)${(f)_file[1]}:# *}# }%% *} ) + _model=( ${${${(M)${(f)_file[2]}:# *}# }%% *} ) + _variant=( ${${${(M)${(f)_file[3]}:# *}# }%% *} ) + _options=( ${${${(M)${(f)_file[4]}:# *}# }%% *} ) + #_layout=( ${(f)"$( echo $_file[1] | awk '/^ / {print $1}' )"} ) + #_model=( ${(f)"$(echo $_file[2] | awk '/^ / {print $1}')"} ) + #_variant=( ${(f)"$(echo $_file[3] | awk '/^ / {print $1}')"} ) + #_options=( ${(f)"$(echo ${_file[4]//:/\\:} | awk '/^ / {print $1}')"} ) + + case $CURRENT in + 2) _describe layouts _layout ;; + 3) _describe models _model;; + 4) _describe variants _variant;; + 5) _describe options _options;; + *) _message "no more options" + esac + fi +} + + +_localectl_command() { + local -a _localectl_cmds + _localectl_cmds=( + 'status:Show current locale settings' + 'set-locale:Set system locale' + 'list-locales:Show known locales' + 'set-keymap:Set virtual console keyboard mapping' + 'list-keymaps:Show known virtual console keyboard mappings' + 'set-x11-keymap:Set X11 keyboard mapping' + ) + if (( CURRENT == 1 )); then + _describe -t commands 'localectl command' _localectl_cmds + else + local curcontext="$curcontext" + cmd="${${_localectl_cmds[(r)$words[1]:*]%%:*}}" + if (( $+functions[_localectl_$cmd] )); then + _localectl_$cmd + else + _message "no more options" + fi + fi +} + +_timedatectl_set-timezone(){ + local -a _timezones + _timezones=( ${(f)"$(_call_program timezones "${service}" list-timezones)"} ) + compadd "$_timezones[@]" +} + +_timedatectl_set-time(){ + _message "YYYY-MM-DD HH:MM:SS" +} + +_timedatectl_set-local-rtc(){ + local -a _options + _options=( + '0:Maintain RTC in universal time' + '1:Maintain RTC in local time' + ) + _describe options _options +} + +_timedatectl_set-ntp(){ + local -a _options + _options=( + '0:Disable NTP based network time configuration' + '1:Enable NTP based network time configuration' + ) + _describe options _options +} + +_timedatectl_command(){ + local -a _timedatectl_cmds + _timedatectl_cmds=( + 'status:Show current time settings' + 'set-time:Set system time' + 'set-timezone:Set system timezone' + 'list-timezones:Show known timezones' + 'set-local-rtc:Control whether RTC is in local time' + 'set-ntp:Control whether NTP is enabled' + ) + if (( CURRENT == 1 )); then + _describe -t commands 'timedatectl command' _timedatectl_cmds + else + local curcontext="$curcontext" + cmd="${${_timedatectl_cmds[(r)$words[1]:*]%%:*}}" + if (( $#cmd )); then + if (( $+functions[_timedatectl_$cmd] )); then + _timedatectl_$cmd + else + _message "no more options" + fi + else + _message "unknown timedatectl command: $words[1]" + fi + fi +} +_systemd-coredumpctl_command(){ + local -a _systemd_coredumpctl_cmds + _systemd_coredumpctl_cmds=( + 'list:List available coredumps' + 'dump:Print coredump to std' + ) + if (( CURRENT == 1 )); then + _describe -t commands 'systemd-coredumpctl command' _systemd_coredumpctl_cmds + else + local curcontext="$curcontext" + local -a _dumps + cmd="${${_systemd_coredumpctl_cmds[(r)$words[1]:*]%%:*}}" + if (( $#cmd )); then + # user can set zstyle ':completion:*:*:systemd-coredumpctl:*' sort no for coredumps to be ordered by date, otherwise they get ordered by pid + _dumps=( "${(foa)$(systemd-coredumpctl list | awk 'BEGIN{OFS=":"} /^\s/ {sub(/[[ \t]+/, ""); print $5,$0}' 2>/dev/null)}" ) + if [[ -n "$_dumps" ]]; then + _describe -t pids 'coredumps' _dumps + else + _message "no coredumps" + fi + else + _message "no more options" + fi + + fi + +} + +(( $+functions[_machinectl_command] )) || _machinectl_command() +{ + local -a _machinectl_cmds + _machinectl_cmds=( + "list:List currently running VMs/containers" + "status:Show VM/container status" + "show:Show properties of one or more VMs/containers" + "terminate:Terminate one or more VMs/containers" + "kill:Send signal to process or a VM/container" + ) + if (( CURRENT == 1 )); then + _describe -t commands 'machinectl command' _machinectl_cmds || compadd "$@" + else + local curcontext="$curcontext" + cmd="${${_machinectl_cmds[(r)$words[1]:*]%%:*}}" + if (( $#cmd )); then + case $cmd in + list) msg="no options" ;; + *) + _machines=( "${(foa)$(machinectl list | awk '{print $1}')}" ) + if [[ -n "$_machines" ]]; then + _describe 'machines' _machines + else + _message 'no machines' + fi + esac + else + _message "no more options" + fi + fi +} + +_udevadm_info(){ + _arguments \ + '--query=[Query the database for specified type of device data. It needs the --path or --name to identify the specified device.]:type:(name symlink path property all)' \ + '--path=[The devpath of the device to query.]:sys files:_files -P /sys/ -W /sys' \ + '--name=[The name of the device node or a symlink to query]:device files:_files -P /dev/ -W /dev' \ + '--root[Print absolute paths in name or symlink query.]' \ + '--attribute-walk[Print all sysfs properties of the specified device that can be used in udev rules to match the specified device]' \ + '--export[Print output as key/value pairs.]' \ + '--export-prefix=[Add a prefix to the key name of exported values.]:prefix' \ + '--device-id-of-file=[Print major/minor numbers of the underlying device, where the file lives on.]:files:_udevadm_mounts' \ + '--export-db[Export the content of the udev database.]' \ + '--cleanup-db[Cleanup the udev database.]' +} + +_udevadm_trigger(){ + _arguments \ + '--verbose[Print the list of devices which will be triggered.]' \ + '--dry-run[Do not actually trigger the event.]' \ + '--type=[Trigger a specific type of devices.]:types:(devices subsystems failed)' \ + '--action=[Type of event to be triggered.]:actions:(add change remove)' \ + '--subsystem-match=[Trigger events for devices which belong to a matching subsystem.]' \ + '--subsystem-nomatch=[Do not trigger events for devices which belong to a matching subsystem.]' \ + '--attr-match=attribute=[Trigger events for devices with a matching sysfs attribute.]' \ + '--attr-nomatch=attribute=[Do not trigger events for devices with a matching sysfs attribute.]' \ + '--property-match=[Trigger events for devices with a matching property value.]' \ + '--tag-match=property[Trigger events for devices with a matching tag.]' \ + '--sysname-match=[Trigger events for devices with a matching sys device name.]' \ + '--parent-match=[Trigger events for all children of a given device.]' +} + +_udevadm_settle(){ + _arguments \ + '--timeout=[Maximum number of seconds to wait for the event queue to become empty.]' \ + '--seq-start=[Wait only for events after the given sequence number.]' \ + '--seq-end=[Wait only for events before the given sequence number.]' \ + '--exit-if-exists=[Stop waiting if file exists.]:files:_files' \ + '--quiet[Do not print any output, like the remaining queue entries when reaching the timeout.]' \ + '--help[Print help text.]' +} + +_udevadm_control(){ + _arguments \ + '--exit[Signal and wait for systemd-udevd to exit.]' \ + '--log-priority=[Set the internal log level of systemd-udevd.]:priorities:(err info debug)' \ + '--stop-exec-queue[Signal systemd-udevd to stop executing new events. Incoming events will be queued.]' \ + '--start-exec-queue[Signal systemd-udevd to enable the execution of events.]' \ + '--reload[Signal systemd-udevd to reload the rules files and other databases like the kernel module index.]' \ + '--property=[Set a global property for all events.]' \ + '--children-max=[Set the maximum number of events.]' \ + '--timeout=[The maximum number of seconds to wait for a reply from systemd-udevd.]' \ + '--help[Print help text.]' +} + +_udevadm_monitor(){ + _arguments \ + '--kernel[Print the kernel uevents.]' \ + '--udev[Print the udev event after the rule processing.]' \ + '--property[Also print the properties of the event.]' \ + '--subsystem-match=[Filter events by subsystem/\[devtype\].]' \ + '--tag-match=[Filter events by property.]' \ + '--help[Print help text.]' +} + +_udevadm_test(){ + _arguments \ + '--action=[The action string.]:actions:(add change remove)' \ + '--subsystem=[The subsystem string.]' \ + '--help[Print help text.]' \ + '*::devpath:_files -P /sys/ -W /sys' +} + +_udevadm_test-builtin(){ + if (( CURRENT == 2 )); then + _arguments \ + '--help[Print help text]' \ + '*::builtins:(blkid btrfs hwdb input_id kmod path_id usb_id uaccess)' + elif (( CURRENT == 3 )); then + _arguments \ + '--help[Print help text]' \ + '*::syspath:_files -P /sys -W /sys' + else + _arguments \ + '--help[Print help text]' + fi +} + +_udevadm_mounts(){ + local dev_tmp dpath_tmp mp_tmp mline + + tmp=( "${(@f)$(< /etc/mtab)}" ) + dev_tmp=( "${(@)${(@)tmp%% *}:#none}" ) + mp_tmp=( "${(@)${(@)tmp#* }%% *}" ) + + local MATCH + mp_tmp=("${(@q)mp_tmp//(#m)\\[0-7](#c3)/${(#)$(( 8#${MATCH[2,-1]} ))}}") + dpath_tmp=( "${(@Mq)dev_tmp:#/*}" ) + dev_tmp=( "${(@q)dev_tmp:#/*}" ) + + _alternative \ + 'device-paths: device path:compadd -a dpath_tmp' \ + 'directories:mount point:compadd -a mp_tmp' +} + + +_udevadm_command(){ + local -a _udevadm_cmds + _udevadm_cmds=( + 'info:query sysfs or the udev database' + 'trigger:request events from the kernel' + 'settle:wait for the event queue to finish' + 'control:control the udev daemon' + 'monitor:listen to kernel and udev events' + 'test:test an event run' + 'test-builtin:test a built-in command' + ) + + if ((CURRENT == 1)); then + _describe -t commands 'udevadm commands' _udevadm_cmds + else + local curcontext="$curcontext" + cmd="${${_udevadm_cmds[(r)$words[1]:*]%%:*}}" + if (($#cmd)); then + if (( $+functions[_udevadm_$cmd] )); then + _udevadm_$cmd + else + _message "no options for $cmd" + fi + else + _message "no more options" + fi + fi +} + +_ctls "$@" + +#vim: set ft=zsh sw=4 ts=4 et diff --git a/SOURCES/zlogin.rhs b/SOURCES/zlogin.rhs new file mode 100644 index 0000000..5b7de4a --- /dev/null +++ b/SOURCES/zlogin.rhs @@ -0,0 +1,8 @@ +# +# /etc/zlogin and .zlogin are sourced in login shells. It should +# contain commands that should be executed only in +# login shells. It should be used to set the terminal +# type and run a series of external commands (fortune, +# msgs, from, etc). +# + diff --git a/SOURCES/zlogout.rhs b/SOURCES/zlogout.rhs new file mode 100644 index 0000000..3e78094 --- /dev/null +++ b/SOURCES/zlogout.rhs @@ -0,0 +1,7 @@ +# +# +# /etc/zlogout and ~/.zlogout are run when an interactive session ends +# +# + +clear diff --git a/SOURCES/zprofile.rhs b/SOURCES/zprofile.rhs new file mode 100644 index 0000000..03d316f --- /dev/null +++ b/SOURCES/zprofile.rhs @@ -0,0 +1,22 @@ +# +# /etc/zprofile and ~/.zprofile are run for login shells +# + +PATH="$PATH:$HOME/bin" +export PATH + +_src_etc_profile() +{ + # Make /etc/profile happier, and have possible ~/.zshenv options like + # NOMATCH ignored. + # + emulate -L ksh + + # source profile + if [ -f /etc/profile ]; then + source /etc/profile + fi +} +_src_etc_profile + +unset -f _src_etc_profile diff --git a/SOURCES/zsh-4.3.6-8bit-prompts.patch b/SOURCES/zsh-4.3.6-8bit-prompts.patch new file mode 100644 index 0000000..d759ddd --- /dev/null +++ b/SOURCES/zsh-4.3.6-8bit-prompts.patch @@ -0,0 +1,125 @@ +diff -ru zsh-4.3.9-orig/Functions/Prompts/prompt_bigfade_setup zsh-4.3.9/Functions/Prompts/prompt_bigfade_setup +--- zsh-4.3.9-orig/Functions/Prompts/prompt_bigfade_setup 2008-07-14 10:04:18.000000000 -0400 ++++ zsh-4.3.9/Functions/Prompts/prompt_bigfade_setup 2008-12-18 20:32:59.000000000 -0500 +@@ -7,7 +7,7 @@ + cat < [ [ []]]] ++ prompt bigfade [8bit] [ [ [ []]]] + + where the parameters are the colors for the fade-bar, user@host text, + date text, and current working directory respectively. The default +@@ -27,9 +27,12 @@ + local date=${3:-'white'} + local cwd=${4:-'yellow'} + ++ if [[ $1 == '8bit' ]]; then ++ shift + local -A schars + autoload -Uz prompt_special_chars + prompt_special_chars ++ fi + + PS1="%B%F{$fadebar}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$userhost}%K{$fadebar}%n@%m%b%k%f%F{$fadebar}%K{black}$schars[260]$schars[261]$schars[262]$schars[333]%b%f%k%F{$fadebar}%K{black}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$date}%K{black} %D{%a %b %d} %D{%I:%M:%S%P}$prompt_newline%B%F{$cwd}%K{black}%d>%b%f%k " + PS2="%B%F{$fadebar}$schars[333]$schars[262]$schars[261]$schars[260]%b%F{$fadebar}%K{black}$schars[260]$schars[261]$schars[262]$schars[333]%F{$fadebar}%K{black}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$fadebar}>%b%f%k " +diff -ru zsh-4.3.9-orig/Functions/Prompts/prompt_elite2_setup zsh-4.3.9/Functions/Prompts/prompt_elite2_setup +--- zsh-4.3.9-orig/Functions/Prompts/prompt_elite2_setup 2008-07-14 10:04:18.000000000 -0400 ++++ zsh-4.3.9/Functions/Prompts/prompt_elite2_setup 2008-12-18 20:33:31.000000000 -0500 +@@ -6,7 +6,7 @@ + cat < []] ++ prompt elite2 [8bit] [ []] + + The default colors are both cyan. This theme works best with a dark + background. +@@ -21,9 +21,12 @@ + local text_col=${1:-'cyan'} + local parens_col=${2:-$text_col} + ++ if [[ $1 == '8bit' ]]; then ++ shift + local -A schars + autoload -Uz prompt_special_chars + prompt_special_chars ++ fi + + local text="%b%F{$text_col}" + local parens="%B%F{$parens_col}" +diff -ru zsh-4.3.9-orig/Functions/Prompts/prompt_elite_setup zsh-4.3.9/Functions/Prompts/prompt_elite_setup +--- zsh-4.3.9-orig/Functions/Prompts/prompt_elite_setup 2008-07-14 10:04:18.000000000 -0400 ++++ zsh-4.3.9/Functions/Prompts/prompt_elite_setup 2008-12-18 20:33:45.000000000 -0500 +@@ -6,7 +6,7 @@ + cat < []] ++ prompt elite [8bit] [ []] + + The default colors are red and blue respectively. This theme is + intended for use with a black background. +@@ -21,9 +21,12 @@ + local text=${1:-'red'} + local punctuation=${2:-'blue'} + ++ if [[ $1 == '8bit' ]]; then ++ shift + local -A schars + autoload -Uz prompt_special_chars + prompt_special_chars ++ fi + + PS1="%F{$text}$schars[332]$schars[304]%F{$punctuation}(%F{$text}%n%F{$punctuation}@%F{$text}%m%F{$punctuation})%F{$text}-%F{$punctuation}(%F{$text}%D{%I:%M%P}%F{$punctuation}-:-%F{$text}%D{%m}%F{$punctuation}%F{$text}/%D{%d}%F{$punctuation})%F{$text}$schars[304]-%F{$punctuation}$schars[371]%F{$text}-$schars[371]$schars[371]%F{$punctuation}$schars[372]$prompt_newline%F{$text}$schars[300]$schars[304]%F{$punctuation}(%F{$text}%1~%F{$punctuation})%F{$text}$schars[304]$schars[371]%F{$punctuation}$schars[372]%f" + PS2="> " +diff -ru zsh-4.3.9-orig/Functions/Prompts/prompt_fade_setup zsh-4.3.9/Functions/Prompts/prompt_fade_setup +--- zsh-4.3.9-orig/Functions/Prompts/prompt_fade_setup 2008-07-14 10:04:18.000000000 -0400 ++++ zsh-4.3.9/Functions/Prompts/prompt_fade_setup 2008-12-18 20:33:55.000000000 -0500 +@@ -7,7 +7,7 @@ + cat < [ []]] ++ prompt fade [8bit] [ [ []]] + + where the parameters are the colors for the fade-bar and current + working directory, user@host text, and date text respectively. The +@@ -27,9 +27,12 @@ + local userhost=${2:-'white'} + local date=${3:-'white'} + ++ if [[ $1 == '8bit' ]]; then ++ shift + local -A schars + autoload -Uz prompt_special_chars + prompt_special_chars ++ fi + + PS1="%F{$fadebar_cwd}%B%K{$fadebar_cwd}$schars[333]$schars[262]$schars[261]$schars[260]%F{$userhost}%K{$fadebar_cwd}%B%n@%m%b%F{$fadebar_cwd}%K{black}$schars[333]$schars[262]$schars[261]$schars[260]%F{$date}%K{black}%B %D{%a %b %d} %D{%I:%M:%S%P} $prompt_newline%F{$fadebar_cwd}%K{black}%B%~/%b%k%f " + PS2="%F{$fadebar_cwd}%K{black}$schars[333]$schars[262]$schars[261]$schars[260]%f%k>" +diff -ru zsh-4.3.9-orig/Functions/Prompts/prompt_fire_setup zsh-4.3.9/Functions/Prompts/prompt_fire_setup +--- zsh-4.3.9-orig/Functions/Prompts/prompt_fire_setup 2008-07-14 10:04:18.000000000 -0400 ++++ zsh-4.3.9/Functions/Prompts/prompt_fire_setup 2008-12-18 20:34:04.000000000 -0500 +@@ -8,7 +8,7 @@ + cat < [ [ [ [ []]]]]] ++ prompt fire [8bit] [ [ [ [ [ []]]]]] + + where the parameters are the three fire colors, and the colors for the + user@host text, date text, and current working directory respectively. +@@ -29,9 +29,12 @@ + local date=${5:-'white'} + local cwd=${6:-'yellow'} + ++ if [[ $1 == '8bit' ]]; then ++ shift + local -a schars + autoload -Uz prompt_special_chars + prompt_special_chars ++ fi + + local GRAD1="%{$schars[333]$schars[262]$schars[261]$schars[260]%}" + local GRAD2="%{$schars[260]$schars[261]$schars[262]$schars[333]%}" diff --git a/SOURCES/zsh-5.0.2-CVE-2014-10071.patch b/SOURCES/zsh-5.0.2-CVE-2014-10071.patch new file mode 100644 index 0000000..47e4d1e --- /dev/null +++ b/SOURCES/zsh-5.0.2-CVE-2014-10071.patch @@ -0,0 +1,28 @@ +From 1b014b78fa0919a83b0a8082bc78b0fa3dccaf33 Mon Sep 17 00:00:00 2001 +From: Mikael Magnusson +Date: Mon, 6 Oct 2014 20:33:47 +0200 +Subject: [PATCH] 33365: avoid buffer overflow for very long fds in >& fd + syntax + +Upstream-commit: 49a3086bb67575435251c70ee598e2fd406ef055 +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Src/exec.c b/Src/exec.c +index fb9715c..6d47935 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -3134,7 +3134,7 @@ execcmd(Estate state, int input, int output, int how, int last1) + fil = dup(fd); + } + if (fil == -1) { +- char fdstr[4]; ++ char fdstr[DIGBUFSIZE]; + + closemnodes(mfds); + fixfds(save); +-- +2.14.3 + diff --git a/SOURCES/zsh-5.0.2-CVE-2014-10072.patch b/SOURCES/zsh-5.0.2-CVE-2014-10072.patch new file mode 100644 index 0000000..3843fd8 --- /dev/null +++ b/SOURCES/zsh-5.0.2-CVE-2014-10072.patch @@ -0,0 +1,209 @@ +From a787fc5c556cbbc7f3de308d25b7527f9da5a0da Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Sun, 19 Jan 2014 17:41:06 -0800 +Subject: [PATCH 1/3] 32294: prevent buffer overflow when scanning very long + directory paths for symbolic links + +Upstream-commit: 3e06aeabd8a9e8384ebaa8b08996cd1f64737210 +Signed-off-by: Kamil Dudka +--- + Src/utils.c | 31 ++++++++++++++++++------------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +diff --git a/Src/utils.c b/Src/utils.c +index 20fa59d..a197ef8 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -726,32 +726,36 @@ xsymlinks(char *s) + char **pp, **opp; + char xbuf2[PATH_MAX*2], xbuf3[PATH_MAX*2]; + int t0, ret = 0; ++ zulong xbuflen = strlen(xbuf); + + opp = pp = slashsplit(s); +- for (; *pp; pp++) { +- if (!strcmp(*pp, ".")) { +- zsfree(*pp); ++ for (; xbuflen < sizeof(xbuf) && *pp; pp++) { ++ if (!strcmp(*pp, ".")) + continue; +- } + if (!strcmp(*pp, "..")) { + char *p; + +- zsfree(*pp); + if (!strcmp(xbuf, "/")) + continue; + if (!*xbuf) + continue; +- p = xbuf + strlen(xbuf); +- while (*--p != '/'); ++ p = xbuf + xbuflen; ++ while (*--p != '/') ++ xbuflen--; + *p = '\0'; + continue; + } + sprintf(xbuf2, "%s/%s", xbuf, *pp); + t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX); + if (t0 == -1) { +- strcat(xbuf, "/"); +- strcat(xbuf, *pp); +- zsfree(*pp); ++ zulong pplen = strlen(*pp) + 1; ++ if ((xbuflen += pplen) < sizeof(xbuf)) { ++ strcat(xbuf, "/"); ++ strcat(xbuf, *pp); ++ } else { ++ *xbuf = 0; ++ break; ++ } + } else { + ret = 1; + metafy(xbuf3, t0, META_NOALLOC); +@@ -760,10 +764,9 @@ xsymlinks(char *s) + xsymlinks(xbuf3 + 1); + } else + xsymlinks(xbuf3); +- zsfree(*pp); + } + } +- free(opp); ++ freearray(opp); + return ret; + } + +@@ -780,8 +783,10 @@ xsymlink(char *s) + return NULL; + *xbuf = '\0'; + xsymlinks(s + 1); +- if (!*xbuf) ++ if (!*xbuf) { ++ zwarn("path expansion failed, using root directory"); + return ztrdup("/"); ++ } + return ztrdup(xbuf); + } + +-- +2.14.3 + + +From a2de3957b1e6f23c593c47df0a850a8272e7c06a Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Fri, 15 Aug 2014 10:19:54 -0700 +Subject: [PATCH 2/3] 33012: add an error return value (-1) to xsymlinks() + +Upstream-commit: 47d91c5fba6bc90d79503b7c69c6146abb8825f5 +Signed-off-by: Kamil Dudka +--- + Src/utils.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/Src/utils.c b/Src/utils.c +index a197ef8..d3e5812 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -717,7 +717,6 @@ slashsplit(char *s) + } + + /* expands symlinks and .. or . expressions */ +-/* if flag = 0, only expand .. and . expressions */ + + /**/ + static int +@@ -754,6 +753,7 @@ xsymlinks(char *s) + strcat(xbuf, *pp); + } else { + *xbuf = 0; ++ ret = -1; + break; + } + } else { +@@ -761,9 +761,11 @@ xsymlinks(char *s) + metafy(xbuf3, t0, META_NOALLOC); + if (*xbuf3 == '/') { + strcpy(xbuf, ""); +- xsymlinks(xbuf3 + 1); ++ if (xsymlinks(xbuf3 + 1) < 0) ++ ret = -1; + } else +- xsymlinks(xbuf3); ++ if (xsymlinks(xbuf3) < 0) ++ ret = -1; + } + } + freearray(opp); +@@ -782,11 +784,10 @@ xsymlink(char *s) + if (*s != '/') + return NULL; + *xbuf = '\0'; +- xsymlinks(s + 1); +- if (!*xbuf) { ++ if (xsymlinks(s + 1) < 0) + zwarn("path expansion failed, using root directory"); ++ if (!*xbuf) + return ztrdup("/"); +- } + return ztrdup(xbuf); + } + +@@ -796,7 +797,7 @@ print_if_link(char *s) + { + if (*s == '/') { + *xbuf = '\0'; +- if (xsymlinks(s + 1)) ++ if (xsymlinks(s + 1) > 0) + printf(" -> "), zputs(*xbuf ? xbuf : "/", stdout); + } + } +-- +2.20.1 + + +From c84057916eb96714c03fb0072ad0929152e48f0a Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Thu, 13 Nov 2014 19:44:01 +0000 +Subject: [PATCH 3/3] Marc Finet: problems with working directory + rationalisation. + +Ensure the length of the directory is kept up to date. + +Abort following symlinks as soon as there's an error. + +Upstream-commit: c01a178ece6740f719fef81ecdf9283b5c8b71d5 +Signed-off-by: Kamil Dudka +--- + Src/utils.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/Src/utils.c b/Src/utils.c +index d3e5812..e2ffc38 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -728,7 +728,7 @@ xsymlinks(char *s) + zulong xbuflen = strlen(xbuf); + + opp = pp = slashsplit(s); +- for (; xbuflen < sizeof(xbuf) && *pp; pp++) { ++ for (; xbuflen < sizeof(xbuf) && *pp && ret >= 0; pp++) { + if (!strcmp(*pp, ".")) + continue; + if (!strcmp(*pp, "..")) { +@@ -763,9 +763,13 @@ xsymlinks(char *s) + strcpy(xbuf, ""); + if (xsymlinks(xbuf3 + 1) < 0) + ret = -1; ++ else ++ xbuflen = strlen(xbuf); + } else + if (xsymlinks(xbuf3) < 0) + ret = -1; ++ else ++ xbuflen = strlen(xbuf); + } + } + freearray(opp); +-- +2.20.1 + diff --git a/SOURCES/zsh-5.0.2-CVE-2017-18205.patch b/SOURCES/zsh-5.0.2-CVE-2017-18205.patch new file mode 100644 index 0000000..b2c06b8 --- /dev/null +++ b/SOURCES/zsh-5.0.2-CVE-2017-18205.patch @@ -0,0 +1,63 @@ +From 08e287503fb4a8657962917891f2b7b90b713678 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Tue, 13 Jun 2017 15:41:00 +0100 +Subject: [PATCH] 41284: Fix NULL dereference in cd. + +This happened in sh compatiblity mode if HOME was not set +and cd was used with no argument. + +Upstream-commit: eb783754bdb74377f3cea4ceca9c23a02ea1bf58 +Signed-off-by: Kamil Dudka +--- + Src/builtin.c | 11 ++++++++++- + Test/B01cd.ztst | 4 ++++ + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/Src/builtin.c b/Src/builtin.c +index ccfa745..caa4b64 100644 +--- a/Src/builtin.c ++++ b/Src/builtin.c +@@ -842,8 +842,13 @@ cd_get_dest(char *nam, char **argv, int hard, int func) + dir = nextnode(firstnode(dirstack)); + if (dir) + zinsertlinknode(dirstack, dir, getlinknode(dirstack)); +- else if (func != BIN_POPD) ++ else if (func != BIN_POPD) { ++ if (!home) { ++ zwarnnam(nam, "HOME not set"); ++ return NULL; ++ } + zpushnode(dirstack, ztrdup(home)); ++ } + } else if (!argv[1]) { + int dd; + char *end; +@@ -898,6 +903,10 @@ cd_get_dest(char *nam, char **argv, int hard, int func) + if (!dir) { + dir = firstnode(dirstack); + } ++ if (!dir || !getdata(dir)) { ++ DPUTS(1, "Directory not set, not detected early enough"); ++ return NULL; ++ } + if (!(dest = cd_do_chdir(nam, getdata(dir), hard))) { + if (!target) + zsfree(getlinknode(dirstack)); +diff --git a/Test/B01cd.ztst b/Test/B01cd.ztst +index c7920dd..e56fd26 100644 +--- a/Test/B01cd.ztst ++++ b/Test/B01cd.ztst +@@ -125,6 +125,10 @@ F:something is broken. But you already knew that. + 0: + ?(eval):cd:3: not a directory: link_to_nonexistent + ++ (unset HOME; ARGV0=sh $ZTST_testdir/../Src/zsh -c cd) ++1:Implicit cd with unset HOME. ++?zsh:cd:1: HOME not set ++ + %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 +-- +2.14.3 + diff --git a/SOURCES/zsh-5.0.2-CVE-2017-18206.patch b/SOURCES/zsh-5.0.2-CVE-2017-18206.patch new file mode 100644 index 0000000..48abeb7 --- /dev/null +++ b/SOURCES/zsh-5.0.2-CVE-2017-18206.patch @@ -0,0 +1,104 @@ +From e51be32e198f42828b1082f9a40ff525ba892dcb Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Sun, 17 Aug 2014 10:32:02 -0700 +Subject: [PATCH 1/2] Increase size of xbuf2 in xsymlinks to make gcc + FORTIFY_SOURCE=2 happy. + +Upstream-commit: 4ba08eef7e15f7fd0c96353d931b764e25fd251d +Signed-off-by: Kamil Dudka +--- + Src/utils.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Src/utils.c b/Src/utils.c +index a197ef8..13e744e 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -723,7 +723,7 @@ static int + xsymlinks(char *s) + { + char **pp, **opp; +- char xbuf2[PATH_MAX*2], xbuf3[PATH_MAX*2]; ++ char xbuf2[PATH_MAX*3], xbuf3[PATH_MAX*2]; + int t0, ret = 0; + zulong xbuflen = strlen(xbuf); + +-- +2.14.3 + + +From 5059305b758f1fd228837da436b48a1dcadfd7a3 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Tue, 9 May 2017 17:49:18 +0100 +Subject: [PATCH 2/2] 40181: Fix buffer overrun in xsymlinks. + +There was no check for copying to the internal xbuf2 for a +preliminary test. + +Upstream-commit: c7a9cf465dd620ef48d586026944d9bd7a0d5d6d + +The upstream test-case has not been backported because this version +of zsh does not support the :P modifier. + +Signed-off-by: Kamil Dudka + +Also picked a fix for buffer size off-by-one from upstream commit +a62e1640bcafbb82d86ea8d8ce057a83c4683d60 to fix the following defect +newly detected by Coverity Analysis: + +Error: OVERRUN (CWE-119): +zsh-5.0.2/Src/utils.c:732: cond_at_most: Checking "xbuflen < 8192UL" implies that "xbuflen" may be up to 8191 on the true branch. +zsh-5.0.2/Src/utils.c:757: overrun-local: Overrunning array of 8192 bytes at byte offset 8192 by dereferencing pointer "xbuf2 + xbuflen + 1". [Note: The source code implementation of the function has been overridden by a builtin model.] +--- + Src/utils.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/Src/utils.c b/Src/utils.c +index a197ef8..391d020 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -684,7 +684,7 @@ ispwd(char *s) + return 0; + } + +-static char xbuf[PATH_MAX*2]; ++static char xbuf[PATH_MAX*2+1]; + + /**/ + static char ** +@@ -723,9 +723,9 @@ static int + xsymlinks(char *s) + { + char **pp, **opp; +- char xbuf2[PATH_MAX*3], xbuf3[PATH_MAX*2]; ++ char xbuf2[PATH_MAX*3+1], xbuf3[PATH_MAX*2+1]; + int t0, ret = 0; +- zulong xbuflen = strlen(xbuf); ++ zulong xbuflen = strlen(xbuf), pplen; + + opp = pp = slashsplit(s); + for (; xbuflen < sizeof(xbuf) && *pp && ret >= 0; pp++) { +@@ -744,10 +744,18 @@ xsymlinks(char *s) + *p = '\0'; + continue; + } +- sprintf(xbuf2, "%s/%s", xbuf, *pp); ++ /* Includes null byte. */ ++ pplen = strlen(*pp) + 1; ++ if (xbuflen + pplen + 1 > sizeof(xbuf2)) { ++ *xbuf = 0; ++ ret = -1; ++ break; ++ } ++ memcpy(xbuf2, xbuf, xbuflen); ++ xbuf2[xbuflen] = '/'; ++ memcpy(xbuf2 + xbuflen + 1, *pp, pplen); + t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX); + if (t0 == -1) { +- zulong pplen = strlen(*pp) + 1; + if ((xbuflen += pplen) < sizeof(xbuf)) { + strcat(xbuf, "/"); + strcat(xbuf, *pp); +-- +2.14.3 + diff --git a/SOURCES/zsh-5.0.2-CVE-2018-1071.patch b/SOURCES/zsh-5.0.2-CVE-2018-1071.patch new file mode 100644 index 0000000..06c7e4e --- /dev/null +++ b/SOURCES/zsh-5.0.2-CVE-2018-1071.patch @@ -0,0 +1,102 @@ +From c3fec0b136d938704d8b0ba82424eea8d17f86ab Mon Sep 17 00:00:00 2001 +From: Oliver Kiddle +Date: Sat, 24 Mar 2018 15:02:41 +0100 +Subject: [PATCH 1/2] 42518, CVE-2018-1071: check bounds when copying path in + hashcmd() + +Upstream-commit: 679b71ec4d852037fe5f73d35bf557b0f406c8d4 +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 2 +- + Src/utils.c | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/Src/exec.c b/Src/exec.c +index 6d47935..b9ffb35 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -860,7 +860,7 @@ hashcmd(char *arg0, char **pp) + for (; *pp; pp++) + if (**pp == '/') { + s = buf; +- strucpy(&s, *pp); ++ struncpy(&s, *pp, PATH_MAX); + *s++ = '/'; + if ((s - buf) + strlen(arg0) >= PATH_MAX) + continue; +diff --git a/Src/utils.c b/Src/utils.c +index 391d020..c6eba63 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -2010,10 +2010,10 @@ struncpy(char **s, char *t, int n) + { + char *u = *s; + +- while (n--) +- *u++ = *t++; ++ while (n-- && (*u++ = *t++)); + *s = u; +- *u = '\0'; ++ if (n > 0) /* just one null-byte will do, unlike strncpy(3) */ ++ *u = '\0'; + } + + /* Return the number of elements in an array of pointers. * +-- +2.14.3 + + +From 88b8110331ac616a8450fab0b87a65df715ee3a8 Mon Sep 17 00:00:00 2001 +From: Oliver Kiddle +Date: Wed, 28 Mar 2018 09:00:58 +0200 +Subject: [PATCH 2/2] 42539: prevent overflow of PATH_MAX-sized buffer in + spelling correction + +Upstream-commit: c053c6a0799397632df9ba88f8812a1da49c67f1 +Signed-off-by: Kamil Dudka +--- + Src/utils.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/Src/utils.c b/Src/utils.c +index 3989c8c..bac12a9 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -2010,7 +2010,8 @@ struncpy(char **s, char *t, int n) + { + char *u = *s; + +- while (n-- && (*u++ = *t++)); ++ while (n-- && (*u = *t++)) ++ u++; + *s = u; + if (n > 0) /* just one null-byte will do, unlike strncpy(3) */ + *u = '\0'; +@@ -3745,17 +3746,20 @@ spname(char *oldname) + * odd to the human reader, and we may make use of the total * + * distance for all corrections at some point in the future. */ + if (bestdist < maxthresh) { +- strcpy(new, spnameguess); +- strcat(new, old); +- return newname; ++ struncpy(&new, spnameguess, sizeof(newname) - (new - newname)); ++ struncpy(&new, old, sizeof(newname) - (new - newname)); ++ return (new - newname) >= (sizeof(newname)-1) ? NULL : newname; + } else + return NULL; + } else { + maxthresh = bestdist + thresh; + bestdist += thisdist; + } +- for (p = spnamebest; (*new = *p++);) ++ for (p = spnamebest; (*new = *p++);) { ++ if ((new - newname) >= (sizeof(newname)-1)) ++ return NULL; + new++; ++ } + } + } + +-- +2.17.2 + diff --git a/SOURCES/zsh-5.0.2-CVE-2018-1083.patch b/SOURCES/zsh-5.0.2-CVE-2018-1083.patch new file mode 100644 index 0000000..722079a --- /dev/null +++ b/SOURCES/zsh-5.0.2-CVE-2018-1083.patch @@ -0,0 +1,63 @@ +From 20cf100cddc27a1e7202413261c93b78142899e8 Mon Sep 17 00:00:00 2001 +From: Oliver Kiddle +Date: Sat, 24 Mar 2018 15:04:39 +0100 +Subject: [PATCH] 42519, CVE-2018-1083: check bounds on PATH_MAX-sized buffer + used for file completion candidates + +Upstream-commit: 259ac472eac291c8c103c7a0d8a4eaf3c2942ed7 +Signed-off-by: Kamil Dudka + +Also picked a fix for buffer size off-by-one from upstream commit +a62e1640bcafbb82d86ea8d8ce057a83c4683d60 to fix the following defect +newly detected by Coverity Analysis: + +Error: OVERRUN (CWE-119): +zsh-5.0.2/Src/Zle/compctl.c:2160: cond_at_most: Checking "pathpreflen > 4096" implies that "pathpreflen" may be up to 4096 on the false branch. +zsh-5.0.2/Src/Zle/compctl.c:2172: overrun-buffer-arg: Overrunning array "p" of 4096 bytes by passing it to a function which accesses it at byte offset 4096 using argument "pathpreflen + 1" (which evaluates to 4097). [Note: The source code implementation of the function has been overridden by a builtin model.] +--- + Src/Zle/compctl.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c +index 5d67137..5e636ef 100644 +--- a/Src/Zle/compctl.c ++++ b/Src/Zle/compctl.c +@@ -2136,7 +2136,7 @@ gen_matches_files(int dirs, int execs, int all) + { + DIR *d; + struct stat buf; +- char *n, p[PATH_MAX], *q = NULL, *e, *pathpref; ++ char *n, p[PATH_MAX+1], *q = NULL, *e, *pathpref; + LinkList l = NULL; + int ns = 0, ng = opts[NULLGLOB], test, aw = addwhat, pathpreflen; + +@@ -2157,6 +2157,8 @@ gen_matches_files(int dirs, int execs, int all) + if (prpre && *prpre) { + pathpref = dupstring(prpre); + unmetafy(pathpref, &pathpreflen); ++ if (pathpreflen > PATH_MAX) ++ return; + /* system needs NULL termination, not provided by unmetafy */ + pathpref[pathpreflen] = '\0'; + } else { +@@ -2199,6 +2201,8 @@ gen_matches_files(int dirs, int execs, int all) + * the path buffer by appending the filename. */ + ums = dupstring(n); + unmetafy(ums, ¨en); ++ if (umlen + pathpreflen + 1 > PATH_MAX) ++ continue; + memcpy(q, ums, umlen); + q[umlen] = '\0'; + /* And do the stat. */ +@@ -2213,6 +2217,8 @@ gen_matches_files(int dirs, int execs, int all) + /* We have to test for a path suffix. */ + int o = strlen(p), tt; + ++ if (o + strlen(psuf) > PATH_MAX) ++ continue; + /* Append it to the path buffer. */ + strcpy(p + o, psuf); + +-- +2.14.3 + diff --git a/SOURCES/zsh-5.0.2-CVE-2018-1100.patch b/SOURCES/zsh-5.0.2-CVE-2018-1100.patch new file mode 100644 index 0000000..f430c59 --- /dev/null +++ b/SOURCES/zsh-5.0.2-CVE-2018-1100.patch @@ -0,0 +1,41 @@ +From 7f28151c0b6bca5cb60f56e9a17ccb2fd9665269 Mon Sep 17 00:00:00 2001 +From: Oliver Kiddle +Date: Sat, 7 Apr 2018 18:28:38 +0200 +Subject: [PATCH] 42607, CVE-2018-1100: check bounds on buffer in mail checking + +Upstream-commit: 31f72205630687c1cef89347863aab355296a27f +Signed-off-by: Kamil Dudka +--- + Src/utils.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/Src/utils.c b/Src/utils.c +index c6eba63..41ec45c 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -1419,7 +1419,7 @@ checkmailpath(char **s) + LinkList l; + DIR *lock = opendir(unmeta(*s)); + char buf[PATH_MAX * 2], **arr, **ap; +- int ct = 1; ++ int buflen, ct = 1; + + if (lock) { + char *fn; +@@ -1428,9 +1428,11 @@ checkmailpath(char **s) + l = newlinklist(); + while ((fn = zreaddir(lock, 1)) && !errflag) { + if (u) +- sprintf(buf, "%s/%s?%s", *s, fn, u); ++ buflen = snprintf(buf, sizeof(buf), "%s/%s?%s", *s, fn, u); + else +- sprintf(buf, "%s/%s", *s, fn); ++ buflen = snprintf(buf, sizeof(buf), "%s/%s", *s, fn); ++ if (buflen < 0 || buflen >= (int)sizeof(buf)) ++ continue; + addlinknode(l, dupstring(buf)); + ct++; + } +-- +2.14.3 + diff --git a/SOURCES/zsh-5.0.2-CVE-2018-13259.patch b/SOURCES/zsh-5.0.2-CVE-2018-13259.patch new file mode 100644 index 0000000..a06c3ba --- /dev/null +++ b/SOURCES/zsh-5.0.2-CVE-2018-13259.patch @@ -0,0 +1,162 @@ +From 73eade866e0f1685749c0ec50f49fed0cca0c503 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Fri, 25 Dec 2015 00:31:32 -0800 +Subject: [PATCH 1/2] 37435 (+ fix typo): allow execution of empty files as + "sh" scripts + +Upstream-commit: fc344465f27cdf89664a64fb157b7606c9eb837f +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Src/exec.c b/Src/exec.c +index b9ffb35..f20b96c 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -465,9 +465,10 @@ zexecve(char *pth, char **argv, char **newenvp) + if ((fd = open(pth, O_RDONLY|O_NOCTTY)) >= 0) { + argv0 = *argv; + *argv = pth; ++ execvebuf[0] = '\0'; + ct = read(fd, execvebuf, POUNDBANGLIMIT); + close(fd); +- if (ct > 0) { ++ if (ct >= 0) { + if (execvebuf[0] == '#') { + if (execvebuf[1] == '!') { + for (t0 = 0; t0 != ct; t0++) +-- +2.17.2 + + +From ddb6c5b4c0ab9c6a7404112d367f0c7cc400ceec Mon Sep 17 00:00:00 2001 +From: Anthony Sottile +Date: Mon, 3 Sep 2018 14:39:25 +0000 +Subject: [PATCH 2/2] CVE-2018-0502, CVE-2018-13259: Fix two security issues in + shebang line parsing. + +See NEWS for more information. + +Patch by Anthony Sottile and Buck Evan. + +Upstream-commit: 1c4c7b6a4d17294df028322b70c53803a402233d +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 32 ++++++++++++++++++-------------- + Test/A05execution.ztst | 22 ++++++++++++++++++++++ + 2 files changed, 40 insertions(+), 14 deletions(-) + +diff --git a/Src/exec.c b/Src/exec.c +index f20b96c..c95667e 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -427,7 +427,7 @@ execcursh(Estate state, int do_exec) + + /* execve after handling $_ and #! */ + +-#define POUNDBANGLIMIT 64 ++#define POUNDBANGLIMIT 128 + + /**/ + static int +@@ -465,18 +465,20 @@ zexecve(char *pth, char **argv, char **newenvp) + if ((fd = open(pth, O_RDONLY|O_NOCTTY)) >= 0) { + argv0 = *argv; + *argv = pth; +- execvebuf[0] = '\0'; ++ memset(execvebuf, '\0', POUNDBANGLIMIT + 1); + ct = read(fd, execvebuf, POUNDBANGLIMIT); + close(fd); + if (ct >= 0) { +- if (execvebuf[0] == '#') { +- if (execvebuf[1] == '!') { +- for (t0 = 0; t0 != ct; t0++) +- if (execvebuf[t0] == '\n') +- break; ++ if (ct >= 2 && execvebuf[0] == '#' && execvebuf[1] == '!') { ++ for (t0 = 0; t0 != ct; t0++) ++ if (execvebuf[t0] == '\n') ++ break; ++ if (t0 == ct) ++ zerr("%s: bad interpreter: %s: %e", pth, ++ execvebuf + 2, eno); ++ else { + while (inblank(execvebuf[t0])) + execvebuf[t0--] = '\0'; +- execvebuf[POUNDBANGLIMIT] = '\0'; + for (ptr = execvebuf + 2; *ptr && *ptr == ' '; ptr++); + for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++); + if (eno == ENOENT) { +@@ -485,9 +487,14 @@ zexecve(char *pth, char **argv, char **newenvp) + *ptr = '\0'; + if (*ptr2 != '/' && + (pprog = pathprog(ptr2, NULL))) { +- argv[-2] = ptr2; +- argv[-1] = ptr + 1; +- execve(pprog, argv - 2, newenvp); ++ if (ptr == execvebuf + t0 + 1) { ++ argv[-1] = ptr2; ++ execve(pprog, argv - 1, newenvp); ++ } else { ++ argv[-2] = ptr2; ++ argv[-1] = ptr + 1; ++ execve(pprog, argv - 2, newenvp); ++ } + } + zerr("%s: bad interpreter: %s: %e", pth, ptr2, + eno); +@@ -500,9 +507,6 @@ zexecve(char *pth, char **argv, char **newenvp) + argv[-1] = ptr2; + execve(ptr2, argv - 1, newenvp); + } +- } else if (eno == ENOEXEC) { +- argv[-1] = "sh"; +- execve("/bin/sh", argv - 1, newenvp); + } + } else if (eno == ENOEXEC) { + for (t0 = 0; t0 != ct; t0++) +diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst +index 0804691..fb39d05 100644 +--- a/Test/A05execution.ztst ++++ b/Test/A05execution.ztst +@@ -12,7 +12,14 @@ + + print '#!/bin/sh\necho This is dir2' >dir2/tstcmd + ++ print -n '#!sh\necho This is slashless' >tstcmd-slashless ++ print -n '#!echo foo\necho This is arg' >tstcmd-arg ++ print '#!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxnyyy' >tstcmd-interp-too-long ++ print '#!/bin/sh\necho should not execute; exit 1' >xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxn ++ + chmod 755 tstcmd dir1/tstcmd dir2/tstcmd ++ chmod 755 tstcmd-slashless tstcmd-arg tstcmd-interp-too-long ++ chmod 755 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxn + + %test + ./tstcmd +@@ -33,6 +40,21 @@ + 0:path (2) + >This is top + ++ PATH=/bin:${ZTST_testdir}/command.tmp/ tstcmd-slashless ++0:path (3) ++>This is slashless ++ ++ PATH=/bin:${ZTST_testdir}/command.tmp tstcmd-arg ++0:path (4) ++*>foo */command.tmp/tstcmd-arg ++ ++ path=(/bin ${ZTST_testdir}/command.tmp/) ++ tstcmd-interp-too-long 2>&1; echo "status $?" ++ path=($storepath) ++0:path (5) ++*>*tstcmd-interp-too-long: bad interpreter: x*xn: no such file or directory ++>status 127 ++ + functst() { print $# arguments:; print -l $*; } + functst "Eines Morgens" "als Gregor Samsa" + functst "" +-- +2.17.1 + diff --git a/SOURCES/zsh-5.0.2-CVE-2018-7549.patch b/SOURCES/zsh-5.0.2-CVE-2018-7549.patch new file mode 100644 index 0000000..dff731b --- /dev/null +++ b/SOURCES/zsh-5.0.2-CVE-2018-7549.patch @@ -0,0 +1,38 @@ +From 8aa649ab39c6113072f93d8065d846477ab297f1 Mon Sep 17 00:00:00 2001 +From: Stephane Chazelas +Date: Fri, 22 Dec 2017 22:17:09 +0000 +Subject: [PATCH] Avoid crash copying empty hash table. + +Visible with typeset -p. + +Upstream-commit: c2cc8b0fbefc9868fa83537f5b6d90fc1ec438dd +Signed-off-by: Kamil Dudka +--- + Src/params.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/Src/params.c b/Src/params.c +index be8394b..25f34e8 100644 +--- a/Src/params.c ++++ b/Src/params.c +@@ -492,10 +492,13 @@ scancopyparams(HashNode hn, UNUSED(int flags)) + HashTable + copyparamtable(HashTable ht, char *name) + { +- HashTable nht = newparamtable(ht->hsize, name); +- outtable = nht; +- scanhashtable(ht, 0, 0, 0, scancopyparams, 0); +- outtable = NULL; ++ HashTable nht = 0; ++ if (ht) { ++ nht = newparamtable(ht->hsize, name); ++ outtable = nht; ++ scanhashtable(ht, 0, 0, 0, scancopyparams, 0); ++ outtable = NULL; ++ } + return nht; + } + +-- +2.14.3 + diff --git a/SOURCES/zsh-5.0.2-PATH_MAX-extra-byte.patch b/SOURCES/zsh-5.0.2-PATH_MAX-extra-byte.patch new file mode 100644 index 0000000..26fae02 --- /dev/null +++ b/SOURCES/zsh-5.0.2-PATH_MAX-extra-byte.patch @@ -0,0 +1,199 @@ +From d670cfc55d96b65e124b09430d8f43909939fc55 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Thu, 17 Nov 2016 19:49:17 +0000 +Subject: [PATCH] 39958: Add extra byte to PATH_MAX allocations. + +This ensures we've got enough space for a null, although this +isn't always needed. + +Upstream-commit: a62e1640bcafbb82d86ea8d8ce057a83c4683d60 +Signed-off-by: Kamil Dudka +--- + Src/builtin.c | 2 +- + Src/compat.c | 4 ++-- + Src/exec.c | 16 ++++++++-------- + Src/glob.c | 4 ++-- + Src/hist.c | 2 +- + Src/utils.c | 6 +++--- + 6 files changed, 17 insertions(+), 17 deletions(-) + +diff --git a/Src/builtin.c b/Src/builtin.c +index caa4b64..86d7d9a 100644 +--- a/Src/builtin.c ++++ b/Src/builtin.c +@@ -945,7 +945,7 @@ cd_do_chdir(char *cnam, char *dest, int hard) + * Normalize path under Cygwin to avoid messing with + * DOS style names with drives in them + */ +- static char buf[PATH_MAX]; ++ static char buf[PATH_MAX+1]; + #ifndef _SYS_CYGWIN_H + void cygwin_conv_to_posix_path(const char *, char *); + #endif +diff --git a/Src/compat.c b/Src/compat.c +index cc4e876..d81e3d6 100644 +--- a/Src/compat.c ++++ b/Src/compat.c +@@ -270,7 +270,7 @@ zgetdir(struct dirsav *d) + int len; + #endif + +- buf = zhalloc(bufsiz = PATH_MAX); ++ buf = zhalloc(bufsiz = PATH_MAX+1); + pos = bufsiz - 1; + buf[pos] = '\0'; + strcpy(nbuf, "../"); +@@ -439,7 +439,7 @@ zgetcwd(void) + free(cwd); + } + #else +- char *cwdbuf = zalloc(PATH_MAX); ++ char *cwdbuf = zalloc(PATH_MAX+1); + ret = getcwd(cwdbuf, PATH_MAX); + if (ret) + ret = dupstring(ret); +diff --git a/Src/exec.c b/Src/exec.c +index c95667e..03716ba 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -434,7 +434,7 @@ static int + zexecve(char *pth, char **argv, char **newenvp) + { + int eno; +- static char buf[PATH_MAX * 2]; ++ static char buf[PATH_MAX * 2+1]; + char **eep; + + unmetafy(pth, NULL); +@@ -575,7 +575,7 @@ static void + execute(LinkList args, int flags, int defpath) + { + Cmdnam cn; +- char buf[MAXCMDLEN], buf2[MAXCMDLEN]; ++ char buf[MAXCMDLEN+1], buf2[MAXCMDLEN+1]; + char *s, *z, *arg0; + char **argv, **pp, **newenvp = NULL; + int eno = 0, ee; +@@ -656,7 +656,7 @@ execute(LinkList args, int flags, int defpath) + + /* for command -p, search the default path */ + if (defpath) { +- char *s, pbuf[PATH_MAX]; ++ char *s, pbuf[PATH_MAX+1]; + char *dptr, *pe, *ps = DEFAULT_PATH; + + for(;ps;ps = pe ? pe+1 : NULL) { +@@ -693,7 +693,7 @@ execute(LinkList args, int flags, int defpath) + } else { + + if ((cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0))) { +- char nn[PATH_MAX], *dptr; ++ char nn[PATH_MAX+1], *dptr; + + if (cn->node.flags & HASHED) + strcpy(nn, cn->u.cmd); +@@ -778,7 +778,7 @@ findcmd(char *arg0, int docopy) + break; + } + if (cn) { +- char nn[PATH_MAX]; ++ char nn[PATH_MAX+1]; + + if (cn->node.flags & HASHED) + strcpy(nn, cn->u.cmd); +@@ -859,7 +859,7 @@ mod_export Cmdnam + hashcmd(char *arg0, char **pp) + { + Cmdnam cn; +- char *s, buf[PATH_MAX]; ++ char *s, buf[PATH_MAX+1]; + char **pq; + + for (; *pp; pp++) +@@ -4919,7 +4919,7 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) + Eprog + getfpfunc(char *s, int *ksh, char **fname) + { +- char **pp, buf[PATH_MAX]; ++ char **pp, buf[PATH_MAX+1]; + off_t len; + off_t rlen; + char *d; +@@ -5047,7 +5047,7 @@ cancd(char *s) + char *t; + + if (*s != '/') { +- char sbuf[PATH_MAX], **cp; ++ char sbuf[PATH_MAX+1], **cp; + + if (cancd2(s)) + return s; +diff --git a/Src/glob.c b/Src/glob.c +index 9135fce..92ed8b5 100644 +--- a/Src/glob.c ++++ b/Src/glob.c +@@ -271,7 +271,7 @@ addpath(char *s, int l) + static int + statfullpath(const char *s, struct stat *st, int l) + { +- char buf[PATH_MAX]; ++ char buf[PATH_MAX+1]; + + DPUTS(strlen(s) + !*s + pathpos - pathbufcwd >= PATH_MAX, + "BUG: statfullpath(): pathname too long"); +@@ -775,7 +775,7 @@ parsepat(char *str) + + /* Now there is no (#X) in front, we can check the path. */ + if (!pathbuf) +- pathbuf = zalloc(pathbufsz = PATH_MAX); ++ pathbuf = zalloc(pathbufsz = PATH_MAX+1); + DPUTS(pathbufcwd, "BUG: glob changed directory"); + if (*str == '/') { /* pattern has absolute path */ + str++; +diff --git a/Src/hist.c b/Src/hist.c +index 9a63c15..6764eaf 100644 +--- a/Src/hist.c ++++ b/Src/hist.c +@@ -1658,7 +1658,7 @@ chrealpath(char **junkptr) + char *lastpos, *nonreal, *real; + #else + # ifdef HAVE_REALPATH +- char *lastpos, *nonreal, real[PATH_MAX]; ++ char *lastpos, *nonreal, real[PATH_MAX+1]; + # endif + #endif + +diff --git a/Src/utils.c b/Src/utils.c +index 05eeda4..13910a4 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -930,7 +930,7 @@ finddir(char *s) + if(homenode.diff==1) + homenode.diff = 0; + if(!finddir_full) +- finddir_full = zalloc(ffsz = PATH_MAX); ++ finddir_full = zalloc(ffsz = PATH_MAX+1); + finddir_full[0] = 0; + return finddir_last = NULL; + } +@@ -1418,7 +1418,7 @@ checkmailpath(char **s) + } else if (S_ISDIR(st.st_mode)) { + LinkList l; + DIR *lock = opendir(unmeta(*s)); +- char buf[PATH_MAX * 2], **arr, **ap; ++ char buf[PATH_MAX * 2 + 1], **arr, **ap; + int buflen, ct = 1; + + if (lock) { +@@ -5828,7 +5828,7 @@ strsfx(char *s, char *t) + static int + upchdir(int n) + { +- char buf[PATH_MAX]; ++ char buf[PATH_MAX+1]; + char *s; + int err = -1; + +-- +2.20.1 + diff --git a/SOURCES/zsh-5.0.2-close-fd.patch b/SOURCES/zsh-5.0.2-close-fd.patch new file mode 100644 index 0000000..ddd233b --- /dev/null +++ b/SOURCES/zsh-5.0.2-close-fd.patch @@ -0,0 +1,97 @@ +From 4f4fc498361ea9965fde31c36cf9971a92479e9f Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Tue, 20 Jan 2015 09:29:22 +0000 +Subject: [PATCH 1/2] users/19751: remove error on failure to close file + descriptor by number. + +Keep it when closing file descriptor stored in a variable, i.e. +explicitly opened by the user. + +Upstream-commit: e6d964246700581fe22ea834b2ea12dd301e8c3d +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 7 ++++++- + Test/A04redirect.ztst | 10 ++++++---- + 2 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/Src/exec.c b/Src/exec.c +index 1a4ffe2..fcdc645 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -3075,7 +3075,12 @@ execcmd(Estate state, int input, int output, int how, int last1) + } + if (fn->fd1 < 10) + closemn(mfds, fn->fd1); +- if (!closed && zclose(fn->fd1) < 0) { ++ /* ++ * Only report failures to close file descriptors ++ * if they're under user control as we don't know ++ * what the previous status of others was. ++ */ ++ if (!closed && zclose(fn->fd1) < 0 && fn->varid) { + zwarn("failed to close file descriptor %d: %e", + fn->fd1, errno); + } +diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst +index b8086e7..2f21b95 100644 +--- a/Test/A04redirect.ztst ++++ b/Test/A04redirect.ztst +@@ -152,11 +152,13 @@ + >hello + >goodbye + +- ({ exec 3<&- } 2>/dev/null +- exec 3<&- +- read foo <&-) ++ (exec {varid}<&0 ++ exec {varid}<&- ++ print About to close a second time >&2 ++ read {varid}<&-) + 1:'<&-' redirection +-*?\(eval\):*: failed to close file descriptor 3:* ++?About to close a second time ++*?\(eval\):*: failed to close file descriptor * + + print foo >&- + 0:'>&-' redirection +-- +2.4.0 + + +From 73ea1de52de3f078ef4e6f96ae5042cfe5e79730 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Tue, 20 Jan 2015 11:53:42 +0000 +Subject: [PATCH 2/2] users/19756: test for case of closing fd with no error + message + +Upstream-commit: 638bfa93a009987e57bd7eaa8b2a1c1067a3652a +Signed-off-by: Kamil Dudka +--- + Test/A04redirect.ztst | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst +index 2f21b95..70c210d 100644 +--- a/Test/A04redirect.ztst ++++ b/Test/A04redirect.ztst +@@ -152,11 +152,16 @@ + >hello + >goodbye + ++ ({exec 3<&- } 2>/dev/null ++ exec 3<&- ++ read foo <&-) ++1:'<&-' redirection with numeric fd (no error message on failure) ++ + (exec {varid}<&0 + exec {varid}<&- + print About to close a second time >&2 + read {varid}<&-) +-1:'<&-' redirection ++1:'<&-' redirection with fd in variable (error message on failure) + ?About to close a second time + *?\(eval\):*: failed to close file descriptor * + +-- +2.4.0 + diff --git a/SOURCES/zsh-5.0.2-cmd-subst.patch b/SOURCES/zsh-5.0.2-cmd-subst.patch new file mode 100644 index 0000000..3cd7530 --- /dev/null +++ b/SOURCES/zsh-5.0.2-cmd-subst.patch @@ -0,0 +1,1675 @@ +From 6b8f3f9906ee44be46e022480b6e01755feeaa99 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Tue, 6 Jan 2015 17:05:17 +0000 +Subject: [PATCH 1/9] Fix command substitutions to parse contents as they are + read in. + +Do this by refactoring misnamed lexsave()/lexrestore() to allow +continuity of history and input. + +Add test. + +Upstream-commit: c0d01a6fe0c67911650730cf13a2b9a0db16e59b +Signed-off-by: Kamil Dudka +--- + Src/init.c | 3 +- + Src/input.c | 13 +- + Src/lex.c | 498 ++++++++++++++++++++++++++++++++------------------ + Src/parse.c | 29 ++- + Src/zsh.h | 9 + + Test/D08cmdsubst.ztst | 42 +++++ + 6 files changed, 401 insertions(+), 193 deletions(-) + +diff --git a/Src/init.c b/Src/init.c +index 0742a9f..78f171d 100644 +--- a/Src/init.c ++++ b/Src/init.c +@@ -129,7 +129,8 @@ loop(int toplevel, int justonce) + use_exit_printed = 0; + intr(); /* interrupts on */ + lexinit(); /* initialize lexical state */ +- if (!(prog = parse_event())) { /* if we couldn't parse a list */ ++ if (!(prog = parse_event(ENDINPUT))) { ++ /* if we couldn't parse a list */ + hend(NULL); + if ((tok == ENDINPUT && !errflag) || + (tok == LEXERR && (!isset(SHINSTDIN) || !toplevel)) || +diff --git a/Src/input.c b/Src/input.c +index 5cff22d..1579762 100644 +--- a/Src/input.c ++++ b/Src/input.c +@@ -175,12 +175,12 @@ shingetline(void) + /* Get the next character from the input. + * Will call inputline() to get a new line where necessary. + */ +- ++ + /**/ + int + ingetc(void) + { +- int lastc; ++ int lastc = ' '; + + if (lexstop) + return ' '; +@@ -192,7 +192,7 @@ ingetc(void) + continue; + if (((inbufflags & INP_LINENO) || !strin) && lastc == '\n') + lineno++; +- return lastc; ++ break; + } + + /* +@@ -204,7 +204,7 @@ ingetc(void) + */ + if (!inbufct && (strin || errflag)) { + lexstop = 1; +- return ' '; ++ break; + } + /* If the next element down the input stack is a continuation of + * this, use it. +@@ -215,8 +215,10 @@ ingetc(void) + } + /* As a last resort, get some more input */ + if (inputline()) +- return ' '; ++ break; + } ++ zshlex_raw_add(lastc); ++ return lastc; + } + + /* Read a line from the current command stream and store it as input */ +@@ -421,6 +423,7 @@ inungetc(int c) + inbufleft = 0; + inbuf = inbufptr = ""; + } ++ zshlex_raw_back(); + } + } + +diff --git a/Src/lex.c b/Src/lex.c +index 82bf848..bcceda6 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -146,6 +146,16 @@ mod_export int parend; + /**/ + mod_export int nocomments; + ++/* add raw input characters while parsing command substitution */ ++ ++/**/ ++static int lex_add_raw; ++ ++/* variables associated with the above */ ++ ++static char *tokstr_raw, *bptr_raw; ++static int len_raw, bsiz_raw; ++ + /* text of punctuation tokens */ + + /**/ +@@ -214,6 +224,11 @@ struct lexstack { + char *bptr; + int bsiz; + int len; ++ int lex_add_raw; ++ char *tokstr_raw; ++ char *bptr_raw; ++ int bsiz_raw; ++ int len_raw; + short *chwords; + int chwordlen; + int chwordpos; +@@ -239,89 +254,121 @@ struct lexstack { + + static struct lexstack *lstack = NULL; + +-/* save the lexical state */ ++/* save the context or parts thereof */ + + /* is this a hack or what? */ + + /**/ + mod_export void +-lexsave(void) ++lexsave_partial(int parts) + { + struct lexstack *ls; + + ls = (struct lexstack *)malloc(sizeof(struct lexstack)); + +- ls->incmdpos = incmdpos; +- ls->incond = incond; +- ls->incasepat = incasepat; +- ls->dbparens = dbparens; +- ls->isfirstln = isfirstln; +- ls->isfirstch = isfirstch; +- ls->histactive = histactive; +- ls->histdone = histdone; +- ls->lexflags = lexflags; +- ls->stophist = stophist; +- stophist = 0; +- if (!lstack) { +- /* top level, make this version visible to ZLE */ +- zle_chline = chline; +- /* ensure line stored is NULL-terminated */ +- if (hptr) +- *hptr = '\0'; ++ if (parts & ZCONTEXT_LEX) { ++ ls->incmdpos = incmdpos; ++ ls->incond = incond; ++ ls->incasepat = incasepat; ++ ls->dbparens = dbparens; ++ ls->isfirstln = isfirstln; ++ ls->isfirstch = isfirstch; ++ ls->lexflags = lexflags; ++ ++ ls->tok = tok; ++ ls->isnewlin = isnewlin; ++ ls->tokstr = tokstr; ++ ls->zshlextext = zshlextext; ++ ls->bptr = bptr; ++ ls->bsiz = bsiz; ++ ls->len = len; ++ ls->lex_add_raw = lex_add_raw; ++ ls->tokstr_raw = tokstr_raw; ++ ls->bptr_raw = bptr_raw; ++ ls->bsiz_raw = bsiz_raw; ++ ls->len_raw = len_raw; ++ ls->lexstop = lexstop; ++ ls->toklineno = toklineno; ++ ++ tokstr = zshlextext = bptr = NULL; ++ bsiz = 256; ++ tokstr_raw = bptr_raw = NULL; ++ bsiz_raw = len_raw = lex_add_raw = 0; ++ ++ inredir = 0; ++ } ++ if (parts & ZCONTEXT_HIST) { ++ if (!lstack) { ++ /* top level, make this version visible to ZLE */ ++ zle_chline = chline; ++ /* ensure line stored is NULL-terminated */ ++ if (hptr) ++ *hptr = '\0'; ++ } ++ ls->histactive = histactive; ++ ls->histdone = histdone; ++ ls->stophist = stophist; ++ ls->hline = chline; ++ ls->hptr = hptr; ++ ls->chwords = chwords; ++ ls->chwordlen = chwordlen; ++ ls->chwordpos = chwordpos; ++ ls->hwgetword = hwgetword; ++ ls->hgetc = hgetc; ++ ls->hungetc = hungetc; ++ ls->hwaddc = hwaddc; ++ ls->hwbegin = hwbegin; ++ ls->hwend = hwend; ++ ls->addtoline = addtoline; ++ ls->hlinesz = hlinesz; ++ /* ++ * We save and restore the command stack with history ++ * as it's visible to the user interactively, so if ++ * we're preserving history state we'll continue to ++ * show the current set of commands from input. ++ */ ++ ls->cstack = cmdstack; ++ ls->csp = cmdsp; ++ ++ stophist = 0; ++ chline = NULL; ++ hptr = NULL; ++ histactive = 0; ++ cmdstack = (unsigned char *)zalloc(CMDSTACKSZ); ++ cmdsp = 0; ++ } ++ if (parts & ZCONTEXT_PARSE) { ++ ls->hdocs = hdocs; ++ ls->eclen = eclen; ++ ls->ecused = ecused; ++ ls->ecnpats = ecnpats; ++ ls->ecbuf = ecbuf; ++ ls->ecstrs = ecstrs; ++ ls->ecsoffs = ecsoffs; ++ ls->ecssub = ecssub; ++ ls->ecnfunc = ecnfunc; ++ ecbuf = NULL; ++ hdocs = NULL; + } +- ls->hline = chline; +- chline = NULL; +- ls->hptr = hptr; +- hptr = NULL; +- ls->hlinesz = hlinesz; +- ls->cstack = cmdstack; +- ls->csp = cmdsp; +- cmdstack = (unsigned char *)zalloc(CMDSTACKSZ); +- ls->tok = tok; +- ls->isnewlin = isnewlin; +- ls->tokstr = tokstr; +- ls->zshlextext = zshlextext; +- ls->bptr = bptr; +- tokstr = zshlextext = bptr = NULL; +- ls->bsiz = bsiz; +- bsiz = 256; +- ls->len = len; +- ls->chwords = chwords; +- ls->chwordlen = chwordlen; +- ls->chwordpos = chwordpos; +- ls->hwgetword = hwgetword; +- ls->lexstop = lexstop; +- ls->hdocs = hdocs; +- ls->hgetc = hgetc; +- ls->hungetc = hungetc; +- ls->hwaddc = hwaddc; +- ls->hwbegin = hwbegin; +- ls->hwend = hwend; +- ls->addtoline = addtoline; +- ls->eclen = eclen; +- ls->ecused = ecused; +- ls->ecnpats = ecnpats; +- ls->ecbuf = ecbuf; +- ls->ecstrs = ecstrs; +- ls->ecsoffs = ecsoffs; +- ls->ecssub = ecssub; +- ls->ecnfunc = ecnfunc; +- ls->toklineno = toklineno; +- cmdsp = 0; +- inredir = 0; +- hdocs = NULL; +- histactive = 0; +- ecbuf = NULL; + + ls->next = lstack; + lstack = ls; + } + +-/* restore lexical state */ ++/* save context in full */ + + /**/ + mod_export void +-lexrestore(void) ++lexsave(void) ++{ ++ lexsave_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); ++} ++ ++/* restore context or part therefore */ ++ ++/**/ ++mod_export void ++lexrestore_partial(int parts) + { + struct lexstack *ln = lstack; + +@@ -330,65 +377,89 @@ lexrestore(void) + queue_signals(); + lstack = lstack->next; + +- if (!lstack) { +- /* Back to top level: don't need special ZLE value */ +- DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); +- zle_chline = NULL; ++ if (parts & ZCONTEXT_LEX) { ++ incmdpos = ln->incmdpos; ++ incond = ln->incond; ++ incasepat = ln->incasepat; ++ dbparens = ln->dbparens; ++ isfirstln = ln->isfirstln; ++ isfirstch = ln->isfirstch; ++ lexflags = ln->lexflags; ++ tok = ln->tok; ++ isnewlin = ln->isnewlin; ++ tokstr = ln->tokstr; ++ zshlextext = ln->zshlextext; ++ bptr = ln->bptr; ++ bsiz = ln->bsiz; ++ len = ln->len; ++ lex_add_raw = ln->lex_add_raw; ++ tokstr_raw = ln->tokstr_raw; ++ bptr_raw = ln->bptr_raw; ++ bsiz_raw = ln->bsiz_raw; ++ len_raw = ln->len_raw; ++ lexstop = ln->lexstop; ++ toklineno = ln->toklineno; ++ } ++ ++ if (parts & ZCONTEXT_HIST) { ++ if (!lstack) { ++ /* Back to top level: don't need special ZLE value */ ++ DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); ++ zle_chline = NULL; ++ } ++ histactive = ln->histactive; ++ histdone = ln->histdone; ++ stophist = ln->stophist; ++ chline = ln->hline; ++ hptr = ln->hptr; ++ chwords = ln->chwords; ++ chwordlen = ln->chwordlen; ++ chwordpos = ln->chwordpos; ++ hwgetword = ln->hwgetword; ++ hgetc = ln->hgetc; ++ hungetc = ln->hungetc; ++ hwaddc = ln->hwaddc; ++ hwbegin = ln->hwbegin; ++ hwend = ln->hwend; ++ addtoline = ln->addtoline; ++ hlinesz = ln->hlinesz; ++ if (cmdstack) ++ zfree(cmdstack, CMDSTACKSZ); ++ cmdstack = ln->cstack; ++ cmdsp = ln->csp; ++ } ++ ++ if (parts & ZCONTEXT_PARSE) { ++ if (ecbuf) ++ zfree(ecbuf, eclen); ++ ++ hdocs = ln->hdocs; ++ eclen = ln->eclen; ++ ecused = ln->ecused; ++ ecnpats = ln->ecnpats; ++ ecbuf = ln->ecbuf; ++ ecstrs = ln->ecstrs; ++ ecsoffs = ln->ecsoffs; ++ ecssub = ln->ecssub; ++ ecnfunc = ln->ecnfunc; ++ ++ errflag = 0; + } + +- incmdpos = ln->incmdpos; +- incond = ln->incond; +- incasepat = ln->incasepat; +- dbparens = ln->dbparens; +- isfirstln = ln->isfirstln; +- isfirstch = ln->isfirstch; +- histactive = ln->histactive; +- histdone = ln->histdone; +- lexflags = ln->lexflags; +- stophist = ln->stophist; +- chline = ln->hline; +- hptr = ln->hptr; +- if (cmdstack) +- zfree(cmdstack, CMDSTACKSZ); +- cmdstack = ln->cstack; +- cmdsp = ln->csp; +- tok = ln->tok; +- isnewlin = ln->isnewlin; +- tokstr = ln->tokstr; +- zshlextext = ln->zshlextext; +- bptr = ln->bptr; +- bsiz = ln->bsiz; +- len = ln->len; +- chwords = ln->chwords; +- chwordlen = ln->chwordlen; +- chwordpos = ln->chwordpos; +- hwgetword = ln->hwgetword; +- lexstop = ln->lexstop; +- hdocs = ln->hdocs; +- hgetc = ln->hgetc; +- hungetc = ln->hungetc; +- hwaddc = ln->hwaddc; +- hwbegin = ln->hwbegin; +- hwend = ln->hwend; +- addtoline = ln->addtoline; +- if (ecbuf) +- zfree(ecbuf, eclen); +- eclen = ln->eclen; +- ecused = ln->ecused; +- ecnpats = ln->ecnpats; +- ecbuf = ln->ecbuf; +- ecstrs = ln->ecstrs; +- ecsoffs = ln->ecsoffs; +- ecssub = ln->ecssub; +- ecnfunc = ln->ecnfunc; +- hlinesz = ln->hlinesz; +- toklineno = ln->toklineno; +- errflag = 0; + free(ln); + + unqueue_signals(); + } + ++/* complete restore context */ ++ ++/**/ ++mod_export void ++lexrestore(void) ++{ ++ lexrestore_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); ++} ++ + /**/ + void + zshlex(void) +@@ -1889,80 +1960,151 @@ exalias(void) + return 0; + } + +-/* skip (...) */ ++/**/ ++void ++zshlex_raw_add(int c) ++{ ++ if (!lex_add_raw) ++ return; ++ ++ *bptr_raw++ = c; ++ if (bsiz_raw == ++len_raw) { ++ int newbsiz = bsiz_raw * 2; ++ ++ tokstr_raw = (char *)hrealloc(tokstr_raw, bsiz_raw, newbsiz); ++ bptr_raw = tokstr_raw + len_raw; ++ memset(bptr_raw, 0, newbsiz - bsiz_raw); ++ bsiz_raw = newbsiz; ++ } ++} ++ ++/**/ ++void ++zshlex_raw_back(void) ++{ ++ if (!lex_add_raw) ++ return; ++ bptr_raw--; ++ len_raw--; ++} ++ ++/* ++ * Skip (...) for command-style substitutions: $(...), <(...), >(...) ++ * ++ * In order to ensure we don't stop at closing parentheses with ++ * some other syntactic significance, we'll parse the input until ++ * we find an unmatched closing parenthesis. However, we'll throw ++ * away the result of the parsing and just keep the string we've built ++ * up on the way. ++ */ + + /**/ + static int + skipcomm(void) + { +- int pct = 1, c, start = 1; ++ char *new_tokstr, *new_bptr = bptr_raw; ++ int new_len, new_bsiz, new_lexstop, new_lex_add_raw; + + cmdpush(CS_CMDSUBST); + SETPARBEGIN +- c = Inpar; +- do { +- int iswhite; +- add(c); +- c = hgetc(); +- if (itok(c) || lexstop) +- break; +- iswhite = inblank(c); +- switch (c) { +- case '(': +- pct++; +- break; +- case ')': +- pct--; +- break; +- case '\\': +- add(c); +- c = hgetc(); +- break; +- case '\'': { +- int strquote = bptr[-1] == '$'; +- add(c); +- STOPHIST +- while ((c = hgetc()) != '\'' && !lexstop) { +- if (c == '\\' && strquote) { +- add(c); +- c = hgetc(); +- } +- add(c); +- } +- ALLOWHIST +- break; +- } +- case '\"': +- add(c); +- while ((c = hgetc()) != '\"' && !lexstop) +- if (c == '\\') { +- add(c); +- add(hgetc()); +- } else +- add(c); +- break; +- case '`': +- add(c); +- while ((c = hgetc()) != '`' && !lexstop) +- if (c == '\\') +- add(c), add(hgetc()); +- else +- add(c); +- break; +- case '#': +- if (start) { +- add(c); +- while ((c = hgetc()) != '\n' && !lexstop) +- add(c); +- iswhite = 1; +- } +- break; ++ add(Inpar); ++ ++ new_lex_add_raw = lex_add_raw + 1; ++ if (!lex_add_raw) { ++ /* ++ * We'll combine the string so far with the input ++ * read in for the command substitution. To do this ++ * we'll just propagate the current tokstr etc. as the ++ * variables used for adding raw input, and ++ * ensure we swap those for the real tokstr etc. at the end. ++ * ++ * However, we need to save and restore the rest of the ++ * lexical and parse state as we're effectively parsing ++ * an internal string. Because we're still parsing it from ++ * the original input source (we have to --- we don't know ++ * when to stop inputting it otherwise and can't rely on ++ * the input being recoverable until we've read it) we need ++ * to keep the same history context. ++ */ ++ new_tokstr = tokstr; ++ new_bptr = bptr; ++ new_len = len; ++ new_bsiz = bsiz; ++ ++ lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); ++ } else { ++ /* ++ * Set up for nested command subsitution, however ++ * we don't actually need the string until we get ++ * back to the top level and recover the lot. ++ * The $() body just appears empty. ++ * ++ * We do need to propagate the raw variables which would ++ * otherwise by cleared, though. ++ */ ++ new_tokstr = tokstr_raw; ++ new_bptr = bptr_raw; ++ new_len = len_raw; ++ new_bsiz = bsiz_raw; ++ ++ lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); ++ } ++ tokstr_raw = new_tokstr; ++ bsiz_raw = new_bsiz; ++ len_raw = new_len; ++ bptr_raw = new_bptr; ++ lex_add_raw = new_lex_add_raw; ++ ++ if (!parse_event(OUTPAR) || tok != OUTPAR) ++ lexstop = 1; ++ /* Outpar lexical token gets added in caller if present */ ++ ++ /* ++ * We're going to keep the full raw input string ++ * as the current token string after popping the stack. ++ */ ++ new_tokstr = tokstr_raw; ++ new_bptr = bptr_raw; ++ new_len = len_raw; ++ new_bsiz = bsiz_raw; ++ /* ++ * We're also going to propagate the lexical state: ++ * if we couldn't parse the command substitution we ++ * can't continue. ++ */ ++ new_lexstop = lexstop; ++ ++ lexrestore_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); ++ ++ if (lex_add_raw) { ++ /* ++ * Keep going, so retain the raw variables. ++ */ ++ tokstr_raw = new_tokstr; ++ bptr_raw = new_bptr; ++ len_raw = new_len; ++ bsiz_raw = new_bsiz; ++ } else { ++ if (!new_lexstop) { ++ /* Ignore the ')' added on input */ ++ new_len--; ++ *--new_bptr = '\0'; + } +- start = iswhite; ++ ++ /* ++ * Convince the rest of lex.c we were examining a string ++ * all along. ++ */ ++ tokstr = new_tokstr; ++ bptr = new_bptr; ++ len = new_len; ++ bsiz = new_bsiz; ++ lexstop = new_lexstop; + } +- while (pct); ++ + if (!lexstop) + SETPAREND + cmdpop(); ++ + return lexstop; + } +diff --git a/Src/parse.c b/Src/parse.c +index 753080d..b0a7624 100644 +--- a/Src/parse.c ++++ b/Src/parse.c +@@ -360,7 +360,8 @@ ecstrcode(char *s) + + /* Initialise wordcode buffer. */ + +-static void ++/**/ ++void + init_parse(void) + { + if (ecbuf) zfree(ecbuf, eclen); +@@ -439,11 +440,15 @@ clear_hdocs() + * event : ENDINPUT + * | SEPER + * | sublist [ SEPER | AMPER | AMPERBANG ] ++ * ++ * cmdsubst indicates our event is part of a command-style ++ * substitution terminated by the token indicationg, usual closing ++ * parenthesis. In other cases endtok is ENDINPUT. + */ + + /**/ + Eprog +-parse_event(void) ++parse_event(int endtok) + { + tok = ENDINPUT; + incmdpos = 1; +@@ -451,36 +456,42 @@ parse_event(void) + zshlex(); + init_parse(); + +- if (!par_event()) { ++ if (!par_event(endtok)) { + clear_hdocs(); + return NULL; + } ++ if (endtok != ENDINPUT) { ++ /* don't need to build an eprog for this */ ++ return &dummy_eprog; ++ } + return bld_eprog(); + } + + /**/ +-static int +-par_event(void) ++int ++par_event(int endtok) + { + int r = 0, p, c = 0; + + while (tok == SEPER) { +- if (isnewlin > 0) ++ if (isnewlin > 0 && endtok == ENDINPUT) + return 0; + zshlex(); + } + if (tok == ENDINPUT) + return 0; ++ if (tok == endtok) ++ return 0; + + p = ecadd(0); + + if (par_sublist(&c)) { +- if (tok == ENDINPUT) { ++ if (tok == ENDINPUT || tok == endtok) { + set_list_code(p, Z_SYNC, c); + r = 1; + } else if (tok == SEPER) { + set_list_code(p, Z_SYNC, c); +- if (isnewlin <= 0) ++ if (isnewlin <= 0 || endtok != ENDINPUT) + zshlex(); + r = 1; + } else if (tok == AMPER) { +@@ -509,7 +520,7 @@ par_event(void) + } else { + int oec = ecused; + +- if (!par_event()) { ++ if (!par_event(endtok)) { + ecused = oec; + ecbuf[p] |= wc_bdata(Z_END); + } +diff --git a/Src/zsh.h b/Src/zsh.h +index 207ef18..b3391ed 100644 +--- a/Src/zsh.h ++++ b/Src/zsh.h +@@ -395,6 +395,15 @@ enum { + #define META_HEAPDUP 6 + #define META_HREALLOC 7 + ++/* Context to save and restore (bit fields) */ ++enum { ++ /* History mechanism */ ++ ZCONTEXT_HIST = (1<<0), ++ /* Lexical analyser */ ++ ZCONTEXT_LEX = (1<<1), ++ /* Parser */ ++ ZCONTEXT_PARSE = (1<<2) ++}; + + /**************************/ + /* Abstract types for zsh */ +diff --git a/Test/D08cmdsubst.ztst b/Test/D08cmdsubst.ztst +index 5661b0a..a4c69a0 100644 +--- a/Test/D08cmdsubst.ztst ++++ b/Test/D08cmdsubst.ztst +@@ -106,3 +106,45 @@ + >34 + >" + >" OK ++ ++ echo $(case foo in ++ foo) ++ echo This test worked. ++ ;; ++ bar) ++ echo This test failed in a rather bizarre way. ++ ;; ++ *) ++ echo This test failed. ++ ;; ++ esac) ++0:Parsing of command substitution with unmatched parentheses: case, basic ++>This test worked. ++ ++ echo "$(case bar in ++ foo) ++ echo This test spoobed. ++ ;; ++ bar) ++ echo This test plurbled. ++ ;; ++ *) ++ echo This test bzonked. ++ ;; ++ esac)" ++0:Parsing of command substitution with unmatched parentheses: case with quotes ++>This test plurbled. ++ ++ echo before $( ++ echo start; echo unpretentious | ++ while read line; do ++ case $line in ++ u*) ++ print Word began with u ++ print and ended with a crunch ++ ;; ++ esac ++ done | sed -e 's/Word/Universe/'; echo end ++ ) after ++0:Parsing of command substitution with ummatched parentheses: with frills ++>before start Universe began with u and ended with a crunch end after +-- +2.4.3 + + +From 925112048811087520954e0c739b29371eee188a Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Thu, 8 Jan 2015 21:39:26 +0000 +Subject: [PATCH 2/9] Resolves: #1338689 - better initialize parser state + +This fix is isolated out from a huge upstream commit that includes major +code refactoring changes together with the initialization fix actually +needed to resolve #1338689. + +Upstream-commit: cfd91eac0732da8ece012ca4ab051d928a85c9dd +Signed-off-by: Kamil Dudka +--- + Src/hist.c | 5 +++++ + Src/parse.c | 20 ++++++++++++++++++-- + 2 files changed, 23 insertions(+), 2 deletions(-) + +diff --git a/Src/hist.c b/Src/hist.c +index 561e2ac..4ba61b1 100644 +--- a/Src/hist.c ++++ b/Src/hist.c +@@ -804,6 +804,11 @@ strinbeg(int dohist) + strin++; + hbegin(dohist); + lexinit(); ++ /* ++ * Also initialise some variables owned by the parser but ++ * used for communication between the parser and lexer. ++ */ ++ init_parse_status(); + } + + /* done reading a string */ +diff --git a/Src/parse.c b/Src/parse.c +index b0a7624..b3b004b 100644 +--- a/Src/parse.c ++++ b/Src/parse.c +@@ -358,6 +358,21 @@ ecstrcode(char *s) + } while (0) + + ++/**/ ++mod_export void ++init_parse_status(void) ++{ ++ /* ++ * These variables are currently declared by the parser, so we ++ * initialise them here. Possibly they are more naturally declared ++ * by the lexical anaylser; however, as they are used for signalling ++ * between the two it's a bit ambiguous. We clear them when ++ * using the lexical analyser for strings as well as here. ++ */ ++ incasepat = incond = inredir = infor = 0; ++ incmdpos = 1; ++} ++ + /* Initialise wordcode buffer. */ + + /**/ +@@ -372,6 +387,8 @@ init_parse(void) + ecsoffs = ecnpats = 0; + ecssub = 0; + ecnfunc = 0; ++ ++ init_parse_status(); + } + + /* Build eprog. */ +@@ -535,9 +552,8 @@ parse_list(void) + int c = 0; + + tok = ENDINPUT; +- incmdpos = 1; +- zshlex(); + init_parse(); ++ zshlex(); + par_list(&c); + if (tok != ENDINPUT) { + clear_hdocs(); +-- +2.5.5 + + +From 00bc31b497525433dbaeafd3e7b92c7fe364dc8c Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Wed, 15 Apr 2015 10:20:06 +0100 +Subject: [PATCH 3/9] 34892 (slightly tweaked): math evaluation fix + +An empty expression resulting from substitution includes a +Nularg, which needs handling the same as an empty string. + +Upstream-commit: 2ef4b38461dfb554ed2226d9de8958703bc00b98 +Signed-off-by: Kamil Dudka +--- + Src/math.c | 15 ++++++++++++++- + Test/C01arith.ztst | 4 ++++ + 2 files changed, 18 insertions(+), 1 deletion(-) + +diff --git a/Src/math.c b/Src/math.c +index e90d6a5..d6db7d3 100644 +--- a/Src/math.c ++++ b/Src/math.c +@@ -1330,7 +1330,7 @@ matheval(char *s) + if (!mlevel) + outputradix = 0; + +- if (!*s) { ++ if (!*s || *s == Nularg) { + x.type = MN_INTEGER; + x.u.l = 0; + return x; +@@ -1358,6 +1358,19 @@ mathevalarg(char *s, char **ss) + mnumber x; + int xmtok = mtok; + ++ /* ++ * At this entry point we don't allow an empty expression, ++ * whereas we do with matheval(). I'm not sure if this ++ * difference is deliberate, but it does mean that e.g. ++ * $array[$ind] where ind hasn't been set produces an error, ++ * which is probably safe. ++ * ++ * To avoid a more opaque error further in, bail out here. ++ */ ++ if (!*s || *s == Nularg) { ++ zerr("bad math expression: empty string"); ++ return (zlong)0; ++ } + x = mathevall(s, MPREC_ARG, ss); + if (mtok == COMMA) + (*ss)--; +diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst +index 02d1519..33b03ef 100644 +--- a/Test/C01arith.ztst ++++ b/Test/C01arith.ztst +@@ -243,3 +243,7 @@ + >6000000 + >5000 + >255 ++ ++ print $((`:`)) ++0:Null string in arithmetic evaluation after command substitution ++>0 +-- +2.4.6 + + +From 0c1450a286e578a1cfe266bf743faf2f0719f85b Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Wed, 29 Jul 2015 22:36:45 -0700 +Subject: [PATCH 4/9] 35953: fix handling of command substitution in math + context + +Upstream-commit: c0a80171ee615b52a15a6fc8efe83c2bb53451d2 +Signed-off-by: Kamil Dudka +--- + Src/lex.c | 6 +++++- + Test/A01grammar.ztst | 6 ++++++ + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/Src/lex.c b/Src/lex.c +index bcceda6..f43b92b 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -1541,7 +1541,7 @@ dquote_parse(char endchar, int sub) + { + int pct = 0, brct = 0, bct = 0, intick = 0, err = 0; + int c; +- int math = endchar == ')' || endchar == ']'; ++ int math = endchar == ')' || endchar == ']' || infor; + int zlemath = math && zlemetacs > zlemetall + addedx - inbufct; + + while (((c = hgetc()) != endchar || bct || +@@ -2004,7 +2004,9 @@ skipcomm(void) + { + char *new_tokstr, *new_bptr = bptr_raw; + int new_len, new_bsiz, new_lexstop, new_lex_add_raw; ++ int save_infor = infor; + ++ infor = 0; + cmdpush(CS_CMDSUBST); + SETPARBEGIN + add(Inpar); +@@ -2054,6 +2056,7 @@ skipcomm(void) + len_raw = new_len; + bptr_raw = new_bptr; + lex_add_raw = new_lex_add_raw; ++ dbparens = 0; /* restored by zcontext_restore_partial() */ + + if (!parse_event(OUTPAR) || tok != OUTPAR) + lexstop = 1; +@@ -2105,6 +2108,7 @@ skipcomm(void) + if (!lexstop) + SETPAREND + cmdpop(); ++ infor = save_infor; + + return lexstop; + } +diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst +index f04ddda..584ebd6 100644 +--- a/Test/A01grammar.ztst ++++ b/Test/A01grammar.ztst +@@ -169,6 +169,12 @@ + >1 + >2 + ++ for (( $(true); ; )); do break; done ++ for (( ; $(true); )); do break; done ++ for (( ; ; $(true) )); do break; done ++ for (( ; $((1)); )); do break; done ++0:regression test, nested cmdsubst in arithmetic `for' loop ++ + for keyvar valvar in key1 val1 key2 val2; do + print key=$keyvar val=$valvar + done +-- +2.4.6 + + +From 821815bd9c24a84d8bb5796732ab6144b35e7d27 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Sat, 10 Jan 2015 20:28:57 +0000 +Subject: [PATCH 5/9] 34220: new $(...) handling needs to back up over alias + expansion + +Upstream-commit: 3b32abafdb019cfb8f29908bc3d148e01518981d +Signed-off-by: Kamil Dudka +--- + Src/input.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/Src/input.c b/Src/input.c +index 1579762..5b782dc 100644 +--- a/Src/input.c ++++ b/Src/input.c +@@ -532,6 +532,12 @@ inpush(char *str, int flags, Alias inalias) + static void + inpoptop(void) + { ++ if (!lexstop) { ++ inbufflags &= ~INP_ALCONT; ++ while (inbufptr > inbuf) ++ inungetc(inbufptr[-1]); ++ } ++ + if (inbuf && (inbufflags & INP_FREE)) + free(inbuf); + +-- +2.4.6 + + +From 1c731b7d1178a2623aa1b986f38a7decebf2c993 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Fri, 16 Jan 2015 13:20:05 +0000 +Subject: [PATCH 6/9] 34304: improve use of new cmd subst in completion + +Upstream-commit: db05cc51fa2298cf128e480d3ac8e5373029f6b9 +Signed-off-by: Kamil Dudka +--- + Src/lex.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 103 insertions(+), 10 deletions(-) + +diff --git a/Src/lex.c b/Src/lex.c +index f43b92b..45c1117 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -88,6 +88,12 @@ int inalmore; + int nocorrect; + + /* ++ * TBD: the following exported variables are part of the non-interface ++ * with ZLE for completion. They are poorly named and the whole ++ * scheme is incredibly brittle. One piece of robustness is applied: ++ * the variables are only set if LEXFLAGS_ZLE is set. Improvements ++ * should therefore concentrate on areas with this flag set. ++ * + * Cursor position and line length in zle when the line is + * metafied for access from the main shell. + */ +@@ -111,6 +117,16 @@ mod_export int addedx; + /**/ + mod_export int wb, we; + ++/**/ ++mod_export int wordbeg; ++ ++/**/ ++mod_export int parbegin; ++ ++/**/ ++mod_export int parend; ++ ++ + /* 1 if aliases should not be expanded */ + + /**/ +@@ -132,15 +148,6 @@ mod_export int noaliases; + /**/ + mod_export int lexflags; + +-/**/ +-mod_export int wordbeg; +- +-/**/ +-mod_export int parbegin; +- +-/**/ +-mod_export int parend; +- + /* don't recognize comments */ + + /**/ +@@ -791,7 +798,8 @@ gettok(void) + if (lexstop) + return (errflag) ? LEXERR : ENDINPUT; + isfirstln = 0; +- wordbeg = inbufct - (qbang && c == bangchar); ++ if ((lexflags & LEXFLAGS_ZLE)) ++ wordbeg = inbufct - (qbang && c == bangchar); + hwbegin(-1-(qbang && c == bangchar)); + /* word includes the last character read and possibly \ before ! */ + if (dbparens) { +@@ -2002,6 +2010,78 @@ zshlex_raw_back(void) + static int + skipcomm(void) + { ++#ifdef ZSH_OLD_SKIPCOMM ++ int pct = 1, c, start = 1; ++ ++ cmdpush(CS_CMDSUBST); ++ SETPARBEGIN ++ c = Inpar; ++ do { ++ int iswhite; ++ add(c); ++ c = hgetc(); ++ if (itok(c) || lexstop) ++ break; ++ iswhite = inblank(c); ++ switch (c) { ++ case '(': ++ pct++; ++ break; ++ case ')': ++ pct--; ++ break; ++ case '\\': ++ add(c); ++ c = hgetc(); ++ break; ++ case '\'': { ++ int strquote = lexbuf.ptr[-1] == '$'; ++ add(c); ++ STOPHIST ++ while ((c = hgetc()) != '\'' && !lexstop) { ++ if (c == '\\' && strquote) { ++ add(c); ++ c = hgetc(); ++ } ++ add(c); ++ } ++ ALLOWHIST ++ break; ++ } ++ case '\"': ++ add(c); ++ while ((c = hgetc()) != '\"' && !lexstop) ++ if (c == '\\') { ++ add(c); ++ add(hgetc()); ++ } else ++ add(c); ++ break; ++ case '`': ++ add(c); ++ while ((c = hgetc()) != '`' && !lexstop) ++ if (c == '\\') ++ add(c), add(hgetc()); ++ else ++ add(c); ++ break; ++ case '#': ++ if (start) { ++ add(c); ++ while ((c = hgetc()) != '\n' && !lexstop) ++ add(c); ++ iswhite = 1; ++ } ++ break; ++ } ++ start = iswhite; ++ } ++ while (pct); ++ if (!lexstop) ++ SETPAREND ++ cmdpop(); ++ return lexstop; ++#else + char *new_tokstr, *new_bptr = bptr_raw; + int new_len, new_bsiz, new_lexstop, new_lex_add_raw; + int save_infor = infor; +@@ -2057,6 +2137,18 @@ skipcomm(void) + bptr_raw = new_bptr; + lex_add_raw = new_lex_add_raw; + dbparens = 0; /* restored by zcontext_restore_partial() */ ++ /* ++ * Don't do any ZLE specials down here: they're only needed ++ * when we return the string from the recursive parse. ++ * (TBD: this probably means we should be initialising lexflags ++ * more consistently.) ++ * ++ * Note that in that case we're still using the ZLE line reading ++ * function at the history layer --- this is consistent with the ++ * intention of maintaining the history and input layers across ++ * the recursive parsing. ++ */ ++ lexflags &= ~LEXFLAGS_ZLE; + + if (!parse_event(OUTPAR) || tok != OUTPAR) + lexstop = 1; +@@ -2111,4 +2203,5 @@ skipcomm(void) + infor = save_infor; + + return lexstop; ++#endif + } +-- +2.5.5 + + +From ad64470d3ea4190cd854aab2bc0f8d01ec6aef11 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Fri, 16 Jan 2015 20:12:40 +0000 +Subject: [PATCH 7/9] 32413: turn off history word marking in cmd subst + +Upstream-commit: f2a2f28f7bde196cd1fa205ac0c20336046cf2cf +Signed-off-by: Kamil Dudka +--- + Src/hist.c | 22 ++++++++++++++++++++-- + Src/lex.c | 2 ++ + 2 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/Src/hist.c b/Src/hist.c +index 561e2ac..e29a566 100644 +--- a/Src/hist.c ++++ b/Src/hist.c +@@ -131,6 +131,8 @@ mod_export int hist_skip_flags; + /* Bits of histactive variable */ + #define HA_ACTIVE (1<<0) /* History mechanism is active */ + #define HA_NOINC (1<<1) /* Don't store, curhist not incremented */ ++#define HA_INWORD (1<<2) /* We're inside a word, don't add ++ start and end markers */ + + /* Array of word beginnings and endings in current history line. */ + +@@ -219,6 +221,22 @@ static int histsave_stack_pos = 0; + + static zlong histfile_linect; + ++/* ++ * Mark that the current level of history is or is not ++ * within a word, whatever turns up. This is used for nested ++ * parsing of substitutions. ++ */ ++ ++/**/ ++void ++hist_in_word(int yesno) ++{ ++ if (yesno) ++ histactive |= HA_INWORD; ++ else ++ histactive &= ~HA_INWORD; ++} ++ + /* add a character to the current history word */ + + static void +@@ -1329,7 +1347,7 @@ int hwgetword = -1; + void + ihwbegin(int offset) + { +- if (stophist == 2) ++ if (stophist == 2 || (histactive & HA_INWORD)) + return; + if (chwordpos%2) + chwordpos--; /* make sure we're on a word start, not end */ +@@ -1349,7 +1367,7 @@ ihwbegin(int offset) + void + ihwend(void) + { +- if (stophist == 2) ++ if (stophist == 2 || (histactive & HA_INWORD)) + return; + if (chwordpos%2 && chline) { + /* end of word reached and we've already begun a word */ +diff --git a/Src/lex.c b/Src/lex.c +index f43b92b..f1aa85d 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -2114,6 +2114,7 @@ skipcomm(void) + new_bsiz = bsiz; + + lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); ++ hist_in_word(1); + } else { + /* + * Set up for nested command subsitution, however +@@ -2195,6 +2196,7 @@ skipcomm(void) + len = new_len; + bsiz = new_bsiz; + lexstop = new_lexstop; ++ hist_in_word(0); + } + + if (!lexstop) +-- +2.5.5 + + +From 22b063c5f2bb3350c856215e436a62d25440e605 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Sun, 18 Jan 2015 16:43:26 +0000 +Subject: [PATCH 8/9] 34319: fix alias expansion in history for command + substitution + +Upstream-commit: e34ce85151dcd5ac698e116a6742d481ff64ae2c +Signed-off-by: Kamil Dudka +--- + Src/hist.c | 26 ++++++++++++++++++++------ + 1 file changed, 20 insertions(+), 6 deletions(-) + +diff --git a/Src/hist.c b/Src/hist.c +index e29a566..08763fe 100644 +--- a/Src/hist.c ++++ b/Src/hist.c +@@ -243,7 +243,16 @@ static void + ihwaddc(int c) + { + /* Only if history line exists and lexing has not finished. */ +- if (chline && !(errflag || lexstop)) { ++ if (chline && !(errflag || lexstop) && ++ /* ++ * If we're reading inside a word for command substitution ++ * we allow the lexer to expand aliases but don't deal ++ * with them here. Note matching code in ihungetc(). ++ * TBD: it might be neater to deal with all aliases in this ++ * fashion as we never need the expansion in the history ++ * line, only in the lexer and above. ++ */ ++ !((histactive & HA_INWORD) && (inbufflags & INP_ALIAS))) { + /* Quote un-expanded bangs in the history line. */ + if (c == bangchar && stophist < 2 && qbang) + /* If qbang is not set, we do not escape this bangchar as it's * +@@ -798,11 +807,16 @@ ihungetc(int c) + zlemetall--; + exlast++; + } +- DPUTS(hptr <= chline, "BUG: hungetc attempted at buffer start"); +- hptr--; +- DPUTS(*hptr != (char) c, "BUG: wrong character in hungetc() "); +- qbang = (c == bangchar && stophist < 2 && +- hptr > chline && hptr[-1] == '\\'); ++ if (!(histactive & HA_INWORD) || !(inbufflags & INP_ALIAS)) { ++ DPUTS(hptr <= chline, "BUG: hungetc attempted at buffer start"); ++ hptr--; ++ DPUTS(*hptr != (char) c, "BUG: wrong character in hungetc() "); ++ qbang = (c == bangchar && stophist < 2 && ++ hptr > chline && hptr[-1] == '\\'); ++ } else { ++ /* No active bangs in aliases */ ++ qbang = 0; ++ } + if (doit) + inungetc(c); + if (!qbang) +-- +2.5.5 + + +From 155587d13060e4c7c9bbd61b7cc0a6dd17922d56 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Sun, 18 Jan 2015 22:38:57 +0000 +Subject: [PATCH 9/9] 34322: bug with interface to parsestr() etc. + +Was showing up in places like ${(e)...} where command substitution +could reallocate the token string, but actually there was never any +guarantee that the lexer wouldn't do that, so this was always +a bit iffy. + +Upstream-commit: c6c9f5daf2e196e6ab7346dfbf5f5166a1d87f0c +Signed-off-by: Kamil Dudka +--- + Src/Zle/compctl.c | 4 ++-- + Src/Zle/compresult.c | 3 ++- + Src/exec.c | 9 +++++---- + Src/init.c | 11 +++++++---- + Src/lex.c | 30 +++++++++++++++++++++--------- + Src/params.c | 3 ++- + Src/prompt.c | 2 +- + Src/subst.c | 8 +++++--- + Src/utils.c | 2 +- + Test/D04parameter.ztst | 7 +++++++ + 10 files changed, 53 insertions(+), 26 deletions(-) + +diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c +index 0143370..5d67137 100644 +--- a/Src/Zle/compctl.c ++++ b/Src/Zle/compctl.c +@@ -3854,7 +3854,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) + yaptr = get_user_var(uv); + if ((tt = cc->explain)) { + tt = dupstring(tt); +- if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) { ++ if ((cc->mask & CC_EXPANDEXPL) && !parsestr(&tt)) { + singsub(&tt); + untokenize(tt); + } +@@ -3874,7 +3874,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) + } + } else if ((tt = cc->explain)) { + tt = dupstring(tt); +- if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) { ++ if ((cc->mask & CC_EXPANDEXPL) && !parsestr(&tt)) { + singsub(&tt); + untokenize(tt); + } +diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c +index c0e5ff3..69d066c 100644 +--- a/Src/Zle/compresult.c ++++ b/Src/Zle/compresult.c +@@ -1090,7 +1090,8 @@ do_single(Cmatch m) + } + if (tryit) { + noerrs = 1; +- parsestr(p); ++ p = dupstring(p); ++ parsestr(&p); + singsub(&p); + errflag = 0; + noerrs = ne; +diff --git a/Src/exec.c b/Src/exec.c +index 7817a64..27e235f 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -3631,17 +3631,18 @@ gethere(char **strp, int typ) + *bptr++ = '\n'; + } + *t = '\0'; ++ s = buf; ++ buf = dupstring(buf); ++ zfree(s, bsiz); + if (!qt) { + int ef = errflag; + +- parsestr(buf); ++ parsestr(&buf); + + if (!errflag) + errflag = ef; + } +- s = dupstring(buf); +- zfree(buf, bsiz); +- return s; ++ return buf; + } + + /* open here string fd */ +diff --git a/Src/init.c b/Src/init.c +index 78f171d..485fb32 100644 +--- a/Src/init.c ++++ b/Src/init.c +@@ -1143,10 +1143,13 @@ run_init_scripts(void) + if (islogin) + sourcehome(".profile"); + noerrs = 2; +- if (s && !parsestr(s)) { +- singsub(&s); +- noerrs = 0; +- source(s); ++ if (s) { ++ s = dupstring(s); ++ if (!parsestr(&s)) { ++ singsub(&s); ++ noerrs = 0; ++ source(s); ++ } + } + noerrs = 0; + } else +diff --git a/Src/lex.c b/Src/lex.c +index b8fe332..fa920bd 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -1693,17 +1693,27 @@ dquote_parse(char endchar, int sub) + return err; + } + +-/* Tokenize a string given in s. Parsing is done as in double * +- * quotes. This is usually called before singsub(). */ ++/* ++ * Tokenize a string given in s. Parsing is done as in double ++ * quotes. This is usually called before singsub(). ++ * ++ * parsestr() is noisier, reporting an error if the parse failed. ++ * ++ * On entry, *s must point to a string allocated from the stack of ++ * exactly the right length, i.e. strlen(*s) + 1, as the string ++ * is used as the lexical token string whose memory management ++ * demands this. Usually the input string will therefore be ++ * the result of an immediately preceding dupstring(). ++ */ + + /**/ + mod_export int +-parsestr(char *s) ++parsestr(char **s) + { + int err; + + if ((err = parsestrnoerr(s))) { +- untokenize(s); ++ untokenize(*s); + if (err > 32 && err < 127) + zerr("parse error near `%c'", err); + else +@@ -1714,18 +1724,20 @@ parsestr(char *s) + + /**/ + mod_export int +-parsestrnoerr(char *s) ++parsestrnoerr(char **s) + { +- int l = strlen(s), err; ++ int l = strlen(*s), err; + + lexsave(); +- untokenize(s); +- inpush(dupstring(s), 0, NULL); ++ untokenize(*s); ++ inpush(dupstring(*s), 0, NULL); + strinbeg(0); + len = 0; +- bptr = tokstr = s; ++ bptr = tokstr = *s; + bsiz = l + 1; + err = dquote_parse('\0', 1); ++ if (tokstr) ++ *s = tokstr; + *bptr = '\0'; + strinend(); + inpop(); +diff --git a/Src/params.c b/Src/params.c +index babf6f2..f7551b2 100644 +--- a/Src/params.c ++++ b/Src/params.c +@@ -1241,7 +1241,8 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w, + if (ishash && (keymatch || !rev)) + remnulargs(s); + if (needtok) { +- if (parsestr(s)) ++ s = dupstring(s); ++ if (parsestr(&s)) + return 0; + singsub(&s); + } else if (rev) +diff --git a/Src/prompt.c b/Src/prompt.c +index e51ce24..290f227 100644 +--- a/Src/prompt.c ++++ b/Src/prompt.c +@@ -183,7 +183,7 @@ promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep) + int oldval = lastval; + + s = dupstring(s); +- if (!parsestr(s)) ++ if (!parsestr(&s)) + singsub(&s); + /* + * We don't need the special Nularg hack here and we're +diff --git a/Src/subst.c b/Src/subst.c +index a4df256..dcffe2f 100644 +--- a/Src/subst.c ++++ b/Src/subst.c +@@ -1306,7 +1306,7 @@ get_intarg(char **s, int *delmatchp) + p = dupstring(*s + arglen); + *s = t + arglen; + *t = sav; +- if (parsestr(p)) ++ if (parsestr(&p)) + return -1; + singsub(&p); + if (errflag) +@@ -1329,7 +1329,8 @@ subst_parse_str(char **sp, int single, int err) + + *sp = s = dupstring(*sp); + +- if (!(err ? parsestr(s) : parsestrnoerr(s))) { ++ if (!(err ? parsestr(&s) : parsestrnoerr(&s))) { ++ *sp = s; + if (!single) { + int qt = 0; + +@@ -1426,7 +1427,8 @@ check_colon_subscript(char *str, char **endp) + } + sav = **endp; + **endp = '\0'; +- if (parsestr(str = dupstring(str))) ++ str = dupstring(str); ++ if (parsestr(&str)) + return NULL; + singsub(&str); + remnulargs(str); +diff --git a/Src/utils.c b/Src/utils.c +index 26e2a5c..2c1d034 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -1440,7 +1440,7 @@ checkmailpath(char **s) + setunderscore(*s); + + u = dupstring(u); +- if (! parsestr(u)) { ++ if (!parsestr(&u)) { + singsub(&u); + zputs(u, shout); + fputc('\n', shout); +diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst +index bea9459..fa629b2 100644 +--- a/Test/D04parameter.ztst ++++ b/Test/D04parameter.ztst +@@ -1551,3 +1551,10 @@ + 0:Empty parameter shouldn't cause modifiers to crash the shell + > + > ++ ++# The following tests the return behaviour of parsestr/parsestrnoerr ++ alias param-test-alias='print $'\''\x45xpanded in substitution'\' ++ param='$(param-test-alias)' ++ print ${(e)param} ++0:Alias expansion in command substitution in parameter evaluation ++>Expanded in substitution +-- +2.7.4 + diff --git a/SOURCES/zsh-5.0.2-comp-args.patch b/SOURCES/zsh-5.0.2-comp-args.patch new file mode 100644 index 0000000..185e499 --- /dev/null +++ b/SOURCES/zsh-5.0.2-comp-args.patch @@ -0,0 +1,112 @@ +From f92e6a9a7360b0485ebdaa006042337ffd9aa8df Mon Sep 17 00:00:00 2001 +From: Jun-ichi Takimoto +Date: Fri, 6 Feb 2015 23:06:07 +0900 +Subject: [PATCH 1/2] 34456: lopts should be initialized as an array + +otherwise an empty element remains in lopts, which causes +a trouble when _arguments -- '*:' is called. + +Upstream-commit: 2810317ae2f2f96d06add76c17510a90f2ea3f62 +Signed-off-by: Kamil Dudka +--- + Completion/Base/Utility/_arguments | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Completion/Base/Utility/_arguments b/Completion/Base/Utility/_arguments +index d70c442..1f35e8d 100644 +--- a/Completion/Base/Utility/_arguments ++++ b/Completion/Base/Utility/_arguments +@@ -26,7 +26,7 @@ if (( long )); then + + if (( ! ${(P)+name} )); then + local iopts sopts pattern tmpo dir cur cache +- typeset -U lopts ++ typeset -Ua lopts + + cache=() + +-- +2.5.5 + + +From 08801bde8876d8a671165b1856ad99aec5dd6564 Mon Sep 17 00:00:00 2001 +From: Jun-ichi Takimoto +Date: Wed, 30 Sep 2015 23:56:14 +0900 +Subject: [PATCH 2/2] 36697: handle options of _arguments correctly + +Upstream-commit: 756526eef3e064c3ffb023ae5e5e6df42e6e9162 +Signed-off-by: Kamil Dudka +--- + Completion/Base/Utility/_arguments | 45 +++++++++++++++++++------------------- + 1 file changed, 23 insertions(+), 22 deletions(-) + +diff --git a/Completion/Base/Utility/_arguments b/Completion/Base/Utility/_arguments +index 1f35e8d..87fb20e 100644 +--- a/Completion/Base/Utility/_arguments ++++ b/Completion/Base/Utility/_arguments +@@ -8,15 +8,33 @@ local oldcontext="$curcontext" hasopts rawret optarg singopt alwopt + local setnormarg start rest + local -a match mbegin mend + ++subopts=() ++singopt=() ++while [[ "$1" = -([AMO]*|[CRSWnsw]) ]]; do ++ case "$1" in ++ -C) usecc=yes; shift ;; ++ -O) subopts=( "${(@P)2}" ); shift 2 ;; ++ -O*) subopts=( "${(@P)${1[3,-1]}}" ); shift ;; ++ -R) rawret=yes; shift;; ++ -n) setnormarg=yes; NORMARG=-1; shift;; ++ -w) optarg=yes; shift;; ++ -W) alwopt=arg; shift;; ++ -[Ss]) singopt+=( $1 ); shift;; ++ -[AM]) singopt+=( $1 $2 ); shift 2 ;; ++ -[AM]*) singopt+=( $1 ); shift ;; ++ esac ++done ++ ++[[ $1 = ':' ]] && shift ++singopt+=( ':' ) # always end with ':' to indicate the end of options ++ ++[[ "$PREFIX" = [-+] ]] && alwopt=arg ++ + long=$argv[(I)--] + if (( long )); then + local name tmp tmpargv + +- if [[ long -eq 1 ]]; then +- tmpargv=() +- else +- tmpargv=( "${(@)argv[1,long-1]}" ) +- fi ++ tmpargv=( "${(@)argv[1,long-1]}" ) # optspec's before --, if any + + name=${~words[1]} + [[ "$name" = [^/]*/* ]] && name="$PWD/$name" +@@ -290,23 +308,6 @@ if (( long )); then + set -- "$tmpargv[@]" "${(@P)name}" + fi + +-subopts=() +-singopt=() +-while [[ "$1" = -(O*|[CRWnsw]) ]]; do +- case "$1" in +- -C) usecc=yes; shift ;; +- -O) subopts=( "${(@P)2}" ); shift 2 ;; +- -O*) subopts=( "${(@P)${1[3,-1]}}" ); shift ;; +- -R) rawret=yes; shift;; +- -n) setnormarg=yes; NORMARG=-1; shift;; +- -w) optarg=yes; shift;; +- -s) singopt=(-s); shift;; +- -W) alwopt=arg; shift;; +- esac +-done +- +-[[ "$PREFIX" = [-+] ]] && alwopt=arg +- + zstyle -s ":completion:${curcontext}:options" auto-description autod + + if (( $# )) && comparguments -i "$autod" "$singopt[@]" "$@"; then +-- +2.5.5 + diff --git a/SOURCES/zsh-5.0.2-comp-cache.patch b/SOURCES/zsh-5.0.2-comp-cache.patch new file mode 100644 index 0000000..c8f9c39 --- /dev/null +++ b/SOURCES/zsh-5.0.2-comp-cache.patch @@ -0,0 +1,56 @@ +From 075bb94e05771e5f7132c35811c0d19d03ceda16 Mon Sep 17 00:00:00 2001 +From: Axel Beckert +Date: Wed, 18 Sep 2013 23:50:04 +0200 +Subject: [PATCH 1/2] 31735: fix off-by-one in completion utility cache code. + Was causing crashes in complex completions, particularly with taskwarrior + +Upstream-commit: 844e569b632fc032576edc039f793be47fde724e +Signed-off-by: Kamil Dudka +--- + Src/Zle/computil.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c +index cd508d0..2c323ee 100644 +--- a/Src/Zle/computil.c ++++ b/Src/Zle/computil.c +@@ -2992,7 +2992,7 @@ get_cvdef(char *nam, char **args) + return *p; + } else if (!min || !*p || (*p)->lastt < (*min)->lastt) + min = p; +- if (i) ++ if (i > 0) + min = p; + if ((new = parse_cvdef(nam, args))) { + freecvdef(*min); +-- +2.5.5 + + +From b5f4eda96e0543693334ccc6ada2f87ab60cd7c7 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Thu, 19 Sep 2013 07:55:53 -0700 +Subject: [PATCH 2/2] 31737: same loop counter fix in get_cadef as get_cvdef. + +Upstream-commit: 61deff76f22310ce9e10dd2174b8cf8e48c678ee +Signed-off-by: Kamil Dudka +--- + Src/Zle/computil.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c +index 2c323ee..f8983c3 100644 +--- a/Src/Zle/computil.c ++++ b/Src/Zle/computil.c +@@ -1608,7 +1608,7 @@ get_cadef(char *nam, char **args) + return *p; + } else if (!min || !*p || (*p)->lastt < (*min)->lastt) + min = p; +- if (i) ++ if (i > 0) + min = p; + if ((new = parse_cadef(nam, args))) { + freecadef(*min); +-- +2.5.5 + diff --git a/SOURCES/zsh-5.0.2-disable-alloca.patch b/SOURCES/zsh-5.0.2-disable-alloca.patch new file mode 100644 index 0000000..f369527 --- /dev/null +++ b/SOURCES/zsh-5.0.2-disable-alloca.patch @@ -0,0 +1,53 @@ +From d2f33b7005540aef5ce79479d598cdcc10d397f9 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Thu, 24 Jul 2014 08:45:16 -0700 +Subject: [PATCH] 32853: redefine VARARR() to use heap rather than stack + allocation + +Upstream-commit: 2f0efe9f592255d0d83c0929423cc397bb1ebfa4 +Signed-off-by: Kamil Dudka +--- + Src/mem.c | 5 ++++- + Src/zsh_system.h | 5 +++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/Src/mem.c b/Src/mem.c +index 5275c6c..c4745a5 100644 +--- a/Src/mem.c ++++ b/Src/mem.c +@@ -856,7 +856,10 @@ zrealloc(void *ptr, size_t size) + ptr = NULL; + } else { + /* If ptr is NULL, then behave like malloc */ +- ptr = malloc(size); ++ if (!(ptr = (void *) malloc(size))) { ++ zerr("fatal error: out of memory"); ++ exit(1); ++ } + } + unqueue_signals(); + +diff --git a/Src/zsh_system.h b/Src/zsh_system.h +index f385330..427c25f 100644 +--- a/Src/zsh_system.h ++++ b/Src/zsh_system.h +@@ -286,11 +286,16 @@ struct timezone { + # include + #endif + ++#ifdef USE_STACK_ALLOCATION ++#warning compiling with USE_STACK_ALLOCATION + #ifdef HAVE_VARIABLE_LENGTH_ARRAYS + # define VARARR(X,Y,Z) X (Y)[Z] + #else + # define VARARR(X,Y,Z) X *(Y) = (X *) alloca(sizeof(X) * (Z)) + #endif ++#else ++# define VARARR(X,Y,Z) X *(Y) = (X *) zhalloc(sizeof(X) * (Z)) ++#endif + + /* we should handle unlimited sizes from pathconf(_PC_PATH_MAX) */ + /* but this is too much trouble */ +-- +2.1.0 + diff --git a/SOURCES/zsh-5.0.2-emul-man-page.patch b/SOURCES/zsh-5.0.2-emul-man-page.patch new file mode 100644 index 0000000..bc333a7 --- /dev/null +++ b/SOURCES/zsh-5.0.2-emul-man-page.patch @@ -0,0 +1,55 @@ +From d379782a50437c9a49d48adca163621f9f67aed1 Mon Sep 17 00:00:00 2001 +From: Jan Chaloupka +Date: Mon, 2 Jun 2014 17:06:32 +0200 +Subject: [PATCH] 32666: shell emulation doc addition + +Upstream-commit: d6698d89a6ff9e644ee608c1d08ff21911f9fb27 +Signed-off-by: Kamil Dudka +--- + Doc/Zsh/compat.yo | 2 +- + Doc/zsh.1 | 2 +- + Doc/zshall.1 | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Doc/Zsh/compat.yo b/Doc/Zsh/compat.yo +index bf97fe2..f1be15f 100644 +--- a/Doc/Zsh/compat.yo ++++ b/Doc/Zsh/compat.yo +@@ -6,7 +6,7 @@ cindex(ksh compatibility) + Zsh tries to emulate bf(sh) or bf(ksh) when it is invoked as + tt(sh) or tt(ksh) respectively; more precisely, it looks at the first + letter of the name by which it was invoked, excluding any initial `tt(r)' +-(assumed to stand for `restricted'), and if that is `tt(s)' or `tt(k)' it ++(assumed to stand for `restricted'), and if that is `tt(b)', `tt(s)' or `tt(k)' it + will emulate bf(sh) or bf(ksh). Furthermore, if invoked as tt(su) (which + happens on certain systems when the shell is executed by the tt(su) + command), the shell will try to find an alternative name from the tt(SHELL) +diff --git a/Doc/zsh.1 b/Doc/zsh.1 +index 3ba42a6..8143d16 100644 +--- a/Doc/zsh.1 ++++ b/Doc/zsh.1 +@@ -255,7 +255,7 @@ can be stacked after the `\fB\-b\fP\&' and will take effect as normal\&. + Zsh tries to emulate \fBsh\fP or \fBksh\fP when it is invoked as + \fBsh\fP or \fBksh\fP respectively; more precisely, it looks at the first + letter of the name by which it was invoked, excluding any initial `\fBr\fP\&' +-(assumed to stand for `restricted\&'), and if that is `\fBs\fP' or `\fBk\fP' it ++(assumed to stand for `restricted\&'), and if that is `\fBb\fP', `\fBs\fP' or `\fBk\fP' it + will emulate \fBsh\fP or \fBksh\fP\&. Furthermore, if invoked as \fBsu\fP (which + happens on certain systems when the shell is executed by the \fBsu\fP + command), the shell will try to find an alternative name from the \fBSHELL\fP +diff --git a/Doc/zshall.1 b/Doc/zshall.1 +index 9642c5c..e23492a 100644 +--- a/Doc/zshall.1 ++++ b/Doc/zshall.1 +@@ -252,7 +252,7 @@ can be stacked after the `\fB\-b\fP' and will take effect as normal\&. + Zsh tries to emulate \fBsh\fP or \fBksh\fP when it is invoked as + \fBsh\fP or \fBksh\fP respectively; more precisely, it looks at the first + letter of the name by which it was invoked, excluding any initial `\fBr\fP' +-(assumed to stand for `restricted'), and if that is `\fBs\fP' or `\fBk\fP' it ++(assumed to stand for `restricted'), and if that is `\fBb\fP', `\fBs\fP' or `\fBk\fP' it + will emulate \fBsh\fP or \fBksh\fP\&. Furthermore, if invoked as \fBsu\fP (which + happens on certain systems when the shell is executed by the \fBsu\fP + command), the shell will try to find an alternative name from the \fBSHELL\fP +-- +2.1.0 + diff --git a/SOURCES/zsh-5.0.2-freeheap-crash.patch b/SOURCES/zsh-5.0.2-freeheap-crash.patch new file mode 100644 index 0000000..f386e1c --- /dev/null +++ b/SOURCES/zsh-5.0.2-freeheap-crash.patch @@ -0,0 +1,104 @@ +From 62536afb90ebb3d7421485c018abd90ba72b919c Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Sat, 18 Jan 2014 21:22:11 -0800 +Subject: [PATCH 1/2] 32285: restart the fheap search in freeheap if the + current fheap arena is about to be discarded; fixes crash + +Upstream-commit: 23f98c3e1d4792e32c616e1f73c383988bd86a9c +Signed-off-by: Kamil Dudka +--- + Src/mem.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/Src/mem.c b/Src/mem.c +index aeca3d9..eb5a091 100644 +--- a/Src/mem.c ++++ b/Src/mem.c +@@ -367,6 +367,15 @@ freeheap(void) + } + #endif + } else { ++ if (h == fheap && h != heaps) { ++ /* ++ * When deallocating the last arena with free space, ++ * loop back through the list to find another one. ++ */ ++ fheap = NULL; ++ hn = heaps; ++ continue; ++ } + #ifdef USE_MMAP + munmap((void *) h, h->size); + #else +-- +2.13.5 + + +From d968fe1061acabd72465a276c2de060f0f8bb668 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Wed, 22 Jan 2014 21:47:29 -0800 +Subject: [PATCH 2/2] unposted: reformulate 32285 to lift the fheap->sp test + out of the loop, improve commentary + +Upstream-commit: 6c603a412751c810ba04bcd463cd3595091ca391 +Signed-off-by: Kamil Dudka +--- + Src/mem.c | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/Src/mem.c b/Src/mem.c +index eb5a091..3a7e31d 100644 +--- a/Src/mem.c ++++ b/Src/mem.c +@@ -319,23 +319,26 @@ freeheap(void) + h_free++; + #endif + +- /* At this point we used to do: +- fheap = NULL; +- * ++ /* + * When pushheap() is called, it sweeps over the entire heaps list of + * arenas and marks every one of them with the amount of free space in + * that arena at that moment. zhalloc() is then allowed to grab bits + * out of any of those arenas that have free space. + * +- * With the above reset of fheap, the loop below sweeps back over the ++ * Whenever fheap is NULL here, the loop below sweeps back over the + * entire heap list again, resetting the free space in every arena to + * the amount stashed by pushheap() and finding the first arena with + * free space to optimize zhalloc()'s next search. When there's a lot + * of stuff already on the heap, this is an enormous amount of work, + * and performance goes to hell. + * +- * However, there doesn't seem to be any reason to reset fheap before +- * beginning this loop. Either it's already correct, or it has never ++ * However, if the arena to which fheap points is unused, we want to ++ * free it, so we have no choice but to do the sweep for a new fheap. ++ */ ++ if (fheap && !fheap->sp) ++ fheap = NULL; /* We used to do this unconditionally */ ++ /* ++ * In other cases, either fheap is already correct, or it has never + * been set and this loop will do it, or it'll be reset from scratch + * on the next popheap(). So all that's needed here is to pick up + * the scan wherever the last pass [or the last popheap()] left off. +@@ -367,15 +370,6 @@ freeheap(void) + } + #endif + } else { +- if (h == fheap && h != heaps) { +- /* +- * When deallocating the last arena with free space, +- * loop back through the list to find another one. +- */ +- fheap = NULL; +- hn = heaps; +- continue; +- } + #ifdef USE_MMAP + munmap((void *) h, h->size); + #else +-- +2.13.5 + diff --git a/SOURCES/zsh-5.0.2-initialize-prompt-buffer.patch b/SOURCES/zsh-5.0.2-initialize-prompt-buffer.patch new file mode 100644 index 0000000..57d5b1a --- /dev/null +++ b/SOURCES/zsh-5.0.2-initialize-prompt-buffer.patch @@ -0,0 +1,26 @@ +From 277235463256a3a59649613ef50e80ec5460feb0 Mon Sep 17 00:00:00 2001 +From: Paulo Andrade +Date: Tue, 3 Jan 2017 12:29:34 +0100 +Subject: [PATCH] 40260: zero new space allocated in prompt buffer + +Upstream-commit: 8d4c98540de9bcdba8565facc91fbc45855d27e2 +Signed-off-by: Kamil Dudka +--- + Src/prompt.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Src/prompt.c b/Src/prompt.c +index 290f227..6eb98f3 100644 +--- a/Src/prompt.c ++++ b/Src/prompt.c +@@ -862,6 +862,7 @@ addbufspc(int need) + if(need & 255) + need = (need | 255) + 1; + bv->buf = realloc(bv->buf, bv->bufspc += need); ++ memset(bv->buf + bv->bufspc - need, 0, need); + bv->bp = bv->buf + bo; + if(bo1 != -1) + bv->bp1 = bv->buf + bo1; +-- +2.7.4 + diff --git a/SOURCES/zsh-5.0.2-ksh-syntax-check.patch b/SOURCES/zsh-5.0.2-ksh-syntax-check.patch new file mode 100644 index 0000000..a3d4fe1 --- /dev/null +++ b/SOURCES/zsh-5.0.2-ksh-syntax-check.patch @@ -0,0 +1,151 @@ +From e4761e2cc86db577127ed7f6884bd42363883a16 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Tue, 22 Jan 2013 16:28:58 +0000 +Subject: [PATCH 1/3] 30993: fix parameter modifier crash with :wq on empty + string + +Upstream-commit: 44757a653cb547ae7b556e8c92629d296d3c1f12 +Signed-off-by: Kamil Dudka +--- + Src/subst.c | 10 +++++++++- + Test/D04parameter.ztst | 7 +++++++ + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/Src/subst.c b/Src/subst.c +index 974a845..a4df256 100644 +--- a/Src/subst.c ++++ b/Src/subst.c +@@ -3707,6 +3707,11 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) + char *y; + + x = val; ++ if (!x) { ++ /* Shouldn't have got here with a NULL string. */ ++ DPUTS(1, "value is NULL in paramsubst"); ++ return NULL; ++ } + if (prenum || postnum) + x = dopadding(x, prenum, postnum, preone, postone, + premul, postmul +@@ -4021,7 +4026,10 @@ modify(char **str, char **ptr) + all = tmp; + t = e; + } +- *str = all; ++ if (!all) ++ *str = dupstring(""); ++ else ++ *str = all; + + } else { + switch (c) { +diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst +index 01f8412..bea9459 100644 +--- a/Test/D04parameter.ztst ++++ b/Test/D04parameter.ztst +@@ -1544,3 +1544,10 @@ + 0:Regression test for shwordsplit with null or unset IFS and quoted array + >abc + >a b c ++ ++ foo= ++ print ${foo:wq} ++ print ${:wq} ++0:Empty parameter shouldn't cause modifiers to crash the shell ++> ++> +-- +2.5.2 + + +From 3427fe59c2d76ddbf4b23908c6ae5272734c7c8b Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Wed, 20 May 2015 10:14:04 -0700 +Subject: [PATCH 2/3] 35231: make mkevnstr() safe for NULL value + +Upstream-commit: af957f2ed6287f66953742fbca69188cecb98fbf +Signed-off-by: Kamil Dudka +--- + Src/params.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/Src/params.c b/Src/params.c +index 61edc5d..d0ce0a9 100644 +--- a/Src/params.c ++++ b/Src/params.c +@@ -4488,17 +4488,21 @@ addenv(Param pm, char *value) + static char * + mkenvstr(char *name, char *value, int flags) + { +- char *str, *s; +- int len_name, len_value; ++ char *str, *s = value; ++ int len_name, len_value = 0; + + len_name = strlen(name); +- for (len_value = 0, s = value; +- *s && (*s++ != Meta || *s++ != 32); len_value++); ++ if (s) ++ while (*s && (*s++ != Meta || *s++ != 32)) ++ len_value++; + s = str = (char *) zalloc(len_name + len_value + 2); + strcpy(s, name); + s += len_name; + *s = '='; +- copyenvstr(s, value, flags); ++ if (value) ++ copyenvstr(s, value, flags); ++ else ++ *++s = '\0'; + return str; + } + +-- +2.4.1 + + +From e92e9cbe55c7611e6eef59bf671de9bc95225d56 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Tue, 6 Oct 2015 09:28:07 +0100 +Subject: [PATCH 3/3] 36780: Fix crash in ksh mode with -n and $HOME. + +If home variable is NULL ensure HOME is unset. + +Upstream-commit: 83a175795a444e8169fcb592a110d4d15a09b907 +Signed-off-by: Kamil Dudka +--- + Src/params.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/Src/params.c b/Src/params.c +index e9e6545..babf6f2 100644 +--- a/Src/params.c ++++ b/Src/params.c +@@ -755,17 +755,18 @@ createparamtable(void) + #endif + opts[ALLEXPORT] = oae; + ++ /* ++ * For native emulation we always set the variable home ++ * (see setupvals()). ++ */ ++ pm = (Param) paramtab->getnode(paramtab, "HOME"); + if (EMULATION(EMULATE_ZSH)) + { +- /* +- * For native emulation we always set the variable home +- * (see setupvals()). +- */ +- pm = (Param) paramtab->getnode(paramtab, "HOME"); + pm->node.flags &= ~PM_UNSET; + if (!(pm->node.flags & PM_EXPORTED)) + addenv(pm, home); +- } ++ } else if (!home) ++ pm->node.flags |= PM_UNSET; + pm = (Param) paramtab->getnode(paramtab, "LOGNAME"); + if (!(pm->node.flags & PM_EXPORTED)) + addenv(pm, pm->u.str); +-- +2.5.2 + diff --git a/SOURCES/zsh-5.0.2-malloc-signal.patch b/SOURCES/zsh-5.0.2-malloc-signal.patch new file mode 100644 index 0000000..ca482ee --- /dev/null +++ b/SOURCES/zsh-5.0.2-malloc-signal.patch @@ -0,0 +1,70 @@ +From 160c02c8071b8948231a229ec6247cf0792c389a Mon Sep 17 00:00:00 2001 +From: Filip Krska +Date: Tue, 20 Oct 2015 18:25:38 +0200 +Subject: [PATCH 1/2] lex.c: fix malloc() signal leak in lexsave() + +The bug appears not to affect upstream master, where the function + +lexsave(void) + ... 1x malloc, 1x zalloc + +was rewritten to + +lex_context_save(struct lex_stack *ls, int toplevel) + ... no *alloc at all + +Recheck of any possible malloc() signal leaks in current RHEL 6 zsh code needed. +--- + Src/lex.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Src/lex.c b/Src/lex.c +index 33f6430..0c7f539 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -271,7 +271,7 @@ lexsave_partial(int parts) + { + struct lexstack *ls; + +- ls = (struct lexstack *)malloc(sizeof(struct lexstack)); ++ ls = (struct lexstack *)zalloc(sizeof(struct lexstack)); + + if (parts & ZCONTEXT_LEX) { + ls->incmdpos = incmdpos; +-- +2.5.2 + + +From 861e4cd5f8ba169f5f63ca1efffdc8ebac5a3d61 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 20 Oct 2015 18:27:15 +0200 +Subject: [PATCH 2/2] mem.c: queue signals while calling malloc() in realloc() + +Bug: https://bugzilla.redhat.com/1267903#c6 +--- + Src/mem.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/Src/mem.c b/Src/mem.c +index 9492a60..75622c6 100644 +--- a/Src/mem.c ++++ b/Src/mem.c +@@ -1513,8 +1513,13 @@ realloc(MALLOC_RET_T p, MALLOC_ARG_T size) + int i, l = 0; + + /* some system..., see above */ +- if (!p && size) +- return (MALLOC_RET_T) malloc(size); ++ if (!p && size) { ++ queue_signals(); ++ r = malloc(size); ++ unqueue_signals(); ++ return (MALLOC_RET_T) r; ++ } ++ + /* and some systems even do this... */ + if (!p || !size) + return (MALLOC_RET_T) p; +-- +2.5.2 + diff --git a/SOURCES/zsh-5.0.2-noexec-subscript.patch b/SOURCES/zsh-5.0.2-noexec-subscript.patch new file mode 100644 index 0000000..4f2ea6b --- /dev/null +++ b/SOURCES/zsh-5.0.2-noexec-subscript.patch @@ -0,0 +1,57 @@ +From 2f5bc6482fdddac91a7f06602d65584ebeb41a6c Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Wed, 15 Jul 2015 17:51:41 -0700 +Subject: [PATCH] 35799: with NO_EXEC, parse parameter subscript expressions + +Upstream-commit: a0862f6381979b165e864e9c5b97d12432d35d48 +Signed-off-by: Kamil Dudka +--- + Src/params.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/Src/params.c b/Src/params.c +index f7551b2..be8394b 100644 +--- a/Src/params.c ++++ b/Src/params.c +@@ -1070,14 +1070,12 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w, + Patprog pprog = NULL; + + /* +- * If in NO_EXEC mode, the parameters won't be set up +- * properly, so there's no point even doing any sanity checking. +- * Just return 0 now. ++ * If in NO_EXEC mode, the parameters won't be set up properly, ++ * so just pretend everything is a hash for subscript parsing + */ +- if (unset(EXECOPT)) +- return 0; + +- ishash = (v->pm && PM_TYPE(v->pm->node.flags) == PM_HASHED); ++ ishash = (unset(EXECOPT) || ++ (v->pm && PM_TYPE(v->pm->node.flags) == PM_HASHED)); + if (prevcharlen) + *prevcharlen = 1; + if (nextcharlen) +@@ -1232,8 +1230,18 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w, + } + if (!c) + return 0; +- s = dupstrpfx(s, t - s); + *str = tt = t; ++ ++ /* ++ * If in NO_EXEC mode, the parameters won't be set up properly, ++ * so there's no additional sanity checking we can do. ++ * Just return 0 now. ++ */ ++ if (unset(EXECOPT)) ++ return 0; ++ ++ s = dupstrpfx(s, t - s); ++ + /* If we're NOT reverse subscripting, strip the inull()s so brackets * + * are not backslashed after parsestr(). Otherwise leave them alone * + * so that the brackets will be escaped when we patcompile() or when * +-- +2.7.4 + diff --git a/SOURCES/zsh-5.0.2-noexec.patch b/SOURCES/zsh-5.0.2-noexec.patch new file mode 100644 index 0000000..0615948 --- /dev/null +++ b/SOURCES/zsh-5.0.2-noexec.patch @@ -0,0 +1,59 @@ +From 7e4833e2341463c660655aa76e6a90f455021726 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Fri, 18 Oct 2013 23:42:07 +0100 +Subject: [PATCH 1/2] 31846: fix NOEXEC option in execsimple() optimisation + +Upstream-commit: 8879c46a4897a0e347455334fc6b6732c203a220 +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Src/exec.c b/Src/exec.c +index 1ecbc39..51e8d09 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -1079,6 +1079,9 @@ execsimple(Estate state) + if (errflag) + return (lastval = 1); + ++ if (!isset(EXECOPT)) ++ return lastval = 0; ++ + /* In evaluated traps, don't modify the line number. */ + if (!IN_EVAL_TRAP() && !ineval && code) + lineno = code - 1; +-- +2.1.0 + + +From 15500cd645958d2de544e851dabf7010199f7cf9 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Sat, 19 Oct 2013 23:08:24 +0100 +Subject: [PATCH 2/2] Use VERBOSE option in execstring() + +Upstream-commit: 9a044f1a6ad4ecfdfeff2f89e1685a1d622cb029 +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/Src/exec.c b/Src/exec.c +index 51e8d09..08e4b7d 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -1019,6 +1019,11 @@ execstring(char *s, int dont_change_job, int exiting, char *context) + Eprog prog; + + pushheap(); ++ if (isset(VERBOSE)) { ++ zputs(s, stderr); ++ fputc('\n', stderr); ++ fflush(stderr); ++ } + if ((prog = parse_string(s, 0))) + execode(prog, dont_change_job, exiting, context); + popheap(); +-- +2.1.0 + diff --git a/SOURCES/zsh-5.0.2-oom-fatal-error.patch b/SOURCES/zsh-5.0.2-oom-fatal-error.patch new file mode 100644 index 0000000..0f3cc5e --- /dev/null +++ b/SOURCES/zsh-5.0.2-oom-fatal-error.patch @@ -0,0 +1,91 @@ +From 3925a4fbed618504f49e2a8a5551cc5800d9353b Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Mon, 25 Jan 2016 15:43:06 +0000 +Subject: [PATCH 1/2] 37776: Set errflag before calls to zwarning(). + +This avoids an attempt to call zerr() or zerrnam() recusrively. + +Upstream-commit: be32864e6ff6a872d63314b4baedbfbf2eed54bd +Signed-off-by: Kamil Dudka +--- + Src/utils.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Src/utils.c b/Src/utils.c +index 4640970..9ce3ee9 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -156,12 +156,12 @@ VA_DCL + errflag = 1; + return; + } ++ errflag = 1; + + VA_START(ap, fmt); + VA_GET_ARG(ap, fmt, const char *); + zwarning(NULL, fmt, ap); + va_end(ap); +- errflag = 1; + } + + /**/ +@@ -175,13 +175,13 @@ VA_DCL + + if (errflag || noerrs) + return; ++ errflag = 1; + + VA_START(ap, fmt); + VA_GET_ARG(ap, cmd, const char *); + VA_GET_ARG(ap, fmt, const char *); + zwarning(cmd, fmt, ap); + va_end(ap); +- errflag = 1; + } + + /**/ +-- +2.5.0 + + +From 7a028030cfdcd85b61950e4a530442ebff359f4c Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Mon, 25 Jan 2016 18:01:07 +0100 +Subject: [PATCH 2/2] 37780: Care printing error if nothing to print. + +Upstream-commit: 69c86cd2c3f1533d9b4b345f98d3922418bc6dac +Signed-off-by: Kamil Dudka +--- + Src/utils.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/Src/utils.c b/Src/utils.c +index 9ce3ee9..bb3c241 100644 +--- a/Src/utils.c ++++ b/Src/utils.c +@@ -120,9 +120,11 @@ zwarning(const char *cmd, const char *fmt, va_list ap) + if (isatty(2)) + zleentry(ZLE_CMD_TRASH); + ++ char *prefix = scriptname ? scriptname : (argzero ? argzero : ""); ++ + if (cmd) { + if (unset(SHINSTDIN) || locallevel) { +- nicezputs(scriptname ? scriptname : argzero, stderr); ++ nicezputs(prefix, stderr); + fputc((unsigned char)':', stderr); + } + nicezputs(cmd, stderr); +@@ -134,8 +136,7 @@ zwarning(const char *cmd, const char *fmt, va_list ap) + * program/script is running. It's also set in shell functions, + * so test locallevel, too. + */ +- nicezputs((isset(SHINSTDIN) && !locallevel) ? "zsh" : +- scriptname ? scriptname : argzero, stderr); ++ nicezputs((isset(SHINSTDIN) && !locallevel) ? "zsh" : prefix, stderr); + fputc((unsigned char)':', stderr); + } + +-- +2.5.0 + diff --git a/SOURCES/zsh-5.0.2-sigchld-deadlock.patch b/SOURCES/zsh-5.0.2-sigchld-deadlock.patch new file mode 100644 index 0000000..9c2ffbd --- /dev/null +++ b/SOURCES/zsh-5.0.2-sigchld-deadlock.patch @@ -0,0 +1,41 @@ +From 656bc77fe9eb1c8c3eabcbcda131c3cd4dbb3acd Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Mon, 10 Aug 2015 12:54:05 -0700 +Subject: [PATCH] 36079: do not allow update_job() and its helpers to run the + signal queue while we are processing a job exit. + +Upstream-commit: 93ca77f8f73bc58041bcbf8e4319b056504806e5 +Signed-off-by: Kamil Dudka +--- + Src/signals.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/Src/signals.c b/Src/signals.c +index 6b8b773..c539063 100644 +--- a/Src/signals.c ++++ b/Src/signals.c +@@ -485,6 +485,12 @@ wait_for_processes(void) + break; + } + ++ /* This is necessary to be sure queueing_enabled > 0 when ++ * we enter printjob() from update_job(), so that we don't ++ * decrement to zero in should_report_time() and improperly ++ * run other handlers in the middle of processing this one */ ++ queue_signals(); ++ + /* + * Find the process and job containing this pid and + * update it. +@@ -528,6 +534,8 @@ wait_for_processes(void) + if (jn && !(jn->stat & (STAT_CURSH|STAT_BUILTIN)) && + jn - jobtab != thisjob) + addbgstatus(pid, (int)lastval2); ++ ++ unqueue_signals(); + } + } + +-- +2.5.0 + diff --git a/SOURCES/zsh-5.0.2-signal-handling.patch b/SOURCES/zsh-5.0.2-signal-handling.patch new file mode 100644 index 0000000..b605a17 --- /dev/null +++ b/SOURCES/zsh-5.0.2-signal-handling.patch @@ -0,0 +1,870 @@ +From bbeb06a37ba58f6905803d32a26fb00953459301 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Thu, 20 Mar 2014 07:56:30 -0700 +Subject: [PATCH 1/8] 32500: handle interrupts during pattern matching + +Upstream-commit: 8672d19f0c0f25569e233bbd466b6c39f60c7a55 +Signed-off-by: Kamil Dudka +--- + Src/pattern.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/Src/pattern.c b/Src/pattern.c +index b74a08a..b93b064 100644 +--- a/Src/pattern.c ++++ b/Src/pattern.c +@@ -2128,6 +2128,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, + + return ret; + } else { ++ int q = queue_signal_level(); ++ + /* + * Test for a `must match' string, unless we're scanning for a match + * in which case we don't need to do this each time. +@@ -2175,6 +2177,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, + + patinput = patinstart; + ++ dont_queue_signals(); ++ + if (patmatch((Upat)progstr)) { + /* + * we were lazy and didn't save the globflags if an exclusion +@@ -2311,6 +2315,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen, + } else + ret = 0; + ++ restore_queue_signals(q); ++ + if (tryalloced) + zfree(tryalloced, unmetalen + unmetalenp); + +@@ -2390,7 +2396,7 @@ patmatch(Upat prog) + zrange_t from, to, comp; + patint_t nextch; + +- while (scan) { ++ while (scan && !errflag) { + next = PATNEXT(scan); + + if (!globdots && P_NOTDOT(scan) && patinput == patinstart && +-- +2.5.0 + + +From c3eeba82d560005d830862dace8d771e712693e6 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Sun, 9 Aug 2015 00:50:36 -0700 +Subject: [PATCH 2/8] 36022 fix bug that some loop constructs could not be + interrupted, revise signal queueing + +There are two underlying ideas here: (1) Keeping signals queued around +anything that's doing memory management (including push/pop of the heap) +has become crucial. (2) Anytime the shell is going to run a command, be +it buitin or external, it must be both safe and necessary to process any +queued signals, so that the apparent order of signal arrival and command +execution is preserved. + +Upstream-commit: 9958684574bf8b0ecec6983cca57f3fa3dd7cd63 +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 43 ++++++++++++++++++++++++++++++++++++++----- + Src/init.c | 5 +++++ + Src/input.c | 9 +++++++++ + Src/loop.c | 36 ++++++++++++++++++++++++++++++++++-- + Src/parse.c | 8 ++++++++ + Src/signals.c | 8 ++++++-- + 6 files changed, 100 insertions(+), 9 deletions(-) + +diff --git a/Src/exec.c b/Src/exec.c +index 7817a64..cff1a24 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -1108,8 +1108,12 @@ execsimple(Estate state) + fflush(xtrerr); + } + lv = (errflag ? errflag : cmdoutval); +- } else ++ } else { ++ int q = queue_signal_level(); ++ dont_queue_signals(); + lv = (execfuncs[code - WC_CURSH])(state, 0); ++ restore_queue_signals(q); ++ } + + thisjob = otj; + +@@ -1141,6 +1145,8 @@ execlist(Estate state, int dont_change_job, int exiting) + */ + int oldnoerrexit = noerrexit; + ++ queue_signals(); ++ + cj = thisjob; + old_pline_level = pline_level; + old_list_pipe = list_pipe; +@@ -1391,6 +1397,8 @@ sublist_done: + /* Make sure this doesn't get executed again. */ + sigtrapped[SIGEXIT] = 0; + } ++ ++ unqueue_signals(); + } + + /* Execute a pipeline. * +@@ -1419,6 +1427,14 @@ execpline(Estate state, wordcode slcode, int how, int last1) + else if (slflags & WC_SUBLIST_NOT) + last1 = 0; + ++ /* If trap handlers are allowed to run here, they may start another ++ * external job in the middle of us starting this one, which can ++ * result in jobs being reaped before their job table entries have ++ * been initialized, which in turn leads to waiting forever for ++ * jobs that no longer exist. So don't do that. ++ */ ++ queue_signals(); ++ + pj = thisjob; + ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0; + child_block(); +@@ -1431,6 +1447,7 @@ execpline(Estate state, wordcode slcode, int how, int last1) + */ + if ((thisjob = newjob = initjob()) == -1) { + child_unblock(); ++ unqueue_signals(); + return 1; + } + if (how & Z_TIMED) +@@ -1486,6 +1503,7 @@ execpline(Estate state, wordcode slcode, int how, int last1) + else + spawnjob(); + child_unblock(); ++ unqueue_signals(); + /* Executing background code resets shell status */ + return lastval = 0; + } else { +@@ -1543,15 +1561,18 @@ execpline(Estate state, wordcode slcode, int how, int last1) + } + if (!(jn->stat & STAT_LOCKED)) { + updated = hasprocs(thisjob); +- waitjobs(); ++ waitjobs(); /* deals with signal queue */ + child_block(); + } else + updated = 0; + if (!updated && + list_pipe_job && hasprocs(list_pipe_job) && + !(jobtab[list_pipe_job].stat & STAT_STOPPED)) { ++ int q = queue_signal_level(); + child_unblock(); ++ dont_queue_signals(); + child_block(); ++ restore_queue_signals(q); + } + if (list_pipe_child && + jn->stat & STAT_DONE && +@@ -1631,6 +1652,7 @@ execpline(Estate state, wordcode slcode, int how, int last1) + break; + } + child_unblock(); ++ unqueue_signals(); + + if (list_pipe && (lastval & 0200) && pj >= 0 && + (!(jn->stat & STAT_INUSE) || (jn->stat & STAT_DONE))) { +@@ -3192,6 +3214,7 @@ execcmd(Estate state, int input, int output, int how, int last1) + fflush(xtrerr); + } + } else if (isset(EXECOPT) && !errflag) { ++ int q = queue_signal_level(); + /* + * We delay the entersubsh() to here when we are exec'ing + * the current shell (including a fake exec to run a builtin then +@@ -3210,7 +3233,9 @@ execcmd(Estate state, int input, int output, int how, int last1) + if (type >= WC_CURSH) { + if (last1 == 1) + do_exec = 1; ++ dont_queue_signals(); + lastval = (execfuncs[type - WC_CURSH])(state, do_exec); ++ restore_queue_signals(q); + } else if (is_builtin || is_shfunc) { + LinkList restorelist = 0, removelist = 0; + /* builtin or shell function */ +@@ -3269,7 +3294,9 @@ execcmd(Estate state, int input, int output, int how, int last1) + /* It's a builtin */ + if (forked) + closem(FDT_INTERNAL); ++ dont_queue_signals(); + lastval = execbuiltin(args, (Builtin) hn); ++ restore_queue_signals(q); + #ifdef PATH_DEV_FD + closem(FDT_PROC_SUBST); + #endif +@@ -4415,11 +4442,9 @@ execshfunc(Shfunc shf, LinkList args) + if ((osfc = sfcontext) == SFC_NONE) + sfcontext = SFC_DIRECT; + xtrerr = stderr; +- unqueue_signals(); + + doshfunc(shf, args, 0); + +- queue_signals(); + sfcontext = osfc; + free(cmdstack); + cmdstack = ocs; +@@ -4614,6 +4639,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) + static int funcdepth; + #endif + ++ queue_signals(); /* Lots of memory and global state changes coming */ ++ + pushheap(); + + oargv0 = NULL; +@@ -4814,6 +4841,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) + } + popheap(); + ++ unqueue_signals(); ++ + if (exit_pending) { + if (locallevel > forklevel) { + /* Still functions to return: force them to do so. */ +@@ -4844,6 +4873,8 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) + int cont, ouu; + char *ou; + ++ queue_signals(); ++ + ou = zalloc(ouu = underscoreused); + if (ou) + memcpy(ou, zunderscore, underscoreused); +@@ -4865,12 +4896,14 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) + wrap = wrap->next; + } + startparamscope(); +- execode(prog, 1, 0, "shfunc"); ++ execode(prog, 1, 0, "shfunc"); /* handles signal unqueueing */ + if (ou) { + setunderscore(ou); + zfree(ou, ouu); + } + endparamscope(); ++ ++ unqueue_signals(); + } + + /* Search fpath for an undefined function. Finds the file, and returns the * +diff --git a/Src/init.c b/Src/init.c +index 78f171d..df42349 100644 +--- a/Src/init.c ++++ b/Src/init.c +@@ -105,6 +105,7 @@ loop(int toplevel, int justonce) + Eprog prog; + int err, non_empty = 0; + ++ queue_signals(); + pushheap(); + if (!toplevel) + lexsave(); +@@ -118,7 +119,9 @@ loop(int toplevel, int justonce) + if (interact && toplevel) { + int hstop = stophist; + stophist = 3; ++ unqueue_signals(); + preprompt(); ++ queue_signals(); + if (stophist != 3) + hbegin(1); + else +@@ -197,6 +200,7 @@ loop(int toplevel, int justonce) + if (((!interact || sourcelevel) && errflag) || retflag) + break; + if (isset(SINGLECOMMAND) && toplevel) { ++ dont_queue_signals(); + if (sigtrapped[SIGEXIT]) + dotrap(SIGEXIT); + exit(lastval); +@@ -208,6 +212,7 @@ loop(int toplevel, int justonce) + if (!toplevel) + lexrestore(); + popheap(); ++ unqueue_signals(); + + if (err) + return LOOP_ERROR; +diff --git a/Src/input.c b/Src/input.c +index 5b782dc..dcff78a 100644 +--- a/Src/input.c ++++ b/Src/input.c +@@ -140,14 +140,17 @@ shingetline(void) + int c; + char buf[BUFSIZ]; + char *p; ++ int q = queue_signal_level(); + + p = buf; + for (;;) { ++ dont_queue_signals(); + do { + errno = 0; + c = fgetc(bshin); + } while (c < 0 && errno == EINTR); + if (c < 0 || c == '\n') { ++ restore_queue_signals(q); + if (c == '\n') + *p++ = '\n'; + if (p > buf) { +@@ -163,11 +166,13 @@ shingetline(void) + } else + *p++ = c; + if (p >= buf + BUFSIZ - 1) { ++ queue_signals(); + line = zrealloc(line, ll + (p - buf) + 1); + memcpy(line + ll, buf, p - buf); + ll += p - buf; + line[ll] = '\0'; + p = buf; ++ unqueue_signals(); + } + } + } +@@ -340,6 +345,8 @@ inputline(void) + static void + inputsetline(char *str, int flags) + { ++ queue_signals(); ++ + if ((inbufflags & INP_FREE) && inbuf) { + free(inbuf); + } +@@ -357,6 +364,8 @@ inputsetline(char *str, int flags) + else + inbufct = inbufleft; + inbufflags = flags; ++ ++ unqueue_signals(); + } + + /* +diff --git a/Src/loop.c b/Src/loop.c +index 90a0761..0c07c73 100644 +--- a/Src/loop.c ++++ b/Src/loop.c +@@ -56,6 +56,10 @@ execfor(Estate state, int do_exec) + char *name, *str, *cond = NULL, *advance = NULL; + zlong val = 0; + LinkList vars = NULL, args = NULL; ++ int old_simple_pline = simple_pline; ++ ++ /* See comments in execwhile() */ ++ simple_pline = 1; + + end = state->pc + WC_FOR_SKIP(code); + +@@ -73,6 +77,7 @@ execfor(Estate state, int do_exec) + matheval(str); + if (errflag) { + state->pc = end; ++ simple_pline = old_simple_pline; + return lastval = errflag; + } + cond = ecgetstr(state, EC_NODUP, &ctok); +@@ -85,6 +90,7 @@ execfor(Estate state, int do_exec) + + if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { + state->pc = end; ++ simple_pline = old_simple_pline; + return 0; + } + if (htok) +@@ -190,6 +196,7 @@ execfor(Estate state, int do_exec) + popheap(); + cmdpop(); + loops--; ++ simple_pline = old_simple_pline; + state->pc = end; + return lastval; + } +@@ -206,6 +213,10 @@ execselect(Estate state, UNUSED(int do_exec)) + FILE *inp; + size_t more; + LinkList args; ++ int old_simple_pline = simple_pline; ++ ++ /* See comments in execwhile() */ ++ simple_pline = 1; + + end = state->pc + WC_FOR_SKIP(code); + name = ecgetstr(state, EC_NODUP, NULL); +@@ -221,6 +232,7 @@ execselect(Estate state, UNUSED(int do_exec)) + + if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { + state->pc = end; ++ simple_pline = old_simple_pline; + return 0; + } + if (htok) +@@ -228,6 +240,7 @@ execselect(Estate state, UNUSED(int do_exec)) + } + if (!args || empty(args)) { + state->pc = end; ++ simple_pline = old_simple_pline; + return 1; + } + loops++; +@@ -301,6 +314,7 @@ execselect(Estate state, UNUSED(int do_exec)) + popheap(); + fclose(inp); + loops--; ++ simple_pline = old_simple_pline; + state->pc = end; + return lastval; + } +@@ -368,6 +382,7 @@ execwhile(Estate state, UNUSED(int do_exec)) + Wordcode end, loop; + wordcode code = state->pc[-1]; + int olderrexit, oldval, isuntil = (WC_WHILE_TYPE(code) == WC_WHILE_UNTIL); ++ int old_simple_pline = simple_pline; + + end = state->pc + WC_WHILE_SKIP(code); + olderrexit = noerrexit; +@@ -382,8 +397,6 @@ execwhile(Estate state, UNUSED(int do_exec)) + /* This is an empty loop. Make sure the signal handler sets the + * flags and then just wait for someone hitting ^C. */ + +- int old_simple_pline = simple_pline; +- + simple_pline = 1; + + while (!breaks) +@@ -395,7 +408,14 @@ execwhile(Estate state, UNUSED(int do_exec)) + for (;;) { + state->pc = loop; + noerrexit = 1; ++ ++ /* In case the test condition is a functional no-op, ++ * make sure signal handlers recognize ^C to end the loop. */ ++ simple_pline = 1; ++ + execlist(state, 1, 0); ++ ++ simple_pline = old_simple_pline; + noerrexit = olderrexit; + if (!((lastval == 0) ^ isuntil)) { + if (breaks) +@@ -407,7 +427,14 @@ execwhile(Estate state, UNUSED(int do_exec)) + lastval = oldval; + break; + } ++ ++ /* In case the loop body is also a functional no-op, ++ * make sure signal handlers recognize ^C as above. */ ++ simple_pline = 1; ++ + execlist(state, 1, 0); ++ ++ simple_pline = old_simple_pline; + if (breaks) { + breaks--; + if (breaks || !contflag) +@@ -438,6 +465,10 @@ execrepeat(Estate state, UNUSED(int do_exec)) + wordcode code = state->pc[-1]; + int count, htok = 0; + char *tmp; ++ int old_simple_pline = simple_pline; ++ ++ /* See comments in execwhile() */ ++ simple_pline = 1; + + end = state->pc + WC_REPEAT_SKIP(code); + +@@ -470,6 +501,7 @@ execrepeat(Estate state, UNUSED(int do_exec)) + cmdpop(); + popheap(); + loops--; ++ simple_pline = old_simple_pline; + state->pc = end; + return lastval; + } +diff --git a/Src/parse.c b/Src/parse.c +index b0a7624..04d2707 100644 +--- a/Src/parse.c ++++ b/Src/parse.c +@@ -379,6 +379,8 @@ init_parse_status(void) + void + init_parse(void) + { ++ queue_signals(); ++ + if (ecbuf) zfree(ecbuf, eclen); + + ecbuf = (Wordcode) zalloc((eclen = EC_INIT_SIZE) * sizeof(wordcode)); +@@ -389,6 +391,8 @@ init_parse(void) + ecnfunc = 0; + + init_parse_status(); ++ ++ unqueue_signals(); + } + + /* Build eprog. */ +@@ -409,6 +413,8 @@ bld_eprog(void) + Eprog ret; + int l; + ++ queue_signals(); ++ + ecadd(WCB_END()); + + ret = (Eprog) zhalloc(sizeof(*ret)); +@@ -431,6 +437,8 @@ bld_eprog(void) + zfree(ecbuf, eclen); + ecbuf = NULL; + ++ unqueue_signals(); ++ + return ret; + } + +diff --git a/Src/signals.c b/Src/signals.c +index c539063..73b41b1 100644 +--- a/Src/signals.c ++++ b/Src/signals.c +@@ -1194,6 +1194,8 @@ dotrapargs(int sig, int *sigtr, void *sigfn) + } + } + ++ queue_signals(); /* Any time we manage memory or global state */ ++ + intrap++; + *sigtr |= ZSIG_IGNORED; + +@@ -1231,7 +1233,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) + + sfcontext = SFC_SIGNAL; + incompfunc = 0; +- doshfunc((Shfunc)sigfn, args, 1); ++ doshfunc((Shfunc)sigfn, args, 1); /* manages signal queueing */ + sfcontext = osc; + incompfunc= old_incompfunc; + freelinklist(args, (FreeFunc) NULL); +@@ -1241,7 +1243,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) + trap_state = TRAP_STATE_PRIMED; + trapisfunc = isfunc = 0; + +- execode((Eprog)sigfn, 1, 0, "trap"); ++ execode((Eprog)sigfn, 1, 0, "trap"); /* manages signal queueing */ + } + runhookdef(AFTERTRAPHOOK, NULL); + +@@ -1286,6 +1288,8 @@ dotrapargs(int sig, int *sigtr, void *sigfn) + if (*sigtr != ZSIG_IGNORED) + *sigtr &= ~ZSIG_IGNORED; + intrap--; ++ ++ unqueue_signals(); + } + + /* Standard call to execute a trap for a given signal. */ +-- +2.5.0 + + +From 33905958a1b94e83ca1c32bc6849906da94b91a6 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Sun, 9 Aug 2015 17:37:23 -0700 +Subject: [PATCH 3/8] 36033: a few more queue_signals() to protect global state + changes + +Upstream-commit: df5f825538720a9422859200d58d075d1dd075fc +Signed-off-by: Kamil Dudka +--- + Src/glob.c | 4 ++++ + Src/pattern.c | 8 +++++++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/Src/glob.c b/Src/glob.c +index ca2ffaf..9135fce 100644 +--- a/Src/glob.c ++++ b/Src/glob.c +@@ -213,22 +213,26 @@ static struct globdata curglobdata; + + #define save_globstate(N) \ + do { \ ++ queue_signals(); \ + memcpy(&(N), &curglobdata, sizeof(struct globdata)); \ + (N).gd_pathpos = pathpos; \ + (N).gd_pathbuf = pathbuf; \ + (N).gd_glob_pre = glob_pre; \ + (N).gd_glob_suf = glob_suf; \ + pathbuf = NULL; \ ++ unqueue_signals(); \ + } while (0) + + #define restore_globstate(N) \ + do { \ ++ queue_signals(); \ + zfree(pathbuf, pathbufsz); \ + memcpy(&curglobdata, &(N), sizeof(struct globdata)); \ + pathpos = (N).gd_pathpos; \ + pathbuf = (N).gd_pathbuf; \ + glob_pre = (N).gd_glob_pre; \ + glob_suf = (N).gd_glob_suf; \ ++ unqueue_signals(); \ + } while (0) + + /* pathname component in filename patterns */ +diff --git a/Src/pattern.c b/Src/pattern.c +index b74a08a..52774c0 100644 +--- a/Src/pattern.c ++++ b/Src/pattern.c +@@ -452,6 +452,8 @@ patcompile(char *exp, int inflags, char **endexp) + char *lng, *strp = NULL; + Patprog p; + ++ queue_signals(); ++ + startoff = sizeof(struct patprog); + /* Ensure alignment of start of program string */ + startoff = (startoff + sizeof(union upat) - 1) & ~(sizeof(union upat) - 1); +@@ -521,8 +523,10 @@ patcompile(char *exp, int inflags, char **endexp) + if (!strp || (*strp && *strp != '/')) { + /* No, do normal compilation. */ + strp = NULL; +- if (patcompswitch(0, &flags) == 0) ++ if (patcompswitch(0, &flags) == 0) { ++ unqueue_signals(); + return NULL; ++ } + } else { + /* + * Yes, copy the string, and skip compilation altogether. +@@ -654,6 +658,8 @@ patcompile(char *exp, int inflags, char **endexp) + + if (endexp) + *endexp = patparse; ++ ++ unqueue_signals(); + return p; + } + +-- +2.5.0 + + +From bba38460c88c36fb529ee7494570cb2cfc68641a Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Mon, 10 Aug 2015 16:59:55 +0100 +Subject: [PATCH 4/8] Don't rely on implicit value when saving background + process status + +Upstream-commit: a07f74fadd1180b42258d1fcec5359afe3f9ba00 +Signed-off-by: Kamil Dudka +--- + Src/signals.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/Src/signals.c b/Src/signals.c +index 73b41b1..2e7304f 100644 +--- a/Src/signals.c ++++ b/Src/signals.c +@@ -533,7 +533,14 @@ wait_for_processes(void) + */ + if (jn && !(jn->stat & (STAT_CURSH|STAT_BUILTIN)) && + jn - jobtab != thisjob) +- addbgstatus(pid, (int)lastval2); ++ { ++ int val = (WIFSIGNALED(status) ? ++ 0200 | WTERMSIG(status) : ++ (WIFSTOPPED(status) ? ++ 0200 | WEXITSTATUS(status) : ++ WEXITSTATUS(status))); ++ addbgstatus(pid, val); ++ } + + unqueue_signals(); + } +-- +2.5.0 + + +From 530b59d58273c9f11cd1443c0865f6420eafcbf0 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Tue, 11 Aug 2015 08:44:15 -0700 +Subject: [PATCH 5/8] 36090: keep signals queued for preprompt() + +Upstream-commit: 1af2e6e02d5cb8ca8d11f107b670cddfd10a7e81 +Signed-off-by: Kamil Dudka +--- + Src/init.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/Src/init.c b/Src/init.c +index df42349..ca616d3 100644 +--- a/Src/init.c ++++ b/Src/init.c +@@ -119,9 +119,7 @@ loop(int toplevel, int justonce) + if (interact && toplevel) { + int hstop = stophist; + stophist = 3; +- unqueue_signals(); + preprompt(); +- queue_signals(); + if (stophist != 3) + hbegin(1); + else +-- +2.5.0 + + +From b2994c9f3ef36c3ee3286a08736da1e2c8d65f0b Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Tue, 11 Aug 2015 08:53:12 -0700 +Subject: [PATCH 6/8] 36104: change order of child_block() and + dont_queue_signals() to resolve yet another race condition + +Upstream-commit: 128bf385b1e8256e412d732fa9b80ecd7c5e2c73 +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 2 +- + Src/jobs.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Src/exec.c b/Src/exec.c +index cff1a24..70e2279 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -1570,8 +1570,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) + !(jobtab[list_pipe_job].stat & STAT_STOPPED)) { + int q = queue_signal_level(); + child_unblock(); +- dont_queue_signals(); + child_block(); ++ dont_queue_signals(); + restore_queue_signals(q); + } + if (list_pipe_child && +diff --git a/Src/jobs.c b/Src/jobs.c +index 24b8494..e711a9b 100644 +--- a/Src/jobs.c ++++ b/Src/jobs.c +@@ -1312,9 +1312,9 @@ zwaitjob(int job, int wait_cmd) + int q = queue_signal_level(); + Job jn = jobtab + job; + +- dont_queue_signals(); + child_block(); /* unblocked during signal_suspend() */ + queue_traps(wait_cmd); ++ dont_queue_signals(); + if (jn->procs || jn->auxprocs) { /* if any forks were done */ + jn->stat |= STAT_LOCKED; + if (jn->stat & STAT_CHANGED) +@@ -1350,9 +1350,9 @@ zwaitjob(int job, int wait_cmd) + pipestats[0] = lastval; + numpipestats = 1; + } ++ restore_queue_signals(q); + unqueue_traps(); + child_unblock(); +- restore_queue_signals(q); + + return 0; + } +-- +2.5.0 + + +From 6a0fd02f08972875cc138e783e28515a5c7a7e04 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Sat, 15 Aug 2015 10:15:30 -0700 +Subject: [PATCH 7/8] 36180: avoid infinite job stop/continue loop on "wait + PID" for a background job + +Upstream-commit: 5d019f426af8b2a600ee03e43782c24b357d1401 +Signed-off-by: Kamil Dudka +--- + Src/jobs.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/Src/jobs.c b/Src/jobs.c +index e711a9b..9b94a1f 100644 +--- a/Src/jobs.c ++++ b/Src/jobs.c +@@ -1276,10 +1276,17 @@ waitforpid(pid_t pid, int wait_cmd) + dont_queue_signals(); + child_block(); /* unblocked in signal_suspend() */ + queue_traps(wait_cmd); ++ ++ /* This function should never be called with a pid that is not a ++ * child of the current shell. Consequently, if kill(0, pid) ++ * fails here with ESRCH, the child has already been reaped. In ++ * the loop body, we expect this to happen in signal_suspend() ++ * via zhandler(), after which this test terminates the loop. ++ */ + while (!errflag && (kill(pid, 0) >= 0 || errno != ESRCH)) { + if (first) + first = 0; +- else ++ else if (!wait_cmd) + kill(pid, SIGCONT); + + last_signal = -1; +-- +2.5.0 + + +From d184dd8673c93d35855b4a04613ae09277214df5 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Wed, 2 Sep 2015 19:11:54 -0700 +Subject: [PATCH 8/8] 36393: process queued signals during dotrap() + +Upstream-commit: 9f5dffa1f33ec43c306bdf3c87cebba5fcc95b64 +Signed-off-by: Kamil Dudka +--- + Src/signals.c | 5 +++++ + Test/A05execution.ztst | 9 +++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/Src/signals.c b/Src/signals.c +index 2e7304f..dbc84af 100644 +--- a/Src/signals.c ++++ b/Src/signals.c +@@ -1306,6 +1306,7 @@ void + dotrap(int sig) + { + void *funcprog; ++ int q = queue_signal_level(); + + if (sigtrapped[sig] & ZSIG_FUNC) { + HashNode hn = gettrapnode(sig, 0); +@@ -1328,5 +1329,9 @@ dotrap(int sig) + if ((sigtrapped[sig] & ZSIG_IGNORED) || !funcprog || errflag) + return; + ++ dont_queue_signals(); ++ + dotrapargs(sig, sigtrapped+sig, funcprog); ++ ++ restore_queue_signals(q); + } +diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst +index 77c569c..3b39c75 100644 +--- a/Test/A05execution.ztst ++++ b/Test/A05execution.ztst +@@ -203,3 +203,12 @@ + 1:The status of recently exited background jobs is recorded + >3 + >2 ++ ++# Regression test for workers/36392 ++ print -u $ZTST_fd 'This test takes 3 seconds and hangs the shell when it fails...' ++ callfromchld() { true && { print CHLD } } ++ TRAPCHLD() { callfromchld } ++ sleep 2 & sleep 3; print OK ++0:Background job exit does not affect reaping foreground job ++>CHLD ++>OK +-- +2.5.0 + diff --git a/SOURCES/zsh-5.0.2-signal-safety.patch b/SOURCES/zsh-5.0.2-signal-safety.patch new file mode 100644 index 0000000..d9e2a72 --- /dev/null +++ b/SOURCES/zsh-5.0.2-signal-safety.patch @@ -0,0 +1,406 @@ +From a361a5ac293c9422f953c3d59e53f07e195740d3 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Thu, 6 Nov 2014 10:50:20 -0800 +Subject: [PATCH 1/5] 33614 (based on RedHat BZ-978613): signal safety when + updating global state in execshfunc() + +Upstream-commit: 7abd611a2396bad9d93d18681a2c59cb1ea0e158 +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/Src/exec.c b/Src/exec.c +index 28da5c3..60ee4b8 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -4392,6 +4392,7 @@ execshfunc(Shfunc shf, LinkList args) + fputc('\n', xtrerr); + fflush(xtrerr); + } ++ queue_signals(); + ocs = cmdstack; + ocsp = cmdsp; + cmdstack = (unsigned char *) zalloc(CMDSTACKSZ); +@@ -4399,7 +4400,11 @@ execshfunc(Shfunc shf, LinkList args) + if ((osfc = sfcontext) == SFC_NONE) + sfcontext = SFC_DIRECT; + xtrerr = stderr; ++ unqueue_signals(); ++ + doshfunc(shf, args, 0); ++ ++ queue_signals(); + sfcontext = osfc; + free(cmdstack); + cmdstack = ocs; +@@ -4407,6 +4412,7 @@ execshfunc(Shfunc shf, LinkList args) + + if (!list_pipe) + deletefilelist(last_file_list, 0); ++ unqueue_signals(); + } + + /* Function to execute the special type of command that represents an * +-- +2.4.0 + + +From 236bb914d24e6588d12c3bf66bd06c6416832b8f Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Fri, 20 Feb 2015 18:45:36 -0800 +Subject: [PATCH 2/5] 34590: queue_signals() around more scopes that manipulate + global state + +Upstream-commit: a4ff8e69570cbdb8e7d5bf1d5cc4000ffe63e15e +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 4 +++- + Src/text.c | 15 +++++++++++++++ + 2 files changed, 18 insertions(+), 1 deletion(-) + +diff --git a/Src/exec.c b/Src/exec.c +index 60ee4b8..83b9083 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -2280,6 +2280,7 @@ addvars(Estate state, Wordcode pc, int addflags) + void + setunderscore(char *str) + { ++ queue_signals(); + if (str && *str) { + int l = strlen(str) + 1, nl = (l + 31) & ~31; + +@@ -2297,6 +2298,7 @@ setunderscore(char *str) + *zunderscore = '\0'; + underscoreused = 1; + } ++ unqueue_signals(); + } + + /* These describe the type of expansions that need to be done on the words +@@ -5056,7 +5058,7 @@ execsave(void) + { + struct execstack *es; + +- es = (struct execstack *) malloc(sizeof(struct execstack)); ++ es = (struct execstack *) zalloc(sizeof(struct execstack)); + es->list_pipe_pid = list_pipe_pid; + es->nowait = nowait; + es->pline_level = pline_level; +diff --git a/Src/text.c b/Src/text.c +index f55553e..8f8eb34 100644 +--- a/Src/text.c ++++ b/Src/text.c +@@ -173,6 +173,8 @@ getpermtext(Eprog prog, Wordcode c, int start_indent) + { + struct estate s; + ++ queue_signals(); ++ + if (!c) + c = prog->prog; + +@@ -193,6 +195,9 @@ getpermtext(Eprog prog, Wordcode c, int start_indent) + *tptr = '\0'; + freeeprog(prog); /* mark as unused */ + untokenize(tbuf); ++ ++ unqueue_signals(); ++ + return tbuf; + } + +@@ -206,6 +211,8 @@ getjobtext(Eprog prog, Wordcode c) + + struct estate s; + ++ queue_signals(); ++ + if (!c) + c = prog->prog; + +@@ -224,6 +231,9 @@ getjobtext(Eprog prog, Wordcode c) + *tptr = '\0'; + freeeprog(prog); /* mark as unused */ + untokenize(jbuf); ++ ++ unqueue_signals(); ++ + return jbuf; + } + +@@ -879,6 +889,9 @@ getredirs(LinkList redirs) + ">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<", + "<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">" + }; ++ ++ queue_signals(); ++ + taddchr(' '); + for (n = firstnode(redirs); n; incnode(n)) { + Redir f = (Redir) getdata(n); +@@ -966,4 +979,6 @@ getredirs(LinkList redirs) + } + } + tptr--; ++ ++ unqueue_signals(); + } +-- +2.4.0 + + +From 2e60901b1733929619cccce6cd66898520fd3015 Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Thu, 26 Sep 2013 21:27:27 -0700 +Subject: [PATCH 3/5] 31772: queue_signals() to prevent re-entry into + endparamscope(). + +Upstream-commit: ae92cadc75fbf7e8ec356cf09d3f73db9868424b +Signed-off-by: Kamil Dudka +--- + Src/params.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Src/params.c b/Src/params.c +index 8649178..d6711e4 100644 +--- a/Src/params.c ++++ b/Src/params.c +@@ -4667,10 +4667,12 @@ startparamscope(void) + mod_export void + endparamscope(void) + { ++ queue_signals(); + locallevel--; + /* This pops anything from a higher locallevel */ + saveandpophiststack(0, HFILE_USE_OPTIONS); + scanhashtable(paramtab, 0, 0, 0, scanendscope, 0); ++ unqueue_signals(); + } + + /**/ +-- +2.4.1 + + +From 39dea2e735ae277c9e1238e5d17f3fbd0a08bb6f Mon Sep 17 00:00:00 2001 +From: Bart Schaefer +Date: Thu, 17 Oct 2013 07:35:05 -0700 +Subject: [PATCH 4/5] 31832: make execrestore() more signal-safe. + +Upstream-commit: 978b5bcc8d21fce58369f810ef73bdbc434f33e7 +Signed-off-by: Kamil Dudka +--- + Src/exec.c | 52 ++++++++++++++++++++++++++++------------------------ + 1 file changed, 28 insertions(+), 24 deletions(-) + +diff --git a/Src/exec.c b/Src/exec.c +index 83b9083..2f94052 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -5087,30 +5087,34 @@ execsave(void) + void + execrestore(void) + { +- struct execstack *en; ++ struct execstack *en = exstack; + + DPUTS(!exstack, "BUG: execrestore() without execsave()"); +- list_pipe_pid = exstack->list_pipe_pid; +- nowait = exstack->nowait; +- pline_level = exstack->pline_level; +- list_pipe_child = exstack->list_pipe_child; +- list_pipe_job = exstack->list_pipe_job; +- strcpy(list_pipe_text, exstack->list_pipe_text); +- lastval = exstack->lastval; +- noeval = exstack->noeval; +- badcshglob = exstack->badcshglob; +- cmdoutpid = exstack->cmdoutpid; +- cmdoutval = exstack->cmdoutval; +- use_cmdoutval = exstack->use_cmdoutval; +- trap_return = exstack->trap_return; +- trap_state = exstack->trap_state; +- trapisfunc = exstack->trapisfunc; +- traplocallevel = exstack->traplocallevel; +- noerrs = exstack->noerrs; +- subsh_close = exstack->subsh_close; +- setunderscore(exstack->underscore); +- zsfree(exstack->underscore); +- en = exstack->next; +- free(exstack); +- exstack = en; ++ ++ queue_signals(); ++ exstack = exstack->next; ++ ++ list_pipe_pid = en->list_pipe_pid; ++ nowait = en->nowait; ++ pline_level = en->pline_level; ++ list_pipe_child = en->list_pipe_child; ++ list_pipe_job = en->list_pipe_job; ++ strcpy(list_pipe_text, en->list_pipe_text); ++ lastval = en->lastval; ++ noeval = en->noeval; ++ badcshglob = en->badcshglob; ++ cmdoutpid = en->cmdoutpid; ++ cmdoutval = en->cmdoutval; ++ use_cmdoutval = en->use_cmdoutval; ++ trap_return = en->trap_return; ++ trap_state = en->trap_state; ++ trapisfunc = en->trapisfunc; ++ traplocallevel = en->traplocallevel; ++ noerrs = en->noerrs; ++ subsh_close = en->subsh_close; ++ setunderscore(en->underscore); ++ zsfree(en->underscore); ++ free(en); ++ ++ unqueue_signals(); + } +-- +2.4.1 + + +From 15ac5a43bb483ed753655c7985fbdb056745303b Mon Sep 17 00:00:00 2001 +From: "Barton E. Schaefer" +Date: Tue, 30 Sep 2014 20:34:58 -0700 +Subject: [PATCH 5/5] 33298: make lexrestore() more signal-safe + +Upstream-commit: 8727049674b1f39a8926c02dc74e9f19bbd70289 +Signed-off-by: Kamil Dudka +--- + Src/lex.c | 110 ++++++++++++++++++++++++++++++++------------------------------ + 1 file changed, 57 insertions(+), 53 deletions(-) + +diff --git a/Src/lex.c b/Src/lex.c +index ac87e5e..82bf848 100644 +--- a/Src/lex.c ++++ b/Src/lex.c +@@ -323,66 +323,70 @@ lexsave(void) + mod_export void + lexrestore(void) + { +- struct lexstack *ln; ++ struct lexstack *ln = lstack; + + DPUTS(!lstack, "BUG: lexrestore() without lexsave()"); +- incmdpos = lstack->incmdpos; +- incond = lstack->incond; +- incasepat = lstack->incasepat; +- dbparens = lstack->dbparens; +- isfirstln = lstack->isfirstln; +- isfirstch = lstack->isfirstch; +- histactive = lstack->histactive; +- histdone = lstack->histdone; +- lexflags = lstack->lexflags; +- stophist = lstack->stophist; +- chline = lstack->hline; +- hptr = lstack->hptr; ++ ++ queue_signals(); ++ lstack = lstack->next; ++ ++ if (!lstack) { ++ /* Back to top level: don't need special ZLE value */ ++ DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); ++ zle_chline = NULL; ++ } ++ ++ incmdpos = ln->incmdpos; ++ incond = ln->incond; ++ incasepat = ln->incasepat; ++ dbparens = ln->dbparens; ++ isfirstln = ln->isfirstln; ++ isfirstch = ln->isfirstch; ++ histactive = ln->histactive; ++ histdone = ln->histdone; ++ lexflags = ln->lexflags; ++ stophist = ln->stophist; ++ chline = ln->hline; ++ hptr = ln->hptr; + if (cmdstack) +- free(cmdstack); +- cmdstack = lstack->cstack; +- cmdsp = lstack->csp; +- tok = lstack->tok; +- isnewlin = lstack->isnewlin; +- tokstr = lstack->tokstr; +- zshlextext = lstack->zshlextext; +- bptr = lstack->bptr; +- bsiz = lstack->bsiz; +- len = lstack->len; +- chwords = lstack->chwords; +- chwordlen = lstack->chwordlen; +- chwordpos = lstack->chwordpos; +- hwgetword = lstack->hwgetword; +- lexstop = lstack->lexstop; +- hdocs = lstack->hdocs; +- hgetc = lstack->hgetc; +- hungetc = lstack->hungetc; +- hwaddc = lstack->hwaddc; +- hwbegin = lstack->hwbegin; +- hwend = lstack->hwend; +- addtoline = lstack->addtoline; ++ zfree(cmdstack, CMDSTACKSZ); ++ cmdstack = ln->cstack; ++ cmdsp = ln->csp; ++ tok = ln->tok; ++ isnewlin = ln->isnewlin; ++ tokstr = ln->tokstr; ++ zshlextext = ln->zshlextext; ++ bptr = ln->bptr; ++ bsiz = ln->bsiz; ++ len = ln->len; ++ chwords = ln->chwords; ++ chwordlen = ln->chwordlen; ++ chwordpos = ln->chwordpos; ++ hwgetword = ln->hwgetword; ++ lexstop = ln->lexstop; ++ hdocs = ln->hdocs; ++ hgetc = ln->hgetc; ++ hungetc = ln->hungetc; ++ hwaddc = ln->hwaddc; ++ hwbegin = ln->hwbegin; ++ hwend = ln->hwend; ++ addtoline = ln->addtoline; + if (ecbuf) + zfree(ecbuf, eclen); +- eclen = lstack->eclen; +- ecused = lstack->ecused; +- ecnpats = lstack->ecnpats; +- ecbuf = lstack->ecbuf; +- ecstrs = lstack->ecstrs; +- ecsoffs = lstack->ecsoffs; +- ecssub = lstack->ecssub; +- ecnfunc = lstack->ecnfunc; +- hlinesz = lstack->hlinesz; +- toklineno = lstack->toklineno; ++ eclen = ln->eclen; ++ ecused = ln->ecused; ++ ecnpats = ln->ecnpats; ++ ecbuf = ln->ecbuf; ++ ecstrs = ln->ecstrs; ++ ecsoffs = ln->ecsoffs; ++ ecssub = ln->ecssub; ++ ecnfunc = ln->ecnfunc; ++ hlinesz = ln->hlinesz; ++ toklineno = ln->toklineno; + errflag = 0; ++ free(ln); + +- ln = lstack->next; +- if (!ln) { +- /* Back to top level: don't need special ZLE value */ +- DPUTS(chline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); +- zle_chline = NULL; +- } +- free(lstack); +- lstack = ln; ++ unqueue_signals(); + } + + /**/ +-- +2.4.1 + diff --git a/SOURCES/zsh-5.0.2-wait-for-exited.patch b/SOURCES/zsh-5.0.2-wait-for-exited.patch new file mode 100644 index 0000000..c550b4f --- /dev/null +++ b/SOURCES/zsh-5.0.2-wait-for-exited.patch @@ -0,0 +1,385 @@ +From 223ac53797d33b0473323efc0d5a44d1dceaf746 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Sun, 26 Oct 2014 17:47:42 +0000 +Subject: [PATCH 1/2] 33531 with additions: retain status of exited background + jobs. + +Add linked list of unwaited-for background jobs. +Truncate at value of _SC_CHILD_MAX discarding oldest. +Remove old lastpid_status mechanism for latest exited process only. +Slightly tighten safety of permanently allocated linked lists so +that this doesn't compromise signal handling. + +Upstream-commit: b4f7ccecd93ca9e64c3c3c774fdaefae83d7204a +Signed-off-by: Kamil Dudka +--- + Doc/Zsh/builtins.yo | 16 ++++++ + Doc/Zsh/options.yo | 8 +-- + Doc/zshoptions.1 | 8 +-- + Src/exec.c | 2 - + Src/init.c | 1 - + Src/jobs.c | 138 ++++++++++++++++++++++++++++++++++++++++++++-------- + Src/linklist.c | 4 ++ + Src/signals.c | 14 +++--- + 8 files changed, 152 insertions(+), 39 deletions(-) + +diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo +index 46f40cc..edc335e 100644 +--- a/Doc/Zsh/builtins.yo ++++ b/Doc/Zsh/builtins.yo +@@ -1905,6 +1905,22 @@ then all currently active child processes are waited for. + Each var(job) can be either a job specification or the process ID + of a job in the job table. + The exit status from this command is that of the job waited for. ++ ++It is possible to wait for recent processes (specified by process ID, ++not by job) that were running in the background even if the process has ++exited. Typically the process ID will be recorded by capturing the ++value of the variable tt($!) immediately after the process has been ++started. There is a limit on the number of process IDs remembered by ++the shell; this is given by the value of the system configuration ++parameter tt(CHILD_MAX). When this limit is reached, older process IDs ++are discarded, least recently started processes first. ++ ++Note there is no protection against the process ID wrapping, i.e. if the ++wait is not executed soon enough there is a chance the process waited ++for is the wrong one. A conflict implies both process IDs have been ++generated by the shell, as other processes are not recorded, and that ++the user is potentially interested in both, so this problem is intrinsic ++to process IDs. + ) + findex(whence) + item(tt(whence) [ tt(-vcwfpams) ] var(name) ...)( +diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo +index 068a253..452b258 100644 +--- a/Doc/Zsh/options.yo ++++ b/Doc/Zsh/options.yo +@@ -1401,10 +1401,10 @@ shell is saved for output within a subshell (for example, within a + pipeline). When the option is set, the output of tt(jobs) is empty + until a job is started within the subshell. + +-When the option is set, it becomes possible to use the tt(wait) builtin to +-wait for the last job started in the background (as given by tt($!)) even +-if that job has already exited. This works even if the option is turned +-on temporarily around the use of the tt(wait) builtin. ++In previous versions of the shell, it was necessary to enable ++tt(POSIX_JOBS) in order for the builtin command tt(wait) to return the ++status of background jobs that had already exited. This is no longer ++the case. + ) + enditem() + +diff --git a/Doc/zshoptions.1 b/Doc/zshoptions.1 +index dc8f2f8..17f9e97 100644 +--- a/Doc/zshoptions.1 ++++ b/Doc/zshoptions.1 +@@ -867,10 +867,10 @@ shell is saved for output within a subshell (for example, within a + pipeline)\&. When the option is set, the output of \fBjobs\fP is empty + until a job is started within the subshell\&. + .PP +-When the option is set, it becomes possible to use the \fBwait\fP builtin to +-wait for the last job started in the background (as given by \fB$!\fP) even +-if that job has already exited\&. This works even if the option is turned +-on temporarily around the use of the \fBwait\fP builtin\&. ++In previous versions of the shell, it was necessary to enable ++\fBPOSIX_JOBS\fP in order for the builtin command \fBwait\fP to return the ++status of background jobs that had already exited\&. This is no longer ++the case\&. + .RE + .RE + .PP +diff --git a/Src/exec.c b/Src/exec.c +index d0fadd6..a9c4688 100644 +--- a/Src/exec.c ++++ b/Src/exec.c +@@ -2852,8 +2852,6 @@ execcmd(Estate state, int input, int output, int how, int last1) + #endif + if (how & Z_ASYNC) { + lastpid = (zlong) pid; +- /* indicate it's possible to set status for lastpid */ +- lastpid_status = -2L; + } else if (!jobtab[thisjob].stty_in_env && varspc) { + /* search for STTY=... */ + Wordcode p = varspc; +diff --git a/Src/init.c b/Src/init.c +index c26d887..6666f98 100644 +--- a/Src/init.c ++++ b/Src/init.c +@@ -1018,7 +1018,6 @@ setupvals(void) + bufstack = znewlinklist(); + hsubl = hsubr = NULL; + lastpid = 0; +- lastpid_status = -1L; + + get_usage(); + +diff --git a/Src/jobs.c b/Src/jobs.c +index bd95afb..18bb648 100644 +--- a/Src/jobs.c ++++ b/Src/jobs.c +@@ -104,15 +104,6 @@ int prev_errflag, prev_breaks, errbrk_saved; + /**/ + int numpipestats, pipestats[MAX_PIPESTATS]; + +-/* +- * The status associated with the process lastpid. +- * -1 if not set and no associated lastpid +- * -2 if lastpid is set and status isn't yet +- * else the value returned by wait(). +- */ +-/**/ +-long lastpid_status; +- + /* Diff two timevals for elapsed-time computations */ + + /**/ +@@ -1210,14 +1201,6 @@ addproc(pid_t pid, char *text, int aux, struct timeval *bgtime) + { + Process pn, *pnlist; + +- if (pid == lastpid && lastpid_status != -2L) { +- /* +- * The status for the previous lastpid is invalid. +- * Presumably process numbers have wrapped. +- */ +- lastpid_status = -1L; +- } +- + DPUTS(thisjob == -1, "No valid job in addproc."); + pn = (Process) zshcalloc(sizeof *pn); + pn->pid = pid; +@@ -1826,6 +1809,122 @@ maybeshrinkjobtab(void) + unqueue_signals(); + } + ++/* ++ * Definitions for the background process stuff recorded below. ++ * This would be more efficient as a hash, but ++ * - that's quite heavyweight for something not needed very often ++ * - we need some kind of ordering as POSIX allows us to limit ++ * the size of the list to the value of _SC_CHILD_MAX and clearly ++ * we want to clear the oldest first ++ * - cases with a long list of background jobs where the user doesn't ++ * wait for a large number, and then does wait for one (the only ++ * inefficient case) are rare ++ * - in the context of waiting for an external process, looping ++ * over a list isn't so very inefficient. ++ * Enough excuses already. ++ */ ++ ++/* Data in the link list, a key (process ID) / value (exit status) pair. */ ++struct bgstatus { ++ pid_t pid; ++ int status; ++}; ++typedef struct bgstatus *Bgstatus; ++/* The list of those entries */ ++LinkList bgstatus_list; ++/* Count of entries. Reaches value of _SC_CHILD_MAX and stops. */ ++long bgstatus_count; ++ ++/* ++ * Remove and free a bgstatus entry. ++ */ ++static void rembgstatus(LinkNode node) ++{ ++ zfree(remnode(bgstatus_list, node), sizeof(struct bgstatus)); ++ bgstatus_count--; ++} ++ ++/* ++ * Record the status of a background process that exited so we ++ * can execute the builtin wait for it. ++ * ++ * We can't execute the wait builtin for something that exited in the ++ * foreground as it's not visible to the user, so don't bother recording. ++ */ ++ ++/**/ ++void ++addbgstatus(pid_t pid, int status) ++{ ++ static long child_max; ++ Bgstatus bgstatus_entry; ++ ++ if (!child_max) { ++#ifdef _SC_CHILD_MAX ++ child_max = sysconf(_SC_CHILD_MAX); ++ if (!child_max) /* paranoia */ ++#endif ++ { ++ /* Be inventive */ ++ child_max = 1024L; ++ } ++ } ++ ++ if (!bgstatus_list) { ++ bgstatus_list = znewlinklist(); ++ /* ++ * We're not always robust about memory failures, but ++ * this is pretty deep in the shell basics to be failing owing ++ * to memory, and a failure to wait is reported loudly, so test ++ * and fail silently here. ++ */ ++ if (!bgstatus_list) ++ return; ++ } ++ if (bgstatus_count == child_max) { ++ /* Overflow. List is in order, remove first */ ++ rembgstatus(firstnode(bgstatus_list)); ++ } ++ bgstatus_entry = (Bgstatus)zalloc(sizeof(*bgstatus_entry)); ++ if (!bgstatus_entry) { ++ /* See note above */ ++ return; ++ } ++ bgstatus_entry->pid = pid; ++ bgstatus_entry->status = status; ++ if (!zaddlinknode(bgstatus_list, bgstatus_entry)) { ++ zfree(bgstatus_entry, sizeof(*bgstatus_entry)); ++ return; ++ } ++ bgstatus_count++; ++} ++ ++/* ++ * See if pid has a recorded exit status. ++ * Note we make no guarantee that the PIDs haven't wrapped, so this ++ * may not be the right process. ++ * ++ * This is only used by wait, which must only work on each ++ * pid once, so we need to remove the entry if we find it. ++ */ ++ ++static int getbgstatus(pid_t pid) ++{ ++ LinkNode node; ++ Bgstatus bgstatus_entry; ++ ++ if (!bgstatus_list) ++ return -1; ++ for (node = firstnode(bgstatus_list); node; incnode(node)) { ++ bgstatus_entry = (Bgstatus)getdata(node); ++ if (bgstatus_entry->pid == pid) { ++ int status = bgstatus_entry->status; ++ rembgstatus(node); ++ return status; ++ } ++ } ++ return -1; ++} + + /* bg, disown, fg, jobs, wait: most of the job control commands are * + * here. They all take the same type of argument. Exception: wait can * +@@ -1971,10 +2070,7 @@ bin_fg(char *name, char **argv, Options ops, int func) + } + if (retval == 0) + retval = lastval2; +- } else if (isset(POSIXJOBS) && +- pid == lastpid && lastpid_status >= 0L) { +- retval = (int)lastpid_status; +- } else { ++ } else if ((retval = getbgstatus(pid)) < 0) { + zwarnnam(name, "pid %d is not a child of this shell", pid); + /* presumably lastval2 doesn't tell us a heck of a lot? */ + retval = 1; +diff --git a/Src/linklist.c b/Src/linklist.c +index 1e364fb..3aa8125 100644 +--- a/Src/linklist.c ++++ b/Src/linklist.c +@@ -118,6 +118,8 @@ znewlinklist(void) + LinkList list; + + list = (LinkList) zalloc(sizeof *list); ++ if (!list) ++ return NULL; + list->list.first = NULL; + list->list.last = &list->node; + list->list.flags = 0; +@@ -152,6 +154,8 @@ zinsertlinknode(LinkList list, LinkNode node, void *dat) + + tmp = node->next; + node->next = new = (LinkNode) zalloc(sizeof *tmp); ++ if (!new) ++ return NULL; + new->prev = node; + new->dat = dat; + new->next = tmp; +diff --git a/Src/signals.c b/Src/signals.c +index 2df69f9..e728505 100644 +--- a/Src/signals.c ++++ b/Src/signals.c +@@ -520,14 +520,14 @@ wait_for_processes(void) + get_usage(); + } + /* +- * Remember the status associated with $!, so we can +- * wait for it even if it's exited. This value is +- * only used if we can't find the PID in the job table, +- * so it doesn't matter that the value we save here isn't +- * useful until the process has exited. ++ * Accumulate a list of older jobs. We only do this for ++ * background jobs, which is something in the job table ++ * that's not marked as in the current shell or as shell builtin ++ * and is not equal to the current foreground job. + */ +- if (pn != NULL && pid == lastpid && lastpid_status != -1L) +- lastpid_status = lastval2; ++ if (jn && !(jn->stat & (STAT_CURSH|STAT_BUILTIN)) && ++ jn - jobtab != thisjob) ++ addbgstatus(pid, (int)lastval2); + } + } + +-- +2.1.0 + + +From 2d59469450ba80b69449dc2777f0fc0673e0fbd6 Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Sun, 26 Oct 2014 19:04:47 +0000 +Subject: [PATCH 2/2] 33542: test logic for waiting for already exited + processes + +Upstream-commit: 9a551ca85999ff329714fd2cca138ce2f7d3c3d9 +Signed-off-by: Kamil Dudka +--- + Test/A05execution.ztst | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst +index ca97f4f..589815f 100644 +--- a/Test/A05execution.ztst ++++ b/Test/A05execution.ztst +@@ -178,3 +178,28 @@ + kill $! + 0:Status reset by starting a backgrounded command + >0 ++ ++# This tests that we record the status of processes that have already exited ++# for when we wait for them. ++# ++# Actually, we don't guarantee here that the jobs have already exited, but ++# the order of the waits means it's highly likely we do need to recall a ++# previous status, barring accidents which shouldn't happen very often. In ++# other words, we rely on the test working repeatedly rather than just ++# once. The monitor option is irrelevant to the logic, so we'll make ++# our job easier by turning it off. ++ unsetopt monitor ++ (exit 1) & ++ one=$! ++ (exit 2) & ++ two=$! ++ (exit 3) & ++ three=$! ++ wait $three ++ print $? ++ wait $two ++ print $? ++ wait $one ++1:The status of recently exited background jobs is recorded ++>3 ++>2 +-- +2.1.0 + diff --git a/SOURCES/zsh-5.0.2-wildcard-opt.patch b/SOURCES/zsh-5.0.2-wildcard-opt.patch new file mode 100644 index 0000000..bca51a5 --- /dev/null +++ b/SOURCES/zsh-5.0.2-wildcard-opt.patch @@ -0,0 +1,52 @@ +From 941f312444dfda4d0d1d02edcfbae9dc1ec6b95e Mon Sep 17 00:00:00 2001 +From: Peter Stephenson +Date: Mon, 8 Sep 2014 16:38:51 +0100 +Subject: [PATCH] users/19059 based on users/19058: remove ineffiency with + multiple * matches + +Upstream-commit: 8bf3595e3a05f0cea7f12c463a0df09e4010cd1c +Signed-off-by: Kamil Dudka +--- + Src/pattern.c | 10 ++++++++++ + Test/D02glob.ztst | 9 ++++++++- + 2 files changed, 18 insertions(+), 1 deletion(-) + +diff --git a/Src/pattern.c b/Src/pattern.c +index 53ada0f..b74a08a 100644 +--- a/Src/pattern.c ++++ b/Src/pattern.c +@@ -2911,6 +2911,16 @@ patmatch(Upat prog) + break; + case P_STAR: + /* Handle specially for speed, although really P_ONEHASH+P_ANY */ ++ while (P_OP(next) == P_STAR) { ++ /* ++ * If there's another * following we can optimise it ++ * out. Chains of *'s can give pathologically bad ++ * performance. ++ */ ++ scan = next; ++ next = PATNEXT(scan); ++ } ++ /*FALLTHROUGH*/ + case P_ONEHASH: + case P_TWOHASH: + /* +diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst +index 0aea261..5709e5c 100644 +--- a/Test/D02glob.ztst ++++ b/Test/D02glob.ztst +@@ -433,3 +433,10 @@ + print glob.tmp/dir5/N<->(N) + 0:Numeric glob is not usurped by process substitution. + >glob.tmp/dir5/N123 ++ ++# The following should not cause excessive slowdown. ++ print glob.tmp/*.* ++ print glob.tmp/**************************.************************* ++0:Optimisation to squeeze multiple *'s used as ordinary glob wildcards. ++>glob.tmp/ra=1.0_et=3.5 ++>glob.tmp/ra=1.0_et=3.5 +-- +2.1.0 + diff --git a/SOURCES/zsh-5.0.2.texi-itemx.patch b/SOURCES/zsh-5.0.2.texi-itemx.patch new file mode 100644 index 0000000..0fed3bc --- /dev/null +++ b/SOURCES/zsh-5.0.2.texi-itemx.patch @@ -0,0 +1,14 @@ +diff -ru zsh-5.0.2-orig/Doc/zsh.texi zsh-5.0.2/Doc/zsh.texi +--- zsh-5.0.2-orig/Doc/zsh.texi 2012-12-21 14:33:06.000000000 -0500 ++++ zsh-5.0.2/Doc/zsh.texi 2013-04-15 18:34:36.660096321 -0400 +@@ -22643,8 +22643,7 @@ + described above. + + @findex _pick_variant +-@item @t{_pick_variant} [ @t{-b} @var{builtin-label} ] [ @t{-c} +-@var{command} ] [ @t{-r} @var{name} ] ++@item @t{_pick_variant} [ @t{-b} @var{builtin-label} ] [ @t{-c} @var{command} ] [ @t{-r} @var{name} ] + @itemx @var{label}@t{=}@var{pattern} ... @var{label} [ @var{args} ... ] + This function is used to resolve situations where a single command name + requires more than one type of handling, either because it +Only in zsh-5.0.2/Doc: zsh.texi~ diff --git a/SOURCES/zsh-aarch64.patch b/SOURCES/zsh-aarch64.patch new file mode 100644 index 0000000..075d633 --- /dev/null +++ b/SOURCES/zsh-aarch64.patch @@ -0,0 +1,1144 @@ +diff -urN zsh-5.0.2/config.guess zsh-5.0.2-aarch64/config.guess +--- zsh-5.0.2/config.guess 2011-12-10 11:23:14.000000000 -0600 ++++ zsh-5.0.2-aarch64/config.guess 2013-03-03 09:34:03.438256458 -0600 +@@ -1,10 +1,10 @@ + #! /bin/sh + # Attempt to guess a canonical system name. + # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +-# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +-# Free Software Foundation, Inc. ++# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, ++# 2011, 2012 Free Software Foundation, Inc. + +-timestamp='2009-11-20' ++timestamp='2012-09-25' + + # This file is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by +@@ -17,9 +17,7 @@ + # General Public License for more details. + # + # You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +-# 02110-1301, USA. ++# along with this program; if not, see . + # + # As a special exception to the GNU General Public License, if you + # distribute this file as part of a program that contains a +@@ -56,8 +54,9 @@ + GNU config.guess ($timestamp) + + Originally written by Per Bothner. +-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. ++Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, ++2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 ++Free Software Foundation, Inc. + + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." +@@ -144,7 +143,7 @@ + case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or +- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, ++ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward +@@ -180,7 +179,7 @@ + fi + ;; + *) +- os=netbsd ++ os=netbsd + ;; + esac + # The OS release +@@ -201,6 +200,10 @@ + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; ++ *:Bitrig:*:*) ++ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` ++ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} ++ exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} +@@ -223,7 +226,7 @@ + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) +- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ++ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on +@@ -269,7 +272,10 @@ + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` +- exit ;; ++ # Reset EXIT trap before exiting to avoid spurious non-zero exit code. ++ exitcode=$? ++ trap '' 0 ++ exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead +@@ -295,12 +301,12 @@ + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) +- echo powerpc-ibm-os400 ++ echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; +- arm:riscos:*:*|arm:RISCOS:*:*) ++ arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) +@@ -394,23 +400,23 @@ + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) +- echo m68k-atari-mint${UNAME_RELEASE} ++ echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} +- exit ;; ++ exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) +- echo m68k-atari-mint${UNAME_RELEASE} ++ echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) +- echo m68k-milan-mint${UNAME_RELEASE} +- exit ;; ++ echo m68k-milan-mint${UNAME_RELEASE} ++ exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) +- echo m68k-hades-mint${UNAME_RELEASE} +- exit ;; ++ echo m68k-hades-mint${UNAME_RELEASE} ++ exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) +- echo m68k-unknown-mint${UNAME_RELEASE} +- exit ;; ++ echo m68k-unknown-mint${UNAME_RELEASE} ++ exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; +@@ -480,8 +486,8 @@ + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) +- # DG/UX returns AViiON for all architectures +- UNAME_PROCESSOR=`/usr/bin/uname -p` ++ # DG/UX returns AViiON for all architectures ++ UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ +@@ -494,7 +500,7 @@ + else + echo i586-dg-dgux${UNAME_RELEASE} + fi +- exit ;; ++ exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; +@@ -551,7 +557,7 @@ + echo rs6000-ibm-aix3.2 + fi + exit ;; +- *:AIX:*:[456]) ++ *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 +@@ -594,52 +600,52 @@ + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` +- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` +- case "${sc_cpu_version}" in +- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 +- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 +- 532) # CPU_PA_RISC2_0 +- case "${sc_kernel_bits}" in +- 32) HP_ARCH="hppa2.0n" ;; +- 64) HP_ARCH="hppa2.0w" ;; ++ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` ++ case "${sc_cpu_version}" in ++ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 ++ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 ++ 532) # CPU_PA_RISC2_0 ++ case "${sc_kernel_bits}" in ++ 32) HP_ARCH="hppa2.0n" ;; ++ 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 +- esac ;; +- esac ++ esac ;; ++ esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build +- sed 's/^ //' << EOF >$dummy.c ++ sed 's/^ //' << EOF >$dummy.c ++ ++ #define _HPUX_SOURCE ++ #include ++ #include + +- #define _HPUX_SOURCE +- #include +- #include +- +- int main () +- { +- #if defined(_SC_KERNEL_BITS) +- long bits = sysconf(_SC_KERNEL_BITS); +- #endif +- long cpu = sysconf (_SC_CPU_VERSION); +- +- switch (cpu) +- { +- case CPU_PA_RISC1_0: puts ("hppa1.0"); break; +- case CPU_PA_RISC1_1: puts ("hppa1.1"); break; +- case CPU_PA_RISC2_0: +- #if defined(_SC_KERNEL_BITS) +- switch (bits) +- { +- case 64: puts ("hppa2.0w"); break; +- case 32: puts ("hppa2.0n"); break; +- default: puts ("hppa2.0"); break; +- } break; +- #else /* !defined(_SC_KERNEL_BITS) */ +- puts ("hppa2.0"); break; +- #endif +- default: puts ("hppa1.0"); break; +- } +- exit (0); +- } ++ int main () ++ { ++ #if defined(_SC_KERNEL_BITS) ++ long bits = sysconf(_SC_KERNEL_BITS); ++ #endif ++ long cpu = sysconf (_SC_CPU_VERSION); ++ ++ switch (cpu) ++ { ++ case CPU_PA_RISC1_0: puts ("hppa1.0"); break; ++ case CPU_PA_RISC1_1: puts ("hppa1.1"); break; ++ case CPU_PA_RISC2_0: ++ #if defined(_SC_KERNEL_BITS) ++ switch (bits) ++ { ++ case 64: puts ("hppa2.0w"); break; ++ case 32: puts ("hppa2.0n"); break; ++ default: puts ("hppa2.0"); break; ++ } break; ++ #else /* !defined(_SC_KERNEL_BITS) */ ++ puts ("hppa2.0"); break; ++ #endif ++ default: puts ("hppa1.0"); break; ++ } ++ exit (0); ++ } + EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa +@@ -730,22 +736,22 @@ + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd +- exit ;; ++ exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi +- exit ;; ++ exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd +- exit ;; ++ exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd +- exit ;; ++ exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd +- exit ;; ++ exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; +@@ -769,14 +775,14 @@ + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` +- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` +- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` +- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" +- exit ;; ++ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` ++ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` ++ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" ++ exit ;; + 5000:UNIX_System_V:4.*:*) +- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` +- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` +- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" ++ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` ++ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` ++ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} +@@ -788,30 +794,35 @@ + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) +- case ${UNAME_MACHINE} in +- pc98) +- echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; ++ UNAME_PROCESSOR=`/usr/bin/uname -p` ++ case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) +- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; ++ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; ++ *:MINGW64*:*) ++ echo ${UNAME_MACHINE}-pc-mingw64 ++ exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; ++ i*:MSYS*:*) ++ echo ${UNAME_MACHINE}-pc-msys ++ exit ;; + i*:windows32*:*) +- # uname -m includes "-pc" on this system. +- echo ${UNAME_MACHINE}-mingw32 ++ # uname -m includes "-pc" on this system. ++ echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) +- case ${UNAME_MACHINE} in ++ case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; +@@ -857,6 +868,13 @@ + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; ++ aarch64:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ aarch64_be:Linux:*:*) ++ UNAME_MACHINE=aarch64_be ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; +@@ -866,7 +884,7 @@ + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; +- esac ++ esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} +@@ -878,20 +896,29 @@ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else +- echo ${UNAME_MACHINE}-unknown-linux-gnueabi ++ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ ++ | grep -q __ARM_PCS_VFP ++ then ++ echo ${UNAME_MACHINE}-unknown-linux-gnueabi ++ else ++ echo ${UNAME_MACHINE}-unknown-linux-gnueabihf ++ fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) +- echo cris-axis-linux-gnu ++ echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) +- echo crisv32-axis-linux-gnu ++ echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + frv:Linux:*:*) +- echo frv-unknown-linux-gnu ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; ++ hexagon:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu +@@ -933,7 +960,7 @@ + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) +- echo or32-unknown-linux-gnu ++ echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu +@@ -959,7 +986,7 @@ + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu ++ echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu +@@ -967,14 +994,17 @@ + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; ++ tile*:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-gnu ++ exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) +- echo x86_64-unknown-linux-gnu ++ echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) +- echo ${UNAME_MACHINE}-unknown-linux-gnu ++ echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. +@@ -983,11 +1013,11 @@ + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) +- # Unixware is an offshoot of SVR4, but it has its own version +- # number series starting with 2... +- # I am not positive that other SVR4 systems won't match this, ++ # Unixware is an offshoot of SVR4, but it has its own version ++ # number series starting with 2... ++ # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. +- # Use sysv4.2uw... so that sysv4* matches it. ++ # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) +@@ -1019,7 +1049,7 @@ + fi + exit ;; + i*86:*:5:[678]*) +- # UnixWare 7.x, OpenUNIX and OpenServer 6. ++ # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; +@@ -1047,13 +1077,13 @@ + exit ;; + pc:*:*:*) + # Left here for compatibility: +- # uname -m prints for DJGPP always 'pc', but it prints nothing about +- # the processor, so we play safe by assuming i586. ++ # uname -m prints for DJGPP always 'pc', but it prints nothing about ++ # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp +- exit ;; ++ exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; +@@ -1088,8 +1118,8 @@ + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) +- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ +- && { echo i486-ncr-sysv4; exit; } ;; ++ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ ++ && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ +@@ -1132,10 +1162,10 @@ + echo ns32k-sni-sysv + fi + exit ;; +- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort +- # says +- echo i586-unisys-sysv4 +- exit ;; ++ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort ++ # says ++ echo i586-unisys-sysv4 ++ exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm +@@ -1161,11 +1191,11 @@ + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then +- echo mips-nec-sysv${UNAME_RELEASE} ++ echo mips-nec-sysv${UNAME_RELEASE} + else +- echo mips-unknown-sysv${UNAME_RELEASE} ++ echo mips-unknown-sysv${UNAME_RELEASE} + fi +- exit ;; ++ exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; +@@ -1178,6 +1208,9 @@ + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; ++ x86_64:Haiku:*:*) ++ echo x86_64-unknown-haiku ++ exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; +@@ -1230,7 +1263,10 @@ + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; +- NSE-?:NONSTOP_KERNEL:*:*) ++ NEO-?:NONSTOP_KERNEL:*:*) ++ echo neo-tandem-nsk${UNAME_RELEASE} ++ exit ;; ++ NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) +@@ -1275,13 +1311,13 @@ + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) +- echo mips-sei-seiux${UNAME_RELEASE} ++ echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) +- UNAME_MACHINE=`(uname -p) 2>/dev/null` ++ UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; +@@ -1299,11 +1335,11 @@ + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; ++ x86_64:VMkernel:*:*) ++ echo ${UNAME_MACHINE}-unknown-esx ++ exit ;; + esac + +-#echo '(No uname command or uname output not recognized.)' 1>&2 +-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 +- + eval $set_cc_for_build + cat >$dummy.c < + printf ("m68k-sony-newsos%s\n", + #ifdef NEWSOS4 +- "4" ++ "4" + #else +- "" ++ "" + #endif +- ); exit (0); ++ ); exit (0); + #endif + #endif + +diff -urN zsh-5.0.2/config.sub zsh-5.0.2-aarch64/config.sub +--- zsh-5.0.2/config.sub 2011-12-10 11:23:14.000000000 -0600 ++++ zsh-5.0.2-aarch64/config.sub 2013-03-03 09:34:03.465253348 -0600 +@@ -1,10 +1,10 @@ + #! /bin/sh + # Configuration validation subroutine script. + # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +-# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +-# Free Software Foundation, Inc. ++# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, ++# 2011, 2012 Free Software Foundation, Inc. + +-timestamp='2009-11-20' ++timestamp='2012-10-10' + + # This file is (in principle) common to ALL GNU software. + # The presence of a machine in this file suggests that SOME GNU software +@@ -21,9 +21,7 @@ + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License +-# along with this program; if not, write to the Free Software +-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +-# 02110-1301, USA. ++# along with this program; if not, see . + # + # As a special exception to the GNU General Public License, if you + # distribute this file as part of a program that contains a +@@ -75,8 +73,9 @@ + version="\ + GNU config.sub ($timestamp) + +-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. ++Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, ++2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 ++Free Software Foundation, Inc. + + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." +@@ -123,13 +122,18 @@ + # Here we must recognize all the valid KERNEL-OS combinations. + maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` + case $maybe_os in +- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ +- uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ ++ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ ++ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ ++ knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; ++ android-linux) ++ os=-linux-android ++ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ++ ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] +@@ -152,12 +156,12 @@ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ +- -apple | -axis | -knuth | -cray | -microblaze) ++ -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; +- -bluegene*) +- os=-cnk ++ -bluegene*) ++ os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= +@@ -173,10 +177,10 @@ + os=-chorusos + basic_machine=$1 + ;; +- -chorusrdb) +- os=-chorusrdb ++ -chorusrdb) ++ os=-chorusrdb + basic_machine=$1 +- ;; ++ ;; + -hiux*) + os=-hiuxwe2 + ;; +@@ -221,6 +225,12 @@ + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; ++ -lynx*178) ++ os=-lynxos178 ++ ;; ++ -lynx*5) ++ os=-lynxos5 ++ ;; + -lynx*) + os=-lynxos + ;; +@@ -245,20 +255,25 @@ + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ ++ | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ ++ | be32 | be64 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ ++ | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ ++ | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ ++ | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ +- | maxq | mb | microblaze | mcore | mep | metag \ ++ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ +@@ -281,29 +296,39 @@ + | moxie \ + | mt \ + | msp430 \ ++ | nds32 | nds32le | nds32be \ + | nios | nios2 \ + | ns16k | ns32k \ ++ | open8 \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ +- | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ ++ | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ +- | rx \ ++ | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ +- | spu | strongarm \ +- | tahoe | thumb | tic4x | tic80 | tron \ ++ | spu \ ++ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ +- | v850 | v850e \ ++ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ +- | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ ++ | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; +- m6811 | m68hc11 | m6812 | m68hc12 | picochip) +- # Motorola 68HC11/12. ++ c54x) ++ basic_machine=tic54x-unknown ++ ;; ++ c55x) ++ basic_machine=tic55x-unknown ++ ;; ++ c6x) ++ basic_machine=tic6x-unknown ++ ;; ++ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; +@@ -313,6 +338,21 @@ + basic_machine=mt-unknown + ;; + ++ strongarm | thumb | xscale) ++ basic_machine=arm-unknown ++ ;; ++ xgate) ++ basic_machine=$basic_machine-unknown ++ os=-none ++ ;; ++ xscaleeb) ++ basic_machine=armeb-unknown ++ ;; ++ ++ xscaleel) ++ basic_machine=armel-unknown ++ ;; ++ + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. +@@ -327,25 +367,30 @@ + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ ++ | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ ++ | be32-* | be64-* \ + | bfin-* | bs2000-* \ +- | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ ++ | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ ++ | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ ++ | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ +- | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ ++ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ ++ | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ +@@ -367,25 +412,29 @@ + | mmix-* \ + | mt-* \ + | msp430-* \ ++ | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ ++ | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ +- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ ++ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ +- | romp-* | rs6000-* | rx-* \ ++ | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ +- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ +- | tahoe-* | thumb-* \ +- | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ ++ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ ++ | tahoe-* \ ++ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ ++ | tile*-* \ + | tron-* \ + | ubicom32-* \ +- | v850-* | v850e-* | vax-* \ ++ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ ++ | vax-* \ + | we32k-* \ +- | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ ++ | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) +@@ -410,7 +459,7 @@ + basic_machine=a29k-amd + os=-udi + ;; +- abacus) ++ abacus) + basic_machine=abacus-unknown + ;; + adobe68k) +@@ -480,11 +529,20 @@ + basic_machine=powerpc-ibm + os=-cnk + ;; ++ c54x-*) ++ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ c55x-*) ++ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; ++ c6x-*) ++ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; +- cegcc) ++ cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; +@@ -516,7 +574,7 @@ + basic_machine=craynv-cray + os=-unicosmp + ;; +- cr16) ++ cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; +@@ -674,7 +732,6 @@ + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +-# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 +@@ -732,9 +789,13 @@ + basic_machine=ns32k-utek + os=-sysv + ;; +- microblaze) ++ microblaze*) + basic_machine=microblaze-xilinx + ;; ++ mingw64) ++ basic_machine=x86_64-pc ++ os=-mingw64 ++ ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 +@@ -771,10 +832,18 @@ + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; ++ msys) ++ basic_machine=i386-pc ++ os=-msys ++ ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; ++ nacl) ++ basic_machine=le32-unknown ++ os=-nacl ++ ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 +@@ -839,6 +908,12 @@ + np1) + basic_machine=np1-gould + ;; ++ neo-tandem) ++ basic_machine=neo-tandem ++ ;; ++ nse-tandem) ++ basic_machine=nse-tandem ++ ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; +@@ -921,9 +996,10 @@ + ;; + power) basic_machine=power-ibm + ;; +- ppc) basic_machine=powerpc-unknown ++ ppc | ppcbe) basic_machine=powerpc-unknown + ;; +- ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ppc-* | ppcbe-*) ++ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown +@@ -1017,6 +1093,9 @@ + basic_machine=i860-stratus + os=-sysv4 + ;; ++ strongarm-* | thumb-*) ++ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ++ ;; + sun2) + basic_machine=m68000-sun + ;; +@@ -1073,20 +1152,8 @@ + basic_machine=t90-cray + os=-unicos + ;; +- tic54x | c54x*) +- basic_machine=tic54x-unknown +- os=-coff +- ;; +- tic55x | c55x*) +- basic_machine=tic55x-unknown +- os=-coff +- ;; +- tic6x | c6x*) +- basic_machine=tic6x-unknown +- os=-coff +- ;; + tile*) +- basic_machine=tile-unknown ++ basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) +@@ -1156,6 +1223,9 @@ + xps | xps100) + basic_machine=xps100-honeywell + ;; ++ xscale-* | xscalee[bl]-*) ++ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ++ ;; + ymp) + basic_machine=ymp-cray + os=-unicos +@@ -1253,11 +1323,11 @@ + if [ x"$os" != x"" ] + then + case $os in +- # First match some system type aliases +- # that might get confused with valid system types. ++ # First match some system type aliases ++ # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. +- -auroraux) +- os=-auroraux ++ -auroraux) ++ os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` +@@ -1287,14 +1357,15 @@ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ +- | -openbsd* | -solidbsd* \ ++ | -bitrig* | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ +- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ +- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ ++ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ ++ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ ++ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ +@@ -1341,7 +1412,7 @@ + -opened*) + os=-openedition + ;; +- -os400*) ++ -os400*) + os=-os400 + ;; + -wince*) +@@ -1390,7 +1461,7 @@ + -sinix*) + os=-sysv4 + ;; +- -tpf*) ++ -tpf*) + os=-tpf + ;; + -triton*) +@@ -1435,6 +1506,8 @@ + -dicos*) + os=-dicos + ;; ++ -nacl*) ++ ;; + -none) + ;; + *) +@@ -1457,10 +1530,10 @@ + # system, and we'll never get to this point. + + case $basic_machine in +- score-*) ++ score-*) + os=-elf + ;; +- spu-*) ++ spu-*) + os=-elf + ;; + *-acorn) +@@ -1472,8 +1545,20 @@ + arm*-semi) + os=-aout + ;; +- c4x-* | tic4x-*) +- os=-coff ++ c4x-* | tic4x-*) ++ os=-coff ++ ;; ++ hexagon-*) ++ os=-elf ++ ;; ++ tic54x-*) ++ os=-coff ++ ;; ++ tic55x-*) ++ os=-coff ++ ;; ++ tic6x-*) ++ os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) +@@ -1493,14 +1578,11 @@ + ;; + m68000-sun) + os=-sunos3 +- # This also exists in the configure program, but was not the +- # default. +- # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; +- mep-*) ++ mep-*) + os=-elf + ;; + mips*-cisco) +@@ -1527,7 +1609,7 @@ + *-ibm) + os=-aix + ;; +- *-knuth) ++ *-knuth) + os=-mmixware + ;; + *-wec) diff --git a/SOURCES/zsh-serial.patch b/SOURCES/zsh-serial.patch new file mode 100644 index 0000000..ebfde77 --- /dev/null +++ b/SOURCES/zsh-serial.patch @@ -0,0 +1,65 @@ +--- zsh-4.0.4/Src/builtin.c.open Tue Oct 16 02:49:17 2001 ++++ zsh-4.0.4/Src/builtin.c Wed May 15 11:55:32 2002 +@@ -5262,7 +5262,7 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func)) + if (!zleactive) { + if (SHTTY == -1) { + /* need to open /dev/tty specially */ +- if ((SHTTY = open("/dev/tty", O_RDWR|O_NOCTTY)) != -1) { ++ if ((SHTTY = block_open("/dev/tty", O_RDWR|O_NOCTTY)) != -1) { + haso = 1; + oshout = shout; + init_shout(); +--- zsh-4.0.4/Src/init.c.open Wed Oct 24 04:16:32 2001 ++++ zsh-4.0.4/Src/init.c Wed May 15 12:00:07 2002 +@@ -508,7 +508,7 @@ init_io(void) + if (isatty(0)) { + zsfree(ttystrname); + if ((ttystrname = ztrdup(ttyname(0)))) { +- SHTTY = movefd(open(ttystrname, O_RDWR | O_NOCTTY)); ++ SHTTY = movefd(block_open(ttystrname, O_RDWR | O_NOCTTY)); + #ifdef TIOCNXCL + /* + * See if the terminal claims to be busy. If so, and fd 0 +@@ -549,7 +549,7 @@ init_io(void) + ttystrname = ztrdup(ttyname(1)); + } + if (SHTTY == -1 && +- (SHTTY = movefd(open("/dev/tty", O_RDWR | O_NOCTTY))) != -1) { ++ (SHTTY = movefd(block_open("/dev/tty", O_RDWR | O_NOCTTY))) != -1) { + zsfree(ttystrname); + ttystrname = ztrdup(ttyname(SHTTY)); + } +@@ -1671,3 +1671,33 @@ zsh_main(UNUSED(int argc), char **argv) + : "use 'logout' to logout."); + } + } ++ ++/**/ ++int ++block_open (const char *tty, int flags) ++{ ++ int saved_errno; ++ int fd; ++ ++ if ((flags & O_NONBLOCK) == 0) { ++ fd = open (tty, flags | O_NONBLOCK); ++ if (fd == -1) ++ return fd; ++ flags = fcntl(fd, F_GETFL); ++ if (flags == -1) ++ goto bad; ++ flags &= ~O_NONBLOCK; ++ if (fcntl(fd, F_SETFL, flags) == -1) ++ goto bad; ++ } ++ else ++ fd = open (tty, flags); ++ ++ return fd; ++ ++bad: ++ saved_errno = errno; ++ close (fd); ++ errno = saved_errno; ++ return -1; ++} diff --git a/SOURCES/zsh-test-C02-dev_fd-mock.patch b/SOURCES/zsh-test-C02-dev_fd-mock.patch new file mode 100644 index 0000000..454da92 --- /dev/null +++ b/SOURCES/zsh-test-C02-dev_fd-mock.patch @@ -0,0 +1,23 @@ +diff -ru zsh-4.3.6-orig/Test/C02cond.ztst zsh-4.3.6/Test/C02cond.ztst +--- zsh-4.3.6-orig/Test/C02cond.ztst 2008-02-27 06:41:13.000000000 -0500 ++++ zsh-4.3.6/Test/C02cond.ztst 2008-08-25 17:39:13.000000000 -0400 +@@ -187,7 +187,8 @@ + print -u$ZTST_fd "Warning: not testing [[ -e /dev/fd/0 ]] (/dev/fd not supported)" + true + else +- [[ -e /dev/fd/0 ]] ++ print -u$ZTST_fd "Warning: not testing: [[ -e /dev/fd/0 ]] (mock kills us)" ++ true + fi + 0dD:/dev/fd support in conds handled by access + +@@ -195,7 +196,8 @@ + print -u$ZTST_fd "Warning: not testing [[ -O /dev/fd/0 ]] (/dev/fd not supported)" + true + else +- [[ -O /dev/fd/0 ]] ++ print -u$ZTST_fd "Warning: not testing: [[ -O /dev/fd/0 ]] (mock kills us)" ++ true + fi + 0dD:/dev/fd support in conds handled by stat + diff --git a/SOURCES/zshenv.rhs b/SOURCES/zshenv.rhs new file mode 100644 index 0000000..a6614d3 --- /dev/null +++ b/SOURCES/zshenv.rhs @@ -0,0 +1,14 @@ +# /etc/zsh/zshenv: system-wide .zshenv file for zsh(1). +# +# This file is sourced on all invocations of the shell. +# If the -f flag is present or if the NO_RCS option is +# set within this file, all other initialization files +# are skipped. +# +# This file should contain commands to set the command +# search path, plus other important environment variables. +# This file should not contain commands that produce +# output or assume the shell is attached to a tty. +# +# Global Order: zshenv, zprofile, zshrc, zlogin + diff --git a/SOURCES/zshprompt.pl b/SOURCES/zshprompt.pl new file mode 100644 index 0000000..b9d5f0f --- /dev/null +++ b/SOURCES/zshprompt.pl @@ -0,0 +1,235 @@ +#!/usr/bin/perl -w + +#requires Gtk-Perl + +use Gtk; +use strict; + +set_locale Gtk; +init Gtk; + +my $window = new Gtk::Window("toplevel"); +$window->signal_connect( "delete_event", \&CloseAppWindow ); +my $table = new Gtk::Table( 20, 6, 0 ); +$window->border_width( 5 ); +#$window->add( $button ); + + +my $prompt = new Gtk::Entry( 128); +my $log = new Gtk::Text(); +$log->set_usize(40,60); +$log->show(); +$prompt->show(); +#$prompt->set_editable (1); +$prompt->set_text(""); +$table->attach( $prompt,0,4,0,4,[ 'expand', 'shrink', 'fill' ], + 'shrink', + 0, 0 ); + +$table->set_row_spacings( 5 ); +$table->set_col_spacings( 5 ); + +my $currDir = new Gtk::Button( "Current Directory" ); +$currDir->show(); +$table->attach_defaults( $currDir,0,1,4,6 ); + +my $errorCode = new Gtk::Button( "Last Return Code" ); +$errorCode->show(); +$table->attach_defaults( $errorCode,1,2,4,6 ); + +my $currTime = new Gtk::Button( "Time" ); +$currTime->show(); +$table->attach_defaults( $currTime,2,3,4,6 ); + +my $hist = new Gtk::Button( "History Number" ); +$hist->show(); +$table->attach_defaults( $hist,3,4,4,6 ); + +my $host = new Gtk::Button( "Hostname" ); +$host->show(); +$table->attach_defaults( $host,0,1,6,8 ); + + + +my $backgroundBlue = new Gtk::Button( "Blue Background" ); +$backgroundBlue->show(); +$table->attach_defaults( $backgroundBlue,0,1,8,10 ); + +my $backgroundRed = new Gtk::Button( "Red Background" ); +$backgroundRed->show(); +$table->attach_defaults( $backgroundRed,1,2,8,10 ); + +my $backgroundGreen = new Gtk::Button( "Green Background" ); +$backgroundGreen->show(); +$table->attach_defaults( $backgroundGreen,2,3,8,10 ); + +my $backgroundYellow = new Gtk::Button( "Yellow Background" ); +$backgroundYellow->show(); +$table->attach_defaults( $backgroundYellow,3,4,8,10 ); + +my $backgroundBlack = new Gtk::Button( "Black Background" ); +$backgroundBlack->show(); +$table->attach_defaults( $backgroundBlack,5,6,8,10 ); + +my $backgroundWhite = new Gtk::Button( "White Background" ); +$backgroundWhite->show(); +$table->attach_defaults( $backgroundWhite,6,7,8,10 ); + +my $backgroundPink = new Gtk::Button( "Pink Background" ); +$backgroundPink->show(); +$table->attach_defaults( $backgroundPink,7,8,8,10 ); + + + + + +my $textBlue = new Gtk::Button( "Blue Text" ); +$textBlue->show(); +$table->attach_defaults( $textBlue,0,1,10,12 ); + +my $textRed = new Gtk::Button( "Red Text" ); +$textRed->show(); +$table->attach_defaults( $textRed,1,2,10,12 ); + +my $textGreen = new Gtk::Button( "Green Text" ); +$textGreen->show(); +$table->attach_defaults( $textGreen,2,3,10,12 ); + +my $textYellow = new Gtk::Button( "Yellow Text" ); +$textYellow->show(); +$table->attach_defaults( $textYellow,3,4,10,12 ); + +my $textBlack = new Gtk::Button( "Black Text" ); +$textBlack->show(); +$table->attach_defaults( $textBlack,5,6,10,12 ); + +my $textWhite = new Gtk::Button( "White Text" ); +$textWhite->show(); +$table->attach_defaults( $textWhite,6,7,10,12 ); + +my $textPink = new Gtk::Button( "Pink Text" ); +$textPink->show(); +$table->attach_defaults( $textPink,7,8,10,12 ); + + +my $textDefault = new Gtk::Button( "Default Text" ); +$textDefault->show(); +$table->attach_defaults( $textDefault,0,1,12,14 ); + +my $backgroundDefault = new Gtk::Button( "Default Background" ); +$backgroundDefault->show(); +$table->attach_defaults( $backgroundDefault,1,2,12,14 ); + + + +my $set = new Gtk::Button( "Save Settings" ); +$set->show(); +$table->attach_defaults( $set,0,1,16,18 ); + +my $xterm = new Gtk::Button( "Test saved settings" ); +$xterm->show(); +$table->attach_defaults( $xterm,1,2,16,18 ); + +$table->attach_defaults( $log,0,6,18,20 ); + + +$currDir->signal_connect( "clicked", \&insertButtonText, "%1/" ); +$errorCode->signal_connect( "clicked", \&insertButtonText, "%?" ); +$currTime->signal_connect( "clicked", \&insertButtonText, "%T" ); +$hist->signal_connect( "clicked", \&insertButtonText, "%!" ); +$host->signal_connect( "clicked", \&insertButtonText, "%m" ); + +$backgroundBlue->signal_connect( "clicked", \&insertButtonText, "%{\$bg[blue]%}" ); +$backgroundRed->signal_connect( "clicked", \&insertButtonText, "%{\$bg[red]%}" ); +$backgroundGreen->signal_connect( "clicked", \&insertButtonText, "%{\$bg[green]%}" ); +$backgroundYellow->signal_connect( "clicked", \&insertButtonText, "%{\$bg[yellow]%}" ); +$backgroundBlack->signal_connect( "clicked", \&insertButtonText, "%{\$bg[black]%}" ); +$backgroundWhite->signal_connect( "clicked", \&insertButtonText, "%{\$bg[white]%}" ); +$backgroundPink->signal_connect( "clicked", \&insertButtonText, "%{\$bg[magenta]%}" ); +$backgroundDefault->signal_connect( "clicked", \&insertButtonText, "%{\$bg[default]%}" ); + + + + +$textBlue->signal_connect( "clicked", \&insertButtonText, "%{\$fg[blue]%}" ); +$textRed->signal_connect( "clicked", \&insertButtonText, "%{\$fg[red]%}" ); +$textGreen->signal_connect( "clicked", \&insertButtonText, "%{\$fg[green]%}" ); +$textYellow->signal_connect( "clicked", \&insertButtonText, "%{\$fg[yellow]%}" ); +$textBlack->signal_connect( "clicked", \&insertButtonText, "%{\$fg[black]%}" ); +$textWhite->signal_connect( "clicked", \&insertButtonText, "%{\$fg[white]%}" ); +$textPink->signal_connect( "clicked", \&insertButtonText, "%{\$fg[magenta]%}" ); +$textDefault->signal_connect( "clicked", \&insertButtonText, "%{\$fg[default]%}" ); + + + + + +$set->signal_connect( "clicked", \&pushEnv ); +$xterm->signal_connect( "clicked", \&xterm ); + +sub xterm +{ +my $string="xterm -e zsh -li&"; +#$string.=$prompt->get_text(); + +#$string.="' zsh -li\"& "; + +system($string); +# $prompt->append_text( $string ); +$log->insert( "", "white", "black", "executing:\n $string\n"); +} + + +sub pushEnv +{ +chdir("~"); +use Env qw(PS1); +my $pNotSet=0; +open(PROMPT, "+<", ".prompt") or $pNotSet=1; + + +if($pNotSet) +{ + #$prompt->insert( "", "white", "black", "prompt is not set"); + open(ZSHRC, '>>','.zshrc') or die "cannot open zshrc"; + print ZSHRC ". ~/.prompt\n"; + close (ZSHRC); +} +close (PROMPT); +open(PROMPT, ">", ".prompt"); +print PROMPT "export PS1=\"",$prompt->get_text(),"\"\n"; + +#$prompt->insert( "", "white", "black", $PS1); + +close(PROMPT); +close(ZSHRC); +$prompt->grab_focus(); + +} +$prompt->can_default(1); +$prompt->grab_default(); +$table->show(); +$window->add( $table ); + + + + +$window->show(); +$prompt->grab_focus(); +main Gtk; + +exit( 0 ); + +sub CloseAppWindow +{ + Gtk->exit( 0 ); + return 0; +} + + +sub insertButtonText +{ + my ($widget, $txt) = @_; + $prompt->append_text( $txt ); +$prompt->grab_focus(); +} diff --git a/SOURCES/zshrc.rhs b/SOURCES/zshrc.rhs new file mode 100644 index 0000000..5b3b92a --- /dev/null +++ b/SOURCES/zshrc.rhs @@ -0,0 +1,50 @@ +# +# /etc/zshrc is sourced in interactive shells. It +# should contain commands to set up aliases, functions, +# options, key bindings, etc. +# + +## shell functions +#setenv() { export $1=$2 } # csh compatibility + +# Set prompts +PROMPT='[%n@%m]%~%# ' # default prompt +#RPROMPT=' %~' # prompt for right side of screen + +# bindkey -v # vi key bindings +# bindkey -e # emacs key bindings +bindkey ' ' magic-space # also do history expansion on space + +# Provide pathmunge for /etc/profile.d scripts +pathmunge() +{ + if ! echo $PATH | /bin/grep -qE "(^|:)$1($|:)" ; then + if [ "$2" = "after" ] ; then + PATH=$PATH:$1 + else + PATH=$1:$PATH + fi + fi +} + +_src_etc_profile_d() +{ + # Make the *.sh things happier, and have possible ~/.zshenv options like + # NOMATCH ignored. + emulate -L ksh + + + # from bashrc, with zsh fixes + if [[ ! -o login ]]; then # We're not a login shell + for i in /etc/profile.d/*.sh; do + if [ -r "$i" ]; then + . $i + fi + done + unset i + fi +} +_src_etc_profile_d + +unset -f pathmunge _src_etc_profile_d + diff --git a/SPECS/zsh.spec b/SPECS/zsh.spec new file mode 100644 index 0000000..70266e2 --- /dev/null +++ b/SPECS/zsh.spec @@ -0,0 +1,472 @@ +# this file is encoded in UTF-8 -*- coding: utf-8 -*- + +Summary: Powerful interactive shell +Name: zsh +Version: 5.0.2 +Release: 34%{?dist} +License: MIT +URL: http://zsh.sourceforge.net/ +Group: System Environment/Shells +Source0: http://download.sourceforge.net/%{name}/%{name}-%{version}.tar.bz2 +Source1: zlogin.rhs +Source2: zlogout.rhs +Source3: zprofile.rhs +Source4: zshrc.rhs +Source5: zshenv.rhs +Source6: dotzshrc +Source7: zshprompt.pl +Source8: http://cgit.freedesktop.org/systemd/systemd/plain/shell-completion/systemd-zsh-completion.zsh +Patch0: zsh-serial.patch + +# make the wait built-in work for already exited processes (#1150554) +Patch2: zsh-5.0.2-wait-for-exited.patch + +Patch4: zsh-4.3.6-8bit-prompts.patch +Patch5: zsh-test-C02-dev_fd-mock.patch + +# signal safety when updating global state (#1163823) +Patch6: zsh-5.0.2-signal-safety.patch + +# fix NOEXEC option in execsimple() optimisation (#1146512) +Patch7: zsh-5.0.2-noexec.patch + +# optimize matching of multiple * in wildcards (#1130418) +Patch8: zsh-5.0.2-wildcard-opt.patch + +# use heap rather than stack allocation for variable length arrays (#1130418) +Patch9: zsh-5.0.2-disable-alloca.patch + +# shell emulation doc addition (#1147545) +Patch10: zsh-5.0.2-emul-man-page.patch + +# Tmp. +Patch11: zsh-5.0.2.texi-itemx.patch +Patch12: http://ausil.fedorapeople.org/aarch64/zsh/zsh-aarch64.patch + +# suppress a warning about closing an already closed file descriptor (#1131191) +Patch13: zsh-5.0.2-close-fd.patch + +# fix SIGSEGV of the syntax check in ksh emulation mode (#1222867) +Patch14: zsh-5.0.2-ksh-syntax-check.patch + +# fix command substitutions to parse contents as they are read in (#1241023) +Patch15: zsh-5.0.2-cmd-subst.patch + +# fix malloc() signal leak in lexsave() (#1267912) +Patch16: zsh-5.0.2-malloc-signal.patch + +# queue signals while processing a job exit (#1291782) +Patch17: zsh-5.0.2-sigchld-deadlock.patch + +# prevent zsh from crashing when printing the "out of memory" message (#1302229) +Patch18: zsh-5.0.2-oom-fatal-error.patch + +# signal-handling related fixes collected from upstream (#1198671) +Patch19: zsh-5.0.2-signal-handling.patch + +# improve options handling in the _arguments completion utility (#1334312) +Patch20: zsh-5.0.2-comp-args.patch + +# fix off-by-one error in completion utility cache code (#1344599) +Patch21: zsh-5.0.2-comp-cache.patch + +# fix parsing of parameter subscript expression with NOEXEC (#1398740) +Patch22: zsh-5.0.2-noexec-subscript.patch + +# zero new space allocated in prompt buffer (#1408619) +Patch23: zsh-5.0.2-initialize-prompt-buffer.patch + +# fix crash while inputting long multi-line strings (#1492595) +Patch24: zsh-5.0.2-freeheap-crash.patch + +# fix buffer overflow for very long fds in >& fd syntax (CVE-2014-10071) +Patch33: zsh-5.0.2-CVE-2014-10071.patch + +# fix buffer overflow when scanning very long path for symlinks (CVE-2014-10072) +Patch34: zsh-5.0.2-CVE-2014-10072.patch + +# fix NULL dereference in cd (CVE-2017-18205) +Patch35: zsh-5.0.2-CVE-2017-18205.patch + +# fix buffer overrun in xsymlinks (CVE-2017-18206) +Patch36: zsh-5.0.2-CVE-2017-18206.patch + +# avoid crash when copying empty hash table (CVE-2018-7549) +Patch37: zsh-5.0.2-CVE-2018-7549.patch + +# fix stack-based buffer overflow in exec.c:hashcmd() (CVE-2018-1071) +Patch38: zsh-5.0.2-CVE-2018-1071.patch + +# fix stack-based buffer overflow in gen_matches_files() (CVE-2018-1083) +Patch39: zsh-5.0.2-CVE-2018-1083.patch + +# fix stack-based buffer overflow in utils.c:checkmailpath() (CVE-2018-1100) +Patch40: zsh-5.0.2-CVE-2018-1100.patch + +# fix improper handling of shebang line longer than 64 bytes (CVE-2018-13259) +Patch41: zsh-5.0.2-CVE-2018-13259.patch + +# fix off-by-one error in buffer allocation to avoid stack smashing (#1722486) +Patch42: zsh-5.0.2-PATH_MAX-extra-byte.patch + +BuildRequires: coreutils sed ncurses-devel libcap-devel +BuildRequires: texinfo texi2html gawk hostname +Requires(post): /sbin/install-info grep +Requires(preun): /sbin/install-info +Requires(postun): coreutils grep + +%description +The zsh shell is a command interpreter usable as an interactive login +shell and as a shell script command processor. Zsh resembles the ksh +shell (the Korn shell), but includes many enhancements. Zsh supports +command line editing, built-in spelling correction, programmable +command completion, shell functions (with autoloading), a history +mechanism, and more. + +%package html +Summary: Zsh shell manual in html format +Group: System Environment/Shells + +%description html +The zsh shell is a command interpreter usable as an interactive login +shell and as a shell script command processor. Zsh resembles the ksh +shell (the Korn shell), but includes many enhancements. Zsh supports +command line editing, built-in spelling correction, programmable +command completion, shell functions (with autoloading), a history +mechanism, and more. + +This package contains the Zsh manual in html format. + +%prep + +%setup -q +%patch0 -p1 -b .serial +%patch2 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch33 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 +%patch37 -p1 +%patch38 -p1 +%patch39 -p1 +%patch40 -p1 +%patch41 -p1 +%patch42 -p1 + +cp -p %SOURCE7 . + +%build +%define _bindir /bin +# Avoid stripping... +export LDFLAGS="" +%configure --enable-etcdir=%{_sysconfdir} --with-tcsetpgrp --enable-maildir-support + +make all html + +%check +# Run the testsuite +# the completion tests hang on s390 and s390x + ( cd Test + mkdir skipped +%ifarch s390 s390x ppc ppc64 + mv Y*.ztst skipped +%endif +%ifarch s390 s390x ppc64 + # FIXME: This is a real failure, Debian apparently just don't test. + # RHBZ: 460043 + mv D02glob.ztst skipped +%endif + # FIXME: This hangs in mock + # Running test: Test loading of all compiled modules + mv V01zmodload.ztst skipped + true ) + ZTST_verbose=1 make test + +%install +rm -rf $RPM_BUILD_ROOT +%makeinstall install.info \ + fndir=$RPM_BUILD_ROOT%{_datadir}/zsh/%{version}/functions \ + sitefndir=$RPM_BUILD_ROOT%{_datadir}/zsh/site-functions \ + scriptdir=$RPM_BUILD_ROOT%{_datadir}/zsh/%{version}/scripts \ + sitescriptdir=$RPM_BUILD_ROOT%{_datadir}/zsh/scripts + +install -p %SOURCE8 $RPM_BUILD_ROOT%{_datadir}/zsh/%{version}/functions/_systemd + +rm -f ${RPM_BUILD_ROOT}%{_bindir}/zsh-%{version} +rm -f $RPM_BUILD_ROOT%{_infodir}/dir + +mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir} +for i in %{SOURCE4} %{SOURCE1} %{SOURCE2} %{SOURCE5} %{SOURCE3}; do + install -m 644 $i ${RPM_BUILD_ROOT}%{_sysconfdir}/"$(basename $i .rhs)" +done + +mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/skel +install -m 644 %{SOURCE6} ${RPM_BUILD_ROOT}%{_sysconfdir}/skel/.zshrc + +# This is just here to shut up rpmlint, and is very annoying. +# Note that we can't chmod everything as then rpmlint will complain about +# those without a she-bang line. +for i in checkmail harden run-help zcalc zkbd; do + sed -i -e 's!/usr/local/bin/zsh!%{_bindir}/zsh!' \ + ${RPM_BUILD_ROOT}%{_datadir}/zsh/*/functions/$i + chmod +x ${RPM_BUILD_ROOT}%{_datadir}/zsh/*/functions/$i +done + + +%clean +rm -rf $RPM_BUILD_ROOT + +%post +if [ ! -f %{_sysconfdir}/shells ] ; then + echo "%{_bindir}/zsh" > %{_sysconfdir}/shells +else + grep -q "^%{_bindir}/zsh$" %{_sysconfdir}/shells || echo "%{_bindir}/zsh" >> %{_sysconfdir}/shells +fi + +if [ -f %{_infodir}/zsh.info.gz ]; then +# This is needed so that --excludedocs works. +/sbin/install-info %{_infodir}/zsh.info.gz %{_infodir}/dir \ + --entry="* zsh: (zsh). An enhanced bourne shell." +fi + +: + +%preun +if [ "$1" = 0 ] ; then + if [ -f %{_infodir}/zsh.info.gz ]; then + # This is needed so that --excludedocs works. + /sbin/install-info --delete %{_infodir}/zsh.info.gz %{_infodir}/dir \ + --entry="* zsh: (zsh). An enhanced bourne shell." + fi +fi +: + +%postun +if [ "$1" = 0 ] ; then + if [ -f %{_sysconfdir}/shells ] ; then + TmpFile=`%{_bindir}/mktemp /tmp/.zshrpmXXXXXX` + grep -v '^%{_bindir}/zsh$' %{_sysconfdir}/shells > $TmpFile + cp -f $TmpFile %{_sysconfdir}/shells + rm -f $TmpFile + fi +fi + +%files +%defattr(-,root,root) +%doc README LICENCE Etc/BUGS Etc/CONTRIBUTORS Etc/FAQ FEATURES MACHINES +%doc NEWS Etc/zsh-development-guide Etc/completion-style-guide zshprompt.pl +%attr(755,root,root) %{_bindir}/zsh +%{_mandir}/*/* +%{_infodir}/* +%{_datadir}/zsh +%{_libdir}/zsh +%config(noreplace) %{_sysconfdir}/skel/.z* +%config(noreplace) %{_sysconfdir}/z* + +%files html +%defattr(-,root,root) +%doc Doc/*.html + +%changelog +* Tue Aug 06 2019 Kamil Dudka - 5.0.2-34 +- make the chaselinks option work again (#1729997) +- fix off-by-one error in buffer allocation to avoid stack smashing (#1722486) + +* Mon Mar 04 2019 Kamil Dudka - 5.0.2-33 +- fix regression in oh-my-zsh vcs_info hooks introduced in -30 (#1677696) + +* Fri Nov 09 2018 Kamil Dudka - 5.0.2-32 +- fix improper handling of shebang line longer than 64 bytes (CVE-2018-13259) + +* Fri May 04 2018 Kamil Dudka - 5.0.2-31 +- fix defects detected by Coverity related to CVE-2017-18206 and CVE-2018-1083 + +* Thu May 03 2018 Kamil Dudka - 5.0.2-30 +- fix stack-based buffer overflow in utils.c:checkmailpath() (CVE-2018-1100) +- fix stack-based buffer overflow in gen_matches_files() (CVE-2018-1083) +- fix stack-based buffer overflow in exec.c:hashcmd() (CVE-2018-1071) +- avoid crash when copying empty hash table (CVE-2018-7549) +- fix buffer overrun in xsymlinks (CVE-2017-18206) +- fix NULL dereference in cd (CVE-2017-18205) +- fix buffer overflow when scanning very long path for symlinks (CVE-2014-10072) +- fix buffer overflow for very long fds in >& fd syntax (CVE-2014-10071) + +* Tue Sep 19 2017 Kamil Dudka - 5.0.2-29 +- fix crash while inputting long multi-line strings (#1492595) + +* Thu Feb 16 2017 Kamil Dudka - 5.0.2-28 +- zero new space allocated in prompt buffer (#1408619) + +* Mon Nov 28 2016 Kamil Dudka - 5.0.2-27 +- fix parsing of parameter subscript expression with NOEXEC (#1398740) + +* Mon Oct 17 2016 Kamil Dudka - 5.0.2-26 +- fix crash while parsing the here-document syntax (#1374752) + +* Thu Jul 14 2016 Kamil Dudka - 5.0.2-25 +- improve use of new command substitution in completion (#1356388) + +* Fri Jun 10 2016 Kamil Dudka - 5.0.2-24 +- fix off-by-one error in completion utility cache code (#1344599) + +* Mon May 23 2016 Kamil Dudka - 5.0.2-23 +- fix parse error on a script with unescaped exclamation mark (#1338689) + +* Tue May 17 2016 Kamil Dudka - 5.0.2-22 +- fix alias expansion in history for command substitution (#1321303) + +* Mon May 09 2016 Kamil Dudka - 5.0.2-21 +- improve options handling in the _arguments completion utility (#1334312) + +* Tue Mar 29 2016 Kamil Dudka - 5.0.2-20 +- turn off history word marking in command substitution (#1321303) + +* Tue Mar 01 2016 Kamil Dudka - 5.0.2-19 +- signal-handling related fixes collected from upstream (#1198671) + +* Wed Feb 17 2016 Kamil Dudka - 5.0.2-18 +- prevent zsh from crashing when printing the "out of memory" message (#1302229) + +* Wed Feb 17 2016 Kamil Dudka - 5.0.2-17 +- queue signals while processing a job exit (#1291782) + +* Mon Nov 02 2015 Kamil Dudka - 5.0.2-16 +- fix malloc() signal leak in lexsave() (#1267912) + +* Thu Oct 08 2015 Kamil Dudka - 5.0.2-15 +- fix crash in ksh mode with -n and $HOME (#1267251) + +* Fri Aug 14 2015 Kamil Dudka - 5.0.2-14 +- fix alias handling in command substitution (#1253555) + +* Thu Jul 30 2015 Kamil Dudka - 5.0.2-13 +- fix parser regression introduced by the fix for bug #1241023 + +* Wed Jul 08 2015 Kamil Dudka - 5.0.2-12 +- fix command substitutions to parse contents as they are read in (#1241023) + +* Fri May 22 2015 Kamil Dudka - 5.0.2-11 +- fix SIGSEGV of the syntax check in ksh emulation mode (#1222867) + +* Mon May 18 2015 Kamil Dudka - 5.0.2-10 +- signal safety when updating global state (#1163823) + +* Tue May 05 2015 Kamil Dudka - 5.0.2-9 +- signal safety when updating global state in execshfunc() (#1163823) +- make the wait built-in work for already exited processes (#1162198) +- replace an incorrect comment in /etc/zshenv (#1164312) +- optimize matching of multiple * in wildcards (#1130418) +- use heap rather than stack allocation for variable length arrays (#1165118) +- shell emulation doc addition (#1147545) +- suppress a warning about closing an already closed file descriptor (#1131191) + +* Thu Mar 19 2015 Kamil Dudka - 5.0.2-8 +- fix NOEXEC option in execsimple() optimisation (#1146512) + +* Tue Jan 28 2014 James Antill - 5.0.2-7 +- Remove unneeded build require on tetex. +- Resolves: rhbz#1037828 +- Depend on hostname package instead of /bin/hostname. + +* Fri Jan 24 2014 Daniel Mach - 5.0.2-6 +- Mass rebuild 2014-01-24 + +* Fri Dec 27 2013 Daniel Mach - 5.0.2-5 +- Mass rebuild 2013-12-27 + +* Tue Jun 25 2013 Dominic Hopf - 5.0.2-4 +- up-to-date systemd completion (#949003) +- apply patch for building for aarch64 (#926864) + +* Mon Apr 15 2013 James Antill - 5.0.2-3 +- Fix the changelog dates. +- Fix the texi itemx bug. +- Resolves: bug#927863 + +* Fri Feb 15 2013 Fedora Release Engineering - 5.0.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Tue Jan 08 2013 Dominic Hopf - 5.0.2-1 +- Update to new upstream version: Zsh 5.0.2 + +* Wed Nov 21 2012 Dominic Hopf - 5.0.0-1 +- Update to new upstream version: Zsh 5.0.0 + +* Sun Jul 22 2012 Fedora Release Engineering - 4.3.17-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Sun Mar 04 2012 Dominic Hopf - 4.3.17-1 +- Update to new upstream version: Zsh 4.3.17 + +* Sat Jan 14 2012 Fedora Release Engineering - 4.3.15-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Sat Dec 24 2011 Dominic Hopf - 4.3.15-1 +- Update to new upstream version: Zsh 4.3.15 + +* Sat Dec 17 2011 Dominic Hopf - 4.3.14-2 +- change the License field to MIT (RHBZ#768548) + +* Sat Dec 10 2011 Dominic Hopf - 4.3.14-1 +- Update to new upstream version: Zsh 4.3.14 + +* Sat Dec 03 2011 Dominic Hopf - 4.3.13-1 +- Update to new upstream version: Zsh 4.3.13 + +* Sat Aug 13 2011 Dominic Hopf - 4.3.12-1 +- Update to new upstream version: Zsh 4.3.12 + +* Tue Feb 08 2011 Fedora Release Engineering - 4.3.11-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Thu Jan 20 2011 Christopher Ailon - 4.3.11-1 +- Rebase to upstream version 4.3.11 + +* Tue Dec 7 2010 Toshio Kuratomi - 4.3.10-6 +- Rebuild for FTBFS https://bugzilla.redhat.com/show_bug.cgi?id=631197 +- Remove deprecated PreReq, the packages aren't needed at runtime and they're + already in Requires(post,preun,etc): lines. + +* Mon Mar 22 2010 James Antill - 4.3.10-5 +- Add pathmunge to our /etc/zshrc, for profile.d compat. +- Resolves: bug#548960 + +* Fri Aug 7 2009 James Antill - 4.3.10-4 +- Allow --excludedocs command to work! +- Resolves: bug#515986 + +* Mon Jul 27 2009 Fedora Release Engineering - 4.3.10-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jul 20 2009 James Antill - 4.3.10-1 +- Import new upstream 4.3.10 + +* Wed Jun 10 2009 Karsten Hopp 4.3.9-4.1 +- skip D02glob test on s390, too + +* Mon Mar 2 2009 James Antill - 4.3.9-4 +- Remove D02glob testcase on ppc/ppc64, and hope noone cares + +* Wed Feb 25 2009 Fedora Release Engineering - 4.3.9-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild