From 0ab6f83070c9a32a24454053319c99559c2654ca Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Mon, 23 Aug 2010 17:57:48 -0700 Subject: [PATCH] Handle SIGPIPE when unpack() extracts tar files through a pipe (bug #309001). When checking ${PIPESTATUS[@]} for extraction of tar files in unpack(), use a new assert_sigpipe_ok() function which behaves the same as the existing assert() function except that it tolerates pipe writers being killed by SIGPIPE. --- bin/ebuild.sh | 4 ++-- bin/isolated-functions.sh | 26 ++++++++++++++++++++++++++ pym/_emerge/BinpkgExtractorAsync.py | 4 +++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/bin/ebuild.sh b/bin/ebuild.sh index 84a83fe40..b2ac5b419 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -348,7 +348,7 @@ unpack() { _unpack_tar() { if [ "${y}" == "tar" ]; then $1 -dc "$srcdir$x" | tar xof - - assert "$myfail" + assert_sigpipe_ok "$myfail" else $1 -dc "${srcdir}${x}" > ${x%.*} || die "$myfail" fi @@ -364,7 +364,7 @@ unpack() { ;; tbz|tbz2) bzip2 -dc "$srcdir$x" | tar xof - - assert "$myfail" + assert_sigpipe_ok "$myfail" ;; ZIP|zip|jar) unzip -qo "${srcdir}${x}" || die "$myfail" diff --git a/bin/isolated-functions.sh b/bin/isolated-functions.sh index 53312dba8..a490f27c0 100644 --- a/bin/isolated-functions.sh +++ b/bin/isolated-functions.sh @@ -15,6 +15,32 @@ assert() { done } +assert_sigpipe_ok() { + # When extracting a tar file like this: + # + # bzip2 -dc foo.tar.bz2 | tar xof - + # + # For some tar files (see bug #309001), tar will + # close its stdin pipe when the decompressor still has + # remaining data to be written to its stdout pipe. This + # causes the decompressor to be killed by SIGPIPE. In + # this case, we want to ignore pipe writers killed by + # SIGPIPE, and trust the exit status of tar. We refer + # to the bash manual section "3.7.5 Exit Status" + # which says, "When a command terminates on a fatal + # signal whose number is N, Bash uses the value 128+N + # as the exit status." + + local x pipestatus=${PIPESTATUS[*]} + for x in $pipestatus ; do + # Allow SIGPIPE through (128 + 13) + [[ $x -ne 0 && $x -ne 141 ]] && die "$@" + done + + # Require normal success for the last process (tar). + [[ $x -eq 0 ]] || die "$@" +} + shopt -s extdebug # dump_trace([number of funcs on stack to skip], diff --git a/pym/_emerge/BinpkgExtractorAsync.py b/pym/_emerge/BinpkgExtractorAsync.py index a4941fccf..3a2654ec1 100644 --- a/pym/_emerge/BinpkgExtractorAsync.py +++ b/pym/_emerge/BinpkgExtractorAsync.py @@ -12,10 +12,12 @@ class BinpkgExtractorAsync(SpawnProcess): _shell_binary = portage.const.BASH_BINARY def _start(self): + # SIGPIPE handling (status 141) should be compatible with + # assert_sigpipe_ok() that's used by the ebuild unpack() helper. self.args = [self._shell_binary, "-c", ("bzip2 -dqc -- %s | tar -xp -C %s -f - ; " + \ "p=(${PIPESTATUS[@]}) ; " + \ - "if [ ${p[0]} != 0 ] ; then " + \ + "if [[ ${p[0]} != 0 && ${p[0]} != 141 ]] ; then " + \ "echo bzip2 failed with status ${p[0]} ; exit ${p[0]} ; fi ; " + \ "if [ ${p[1]} != 0 ] ; then " + \ "echo tar failed with status ${p[1]} ; exit ${p[1]} ; fi ; " + \ -- 2.26.2