diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-17 09:57:52 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-17 09:57:52 +0000 |
commit | c0b210ee445f489f34a6565f51adb62f10988562 (patch) | |
tree | 0f9fd1d1061927fcd4865d0e951858473ceab398 /base | |
parent | 3b3cc646c182ca1578e745c110ba47af34468b15 (diff) | |
download | chromium_src-c0b210ee445f489f34a6565f51adb62f10988562.zip chromium_src-c0b210ee445f489f34a6565f51adb62f10988562.tar.gz chromium_src-c0b210ee445f489f34a6565f51adb62f10988562.tar.bz2 |
Add GetAppOutput function, a better replacement for popen.
It will replace popen call in chrome_process_util_linux.
I don't see much benefit in having a Windows implementation
(not many useful programs you can launch and get output),
so POSIX-only.
Review URL: http://codereview.chromium.org/67226
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13920 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/process_util.h | 8 | ||||
-rw-r--r-- | base/process_util_posix.cc | 68 | ||||
-rw-r--r-- | base/process_util_unittest.cc | 16 |
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 |