Modify the code for processing the output of a process launched via
utils.run, post-termination. The calling code can't safely assume
that is can just do a full read() on the terminated processes output
stream, since it may have passed the pipes off to another daemon
process that is still alive. This can cause these final calls to
block, indefinitely. Instead, just read as much as possible without
blocking and then close our end of the pipes.

Risk: High
Visibility: We should never again block on a terminated subprocess
launched through utils.run (or system/system_output).

Signed-off-by: John Admanski <jadmanski@google.com>



git-svn-id: http://test.kernel.org/svn/autotest/trunk@1888 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/client/common_lib/utils.py b/client/common_lib/utils.py
index f31fb2f..c29d7e4 100644
--- a/client/common_lib/utils.py
+++ b/client/common_lib/utils.py
@@ -221,10 +221,8 @@
         result.exit_status = ret
         result.duration = time.time() - start_time
         # don't use os.read now, so we get all the rest of the output
-        _process_output(sp.stdout, stdout_file, stdout_tee,
-                        use_os_read=False)
-        _process_output(sp.stderr, stderr_file, stderr_tee,
-                        use_os_read=False)
+        _process_output(sp.stdout, stdout_file, stdout_tee, final_read=True)
+        _process_output(sp.stderr, stderr_file, stderr_tee, final_read=True)
     finally:
         # close our ends of the pipes to the sp no matter what
         sp.stdout.close()
@@ -260,11 +258,9 @@
         # os.read() has to be used instead of
         # subproc.stdout.read() which will otherwise block
         if subproc.stdout in ready:
-            _process_output(subproc.stdout, stdout_file,
-                            stdout_tee)
+            _process_output(subproc.stdout, stdout_file, stdout_tee)
         if subproc.stderr in ready:
-            _process_output(subproc.stderr, stderr_file,
-                            stderr_tee)
+            _process_output(subproc.stderr, stderr_file, stderr_tee)
 
         exit_status_indication = subproc.poll()
 
@@ -328,11 +324,18 @@
             pass
 
 
-def _process_output(pipe, fbuffer, teefile=None, use_os_read=True):
-    if use_os_read:
-        data = os.read(pipe.fileno(), 1024)
+def _process_output(pipe, fbuffer, teefile=None, final_read=False):
+    if final_read:
+        # read in all the data we can from pipe and then stop
+        data = []
+        while select.select([pipe], [], [], 0)[0]:
+            data.append(os.read(pipe.fileno(), 1024))
+            if len(data[-1]) == 0:
+                break
+        data = "".join(data)
     else:
-        data = pipe.read()
+        # perform a single read
+        data = os.read(pipe.fileno(), 1024)
     fbuffer.write(data)
     if teefile:
         teefile.write(data)