diff --git a/tar-1.24-openat-partial-revert.patch b/tar-1.24-openat-partial-revert.patch deleted file mode 100644 index e7bc149..0000000 --- a/tar-1.24-openat-partial-revert.patch +++ /dev/null @@ -1,111 +0,0 @@ -From fd137d96707d776fb2541e3d362825bb650dc786 Mon Sep 17 00:00:00 2001 -From: Kamil Dudka -Date: Mon, 26 Sep 2011 15:36:13 +0200 -Subject: [PATCH 2/2] misc: partially revert upstream commit 4bde4f3 - ---- - src/misc.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- - 1 files changed, 50 insertions(+), 1 deletions(-) - -diff --git a/src/misc.c b/src/misc.c -index b75f2ab..a6e5294 100644 ---- a/src/misc.c -+++ b/src/misc.c -@@ -21,6 +21,7 @@ - #include - #include "common.h" - #include -+#include - #include - #include - #include -@@ -633,6 +634,14 @@ struct wd - /* The directory's name. */ - char const *name; - -+ /* A negative value if no attempt has been made to save the -+ directory, 0 if it was saved successfully, and a positive errno -+ value if it was not saved successfully. */ -+ int err; -+ -+ /* The saved version of the directory, if ERR == 0. */ -+ struct saved_cwd saved_cwd; -+ - /* If nonzero, the file descriptor of the directory, or AT_FDCWD if - the working directory. If zero, the directory needs to be opened - to be used. */ -@@ -687,6 +696,7 @@ chdir_arg (char const *dir) - if (! wd_count) - { - wd[wd_count].name = "."; -+ wd[wd_count].err = -1; - wd[wd_count].fd = AT_FDCWD; - wd_count++; - } -@@ -704,6 +714,7 @@ chdir_arg (char const *dir) - } - - wd[wd_count].name = dir; -+ wd[wd_count].err = -1; - wd[wd_count].fd = 0; - return wd_count++; - } -@@ -728,9 +739,44 @@ chdir_do (int i) - if (chdir_current != i) - { - struct wd *curr = &wd[i]; -+ struct wd *prev = &wd[chdir_current]; - int fd = curr->fd; - -- if (! fd) -+ if (prev->err < 0) -+ { -+ prev->err = 0; -+ if (save_cwd (&prev->saved_cwd) != 0) -+ prev->err = errno; -+ else if (0 <= prev->saved_cwd.desc) -+ { -+ /* Make sure we still have at least one descriptor available. */ -+ int fd1 = prev->saved_cwd.desc; -+ int fd2 = dup (fd1); -+ if (0 <= fd2) -+ close (fd2); -+ else if (errno == EMFILE) -+ { -+ /* Force restore_cwd to use chdir_long. */ -+ close (fd1); -+ prev->saved_cwd.desc = -1; -+ prev->saved_cwd.name = xgetcwd (); -+ if (! prev->saved_cwd.name) -+ prev->err = errno; -+ } -+ else -+ prev->err = errno; -+ } -+ } -+ -+ if (0 <= curr->err) -+ { -+ int err = curr->err; -+ if (err == 0 && restore_cwd (&curr->saved_cwd) != 0) -+ err = errno; -+ if (err) -+ FATAL_ERROR ((0, err, _("Cannot restore working directory"))); -+ } -+ else if (! fd) - { - if (! IS_ABSOLUTE_FILE_NAME (curr->name)) - chdir_do (i - 1); -@@ -741,6 +787,9 @@ chdir_do (int i) - - curr->fd = fd; - -+ if (chdir (curr->name) != 0) -+ chdir_fatal (curr->name); -+ - /* Add I to the cache, tossing out the lowest-ranking entry if the - cache is full. */ - if (wdcache_count < CHDIR_CACHE_SIZE) --- -1.7.4.4 - diff --git a/tar-1.26-arm-config-sub-guess.patch b/tar-1.26-arm-config-sub-guess.patch deleted file mode 100644 index 9acac5d..0000000 --- a/tar-1.26-arm-config-sub-guess.patch +++ /dev/null @@ -1,651 +0,0 @@ -diff --git a/build-aux/config.guess b/build-aux/config.guess -index 187cd54..1804e9f 100755 ---- a/build-aux/config.guess -+++ b/build-aux/config.guess -@@ -2,13 +2,13 @@ - # 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, 2010, --# 2011 Free Software Foundation, Inc. -+# 2011, 2012, 2013 Free Software Foundation, Inc. - --timestamp='2011-02-02' -+timestamp='2012-12-29' - - # 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 --# the Free Software Foundation; either version 2 of the License, or -+# the Free Software Foundation; either version 3 of the License, or - # (at your option) any later version. - # - # This program is distributed in the hope that it will be useful, but -@@ -17,26 +17,22 @@ timestamp='2011-02-02' - # 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 - # configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. -- -- --# Originally written by Per Bothner. Please send patches (context --# diff format) to and include a ChangeLog --# entry. -+# the same distribution terms that you use for the rest of that -+# program. This Exception is an additional permission under section 7 -+# of the GNU General Public License, version 3 ("GPLv3"). - # --# This script attempts to guess a canonical system name similar to --# config.sub. If it succeeds, it prints the system name on stdout, and --# exits with 0. Otherwise, it exits with 1. -+# Originally written by Per Bothner. - # - # You can get the latest version of this script from: - # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD -+# -+# Please send patches with a ChangeLog entry to config-patches@gnu.org. -+ - - me=`echo "$0" | sed -e 's,.*/,,'` - -@@ -57,8 +53,8 @@ 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, 2009, 2010, 2011 Free --Software Foundation, Inc. -+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -+2012, 2013 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." -@@ -145,7 +141,7 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - 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 -@@ -202,6 +198,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - # 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} -@@ -304,7 +304,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - 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:*:*) -@@ -792,21 +792,26 @@ EOF - 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 -@@ -861,6 +866,13 @@ EOF - 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 ;; -@@ -882,20 +894,29 @@ EOF - 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 -@@ -937,7 +958,7 @@ EOF - 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 -@@ -972,13 +993,13 @@ EOF - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - tile*:Linux:*:*) -- echo ${UNAME_MACHINE}-tilera-linux-gnu -+ 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 -@@ -1185,6 +1206,9 @@ EOF - 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 ;; -@@ -1240,7 +1264,7 @@ EOF - NEO-?:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk${UNAME_RELEASE} - exit ;; -- NSE-?:NONSTOP_KERNEL:*:*) -+ NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} - exit ;; - NSR-?:NONSTOP_KERNEL:*:*) -@@ -1309,11 +1333,11 @@ EOF - 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 <. - # - # As a special exception to the GNU General Public License, if you - # distribute this file as part of a program that contains a - # configuration script generated by Autoconf, you may include it under --# the same distribution terms that you use for the rest of that program. -+# the same distribution terms that you use for the rest of that -+# program. This Exception is an additional permission under section 7 -+# of the GNU General Public License, version 3 ("GPLv3"). - - --# Please send patches to . Submit a context --# diff and a properly formatted GNU ChangeLog entry. -+# Please send patches with a ChangeLog entry to config-patches@gnu.org. - # - # Configuration subroutine to validate and canonicalize a configuration type. - # Supply the specified configuration type as an argument. -@@ -76,8 +71,8 @@ version="\ - GNU config.sub ($timestamp) - - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, --2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free --Software Foundation, Inc. -+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, -+2012, 2013 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." -@@ -125,13 +120,17 @@ esac - maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` - case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ -- linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ -+ 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 ] -@@ -154,7 +153,7 @@ case $os in - -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 - ;; -@@ -223,6 +222,12 @@ case $os in - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; -+ -lynx*178) -+ os=-lynxos178 -+ ;; -+ -lynx*5) -+ os=-lynxos5 -+ ;; - -lynx*) - os=-lynxos - ;; -@@ -247,20 +252,27 @@ case $basic_machine in - # 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 \ -+ | arc \ -+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ -+ | 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 \ -@@ -286,22 +298,23 @@ case $basic_machine in - | 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 | tic54x | tic55x | tic6x | 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 - ;; -@@ -314,8 +327,7 @@ case $basic_machine in - c6x) - basic_machine=tic6x-unknown - ;; -- m6811 | m68hc11 | m6812 | m68hc12 | picochip) -- # Motorola 68HC11/12. -+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) - basic_machine=$basic_machine-unknown - os=-none - ;; -@@ -325,6 +337,21 @@ case $basic_machine in - 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. -@@ -339,11 +366,13 @@ case $basic_machine in - # 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-* \ - | clipper-* | craynv-* | cydra-* \ -@@ -352,12 +381,15 @@ case $basic_machine in - | 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-* \ -@@ -382,24 +414,26 @@ case $basic_machine in - | 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-* \ -+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ -+ | tahoe-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ -- | tile-* | tilegx-* \ -+ | 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-*) -@@ -697,7 +731,6 @@ case $basic_machine in - 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 -@@ -755,9 +788,13 @@ case $basic_machine in - 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 -@@ -794,10 +831,18 @@ case $basic_machine in - 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 -@@ -950,9 +995,10 @@ case $basic_machine in - ;; - 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 -@@ -962,7 +1008,7 @@ case $basic_machine in - ;; - ppc64) basic_machine=powerpc64-unknown - ;; -- ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ppc64-* | ppc64p7-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) - basic_machine=powerpc64le-unknown -@@ -977,7 +1023,11 @@ case $basic_machine in - basic_machine=i586-unknown - os=-pw32 - ;; -- rdos) -+ rdos | rdos64) -+ basic_machine=x86_64-pc -+ os=-rdos -+ ;; -+ rdos32) - basic_machine=i386-pc - os=-rdos - ;; -@@ -1046,6 +1096,9 @@ case $basic_machine in - basic_machine=i860-stratus - os=-sysv4 - ;; -+ strongarm-* | thumb-*) -+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; - sun2) - basic_machine=m68000-sun - ;; -@@ -1102,13 +1155,8 @@ case $basic_machine in - basic_machine=t90-cray - os=-unicos - ;; -- # This must be matched before tile*. -- tilegx*) -- basic_machine=tilegx-unknown -- os=-linux-gnu -- ;; - tile*) -- basic_machine=tile-unknown -+ basic_machine=$basic_machine-unknown - os=-linux-gnu - ;; - tx39) -@@ -1178,6 +1226,9 @@ case $basic_machine in - 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 -@@ -1309,15 +1360,15 @@ case $os in - | -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-android* \ -- | -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* \ -@@ -1500,6 +1551,9 @@ case $basic_machine in - c4x-* | tic4x-*) - os=-coff - ;; -+ hexagon-*) -+ os=-elf -+ ;; - tic54x-*) - os=-coff - ;; -@@ -1527,9 +1581,6 @@ case $basic_machine in - ;; - m68000-sun) - os=-sunos3 -- # This also exists in the configure program, but was not the -- # default. -- # os=-sunos4 - ;; - m68*-cisco) - os=-aout diff --git a/tar-1.26-command-args.patch b/tar-1.26-command-args.patch deleted file mode 100644 index c99324e..0000000 --- a/tar-1.26-command-args.patch +++ /dev/null @@ -1,2279 +0,0 @@ -diff --git a/NEWS b/NEWS -index 8f3c416..421e5fa 100644 ---- a/NEWS -+++ b/NEWS -@@ -1,6 +1,24 @@ - GNU tar NEWS - User visible changes. 2012-11-19 - Please send GNU tar bug reports to - -+* Passing command line arguments to external commands. -+ -+Any option taking a command name as its argument now accepts a full -+command line as well. Thus, it is now possible to pass additional -+arguments to invoked programs. The affected options are: -+ -+ --checkpoint-action=exec -+ -I, --use-compress-program -+ -F, --info-script -+ --to-command -+ -+Furthermore, if any additional information is supplied to such a -+command via environment variables, these variables can now be used in -+the command line itself. Care should be taken to escape them, to -+prevent from being expanded too early, for example: -+ -+ tar -x -f a.tar --info-script='changevol $TAR_ARCHIVE $TAR_VOLUME' -+ - ** Sparse files with large data - - When creating a PAX-format archive, tar no longer arbitrarily restricts -diff --git a/doc/tar.texi b/doc/tar.texi -index a0e3d5f..d678db9 100644 ---- a/doc/tar.texi -+++ b/doc/tar.texi -@@ -1801,13 +1801,14 @@ and @option{--interactive} options (@pxref{interactive}). - * Synopsis:: - * using tar options:: - * Styles:: --* All Options:: --* help:: --* defaults:: --* verbose:: --* checkpoints:: --* warnings:: --* interactive:: -+* All Options:: All @command{tar} Options. -+* help:: Where to Get Help. -+* defaults:: What are the Default Values. -+* verbose:: Checking @command{tar} progress. -+* checkpoints:: Checkpoints. -+* warnings:: Controlling Warning Messages. -+* interactive:: Asking for Confirmation During Operations. -+* external:: Running External Commands. - @end menu - - @node Synopsis -@@ -2788,14 +2789,14 @@ Send verbose output to @var{file} instead of to standard output. - - @opsummary{info-script} - @opsummary{new-volume-script} --@item --info-script=@var{script-file} --@itemx --new-volume-script=@var{script-file} --@itemx -F @var{script-file} -+@item --info-script=@var{command} -+@itemx --new-volume-script=@var{command} -+@itemx -F @var{command} - --When @command{tar} is performing multi-tape backups, @var{script-file} is run --at the end of each tape. If @var{script-file} exits with nonzero status, --@command{tar} fails immediately. @xref{info-script}, for a detailed --discussion of @var{script-file}. -+When @command{tar} is performing multi-tape backups, @var{command} is run -+at the end of each tape. If it exits with nonzero status, -+@command{tar} fails immediately. @xref{info-script}, for a detailed -+discussion of this feature. - - @opsummary{interactive} - @item --interactive -@@ -4009,17 +4010,22 @@ checkpoint: - $ @kbd{tar -c --checkpoint=1000 --checkpoint-action=sleep=30} - @end smallexample - -+@anchor{checkpoint exec} - @cindex @code{exec}, checkpoint action --Finally, the @code{exec} action executes a given external program. -+Finally, the @code{exec} action executes a given external command. - For example: - - @smallexample - $ @kbd{tar -c --checkpoint=1000 --checkpoint-action=exec=/sbin/cpoint} - @end smallexample - --This program is executed using @command{/bin/sh -c}, with no --additional arguments. Its exit code is ignored. It gets a copy of --@command{tar}'s environment plus the following variables: -+The supplied command can be any valid command invocation, with or -+without additional command line arguments. If it does contain -+arguments, don't forget to quote it to prevent it from being split by -+the shell. @xref{external, Running External Commands}, for more detail. -+ -+The command gets a copy of @command{tar}'s environment plus the -+following variables: - - @table @env - @vrindex TAR_VERSION, checkpoint script environment -@@ -4049,6 +4055,18 @@ Format of the archive being processed. @xref{Formats}, for a complete - list of archive format names. - @end table - -+These environment variables can also be passed as arguments to the -+command, provided that they are properly escaped, for example: -+ -+@smallexample -+@kbd{tar -c -f arc.tar \ -+ --checkpoint-action='exec=/sbin/cpoint $TAR_FILENAME'} -+@end smallexample -+ -+@noindent -+Notice single quotes to prevent variable names from being expanded by -+the shell when invoking @command{tar}. -+ - Any number of actions can be defined, by supplying several - @option{--checkpoint-action} options in the command line. For - example, the command below displays two messages, pauses -@@ -4263,6 +4281,42 @@ named pipe to receive the archive, and having the consumer process to - read from that named pipe. This has the advantage of letting standard - output free to receive verbose output, all separate from errors. - -+@node external -+@section Running External Commands -+ -+Certain @GNUTAR{} operations imply running external commands that you -+supply on the command line. One of such operations is checkpointing, -+described above (@pxref{checkpoint exec}). Another example of this -+feature is the @option{-I} option, which allows you to supply the -+program to use for compressing or decompressing the archive -+(@pxref{use-compress-program}). -+ -+Whenever such operation is requested, @command{tar} first splits the -+supplied command into words much like the shell does. It then treats -+the first word as the name of the program or the shell script to execute -+and the rest of words as its command line arguments. The program, -+unless given as an absolute file name, is searched in the shell's -+@env{PATH}. -+ -+Any additional information is normally supplied to external commands -+in environment variables, specific to each particular operation. For -+example, the @option{--checkpoint-action=exec} option, defines the -+@env{TAR_ARCHIVE} variable to the name of the archive being worked -+upon. You can, should the need be, use these variables in the -+command line of the external command. For example: -+ -+@smallexample -+$ @kbd{tar -x -f archive.tar \ -+ --checkpoint=exec='printf "%04d in %32s\r" $TAR_CHECKPOINT $TAR_ARCHIVE'} -+@end smallexample -+ -+@noindent -+This command prints for each checkpoint its number and the name of the -+archive, using the same output line on the screen. -+ -+Notice the use of single quotes to prevent variable names from being -+expanded by the shell when invoking @command{tar}. -+ - @node operations - @chapter @GNUTAR{} Operations - -@@ -5460,11 +5514,13 @@ file to the standard input of an external program: - @opindex to-command - @item --to-command=@var{command} - Extract files and pipe their contents to the standard input of --@var{command}. When this option is used, instead of creating the -+@var{command}. When this option is used, instead of creating the - files specified, @command{tar} invokes @var{command} and pipes the --contents of the files to its standard output. The @var{command} may --contain command line arguments. The program is executed via --@code{sh -c}. Notice, that @var{command} is executed once for each regular file -+contents of the files to its standard output. The @var{command} may -+contain command line arguments (see @ref{external, Running External Commands}, -+for more detail). -+ -+Notice, that @var{command} is executed once for each regular file - extracted. Non-regular files (directories, etc.) are ignored when this - option is used. - @end table -@@ -5562,6 +5618,20 @@ Format of the archive being processed. @xref{Formats}, for a complete - list of archive format names. - @end table - -+These variables are defined prior to executing the command, so you can -+pass them as arguments, if you prefer. For example, if the command -+@var{proc} takes the member name and size as its arguments, then you -+could do: -+ -+@smallexample -+$ @kbd{tar -x -f archive.tar \ -+ --to-command='proc $TAR_FILENAME $TAR_SIZE'} -+@end smallexample -+ -+@noindent -+Notice single quotes to prevent variable names from being expanded by -+the shell when invoking @command{tar}. -+ - If @var{command} exits with a non-0 status, @command{tar} will print - an error message similar to the following: - -@@ -8972,21 +9042,29 @@ suffix. The following suffixes are recognized: - @item @samp{.xz} @tab @command{xz} - @end multitable - -+@anchor{use-compress-program} - @opindex use-compress-program --@item --use-compress-program=@var{prog} --@itemx -I=@var{prog} --Use external compression program @var{prog}. Use this option if you -+@item --use-compress-program=@var{command} -+@itemx -I=@var{command} -+Use external compression program @var{command}. Use this option if you - are not happy with the compression program associated with the suffix - at compile time or if you have a compression program that @GNUTAR{} --does not support. There are two requirements to which @var{prog} --should comply: -+does not support. The @var{command} argument is a valid command -+invocation, as you would type it at the command line prompt, with any -+additional options as needed. Enclose it in quotes if it contains -+white space (see @ref{external, Running External Commands}, for more detail). -+ -+The @var{command} should follow two conventions: - --First, when called without options, it should read data from standard --input, compress it and output it on standard output. -+First, when invoked without additional options, it should read data -+from standard input, compress it and output it on standard output. - --Secondly, if called with @option{-d} argument, it should do exactly --the opposite, i.e., read the compressed data from the standard input --and produce uncompressed data on the standard output. -+Secondly, if invoked with the additional @option{-d} option, it should -+do exactly the opposite, i.e., read the compressed data from the -+standard input and produce uncompressed data on the standard output. -+ -+The latter requirement means that you must not use the @option{-d} -+option as a part of the @var{command} itself. - @end table - - @cindex gpg, using with tar -@@ -10458,10 +10536,10 @@ maximum tape length, you might avoid the problem entirely. - - @xopindex{info-script, short description} - @xopindex{new-volume-script, short description} --@item -F @var{file} --@itemx --info-script=@var{file} --@itemx --new-volume-script=@var{file} --Execute @file{file} at end of each tape. This implies -+@item -F @var{command} -+@itemx --info-script=@var{command} -+@itemx --new-volume-script=@var{command} -+Execute @var{command} at end of each tape. This implies - @option{--multi-volume} (@option{-M}). @xref{info-script}, for a detailed - description of this option. - @end table -@@ -11342,19 +11420,20 @@ volume, and instruct @command{tar} to use it instead of its normal - prompting procedure: - - @table @option --@item --info-script=@var{script-name} --@itemx --new-volume-script=@var{script-name} --@itemx -F @var{script-name} --Specify the full name of the volume script to use. The script can be --used to eject cassettes, or to broadcast messages such as -+@item --info-script=@var{command} -+@itemx --new-volume-script=@var{command} -+@itemx -F @var{command} -+Specify the command to invoke when switching volumes. The @var{command} -+can be used to eject cassettes, or to broadcast messages such as - @samp{Someone please come change my tape} when performing unattended - backups. - @end table - --The @var{script-name} is executed without any command line --arguments. It inherits @command{tar}'s shell environment. --Additional data is passed to it via the following --environment variables: -+The @var{command} can contain additional options, if such are needed. -+@xref{external, Running External Commands}, for a detailed discussion -+of the way @GNUTAR{} runs external commands. It inherits -+@command{tar}'s shell environment. Additional data is passed to it -+via the following environment variables: - - @table @env - @vrindex TAR_VERSION, info script environment variable -@@ -11389,6 +11468,10 @@ File descriptor which can be used to communicate the new volume - name to @command{tar}. - @end table - -+These variables can be used in the @var{command} itself, provided that -+they are properly quoted to prevent them from being expanded by the -+shell that invokes @command{tar}. -+ - The volume script can instruct @command{tar} to use new archive name, - by writing in to file descriptor @env{$TAR_FD} (see below for an example). - -diff --git a/lib/Makefile.am b/lib/Makefile.am -index d73fac8..24e12e0 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -28,7 +28,15 @@ BUILT_SOURCES = rmt-command.h - CLEANFILES = rmt-command.h rmt-command.h-t - INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu - --noinst_HEADERS = system.h system-ioctl.h rmt.h paxlib.h stdopen.h xattr-at.h -+noinst_HEADERS = \ -+ paxlib.h\ -+ rmt.h\ -+ stdopen.h\ -+ system.h\ -+ system-ioctl.h\ -+ wordsplit.h\ -+ xattr-at.h -+ - libtar_a_SOURCES = \ - paxerror.c paxexit-status.c paxlib.h paxnames.c \ - prepargs.c prepargs.h \ -@@ -36,6 +44,7 @@ libtar_a_SOURCES = \ - rmt.h \ - stdopen.c stdopen.h \ - system.h system-ioctl.h \ -+ wordsplit.c\ - xattr-at.c - - if !TAR_COND_XATTR_H -diff --git a/lib/wordsplit.c b/lib/wordsplit.c -new file mode 100644 -index 0000000..bd5d59d ---- /dev/null -+++ b/lib/wordsplit.c -@@ -0,0 +1,1625 @@ -+/* wordsplit - a word splitter -+ Copyright (C) 2009-2013 Free Software Foundation, Inc. -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms of the GNU General Public License as published by the -+ Free Software Foundation; either version 3 of the License, or (at your -+ option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ 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, see . -+ -+ Written by Sergey Poznyakoff -+*/ -+ -+#ifdef HAVE_CONFIG_H -+# include -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#if ENABLE_NLS -+# include -+#else -+# define gettext(msgid) msgid -+#endif -+#define _(msgid) gettext (msgid) -+#define N_(msgid) msgid -+ -+#include -+ -+#define ISWS(c) ((c)==' '||(c)=='\t'||(c)=='\n') -+#define ISDELIM(ws,c) \ -+ (strchr ((ws)->ws_delim, (c)) != NULL) -+#define ISPUNCT(c) (strchr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",(c))!=NULL) -+#define ISUPPER(c) ('A' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'Z') -+#define ISLOWER(c) ('a' <= ((unsigned) (c)) && ((unsigned) (c)) <= 'z') -+#define ISALPHA(c) (ISUPPER(c) || ISLOWER(c)) -+#define ISDIGIT(c) ('0' <= ((unsigned) (c)) && ((unsigned) (c)) <= '9') -+#define ISXDIGIT(c) (strchr("abcdefABCDEF", c)!=NULL) -+#define ISALNUM(c) (ISALPHA(c) || ISDIGIT(c)) -+#define ISPRINT(c) (' ' <= ((unsigned) (c)) && ((unsigned) (c)) <= 127) -+ -+#define ALLOC_INIT 128 -+#define ALLOC_INCR 128 -+ -+static void -+_wsplt_alloc_die (struct wordsplit *wsp) -+{ -+ wsp->ws_error (_("memory exhausted")); -+ abort (); -+} -+ -+static void -+_wsplt_error (const char *fmt, ...) -+{ -+ va_list ap; -+ -+ va_start (ap, fmt); -+ vfprintf (stderr, fmt, ap); -+ va_end (ap); -+ fputc ('\n', stderr); -+} -+ -+static void wordsplit_free_nodes (struct wordsplit *); -+ -+static int -+_wsplt_nomem (struct wordsplit *wsp) -+{ -+ errno = ENOMEM; -+ wsp->ws_errno = WRDSE_NOSPACE; -+ if (wsp->ws_flags & WRDSF_ENOMEMABRT) -+ wsp->ws_alloc_die (wsp); -+ if (wsp->ws_flags & WRDSF_SHOWERR) -+ wordsplit_perror (wsp); -+ if (!(wsp->ws_flags & WRDSF_REUSE)) -+ wordsplit_free (wsp); -+ wordsplit_free_nodes (wsp); -+ return wsp->ws_errno; -+} -+ -+static void -+wordsplit_init0 (struct wordsplit *wsp) -+{ -+ if (wsp->ws_flags & WRDSF_REUSE) -+ { -+ if (!(wsp->ws_flags & WRDSF_APPEND)) -+ wordsplit_free_words (wsp); -+ } -+ else -+ { -+ wsp->ws_wordv = NULL; -+ wsp->ws_wordc = 0; -+ wsp->ws_wordn = 0; -+ } -+ -+ wsp->ws_errno = 0; -+ wsp->ws_head = wsp->ws_tail = NULL; -+} -+ -+static int -+wordsplit_init (struct wordsplit *wsp, const char *input, size_t len, -+ int flags) -+{ -+ wsp->ws_flags = flags; -+ -+ if (!(wsp->ws_flags & WRDSF_ALLOC_DIE)) -+ wsp->ws_alloc_die = _wsplt_alloc_die; -+ if (!(wsp->ws_flags & WRDSF_ERROR)) -+ wsp->ws_error = _wsplt_error; -+ -+ if (!(wsp->ws_flags & WRDSF_NOVAR) -+ && !(wsp->ws_flags & (WRDSF_ENV | WRDSF_GETVAR))) -+ { -+ errno = EINVAL; -+ wsp->ws_errno = WRDSE_USAGE; -+ if (wsp->ws_flags & WRDSF_SHOWERR) -+ wordsplit_perror (wsp); -+ return wsp->ws_errno; -+ } -+ -+ if (!(wsp->ws_flags & WRDSF_NOCMD)) -+ { -+ errno = EINVAL; -+ wsp->ws_errno = WRDSE_NOSUPP; -+ if (wsp->ws_flags & WRDSF_SHOWERR) -+ wordsplit_perror (wsp); -+ return wsp->ws_errno; -+ } -+ -+ if (wsp->ws_flags & WRDSF_SHOWDBG) -+ { -+ if (!(wsp->ws_flags & WRDSF_DEBUG)) -+ { -+ if (wsp->ws_flags & WRDSF_ERROR) -+ wsp->ws_debug = wsp->ws_error; -+ else if (wsp->ws_flags & WRDSF_SHOWERR) -+ wsp->ws_debug = _wsplt_error; -+ else -+ wsp->ws_flags &= ~WRDSF_SHOWDBG; -+ } -+ } -+ -+ wsp->ws_input = input; -+ wsp->ws_len = len; -+ -+ if (!(wsp->ws_flags & WRDSF_DOOFFS)) -+ wsp->ws_offs = 0; -+ -+ if (!(wsp->ws_flags & WRDSF_DELIM)) -+ wsp->ws_delim = " \t\n"; -+ -+ if (!(wsp->ws_flags & WRDSF_COMMENT)) -+ wsp->ws_comment = NULL; -+ -+ if (!(wsp->ws_flags & WRDSF_CLOSURE)) -+ wsp->ws_closure = NULL; -+ -+ wsp->ws_endp = 0; -+ -+ wordsplit_init0 (wsp); -+ -+ return 0; -+} -+ -+static int -+alloc_space (struct wordsplit *wsp, size_t count) -+{ -+ size_t offs = (wsp->ws_flags & WRDSF_DOOFFS) ? wsp->ws_offs : 0; -+ char **ptr; -+ size_t newalloc; -+ -+ if (wsp->ws_wordv == NULL) -+ { -+ newalloc = offs + count > ALLOC_INIT ? count : ALLOC_INIT; -+ ptr = calloc (newalloc, sizeof (ptr[0])); -+ } -+ else if (wsp->ws_wordn < offs + wsp->ws_wordc + count) -+ { -+ newalloc = offs + wsp->ws_wordc + -+ (count > ALLOC_INCR ? count : ALLOC_INCR); -+ ptr = realloc (wsp->ws_wordv, newalloc * sizeof (ptr[0])); -+ } -+ else -+ return 0; -+ -+ if (ptr) -+ { -+ wsp->ws_wordn = newalloc; -+ wsp->ws_wordv = ptr; -+ } -+ else -+ return _wsplt_nomem (wsp); -+ return 0; -+} -+ -+ -+/* Node state flags */ -+#define _WSNF_NULL 0x01 /* null node (a noop) */ -+#define _WSNF_WORD 0x02 /* node contains word in v.word */ -+#define _WSNF_QUOTE 0x04 /* text is quoted */ -+#define _WSNF_NOEXPAND 0x08 /* text is not subject to expansion */ -+#define _WSNF_JOIN 0x10 /* node must be joined with the next node */ -+#define _WSNF_SEXP 0x20 /* is a sed expression */ -+ -+#define _WSNF_EMPTYOK 0x0100 /* special flag indicating that -+ wordsplit_add_segm must add the -+ segment even if it is empty */ -+ -+struct wordsplit_node -+{ -+ struct wordsplit_node *prev; /* Previous element */ -+ struct wordsplit_node *next; /* Next element */ -+ int flags; /* Node flags */ -+ union -+ { -+ struct -+ { -+ size_t beg; /* Start of word in ws_input */ -+ size_t end; /* End of word in ws_input */ -+ } segm; -+ char *word; -+ } v; -+}; -+ -+static const char * -+wsnode_flagstr (int flags) -+{ -+ static char retbuf[6]; -+ char *p = retbuf; -+ -+ if (flags & _WSNF_WORD) -+ *p++ = 'w'; -+ else if (flags & _WSNF_NULL) -+ *p++ = 'n'; -+ else -+ *p++ = '-'; -+ if (flags & _WSNF_QUOTE) -+ *p++ = 'q'; -+ else -+ *p++ = '-'; -+ if (flags & _WSNF_NOEXPAND) -+ *p++ = 'E'; -+ else -+ *p++ = '-'; -+ if (flags & _WSNF_JOIN) -+ *p++ = 'j'; -+ else -+ *p++ = '-'; -+ if (flags & _WSNF_SEXP) -+ *p++ = 's'; -+ else -+ *p++ = '-'; -+ *p = 0; -+ return retbuf; -+} -+ -+static const char * -+wsnode_ptr (struct wordsplit *wsp, struct wordsplit_node *p) -+{ -+ if (p->flags & _WSNF_NULL) -+ return ""; -+ else if (p->flags & _WSNF_WORD) -+ return p->v.word; -+ else -+ return wsp->ws_input + p->v.segm.beg; -+} -+ -+static size_t -+wsnode_len (struct wordsplit_node *p) -+{ -+ if (p->flags & _WSNF_NULL) -+ return 0; -+ else if (p->flags & _WSNF_WORD) -+ return strlen (p->v.word); -+ else -+ return p->v.segm.end - p->v.segm.beg; -+} -+ -+static int -+wsnode_new (struct wordsplit *wsp, struct wordsplit_node **pnode) -+{ -+ struct wordsplit_node *node = calloc (1, sizeof (*node)); -+ if (!node) -+ return _wsplt_nomem (wsp); -+ *pnode = node; -+ return 0; -+} -+ -+static void -+wsnode_free (struct wordsplit_node *p) -+{ -+ if (p->flags & _WSNF_WORD) -+ free (p->v.word); -+ free (p); -+} -+ -+static void -+wsnode_append (struct wordsplit *wsp, struct wordsplit_node *node) -+{ -+ node->next = NULL; -+ node->prev = wsp->ws_tail; -+ if (wsp->ws_tail) -+ wsp->ws_tail->next = node; -+ else -+ wsp->ws_head = node; -+ wsp->ws_tail = node; -+} -+ -+static void -+wsnode_remove (struct wordsplit *wsp, struct wordsplit_node *node) -+{ -+ struct wordsplit_node *p; -+ -+ p = node->prev; -+ if (p) -+ { -+ p->next = node->next; -+ if (!node->next) -+ p->flags &= ~_WSNF_JOIN; -+ } -+ else -+ wsp->ws_head = node->next; -+ -+ p = node->next; -+ if (p) -+ p->prev = node->prev; -+ else -+ wsp->ws_tail = node->prev; -+ -+ node->next = node->prev = NULL; -+} -+ -+static void -+wsnode_insert (struct wordsplit *wsp, struct wordsplit_node *node, -+ struct wordsplit_node *anchor, int before) -+{ -+ if (!wsp->ws_head) -+ { -+ node->next = node->prev = NULL; -+ wsp->ws_head = wsp->ws_tail = node; -+ } -+ else if (before) -+ { -+ if (anchor->prev) -+ wsnode_insert (wsp, node, anchor->prev, 0); -+ else -+ { -+ node->prev = NULL; -+ node->next = anchor; -+ anchor->prev = node; -+ wsp->ws_head = node; -+ } -+ } -+ else -+ { -+ struct wordsplit_node *p; -+ -+ p = anchor->next; -+ if (p) -+ p->prev = node; -+ else -+ wsp->ws_tail = node; -+ node->next = p; -+ node->prev = anchor; -+ anchor->next = node; -+ } -+} -+ -+static int -+wordsplit_add_segm (struct wordsplit *wsp, size_t beg, size_t end, int flg) -+{ -+ struct wordsplit_node *node; -+ int rc; -+ -+ if (end == beg && !(flg & _WSNF_EMPTYOK)) -+ return 0; -+ rc = wsnode_new (wsp, &node); -+ if (rc) -+ return rc; -+ node->flags = flg & ~(_WSNF_WORD | _WSNF_EMPTYOK); -+ node->v.segm.beg = beg; -+ node->v.segm.end = end; -+ wsnode_append (wsp, node); -+ return 0; -+} -+ -+static void -+wordsplit_free_nodes (struct wordsplit *wsp) -+{ -+ struct wordsplit_node *p; -+ -+ for (p = wsp->ws_head; p;) -+ { -+ struct wordsplit_node *next = p->next; -+ wsnode_free (p); -+ p = next; -+ } -+ wsp->ws_head = wsp->ws_tail = NULL; -+} -+ -+static void -+wordsplit_dump_nodes (struct wordsplit *wsp) -+{ -+ struct wordsplit_node *p; -+ int n = 0; -+ -+ for (p = wsp->ws_head, n = 0; p; p = p->next, n++) -+ { -+ if (p->flags & _WSNF_WORD) -+ wsp->ws_debug ("%4d: %p: %#04x (%s):%s;", -+ n, p, p->flags, wsnode_flagstr (p->flags), p->v.word); -+ else -+ wsp->ws_debug ("%4d: %p: %#04x (%s):%.*s;", -+ n, p, p->flags, wsnode_flagstr (p->flags), -+ (int) (p->v.segm.end - p->v.segm.beg), -+ wsp->ws_input + p->v.segm.beg); -+ } -+} -+ -+static int -+coalesce_segment (struct wordsplit *wsp, struct wordsplit_node *node) -+{ -+ struct wordsplit_node *p, *end; -+ size_t len = 0; -+ char *buf, *cur; -+ int stop; -+ -+ for (p = node; p && (p->flags & _WSNF_JOIN); p = p->next) -+ { -+ len += wsnode_len (p); -+ } -+ len += wsnode_len (p); -+ end = p; -+ -+ buf = malloc (len + 1); -+ if (!buf) -+ return _wsplt_nomem (wsp); -+ cur = buf; -+ -+ p = node; -+ for (stop = 0; !stop;) -+ { -+ struct wordsplit_node *next = p->next; -+ const char *str = wsnode_ptr (wsp, p); -+ size_t slen = wsnode_len (p); -+ -+ memcpy (cur, str, slen); -+ cur += slen; -+ if (p != node) -+ { -+ wsnode_remove (wsp, p); -+ stop = p == end; -+ wsnode_free (p); -+ } -+ p = next; -+ } -+ -+ *cur = 0; -+ -+ node->flags &= ~_WSNF_JOIN; -+ -+ if (node->flags & _WSNF_WORD) -+ free (node->v.word); -+ else -+ node->flags |= _WSNF_WORD; -+ node->v.word = buf; -+ return 0; -+} -+ -+static int -+wsnode_quoteremoval (struct wordsplit *wsp) -+{ -+ struct wordsplit_node *p; -+ void (*uqfn) (char *, const char *, size_t) = -+ (wsp->ws_flags & WRDSF_CESCAPES) ? -+ wordsplit_c_unquote_copy : wordsplit_sh_unquote_copy; -+ -+ for (p = wsp->ws_head; p; p = p->next) -+ { -+ const char *str = wsnode_ptr (wsp, p); -+ size_t slen = wsnode_len (p); -+ int unquote; -+ -+ if (wsp->ws_flags & WRDSF_QUOTE) -+ { -+ unquote = !(p->flags & _WSNF_NOEXPAND); -+ } -+ else -+ unquote = 0; -+ -+ if (unquote) -+ { -+ if (!(p->flags & _WSNF_WORD)) -+ { -+ char *newstr = malloc (slen + 1); -+ if (!newstr) -+ return _wsplt_nomem (wsp); -+ memcpy (newstr, str, slen); -+ newstr[slen] = 0; -+ p->v.word = newstr; -+ p->flags |= _WSNF_WORD; -+ } -+ -+ if (wsp->ws_flags & WRDSF_ESCAPE) -+ wordsplit_general_unquote_copy (p->v.word, str, slen, -+ wsp->ws_escape); -+ else -+ uqfn (p->v.word, str, slen); -+ } -+ } -+ return 0; -+} -+ -+static int -+wsnode_coalesce (struct wordsplit *wsp) -+{ -+ struct wordsplit_node *p; -+ -+ for (p = wsp->ws_head; p; p = p->next) -+ { -+ if (p->flags & _WSNF_JOIN) -+ if (coalesce_segment (wsp, p)) -+ return 1; -+ } -+ return 0; -+} -+ -+static int -+wordsplit_finish (struct wordsplit *wsp) -+{ -+ struct wordsplit_node *p; -+ size_t n; -+ -+ n = 0; -+ -+ for (p = wsp->ws_head; p; p = p->next) -+ n++; -+ -+ if (alloc_space (wsp, n + 1)) -+ return 1; -+ -+ for (p = wsp->ws_head; p; p = p->next) -+ { -+ const char *str = wsnode_ptr (wsp, p); -+ size_t slen = wsnode_len (p); -+ char *newstr = malloc (slen + 1); -+ -+ /* Assign newstr first, even if it is NULL. This way -+ wordsplit_free will work even if we return -+ nomem later. */ -+ wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = newstr; -+ if (!newstr) -+ return _wsplt_nomem (wsp); -+ memcpy (newstr, str, slen); -+ newstr[slen] = 0; -+ -+ wsp->ws_wordc++; -+ -+ } -+ wsp->ws_wordv[wsp->ws_offs + wsp->ws_wordc] = NULL; -+ return 0; -+} -+ -+ -+/* Variable expansion */ -+static int -+node_split_prefix (struct wordsplit *wsp, -+ struct wordsplit_node **ptail, -+ struct wordsplit_node *node, -+ size_t beg, size_t len, int flg) -+{ -+ struct wordsplit_node *newnode; -+ -+ if (len == 0) -+ return 0; -+ if (wsnode_new (wsp, &newnode)) -+ return 1; -+ wsnode_insert (wsp, newnode, *ptail, 0); -+ if (node->flags & _WSNF_WORD) -+ { -+ const char *str = wsnode_ptr (wsp, node); -+ char *newstr = malloc (len + 1); -+ if (!newstr) -+ return _wsplt_nomem (wsp); -+ memcpy (newstr, str + beg, len); -+ newstr[len] = 0; -+ newnode->flags = _WSNF_WORD; -+ newnode->v.word = newstr; -+ } -+ else -+ { -+ newnode->v.segm.beg = node->v.segm.beg + beg; -+ newnode->v.segm.end = newnode->v.segm.beg + len; -+ } -+ newnode->flags |= flg; -+ *ptail = newnode; -+ return 0; -+} -+ -+static int -+find_closing_cbrace (const char *str, size_t i, size_t len, size_t * poff) -+{ -+ enum -+ { st_init, st_squote, st_dquote } state = st_init; -+ size_t level = 1; -+ -+ for (; i < len; i++) -+ { -+ switch (state) -+ { -+ case st_init: -+ switch (str[i]) -+ { -+ case '{': -+ level++; -+ break; -+ -+ case '}': -+ if (--level == 0) -+ { -+ *poff = i; -+ return 0; -+ } -+ break; -+ -+ case '"': -+ state = st_dquote; -+ break; -+ -+ case '\'': -+ state = st_squote; -+ break; -+ } -+ break; -+ -+ case st_squote: -+ if (str[i] == '\'') -+ state = st_init; -+ break; -+ -+ case st_dquote: -+ if (str[i] == '\\') -+ i++; -+ else if (str[i] == '"') -+ state = st_init; -+ break; -+ } -+ } -+ return 1; -+} -+ -+static const char * -+wordsplit_find_env (struct wordsplit *wsp, const char *name, size_t len) -+{ -+ size_t i; -+ -+ if (!(wsp->ws_flags & WRDSF_ENV)) -+ return NULL; -+ -+ if (wsp->ws_flags & WRDSF_ENV_KV) -+ { -+ /* A key-value pair environment */ -+ for (i = 0; wsp->ws_env[i]; i++) -+ { -+ size_t elen = strlen (wsp->ws_env[i]); -+ if (elen == len && memcmp (wsp->ws_env[i], name, elen) == 0) -+ return wsp->ws_env[i + 1]; -+ /* Skip the value. Break the loop if it is NULL. */ -+ i++; -+ if (wsp->ws_env[i] == NULL) -+ break; -+ } -+ } -+ else -+ { -+ /* Usual (A=B) environment. */ -+ for (i = 0; wsp->ws_env[i]; i++) -+ { -+ size_t j; -+ const char *var = wsp->ws_env[i]; -+ -+ for (j = 0; j < len; j++) -+ if (name[j] != var[j]) -+ break; -+ if (j == len && var[j] == '=') -+ return var + j + 1; -+ } -+ } -+ return NULL; -+} -+ -+static int -+expvar (struct wordsplit *wsp, const char *str, size_t len, -+ struct wordsplit_node **ptail, const char **pend, int flg) -+{ -+ size_t i = 0; -+ const char *defstr = NULL; -+ const char *value; -+ const char *vptr; -+ struct wordsplit_node *newnode; -+ const char *start = str - 1; -+ -+ if (ISALPHA (str[0]) || str[0] == '_') -+ { -+ for (i = 1; i < len; i++) -+ if (!(ISALNUM (str[i]) || str[i] == '_')) -+ break; -+ *pend = str + i - 1; -+ } -+ else if (str[0] == '{') -+ { -+ str++; -+ len--; -+ for (i = 1; i < len; i++) -+ if (str[i] == '}' || str[i] == ':') -+ break; -+ if (str[i] == ':') -+ { -+ size_t j; -+ -+ defstr = str + i + 1; -+ if (find_closing_cbrace (str, i + 1, len, &j)) -+ { -+ wsp->ws_errno = WRDSE_CBRACE; -+ return 1; -+ } -+ *pend = str + j; -+ } -+ else if (str[i] == '}') -+ { -+ defstr = NULL; -+ *pend = str + i; -+ } -+ else -+ { -+ wsp->ws_errno = WRDSE_CBRACE; -+ return 1; -+ } -+ } -+ else -+ { -+ if (wsnode_new (wsp, &newnode)) -+ return 1; -+ wsnode_insert (wsp, newnode, *ptail, 0); -+ *ptail = newnode; -+ newnode->flags = _WSNF_WORD | flg; -+ newnode->v.word = malloc (3); -+ if (!newnode->v.word) -+ return _wsplt_nomem (wsp); -+ newnode->v.word[0] = '$'; -+ newnode->v.word[1] = str[0]; -+ newnode->v.word[2] = 0; -+ *pend = str; -+ return 0; -+ } -+ -+ /* Actually expand the variable */ -+ /* str - start of the variable name -+ i - its length -+ defstr - default replacement str */ -+ -+ vptr = wordsplit_find_env (wsp, str, i); -+ if (vptr) -+ { -+ value = strdup (vptr); -+ if (!value) -+ return _wsplt_nomem (wsp); -+ } -+ else if (wsp->ws_flags & WRDSF_GETVAR) -+ value = wsp->ws_getvar (str, i, wsp->ws_closure); -+ else if (wsp->ws_flags & WRDSF_UNDEF) -+ { -+ wsp->ws_errno = WRDSE_UNDEF; -+ if (wsp->ws_flags & WRDSF_SHOWERR) -+ wordsplit_perror (wsp); -+ return 1; -+ } -+ else -+ { -+ if (wsp->ws_flags & WRDSF_WARNUNDEF) -+ wsp->ws_error (_("warning: undefined variable `%.*s'"), (int) i, str); -+ if (wsp->ws_flags & WRDSF_KEEPUNDEF) -+ value = NULL; -+ else -+ value = ""; -+ } -+ /* FIXME: handle defstr */ -+ if (value) -+ { -+ if (flg & _WSNF_QUOTE) -+ { -+ if (wsnode_new (wsp, &newnode)) -+ return 1; -+ wsnode_insert (wsp, newnode, *ptail, 0); -+ *ptail = newnode; -+ newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg; -+ newnode->v.word = strdup (value); -+ if (!newnode->v.word) -+ return _wsplt_nomem (wsp); -+ } -+ else if (*value == 0) -+ { -+ /* Empty string is a special case */ -+ if (wsnode_new (wsp, &newnode)) -+ return 1; -+ wsnode_insert (wsp, newnode, *ptail, 0); -+ *ptail = newnode; -+ newnode->flags = _WSNF_NULL; -+ } -+ else -+ { -+ struct wordsplit ws; -+ int i; -+ -+ ws.ws_delim = wsp->ws_delim; -+ if (wordsplit (value, &ws, -+ WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM | WRDSF_WS)) -+ { -+ wordsplit_free (&ws); -+ return 1; -+ } -+ for (i = 0; i < ws.ws_wordc; i++) -+ { -+ if (wsnode_new (wsp, &newnode)) -+ return 1; -+ wsnode_insert (wsp, newnode, *ptail, 0); -+ *ptail = newnode; -+ newnode->flags = _WSNF_WORD | -+ _WSNF_NOEXPAND | -+ (i + 1 < ws.ws_wordc ? (flg & ~_WSNF_JOIN) : flg); -+ newnode->v.word = strdup (ws.ws_wordv[i]); -+ if (!newnode->v.word) -+ return _wsplt_nomem (wsp); -+ } -+ wordsplit_free (&ws); -+ } -+ } -+ else if (wsp->ws_flags & WRDSF_KEEPUNDEF) -+ { -+ size_t size = *pend - start + 1; -+ -+ if (wsnode_new (wsp, &newnode)) -+ return 1; -+ wsnode_insert (wsp, newnode, *ptail, 0); -+ *ptail = newnode; -+ newnode->flags = _WSNF_WORD | _WSNF_NOEXPAND | flg; -+ newnode->v.word = malloc (size + 1); -+ if (!newnode->v.word) -+ return _wsplt_nomem (wsp); -+ memcpy (newnode->v.word, start, size); -+ newnode->v.word[size] = 0; -+ } -+ else -+ { -+ if (wsnode_new (wsp, &newnode)) -+ return 1; -+ wsnode_insert (wsp, newnode, *ptail, 0); -+ *ptail = newnode; -+ newnode->flags = _WSNF_NULL; -+ } -+ return 0; -+} -+ -+static int -+node_expand_vars (struct wordsplit *wsp, struct wordsplit_node *node) -+{ -+ const char *str = wsnode_ptr (wsp, node); -+ size_t slen = wsnode_len (node); -+ const char *end = str + slen; -+ const char *p; -+ size_t off = 0; -+ struct wordsplit_node *tail = node; -+ -+ for (p = str; p < end; p++) -+ { -+ if (*p == '\\') -+ { -+ p++; -+ continue; -+ } -+ if (*p == '$') -+ { -+ size_t n = p - str; -+ -+ if (tail != node) -+ tail->flags |= _WSNF_JOIN; -+ if (node_split_prefix (wsp, &tail, node, off, n, _WSNF_JOIN)) -+ return 1; -+ p++; -+ if (expvar (wsp, p, slen - n, &tail, &p, -+ node->flags & (_WSNF_JOIN | _WSNF_QUOTE))) -+ return 1; -+ off += p - str + 1; -+ str = p + 1; -+ } -+ } -+ if (p > str) -+ { -+ if (tail != node) -+ tail->flags |= _WSNF_JOIN; -+ if (node_split_prefix (wsp, &tail, node, off, p - str, -+ node->flags & _WSNF_JOIN)) -+ return 1; -+ } -+ if (tail != node) -+ { -+ wsnode_remove (wsp, node); -+ wsnode_free (node); -+ } -+ return 0; -+} -+ -+/* Remove NULL lists */ -+static void -+wsnode_nullelim (struct wordsplit *wsp) -+{ -+ struct wordsplit_node *p; -+ -+ for (p = wsp->ws_head; p;) -+ { -+ struct wordsplit_node *next = p->next; -+ if (p->flags & _WSNF_NULL) -+ { -+ wsnode_remove (wsp, p); -+ wsnode_free (p); -+ } -+ p = next; -+ } -+} -+ -+static int -+wordsplit_varexp (struct wordsplit *wsp) -+{ -+ struct wordsplit_node *p; -+ -+ for (p = wsp->ws_head; p;) -+ { -+ struct wordsplit_node *next = p->next; -+ if (!(p->flags & _WSNF_NOEXPAND)) -+ if (node_expand_vars (wsp, p)) -+ return 1; -+ p = next; -+ } -+ -+ wsnode_nullelim (wsp); -+ return 0; -+} -+ -+/* Strip off any leading and trailing whitespace. This function is called -+ right after the initial scanning, therefore it assumes that every -+ node in the list is a text reference node. */ -+static void -+wordsplit_trimws (struct wordsplit *wsp) -+{ -+ struct wordsplit_node *p; -+ -+ for (p = wsp->ws_head; p; p = p->next) -+ { -+ size_t n; -+ -+ if (p->flags & _WSNF_QUOTE) -+ continue; -+ -+ /* Skip leading whitespace: */ -+ for (n = p->v.segm.beg; n < p->v.segm.end && ISWS (wsp->ws_input[n]); -+ n++) -+ ; -+ p->v.segm.beg = n; -+ /* Trim trailing whitespace */ -+ for (n = p->v.segm.end; -+ n > p->v.segm.beg && ISWS (wsp->ws_input[n - 1]); n--); -+ p->v.segm.end = n; -+ if (p->v.segm.beg == p->v.segm.end) -+ p->flags |= _WSNF_NULL; -+ } -+ -+ wsnode_nullelim (wsp); -+} -+ -+static int -+skip_sed_expr (const char *command, size_t i, size_t len) -+{ -+ int state; -+ -+ do -+ { -+ int delim; -+ -+ if (command[i] == ';') -+ i++; -+ if (!(command[i] == 's' && i + 3 < len && ISPUNCT (command[i + 1]))) -+ break; -+ -+ delim = command[++i]; -+ state = 1; -+ for (i++; i < len; i++) -+ { -+ if (state == 3) -+ { -+ if (command[i] == delim || !ISALNUM (command[i])) -+ break; -+ } -+ else if (command[i] == '\\') -+ i++; -+ else if (command[i] == delim) -+ state++; -+ } -+ } -+ while (state == 3 && i < len && command[i] == ';'); -+ return i; -+} -+ -+static size_t -+skip_delim (struct wordsplit *wsp) -+{ -+ size_t start = wsp->ws_endp; -+ if (wsp->ws_flags & WRDSF_SQUEEZE_DELIMS) -+ { -+ if ((wsp->ws_flags & WRDSF_RETURN_DELIMS) && -+ ISDELIM (wsp, wsp->ws_input[start])) -+ { -+ int delim = wsp->ws_input[start]; -+ do -+ start++; -+ while (start < wsp->ws_len && delim == wsp->ws_input[start]); -+ } -+ else -+ { -+ do -+ start++; -+ while (start < wsp->ws_len && ISDELIM (wsp, wsp->ws_input[start])); -+ } -+ start--; -+ } -+ -+ if (!(wsp->ws_flags & WRDSF_RETURN_DELIMS)) -+ start++; -+ -+ return start; -+} -+ -+#define _WRDS_EOF 0 -+#define _WRDS_OK 1 -+#define _WRDS_ERR 2 -+ -+static int -+scan_qstring (struct wordsplit *wsp, size_t start, size_t * end) -+{ -+ size_t j; -+ const char *command = wsp->ws_input; -+ size_t len = wsp->ws_len; -+ char q = command[start]; -+ -+ for (j = start + 1; j < len && command[j] != q; j++) -+ if (q == '"' && command[j] == '\\') -+ j++; -+ if (j < len && command[j] == q) -+ { -+ int flags = _WSNF_QUOTE | _WSNF_EMPTYOK; -+ if (q == '\'') -+ flags |= _WSNF_NOEXPAND; -+ if (wordsplit_add_segm (wsp, start + 1, j, flags)) -+ return _WRDS_ERR; -+ *end = j; -+ } -+ else -+ { -+ wsp->ws_endp = start; -+ wsp->ws_errno = WRDSE_QUOTE; -+ if (wsp->ws_flags & WRDSF_SHOWERR) -+ wordsplit_perror (wsp); -+ return _WRDS_ERR; -+ } -+ return 0; -+} -+ -+static int -+scan_word (struct wordsplit *wsp, size_t start) -+{ -+ size_t len = wsp->ws_len; -+ const char *command = wsp->ws_input; -+ const char *comment = wsp->ws_comment; -+ int join = 0; -+ int flags = 0; -+ -+ size_t i = start; -+ -+ if (i >= len) -+ { -+ wsp->ws_errno = WRDSE_EOF; -+ return _WRDS_EOF; -+ } -+ -+ start = i; -+ -+ if (wsp->ws_flags & WRDSF_SED_EXPR -+ && command[i] == 's' && i + 3 < len && ISPUNCT (command[i + 1])) -+ { -+ flags = _WSNF_SEXP; -+ i = skip_sed_expr (command, i, len); -+ } -+ else if (!ISDELIM (wsp, command[i])) -+ { -+ while (i < len) -+ { -+ if (comment && strchr (comment, command[i]) != NULL) -+ { -+ size_t j; -+ for (j = i + 1; j < len && command[j] != '\n'; j++) -+ ; -+ if (wordsplit_add_segm (wsp, start, i, 0)) -+ return _WRDS_ERR; -+ wsp->ws_endp = j; -+ return _WRDS_OK; -+ } -+ -+ if (wsp->ws_flags & WRDSF_QUOTE) -+ { -+ if (command[i] == '\\') -+ { -+ if (++i == len) -+ break; -+ i++; -+ continue; -+ } -+ -+ if (((wsp->ws_flags & WRDSF_SQUOTE) && command[i] == '\'') || -+ ((wsp->ws_flags & WRDSF_DQUOTE) && command[i] == '"')) -+ { -+ if (join && wsp->ws_tail) -+ wsp->ws_tail->flags |= _WSNF_JOIN; -+ if (wordsplit_add_segm (wsp, start, i, _WSNF_JOIN)) -+ return _WRDS_ERR; -+ if (scan_qstring (wsp, i, &i)) -+ return _WRDS_ERR; -+ start = i + 1; -+ join = 1; -+ } -+ } -+ -+ if (ISDELIM (wsp, command[i])) -+ break; -+ else -+ i++; -+ } -+ } -+ else if (wsp->ws_flags & WRDSF_RETURN_DELIMS) -+ { -+ i++; -+ } -+ else if (!(wsp->ws_flags & WRDSF_SQUEEZE_DELIMS)) -+ flags |= _WSNF_EMPTYOK; -+ -+ if (join && i > start && wsp->ws_tail) -+ wsp->ws_tail->flags |= _WSNF_JOIN; -+ if (wordsplit_add_segm (wsp, start, i, flags)) -+ return _WRDS_ERR; -+ wsp->ws_endp = i; -+ if (wsp->ws_flags & WRDSF_INCREMENTAL) -+ return _WRDS_EOF; -+ return _WRDS_OK; -+} -+ -+static char quote_transtab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v"; -+ -+int -+wordsplit_c_unquote_char (int c) -+{ -+ char *p; -+ -+ for (p = quote_transtab; *p; p += 2) -+ { -+ if (*p == c) -+ return p[1]; -+ } -+ return c; -+} -+ -+int -+wordsplit_c_quote_char (int c) -+{ -+ char *p; -+ -+ for (p = quote_transtab + sizeof (quote_transtab) - 2; -+ p > quote_transtab; p -= 2) -+ { -+ if (*p == c) -+ return p[-1]; -+ } -+ return -1; -+} -+ -+#define to_num(c) \ -+ (ISDIGIT(c) ? c - '0' : (ISXDIGIT(c) ? toupper(c) - 'A' + 10 : 255 )) -+ -+static int -+xtonum (int *pval, const char *src, int base, int cnt) -+{ -+ int i, val; -+ -+ for (i = 0, val = 0; i < cnt; i++, src++) -+ { -+ int n = *(unsigned char *) src; -+ if (n > 127 || (n = to_num (n)) >= base) -+ break; -+ val = val * base + n; -+ } -+ *pval = val; -+ return i; -+} -+ -+size_t -+wordsplit_c_quoted_length (const char *str, int quote_hex, int *quote) -+{ -+ size_t len = 0; -+ -+ *quote = 0; -+ for (; *str; str++) -+ { -+ if (strchr (" \"", *str)) -+ *quote = 1; -+ -+ if (*str == ' ') -+ len++; -+ else if (*str == '"') -+ len += 2; -+ else if (*str != '\t' && *str != '\\' && ISPRINT (*str)) -+ len++; -+ else if (quote_hex) -+ len += 3; -+ else -+ { -+ if (wordsplit_c_quote_char (*str) != -1) -+ len += 2; -+ else -+ len += 4; -+ } -+ } -+ return len; -+} -+ -+void -+wordsplit_general_unquote_copy (char *dst, const char *src, size_t n, -+ const char *escapable) -+{ -+ int i; -+ -+ for (i = 0; i < n;) -+ { -+ if (src[i] == '\\' && i < n && strchr (escapable, src[i + 1])) -+ i++; -+ *dst++ = src[i++]; -+ } -+ *dst = 0; -+} -+ -+void -+wordsplit_sh_unquote_copy (char *dst, const char *src, size_t n) -+{ -+ int i; -+ -+ for (i = 0; i < n;) -+ { -+ if (src[i] == '\\') -+ i++; -+ *dst++ = src[i++]; -+ } -+ *dst = 0; -+} -+ -+void -+wordsplit_c_unquote_copy (char *dst, const char *src, size_t n) -+{ -+ int i = 0; -+ int c; -+ -+ while (i < n) -+ { -+ if (src[i] == '\\') -+ { -+ ++i; -+ if (src[i] == 'x' || src[i] == 'X') -+ { -+ if (n - i < 2) -+ { -+ *dst++ = '\\'; -+ *dst++ = src[i++]; -+ } -+ else -+ { -+ int off = xtonum (&c, src + i + 1, -+ 16, 2); -+ if (off == 0) -+ { -+ *dst++ = '\\'; -+ *dst++ = src[i++]; -+ } -+ else -+ { -+ *dst++ = c; -+ i += off + 1; -+ } -+ } -+ } -+ else if ((unsigned char) src[i] < 128 && ISDIGIT (src[i])) -+ { -+ if (n - i < 1) -+ { -+ *dst++ = '\\'; -+ *dst++ = src[i++]; -+ } -+ else -+ { -+ int off = xtonum (&c, src + i, 8, 3); -+ if (off == 0) -+ { -+ *dst++ = '\\'; -+ *dst++ = src[i++]; -+ } -+ else -+ { -+ *dst++ = c; -+ i += off; -+ } -+ } -+ } -+ else -+ *dst++ = wordsplit_c_unquote_char (src[i++]); -+ } -+ else -+ *dst++ = src[i++]; -+ } -+ *dst = 0; -+} -+ -+void -+wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex) -+{ -+ for (; *src; src++) -+ { -+ if (*src == '"') -+ { -+ *dst++ = '\\'; -+ *dst++ = *src; -+ } -+ else if (*src != '\t' && *src != '\\' && ISPRINT (*src)) -+ *dst++ = *src; -+ else -+ { -+ char tmp[4]; -+ -+ if (quote_hex) -+ { -+ snprintf (tmp, sizeof tmp, "%%%02X", *(unsigned char *) src); -+ memcpy (dst, tmp, 3); -+ dst += 3; -+ } -+ else -+ { -+ int c = wordsplit_c_quote_char (*src); -+ *dst++ = '\\'; -+ if (c != -1) -+ *dst++ = c; -+ else -+ { -+ snprintf (tmp, sizeof tmp, "%03o", *(unsigned char *) src); -+ memcpy (dst, tmp, 3); -+ dst += 3; -+ } -+ } -+ } -+ } -+} -+ -+static int -+wordsplit_process_list (struct wordsplit *wsp, size_t start) -+{ -+ if (wsp->ws_flags & WRDSF_NOSPLIT) -+ { -+ /* Treat entire input as a quoted argument */ -+ if (wordsplit_add_segm (wsp, start, wsp->ws_len, _WSNF_QUOTE)) -+ return wsp->ws_errno; -+ } -+ else -+ { -+ int rc; -+ -+ while ((rc = scan_word (wsp, start)) == _WRDS_OK) -+ start = skip_delim (wsp); -+ /* Make sure tail element is not joinable */ -+ if (wsp->ws_tail) -+ wsp->ws_tail->flags &= ~_WSNF_JOIN; -+ if (rc == _WRDS_ERR) -+ return wsp->ws_errno; -+ } -+ -+ if (wsp->ws_flags & WRDSF_SHOWDBG) -+ { -+ wsp->ws_debug ("Initial list:"); -+ wordsplit_dump_nodes (wsp); -+ } -+ -+ if (wsp->ws_flags & WRDSF_WS) -+ { -+ /* Trim leading and trailing whitespace */ -+ wordsplit_trimws (wsp); -+ if (wsp->ws_flags & WRDSF_SHOWDBG) -+ { -+ wsp->ws_debug ("After WS trimming:"); -+ wordsplit_dump_nodes (wsp); -+ } -+ } -+ -+ /* Expand variables (FIXME: & commands) */ -+ if (!(wsp->ws_flags & WRDSF_NOVAR)) -+ { -+ if (wordsplit_varexp (wsp)) -+ { -+ wordsplit_free_nodes (wsp); -+ return wsp->ws_errno; -+ } -+ if (wsp->ws_flags & WRDSF_SHOWDBG) -+ { -+ wsp->ws_debug ("Expanded list:"); -+ wordsplit_dump_nodes (wsp); -+ } -+ } -+ -+ do -+ { -+ if (wsnode_quoteremoval (wsp)) -+ break; -+ if (wsp->ws_flags & WRDSF_SHOWDBG) -+ { -+ wsp->ws_debug ("After quote removal:"); -+ wordsplit_dump_nodes (wsp); -+ } -+ -+ if (wsnode_coalesce (wsp)) -+ break; -+ -+ if (wsp->ws_flags & WRDSF_SHOWDBG) -+ { -+ wsp->ws_debug ("Coalesced list:"); -+ wordsplit_dump_nodes (wsp); -+ } -+ } -+ while (0); -+ return wsp->ws_errno; -+} -+ -+int -+wordsplit_len (const char *command, size_t length, struct wordsplit *wsp, -+ int flags) -+{ -+ int rc; -+ size_t start; -+ const char *cmdptr; -+ size_t cmdlen; -+ -+ if (!command) -+ { -+ if (!(flags & WRDSF_INCREMENTAL)) -+ return EINVAL; -+ -+ start = skip_delim (wsp); -+ if (wsp->ws_endp == wsp->ws_len) -+ { -+ wsp->ws_errno = WRDSE_NOINPUT; -+ if (wsp->ws_flags & WRDSF_SHOWERR) -+ wordsplit_perror (wsp); -+ return wsp->ws_errno; -+ } -+ -+ cmdptr = wsp->ws_input + wsp->ws_endp; -+ cmdlen = wsp->ws_len - wsp->ws_endp; -+ wsp->ws_flags |= WRDSF_REUSE; -+ wordsplit_init0 (wsp); -+ } -+ else -+ { -+ cmdptr = command; -+ cmdlen = length; -+ start = 0; -+ rc = wordsplit_init (wsp, cmdptr, cmdlen, flags); -+ if (rc) -+ return rc; -+ } -+ -+ if (wsp->ws_flags & WRDSF_SHOWDBG) -+ wsp->ws_debug ("Input:%.*s;", (int) cmdlen, cmdptr); -+ -+ rc = wordsplit_process_list (wsp, start); -+ if (rc == 0 && (flags & WRDSF_INCREMENTAL)) -+ { -+ while (!wsp->ws_head && wsp->ws_endp < wsp->ws_len) -+ { -+ start = skip_delim (wsp); -+ if (wsp->ws_flags & WRDSF_SHOWDBG) -+ { -+ cmdptr = wsp->ws_input + wsp->ws_endp; -+ cmdlen = wsp->ws_len - wsp->ws_endp; -+ wsp->ws_debug ("Restart:%.*s;", (int) cmdlen, cmdptr); -+ } -+ rc = wordsplit_process_list (wsp, start); -+ if (rc) -+ break; -+ } -+ } -+ if (rc) -+ { -+ wordsplit_free_nodes (wsp); -+ return rc; -+ } -+ wordsplit_finish (wsp); -+ wordsplit_free_nodes (wsp); -+ return wsp->ws_errno; -+} -+ -+int -+wordsplit (const char *command, struct wordsplit *ws, int flags) -+{ -+ return wordsplit_len (command, command ? strlen (command) : 0, ws, -+ flags); -+} -+ -+void -+wordsplit_free_words (struct wordsplit *ws) -+{ -+ size_t i; -+ -+ for (i = 0; i < ws->ws_wordc; i++) -+ { -+ char *p = ws->ws_wordv[ws->ws_offs + i]; -+ if (p) -+ { -+ free (p); -+ ws->ws_wordv[ws->ws_offs + i] = NULL; -+ } -+ } -+ ws->ws_wordc = 0; -+} -+ -+void -+wordsplit_free (struct wordsplit *ws) -+{ -+ wordsplit_free_words (ws); -+ free (ws->ws_wordv); -+ ws->ws_wordv = NULL; -+} -+ -+void -+wordsplit_perror (struct wordsplit *wsp) -+{ -+ switch (wsp->ws_errno) -+ { -+ case WRDSE_EOF: -+ wsp->ws_error (_("no error")); -+ break; -+ -+ case WRDSE_QUOTE: -+ wsp->ws_error (_("missing closing %c (start near #%lu)"), -+ wsp->ws_input[wsp->ws_endp], -+ (unsigned long) wsp->ws_endp); -+ break; -+ -+ case WRDSE_NOSPACE: -+ wsp->ws_error (_("memory exhausted")); -+ break; -+ -+ case WRDSE_NOSUPP: -+ wsp->ws_error (_("command substitution is not yet supported")); -+ -+ case WRDSE_USAGE: -+ wsp->ws_error (_("invalid wordsplit usage")); -+ break; -+ -+ case WRDSE_CBRACE: -+ wsp->ws_error (_("unbalanced curly brace")); -+ break; -+ -+ case WRDSE_UNDEF: -+ wsp->ws_error (_("undefined variable")); -+ break; -+ -+ case WRDSE_NOINPUT: -+ wsp->ws_error (_("input exhausted")); -+ break; -+ -+ default: -+ wsp->ws_error (_("unknown error")); -+ } -+} -+ -+const char *_wordsplit_errstr[] = { -+ N_("no error"), -+ N_("missing closing quote"), -+ N_("memory exhausted"), -+ N_("command substitution is not yet supported"), -+ N_("invalid wordsplit usage"), -+ N_("unbalanced curly brace"), -+ N_("undefined variable"), -+ N_("input exhausted") -+}; -+int _wordsplit_nerrs = -+ sizeof (_wordsplit_errstr) / sizeof (_wordsplit_errstr[0]); -+ -+const char * -+wordsplit_strerror (struct wordsplit *ws) -+{ -+ if (ws->ws_errno < _wordsplit_nerrs) -+ return _wordsplit_errstr[ws->ws_errno]; -+ return N_("unknown error"); -+} -diff --git a/lib/wordsplit.h b/lib/wordsplit.h -new file mode 100644 -index 0000000..b48e3cd ---- /dev/null -+++ b/lib/wordsplit.h -@@ -0,0 +1,162 @@ -+/* wordsplit - a word splitter -+ Copyright (C) 2009-2013 Free Software Foundation, Inc. -+ -+ This program is free software; you can redistribute it and/or modify it -+ under the terms of the GNU General Public License as published by the -+ Free Software Foundation; either version 3 of the License, or (at your -+ option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ 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, see . -+ -+ Written by Sergey Poznyakoff -+*/ -+ -+#ifndef __WORDSPLIT_H -+#define __WORDSPLIT_H -+ -+#include -+ -+struct wordsplit -+{ -+ size_t ws_wordc; -+ char **ws_wordv; -+ size_t ws_offs; -+ size_t ws_wordn; -+ int ws_flags; -+ const char *ws_delim; -+ const char *ws_comment; -+ const char *ws_escape; -+ void (*ws_alloc_die) (struct wordsplit * wsp); -+ void (*ws_error) (const char *, ...) -+ __attribute__ ((__format__ (__printf__, 1, 2))); -+ void (*ws_debug) (const char *, ...) -+ __attribute__ ((__format__ (__printf__, 1, 2))); -+ -+ const char **ws_env; -+ const char *(*ws_getvar) (const char *, size_t, void *); -+ void *ws_closure; -+ -+ const char *ws_input; -+ size_t ws_len; -+ size_t ws_endp; -+ int ws_errno; -+ struct wordsplit_node *ws_head, *ws_tail; -+}; -+ -+/* Wordsplit flags. Only 2 bits of a 32-bit word remain unused. -+ It is getting crowded... */ -+/* Append the words found to the array resulting from a previous -+ call. */ -+#define WRDSF_APPEND 0x00000001 -+/* Insert we_offs initial NULLs in the array ws_wordv. -+ (These are not counted in the returned ws_wordc.) */ -+#define WRDSF_DOOFFS 0x00000002 -+/* Don't do command substitution. Reserved for future use. */ -+#define WRDSF_NOCMD 0x00000004 -+/* The parameter p resulted from a previous call to -+ wordsplit(), and wordsplit_free() was not called. Reuse the -+ allocated storage. */ -+#define WRDSF_REUSE 0x00000008 -+/* Print errors */ -+#define WRDSF_SHOWERR 0x00000010 -+/* Consider it an error if an undefined shell variable -+ is expanded. */ -+#define WRDSF_UNDEF 0x00000020 -+ -+/* Don't do variable expansion. */ -+#define WRDSF_NOVAR 0x00000040 -+/* Abort on ENOMEM error */ -+#define WRDSF_ENOMEMABRT 0x00000080 -+/* Trim off any leading and trailind whitespace */ -+#define WRDSF_WS 0x00000100 -+/* Handle single quotes */ -+#define WRDSF_SQUOTE 0x00000200 -+/* Handle double quotes */ -+#define WRDSF_DQUOTE 0x00000400 -+/* Handle quotes and escape directives */ -+#define WRDSF_QUOTE (WRDSF_SQUOTE|WRDSF_DQUOTE) -+/* Replace each input sequence of repeated delimiters with a single -+ delimiter */ -+#define WRDSF_SQUEEZE_DELIMS 0x00000800 -+/* Return delimiters */ -+#define WRDSF_RETURN_DELIMS 0x00001000 -+/* Treat sed expressions as words */ -+#define WRDSF_SED_EXPR 0x00002000 -+/* ws_delim field is initialized */ -+#define WRDSF_DELIM 0x00004000 -+/* ws_comment field is initialized */ -+#define WRDSF_COMMENT 0x00008000 -+/* ws_alloc_die field is initialized */ -+#define WRDSF_ALLOC_DIE 0x00010000 -+/* ws_error field is initialized */ -+#define WRDSF_ERROR 0x00020000 -+/* ws_debug field is initialized */ -+#define WRDSF_DEBUG 0x00040000 -+/* ws_env field is initialized */ -+#define WRDSF_ENV 0x00080000 -+/* ws_getvar field is initialized */ -+#define WRDSF_GETVAR 0x00100000 -+/* enable debugging */ -+#define WRDSF_SHOWDBG 0x00200000 -+/* Don't split input into words. Useful for side effects. */ -+#define WRDSF_NOSPLIT 0x00400000 -+/* Keep undefined variables in place, instead of expanding them to -+ empty string */ -+#define WRDSF_KEEPUNDEF 0x00800000 -+/* Warn about undefined variables */ -+#define WRDSF_WARNUNDEF 0x01000000 -+/* Handle C escapes */ -+#define WRDSF_CESCAPES 0x02000000 -+ -+/* ws_closure is set */ -+#define WRDSF_CLOSURE 0x04000000 -+/* ws_env is a Key/Value environment, i.e. the value of a variable is -+ stored in the element that follows its name. */ -+#define WRDSF_ENV_KV 0x08000000 -+ -+/* ws_escape is set */ -+#define WRDSF_ESCAPE 0x10000000 -+ -+/* Incremental mode */ -+#define WRDSF_INCREMENTAL 0x20000000 -+ -+#define WRDSF_DEFFLAGS \ -+ (WRDSF_NOVAR | WRDSF_NOCMD | \ -+ WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES) -+ -+#define WRDSE_EOF 0 -+#define WRDSE_QUOTE 1 -+#define WRDSE_NOSPACE 2 -+#define WRDSE_NOSUPP 3 -+#define WRDSE_USAGE 4 -+#define WRDSE_CBRACE 5 -+#define WRDSE_UNDEF 6 -+#define WRDSE_NOINPUT 7 -+ -+int wordsplit (const char *s, struct wordsplit *p, int flags); -+int wordsplit_len (const char *s, size_t len, -+ struct wordsplit *p, int flags); -+void wordsplit_free (struct wordsplit *p); -+void wordsplit_free_words (struct wordsplit *ws); -+ -+int wordsplit_c_unquote_char (int c); -+int wordsplit_c_quote_char (int c); -+size_t wordsplit_c_quoted_length (const char *str, int quote_hex, -+ int *quote); -+void wordsplit_general_unquote_copy (char *dst, const char *src, size_t n, -+ const char *escapable); -+void wordsplit_sh_unquote_copy (char *dst, const char *src, size_t n); -+void wordsplit_c_unquote_copy (char *dst, const char *src, size_t n); -+void wordsplit_c_quote_copy (char *dst, const char *src, int quote_hex); -+ -+void wordsplit_perror (struct wordsplit *ws); -+const char *wordsplit_strerror (struct wordsplit *ws); -+ -+ -+#endif -diff --git a/src/system.c b/src/system.c -index ea88cd6..a27a7de 100644 ---- a/src/system.c -+++ b/src/system.c -@@ -23,6 +23,20 @@ - #include - #include - #include -+#include -+ -+static void -+xexec (const char *cmd) -+{ -+ struct wordsplit ws; -+ -+ ws.ws_env = (const char **) environ; -+ if (wordsplit (cmd, &ws, (WRDSF_DEFFLAGS | WRDSF_ENV) & ~WRDSF_NOVAR)) -+ FATAL_ERROR ((0, 0, _("cannot split string '%s': %s"), -+ cmd, wordsplit_strerror (&ws))); -+ execvp (ws.ws_wordv[0], ws.ws_wordv); -+ exec_fatal (cmd); -+} - - #if MSDOS - -@@ -194,7 +208,7 @@ sys_spawn_shell (void) - if (child == 0) - { - priv_set_restore_linkdir (); -- execlp (shell, "-sh", "-i", (char *) 0); -+ execlp (shell, "-sh", "-i", NULL); - exec_fatal (shell); - } - else -@@ -334,7 +348,7 @@ sys_child_open_for_compress (void) - int child_pipe[2]; - pid_t grandchild_pid; - pid_t child_pid; -- -+ - xpipe (parent_pipe); - child_pid = xfork (); - -@@ -382,8 +396,7 @@ sys_child_open_for_compress (void) - xdup2 (archive, STDOUT_FILENO); - } - priv_set_restore_linkdir (); -- execlp (use_compress_program_option, use_compress_program_option, NULL); -- exec_fatal (use_compress_program_option); -+ xexec (use_compress_program_option); - } - - /* We do need a grandchild tar. */ -@@ -400,9 +413,7 @@ sys_child_open_for_compress (void) - xdup2 (child_pipe[PWRITE], STDOUT_FILENO); - xclose (child_pipe[PREAD]); - priv_set_restore_linkdir (); -- execlp (use_compress_program_option, use_compress_program_option, -- (char *) 0); -- exec_fatal (use_compress_program_option); -+ xexec (use_compress_program_option); - } - - /* The child tar is still here! */ -@@ -477,7 +488,12 @@ run_decompress_program (void) - { - int i; - const char *p, *prog = NULL; -+ struct wordsplit ws; -+ int wsflags = (WRDSF_DEFFLAGS | WRDSF_ENV | WRDSF_DOOFFS) & ~WRDSF_NOVAR; - -+ ws.ws_env = (const char **) environ; -+ ws.ws_offs = 1; -+ - for (p = first_decompress_program (&i); p; p = next_decompress_program (&i)) - { - if (prog) -@@ -487,8 +503,16 @@ run_decompress_program (void) - WARNOPT (WARN_DECOMPRESS_PROGRAM, - (0, 0, _("trying %s"), p)); - } -- prog = p; -- execlp (p, p, "-d", NULL); -+ if (wordsplit (p, &ws, wsflags)) -+ FATAL_ERROR ((0, 0, _("cannot split string '%s': %s"), -+ p, wordsplit_strerror (&ws))); -+ wsflags |= WRDSF_REUSE; -+ memmove(ws.ws_wordv, ws.ws_wordv + ws.ws_offs, -+ sizeof(ws.ws_wordv[0])*ws.ws_wordc); -+ ws.ws_wordv[ws.ws_wordc] = "-d"; -+ prog = p; -+ execvp (ws.ws_wordv[0], ws.ws_wordv); -+ ws.ws_wordv[ws.ws_wordc] = NULL; - } - if (!prog) - FATAL_ERROR ((0, 0, _("unable to run decompression program"))); -@@ -722,7 +746,7 @@ sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st) - { - int p[2]; - char *argv[4]; -- -+ - xpipe (p); - pipe_handler = signal (SIGPIPE, SIG_IGN); - global_pid = xfork (); -@@ -739,15 +763,8 @@ sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st) - - stat_to_env (file_name, typechar, st); - -- argv[0] = "/bin/sh"; -- argv[1] = "-c"; -- argv[2] = to_command_option; -- argv[3] = NULL; -- - priv_set_restore_linkdir (); -- execv ("/bin/sh", argv); -- -- exec_fatal (file_name); -+ xexec (to_command_option); - } - - void -@@ -854,15 +871,8 @@ sys_exec_info_script (const char **archive_name, int volume_number) - - xclose (p[PREAD]); - -- argv[0] = "/bin/sh"; -- argv[1] = "-c"; -- argv[2] = (char *) info_script_option; -- argv[3] = NULL; -- - priv_set_restore_linkdir (); -- execv (argv[0], argv); -- -- exec_fatal (info_script_option); -+ xexec (info_script_option); - } - - void -@@ -908,9 +918,7 @@ sys_exec_checkpoint_script (const char *script_name, - argv[3] = NULL; - - priv_set_restore_linkdir (); -- execv (argv[0], argv); -- -- exec_fatal (script_name); -+ xexec (script_name); - } - - #endif /* not MSDOS */