From 26434ee1b77dbff8f1904dd12204a93e87c8b6d3 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Thu, 9 Sep 2010 21:51:37 -0700 Subject: Bug #336644 - Make ebuild-ipc.py use array.fromfile() to read pickles in single atomic non-blocking read() calls, similar to how AbstractPollTask._read_buf() does it. If the read fails, exit with status 2 so that best_version() and has_version() can detect the error and die when necessary. --- bin/ebuild-ipc.py | 54 +++++++++++++++++++++++++++++------------------------- bin/ebuild.sh | 15 +++++++-------- 2 files changed, 36 insertions(+), 33 deletions(-) (limited to 'bin') diff --git a/bin/ebuild-ipc.py b/bin/ebuild-ipc.py index 13c062654..3869a3c49 100755 --- a/bin/ebuild-ipc.py +++ b/bin/ebuild-ipc.py @@ -5,6 +5,7 @@ # This is a helper which ebuild processes can use # to communicate with portage's main python process. +import array import logging import os import pickle @@ -34,6 +35,7 @@ portage._disable_legacy_globals() class EbuildIpc(object): _COMMUNICATE_TIMEOUT_SECONDS = 40 + _BUFSIZE = 4096 def __init__(self): self.fifo_dir = os.environ['PORTAGE_BUILDDIR'] @@ -82,31 +84,33 @@ class EbuildIpc(object): events = select.select([input_file], [], []) - # Read the whole pickle in a single read() call since - # this stream is in non-blocking mode and pickle.load() - # has been known to raise the following exception when - # reading from a non-blocking stream: - # - # File "/usr/lib64/python2.6/pickle.py", line 1370, in load - # return Unpickler(file).load() - # File "/usr/lib64/python2.6/pickle.py", line 858, in load - # dispatch[key](self) - # File "/usr/lib64/python2.6/pickle.py", line 1195, in load_setitem - # value = stack.pop() - # IndexError: pop from empty list - - pickle_str = input_file.read() - reply = pickle.loads(pickle_str) - output_file.close() - input_file.close() - - (out, err, rval) = reply - - if out: - portage.util.writemsg_stdout(out, noiselevel=-1) - - if err: - portage.util.writemsg(err, noiselevel=-1) + # Read the whole pickle in a single atomic read() call. + buf = array.array('B') + try: + buf.fromfile(input_file, self._BUFSIZE) + except EOFError as e: + #portage.util.writemsg("%s\n" % (e), noiselevel=-1) + pass + except IOError as e: + portage.util.writemsg("%s\n" % (e), noiselevel=-1) + + if buf: + + reply = pickle.loads(buf.tostring()) + output_file.close() + input_file.close() + + (out, err, rval) = reply + + if out: + portage.util.writemsg_stdout(out, noiselevel=-1) + + if err: + portage.util.writemsg(err, noiselevel=-1) + + else: + + rval = 2 return rval diff --git a/bin/ebuild.sh b/bin/ebuild.sh index cc3b4a142..a742eae62 100755 --- a/bin/ebuild.sh +++ b/bin/ebuild.sh @@ -180,13 +180,13 @@ has_version() { die "portageq calls (has_version calls portageq) are not allowed in the global scope" fi + local retval if [[ -n $PORTAGE_IPC_DAEMON ]] ; then "$PORTAGE_BIN_PATH"/ebuild-ipc has_version "$ROOT" "$1" - return $? + else + PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \ + "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/portageq" has_version "${ROOT}" "$1" fi - - PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \ - "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/portageq" has_version "${ROOT}" "$1" local retval=$? case "${retval}" in 0) @@ -225,11 +225,10 @@ best_version() { if [[ -n $PORTAGE_IPC_DAEMON ]] ; then "$PORTAGE_BIN_PATH"/ebuild-ipc best_version "$ROOT" "$1" - return $? + else + PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \ + "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/portageq" 'best_version' "${ROOT}" "$1" fi - - PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \ - "${PORTAGE_PYTHON:-/usr/bin/python}" "${PORTAGE_BIN_PATH}/portageq" 'best_version' "${ROOT}" "$1" local retval=$? case "${retval}" in 0) -- cgit v1.2.3-1-g7c22