summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/process_util.h8
-rw-r--r--base/process_util_posix.cc68
-rw-r--r--base/process_util_unittest.cc16
3 files changed, 92 insertions, 0 deletions
diff --git a/base/process_util.h b/base/process_util.h
index 615e5b6..367c772 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -124,6 +124,14 @@ bool LaunchApp(const std::vector<std::string>& argv,
bool LaunchApp(const CommandLine& cl,
bool wait, bool start_hidden, ProcessHandle* process_handle);
+#if defined(OS_POSIX)
+// Execute the application specified by |cl| and wait for it to exit. Store
+// the output (stdout and stderr) in |output|. Returns true on success
+// (application launched and exited cleanly, with exit code indicating success).
+// |output| is modified only when the function finished successfully.
+bool GetAppOutput(const CommandLine& cl, std::string* output);
+#endif // defined(OS_POSIX)
+
// Used to filter processes by process ID.
class ProcessFilter {
public:
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index d55f65d..75c9b96 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -312,6 +312,74 @@ int ProcessMetrics::GetCPUUsage() {
return cpu;
}
+bool GetAppOutput(const CommandLine& cl, std::string* output) {
+ int pipe_fd[2];
+ pid_t pid;
+
+ if (pipe(pipe_fd) < 0)
+ return false;
+
+ switch (pid = fork()) {
+ case -1: // error
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ return false;
+ case 0: // child
+ {
+ int rv;
+ do {
+ rv = dup2(pipe_fd[1], STDOUT_FILENO);
+ } while (rv == -1 && errno == EINTR);
+ do {
+ rv = dup2(pipe_fd[1], STDERR_FILENO);
+ } while (rv == -1 && errno == EINTR);
+ if (pipe_fd[0] != STDOUT_FILENO && pipe_fd[0] != STDERR_FILENO)
+ close(pipe_fd[0]);
+ if (pipe_fd[1] != STDOUT_FILENO && pipe_fd[1] != STDERR_FILENO)
+ close(pipe_fd[1]);
+
+ const std::vector<std::string> argv = cl.argv();
+ char* argv_cstr[argv.size() + 1];
+ for (size_t i = 0; i < argv.size(); i++)
+ argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+ argv_cstr[argv.size()] = NULL;
+ execvp(argv_cstr[0], argv_cstr);
+ exit(127);
+ }
+ default: // parent
+ {
+ // Close our writing end of pipe now. Otherwise later read would not
+ // be able to detect end of child's output (in theory we could still
+ // write to the pipe).
+ close(pipe_fd[1]);
+
+ int exit_code = EXIT_FAILURE;
+ bool success = WaitForExitCode(pid, &exit_code);
+ if (!success || exit_code != EXIT_SUCCESS) {
+ close(pipe_fd[0]);
+ return false;
+ }
+
+ char buffer[256];
+ std::string buf_output;
+ ssize_t bytes_read = 0;
+
+ while (true) {
+ bytes_read = read(pipe_fd[0], buffer, sizeof(buffer));
+ if (bytes_read == 0)
+ break;
+ if (bytes_read == -1 && errno != EINTR)
+ break;
+ if (bytes_read > 0)
+ buf_output.append(buffer, bytes_read);
+ }
+ output->assign(buf_output);
+ close(pipe_fd[0]);
+ return true;
+ }
+ }
+}
+
int GetProcessCount(const std::wstring& executable_name,
const ProcessFilter* filter) {
int count = 0;
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index acb60e0..fba7b2b 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -4,6 +4,7 @@
#define _CRT_SECURE_NO_WARNINGS
+#include "base/command_line.h"
#include "base/multiprocess_test.h"
#include "base/platform_thread.h"
#include "base/process_util.h"
@@ -218,6 +219,21 @@ TEST_F(ProcessUtilTest, FDRemapping) {
close(dev_null);
}
+TEST_F(ProcessUtilTest, GetAppOutput) {
+ std::string output;
+ EXPECT_TRUE(GetAppOutput(CommandLine(L"true"), &output));
+ EXPECT_STREQ("", output.c_str());
+
+ EXPECT_FALSE(GetAppOutput(CommandLine(L"false"), &output));
+
+ std::vector<std::string> argv;
+ argv.push_back("/bin/echo");
+ argv.push_back("-n");
+ argv.push_back("foobar42");
+ EXPECT_TRUE(GetAppOutput(CommandLine(argv), &output));
+ EXPECT_STREQ("foobar42", output.c_str());
+}
+
#endif // defined(OS_POSIX)
} // namespace base