1e66f31c5Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2e66f31c5Sopenharmony_ci * 3e66f31c5Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 4e66f31c5Sopenharmony_ci * of this software and associated documentation files (the "Software"), to 5e66f31c5Sopenharmony_ci * deal in the Software without restriction, including without limitation the 6e66f31c5Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7e66f31c5Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 8e66f31c5Sopenharmony_ci * furnished to do so, subject to the following conditions: 9e66f31c5Sopenharmony_ci * 10e66f31c5Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 11e66f31c5Sopenharmony_ci * all copies or substantial portions of the Software. 12e66f31c5Sopenharmony_ci * 13e66f31c5Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14e66f31c5Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15e66f31c5Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16e66f31c5Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17e66f31c5Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18e66f31c5Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19e66f31c5Sopenharmony_ci * IN THE SOFTWARE. 20e66f31c5Sopenharmony_ci */ 21e66f31c5Sopenharmony_ci 22e66f31c5Sopenharmony_ci#include "uv.h" 23e66f31c5Sopenharmony_ci#include "internal.h" 24e66f31c5Sopenharmony_ci 25e66f31c5Sopenharmony_ci#include <stdio.h> 26e66f31c5Sopenharmony_ci#include <stdlib.h> 27e66f31c5Sopenharmony_ci#include <assert.h> 28e66f31c5Sopenharmony_ci#include <errno.h> 29e66f31c5Sopenharmony_ci#include <signal.h> 30e66f31c5Sopenharmony_ci#include <string.h> 31e66f31c5Sopenharmony_ci 32e66f31c5Sopenharmony_ci#include <sys/types.h> 33e66f31c5Sopenharmony_ci#include <sys/wait.h> 34e66f31c5Sopenharmony_ci#include <unistd.h> 35e66f31c5Sopenharmony_ci#include <fcntl.h> 36e66f31c5Sopenharmony_ci#include <poll.h> 37e66f31c5Sopenharmony_ci 38e66f31c5Sopenharmony_ci#if defined(__APPLE__) 39e66f31c5Sopenharmony_ci# include <spawn.h> 40e66f31c5Sopenharmony_ci# include <paths.h> 41e66f31c5Sopenharmony_ci# include <sys/kauth.h> 42e66f31c5Sopenharmony_ci# include <sys/types.h> 43e66f31c5Sopenharmony_ci# include <sys/sysctl.h> 44e66f31c5Sopenharmony_ci# include <dlfcn.h> 45e66f31c5Sopenharmony_ci# include <crt_externs.h> 46e66f31c5Sopenharmony_ci# include <xlocale.h> 47e66f31c5Sopenharmony_ci# define environ (*_NSGetEnviron()) 48e66f31c5Sopenharmony_ci 49e66f31c5Sopenharmony_ci/* macOS 10.14 back does not define this constant */ 50e66f31c5Sopenharmony_ci# ifndef POSIX_SPAWN_SETSID 51e66f31c5Sopenharmony_ci# define POSIX_SPAWN_SETSID 1024 52e66f31c5Sopenharmony_ci# endif 53e66f31c5Sopenharmony_ci 54e66f31c5Sopenharmony_ci#else 55e66f31c5Sopenharmony_ciextern char **environ; 56e66f31c5Sopenharmony_ci#endif 57e66f31c5Sopenharmony_ci 58e66f31c5Sopenharmony_ci#if defined(__linux__) 59e66f31c5Sopenharmony_ci# include <grp.h> 60e66f31c5Sopenharmony_ci#endif 61e66f31c5Sopenharmony_ci 62e66f31c5Sopenharmony_ci#if defined(__MVS__) 63e66f31c5Sopenharmony_ci# include "zos-base.h" 64e66f31c5Sopenharmony_ci#endif 65e66f31c5Sopenharmony_ci 66e66f31c5Sopenharmony_ci#if defined(__APPLE__) || \ 67e66f31c5Sopenharmony_ci defined(__DragonFly__) || \ 68e66f31c5Sopenharmony_ci defined(__FreeBSD__) || \ 69e66f31c5Sopenharmony_ci defined(__NetBSD__) || \ 70e66f31c5Sopenharmony_ci defined(__OpenBSD__) 71e66f31c5Sopenharmony_ci#include <sys/event.h> 72e66f31c5Sopenharmony_ci#else 73e66f31c5Sopenharmony_ci#define UV_USE_SIGCHLD 74e66f31c5Sopenharmony_ci#endif 75e66f31c5Sopenharmony_ci 76e66f31c5Sopenharmony_ci 77e66f31c5Sopenharmony_ci#ifdef UV_USE_SIGCHLD 78e66f31c5Sopenharmony_cistatic void uv__chld(uv_signal_t* handle, int signum) { 79e66f31c5Sopenharmony_ci assert(signum == SIGCHLD); 80e66f31c5Sopenharmony_ci uv__wait_children(handle->loop); 81e66f31c5Sopenharmony_ci} 82e66f31c5Sopenharmony_ci 83e66f31c5Sopenharmony_ci 84e66f31c5Sopenharmony_ciint uv__process_init(uv_loop_t* loop) { 85e66f31c5Sopenharmony_ci int err; 86e66f31c5Sopenharmony_ci 87e66f31c5Sopenharmony_ci err = uv_signal_init(loop, &loop->child_watcher); 88e66f31c5Sopenharmony_ci if (err) 89e66f31c5Sopenharmony_ci return err; 90e66f31c5Sopenharmony_ci uv__handle_unref(&loop->child_watcher); 91e66f31c5Sopenharmony_ci loop->child_watcher.flags |= UV_HANDLE_INTERNAL; 92e66f31c5Sopenharmony_ci return 0; 93e66f31c5Sopenharmony_ci} 94e66f31c5Sopenharmony_ci 95e66f31c5Sopenharmony_ci 96e66f31c5Sopenharmony_ci#else 97e66f31c5Sopenharmony_ciint uv__process_init(uv_loop_t* loop) { 98e66f31c5Sopenharmony_ci memset(&loop->child_watcher, 0, sizeof(loop->child_watcher)); 99e66f31c5Sopenharmony_ci return 0; 100e66f31c5Sopenharmony_ci} 101e66f31c5Sopenharmony_ci#endif 102e66f31c5Sopenharmony_ci 103e66f31c5Sopenharmony_ci 104e66f31c5Sopenharmony_civoid uv__wait_children(uv_loop_t* loop) { 105e66f31c5Sopenharmony_ci uv_process_t* process; 106e66f31c5Sopenharmony_ci int exit_status; 107e66f31c5Sopenharmony_ci int term_signal; 108e66f31c5Sopenharmony_ci int status; 109e66f31c5Sopenharmony_ci int options; 110e66f31c5Sopenharmony_ci pid_t pid; 111e66f31c5Sopenharmony_ci struct uv__queue pending; 112e66f31c5Sopenharmony_ci struct uv__queue* q; 113e66f31c5Sopenharmony_ci struct uv__queue* h; 114e66f31c5Sopenharmony_ci 115e66f31c5Sopenharmony_ci uv__queue_init(&pending); 116e66f31c5Sopenharmony_ci 117e66f31c5Sopenharmony_ci h = &loop->process_handles; 118e66f31c5Sopenharmony_ci q = uv__queue_head(h); 119e66f31c5Sopenharmony_ci while (q != h) { 120e66f31c5Sopenharmony_ci process = uv__queue_data(q, uv_process_t, queue); 121e66f31c5Sopenharmony_ci q = uv__queue_next(q); 122e66f31c5Sopenharmony_ci 123e66f31c5Sopenharmony_ci#ifndef UV_USE_SIGCHLD 124e66f31c5Sopenharmony_ci if ((process->flags & UV_HANDLE_REAP) == 0) 125e66f31c5Sopenharmony_ci continue; 126e66f31c5Sopenharmony_ci options = 0; 127e66f31c5Sopenharmony_ci process->flags &= ~UV_HANDLE_REAP; 128e66f31c5Sopenharmony_ci loop->nfds--; 129e66f31c5Sopenharmony_ci#else 130e66f31c5Sopenharmony_ci options = WNOHANG; 131e66f31c5Sopenharmony_ci#endif 132e66f31c5Sopenharmony_ci 133e66f31c5Sopenharmony_ci do 134e66f31c5Sopenharmony_ci pid = waitpid(process->pid, &status, options); 135e66f31c5Sopenharmony_ci while (pid == -1 && errno == EINTR); 136e66f31c5Sopenharmony_ci 137e66f31c5Sopenharmony_ci#ifdef UV_USE_SIGCHLD 138e66f31c5Sopenharmony_ci if (pid == 0) /* Not yet exited */ 139e66f31c5Sopenharmony_ci continue; 140e66f31c5Sopenharmony_ci#endif 141e66f31c5Sopenharmony_ci 142e66f31c5Sopenharmony_ci if (pid == -1) { 143e66f31c5Sopenharmony_ci if (errno != ECHILD) 144e66f31c5Sopenharmony_ci abort(); 145e66f31c5Sopenharmony_ci /* The child died, and we missed it. This probably means someone else 146e66f31c5Sopenharmony_ci * stole the waitpid from us. Handle this by not handling it at all. */ 147e66f31c5Sopenharmony_ci continue; 148e66f31c5Sopenharmony_ci } 149e66f31c5Sopenharmony_ci 150e66f31c5Sopenharmony_ci assert(pid == process->pid); 151e66f31c5Sopenharmony_ci process->status = status; 152e66f31c5Sopenharmony_ci uv__queue_remove(&process->queue); 153e66f31c5Sopenharmony_ci uv__queue_insert_tail(&pending, &process->queue); 154e66f31c5Sopenharmony_ci } 155e66f31c5Sopenharmony_ci 156e66f31c5Sopenharmony_ci h = &pending; 157e66f31c5Sopenharmony_ci q = uv__queue_head(h); 158e66f31c5Sopenharmony_ci while (q != h) { 159e66f31c5Sopenharmony_ci process = uv__queue_data(q, uv_process_t, queue); 160e66f31c5Sopenharmony_ci q = uv__queue_next(q); 161e66f31c5Sopenharmony_ci 162e66f31c5Sopenharmony_ci uv__queue_remove(&process->queue); 163e66f31c5Sopenharmony_ci uv__queue_init(&process->queue); 164e66f31c5Sopenharmony_ci uv__handle_stop(process); 165e66f31c5Sopenharmony_ci 166e66f31c5Sopenharmony_ci if (process->exit_cb == NULL) 167e66f31c5Sopenharmony_ci continue; 168e66f31c5Sopenharmony_ci 169e66f31c5Sopenharmony_ci exit_status = 0; 170e66f31c5Sopenharmony_ci if (WIFEXITED(process->status)) 171e66f31c5Sopenharmony_ci exit_status = WEXITSTATUS(process->status); 172e66f31c5Sopenharmony_ci 173e66f31c5Sopenharmony_ci term_signal = 0; 174e66f31c5Sopenharmony_ci if (WIFSIGNALED(process->status)) 175e66f31c5Sopenharmony_ci term_signal = WTERMSIG(process->status); 176e66f31c5Sopenharmony_ci 177e66f31c5Sopenharmony_ci process->exit_cb(process, exit_status, term_signal); 178e66f31c5Sopenharmony_ci } 179e66f31c5Sopenharmony_ci assert(uv__queue_empty(&pending)); 180e66f31c5Sopenharmony_ci} 181e66f31c5Sopenharmony_ci 182e66f31c5Sopenharmony_ci/* 183e66f31c5Sopenharmony_ci * Used for initializing stdio streams like options.stdin_stream. Returns 184e66f31c5Sopenharmony_ci * zero on success. See also the cleanup section in uv_spawn(). 185e66f31c5Sopenharmony_ci */ 186e66f31c5Sopenharmony_ci#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) 187e66f31c5Sopenharmony_ci/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be 188e66f31c5Sopenharmony_ci * avoided. Since this isn't called on those targets, the function 189e66f31c5Sopenharmony_ci * doesn't even need to be defined for them. 190e66f31c5Sopenharmony_ci */ 191e66f31c5Sopenharmony_cistatic int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { 192e66f31c5Sopenharmony_ci int mask; 193e66f31c5Sopenharmony_ci int fd; 194e66f31c5Sopenharmony_ci 195e66f31c5Sopenharmony_ci mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM; 196e66f31c5Sopenharmony_ci 197e66f31c5Sopenharmony_ci switch (container->flags & mask) { 198e66f31c5Sopenharmony_ci case UV_IGNORE: 199e66f31c5Sopenharmony_ci return 0; 200e66f31c5Sopenharmony_ci 201e66f31c5Sopenharmony_ci case UV_CREATE_PIPE: 202e66f31c5Sopenharmony_ci assert(container->data.stream != NULL); 203e66f31c5Sopenharmony_ci if (container->data.stream->type != UV_NAMED_PIPE) 204e66f31c5Sopenharmony_ci return UV_EINVAL; 205e66f31c5Sopenharmony_ci else 206e66f31c5Sopenharmony_ci return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0); 207e66f31c5Sopenharmony_ci 208e66f31c5Sopenharmony_ci case UV_INHERIT_FD: 209e66f31c5Sopenharmony_ci case UV_INHERIT_STREAM: 210e66f31c5Sopenharmony_ci if (container->flags & UV_INHERIT_FD) 211e66f31c5Sopenharmony_ci fd = container->data.fd; 212e66f31c5Sopenharmony_ci else 213e66f31c5Sopenharmony_ci fd = uv__stream_fd(container->data.stream); 214e66f31c5Sopenharmony_ci 215e66f31c5Sopenharmony_ci if (fd == -1) 216e66f31c5Sopenharmony_ci return UV_EINVAL; 217e66f31c5Sopenharmony_ci 218e66f31c5Sopenharmony_ci fds[1] = fd; 219e66f31c5Sopenharmony_ci return 0; 220e66f31c5Sopenharmony_ci 221e66f31c5Sopenharmony_ci default: 222e66f31c5Sopenharmony_ci assert(0 && "Unexpected flags"); 223e66f31c5Sopenharmony_ci return UV_EINVAL; 224e66f31c5Sopenharmony_ci } 225e66f31c5Sopenharmony_ci} 226e66f31c5Sopenharmony_ci 227e66f31c5Sopenharmony_ci 228e66f31c5Sopenharmony_cistatic int uv__process_open_stream(uv_stdio_container_t* container, 229e66f31c5Sopenharmony_ci int pipefds[2]) { 230e66f31c5Sopenharmony_ci int flags; 231e66f31c5Sopenharmony_ci int err; 232e66f31c5Sopenharmony_ci 233e66f31c5Sopenharmony_ci if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0) 234e66f31c5Sopenharmony_ci return 0; 235e66f31c5Sopenharmony_ci 236e66f31c5Sopenharmony_ci err = uv__close(pipefds[1]); 237e66f31c5Sopenharmony_ci if (err != 0) 238e66f31c5Sopenharmony_ci abort(); 239e66f31c5Sopenharmony_ci 240e66f31c5Sopenharmony_ci pipefds[1] = -1; 241e66f31c5Sopenharmony_ci uv__nonblock(pipefds[0], 1); 242e66f31c5Sopenharmony_ci 243e66f31c5Sopenharmony_ci flags = 0; 244e66f31c5Sopenharmony_ci if (container->flags & UV_WRITABLE_PIPE) 245e66f31c5Sopenharmony_ci flags |= UV_HANDLE_READABLE; 246e66f31c5Sopenharmony_ci if (container->flags & UV_READABLE_PIPE) 247e66f31c5Sopenharmony_ci flags |= UV_HANDLE_WRITABLE; 248e66f31c5Sopenharmony_ci 249e66f31c5Sopenharmony_ci return uv__stream_open(container->data.stream, pipefds[0], flags); 250e66f31c5Sopenharmony_ci} 251e66f31c5Sopenharmony_ci 252e66f31c5Sopenharmony_ci 253e66f31c5Sopenharmony_cistatic void uv__process_close_stream(uv_stdio_container_t* container) { 254e66f31c5Sopenharmony_ci if (!(container->flags & UV_CREATE_PIPE)) return; 255e66f31c5Sopenharmony_ci uv__stream_close(container->data.stream); 256e66f31c5Sopenharmony_ci} 257e66f31c5Sopenharmony_ci 258e66f31c5Sopenharmony_ci 259e66f31c5Sopenharmony_cistatic void uv__write_int(int fd, int val) { 260e66f31c5Sopenharmony_ci ssize_t n; 261e66f31c5Sopenharmony_ci 262e66f31c5Sopenharmony_ci do 263e66f31c5Sopenharmony_ci n = write(fd, &val, sizeof(val)); 264e66f31c5Sopenharmony_ci while (n == -1 && errno == EINTR); 265e66f31c5Sopenharmony_ci 266e66f31c5Sopenharmony_ci /* The write might have failed (e.g. if the parent process has died), 267e66f31c5Sopenharmony_ci * but we have nothing left but to _exit ourself now too. */ 268e66f31c5Sopenharmony_ci _exit(127); 269e66f31c5Sopenharmony_ci} 270e66f31c5Sopenharmony_ci 271e66f31c5Sopenharmony_ci 272e66f31c5Sopenharmony_cistatic void uv__write_errno(int error_fd) { 273e66f31c5Sopenharmony_ci uv__write_int(error_fd, UV__ERR(errno)); 274e66f31c5Sopenharmony_ci} 275e66f31c5Sopenharmony_ci 276e66f31c5Sopenharmony_ci 277e66f31c5Sopenharmony_cistatic void uv__process_child_init(const uv_process_options_t* options, 278e66f31c5Sopenharmony_ci int stdio_count, 279e66f31c5Sopenharmony_ci int (*pipes)[2], 280e66f31c5Sopenharmony_ci int error_fd) { 281e66f31c5Sopenharmony_ci sigset_t signewset; 282e66f31c5Sopenharmony_ci int close_fd; 283e66f31c5Sopenharmony_ci int use_fd; 284e66f31c5Sopenharmony_ci int fd; 285e66f31c5Sopenharmony_ci int n; 286e66f31c5Sopenharmony_ci 287e66f31c5Sopenharmony_ci /* Reset signal disposition first. Use a hard-coded limit because NSIG is not 288e66f31c5Sopenharmony_ci * fixed on Linux: it's either 32, 34 or 64, depending on whether RT signals 289e66f31c5Sopenharmony_ci * are enabled. We are not allowed to touch RT signal handlers, glibc uses 290e66f31c5Sopenharmony_ci * them internally. 291e66f31c5Sopenharmony_ci */ 292e66f31c5Sopenharmony_ci for (n = 1; n < 32; n += 1) { 293e66f31c5Sopenharmony_ci if (n == SIGKILL || n == SIGSTOP) 294e66f31c5Sopenharmony_ci continue; /* Can't be changed. */ 295e66f31c5Sopenharmony_ci 296e66f31c5Sopenharmony_ci#if defined(__HAIKU__) 297e66f31c5Sopenharmony_ci if (n == SIGKILLTHR) 298e66f31c5Sopenharmony_ci continue; /* Can't be changed. */ 299e66f31c5Sopenharmony_ci#endif 300e66f31c5Sopenharmony_ci 301e66f31c5Sopenharmony_ci if (SIG_ERR != signal(n, SIG_DFL)) 302e66f31c5Sopenharmony_ci continue; 303e66f31c5Sopenharmony_ci 304e66f31c5Sopenharmony_ci uv__write_errno(error_fd); 305e66f31c5Sopenharmony_ci } 306e66f31c5Sopenharmony_ci 307e66f31c5Sopenharmony_ci if (options->flags & UV_PROCESS_DETACHED) 308e66f31c5Sopenharmony_ci setsid(); 309e66f31c5Sopenharmony_ci 310e66f31c5Sopenharmony_ci /* First duplicate low numbered fds, since it's not safe to duplicate them, 311e66f31c5Sopenharmony_ci * they could get replaced. Example: swapping stdout and stderr; without 312e66f31c5Sopenharmony_ci * this fd 2 (stderr) would be duplicated into fd 1, thus making both 313e66f31c5Sopenharmony_ci * stdout and stderr go to the same fd, which was not the intention. */ 314e66f31c5Sopenharmony_ci for (fd = 0; fd < stdio_count; fd++) { 315e66f31c5Sopenharmony_ci use_fd = pipes[fd][1]; 316e66f31c5Sopenharmony_ci if (use_fd < 0 || use_fd >= fd) 317e66f31c5Sopenharmony_ci continue; 318e66f31c5Sopenharmony_ci#ifdef F_DUPFD_CLOEXEC /* POSIX 2008 */ 319e66f31c5Sopenharmony_ci pipes[fd][1] = fcntl(use_fd, F_DUPFD_CLOEXEC, stdio_count); 320e66f31c5Sopenharmony_ci#else 321e66f31c5Sopenharmony_ci pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); 322e66f31c5Sopenharmony_ci#endif 323e66f31c5Sopenharmony_ci if (pipes[fd][1] == -1) 324e66f31c5Sopenharmony_ci uv__write_errno(error_fd); 325e66f31c5Sopenharmony_ci#ifndef F_DUPFD_CLOEXEC /* POSIX 2008 */ 326e66f31c5Sopenharmony_ci n = uv__cloexec(pipes[fd][1], 1); 327e66f31c5Sopenharmony_ci if (n) 328e66f31c5Sopenharmony_ci uv__write_int(error_fd, n); 329e66f31c5Sopenharmony_ci#endif 330e66f31c5Sopenharmony_ci } 331e66f31c5Sopenharmony_ci 332e66f31c5Sopenharmony_ci for (fd = 0; fd < stdio_count; fd++) { 333e66f31c5Sopenharmony_ci close_fd = -1; 334e66f31c5Sopenharmony_ci use_fd = pipes[fd][1]; 335e66f31c5Sopenharmony_ci 336e66f31c5Sopenharmony_ci if (use_fd < 0) { 337e66f31c5Sopenharmony_ci if (fd >= 3) 338e66f31c5Sopenharmony_ci continue; 339e66f31c5Sopenharmony_ci else { 340e66f31c5Sopenharmony_ci /* Redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is 341e66f31c5Sopenharmony_ci * set. */ 342e66f31c5Sopenharmony_ci uv__close_nocheckstdio(fd); /* Free up fd, if it happens to be open. */ 343e66f31c5Sopenharmony_ci use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); 344e66f31c5Sopenharmony_ci close_fd = use_fd; 345e66f31c5Sopenharmony_ci 346e66f31c5Sopenharmony_ci if (use_fd < 0) 347e66f31c5Sopenharmony_ci uv__write_errno(error_fd); 348e66f31c5Sopenharmony_ci } 349e66f31c5Sopenharmony_ci } 350e66f31c5Sopenharmony_ci 351e66f31c5Sopenharmony_ci if (fd == use_fd) { 352e66f31c5Sopenharmony_ci if (close_fd == -1) { 353e66f31c5Sopenharmony_ci n = uv__cloexec(use_fd, 0); 354e66f31c5Sopenharmony_ci if (n) 355e66f31c5Sopenharmony_ci uv__write_int(error_fd, n); 356e66f31c5Sopenharmony_ci } 357e66f31c5Sopenharmony_ci } 358e66f31c5Sopenharmony_ci else { 359e66f31c5Sopenharmony_ci fd = dup2(use_fd, fd); 360e66f31c5Sopenharmony_ci } 361e66f31c5Sopenharmony_ci 362e66f31c5Sopenharmony_ci if (fd == -1) 363e66f31c5Sopenharmony_ci uv__write_errno(error_fd); 364e66f31c5Sopenharmony_ci 365e66f31c5Sopenharmony_ci if (fd <= 2 && close_fd == -1) 366e66f31c5Sopenharmony_ci uv__nonblock_fcntl(fd, 0); 367e66f31c5Sopenharmony_ci 368e66f31c5Sopenharmony_ci if (close_fd >= stdio_count) 369e66f31c5Sopenharmony_ci uv__close(close_fd); 370e66f31c5Sopenharmony_ci } 371e66f31c5Sopenharmony_ci 372e66f31c5Sopenharmony_ci if (options->cwd != NULL && chdir(options->cwd)) 373e66f31c5Sopenharmony_ci uv__write_errno(error_fd); 374e66f31c5Sopenharmony_ci 375e66f31c5Sopenharmony_ci if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { 376e66f31c5Sopenharmony_ci /* When dropping privileges from root, the `setgroups` call will 377e66f31c5Sopenharmony_ci * remove any extraneous groups. If we don't call this, then 378e66f31c5Sopenharmony_ci * even though our uid has dropped, we may still have groups 379e66f31c5Sopenharmony_ci * that enable us to do super-user things. This will fail if we 380e66f31c5Sopenharmony_ci * aren't root, so don't bother checking the return value, this 381e66f31c5Sopenharmony_ci * is just done as an optimistic privilege dropping function. 382e66f31c5Sopenharmony_ci */ 383e66f31c5Sopenharmony_ci SAVE_ERRNO(setgroups(0, NULL)); 384e66f31c5Sopenharmony_ci } 385e66f31c5Sopenharmony_ci 386e66f31c5Sopenharmony_ci if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) 387e66f31c5Sopenharmony_ci uv__write_errno(error_fd); 388e66f31c5Sopenharmony_ci 389e66f31c5Sopenharmony_ci if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) 390e66f31c5Sopenharmony_ci uv__write_errno(error_fd); 391e66f31c5Sopenharmony_ci 392e66f31c5Sopenharmony_ci if (options->env != NULL) 393e66f31c5Sopenharmony_ci environ = options->env; 394e66f31c5Sopenharmony_ci 395e66f31c5Sopenharmony_ci /* Reset signal mask just before exec. */ 396e66f31c5Sopenharmony_ci sigemptyset(&signewset); 397e66f31c5Sopenharmony_ci if (sigprocmask(SIG_SETMASK, &signewset, NULL) != 0) 398e66f31c5Sopenharmony_ci abort(); 399e66f31c5Sopenharmony_ci 400e66f31c5Sopenharmony_ci#ifdef __MVS__ 401e66f31c5Sopenharmony_ci execvpe(options->file, options->args, environ); 402e66f31c5Sopenharmony_ci#else 403e66f31c5Sopenharmony_ci execvp(options->file, options->args); 404e66f31c5Sopenharmony_ci#endif 405e66f31c5Sopenharmony_ci 406e66f31c5Sopenharmony_ci uv__write_errno(error_fd); 407e66f31c5Sopenharmony_ci} 408e66f31c5Sopenharmony_ci 409e66f31c5Sopenharmony_ci 410e66f31c5Sopenharmony_ci#if defined(__APPLE__) && !TARGET_OS_IPHONE 411e66f31c5Sopenharmony_citypedef struct uv__posix_spawn_fncs_tag { 412e66f31c5Sopenharmony_ci struct { 413e66f31c5Sopenharmony_ci int (*addchdir_np)(const posix_spawn_file_actions_t *, const char *); 414e66f31c5Sopenharmony_ci } file_actions; 415e66f31c5Sopenharmony_ci} uv__posix_spawn_fncs_t; 416e66f31c5Sopenharmony_ci 417e66f31c5Sopenharmony_ci 418e66f31c5Sopenharmony_cistatic uv_once_t posix_spawn_init_once = UV_ONCE_INIT; 419e66f31c5Sopenharmony_cistatic uv__posix_spawn_fncs_t posix_spawn_fncs; 420e66f31c5Sopenharmony_cistatic int posix_spawn_can_use_setsid; 421e66f31c5Sopenharmony_ci 422e66f31c5Sopenharmony_ci 423e66f31c5Sopenharmony_cistatic void uv__spawn_init_posix_spawn_fncs(void) { 424e66f31c5Sopenharmony_ci /* Try to locate all non-portable functions at runtime */ 425e66f31c5Sopenharmony_ci posix_spawn_fncs.file_actions.addchdir_np = 426e66f31c5Sopenharmony_ci dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_addchdir_np"); 427e66f31c5Sopenharmony_ci} 428e66f31c5Sopenharmony_ci 429e66f31c5Sopenharmony_ci 430e66f31c5Sopenharmony_cistatic void uv__spawn_init_can_use_setsid(void) { 431e66f31c5Sopenharmony_ci int which[] = {CTL_KERN, KERN_OSRELEASE}; 432e66f31c5Sopenharmony_ci unsigned major; 433e66f31c5Sopenharmony_ci unsigned minor; 434e66f31c5Sopenharmony_ci unsigned patch; 435e66f31c5Sopenharmony_ci char buf[256]; 436e66f31c5Sopenharmony_ci size_t len; 437e66f31c5Sopenharmony_ci 438e66f31c5Sopenharmony_ci len = sizeof(buf); 439e66f31c5Sopenharmony_ci if (sysctl(which, ARRAY_SIZE(which), buf, &len, NULL, 0)) 440e66f31c5Sopenharmony_ci return; 441e66f31c5Sopenharmony_ci 442e66f31c5Sopenharmony_ci /* NULL specifies to use LC_C_LOCALE */ 443e66f31c5Sopenharmony_ci if (3 != sscanf_l(buf, NULL, "%u.%u.%u", &major, &minor, &patch)) 444e66f31c5Sopenharmony_ci return; 445e66f31c5Sopenharmony_ci 446e66f31c5Sopenharmony_ci posix_spawn_can_use_setsid = (major >= 19); /* macOS Catalina */ 447e66f31c5Sopenharmony_ci} 448e66f31c5Sopenharmony_ci 449e66f31c5Sopenharmony_ci 450e66f31c5Sopenharmony_cistatic void uv__spawn_init_posix_spawn(void) { 451e66f31c5Sopenharmony_ci /* Init handles to all potentially non-defined functions */ 452e66f31c5Sopenharmony_ci uv__spawn_init_posix_spawn_fncs(); 453e66f31c5Sopenharmony_ci 454e66f31c5Sopenharmony_ci /* Init feature detection for POSIX_SPAWN_SETSID flag */ 455e66f31c5Sopenharmony_ci uv__spawn_init_can_use_setsid(); 456e66f31c5Sopenharmony_ci} 457e66f31c5Sopenharmony_ci 458e66f31c5Sopenharmony_ci 459e66f31c5Sopenharmony_cistatic int uv__spawn_set_posix_spawn_attrs( 460e66f31c5Sopenharmony_ci posix_spawnattr_t* attrs, 461e66f31c5Sopenharmony_ci const uv__posix_spawn_fncs_t* posix_spawn_fncs, 462e66f31c5Sopenharmony_ci const uv_process_options_t* options) { 463e66f31c5Sopenharmony_ci int err; 464e66f31c5Sopenharmony_ci unsigned int flags; 465e66f31c5Sopenharmony_ci sigset_t signal_set; 466e66f31c5Sopenharmony_ci 467e66f31c5Sopenharmony_ci err = posix_spawnattr_init(attrs); 468e66f31c5Sopenharmony_ci if (err != 0) { 469e66f31c5Sopenharmony_ci /* If initialization fails, no need to de-init, just return */ 470e66f31c5Sopenharmony_ci return err; 471e66f31c5Sopenharmony_ci } 472e66f31c5Sopenharmony_ci 473e66f31c5Sopenharmony_ci if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { 474e66f31c5Sopenharmony_ci /* kauth_cred_issuser currently requires exactly uid == 0 for these 475e66f31c5Sopenharmony_ci * posixspawn_attrs (set_groups_np, setuid_np, setgid_np), which deviates 476e66f31c5Sopenharmony_ci * from the normal specification of setuid (which also uses euid), and they 477e66f31c5Sopenharmony_ci * are also undocumented syscalls, so we do not use them. */ 478e66f31c5Sopenharmony_ci err = ENOSYS; 479e66f31c5Sopenharmony_ci goto error; 480e66f31c5Sopenharmony_ci } 481e66f31c5Sopenharmony_ci 482e66f31c5Sopenharmony_ci /* Set flags for spawn behavior 483e66f31c5Sopenharmony_ci * 1) POSIX_SPAWN_CLOEXEC_DEFAULT: (Apple Extension) All descriptors in the 484e66f31c5Sopenharmony_ci * parent will be treated as if they had been created with O_CLOEXEC. The 485e66f31c5Sopenharmony_ci * only fds that will be passed on to the child are those manipulated by 486e66f31c5Sopenharmony_ci * the file actions 487e66f31c5Sopenharmony_ci * 2) POSIX_SPAWN_SETSIGDEF: Signals mentioned in spawn-sigdefault in the 488e66f31c5Sopenharmony_ci * spawn attributes will be reset to behave as their default 489e66f31c5Sopenharmony_ci * 3) POSIX_SPAWN_SETSIGMASK: Signal mask will be set to the value of 490e66f31c5Sopenharmony_ci * spawn-sigmask in attributes 491e66f31c5Sopenharmony_ci * 4) POSIX_SPAWN_SETSID: Make the process a new session leader if a detached 492e66f31c5Sopenharmony_ci * session was requested. */ 493e66f31c5Sopenharmony_ci flags = POSIX_SPAWN_CLOEXEC_DEFAULT | 494e66f31c5Sopenharmony_ci POSIX_SPAWN_SETSIGDEF | 495e66f31c5Sopenharmony_ci POSIX_SPAWN_SETSIGMASK; 496e66f31c5Sopenharmony_ci if (options->flags & UV_PROCESS_DETACHED) { 497e66f31c5Sopenharmony_ci /* If running on a version of macOS where this flag is not supported, 498e66f31c5Sopenharmony_ci * revert back to the fork/exec flow. Otherwise posix_spawn will 499e66f31c5Sopenharmony_ci * silently ignore the flag. */ 500e66f31c5Sopenharmony_ci if (!posix_spawn_can_use_setsid) { 501e66f31c5Sopenharmony_ci err = ENOSYS; 502e66f31c5Sopenharmony_ci goto error; 503e66f31c5Sopenharmony_ci } 504e66f31c5Sopenharmony_ci 505e66f31c5Sopenharmony_ci flags |= POSIX_SPAWN_SETSID; 506e66f31c5Sopenharmony_ci } 507e66f31c5Sopenharmony_ci err = posix_spawnattr_setflags(attrs, flags); 508e66f31c5Sopenharmony_ci if (err != 0) 509e66f31c5Sopenharmony_ci goto error; 510e66f31c5Sopenharmony_ci 511e66f31c5Sopenharmony_ci /* Reset all signal the child to their default behavior */ 512e66f31c5Sopenharmony_ci sigfillset(&signal_set); 513e66f31c5Sopenharmony_ci err = posix_spawnattr_setsigdefault(attrs, &signal_set); 514e66f31c5Sopenharmony_ci if (err != 0) 515e66f31c5Sopenharmony_ci goto error; 516e66f31c5Sopenharmony_ci 517e66f31c5Sopenharmony_ci /* Reset the signal mask for all signals */ 518e66f31c5Sopenharmony_ci sigemptyset(&signal_set); 519e66f31c5Sopenharmony_ci err = posix_spawnattr_setsigmask(attrs, &signal_set); 520e66f31c5Sopenharmony_ci if (err != 0) 521e66f31c5Sopenharmony_ci goto error; 522e66f31c5Sopenharmony_ci 523e66f31c5Sopenharmony_ci return err; 524e66f31c5Sopenharmony_ci 525e66f31c5Sopenharmony_cierror: 526e66f31c5Sopenharmony_ci (void) posix_spawnattr_destroy(attrs); 527e66f31c5Sopenharmony_ci return err; 528e66f31c5Sopenharmony_ci} 529e66f31c5Sopenharmony_ci 530e66f31c5Sopenharmony_ci 531e66f31c5Sopenharmony_cistatic int uv__spawn_set_posix_spawn_file_actions( 532e66f31c5Sopenharmony_ci posix_spawn_file_actions_t* actions, 533e66f31c5Sopenharmony_ci const uv__posix_spawn_fncs_t* posix_spawn_fncs, 534e66f31c5Sopenharmony_ci const uv_process_options_t* options, 535e66f31c5Sopenharmony_ci int stdio_count, 536e66f31c5Sopenharmony_ci int (*pipes)[2]) { 537e66f31c5Sopenharmony_ci int fd; 538e66f31c5Sopenharmony_ci int fd2; 539e66f31c5Sopenharmony_ci int use_fd; 540e66f31c5Sopenharmony_ci int err; 541e66f31c5Sopenharmony_ci 542e66f31c5Sopenharmony_ci err = posix_spawn_file_actions_init(actions); 543e66f31c5Sopenharmony_ci if (err != 0) { 544e66f31c5Sopenharmony_ci /* If initialization fails, no need to de-init, just return */ 545e66f31c5Sopenharmony_ci return err; 546e66f31c5Sopenharmony_ci } 547e66f31c5Sopenharmony_ci 548e66f31c5Sopenharmony_ci /* Set the current working directory if requested */ 549e66f31c5Sopenharmony_ci if (options->cwd != NULL) { 550e66f31c5Sopenharmony_ci if (posix_spawn_fncs->file_actions.addchdir_np == NULL) { 551e66f31c5Sopenharmony_ci err = ENOSYS; 552e66f31c5Sopenharmony_ci goto error; 553e66f31c5Sopenharmony_ci } 554e66f31c5Sopenharmony_ci 555e66f31c5Sopenharmony_ci err = posix_spawn_fncs->file_actions.addchdir_np(actions, options->cwd); 556e66f31c5Sopenharmony_ci if (err != 0) 557e66f31c5Sopenharmony_ci goto error; 558e66f31c5Sopenharmony_ci } 559e66f31c5Sopenharmony_ci 560e66f31c5Sopenharmony_ci /* Do not return ENOSYS after this point, as we may mutate pipes. */ 561e66f31c5Sopenharmony_ci 562e66f31c5Sopenharmony_ci /* First duplicate low numbered fds, since it's not safe to duplicate them, 563e66f31c5Sopenharmony_ci * they could get replaced. Example: swapping stdout and stderr; without 564e66f31c5Sopenharmony_ci * this fd 2 (stderr) would be duplicated into fd 1, thus making both 565e66f31c5Sopenharmony_ci * stdout and stderr go to the same fd, which was not the intention. */ 566e66f31c5Sopenharmony_ci for (fd = 0; fd < stdio_count; fd++) { 567e66f31c5Sopenharmony_ci use_fd = pipes[fd][1]; 568e66f31c5Sopenharmony_ci if (use_fd < 0 || use_fd >= fd) 569e66f31c5Sopenharmony_ci continue; 570e66f31c5Sopenharmony_ci use_fd = stdio_count; 571e66f31c5Sopenharmony_ci for (fd2 = 0; fd2 < stdio_count; fd2++) { 572e66f31c5Sopenharmony_ci /* If we were not setting POSIX_SPAWN_CLOEXEC_DEFAULT, we would need to 573e66f31c5Sopenharmony_ci * also consider whether fcntl(fd, F_GETFD) returned without the 574e66f31c5Sopenharmony_ci * FD_CLOEXEC flag set. */ 575e66f31c5Sopenharmony_ci if (pipes[fd2][1] == use_fd) { 576e66f31c5Sopenharmony_ci use_fd++; 577e66f31c5Sopenharmony_ci fd2 = 0; 578e66f31c5Sopenharmony_ci } 579e66f31c5Sopenharmony_ci } 580e66f31c5Sopenharmony_ci err = posix_spawn_file_actions_adddup2( 581e66f31c5Sopenharmony_ci actions, 582e66f31c5Sopenharmony_ci pipes[fd][1], 583e66f31c5Sopenharmony_ci use_fd); 584e66f31c5Sopenharmony_ci assert(err != ENOSYS); 585e66f31c5Sopenharmony_ci if (err != 0) 586e66f31c5Sopenharmony_ci goto error; 587e66f31c5Sopenharmony_ci pipes[fd][1] = use_fd; 588e66f31c5Sopenharmony_ci } 589e66f31c5Sopenharmony_ci 590e66f31c5Sopenharmony_ci /* Second, move the descriptors into their respective places */ 591e66f31c5Sopenharmony_ci for (fd = 0; fd < stdio_count; fd++) { 592e66f31c5Sopenharmony_ci use_fd = pipes[fd][1]; 593e66f31c5Sopenharmony_ci if (use_fd < 0) { 594e66f31c5Sopenharmony_ci if (fd >= 3) 595e66f31c5Sopenharmony_ci continue; 596e66f31c5Sopenharmony_ci else { 597e66f31c5Sopenharmony_ci /* If ignored, redirect to (or from) /dev/null, */ 598e66f31c5Sopenharmony_ci err = posix_spawn_file_actions_addopen( 599e66f31c5Sopenharmony_ci actions, 600e66f31c5Sopenharmony_ci fd, 601e66f31c5Sopenharmony_ci "/dev/null", 602e66f31c5Sopenharmony_ci fd == 0 ? O_RDONLY : O_RDWR, 603e66f31c5Sopenharmony_ci 0); 604e66f31c5Sopenharmony_ci assert(err != ENOSYS); 605e66f31c5Sopenharmony_ci if (err != 0) 606e66f31c5Sopenharmony_ci goto error; 607e66f31c5Sopenharmony_ci continue; 608e66f31c5Sopenharmony_ci } 609e66f31c5Sopenharmony_ci } 610e66f31c5Sopenharmony_ci 611e66f31c5Sopenharmony_ci if (fd == use_fd) 612e66f31c5Sopenharmony_ci err = posix_spawn_file_actions_addinherit_np(actions, fd); 613e66f31c5Sopenharmony_ci else 614e66f31c5Sopenharmony_ci err = posix_spawn_file_actions_adddup2(actions, use_fd, fd); 615e66f31c5Sopenharmony_ci assert(err != ENOSYS); 616e66f31c5Sopenharmony_ci if (err != 0) 617e66f31c5Sopenharmony_ci goto error; 618e66f31c5Sopenharmony_ci 619e66f31c5Sopenharmony_ci /* Make sure the fd is marked as non-blocking (state shared between child 620e66f31c5Sopenharmony_ci * and parent). */ 621e66f31c5Sopenharmony_ci uv__nonblock_fcntl(use_fd, 0); 622e66f31c5Sopenharmony_ci } 623e66f31c5Sopenharmony_ci 624e66f31c5Sopenharmony_ci /* Finally, close all the superfluous descriptors */ 625e66f31c5Sopenharmony_ci for (fd = 0; fd < stdio_count; fd++) { 626e66f31c5Sopenharmony_ci use_fd = pipes[fd][1]; 627e66f31c5Sopenharmony_ci if (use_fd < stdio_count) 628e66f31c5Sopenharmony_ci continue; 629e66f31c5Sopenharmony_ci 630e66f31c5Sopenharmony_ci /* Check if we already closed this. */ 631e66f31c5Sopenharmony_ci for (fd2 = 0; fd2 < fd; fd2++) { 632e66f31c5Sopenharmony_ci if (pipes[fd2][1] == use_fd) 633e66f31c5Sopenharmony_ci break; 634e66f31c5Sopenharmony_ci } 635e66f31c5Sopenharmony_ci if (fd2 < fd) 636e66f31c5Sopenharmony_ci continue; 637e66f31c5Sopenharmony_ci 638e66f31c5Sopenharmony_ci err = posix_spawn_file_actions_addclose(actions, use_fd); 639e66f31c5Sopenharmony_ci assert(err != ENOSYS); 640e66f31c5Sopenharmony_ci if (err != 0) 641e66f31c5Sopenharmony_ci goto error; 642e66f31c5Sopenharmony_ci } 643e66f31c5Sopenharmony_ci 644e66f31c5Sopenharmony_ci return 0; 645e66f31c5Sopenharmony_ci 646e66f31c5Sopenharmony_cierror: 647e66f31c5Sopenharmony_ci (void) posix_spawn_file_actions_destroy(actions); 648e66f31c5Sopenharmony_ci return err; 649e66f31c5Sopenharmony_ci} 650e66f31c5Sopenharmony_ci 651e66f31c5Sopenharmony_cichar* uv__spawn_find_path_in_env(char** env) { 652e66f31c5Sopenharmony_ci char** env_iterator; 653e66f31c5Sopenharmony_ci const char path_var[] = "PATH="; 654e66f31c5Sopenharmony_ci 655e66f31c5Sopenharmony_ci /* Look for an environment variable called PATH in the 656e66f31c5Sopenharmony_ci * provided env array, and return its value if found */ 657e66f31c5Sopenharmony_ci for (env_iterator = env; *env_iterator != NULL; env_iterator++) { 658e66f31c5Sopenharmony_ci if (strncmp(*env_iterator, path_var, sizeof(path_var) - 1) == 0) { 659e66f31c5Sopenharmony_ci /* Found "PATH=" at the beginning of the string */ 660e66f31c5Sopenharmony_ci return *env_iterator + sizeof(path_var) - 1; 661e66f31c5Sopenharmony_ci } 662e66f31c5Sopenharmony_ci } 663e66f31c5Sopenharmony_ci 664e66f31c5Sopenharmony_ci return NULL; 665e66f31c5Sopenharmony_ci} 666e66f31c5Sopenharmony_ci 667e66f31c5Sopenharmony_ci 668e66f31c5Sopenharmony_cistatic int uv__spawn_resolve_and_spawn(const uv_process_options_t* options, 669e66f31c5Sopenharmony_ci posix_spawnattr_t* attrs, 670e66f31c5Sopenharmony_ci posix_spawn_file_actions_t* actions, 671e66f31c5Sopenharmony_ci pid_t* pid) { 672e66f31c5Sopenharmony_ci const char *p; 673e66f31c5Sopenharmony_ci const char *z; 674e66f31c5Sopenharmony_ci const char *path; 675e66f31c5Sopenharmony_ci size_t l; 676e66f31c5Sopenharmony_ci size_t k; 677e66f31c5Sopenharmony_ci int err; 678e66f31c5Sopenharmony_ci int seen_eacces; 679e66f31c5Sopenharmony_ci 680e66f31c5Sopenharmony_ci path = NULL; 681e66f31c5Sopenharmony_ci err = -1; 682e66f31c5Sopenharmony_ci seen_eacces = 0; 683e66f31c5Sopenharmony_ci 684e66f31c5Sopenharmony_ci /* Short circuit for erroneous case */ 685e66f31c5Sopenharmony_ci if (options->file == NULL) 686e66f31c5Sopenharmony_ci return ENOENT; 687e66f31c5Sopenharmony_ci 688e66f31c5Sopenharmony_ci /* The environment for the child process is that of the parent unless overridden 689e66f31c5Sopenharmony_ci * by options->env */ 690e66f31c5Sopenharmony_ci char** env = environ; 691e66f31c5Sopenharmony_ci if (options->env != NULL) 692e66f31c5Sopenharmony_ci env = options->env; 693e66f31c5Sopenharmony_ci 694e66f31c5Sopenharmony_ci /* If options->file contains a slash, posix_spawn/posix_spawnp should behave 695e66f31c5Sopenharmony_ci * the same, and do not involve PATH resolution at all. The libc 696e66f31c5Sopenharmony_ci * `posix_spawnp` provided by Apple is buggy (since 10.15), so we now emulate it 697e66f31c5Sopenharmony_ci * here, per https://github.com/libuv/libuv/pull/3583. */ 698e66f31c5Sopenharmony_ci if (strchr(options->file, '/') != NULL) { 699e66f31c5Sopenharmony_ci do 700e66f31c5Sopenharmony_ci err = posix_spawn(pid, options->file, actions, attrs, options->args, env); 701e66f31c5Sopenharmony_ci while (err == EINTR); 702e66f31c5Sopenharmony_ci return err; 703e66f31c5Sopenharmony_ci } 704e66f31c5Sopenharmony_ci 705e66f31c5Sopenharmony_ci /* Look for the definition of PATH in the provided env */ 706e66f31c5Sopenharmony_ci path = uv__spawn_find_path_in_env(env); 707e66f31c5Sopenharmony_ci 708e66f31c5Sopenharmony_ci /* The following resolution logic (execvpe emulation) is copied from 709e66f31c5Sopenharmony_ci * https://git.musl-libc.org/cgit/musl/tree/src/process/execvp.c 710e66f31c5Sopenharmony_ci * and adapted to work for our specific usage */ 711e66f31c5Sopenharmony_ci 712e66f31c5Sopenharmony_ci /* If no path was provided in env, use the default value 713e66f31c5Sopenharmony_ci * to look for the executable */ 714e66f31c5Sopenharmony_ci if (path == NULL) 715e66f31c5Sopenharmony_ci path = _PATH_DEFPATH; 716e66f31c5Sopenharmony_ci 717e66f31c5Sopenharmony_ci k = strnlen(options->file, NAME_MAX + 1); 718e66f31c5Sopenharmony_ci if (k > NAME_MAX) 719e66f31c5Sopenharmony_ci return ENAMETOOLONG; 720e66f31c5Sopenharmony_ci 721e66f31c5Sopenharmony_ci l = strnlen(path, PATH_MAX - 1) + 1; 722e66f31c5Sopenharmony_ci 723e66f31c5Sopenharmony_ci for (p = path;; p = z) { 724e66f31c5Sopenharmony_ci /* Compose the new process file from the entry in the PATH 725e66f31c5Sopenharmony_ci * environment variable and the actual file name */ 726e66f31c5Sopenharmony_ci char b[PATH_MAX + NAME_MAX]; 727e66f31c5Sopenharmony_ci z = strchr(p, ':'); 728e66f31c5Sopenharmony_ci if (!z) 729e66f31c5Sopenharmony_ci z = p + strlen(p); 730e66f31c5Sopenharmony_ci if ((size_t)(z - p) >= l) { 731e66f31c5Sopenharmony_ci if (!*z++) 732e66f31c5Sopenharmony_ci break; 733e66f31c5Sopenharmony_ci 734e66f31c5Sopenharmony_ci continue; 735e66f31c5Sopenharmony_ci } 736e66f31c5Sopenharmony_ci memcpy(b, p, z - p); 737e66f31c5Sopenharmony_ci b[z - p] = '/'; 738e66f31c5Sopenharmony_ci memcpy(b + (z - p) + (z > p), options->file, k + 1); 739e66f31c5Sopenharmony_ci 740e66f31c5Sopenharmony_ci /* Try to spawn the new process file. If it fails with ENOENT, the 741e66f31c5Sopenharmony_ci * new process file is not in this PATH entry, continue with the next 742e66f31c5Sopenharmony_ci * PATH entry. */ 743e66f31c5Sopenharmony_ci do 744e66f31c5Sopenharmony_ci err = posix_spawn(pid, b, actions, attrs, options->args, env); 745e66f31c5Sopenharmony_ci while (err == EINTR); 746e66f31c5Sopenharmony_ci 747e66f31c5Sopenharmony_ci switch (err) { 748e66f31c5Sopenharmony_ci case EACCES: 749e66f31c5Sopenharmony_ci seen_eacces = 1; 750e66f31c5Sopenharmony_ci break; /* continue search */ 751e66f31c5Sopenharmony_ci case ENOENT: 752e66f31c5Sopenharmony_ci case ENOTDIR: 753e66f31c5Sopenharmony_ci break; /* continue search */ 754e66f31c5Sopenharmony_ci default: 755e66f31c5Sopenharmony_ci return err; 756e66f31c5Sopenharmony_ci } 757e66f31c5Sopenharmony_ci 758e66f31c5Sopenharmony_ci if (!*z++) 759e66f31c5Sopenharmony_ci break; 760e66f31c5Sopenharmony_ci } 761e66f31c5Sopenharmony_ci 762e66f31c5Sopenharmony_ci if (seen_eacces) 763e66f31c5Sopenharmony_ci return EACCES; 764e66f31c5Sopenharmony_ci return err; 765e66f31c5Sopenharmony_ci} 766e66f31c5Sopenharmony_ci 767e66f31c5Sopenharmony_ci 768e66f31c5Sopenharmony_cistatic int uv__spawn_and_init_child_posix_spawn( 769e66f31c5Sopenharmony_ci const uv_process_options_t* options, 770e66f31c5Sopenharmony_ci int stdio_count, 771e66f31c5Sopenharmony_ci int (*pipes)[2], 772e66f31c5Sopenharmony_ci pid_t* pid, 773e66f31c5Sopenharmony_ci const uv__posix_spawn_fncs_t* posix_spawn_fncs) { 774e66f31c5Sopenharmony_ci int err; 775e66f31c5Sopenharmony_ci posix_spawnattr_t attrs; 776e66f31c5Sopenharmony_ci posix_spawn_file_actions_t actions; 777e66f31c5Sopenharmony_ci 778e66f31c5Sopenharmony_ci err = uv__spawn_set_posix_spawn_attrs(&attrs, posix_spawn_fncs, options); 779e66f31c5Sopenharmony_ci if (err != 0) 780e66f31c5Sopenharmony_ci goto error; 781e66f31c5Sopenharmony_ci 782e66f31c5Sopenharmony_ci /* This may mutate pipes. */ 783e66f31c5Sopenharmony_ci err = uv__spawn_set_posix_spawn_file_actions(&actions, 784e66f31c5Sopenharmony_ci posix_spawn_fncs, 785e66f31c5Sopenharmony_ci options, 786e66f31c5Sopenharmony_ci stdio_count, 787e66f31c5Sopenharmony_ci pipes); 788e66f31c5Sopenharmony_ci if (err != 0) { 789e66f31c5Sopenharmony_ci (void) posix_spawnattr_destroy(&attrs); 790e66f31c5Sopenharmony_ci goto error; 791e66f31c5Sopenharmony_ci } 792e66f31c5Sopenharmony_ci 793e66f31c5Sopenharmony_ci /* Try to spawn options->file resolving in the provided environment 794e66f31c5Sopenharmony_ci * if any */ 795e66f31c5Sopenharmony_ci err = uv__spawn_resolve_and_spawn(options, &attrs, &actions, pid); 796e66f31c5Sopenharmony_ci assert(err != ENOSYS); 797e66f31c5Sopenharmony_ci 798e66f31c5Sopenharmony_ci /* Destroy the actions/attributes */ 799e66f31c5Sopenharmony_ci (void) posix_spawn_file_actions_destroy(&actions); 800e66f31c5Sopenharmony_ci (void) posix_spawnattr_destroy(&attrs); 801e66f31c5Sopenharmony_ci 802e66f31c5Sopenharmony_cierror: 803e66f31c5Sopenharmony_ci /* In an error situation, the attributes and file actions are 804e66f31c5Sopenharmony_ci * already destroyed, only the happy path requires cleanup */ 805e66f31c5Sopenharmony_ci return UV__ERR(err); 806e66f31c5Sopenharmony_ci} 807e66f31c5Sopenharmony_ci#endif 808e66f31c5Sopenharmony_ci 809e66f31c5Sopenharmony_cistatic int uv__spawn_and_init_child_fork(const uv_process_options_t* options, 810e66f31c5Sopenharmony_ci int stdio_count, 811e66f31c5Sopenharmony_ci int (*pipes)[2], 812e66f31c5Sopenharmony_ci int error_fd, 813e66f31c5Sopenharmony_ci pid_t* pid) { 814e66f31c5Sopenharmony_ci sigset_t signewset; 815e66f31c5Sopenharmony_ci sigset_t sigoldset; 816e66f31c5Sopenharmony_ci 817e66f31c5Sopenharmony_ci /* Start the child with most signals blocked, to avoid any issues before we 818e66f31c5Sopenharmony_ci * can reset them, but allow program failures to exit (and not hang). */ 819e66f31c5Sopenharmony_ci sigfillset(&signewset); 820e66f31c5Sopenharmony_ci sigdelset(&signewset, SIGKILL); 821e66f31c5Sopenharmony_ci sigdelset(&signewset, SIGSTOP); 822e66f31c5Sopenharmony_ci sigdelset(&signewset, SIGTRAP); 823e66f31c5Sopenharmony_ci sigdelset(&signewset, SIGSEGV); 824e66f31c5Sopenharmony_ci sigdelset(&signewset, SIGBUS); 825e66f31c5Sopenharmony_ci sigdelset(&signewset, SIGILL); 826e66f31c5Sopenharmony_ci sigdelset(&signewset, SIGSYS); 827e66f31c5Sopenharmony_ci sigdelset(&signewset, SIGABRT); 828e66f31c5Sopenharmony_ci if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0) 829e66f31c5Sopenharmony_ci abort(); 830e66f31c5Sopenharmony_ci 831e66f31c5Sopenharmony_ci *pid = fork(); 832e66f31c5Sopenharmony_ci 833e66f31c5Sopenharmony_ci if (*pid == 0) { 834e66f31c5Sopenharmony_ci /* Fork succeeded, in the child process */ 835e66f31c5Sopenharmony_ci uv__process_child_init(options, stdio_count, pipes, error_fd); 836e66f31c5Sopenharmony_ci abort(); 837e66f31c5Sopenharmony_ci } 838e66f31c5Sopenharmony_ci 839e66f31c5Sopenharmony_ci if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) 840e66f31c5Sopenharmony_ci abort(); 841e66f31c5Sopenharmony_ci 842e66f31c5Sopenharmony_ci if (*pid == -1) 843e66f31c5Sopenharmony_ci /* Failed to fork */ 844e66f31c5Sopenharmony_ci return UV__ERR(errno); 845e66f31c5Sopenharmony_ci 846e66f31c5Sopenharmony_ci /* Fork succeeded, in the parent process */ 847e66f31c5Sopenharmony_ci return 0; 848e66f31c5Sopenharmony_ci} 849e66f31c5Sopenharmony_ci 850e66f31c5Sopenharmony_cistatic int uv__spawn_and_init_child( 851e66f31c5Sopenharmony_ci uv_loop_t* loop, 852e66f31c5Sopenharmony_ci const uv_process_options_t* options, 853e66f31c5Sopenharmony_ci int stdio_count, 854e66f31c5Sopenharmony_ci int (*pipes)[2], 855e66f31c5Sopenharmony_ci pid_t* pid) { 856e66f31c5Sopenharmony_ci int signal_pipe[2] = { -1, -1 }; 857e66f31c5Sopenharmony_ci int status; 858e66f31c5Sopenharmony_ci int err; 859e66f31c5Sopenharmony_ci int exec_errorno; 860e66f31c5Sopenharmony_ci ssize_t r; 861e66f31c5Sopenharmony_ci 862e66f31c5Sopenharmony_ci#if defined(__APPLE__) && !TARGET_OS_IPHONE 863e66f31c5Sopenharmony_ci uv_once(&posix_spawn_init_once, uv__spawn_init_posix_spawn); 864e66f31c5Sopenharmony_ci 865e66f31c5Sopenharmony_ci /* Special child process spawn case for macOS Big Sur (11.0) onwards 866e66f31c5Sopenharmony_ci * 867e66f31c5Sopenharmony_ci * Big Sur introduced a significant performance degradation on a call to 868e66f31c5Sopenharmony_ci * fork/exec when the process has many pages mmaped in with MAP_JIT, like, say 869e66f31c5Sopenharmony_ci * a javascript interpreter. Electron-based applications, for example, 870e66f31c5Sopenharmony_ci * are impacted; though the magnitude of the impact depends on how much the 871e66f31c5Sopenharmony_ci * app relies on subprocesses. 872e66f31c5Sopenharmony_ci * 873e66f31c5Sopenharmony_ci * On macOS, though, posix_spawn is implemented in a way that does not 874e66f31c5Sopenharmony_ci * exhibit the problem. This block implements the forking and preparation 875e66f31c5Sopenharmony_ci * logic with posix_spawn and its related primitives. It also takes advantage of 876e66f31c5Sopenharmony_ci * the macOS extension POSIX_SPAWN_CLOEXEC_DEFAULT that makes impossible to 877e66f31c5Sopenharmony_ci * leak descriptors to the child process. */ 878e66f31c5Sopenharmony_ci err = uv__spawn_and_init_child_posix_spawn(options, 879e66f31c5Sopenharmony_ci stdio_count, 880e66f31c5Sopenharmony_ci pipes, 881e66f31c5Sopenharmony_ci pid, 882e66f31c5Sopenharmony_ci &posix_spawn_fncs); 883e66f31c5Sopenharmony_ci 884e66f31c5Sopenharmony_ci /* The posix_spawn flow will return UV_ENOSYS if any of the posix_spawn_x_np 885e66f31c5Sopenharmony_ci * non-standard functions is both _needed_ and _undefined_. In those cases, 886e66f31c5Sopenharmony_ci * default back to the fork/execve strategy. For all other errors, just fail. */ 887e66f31c5Sopenharmony_ci if (err != UV_ENOSYS) 888e66f31c5Sopenharmony_ci return err; 889e66f31c5Sopenharmony_ci 890e66f31c5Sopenharmony_ci#endif 891e66f31c5Sopenharmony_ci 892e66f31c5Sopenharmony_ci /* This pipe is used by the parent to wait until 893e66f31c5Sopenharmony_ci * the child has called `execve()`. We need this 894e66f31c5Sopenharmony_ci * to avoid the following race condition: 895e66f31c5Sopenharmony_ci * 896e66f31c5Sopenharmony_ci * if ((pid = fork()) > 0) { 897e66f31c5Sopenharmony_ci * kill(pid, SIGTERM); 898e66f31c5Sopenharmony_ci * } 899e66f31c5Sopenharmony_ci * else if (pid == 0) { 900e66f31c5Sopenharmony_ci * execve("/bin/cat", argp, envp); 901e66f31c5Sopenharmony_ci * } 902e66f31c5Sopenharmony_ci * 903e66f31c5Sopenharmony_ci * The parent sends a signal immediately after forking. 904e66f31c5Sopenharmony_ci * Since the child may not have called `execve()` yet, 905e66f31c5Sopenharmony_ci * there is no telling what process receives the signal, 906e66f31c5Sopenharmony_ci * our fork or /bin/cat. 907e66f31c5Sopenharmony_ci * 908e66f31c5Sopenharmony_ci * To avoid ambiguity, we create a pipe with both ends 909e66f31c5Sopenharmony_ci * marked close-on-exec. Then, after the call to `fork()`, 910e66f31c5Sopenharmony_ci * the parent polls the read end until it EOFs or errors with EPIPE. 911e66f31c5Sopenharmony_ci */ 912e66f31c5Sopenharmony_ci err = uv__make_pipe(signal_pipe, 0); 913e66f31c5Sopenharmony_ci if (err) 914e66f31c5Sopenharmony_ci return err; 915e66f31c5Sopenharmony_ci 916e66f31c5Sopenharmony_ci /* Acquire write lock to prevent opening new fds in worker threads */ 917e66f31c5Sopenharmony_ci uv_rwlock_wrlock(&loop->cloexec_lock); 918e66f31c5Sopenharmony_ci 919e66f31c5Sopenharmony_ci err = uv__spawn_and_init_child_fork(options, stdio_count, pipes, signal_pipe[1], pid); 920e66f31c5Sopenharmony_ci 921e66f31c5Sopenharmony_ci /* Release lock in parent process */ 922e66f31c5Sopenharmony_ci uv_rwlock_wrunlock(&loop->cloexec_lock); 923e66f31c5Sopenharmony_ci 924e66f31c5Sopenharmony_ci uv__close(signal_pipe[1]); 925e66f31c5Sopenharmony_ci 926e66f31c5Sopenharmony_ci if (err == 0) { 927e66f31c5Sopenharmony_ci do 928e66f31c5Sopenharmony_ci r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno)); 929e66f31c5Sopenharmony_ci while (r == -1 && errno == EINTR); 930e66f31c5Sopenharmony_ci 931e66f31c5Sopenharmony_ci if (r == 0) 932e66f31c5Sopenharmony_ci ; /* okay, EOF */ 933e66f31c5Sopenharmony_ci else if (r == sizeof(exec_errorno)) { 934e66f31c5Sopenharmony_ci do 935e66f31c5Sopenharmony_ci err = waitpid(*pid, &status, 0); /* okay, read errorno */ 936e66f31c5Sopenharmony_ci while (err == -1 && errno == EINTR); 937e66f31c5Sopenharmony_ci assert(err == *pid); 938e66f31c5Sopenharmony_ci err = exec_errorno; 939e66f31c5Sopenharmony_ci } else if (r == -1 && errno == EPIPE) { 940e66f31c5Sopenharmony_ci /* Something unknown happened to our child before spawn */ 941e66f31c5Sopenharmony_ci do 942e66f31c5Sopenharmony_ci err = waitpid(*pid, &status, 0); /* okay, got EPIPE */ 943e66f31c5Sopenharmony_ci while (err == -1 && errno == EINTR); 944e66f31c5Sopenharmony_ci assert(err == *pid); 945e66f31c5Sopenharmony_ci err = UV_EPIPE; 946e66f31c5Sopenharmony_ci } else 947e66f31c5Sopenharmony_ci abort(); 948e66f31c5Sopenharmony_ci } 949e66f31c5Sopenharmony_ci 950e66f31c5Sopenharmony_ci uv__close_nocheckstdio(signal_pipe[0]); 951e66f31c5Sopenharmony_ci 952e66f31c5Sopenharmony_ci return err; 953e66f31c5Sopenharmony_ci} 954e66f31c5Sopenharmony_ci#endif /* ISN'T TARGET_OS_TV || TARGET_OS_WATCH */ 955e66f31c5Sopenharmony_ci 956e66f31c5Sopenharmony_ciint uv_spawn(uv_loop_t* loop, 957e66f31c5Sopenharmony_ci uv_process_t* process, 958e66f31c5Sopenharmony_ci const uv_process_options_t* options) { 959e66f31c5Sopenharmony_ci#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) 960e66f31c5Sopenharmony_ci /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ 961e66f31c5Sopenharmony_ci return UV_ENOSYS; 962e66f31c5Sopenharmony_ci#else 963e66f31c5Sopenharmony_ci int pipes_storage[8][2]; 964e66f31c5Sopenharmony_ci int (*pipes)[2]; 965e66f31c5Sopenharmony_ci int stdio_count; 966e66f31c5Sopenharmony_ci pid_t pid; 967e66f31c5Sopenharmony_ci int err; 968e66f31c5Sopenharmony_ci int exec_errorno; 969e66f31c5Sopenharmony_ci int i; 970e66f31c5Sopenharmony_ci 971e66f31c5Sopenharmony_ci assert(options->file != NULL); 972e66f31c5Sopenharmony_ci assert(!(options->flags & ~(UV_PROCESS_DETACHED | 973e66f31c5Sopenharmony_ci UV_PROCESS_SETGID | 974e66f31c5Sopenharmony_ci UV_PROCESS_SETUID | 975e66f31c5Sopenharmony_ci UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME | 976e66f31c5Sopenharmony_ci UV_PROCESS_WINDOWS_HIDE | 977e66f31c5Sopenharmony_ci UV_PROCESS_WINDOWS_HIDE_CONSOLE | 978e66f31c5Sopenharmony_ci UV_PROCESS_WINDOWS_HIDE_GUI | 979e66f31c5Sopenharmony_ci UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); 980e66f31c5Sopenharmony_ci 981e66f31c5Sopenharmony_ci uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); 982e66f31c5Sopenharmony_ci uv__queue_init(&process->queue); 983e66f31c5Sopenharmony_ci process->status = 0; 984e66f31c5Sopenharmony_ci 985e66f31c5Sopenharmony_ci stdio_count = options->stdio_count; 986e66f31c5Sopenharmony_ci if (stdio_count < 3) 987e66f31c5Sopenharmony_ci stdio_count = 3; 988e66f31c5Sopenharmony_ci 989e66f31c5Sopenharmony_ci err = UV_ENOMEM; 990e66f31c5Sopenharmony_ci pipes = pipes_storage; 991e66f31c5Sopenharmony_ci if (stdio_count > (int) ARRAY_SIZE(pipes_storage)) 992e66f31c5Sopenharmony_ci pipes = uv__malloc(stdio_count * sizeof(*pipes)); 993e66f31c5Sopenharmony_ci 994e66f31c5Sopenharmony_ci if (pipes == NULL) 995e66f31c5Sopenharmony_ci goto error; 996e66f31c5Sopenharmony_ci 997e66f31c5Sopenharmony_ci for (i = 0; i < stdio_count; i++) { 998e66f31c5Sopenharmony_ci pipes[i][0] = -1; 999e66f31c5Sopenharmony_ci pipes[i][1] = -1; 1000e66f31c5Sopenharmony_ci } 1001e66f31c5Sopenharmony_ci 1002e66f31c5Sopenharmony_ci for (i = 0; i < options->stdio_count; i++) { 1003e66f31c5Sopenharmony_ci err = uv__process_init_stdio(options->stdio + i, pipes[i]); 1004e66f31c5Sopenharmony_ci if (err) 1005e66f31c5Sopenharmony_ci goto error; 1006e66f31c5Sopenharmony_ci } 1007e66f31c5Sopenharmony_ci 1008e66f31c5Sopenharmony_ci#ifdef UV_USE_SIGCHLD 1009e66f31c5Sopenharmony_ci uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); 1010e66f31c5Sopenharmony_ci#endif 1011e66f31c5Sopenharmony_ci 1012e66f31c5Sopenharmony_ci /* Spawn the child */ 1013e66f31c5Sopenharmony_ci exec_errorno = uv__spawn_and_init_child(loop, options, stdio_count, pipes, &pid); 1014e66f31c5Sopenharmony_ci 1015e66f31c5Sopenharmony_ci#if 0 1016e66f31c5Sopenharmony_ci /* This runs into a nodejs issue (it expects initialized streams, even if the 1017e66f31c5Sopenharmony_ci * exec failed). 1018e66f31c5Sopenharmony_ci * See https://github.com/libuv/libuv/pull/3107#issuecomment-782482608 */ 1019e66f31c5Sopenharmony_ci if (exec_errorno != 0) 1020e66f31c5Sopenharmony_ci goto error; 1021e66f31c5Sopenharmony_ci#endif 1022e66f31c5Sopenharmony_ci 1023e66f31c5Sopenharmony_ci /* Activate this handle if exec() happened successfully, even if we later 1024e66f31c5Sopenharmony_ci * fail to open a stdio handle. This ensures we can eventually reap the child 1025e66f31c5Sopenharmony_ci * with waitpid. */ 1026e66f31c5Sopenharmony_ci if (exec_errorno == 0) { 1027e66f31c5Sopenharmony_ci#ifndef UV_USE_SIGCHLD 1028e66f31c5Sopenharmony_ci struct kevent event; 1029e66f31c5Sopenharmony_ci EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0); 1030e66f31c5Sopenharmony_ci if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) { 1031e66f31c5Sopenharmony_ci if (errno != ESRCH) 1032e66f31c5Sopenharmony_ci abort(); 1033e66f31c5Sopenharmony_ci /* Process already exited. Call waitpid on the next loop iteration. */ 1034e66f31c5Sopenharmony_ci process->flags |= UV_HANDLE_REAP; 1035e66f31c5Sopenharmony_ci loop->flags |= UV_LOOP_REAP_CHILDREN; 1036e66f31c5Sopenharmony_ci } 1037e66f31c5Sopenharmony_ci /* This prevents uv__io_poll() from bailing out prematurely, being unaware 1038e66f31c5Sopenharmony_ci * that we added an event here for it to react to. We will decrement this 1039e66f31c5Sopenharmony_ci * again after the waitpid call succeeds. */ 1040e66f31c5Sopenharmony_ci loop->nfds++; 1041e66f31c5Sopenharmony_ci#endif 1042e66f31c5Sopenharmony_ci 1043e66f31c5Sopenharmony_ci process->pid = pid; 1044e66f31c5Sopenharmony_ci process->exit_cb = options->exit_cb; 1045e66f31c5Sopenharmony_ci uv__queue_insert_tail(&loop->process_handles, &process->queue); 1046e66f31c5Sopenharmony_ci uv__handle_start(process); 1047e66f31c5Sopenharmony_ci } 1048e66f31c5Sopenharmony_ci 1049e66f31c5Sopenharmony_ci for (i = 0; i < options->stdio_count; i++) { 1050e66f31c5Sopenharmony_ci err = uv__process_open_stream(options->stdio + i, pipes[i]); 1051e66f31c5Sopenharmony_ci if (err == 0) 1052e66f31c5Sopenharmony_ci continue; 1053e66f31c5Sopenharmony_ci 1054e66f31c5Sopenharmony_ci while (i--) 1055e66f31c5Sopenharmony_ci uv__process_close_stream(options->stdio + i); 1056e66f31c5Sopenharmony_ci 1057e66f31c5Sopenharmony_ci goto error; 1058e66f31c5Sopenharmony_ci } 1059e66f31c5Sopenharmony_ci 1060e66f31c5Sopenharmony_ci if (pipes != pipes_storage) 1061e66f31c5Sopenharmony_ci uv__free(pipes); 1062e66f31c5Sopenharmony_ci 1063e66f31c5Sopenharmony_ci return exec_errorno; 1064e66f31c5Sopenharmony_ci 1065e66f31c5Sopenharmony_cierror: 1066e66f31c5Sopenharmony_ci if (pipes != NULL) { 1067e66f31c5Sopenharmony_ci for (i = 0; i < stdio_count; i++) { 1068e66f31c5Sopenharmony_ci if (i < options->stdio_count) 1069e66f31c5Sopenharmony_ci if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) 1070e66f31c5Sopenharmony_ci continue; 1071e66f31c5Sopenharmony_ci if (pipes[i][0] != -1) 1072e66f31c5Sopenharmony_ci uv__close_nocheckstdio(pipes[i][0]); 1073e66f31c5Sopenharmony_ci if (pipes[i][1] != -1) 1074e66f31c5Sopenharmony_ci uv__close_nocheckstdio(pipes[i][1]); 1075e66f31c5Sopenharmony_ci } 1076e66f31c5Sopenharmony_ci 1077e66f31c5Sopenharmony_ci if (pipes != pipes_storage) 1078e66f31c5Sopenharmony_ci uv__free(pipes); 1079e66f31c5Sopenharmony_ci } 1080e66f31c5Sopenharmony_ci 1081e66f31c5Sopenharmony_ci return err; 1082e66f31c5Sopenharmony_ci#endif 1083e66f31c5Sopenharmony_ci} 1084e66f31c5Sopenharmony_ci 1085e66f31c5Sopenharmony_ci 1086e66f31c5Sopenharmony_ciint uv_process_kill(uv_process_t* process, int signum) { 1087e66f31c5Sopenharmony_ci return uv_kill(process->pid, signum); 1088e66f31c5Sopenharmony_ci} 1089e66f31c5Sopenharmony_ci 1090e66f31c5Sopenharmony_ci 1091e66f31c5Sopenharmony_ciint uv_kill(int pid, int signum) { 1092e66f31c5Sopenharmony_ci if (kill(pid, signum)) { 1093e66f31c5Sopenharmony_ci#if defined(__MVS__) 1094e66f31c5Sopenharmony_ci /* EPERM is returned if the process is a zombie. */ 1095e66f31c5Sopenharmony_ci siginfo_t infop; 1096e66f31c5Sopenharmony_ci if (errno == EPERM && 1097e66f31c5Sopenharmony_ci waitid(P_PID, pid, &infop, WNOHANG | WNOWAIT | WEXITED) == 0) 1098e66f31c5Sopenharmony_ci return 0; 1099e66f31c5Sopenharmony_ci#endif 1100e66f31c5Sopenharmony_ci return UV__ERR(errno); 1101e66f31c5Sopenharmony_ci } else 1102e66f31c5Sopenharmony_ci return 0; 1103e66f31c5Sopenharmony_ci} 1104e66f31c5Sopenharmony_ci 1105e66f31c5Sopenharmony_ci 1106e66f31c5Sopenharmony_civoid uv__process_close(uv_process_t* handle) { 1107e66f31c5Sopenharmony_ci uv__queue_remove(&handle->queue); 1108e66f31c5Sopenharmony_ci uv__handle_stop(handle); 1109e66f31c5Sopenharmony_ci#ifdef UV_USE_SIGCHLD 1110e66f31c5Sopenharmony_ci if (uv__queue_empty(&handle->loop->process_handles)) 1111e66f31c5Sopenharmony_ci uv_signal_stop(&handle->loop->child_watcher); 1112e66f31c5Sopenharmony_ci#endif 1113e66f31c5Sopenharmony_ci} 1114