AU: Add support for reading the output of synchronous exec calls.

This will be used in a subsequent patch to invoke 'crossystem hwid' to read the
HWID.

BUG=chromium-os:15255
TEST=unit tests, tested AU on device

Change-Id: Ie26bae3621626d40f92f08e8549eefda77151102
Reviewed-on: http://gerrit.chromium.org/gerrit/1047
Reviewed-by: Thieu Le <thieule@chromium.org>
Tested-by: Darin Petkov <petkov@chromium.org>
diff --git a/delta_diff_generator.cc b/delta_diff_generator.cc
index a500054..f00ac7f 100644
--- a/delta_diff_generator.cc
+++ b/delta_diff_generator.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -1553,7 +1553,7 @@
 
   int rc = 1;
   vector<char> patch_file;
-  TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc));
+  TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &rc, NULL));
   TEST_AND_RETURN_FALSE(rc == 0);
   TEST_AND_RETURN_FALSE(utils::ReadFile(patch_file_path, out));
   unlink(patch_file_path.c_str());
diff --git a/delta_performer.cc b/delta_performer.cc
index 9978faf..6466795 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -517,8 +517,9 @@
   int return_code = 0;
   TEST_AND_RETURN_FALSE(
       Subprocess::SynchronousExecFlags(cmd,
+                                       G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
                                        &return_code,
-                                       G_SPAWN_LEAVE_DESCRIPTORS_OPEN));
+                                       NULL));
   TEST_AND_RETURN_FALSE(return_code == 0);
 
   if (operation.dst_length() % block_size_) {
diff --git a/download_action.cc b/download_action.cc
index 933cbdd..1491caa 100644
--- a/download_action.cc
+++ b/download_action.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -140,7 +140,7 @@
   command.push_back("/bin/sync");
   int rc;
   LOG(INFO) << "FlushLinuxCaches-sync...";
-  Subprocess::SynchronousExec(command, &rc);
+  Subprocess::SynchronousExec(command, &rc, NULL);
   LOG(INFO) << "FlushLinuxCaches-drop_caches...";
 
   const char* const drop_cmd = "3\n";
diff --git a/payload_signer.cc b/payload_signer.cc
index f613f36..c27e3bc 100644
--- a/payload_signer.cc
+++ b/payload_signer.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -155,7 +155,7 @@
   cmd[cmd.size() - 1] = sig_path;
 
   int return_code = 0;
-  TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code));
+  TEST_AND_RETURN_FALSE(Subprocess::SynchronousExec(cmd, &return_code, NULL));
   TEST_AND_RETURN_FALSE(return_code == 0);
 
   vector<char> signature;
diff --git a/subprocess.cc b/subprocess.cc
index 34f5994..a638145 100644
--- a/subprocess.cc
+++ b/subprocess.cc
@@ -117,7 +117,7 @@
 };
 }  // namespace {}
 
-uint32_t Subprocess::Exec(const std::vector<std::string>& cmd,
+uint32_t Subprocess::Exec(const vector<string>& cmd,
                           ExecCallback callback,
                           void* p) {
   GPid child_pid;
@@ -181,9 +181,13 @@
   subprocess_records_[tag]->callback = NULL;
 }
 
-bool Subprocess::SynchronousExecFlags(const std::vector<std::string>& cmd,
+bool Subprocess::SynchronousExecFlags(const vector<string>& cmd,
+                                      GSpawnFlags flags,
                                       int* return_code,
-                                      GSpawnFlags flags) {
+                                      string* stdout) {
+  if (stdout) {
+    *stdout = "";
+  }
   GError* err = NULL;
   scoped_array<char*> argv(new char*[cmd.size() + 1]);
   for (unsigned int i = 0; i < cmd.size(); i++) {
@@ -221,7 +225,9 @@
     g_error_free(err);
   }
   if (child_stdout) {
-    if (strlen(child_stdout)) {
+    if (stdout) {
+      *stdout = child_stdout;
+    } else if (*child_stdout) {
       LOG(INFO) << "Subprocess output:\n" << child_stdout;
     }
     g_free(child_stdout);
@@ -229,6 +235,15 @@
   return success;
 }
 
+bool Subprocess::SynchronousExec(const std::vector<std::string>& cmd,
+                                 int* return_code,
+                                 std::string* stdout) {
+  return SynchronousExecFlags(cmd,
+                              static_cast<GSpawnFlags>(0),
+                              return_code,
+                              stdout);
+}
+
 bool Subprocess::SubprocessInFlight() {
   for (std::map<int, shared_ptr<SubprocessRecord> >::iterator it =
            subprocess_records_.begin();
diff --git a/subprocess.h b/subprocess.h
index 3492e79..c55b090 100644
--- a/subprocess.h
+++ b/subprocess.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -41,14 +41,16 @@
   // Used to cancel the callback. The process will still run to completion.
   void CancelExec(uint32_t tag);
 
-  // Executes a command synchronously. Returns true on success.
+  // Executes a command synchronously. Returns true on success. If |stdout| is
+  // non-null, the process output is stored in it, otherwise the output is
+  // logged. Note that stderr is redirected to stdout.
   static bool SynchronousExecFlags(const std::vector<std::string>& cmd,
+                                   GSpawnFlags flags,
                                    int* return_code,
-                                   GSpawnFlags flags);
+                                   std::string* stdout);
   static bool SynchronousExec(const std::vector<std::string>& cmd,
-                              int* return_code) {
-    return SynchronousExecFlags(cmd, return_code, static_cast<GSpawnFlags>(0));
-  }
+                              int* return_code,
+                              std::string* stdout);
 
   // Gets the one instance
   static Subprocess& Get() {
diff --git a/subprocess_unittest.cc b/subprocess_unittest.cc
index 37deba9..6c0dcb2 100644
--- a/subprocess_unittest.cc
+++ b/subprocess_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -72,6 +72,28 @@
   g_main_loop_unref(loop);
 }
 
+TEST(SubprocessTest, SynchronousEchoTest) {
+  vector<string> cmd;
+  cmd.push_back("/bin/sh");
+  cmd.push_back("-c");
+  cmd.push_back("echo -n stdout-here; echo -n stderr-there > /dev/stderr");
+  int rc = -1;
+  string stdout;
+  ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, &stdout));
+  EXPECT_EQ(0, rc);
+  EXPECT_EQ("stdout-herestderr-there", stdout);
+}
+
+TEST(SubprocessTest, SynchronousEchoNoOutputTest) {
+  vector<string> cmd;
+  cmd.push_back("/bin/sh");
+  cmd.push_back("-c");
+  cmd.push_back("echo test");
+  int rc = -1;
+  ASSERT_TRUE(Subprocess::SynchronousExec(cmd, &rc, NULL));
+  EXPECT_EQ(0, rc);
+}
+
 namespace {
 void CallbackBad(int return_code, const string& output, void *p) {
   CHECK(false) << "should never be called.";
diff --git a/test_utils.h b/test_utils.h
index 2283e6a..b5ac853 100644
--- a/test_utils.h
+++ b/test_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -121,7 +121,7 @@
       args.push_back("-d");
       args.push_back(dev_);
       int return_code = 0;
-      EXPECT_TRUE(Subprocess::SynchronousExec(args, &return_code));
+      EXPECT_TRUE(Subprocess::SynchronousExec(args, &return_code, NULL));
       if (return_code == 0) {
         return;
       }
diff --git a/utils.cc b/utils.cc
index e1256a7..9c05a25 100644
--- a/utils.cc
+++ b/utils.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -60,7 +60,7 @@
 
   // Assume dev mode if the dev switch is set to 1 and there was no error
   // executing crossystem. Assume normal mode otherwise.
-  bool success = Subprocess::SynchronousExec(cmd, &exit_code);
+  bool success = Subprocess::SynchronousExec(cmd, &exit_code, NULL);
   bool dev_mode = success && exit_code == 0;
   LOG_IF(INFO, dev_mode) << "Booted in dev mode.";
   return !dev_mode;
@@ -513,7 +513,7 @@
   command.push_back("-r");
   command.push_back("now");
   int rc = 0;
-  Subprocess::SynchronousExec(command, &rc);
+  Subprocess::SynchronousExec(command, &rc, NULL);
   TEST_AND_RETURN_FALSE(rc == 0);
   return true;
 }