Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/process/launch.h" |
| 6 | |
Wez | 5c3c6f15 | 2018-06-09 18:24:02 | [diff] [blame] | 7 | #include <lib/fdio/limits.h> |
| 8 | #include <lib/fdio/namespace.h> |
| 9 | #include <lib/fdio/spawn.h> |
Wez | 82017b0e | 2018-07-09 17:21:10 | [diff] [blame] | 10 | #include <lib/zx/job.h> |
Kevin Marshall | 65c2670 | 2017-09-25 18:21:42 | [diff] [blame] | 11 | #include <stdint.h> |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 12 | #include <unistd.h> |
Scott Graham | fe0e9f46 | 2017-09-18 21:25:04 | [diff] [blame] | 13 | #include <zircon/processargs.h> |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 14 | |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 15 | #include <tuple> |
| 16 | |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 17 | #include "base/command_line.h" |
Sergey Ulanov | fea2f07 | 2017-10-21 04:34:26 | [diff] [blame] | 18 | #include "base/files/file_util.h" |
Kevin Marshall | a6c7a411 | 2017-08-25 23:39:12 | [diff] [blame] | 19 | #include "base/fuchsia/default_job.h" |
Kevin Marshall | ad910ae2 | 2018-06-16 05:40:53 | [diff] [blame] | 20 | #include "base/fuchsia/file_utils.h" |
Wez | eebd36b | 2018-03-28 18:24:03 | [diff] [blame] | 21 | #include "base/fuchsia/fuchsia_logging.h" |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 22 | #include "base/logging.h" |
Wez | 4e86105 | 2023-07-12 12:18:57 | [diff] [blame] | 23 | #include "base/memory/ptr_util.h" |
David Benjamin | 76ee79eb | 2019-03-15 17:02:09 | [diff] [blame] | 24 | #include "base/process/environment_internal.h" |
Wez | 4e86105 | 2023-07-12 12:18:57 | [diff] [blame] | 25 | #include "base/scoped_generic.h" |
| 26 | #include "base/threading/scoped_blocking_call.h" |
Etienne Pierre-doray | fc7952f0 | 2025-06-06 00:04:33 | [diff] [blame] | 27 | #include "base/trace_event/trace_event.h" |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 28 | |
| 29 | namespace base { |
| 30 | |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 31 | namespace { |
| 32 | |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 33 | bool GetAppOutputInternal(const CommandLine& cmd_line, |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 34 | bool include_stderr, |
| 35 | std::string* output, |
| 36 | int* exit_code) { |
| 37 | DCHECK(exit_code); |
Gabriel Charette | 6836c0d5 | 2021-01-11 17:40:26 | [diff] [blame] | 38 | TRACE_EVENT0("base", "GetAppOutput"); |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 39 | |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 40 | LaunchOptions options; |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 41 | |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 42 | // LaunchProcess will automatically clone any stdio fd we do not explicitly |
| 43 | // map. |
| 44 | int pipe_fd[2]; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 45 | if (pipe(pipe_fd) < 0) { |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 46 | return false; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 47 | } |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 48 | options.fds_to_remap.emplace_back(pipe_fd[1], STDOUT_FILENO); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 49 | if (include_stderr) { |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 50 | options.fds_to_remap.emplace_back(pipe_fd[1], STDERR_FILENO); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 51 | } |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 52 | |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 53 | Process process = LaunchProcess(cmd_line, options); |
| 54 | close(pipe_fd[1]); |
| 55 | if (!process.IsValid()) { |
| 56 | close(pipe_fd[0]); |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 57 | return false; |
| 58 | } |
| 59 | |
| 60 | output->clear(); |
| 61 | for (;;) { |
| 62 | char buffer[256]; |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 63 | ssize_t bytes_read = read(pipe_fd[0], buffer, sizeof(buffer)); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 64 | if (bytes_read <= 0) { |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 65 | break; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 66 | } |
Peter Kasting | 2f61c8b | 2022-07-19 23:43:46 | [diff] [blame] | 67 | output->append(buffer, static_cast<size_t>(bytes_read)); |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 68 | } |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 69 | close(pipe_fd[0]); |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 70 | |
Gabriel Charette | 6836c0d5 | 2021-01-11 17:40:26 | [diff] [blame] | 71 | // It is okay to allow this process to wait on the launched process as a |
| 72 | // process launched with GetAppOutput*() shouldn't wait back on the process |
| 73 | // that launched it. |
| 74 | internal::GetAppOutputScopedAllowBaseSyncPrimitives allow_wait; |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 75 | return process.WaitForExit(exit_code); |
| 76 | } |
| 77 | |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 78 | fdio_spawn_action_t FdioSpawnAction(uint32_t action) { |
| 79 | fdio_spawn_action_t new_action = {}; |
| 80 | new_action.action = action; |
| 81 | return new_action; |
| 82 | } |
Kevin Marshall | 2bd0455 | 2018-02-01 21:23:45 | [diff] [blame] | 83 | |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 84 | fdio_spawn_action_t FdioSpawnActionCloneFd(int local_fd, int target_fd) { |
| 85 | fdio_spawn_action_t action = FdioSpawnAction(FDIO_SPAWN_ACTION_CLONE_FD); |
| 86 | action.fd.local_fd = local_fd; |
| 87 | action.fd.target_fd = target_fd; |
| 88 | return action; |
| 89 | } |
Kevin Marshall | 2bd0455 | 2018-02-01 21:23:45 | [diff] [blame] | 90 | |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 91 | fdio_spawn_action_t FdioSpawnActionAddNamespaceEntry(const char* prefix, |
| 92 | zx_handle_t handle) { |
| 93 | fdio_spawn_action_t action = FdioSpawnAction(FDIO_SPAWN_ACTION_ADD_NS_ENTRY); |
| 94 | action.ns.prefix = prefix; |
| 95 | action.ns.handle = handle; |
| 96 | return action; |
| 97 | } |
| 98 | |
| 99 | fdio_spawn_action_t FdioSpawnActionAddHandle(uint32_t id, zx_handle_t handle) { |
| 100 | fdio_spawn_action_t action = FdioSpawnAction(FDIO_SPAWN_ACTION_ADD_HANDLE); |
| 101 | action.h.id = id; |
| 102 | action.h.handle = handle; |
| 103 | return action; |
| 104 | } |
Kevin Marshall | 2bd0455 | 2018-02-01 21:23:45 | [diff] [blame] | 105 | |
Sergey Ulanov | 53ab7dd | 2019-08-27 17:53:18 | [diff] [blame] | 106 | fdio_spawn_action_t FdioSpawnActionSetName(const char* name) { |
| 107 | fdio_spawn_action_t action = FdioSpawnAction(FDIO_SPAWN_ACTION_SET_NAME); |
| 108 | action.name.data = name; |
| 109 | return action; |
| 110 | } |
| 111 | |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 112 | } // namespace |
| 113 | |
Wez | 35e50b5 | 2018-12-01 01:52:44 | [diff] [blame] | 114 | // static |
| 115 | uint32_t LaunchOptions::AddHandleToTransfer( |
| 116 | HandlesToTransferVector* handles_to_transfer, |
| 117 | zx_handle_t handle) { |
Sharon Yang | 9fadcefd | 2020-07-07 23:49:19 | [diff] [blame] | 118 | CHECK_LE(handles_to_transfer->size(), std::numeric_limits<uint16_t>::max()) |
| 119 | << "Number of handles to transfer exceeds total allowed"; |
Peter Kasting | 2f61c8b | 2022-07-19 23:43:46 | [diff] [blame] | 120 | auto handle_id = |
| 121 | static_cast<uint32_t>(PA_HND(PA_USER1, handles_to_transfer->size())); |
Wez | 35e50b5 | 2018-12-01 01:52:44 | [diff] [blame] | 122 | handles_to_transfer->push_back({handle_id, handle}); |
| 123 | return handle_id; |
| 124 | } |
| 125 | |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 126 | Process LaunchProcess(const CommandLine& cmdline, |
| 127 | const LaunchOptions& options) { |
| 128 | return LaunchProcess(cmdline.argv(), options); |
| 129 | } |
| 130 | |
| 131 | Process LaunchProcess(const std::vector<std::string>& argv, |
| 132 | const LaunchOptions& options) { |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 133 | // fdio_spawn_etc() accepts an array of |fdio_spawn_action_t|, describing |
| 134 | // namespace entries, descriptors and handles to launch the child process |
David Dorwin | 8a971d32f | 2022-02-09 16:37:21 | [diff] [blame] | 135 | // with. |fdio_spawn_action_t| does not own any values assigned to its |
| 136 | // members, so strings assigned to members must be valid through the |
| 137 | // fdio_spawn_etc() call. |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 138 | std::vector<fdio_spawn_action_t> spawn_actions; |
| 139 | |
| 140 | // Handles to be transferred to the child are owned by this vector, so that |
| 141 | // they they are closed on early-exit, and can be release()d otherwise. |
Kevin Marshall | ad910ae2 | 2018-06-16 05:40:53 | [diff] [blame] | 142 | std::vector<zx::handle> transferred_handles; |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 143 | |
| 144 | // Add caller-supplied handles for transfer. We must do this first to ensure |
| 145 | // that the handles are consumed even if some later step fails. |
| 146 | for (const auto& id_and_handle : options.handles_to_transfer) { |
| 147 | spawn_actions.push_back( |
| 148 | FdioSpawnActionAddHandle(id_and_handle.id, id_and_handle.handle)); |
| 149 | transferred_handles.emplace_back(id_and_handle.handle); |
| 150 | } |
| 151 | |
| 152 | // Determine the job under which to launch the new process. |
Wez | 82017b0e | 2018-07-09 17:21:10 | [diff] [blame] | 153 | zx::unowned_job job = options.job_handle != ZX_HANDLE_INVALID |
| 154 | ? zx::unowned_job(options.job_handle) |
| 155 | : GetDefaultJob(); |
| 156 | DCHECK(job->is_valid()); |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 157 | |
| 158 | // Construct an |argv| array of C-strings from the supplied std::strings. |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 159 | std::vector<const char*> argv_cstr; |
| 160 | argv_cstr.reserve(argv.size() + 1); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 161 | for (const auto& arg : argv) { |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 162 | argv_cstr.push_back(arg.c_str()); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 163 | } |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 164 | argv_cstr.push_back(nullptr); |
| 165 | |
Wez | 9dd1de38 | 2022-04-27 16:20:43 | [diff] [blame] | 166 | // If |environment| is set then it contains values to set/replace to create |
| 167 | // the new process' environment. |
David Benjamin | 76ee79eb | 2019-03-15 17:02:09 | [diff] [blame] | 168 | EnvironmentMap environ_modifications = options.environment; |
Wez | 9dd1de38 | 2022-04-27 16:20:43 | [diff] [blame] | 169 | |
| 170 | // "PWD" is set in the new process' environment, to one of: |
| 171 | // 1. The value of |current_directory|, if set. |
| 172 | // 2. The value specified in |environment|, if any. |
| 173 | // 3. The current process' current working directory, if known. |
Scott Graham | f6305969 | 2017-06-21 00:37:51 | [diff] [blame] | 174 | if (!options.current_directory.empty()) { |
| 175 | environ_modifications["PWD"] = options.current_directory.value(); |
Wez | 9dd1de38 | 2022-04-27 16:20:43 | [diff] [blame] | 176 | } else if (environ_modifications.find("PWD") == environ_modifications.end()) { |
Sergey Ulanov | fea2f07 | 2017-10-21 04:34:26 | [diff] [blame] | 177 | FilePath cwd; |
Wez | 9dd1de38 | 2022-04-27 16:20:43 | [diff] [blame] | 178 | if (GetCurrentDirectory(&cwd)) { |
| 179 | environ_modifications["PWD"] = cwd.value(); |
| 180 | } |
Scott Graham | f6305969 | 2017-06-21 00:37:51 | [diff] [blame] | 181 | } |
| 182 | |
Wez | 9dd1de38 | 2022-04-27 16:20:43 | [diff] [blame] | 183 | // By default the calling process' environment is copied, and the collated |
| 184 | // modifications applied, to create the new process' environment. If |
| 185 | // |clear_environment| is set then only the collated modifications are used. |
| 186 | char* const kEmptyEnviron = nullptr; |
| 187 | char* const* old_environ = |
| 188 | options.clear_environment ? &kEmptyEnviron : environ; |
Maria Kazinova | 112e788 | 2024-06-10 16:04:36 | [diff] [blame] | 189 | base::HeapArray<char*> new_environ = |
Wez | 9dd1de38 | 2022-04-27 16:20:43 | [diff] [blame] | 190 | internal::AlterEnvironment(old_environ, environ_modifications); |
| 191 | |
| 192 | // Always clone the library loader service and UTC clock to new processes, |
| 193 | // in addition to any flags specified by the caller. |
| 194 | uint32_t spawn_flags = FDIO_SPAWN_DEFAULT_LDSVC | FDIO_SPAWN_CLONE_UTC_CLOCK | |
| 195 | options.spawn_flags; |
Scott Graham | f6305969 | 2017-06-21 00:37:51 | [diff] [blame] | 196 | |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 197 | // Add actions to clone handles for any specified paths into the new process' |
| 198 | // namespace. |
Kevin Marshall | ad910ae2 | 2018-06-16 05:40:53 | [diff] [blame] | 199 | if (!options.paths_to_clone.empty() || !options.paths_to_transfer.empty()) { |
Sergey Ulanov | f1b12ddf | 2018-11-27 02:56:58 | [diff] [blame] | 200 | DCHECK((options.spawn_flags & FDIO_SPAWN_CLONE_NAMESPACE) == 0); |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 201 | transferred_handles.reserve(transferred_handles.size() + |
Kevin Marshall | ad910ae2 | 2018-06-16 05:40:53 | [diff] [blame] | 202 | options.paths_to_clone.size() + |
| 203 | options.paths_to_transfer.size()); |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 204 | |
Kevin Marshall | ad910ae2 | 2018-06-16 05:40:53 | [diff] [blame] | 205 | for (const auto& path_to_transfer : options.paths_to_transfer) { |
| 206 | zx::handle handle(path_to_transfer.handle); |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 207 | spawn_actions.push_back(FdioSpawnActionAddNamespaceEntry( |
Kevin Marshall | ad910ae2 | 2018-06-16 05:40:53 | [diff] [blame] | 208 | path_to_transfer.path.value().c_str(), handle.get())); |
Kevin Marshall | ad910ae2 | 2018-06-16 05:40:53 | [diff] [blame] | 209 | transferred_handles.push_back(std::move(handle)); |
| 210 | } |
| 211 | |
| 212 | for (const auto& path_to_clone : options.paths_to_clone) { |
Sergey Ulanov | 713b7777 | 2019-03-14 22:53:32 | [diff] [blame] | 213 | fidl::InterfaceHandle<::fuchsia::io::Directory> directory = |
Wez | 4e86105 | 2023-07-12 12:18:57 | [diff] [blame] | 214 | base::OpenDirectoryHandle(path_to_clone); |
Sergey Ulanov | 713b7777 | 2019-03-14 22:53:32 | [diff] [blame] | 215 | if (!directory) { |
Wez | 4e86105 | 2023-07-12 12:18:57 | [diff] [blame] | 216 | LOG(WARNING) << "Could not open handle for path: " << path_to_clone; |
Kevin Marshall | ad910ae2 | 2018-06-16 05:40:53 | [diff] [blame] | 217 | return base::Process(); |
| 218 | } |
| 219 | |
Sergey Ulanov | 713b7777 | 2019-03-14 22:53:32 | [diff] [blame] | 220 | zx::handle handle = directory.TakeChannel(); |
| 221 | |
Kevin Marshall | ad910ae2 | 2018-06-16 05:40:53 | [diff] [blame] | 222 | spawn_actions.push_back(FdioSpawnActionAddNamespaceEntry( |
Wez | 4e86105 | 2023-07-12 12:18:57 | [diff] [blame] | 223 | path_to_clone.value().c_str(), handle.get())); |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 224 | transferred_handles.push_back(std::move(handle)); |
Kevin Marshall | 2bd0455 | 2018-02-01 21:23:45 | [diff] [blame] | 225 | } |
| 226 | } |
| 227 | |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 228 | // Add any file-descriptors to be cloned into the new process. |
| 229 | // Note that if FDIO_SPAWN_CLONE_STDIO is set, then any stdio entries in |
| 230 | // |fds_to_remap| will be used in place of the parent process' descriptors. |
Wez | ec2506f | 2017-08-03 17:49:18 | [diff] [blame] | 231 | for (const auto& src_target : options.fds_to_remap) { |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 232 | spawn_actions.push_back( |
| 233 | FdioSpawnActionCloneFd(src_target.first, src_target.second)); |
Wez | ec2506f | 2017-08-03 17:49:18 | [diff] [blame] | 234 | } |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 235 | |
Sergey Ulanov | 53ab7dd | 2019-08-27 17:53:18 | [diff] [blame] | 236 | // If |process_name_suffix| is specified then set process name as |
| 237 | // "<file_name><suffix>", otherwise leave the default value. |
David Dorwin | 8a971d32f | 2022-02-09 16:37:21 | [diff] [blame] | 238 | std::string process_name; // Must outlive the fdio_spawn_etc() call. |
Sergey Ulanov | 53ab7dd | 2019-08-27 17:53:18 | [diff] [blame] | 239 | if (!options.process_name_suffix.empty()) { |
| 240 | process_name = base::FilePath(argv[0]).BaseName().value() + |
| 241 | options.process_name_suffix; |
| 242 | spawn_actions.push_back(FdioSpawnActionSetName(process_name.c_str())); |
| 243 | } |
| 244 | |
Wez | 157707d6 | 2018-07-10 22:48:47 | [diff] [blame] | 245 | zx::process process_handle; |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 246 | // fdio_spawn_etc() will write a null-terminated scring to |error_message| in |
| 247 | // case of failure, so we avoid unnecessarily initializing it here. |
| 248 | char error_message[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; |
| 249 | zx_status_t status = fdio_spawn_etc( |
Wez | 82017b0e | 2018-07-09 17:21:10 | [diff] [blame] | 250 | job->get(), spawn_flags, argv_cstr[0], argv_cstr.data(), |
Maria Kazinova | 112e788 | 2024-06-10 16:04:36 | [diff] [blame] | 251 | new_environ.data(), spawn_actions.size(), spawn_actions.data(), |
Wez | 157707d6 | 2018-07-10 22:48:47 | [diff] [blame] | 252 | process_handle.reset_and_get_address(), error_message); |
Wez | 1603c32 | 2017-08-10 05:24:54 | [diff] [blame] | 253 | |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 254 | // fdio_spawn_etc() will close all handles specified in add-handle actions, |
| 255 | // regardless of whether it succeeds or fails, so release our copies. |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 256 | for (auto& transferred_handle : transferred_handles) { |
Avi Drissman | 933398e | 2022-01-22 00:55:42 | [diff] [blame] | 257 | std::ignore = transferred_handle.release(); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 258 | } |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 259 | |
| 260 | if (status != ZX_OK) { |
| 261 | ZX_LOG(ERROR, status) << "fdio_spawn: " << error_message; |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 262 | return Process(); |
| 263 | } |
| 264 | |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 265 | // Wrap the handle into a Process, and wait for it to terminate, if requested. |
| 266 | Process process(process_handle.release()); |
Wez | c6b685d | 2018-01-09 17:27:42 | [diff] [blame] | 267 | if (options.wait) { |
| 268 | status = zx_object_wait_one(process.Handle(), ZX_TASK_TERMINATED, |
| 269 | ZX_TIME_INFINITE, nullptr); |
Wez | 0629d40 | 2018-06-06 00:26:43 | [diff] [blame] | 270 | ZX_DCHECK(status == ZX_OK, status) << "zx_object_wait_one"; |
Wez | c6b685d | 2018-01-09 17:27:42 | [diff] [blame] | 271 | } |
| 272 | |
| 273 | return process; |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 274 | } |
| 275 | |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 276 | bool GetAppOutput(const CommandLine& cl, std::string* output) { |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 277 | int exit_code; |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 278 | bool result = GetAppOutputInternal(cl, false, output, &exit_code); |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 279 | return result && exit_code == EXIT_SUCCESS; |
| 280 | } |
| 281 | |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 282 | bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) { |
| 283 | return GetAppOutput(CommandLine(argv), output); |
| 284 | } |
| 285 | |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 286 | bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 287 | int exit_code; |
| 288 | bool result = GetAppOutputInternal(cl, true, output, &exit_code); |
| 289 | return result && exit_code == EXIT_SUCCESS; |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 290 | } |
| 291 | |
| 292 | bool GetAppOutputAndError(const std::vector<std::string>& argv, |
| 293 | std::string* output) { |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 294 | return GetAppOutputAndError(CommandLine(argv), output); |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 295 | } |
| 296 | |
| 297 | bool GetAppOutputWithExitCode(const CommandLine& cl, |
| 298 | std::string* output, |
| 299 | int* exit_code) { |
Scott Graham | 0b0f7d7 | 2017-07-26 01:47:11 | [diff] [blame] | 300 | // Contrary to GetAppOutput(), |true| return here means that the process was |
| 301 | // launched and the exit code was waited upon successfully, but not |
| 302 | // necessarily that the exit code was EXIT_SUCCESS. |
Wez | 78d1265 | 2017-08-29 23:22:48 | [diff] [blame] | 303 | return GetAppOutputInternal(cl, false, output, exit_code); |
Scott Graham | 3ba02bd | 2017-05-25 23:16:39 | [diff] [blame] | 304 | } |
| 305 | |
Sergey Ulanov | a93cf8b | 2017-12-01 21:52:53 | [diff] [blame] | 306 | void RaiseProcessToHighPriority() { |
| 307 | // Fuchsia doesn't provide an API to change process priority. |
| 308 | } |
| 309 | |
scottmg | e5a1d49 | 2017-05-24 23:41:43 | [diff] [blame] | 310 | } // namespace base |