summaryrefslogtreecommitdiffstats
path: root/Utilities/cmlibuv/src/unix/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmlibuv/src/unix/process.c')
-rw-r--r--Utilities/cmlibuv/src/unix/process.c210
1 files changed, 82 insertions, 128 deletions
diff --git a/Utilities/cmlibuv/src/unix/process.c b/Utilities/cmlibuv/src/unix/process.c
index 08aa2f3..2af2088 100644
--- a/Utilities/cmlibuv/src/unix/process.c
+++ b/Utilities/cmlibuv/src/unix/process.c
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
+#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -45,6 +46,10 @@ extern char **environ;
# include <grp.h>
#endif
+#if defined(__MVS__)
+# include "zos-base.h"
+#endif
+
#ifndef CMAKE_BOOTSTRAP
#if defined(__linux__)
# define uv__cpu_set_t cpu_set_t
@@ -122,68 +127,6 @@ static void uv__chld(uv_signal_t* handle, int signum) {
assert(QUEUE_EMPTY(&pending));
}
-
-static int uv__make_socketpair(int fds[2]) {
-#if defined(__FreeBSD__) || defined(__linux__)
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds))
- return UV__ERR(errno);
-
- return 0;
-#else
- int err;
-
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
- return UV__ERR(errno);
-
- err = uv__cloexec(fds[0], 1);
- if (err == 0)
- err = uv__cloexec(fds[1], 1);
-
- if (err != 0) {
- uv__close(fds[0]);
- uv__close(fds[1]);
- return UV__ERR(errno);
- }
-
- return 0;
-#endif
-}
-
-
-int uv__make_pipe(int fds[2], int flags) {
-#if defined(__FreeBSD__) || defined(__linux__)
- if (pipe2(fds, flags | O_CLOEXEC))
- return UV__ERR(errno);
-
- return 0;
-#else
- if (pipe(fds))
- return UV__ERR(errno);
-
- if (uv__cloexec(fds[0], 1))
- goto fail;
-
- if (uv__cloexec(fds[1], 1))
- goto fail;
-
- if (flags & UV__F_NONBLOCK) {
- if (uv__nonblock(fds[0], 1))
- goto fail;
-
- if (uv__nonblock(fds[1], 1))
- goto fail;
- }
-
- return 0;
-
-fail:
- uv__close(fds[0]);
- uv__close(fds[1]);
- return UV__ERR(errno);
-#endif
-}
-
-
/*
* Used for initializing stdio streams like options.stdin_stream. Returns
* zero on success. See also the cleanup section in uv_spawn().
@@ -203,7 +146,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
if (container->data.stream->type != UV_NAMED_PIPE)
return UV_EINVAL;
else
- return uv__make_socketpair(fds);
+ return uv_socketpair(SOCK_STREAM, 0, fds, 0, 0);
case UV_INHERIT_FD:
case UV_INHERIT_STREAM:
@@ -270,6 +213,12 @@ static void uv__write_int(int fd, int val) {
}
+static void uv__write_errno(int error_fd) {
+ uv__write_int(error_fd, UV__ERR(errno));
+ _exit(127);
+}
+
+
#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
* avoided. Since this isn't called on those targets, the function
@@ -279,10 +228,9 @@ static void uv__process_child_init(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
int error_fd) {
- sigset_t set;
+ sigset_t signewset;
int close_fd;
int use_fd;
- int err;
int fd;
int n;
#ifndef CMAKE_BOOTSTRAP
@@ -294,6 +242,26 @@ static void uv__process_child_init(const uv_process_options_t* options,
#endif
#endif
+ /* Reset signal disposition first. Use a hard-coded limit because NSIG is not
+ * fixed on Linux: it's either 32, 34 or 64, depending on whether RT signals
+ * are enabled. We are not allowed to touch RT signal handlers, glibc uses
+ * them internally.
+ */
+ for (n = 1; n < 32; n += 1) {
+ if (n == SIGKILL || n == SIGSTOP)
+ continue; /* Can't be changed. */
+
+#if defined(__HAIKU__)
+ if (n == SIGKILLTHR)
+ continue; /* Can't be changed. */
+#endif
+
+ if (SIG_ERR != signal(n, SIG_DFL))
+ continue;
+
+ uv__write_errno(error_fd);
+ }
+
if (options->flags & UV_PROCESS_DETACHED)
setsid();
@@ -306,10 +274,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
if (use_fd < 0 || use_fd >= fd)
continue;
pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
- if (pipes[fd][1] == -1) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if (pipes[fd][1] == -1)
+ uv__write_errno(error_fd);
}
for (fd = 0; fd < stdio_count; fd++) {
@@ -326,10 +292,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
close_fd = use_fd;
- if (use_fd < 0) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if (use_fd < 0)
+ uv__write_errno(error_fd);
}
}
@@ -338,10 +302,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
else
fd = dup2(use_fd, fd);
- if (fd == -1) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if (fd == -1)
+ uv__write_errno(error_fd);
if (fd <= 2)
uv__nonblock_fcntl(fd, 0);
@@ -357,10 +319,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
uv__close(use_fd);
}
- if (options->cwd != NULL && chdir(options->cwd)) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if (options->cwd != NULL && chdir(options->cwd))
+ uv__write_errno(error_fd);
if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
/* When dropping privileges from root, the `setgroups` call will
@@ -373,15 +333,11 @@ static void uv__process_child_init(const uv_process_options_t* options,
SAVE_ERRNO(setgroups(0, NULL));
}
- if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid))
+ uv__write_errno(error_fd);
- if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
+ if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid))
+ uv__write_errno(error_fd);
#ifndef CMAKE_BOOTSTRAP
#if defined(__linux__) || defined(__FreeBSD__)
@@ -409,39 +365,19 @@ static void uv__process_child_init(const uv_process_options_t* options,
environ = options->env;
}
- /* Reset signal disposition. Use a hard-coded limit because NSIG
- * is not fixed on Linux: it's either 32, 34 or 64, depending on
- * whether RT signals are enabled. We are not allowed to touch
- * RT signal handlers, glibc uses them internally.
- */
- for (n = 1; n < 32; n += 1) {
- if (n == SIGKILL || n == SIGSTOP)
- continue; /* Can't be changed. */
+ /* Reset signal mask just before exec. */
+ sigemptyset(&signewset);
+ if (sigprocmask(SIG_SETMASK, &signewset, NULL) != 0)
+ abort();
-#if defined(__HAIKU__)
- if (n == SIGKILLTHR)
- continue; /* Can't be changed. */
+#ifdef __MVS__
+ execvpe(options->file, options->args, environ);
+#else
+ execvp(options->file, options->args);
#endif
- if (SIG_ERR != signal(n, SIG_DFL))
- continue;
-
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
-
- /* Reset signal mask. */
- sigemptyset(&set);
- err = pthread_sigmask(SIG_SETMASK, &set, NULL);
-
- if (err != 0) {
- uv__write_int(error_fd, UV__ERR(err));
- _exit(127);
- }
-
- execvp(options->file, options->args);
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
+ uv__write_errno(error_fd);
+ abort();
}
#endif
@@ -453,6 +389,8 @@ int uv_spawn(uv_loop_t* loop,
/* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
return UV_ENOSYS;
#else
+ sigset_t signewset;
+ sigset_t sigoldset;
int signal_pipe[2] = { -1, -1 };
int pipes_storage[8][2];
int (*pipes)[2];
@@ -541,25 +479,41 @@ int uv_spawn(uv_loop_t* loop,
/* Acquire write lock to prevent opening new fds in worker threads */
uv_rwlock_wrlock(&loop->cloexec_lock);
- pid = fork();
- if (pid == -1) {
+ /* Start the child with most signals blocked, to avoid any issues before we
+ * can reset them, but allow program failures to exit (and not hang). */
+ sigfillset(&signewset);
+ sigdelset(&signewset, SIGKILL);
+ sigdelset(&signewset, SIGSTOP);
+ sigdelset(&signewset, SIGTRAP);
+ sigdelset(&signewset, SIGSEGV);
+ sigdelset(&signewset, SIGBUS);
+ sigdelset(&signewset, SIGILL);
+ sigdelset(&signewset, SIGSYS);
+ sigdelset(&signewset, SIGABRT);
+ if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0)
+ abort();
+
+ pid = fork();
+ if (pid == -1)
err = UV__ERR(errno);
- uv_rwlock_wrunlock(&loop->cloexec_lock);
- uv__close(signal_pipe[0]);
- uv__close(signal_pipe[1]);
- goto error;
- }
- if (pid == 0) {
+ if (pid == 0)
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
+
+ if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0)
abort();
- }
/* Release lock in parent process */
uv_rwlock_wrunlock(&loop->cloexec_lock);
+
uv__close(signal_pipe[1]);
+ if (pid == -1) {
+ uv__close(signal_pipe[0]);
+ goto error;
+ }
+
process->status = 0;
exec_errorno = 0;
do