aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2010-08-23 17:57:48 -0700
committerZac Medico <zmedico@gentoo.org>2010-08-23 17:57:48 -0700
commit0ab6f83070c9a32a24454053319c99559c2654ca (patch)
tree02691a5ce6da1bfeb67761571f46c47e2b4161a1
parent* Use iterators instead of keys() when possible. (diff)
downloadportage-0ab6f83070c9a32a24454053319c99559c2654ca.tar.gz
portage-0ab6f83070c9a32a24454053319c99559c2654ca.tar.bz2
portage-0ab6f83070c9a32a24454053319c99559c2654ca.zip
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.
-rwxr-xr-xbin/ebuild.sh4
-rw-r--r--bin/isolated-functions.sh26
-rw-r--r--pym/_emerge/BinpkgExtractorAsync.py4
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 ; " + \