Index: fusl/src/process/posix_spawn.c |
diff --git a/fusl/src/process/posix_spawn.c b/fusl/src/process/posix_spawn.c |
index 0bdf71cd8d0437960ea0d7f31a80d0dd151bc651..9f7327159a6ee4a72ca295a80e3b3b970bf87af3 100644 |
--- a/fusl/src/process/posix_spawn.c |
+++ b/fusl/src/process/posix_spawn.c |
@@ -11,185 +11,195 @@ |
#include "libc.h" |
struct args { |
- int p[2]; |
- sigset_t oldmask; |
- const char *path; |
- int (*exec)(const char *, char *const *, char *const *); |
- const posix_spawn_file_actions_t *fa; |
- const posix_spawnattr_t *restrict attr; |
- char *const *argv, *const *envp; |
+ int p[2]; |
+ sigset_t oldmask; |
+ const char* path; |
+ int (*exec)(const char*, char* const*, char* const*); |
+ const posix_spawn_file_actions_t* fa; |
+ const posix_spawnattr_t* restrict attr; |
+ char *const *argv, *const *envp; |
}; |
-void __get_handler_set(sigset_t *); |
+void __get_handler_set(sigset_t*); |
-static int __sys_dup2(int old, int new) |
-{ |
+static int __sys_dup2(int old, int new) { |
#ifdef SYS_dup2 |
- return __syscall(SYS_dup2, old, new); |
+ return __syscall(SYS_dup2, old, new); |
#else |
- if (old==new) { |
- int r = __syscall(SYS_fcntl, old, F_GETFD); |
- return r<0 ? r : old; |
- } else { |
- return __syscall(SYS_dup3, old, new, 0); |
- } |
+ if (old == new) { |
+ int r = __syscall(SYS_fcntl, old, F_GETFD); |
+ return r < 0 ? r : old; |
+ } else { |
+ return __syscall(SYS_dup3, old, new, 0); |
+ } |
#endif |
} |
-static int child(void *args_vp) |
-{ |
- int i, ret; |
- struct sigaction sa = {0}; |
- struct args *args = args_vp; |
- int p = args->p[1]; |
- const posix_spawn_file_actions_t *fa = args->fa; |
- const posix_spawnattr_t *restrict attr = args->attr; |
- sigset_t hset; |
- |
- close(args->p[0]); |
- |
- /* All signal dispositions must be either SIG_DFL or SIG_IGN |
- * before signals are unblocked. Otherwise a signal handler |
- * from the parent might get run in the child while sharing |
- * memory, with unpredictable and dangerous results. To |
- * reduce overhead, sigaction has tracked for us which signals |
- * potentially have a signal handler. */ |
- __get_handler_set(&hset); |
- for (i=1; i<_NSIG; i++) { |
- if ((attr->__flags & POSIX_SPAWN_SETSIGDEF) |
- && sigismember(&attr->__def, i)) { |
- sa.sa_handler = SIG_DFL; |
- } else if (sigismember(&hset, i)) { |
- if (i-32<3U) { |
- sa.sa_handler = SIG_IGN; |
- } else { |
- __libc_sigaction(i, 0, &sa); |
- if (sa.sa_handler==SIG_IGN) continue; |
- sa.sa_handler = SIG_DFL; |
- } |
- } else { |
- continue; |
- } |
- __libc_sigaction(i, &sa, 0); |
- } |
- |
- if (attr->__flags & POSIX_SPAWN_SETPGROUP) |
- if ((ret=__syscall(SYS_setpgid, 0, attr->__pgrp))) |
- goto fail; |
- |
- /* Use syscalls directly because the library functions attempt |
- * to do a multi-threaded synchronized id-change, which would |
- * trash the parent's state. */ |
- if (attr->__flags & POSIX_SPAWN_RESETIDS) |
- if ((ret=__syscall(SYS_setgid, __syscall(SYS_getgid))) || |
- (ret=__syscall(SYS_setuid, __syscall(SYS_getuid))) ) |
- goto fail; |
- |
- if (fa && fa->__actions) { |
- struct fdop *op; |
- int fd; |
- for (op = fa->__actions; op->next; op = op->next); |
- for (; op; op = op->prev) { |
- /* It's possible that a file operation would clobber |
- * the pipe fd used for synchronizing with the |
- * parent. To avoid that, we dup the pipe onto |
- * an unoccupied fd. */ |
- if (op->fd == p) { |
- ret = __syscall(SYS_dup, p); |
- if (ret < 0) goto fail; |
- __syscall(SYS_close, p); |
- p = ret; |
- } |
- switch(op->cmd) { |
- case FDOP_CLOSE: |
- __syscall(SYS_close, op->fd); |
- break; |
- case FDOP_DUP2: |
- if ((ret=__sys_dup2(op->srcfd, op->fd))<0) |
- goto fail; |
- break; |
- case FDOP_OPEN: |
- fd = __sys_open(op->path, op->oflag, op->mode); |
- if ((ret=fd) < 0) goto fail; |
- if (fd != op->fd) { |
- if ((ret=__sys_dup2(fd, op->fd))<0) |
- goto fail; |
- __syscall(SYS_close, fd); |
- } |
- break; |
- } |
- } |
- } |
- |
- /* Close-on-exec flag may have been lost if we moved the pipe |
- * to a different fd. We don't use F_DUPFD_CLOEXEC above because |
- * it would fail on older kernels and atomicity is not needed -- |
- * in this process there are no threads or signal handlers. */ |
- __syscall(SYS_fcntl, p, F_SETFD, FD_CLOEXEC); |
- |
- pthread_sigmask(SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK) |
- ? &attr->__mask : &args->oldmask, 0); |
- |
- args->exec(args->path, args->argv, args->envp); |
- ret = -errno; |
+static int child(void* args_vp) { |
+ int i, ret; |
+ struct sigaction sa = {0}; |
+ struct args* args = args_vp; |
+ int p = args->p[1]; |
+ const posix_spawn_file_actions_t* fa = args->fa; |
+ const posix_spawnattr_t* restrict attr = args->attr; |
+ sigset_t hset; |
+ |
+ close(args->p[0]); |
+ |
+ /* All signal dispositions must be either SIG_DFL or SIG_IGN |
+ * before signals are unblocked. Otherwise a signal handler |
+ * from the parent might get run in the child while sharing |
+ * memory, with unpredictable and dangerous results. To |
+ * reduce overhead, sigaction has tracked for us which signals |
+ * potentially have a signal handler. */ |
+ __get_handler_set(&hset); |
+ for (i = 1; i < _NSIG; i++) { |
+ if ((attr->__flags & POSIX_SPAWN_SETSIGDEF) && |
+ sigismember(&attr->__def, i)) { |
+ sa.sa_handler = SIG_DFL; |
+ } else if (sigismember(&hset, i)) { |
+ if (i - 32 < 3U) { |
+ sa.sa_handler = SIG_IGN; |
+ } else { |
+ __libc_sigaction(i, 0, &sa); |
+ if (sa.sa_handler == SIG_IGN) |
+ continue; |
+ sa.sa_handler = SIG_DFL; |
+ } |
+ } else { |
+ continue; |
+ } |
+ __libc_sigaction(i, &sa, 0); |
+ } |
+ |
+ if (attr->__flags & POSIX_SPAWN_SETPGROUP) |
+ if ((ret = __syscall(SYS_setpgid, 0, attr->__pgrp))) |
+ goto fail; |
+ |
+ /* Use syscalls directly because the library functions attempt |
+ * to do a multi-threaded synchronized id-change, which would |
+ * trash the parent's state. */ |
+ if (attr->__flags & POSIX_SPAWN_RESETIDS) |
+ if ((ret = __syscall(SYS_setgid, __syscall(SYS_getgid))) || |
+ (ret = __syscall(SYS_setuid, __syscall(SYS_getuid)))) |
+ goto fail; |
+ |
+ if (fa && fa->__actions) { |
+ struct fdop* op; |
+ int fd; |
+ for (op = fa->__actions; op->next; op = op->next) |
+ ; |
+ for (; op; op = op->prev) { |
+ /* It's possible that a file operation would clobber |
+ * the pipe fd used for synchronizing with the |
+ * parent. To avoid that, we dup the pipe onto |
+ * an unoccupied fd. */ |
+ if (op->fd == p) { |
+ ret = __syscall(SYS_dup, p); |
+ if (ret < 0) |
+ goto fail; |
+ __syscall(SYS_close, p); |
+ p = ret; |
+ } |
+ switch (op->cmd) { |
+ case FDOP_CLOSE: |
+ __syscall(SYS_close, op->fd); |
+ break; |
+ case FDOP_DUP2: |
+ if ((ret = __sys_dup2(op->srcfd, op->fd)) < 0) |
+ goto fail; |
+ break; |
+ case FDOP_OPEN: |
+ fd = __sys_open(op->path, op->oflag, op->mode); |
+ if ((ret = fd) < 0) |
+ goto fail; |
+ if (fd != op->fd) { |
+ if ((ret = __sys_dup2(fd, op->fd)) < 0) |
+ goto fail; |
+ __syscall(SYS_close, fd); |
+ } |
+ break; |
+ } |
+ } |
+ } |
+ |
+ /* Close-on-exec flag may have been lost if we moved the pipe |
+ * to a different fd. We don't use F_DUPFD_CLOEXEC above because |
+ * it would fail on older kernels and atomicity is not needed -- |
+ * in this process there are no threads or signal handlers. */ |
+ __syscall(SYS_fcntl, p, F_SETFD, FD_CLOEXEC); |
+ |
+ pthread_sigmask( |
+ SIG_SETMASK, |
+ (attr->__flags & POSIX_SPAWN_SETSIGMASK) ? &attr->__mask : &args->oldmask, |
+ 0); |
+ |
+ args->exec(args->path, args->argv, args->envp); |
+ ret = -errno; |
fail: |
- /* Since sizeof errno < PIPE_BUF, the write is atomic. */ |
- ret = -ret; |
- if (ret) while (__syscall(SYS_write, p, &ret, sizeof ret) < 0); |
- _exit(127); |
+ /* Since sizeof errno < PIPE_BUF, the write is atomic. */ |
+ ret = -ret; |
+ if (ret) |
+ while (__syscall(SYS_write, p, &ret, sizeof ret) < 0) |
+ ; |
+ _exit(127); |
} |
- |
-int __posix_spawnx(pid_t *restrict res, const char *restrict path, |
- int (*exec)(const char *, char *const *, char *const *), |
- const posix_spawn_file_actions_t *fa, |
- const posix_spawnattr_t *restrict attr, |
- char *const argv[restrict], char *const envp[restrict]) |
-{ |
- pid_t pid; |
- char stack[1024]; |
- int ec=0, cs; |
- struct args args; |
- |
- if (pipe2(args.p, O_CLOEXEC)) |
- return errno; |
- |
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); |
- |
- args.path = path; |
- args.exec = exec; |
- args.fa = fa; |
- args.attr = attr ? attr : &(const posix_spawnattr_t){0}; |
- args.argv = argv; |
- args.envp = envp; |
- pthread_sigmask(SIG_BLOCK, SIGALL_SET, &args.oldmask); |
- |
- pid = __clone(child, stack+sizeof stack, |
- CLONE_VM|CLONE_VFORK|SIGCHLD, &args); |
- close(args.p[1]); |
- |
- if (pid > 0) { |
- if (read(args.p[0], &ec, sizeof ec) != sizeof ec) ec = 0; |
- else waitpid(pid, &(int){0}, 0); |
- } else { |
- ec = -pid; |
- } |
- |
- close(args.p[0]); |
- |
- if (!ec && res) *res = pid; |
- |
- pthread_sigmask(SIG_SETMASK, &args.oldmask, 0); |
- pthread_setcancelstate(cs, 0); |
- |
- return ec; |
+int __posix_spawnx(pid_t* restrict res, |
+ const char* restrict path, |
+ int (*exec)(const char*, char* const*, char* const*), |
+ const posix_spawn_file_actions_t* fa, |
+ const posix_spawnattr_t* restrict attr, |
+ char* const argv[restrict], |
+ char* const envp[restrict]) { |
+ pid_t pid; |
+ char stack[1024]; |
+ int ec = 0, cs; |
+ struct args args; |
+ |
+ if (pipe2(args.p, O_CLOEXEC)) |
+ return errno; |
+ |
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); |
+ |
+ args.path = path; |
+ args.exec = exec; |
+ args.fa = fa; |
+ args.attr = attr ? attr : &(const posix_spawnattr_t){0}; |
+ args.argv = argv; |
+ args.envp = envp; |
+ pthread_sigmask(SIG_BLOCK, SIGALL_SET, &args.oldmask); |
+ |
+ pid = __clone(child, stack + sizeof stack, CLONE_VM | CLONE_VFORK | SIGCHLD, |
+ &args); |
+ close(args.p[1]); |
+ |
+ if (pid > 0) { |
+ if (read(args.p[0], &ec, sizeof ec) != sizeof ec) |
+ ec = 0; |
+ else |
+ waitpid(pid, &(int){0}, 0); |
+ } else { |
+ ec = -pid; |
+ } |
+ |
+ close(args.p[0]); |
+ |
+ if (!ec && res) |
+ *res = pid; |
+ |
+ pthread_sigmask(SIG_SETMASK, &args.oldmask, 0); |
+ pthread_setcancelstate(cs, 0); |
+ |
+ return ec; |
} |
-int posix_spawn(pid_t *restrict res, const char *restrict path, |
- const posix_spawn_file_actions_t *fa, |
- const posix_spawnattr_t *restrict attr, |
- char *const argv[restrict], char *const envp[restrict]) |
-{ |
- return __posix_spawnx(res, path, execve, fa, attr, argv, envp); |
+int posix_spawn(pid_t* restrict res, |
+ const char* restrict path, |
+ const posix_spawn_file_actions_t* fa, |
+ const posix_spawnattr_t* restrict attr, |
+ char* const argv[restrict], |
+ char* const envp[restrict]) { |
+ return __posix_spawnx(res, path, execve, fa, attr, argv, envp); |
} |