Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef CROS_DISKS_PROCESS_H_ |
| 6 | #define CROS_DISKS_PROCESS_H_ |
| 7 | |
| 8 | #include <string> |
François Degros | 597bcf4 | 2020-08-28 19:34:19 +1000 | [diff] [blame] | 9 | #include <utility> |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 10 | #include <vector> |
| 11 | |
Sergei Datsenko | cd676b7 | 2019-05-10 11:42:05 +1000 | [diff] [blame] | 12 | #include <base/files/scoped_file.h> |
François Degros | ee31821 | 2020-07-14 14:11:42 +1000 | [diff] [blame] | 13 | #include <base/strings/string_piece.h> |
Sergei Datsenko | cd676b7 | 2019-05-10 11:42:05 +1000 | [diff] [blame] | 14 | |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 15 | #include <gtest/gtest_prod.h> |
| 16 | |
| 17 | namespace cros_disks { |
| 18 | |
| 19 | // A base class for executing a process. |
| 20 | // |
François Degros | c0b33b1 | 2019-09-12 14:50:43 +1000 | [diff] [blame] | 21 | // TODO(crbug.com/1003654) This base class is not feature complete yet. |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 22 | class Process { |
| 23 | public: |
Ben Chan | acac395 | 2012-04-24 22:50:01 -0700 | [diff] [blame] | 24 | // Invalid process ID assigned to a process that has not started. |
| 25 | static const pid_t kInvalidProcessId; |
| 26 | |
Sergei Datsenko | cd676b7 | 2019-05-10 11:42:05 +1000 | [diff] [blame] | 27 | static const int kInvalidFD; |
| 28 | |
Sergei Datsenko | 50c204d | 2020-11-14 21:18:40 +1100 | [diff] [blame] | 29 | Process(const Process&) = delete; |
| 30 | Process& operator=(const Process&) = delete; |
| 31 | |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 32 | virtual ~Process(); |
| 33 | |
François Degros | ee31821 | 2020-07-14 14:11:42 +1000 | [diff] [blame] | 34 | // Adds an argument to the end of the argument list. |
| 35 | // Precondition: Start() has not been called yet. |
| 36 | void AddArgument(std::string argument); |
| 37 | |
| 38 | // Adds a variable to the environment that will be passed to the process. |
| 39 | // Precondition: Start() has not been called yet. |
| 40 | // Precondition: `name` is not empty and doesn't contain '='. |
| 41 | void AddEnvironmentVariable(base::StringPiece name, base::StringPiece value); |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 42 | |
François Degros | 597bcf4 | 2020-08-28 19:34:19 +1000 | [diff] [blame] | 43 | // Sets the string to pass to the process stdin. |
| 44 | // Might be silently truncated if it doesn't fit in a pipe's buffer. |
| 45 | // Precondition: Start() has not been called yet. |
| 46 | void SetStdIn(std::string input) { input_ = std::move(input); } |
| 47 | |
François Degros | 1ef6994 | 2019-10-01 15:31:17 +1000 | [diff] [blame] | 48 | // Starts the process. The started process has its stdin, stdout and stderr |
| 49 | // connected to /dev/null. Returns true in case of success. Once started, the |
| 50 | // process can be waiting for to finish using Wait(). |
Sergei Datsenko | cd676b7 | 2019-05-10 11:42:05 +1000 | [diff] [blame] | 51 | bool Start(); |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 52 | |
Sergei Datsenko | 9246e9c | 2019-03-22 10:26:47 +1100 | [diff] [blame] | 53 | // Waits for the process to finish and returns its exit status. |
Sergei Datsenko | cd676b7 | 2019-05-10 11:42:05 +1000 | [diff] [blame] | 54 | int Wait(); |
| 55 | |
| 56 | // Checks if the process finished. |
| 57 | bool IsFinished(); |
Sergei Datsenko | 9246e9c | 2019-03-22 10:26:47 +1100 | [diff] [blame] | 58 | |
François Degros | edaefc5 | 2019-10-03 12:00:20 +1000 | [diff] [blame] | 59 | // Starts a process, captures its output and waits for it to finish. Returns |
| 60 | // the same exit status as Wait(). |
| 61 | // |
| 62 | // Precondition: output is non-null |
| 63 | int Run(std::vector<std::string>* output); |
Sergei Datsenko | 9246e9c | 2019-03-22 10:26:47 +1100 | [diff] [blame] | 64 | |
Ben Chan | acac395 | 2012-04-24 22:50:01 -0700 | [diff] [blame] | 65 | pid_t pid() const { return pid_; } |
| 66 | |
Sergei Datsenko | 9246e9c | 2019-03-22 10:26:47 +1100 | [diff] [blame] | 67 | const std::vector<std::string>& arguments() const { return arguments_; } |
François Degros | ee31821 | 2020-07-14 14:11:42 +1000 | [diff] [blame] | 68 | const std::vector<std::string>& environment() const { return environment_; } |
François Degros | 597bcf4 | 2020-08-28 19:34:19 +1000 | [diff] [blame] | 69 | const std::string& input() const { return input_; } |
Sergei Datsenko | 9246e9c | 2019-03-22 10:26:47 +1100 | [diff] [blame] | 70 | |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 71 | protected: |
| 72 | Process(); |
| 73 | |
François Degros | 2a4ec24 | 2019-10-15 16:28:54 +1100 | [diff] [blame] | 74 | // Gets the arguments used to start the process. This method calls |
| 75 | // BuildArgumentsArray() to build |arguments_array_| only once (i.e. when |
| 76 | // |arguments_array_| is empty). Once |arguments_array_| is built, subsequent |
| 77 | // calls to AddArgument() are not allowed. The returned array of arguments is |
| 78 | // owned by this Process object. |
François Degros | 5593b8c | 2019-07-25 12:27:42 +1000 | [diff] [blame] | 79 | char* const* GetArguments(); |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 80 | |
François Degros | ee31821 | 2020-07-14 14:11:42 +1000 | [diff] [blame] | 81 | // Gets the environment to pass to the subprocess. The returned array of |
| 82 | // environment variables is owned by this Process object. |
| 83 | char* const* GetEnvironment(); |
| 84 | |
François Degros | 1ef6994 | 2019-10-01 15:31:17 +1000 | [diff] [blame] | 85 | // Starts a process, and connects to its stdin, stdout and stderr the given |
| 86 | // file descriptors. |
| 87 | // |
| 88 | // Returns the PID of the started process, or -1 in case of error. |
| 89 | virtual pid_t StartImpl(base::ScopedFD in_fd, |
| 90 | base::ScopedFD out_fd, |
| 91 | base::ScopedFD err_fd) = 0; |
François Degros | 92bbea4 | 2019-09-13 10:42:52 +1000 | [diff] [blame] | 92 | |
| 93 | // Once either WaitImpl() or WaitNonBlockingImpl() has returned a nonnegative |
| 94 | // exit status, none of these methods is called again. |
| 95 | |
François Degros | 0156464 | 2019-09-13 14:10:17 +1000 | [diff] [blame] | 96 | // Waits for the process to finish and returns its nonnegative exit status. |
Sergei Datsenko | cd676b7 | 2019-05-10 11:42:05 +1000 | [diff] [blame] | 97 | virtual int WaitImpl() = 0; |
François Degros | 92bbea4 | 2019-09-13 10:42:52 +1000 | [diff] [blame] | 98 | |
François Degros | 0156464 | 2019-09-13 14:10:17 +1000 | [diff] [blame] | 99 | // Checks if the process has finished and returns its nonnegative exit status, |
| 100 | // or -1 if the process is still running. |
François Degros | 92bbea4 | 2019-09-13 10:42:52 +1000 | [diff] [blame] | 101 | virtual int WaitNonBlockingImpl() = 0; |
Ben Chan | acac395 | 2012-04-24 22:50:01 -0700 | [diff] [blame] | 102 | |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 103 | private: |
François Degros | 1ef6994 | 2019-10-01 15:31:17 +1000 | [diff] [blame] | 104 | // Starts the process. The started process has its stdin, stdout and stderr |
| 105 | // redirected to the given file descriptors. Returns true in case of success. |
| 106 | bool Start(base::ScopedFD in_fd, |
| 107 | base::ScopedFD out_fd, |
| 108 | base::ScopedFD err_fd); |
| 109 | |
Sergei Datsenko | cd676b7 | 2019-05-10 11:42:05 +1000 | [diff] [blame] | 110 | // Waits for process to finish collecting process' stdout and stderr |
| 111 | // output and fills interleaved version of it. |
François Degros | 1ef6994 | 2019-10-01 15:31:17 +1000 | [diff] [blame] | 112 | void Communicate(std::vector<std::string>* output, |
| 113 | base::ScopedFD out_fd, |
| 114 | base::ScopedFD err_fd); |
Sergei Datsenko | cd676b7 | 2019-05-10 11:42:05 +1000 | [diff] [blame] | 115 | |
François Degros | 2a4ec24 | 2019-10-15 16:28:54 +1100 | [diff] [blame] | 116 | // Builds |arguments_array_| from |arguments_|. Existing values of |
| 117 | // |arguments_array_| are overridden. |
| 118 | void BuildArgumentsArray(); |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 119 | |
François Degros | 0156464 | 2019-09-13 14:10:17 +1000 | [diff] [blame] | 120 | bool finished() const { return status_ >= 0; } |
| 121 | |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 122 | // Process arguments. |
| 123 | std::vector<std::string> arguments_; |
Ben Chan | 5e3ca67 | 2014-08-25 15:53:58 -0700 | [diff] [blame] | 124 | std::vector<char*> arguments_array_; |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 125 | |
François Degros | ee31821 | 2020-07-14 14:11:42 +1000 | [diff] [blame] | 126 | // Extra environment variables. |
| 127 | std::vector<std::string> environment_; |
| 128 | |
| 129 | // Full environment for the subprocess. |
| 130 | std::vector<char*> environment_array_; |
| 131 | |
François Degros | 597bcf4 | 2020-08-28 19:34:19 +1000 | [diff] [blame] | 132 | // String to pass to the process stdin. |
| 133 | std::string input_; |
| 134 | |
Ben Chan | acac395 | 2012-04-24 22:50:01 -0700 | [diff] [blame] | 135 | // Process ID (default to kInvalidProcessId when the process has not started). |
Sergei Datsenko | cd676b7 | 2019-05-10 11:42:05 +1000 | [diff] [blame] | 136 | pid_t pid_ = kInvalidProcessId; |
| 137 | |
François Degros | 0156464 | 2019-09-13 14:10:17 +1000 | [diff] [blame] | 138 | // Exit status. A nonnegative value indicates that the process has finished. |
Sergei Datsenko | cd676b7 | 2019-05-10 11:42:05 +1000 | [diff] [blame] | 139 | int status_ = -1; |
Ben Chan | acac395 | 2012-04-24 22:50:01 -0700 | [diff] [blame] | 140 | |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 141 | FRIEND_TEST(ProcessTest, GetArguments); |
| 142 | FRIEND_TEST(ProcessTest, GetArgumentsWithNoArgumentsAdded); |
Ben Chan | 6f391cb | 2012-03-21 17:38:21 -0700 | [diff] [blame] | 143 | }; |
| 144 | |
| 145 | } // namespace cros_disks |
| 146 | |
| 147 | #endif // CROS_DISKS_PROCESS_H_ |