diff options
author | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-06 06:14:48 +0000 |
---|---|---|
committer | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-06 06:14:48 +0000 |
commit | d03b05c28ce4dd5da89bee73e507d92506b41958 (patch) | |
tree | 69f988c9d3b18b7408ad6b1c975bacb5a2905485 /base/process_util_posix.cc | |
parent | 031c073b907cd540604377687d49792cf86fdf20 (diff) | |
download | chromium_src-d03b05c28ce4dd5da89bee73e507d92506b41958.zip chromium_src-d03b05c28ce4dd5da89bee73e507d92506b41958.tar.gz chromium_src-d03b05c28ce4dd5da89bee73e507d92506b41958.tar.bz2 |
Added ability to run a command, getting output and exit status on POSIX.
Register protocol handler needs to check the return value of scripts it runs and
collects output from. There needs a variant of GetAppOutput which returns the
exit code of the application run, not just a success or failure, so this function
has been added.
BUG=83557
TEST=Unit test added
Review URL: http://codereview.chromium.org/7198034
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@91527 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/process_util_posix.cc')
-rw-r--r-- | base/process_util_posix.cc | 83 |
1 files changed, 61 insertions, 22 deletions
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc index 43c16ea..0e116de 100644 --- a/base/process_util_posix.cc +++ b/base/process_util_posix.cc @@ -851,18 +851,40 @@ int64 TimeValToMicroseconds(const struct timeval& tv) { return ret; } +// Return value used by GetAppOutputInternal to encapsulate the various exit +// scenarios from the function. +enum GetAppOutputInternalResult { + EXECUTE_FAILURE, + EXECUTE_SUCCESS, + GOT_MAX_OUTPUT, +}; + // Executes the application specified by |cl| and wait for it to exit. Stores // the output (stdout) in |output|. If |do_search_path| is set, it searches the // path for the application; in that case, |envp| must be null, and it will use // the current environment. If |do_search_path| is false, |cl| should fully // specify the path of the application, and |envp| will be used as the -// environment. Redirects stderr to /dev/null. Returns true on success -// (application launched and exited cleanly, with exit code indicating success). -static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], - std::string* output, size_t max_output, - bool do_search_path) { +// environment. Redirects stderr to /dev/null. +// If we successfully start the application and get all requested output, we +// return GOT_MAX_OUTPUT, or if there is a problem starting or exiting +// the application we return RUN_FAILURE. Otherwise we return EXECUTE_SUCCESS. +// The GOT_MAX_OUTPUT return value exists so a caller that asks for limited +// output can treat this as a success, despite having an exit code of SIG_PIPE +// due to us closing the output pipe. +// In the case of EXECUTE_SUCCESS, the application exit code will be returned +// in |*exit_code|, which should be checked to determine if the application +// ran successfully. +static GetAppOutputInternalResult GetAppOutputInternal(const CommandLine& cl, + char* const envp[], + std::string* output, + size_t max_output, + bool do_search_path, + int* exit_code) { // Doing a blocking wait for another command to finish counts as IO. base::ThreadRestrictions::AssertIOAllowed(); + // exit_code must be supplied so calling function can determine success. + DCHECK(exit_code); + *exit_code = EXIT_FAILURE; int pipe_fd[2]; pid_t pid; @@ -878,13 +900,13 @@ static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], DCHECK(!do_search_path ^ !envp); if (pipe(pipe_fd) < 0) - return false; + return EXECUTE_FAILURE; switch (pid = fork()) { case -1: // error close(pipe_fd[0]); close(pipe_fd[1]); - return false; + return EXECUTE_FAILURE; case 0: // child { #if defined(OS_MACOSX) @@ -948,26 +970,28 @@ static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], } close(pipe_fd[0]); - // Always wait for exit code (even if we know we'll declare success). - int exit_code = EXIT_FAILURE; - bool success = WaitForExitCode(pid, &exit_code); - - // If we stopped because we read as much as we wanted, we always declare - // success (because the child may exit due to |SIGPIPE|). - if (output_buf_left || bytes_read <= 0) { - if (!success || exit_code != EXIT_SUCCESS) - return false; - } - - return true; + // Always wait for exit code (even if we know we'll declare + // GOT_MAX_OUTPUT). + bool success = WaitForExitCode(pid, exit_code); + + // If we stopped because we read as much as we wanted, we return + // GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|). + if (!output_buf_left && bytes_read > 0) + return GOT_MAX_OUTPUT; + else if (success) + return EXECUTE_SUCCESS; + return EXECUTE_FAILURE; } } } bool GetAppOutput(const CommandLine& cl, std::string* output) { // Run |execve()| with the current environment and store "unlimited" data. - return GetAppOutputInternal(cl, NULL, output, - std::numeric_limits<std::size_t>::max(), true); + int exit_code; + GetAppOutputInternalResult result = GetAppOutputInternal( + cl, NULL, output, std::numeric_limits<std::size_t>::max(), true, + &exit_code); + return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS; } // TODO(viettrungluu): Conceivably, we should have a timeout as well, so we @@ -976,7 +1000,22 @@ bool GetAppOutputRestricted(const CommandLine& cl, std::string* output, size_t max_output) { // Run |execve()| with the empty environment. char* const empty_environ = NULL; - return GetAppOutputInternal(cl, &empty_environ, output, max_output, false); + int exit_code; + GetAppOutputInternalResult result = GetAppOutputInternal(cl, &empty_environ, + output, max_output, + false, &exit_code); + return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS && + exit_code == EXIT_SUCCESS); +} + +bool GetAppOutputWithExitCode(const CommandLine& cl, + std::string* output, + int* exit_code) { + // Run |execve()| with the current environment and store "unlimited" data. + GetAppOutputInternalResult result = GetAppOutputInternal( + cl, NULL, output, std::numeric_limits<std::size_t>::max(), true, + exit_code); + return result == EXECUTE_SUCCESS; } bool WaitForProcessesToExit(const FilePath::StringType& executable_name, |