Executes a subprocess. NOTE: On Windows, components of the `path` and `argv` that need to be quoted are expected to have been quoted before they are passed to `subprocess. For example, either of these may contain paths with spaces in them, like `C:\"Program Files"\foo.exe`, where notably the character sequence `\"` is not escaped quote, but instead a path separator and the start of a path compone
| 314 | // escape it. Therefore, incorrectly-quoted command arguments will probably |
| 315 | // lead the child process to terminate with an error. |
| 316 | Try<Subprocess> subprocess( |
| 317 | const string& path, |
| 318 | vector<string> argv, |
| 319 | const Subprocess::IO& in, |
| 320 | const Subprocess::IO& out, |
| 321 | const Subprocess::IO& err, |
| 322 | const flags::FlagsBase* flags, |
| 323 | const Option<map<string, string>>& environment, |
| 324 | const Option<lambda::function< |
| 325 | pid_t(const lambda::function<int()>&)>>& _clone, |
| 326 | const vector<Subprocess::ParentHook>& parent_hooks, |
| 327 | const vector<Subprocess::ChildHook>& child_hooks, |
| 328 | const vector<int_fd>& whitelist_fds) |
| 329 | { |
| 330 | // TODO(hausdorff): We should error out on Windows here if we are passing |
| 331 | // parameters that aren't used. |
| 332 | |
| 333 | // File descriptors for redirecting stdin/stdout/stderr. |
| 334 | // These file descriptors are used for different purposes depending |
| 335 | // on the specified I/O modes. |
| 336 | // See `Subprocess::PIPE`, `Subprocess::PATH`, and `Subprocess::FD`. |
| 337 | InputFileDescriptors stdinfds; |
| 338 | OutputFileDescriptors stdoutfds; |
| 339 | OutputFileDescriptors stderrfds; |
| 340 | |
| 341 | // Prepare the file descriptor(s) for stdin. |
| 342 | Try<InputFileDescriptors> input = in.input(); |
| 343 | if (input.isError()) { |
| 344 | return Error(input.error()); |
| 345 | } |
| 346 | |
| 347 | stdinfds = input.get(); |
| 348 | |
| 349 | // Prepare the file descriptor(s) for stdout. |
| 350 | Try<OutputFileDescriptors> output = out.output(); |
| 351 | if (output.isError()) { |
| 352 | process::internal::close(stdinfds, stdoutfds, stderrfds); |
| 353 | return Error(output.error()); |
| 354 | } |
| 355 | |
| 356 | stdoutfds = output.get(); |
| 357 | |
| 358 | // Prepare the file descriptor(s) for stderr. |
| 359 | output = err.output(); |
| 360 | if (output.isError()) { |
| 361 | process::internal::close(stdinfds, stdoutfds, stderrfds); |
| 362 | return Error(output.error()); |
| 363 | } |
| 364 | |
| 365 | stderrfds = output.get(); |
| 366 | |
| 367 | #ifndef __WINDOWS__ |
| 368 | // TODO(jieyu): Consider using O_CLOEXEC for atomic close-on-exec. |
| 369 | Try<Nothing> cloexec = internal::cloexec(stdinfds, stdoutfds, stderrfds); |
| 370 | if (cloexec.isError()) { |
| 371 | process::internal::close(stdinfds, stdoutfds, stderrfds); |
| 372 | return Error("Failed to cloexec: " + cloexec.error()); |
| 373 | } |