Add an execute_capture_output function.
This is to run a command and return its output on stdout and stderr as a
string.
Test: N/A
Bug: 137304531
Change-Id: I382f480504753cc0603d29f56919115f9a9c9b72
diff --git a/common/libs/utils/subprocess.cpp b/common/libs/utils/subprocess.cpp
index 18dbbeb..cca5e28 100644
--- a/common/libs/utils/subprocess.cpp
+++ b/common/libs/utils/subprocess.cpp
@@ -26,6 +26,9 @@
#include <set>
#include <glog/logging.h>
+
+#include "common/libs/fs/shared_buf.h"
+
namespace {
// If a redirected-to file descriptor was already closed, it's possible that
@@ -279,4 +282,34 @@
}
return subprocess.Wait();
}
+
+int execute_capture_output(const std::vector<std::string>& command,
+ std::string* output) {
+ Command cmd(command[0]);
+ for (size_t i = 1; i < command.size(); ++i) {
+ cmd.AddParameter(command[i]);
+ }
+ cvd::SharedFD pipe_read, pipe_write;
+ cvd::SharedFD::Pipe(&pipe_read, &pipe_write);
+ cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut, pipe_write);
+ cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdErr, pipe_write);
+
+ auto subprocess = cmd.Start();
+ if (!subprocess.Started()) {
+ return -1;
+ }
+ {
+ pipe_write->Close();
+ // Force the destructor to run by moving it into a smaller scope.
+ // This is necessary to close the write end of the pipe.
+ cvd::Command forceDelete = std::move(cmd);
+ }
+
+ int read = cvd::ReadAll(pipe_read, output);
+ if (read < 0) {
+ LOG(FATAL) << "Could not read from pipe in execute_capture_output";
+ }
+ return subprocess.Wait();
+}
+
} // namespace cvd
diff --git a/common/libs/utils/subprocess.h b/common/libs/utils/subprocess.h
index a299798..dd435ab 100644
--- a/common/libs/utils/subprocess.h
+++ b/common/libs/utils/subprocess.h
@@ -169,4 +169,8 @@
const std::vector<std::string>& env);
int execute(const std::vector<std::string>& command);
+// Like execute, but captures stdout and stderr and returns it in "output".
+int execute_capture_output(const std::vector<std::string>& command,
+ std::string* output);
+
} // namespace cvd