| 311 | |
| 312 | |
| 313 | inline Try<pid_t> cloneChild( |
| 314 | const std::string& path, |
| 315 | std::vector<std::string> argv, |
| 316 | const Option<std::map<std::string, std::string>>& environment, |
| 317 | const Option<lambda::function< |
| 318 | pid_t(const lambda::function<int()>&)>>& _clone, |
| 319 | const std::vector<Subprocess::ParentHook>& parent_hooks, |
| 320 | const std::vector<Subprocess::ChildHook>& child_hooks, |
| 321 | const InputFileDescriptors stdinfds, |
| 322 | const OutputFileDescriptors stdoutfds, |
| 323 | const OutputFileDescriptors stderrfds, |
| 324 | const std::vector<int_fd>& whitelist_fds) |
| 325 | { |
| 326 | // The real arguments that will be passed to 'os::execvpe'. We need |
| 327 | // to construct them here before doing the clone as it might not be |
| 328 | // async signal safe to perform the memory allocation. |
| 329 | char** _argv = new char*[argv.size() + 1]; |
| 330 | for (size_t i = 0; i < argv.size(); i++) { |
| 331 | _argv[i] = (char*) argv[i].c_str(); |
| 332 | } |
| 333 | _argv[argv.size()] = nullptr; |
| 334 | |
| 335 | // Like above, we need to construct the environment that we'll pass |
| 336 | // to 'os::execvpe' as it might not be async-safe to perform the |
| 337 | // memory allocations. |
| 338 | char** envp = os::raw::environment(); |
| 339 | |
| 340 | if (environment.isSome()) { |
| 341 | // NOTE: We add 1 to the size for a `nullptr` terminator. |
| 342 | envp = new char*[environment->size() + 1]; |
| 343 | |
| 344 | size_t index = 0; |
| 345 | foreachpair ( |
| 346 | const std::string& key, |
| 347 | const std::string& value, environment.get()) { |
| 348 | std::string entry = key + "=" + value; |
| 349 | envp[index] = new char[entry.size() + 1]; |
| 350 | strncpy(envp[index], entry.c_str(), entry.size() + 1); |
| 351 | ++index; |
| 352 | } |
| 353 | |
| 354 | envp[index] = nullptr; |
| 355 | } |
| 356 | |
| 357 | // Determine the function to clone the child process. If the user |
| 358 | // does not specify the clone function, we will use the default. |
| 359 | lambda::function<pid_t(const lambda::function<int()>&)> clone = |
| 360 | (_clone.isSome() ? _clone.get() : defaultClone); |
| 361 | |
| 362 | // Currently we will block the child's execution of the new process |
| 363 | // until all the `parent_hooks` (if any) have executed. |
| 364 | std::array<int, 2> pipes; |
| 365 | const bool blocking = !parent_hooks.empty(); |
| 366 | |
| 367 | if (blocking) { |
| 368 | // We assume this should not fail under reasonable conditions so we |
| 369 | // use CHECK. |
| 370 | Try<std::array<int, 2>> pipe = os::pipe(); |