aboutsummaryrefslogtreecommitdiff
path: root/libc/musl/src/process
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2019-03-13 12:56:58 -0400
committerAndrew Kelley <andrew@ziglang.org>2019-03-13 12:56:58 -0400
commit54edbc6815e42457cd28fa9f1b94e732504b3fc9 (patch)
tree36c97169bf0cd59326a93b8c3c0d458f94aed8a9 /libc/musl/src/process
parent4cb55d3af6a71467b7d4399bedb961c81e9ad3d5 (diff)
parentd495dcc3c952c99e5358d9610cf09eb856f643b0 (diff)
downloadzig-54edbc6815e42457cd28fa9f1b94e732504b3fc9.tar.gz
zig-54edbc6815e42457cd28fa9f1b94e732504b3fc9.zip
Merge remote-tracking branch 'origin/master' into llvm8
Diffstat (limited to 'libc/musl/src/process')
-rw-r--r--libc/musl/src/process/arm/vfork.s10
-rw-r--r--libc/musl/src/process/execl.c22
-rw-r--r--libc/musl/src/process/execle.c23
-rw-r--r--libc/musl/src/process/execlp.c22
-rw-r--r--libc/musl/src/process/execv.c8
-rw-r--r--libc/musl/src/process/execve.c8
-rw-r--r--libc/musl/src/process/execvp.c61
-rw-r--r--libc/musl/src/process/fdop.h10
-rw-r--r--libc/musl/src/process/fexecve.c16
-rw-r--r--libc/musl/src/process/fork.c35
-rw-r--r--libc/musl/src/process/i386/vfork.s12
-rw-r--r--libc/musl/src/process/posix_spawn.c192
-rw-r--r--libc/musl/src/process/posix_spawn_file_actions_addclose.c16
-rw-r--r--libc/musl/src/process/posix_spawn_file_actions_adddup2.c17
-rw-r--r--libc/musl/src/process/posix_spawn_file_actions_addopen.c20
-rw-r--r--libc/musl/src/process/posix_spawn_file_actions_destroy.c14
-rw-r--r--libc/musl/src/process/posix_spawn_file_actions_init.c7
-rw-r--r--libc/musl/src/process/posix_spawnattr_destroy.c6
-rw-r--r--libc/musl/src/process/posix_spawnattr_getflags.c7
-rw-r--r--libc/musl/src/process/posix_spawnattr_getpgroup.c7
-rw-r--r--libc/musl/src/process/posix_spawnattr_getsigdefault.c7
-rw-r--r--libc/musl/src/process/posix_spawnattr_getsigmask.c7
-rw-r--r--libc/musl/src/process/posix_spawnattr_init.c7
-rw-r--r--libc/musl/src/process/posix_spawnattr_sched.c25
-rw-r--r--libc/musl/src/process/posix_spawnattr_setflags.c18
-rw-r--r--libc/musl/src/process/posix_spawnattr_setpgroup.c7
-rw-r--r--libc/musl/src/process/posix_spawnattr_setsigdefault.c7
-rw-r--r--libc/musl/src/process/posix_spawnattr_setsigmask.c7
-rw-r--r--libc/musl/src/process/posix_spawnp.c13
-rw-r--r--libc/musl/src/process/s390x/vfork.s6
-rw-r--r--libc/musl/src/process/sh/vfork.s20
-rw-r--r--libc/musl/src/process/system.c46
-rw-r--r--libc/musl/src/process/vfork.c14
-rw-r--r--libc/musl/src/process/wait.c6
-rw-r--r--libc/musl/src/process/waitid.c7
-rw-r--r--libc/musl/src/process/waitpid.c7
-rw-r--r--libc/musl/src/process/x32/vfork.s10
-rw-r--r--libc/musl/src/process/x86_64/vfork.s10
38 files changed, 737 insertions, 0 deletions
diff --git a/libc/musl/src/process/arm/vfork.s b/libc/musl/src/process/arm/vfork.s
new file mode 100644
index 0000000000..d7ec41b33f
--- /dev/null
+++ b/libc/musl/src/process/arm/vfork.s
@@ -0,0 +1,10 @@
+.syntax unified
+.global vfork
+.type vfork,%function
+vfork:
+ mov ip, r7
+ mov r7, 190
+ svc 0
+ mov r7, ip
+ .hidden __syscall_ret
+ b __syscall_ret
diff --git a/libc/musl/src/process/execl.c b/libc/musl/src/process/execl.c
new file mode 100644
index 0000000000..5ee5c81e35
--- /dev/null
+++ b/libc/musl/src/process/execl.c
@@ -0,0 +1,22 @@
+#include <unistd.h>
+#include <stdarg.h>
+
+int execl(const char *path, const char *argv0, ...)
+{
+ int argc;
+ va_list ap;
+ va_start(ap, argv0);
+ for (argc=1; va_arg(ap, const char *); argc++);
+ va_end(ap);
+ {
+ int i;
+ char *argv[argc+1];
+ va_start(ap, argv0);
+ argv[0] = (char *)argv0;
+ for (i=1; i<argc; i++)
+ argv[i] = va_arg(ap, char *);
+ argv[i] = NULL;
+ va_end(ap);
+ return execv(path, argv);
+ }
+}
diff --git a/libc/musl/src/process/execle.c b/libc/musl/src/process/execle.c
new file mode 100644
index 0000000000..37ca50349a
--- /dev/null
+++ b/libc/musl/src/process/execle.c
@@ -0,0 +1,23 @@
+#include <unistd.h>
+#include <stdarg.h>
+
+int execle(const char *path, const char *argv0, ...)
+{
+ int argc;
+ va_list ap;
+ va_start(ap, argv0);
+ for (argc=1; va_arg(ap, const char *); argc++);
+ va_end(ap);
+ {
+ int i;
+ char *argv[argc+1];
+ char **envp;
+ va_start(ap, argv0);
+ argv[0] = (char *)argv0;
+ for (i=1; i<=argc; i++)
+ argv[i] = va_arg(ap, char *);
+ envp = va_arg(ap, char **);
+ va_end(ap);
+ return execve(path, argv, envp);
+ }
+}
diff --git a/libc/musl/src/process/execlp.c b/libc/musl/src/process/execlp.c
new file mode 100644
index 0000000000..5eed886e71
--- /dev/null
+++ b/libc/musl/src/process/execlp.c
@@ -0,0 +1,22 @@
+#include <unistd.h>
+#include <stdarg.h>
+
+int execlp(const char *file, const char *argv0, ...)
+{
+ int argc;
+ va_list ap;
+ va_start(ap, argv0);
+ for (argc=1; va_arg(ap, const char *); argc++);
+ va_end(ap);
+ {
+ int i;
+ char *argv[argc+1];
+ va_start(ap, argv0);
+ argv[0] = (char *)argv0;
+ for (i=1; i<argc; i++)
+ argv[i] = va_arg(ap, char *);
+ argv[i] = NULL;
+ va_end(ap);
+ return execvp(file, argv);
+ }
+}
diff --git a/libc/musl/src/process/execv.c b/libc/musl/src/process/execv.c
new file mode 100644
index 0000000000..2ac0dec013
--- /dev/null
+++ b/libc/musl/src/process/execv.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+
+extern char **__environ;
+
+int execv(const char *path, char *const argv[])
+{
+ return execve(path, argv, __environ);
+}
diff --git a/libc/musl/src/process/execve.c b/libc/musl/src/process/execve.c
new file mode 100644
index 0000000000..70286a1739
--- /dev/null
+++ b/libc/musl/src/process/execve.c
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include "syscall.h"
+
+int execve(const char *path, char *const argv[], char *const envp[])
+{
+ /* do we need to use environ if envp is null? */
+ return syscall(SYS_execve, path, argv, envp);
+}
diff --git a/libc/musl/src/process/execvp.c b/libc/musl/src/process/execvp.c
new file mode 100644
index 0000000000..1fdf036fde
--- /dev/null
+++ b/libc/musl/src/process/execvp.c
@@ -0,0 +1,61 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+
+extern char **__environ;
+
+int __execvpe(const char *file, char *const argv[], char *const envp[])
+{
+ const char *p, *z, *path = getenv("PATH");
+ size_t l, k;
+ int seen_eacces = 0;
+
+ errno = ENOENT;
+ if (!*file) return -1;
+
+ if (strchr(file, '/'))
+ return execve(file, argv, envp);
+
+ if (!path) path = "/usr/local/bin:/bin:/usr/bin";
+ k = strnlen(file, NAME_MAX+1);
+ if (k > NAME_MAX) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ l = strnlen(path, PATH_MAX-1)+1;
+
+ for(p=path; ; p=z) {
+ char b[l+k+1];
+ z = strchr(p, ':');
+ if (!z) z = p+strlen(p);
+ if (z-p >= l) {
+ if (!*z++) break;
+ continue;
+ }
+ memcpy(b, p, z-p);
+ b[z-p] = '/';
+ memcpy(b+(z-p)+(z>p), file, k+1);
+ execve(b, argv, envp);
+ switch (errno) {
+ case EACCES:
+ seen_eacces = 1;
+ case ENOENT:
+ case ENOTDIR:
+ break;
+ default:
+ return -1;
+ }
+ if (!*z++) break;
+ }
+ if (seen_eacces) errno = EACCES;
+ return -1;
+}
+
+int execvp(const char *file, char *const argv[])
+{
+ return __execvpe(file, argv, __environ);
+}
+
+weak_alias(__execvpe, execvpe);
diff --git a/libc/musl/src/process/fdop.h b/libc/musl/src/process/fdop.h
new file mode 100644
index 0000000000..00b875143a
--- /dev/null
+++ b/libc/musl/src/process/fdop.h
@@ -0,0 +1,10 @@
+#define FDOP_CLOSE 1
+#define FDOP_DUP2 2
+#define FDOP_OPEN 3
+
+struct fdop {
+ struct fdop *next, *prev;
+ int cmd, fd, srcfd, oflag;
+ mode_t mode;
+ char path[];
+};
diff --git a/libc/musl/src/process/fexecve.c b/libc/musl/src/process/fexecve.c
new file mode 100644
index 0000000000..554c1981b6
--- /dev/null
+++ b/libc/musl/src/process/fexecve.c
@@ -0,0 +1,16 @@
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "syscall.h"
+
+int fexecve(int fd, char *const argv[], char *const envp[])
+{
+ int r = __syscall(SYS_execveat, fd, "", argv, envp, AT_EMPTY_PATH);
+ if (r != -ENOSYS) return __syscall_ret(r);
+ char buf[15 + 3*sizeof(int)];
+ __procfdname(buf, fd);
+ execve(buf, argv, envp);
+ if (errno == ENOENT) errno = EBADF;
+ return -1;
+}
diff --git a/libc/musl/src/process/fork.c b/libc/musl/src/process/fork.c
new file mode 100644
index 0000000000..da074ae9c9
--- /dev/null
+++ b/libc/musl/src/process/fork.c
@@ -0,0 +1,35 @@
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include "syscall.h"
+#include "libc.h"
+#include "pthread_impl.h"
+
+static void dummy(int x)
+{
+}
+
+weak_alias(dummy, __fork_handler);
+
+pid_t fork(void)
+{
+ pid_t ret;
+ sigset_t set;
+ __fork_handler(-1);
+ __block_all_sigs(&set);
+#ifdef SYS_fork
+ ret = __syscall(SYS_fork);
+#else
+ ret = __syscall(SYS_clone, SIGCHLD, 0);
+#endif
+ if (!ret) {
+ pthread_t self = __pthread_self();
+ self->tid = __syscall(SYS_gettid);
+ self->robust_list.off = 0;
+ self->robust_list.pending = 0;
+ libc.threads_minus_1 = 0;
+ }
+ __restore_sigs(&set);
+ __fork_handler(!ret);
+ return __syscall_ret(ret);
+}
diff --git a/libc/musl/src/process/i386/vfork.s b/libc/musl/src/process/i386/vfork.s
new file mode 100644
index 0000000000..3d0e6d6bde
--- /dev/null
+++ b/libc/musl/src/process/i386/vfork.s
@@ -0,0 +1,12 @@
+.global vfork
+.type vfork,@function
+vfork:
+ pop %edx
+ mov $190,%eax
+ int $128
+ push %edx
+ push %eax
+ .hidden __syscall_ret
+ call __syscall_ret
+ pop %edx
+ ret
diff --git a/libc/musl/src/process/posix_spawn.c b/libc/musl/src/process/posix_spawn.c
new file mode 100644
index 0000000000..5aaf829d5e
--- /dev/null
+++ b/libc/musl/src/process/posix_spawn.c
@@ -0,0 +1,192 @@
+#define _GNU_SOURCE
+#include <spawn.h>
+#include <sched.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include "syscall.h"
+#include "pthread_impl.h"
+#include "fdop.h"
+
+struct args {
+ int p[2];
+ sigset_t oldmask;
+ const char *path;
+ const posix_spawn_file_actions_t *fa;
+ const posix_spawnattr_t *restrict attr;
+ char *const *argv, *const *envp;
+};
+
+static int __sys_dup2(int old, int new)
+{
+#ifdef SYS_dup2
+ return __syscall(SYS_dup2, old, new);
+#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_SETSID)
+ if ((ret=__syscall(SYS_setsid)) < 0)
+ goto fail;
+
+ 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:
+ fd = op->srcfd;
+ if (fd != op->fd) {
+ if ((ret=__sys_dup2(fd, op->fd))<0)
+ goto fail;
+ } else {
+ ret = __syscall(SYS_fcntl, fd, F_GETFD);
+ ret = __syscall(SYS_fcntl, fd, F_SETFD,
+ ret & ~FD_CLOEXEC);
+ if (ret<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);
+
+ int (*exec)(const char *, char *const *, char *const *) =
+ attr->__fn ? (int (*)())attr->__fn : execve;
+
+ 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);
+}
+
+
+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])
+{
+ pid_t pid;
+ char stack[1024+PATH_MAX];
+ 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.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;
+}
diff --git a/libc/musl/src/process/posix_spawn_file_actions_addclose.c b/libc/musl/src/process/posix_spawn_file_actions_addclose.c
new file mode 100644
index 0000000000..cdda597991
--- /dev/null
+++ b/libc/musl/src/process/posix_spawn_file_actions_addclose.c
@@ -0,0 +1,16 @@
+#include <spawn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "fdop.h"
+
+int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa, int fd)
+{
+ struct fdop *op = malloc(sizeof *op);
+ if (!op) return ENOMEM;
+ op->cmd = FDOP_CLOSE;
+ op->fd = fd;
+ if ((op->next = fa->__actions)) op->next->prev = op;
+ op->prev = 0;
+ fa->__actions = op;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawn_file_actions_adddup2.c b/libc/musl/src/process/posix_spawn_file_actions_adddup2.c
new file mode 100644
index 0000000000..0367498fd4
--- /dev/null
+++ b/libc/musl/src/process/posix_spawn_file_actions_adddup2.c
@@ -0,0 +1,17 @@
+#include <spawn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "fdop.h"
+
+int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa, int srcfd, int fd)
+{
+ struct fdop *op = malloc(sizeof *op);
+ if (!op) return ENOMEM;
+ op->cmd = FDOP_DUP2;
+ op->srcfd = srcfd;
+ op->fd = fd;
+ if ((op->next = fa->__actions)) op->next->prev = op;
+ op->prev = 0;
+ fa->__actions = op;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawn_file_actions_addopen.c b/libc/musl/src/process/posix_spawn_file_actions_addopen.c
new file mode 100644
index 0000000000..368922c76b
--- /dev/null
+++ b/libc/musl/src/process/posix_spawn_file_actions_addopen.c
@@ -0,0 +1,20 @@
+#include <spawn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "fdop.h"
+
+int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t *restrict fa, int fd, const char *restrict path, int flags, mode_t mode)
+{
+ struct fdop *op = malloc(sizeof *op + strlen(path) + 1);
+ if (!op) return ENOMEM;
+ op->cmd = FDOP_OPEN;
+ op->fd = fd;
+ op->oflag = flags;
+ op->mode = mode;
+ strcpy(op->path, path);
+ if ((op->next = fa->__actions)) op->next->prev = op;
+ op->prev = 0;
+ fa->__actions = op;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawn_file_actions_destroy.c b/libc/musl/src/process/posix_spawn_file_actions_destroy.c
new file mode 100644
index 0000000000..3251babb55
--- /dev/null
+++ b/libc/musl/src/process/posix_spawn_file_actions_destroy.c
@@ -0,0 +1,14 @@
+#include <spawn.h>
+#include <stdlib.h>
+#include "fdop.h"
+
+int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa)
+{
+ struct fdop *op = fa->__actions, *next;
+ while (op) {
+ next = op->next;
+ free(op);
+ op = next;
+ }
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawn_file_actions_init.c b/libc/musl/src/process/posix_spawn_file_actions_init.c
new file mode 100644
index 0000000000..89d5e12789
--- /dev/null
+++ b/libc/musl/src/process/posix_spawn_file_actions_init.c
@@ -0,0 +1,7 @@
+#include <spawn.h>
+
+int posix_spawn_file_actions_init(posix_spawn_file_actions_t *fa)
+{
+ fa->__actions = 0;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_destroy.c b/libc/musl/src/process/posix_spawnattr_destroy.c
new file mode 100644
index 0000000000..fc714a1b24
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_destroy.c
@@ -0,0 +1,6 @@
+#include <spawn.h>
+
+int posix_spawnattr_destroy(posix_spawnattr_t *attr)
+{
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_getflags.c b/libc/musl/src/process/posix_spawnattr_getflags.c
new file mode 100644
index 0000000000..aa635ddaf6
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_getflags.c
@@ -0,0 +1,7 @@
+#include <spawn.h>
+
+int posix_spawnattr_getflags(const posix_spawnattr_t *restrict attr, short *restrict flags)
+{
+ *flags = attr->__flags;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_getpgroup.c b/libc/musl/src/process/posix_spawnattr_getpgroup.c
new file mode 100644
index 0000000000..0480527d6f
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_getpgroup.c
@@ -0,0 +1,7 @@
+#include <spawn.h>
+
+int posix_spawnattr_getpgroup(const posix_spawnattr_t *restrict attr, pid_t *restrict pgrp)
+{
+ *pgrp = attr->__pgrp;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_getsigdefault.c b/libc/musl/src/process/posix_spawnattr_getsigdefault.c
new file mode 100644
index 0000000000..a49050aa4f
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_getsigdefault.c
@@ -0,0 +1,7 @@
+#include <spawn.h>
+
+int posix_spawnattr_getsigdefault(const posix_spawnattr_t *restrict attr, sigset_t *restrict def)
+{
+ *def = attr->__def;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_getsigmask.c b/libc/musl/src/process/posix_spawnattr_getsigmask.c
new file mode 100644
index 0000000000..f60ad7f375
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_getsigmask.c
@@ -0,0 +1,7 @@
+#include <spawn.h>
+
+int posix_spawnattr_getsigmask(const posix_spawnattr_t *restrict attr, sigset_t *restrict mask)
+{
+ *mask = attr->__mask;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_init.c b/libc/musl/src/process/posix_spawnattr_init.c
new file mode 100644
index 0000000000..0dcd868f3c
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_init.c
@@ -0,0 +1,7 @@
+#include <spawn.h>
+
+int posix_spawnattr_init(posix_spawnattr_t *attr)
+{
+ *attr = (posix_spawnattr_t){ 0 };
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_sched.c b/libc/musl/src/process/posix_spawnattr_sched.c
new file mode 100644
index 0000000000..3143635bac
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_sched.c
@@ -0,0 +1,25 @@
+#include <spawn.h>
+#include <sched.h>
+#include <errno.h>
+
+int posix_spawnattr_getschedparam(const posix_spawnattr_t *restrict attr,
+ struct sched_param *restrict schedparam)
+{
+ return ENOSYS;
+}
+
+int posix_spawnattr_setschedparam(posix_spawnattr_t *restrict attr,
+ const struct sched_param *restrict schedparam)
+{
+ return ENOSYS;
+}
+
+int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *restrict attr, int *restrict policy)
+{
+ return ENOSYS;
+}
+
+int posix_spawnattr_setschedpolicy(posix_spawnattr_t *attr, int policy)
+{
+ return ENOSYS;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_setflags.c b/libc/musl/src/process/posix_spawnattr_setflags.c
new file mode 100644
index 0000000000..6878099212
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_setflags.c
@@ -0,0 +1,18 @@
+#include <spawn.h>
+#include <errno.h>
+
+int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
+{
+ const unsigned all_flags =
+ POSIX_SPAWN_RESETIDS |
+ POSIX_SPAWN_SETPGROUP |
+ POSIX_SPAWN_SETSIGDEF |
+ POSIX_SPAWN_SETSIGMASK |
+ POSIX_SPAWN_SETSCHEDPARAM |
+ POSIX_SPAWN_SETSCHEDULER |
+ POSIX_SPAWN_USEVFORK |
+ POSIX_SPAWN_SETSID;
+ if (flags & ~all_flags) return EINVAL;
+ attr->__flags = flags;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_setpgroup.c b/libc/musl/src/process/posix_spawnattr_setpgroup.c
new file mode 100644
index 0000000000..f39596a6ec
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_setpgroup.c
@@ -0,0 +1,7 @@
+#include <spawn.h>
+
+int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgrp)
+{
+ attr->__pgrp = pgrp;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_setsigdefault.c b/libc/musl/src/process/posix_spawnattr_setsigdefault.c
new file mode 100644
index 0000000000..5686972670
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_setsigdefault.c
@@ -0,0 +1,7 @@
+#include <spawn.h>
+
+int posix_spawnattr_setsigdefault(posix_spawnattr_t *restrict attr, const sigset_t *restrict def)
+{
+ attr->__def = *def;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnattr_setsigmask.c b/libc/musl/src/process/posix_spawnattr_setsigmask.c
new file mode 100644
index 0000000000..f2532f8e0e
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnattr_setsigmask.c
@@ -0,0 +1,7 @@
+#include <spawn.h>
+
+int posix_spawnattr_setsigmask(posix_spawnattr_t *restrict attr, const sigset_t *restrict mask)
+{
+ attr->__mask = *mask;
+ return 0;
+}
diff --git a/libc/musl/src/process/posix_spawnp.c b/libc/musl/src/process/posix_spawnp.c
new file mode 100644
index 0000000000..aad6133b91
--- /dev/null
+++ b/libc/musl/src/process/posix_spawnp.c
@@ -0,0 +1,13 @@
+#include <spawn.h>
+#include <unistd.h>
+
+int posix_spawnp(pid_t *restrict res, const char *restrict file,
+ const posix_spawn_file_actions_t *fa,
+ const posix_spawnattr_t *restrict attr,
+ char *const argv[restrict], char *const envp[restrict])
+{
+ posix_spawnattr_t spawnp_attr = { 0 };
+ if (attr) spawnp_attr = *attr;
+ spawnp_attr.__fn = (void *)__execvpe;
+ return posix_spawn(res, file, fa, &spawnp_attr, argv, envp);
+}
diff --git a/libc/musl/src/process/s390x/vfork.s b/libc/musl/src/process/s390x/vfork.s
new file mode 100644
index 0000000000..744f9d78d0
--- /dev/null
+++ b/libc/musl/src/process/s390x/vfork.s
@@ -0,0 +1,6 @@
+ .global vfork
+ .type vfork,%function
+vfork:
+ svc 190
+ .hidden __syscall_ret
+ jg __syscall_ret
diff --git a/libc/musl/src/process/sh/vfork.s b/libc/musl/src/process/sh/vfork.s
new file mode 100644
index 0000000000..91dbde7b93
--- /dev/null
+++ b/libc/musl/src/process/sh/vfork.s
@@ -0,0 +1,20 @@
+.global vfork
+.type vfork,@function
+vfork:
+ mov #95, r3
+ add r3, r3
+
+ trapa #31
+ or r0, r0
+ or r0, r0
+ or r0, r0
+ or r0, r0
+ or r0, r0
+
+ mov r0, r4
+ mov.l 1f, r0
+2: braf r0
+ nop
+ .align 2
+ .hidden __syscall_ret
+1: .long __syscall_ret@PLT-(2b+4-.)
diff --git a/libc/musl/src/process/system.c b/libc/musl/src/process/system.c
new file mode 100644
index 0000000000..5af59b809f
--- /dev/null
+++ b/libc/musl/src/process/system.c
@@ -0,0 +1,46 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <spawn.h>
+#include <errno.h>
+#include "pthread_impl.h"
+
+extern char **__environ;
+
+int system(const char *cmd)
+{
+ pid_t pid;
+ sigset_t old, reset;
+ struct sigaction sa = { .sa_handler = SIG_IGN }, oldint, oldquit;
+ int status = -1, ret;
+ posix_spawnattr_t attr;
+
+ pthread_testcancel();
+
+ if (!cmd) return 1;
+
+ sigaction(SIGINT, &sa, &oldint);
+ sigaction(SIGQUIT, &sa, &oldquit);
+ sigaddset(&sa.sa_mask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sa.sa_mask, &old);
+
+ sigemptyset(&reset);
+ if (oldint.sa_handler != SIG_IGN) sigaddset(&reset, SIGINT);
+ if (oldquit.sa_handler != SIG_IGN) sigaddset(&reset, SIGQUIT);
+ posix_spawnattr_init(&attr);
+ posix_spawnattr_setsigmask(&attr, &old);
+ posix_spawnattr_setsigdefault(&attr, &reset);
+ posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK);
+ ret = posix_spawn(&pid, "/bin/sh", 0, &attr,
+ (char *[]){"sh", "-c", (char *)cmd, 0}, __environ);
+ posix_spawnattr_destroy(&attr);
+
+ if (!ret) while (waitpid(pid, &status, 0)<0 && errno == EINTR);
+ sigaction(SIGINT, &oldint, NULL);
+ sigaction(SIGQUIT, &oldquit, NULL);
+ sigprocmask(SIG_SETMASK, &old, NULL);
+
+ if (ret) errno = ret;
+ return status;
+}
diff --git a/libc/musl/src/process/vfork.c b/libc/musl/src/process/vfork.c
new file mode 100644
index 0000000000..d430c13fca
--- /dev/null
+++ b/libc/musl/src/process/vfork.c
@@ -0,0 +1,14 @@
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <signal.h>
+#include "syscall.h"
+
+pid_t vfork(void)
+{
+ /* vfork syscall cannot be made from C code */
+#ifdef SYS_fork
+ return syscall(SYS_fork);
+#else
+ return syscall(SYS_clone, SIGCHLD, 0);
+#endif
+}
diff --git a/libc/musl/src/process/wait.c b/libc/musl/src/process/wait.c
new file mode 100644
index 0000000000..34da102d58
--- /dev/null
+++ b/libc/musl/src/process/wait.c
@@ -0,0 +1,6 @@
+#include <sys/wait.h>
+
+pid_t wait(int *status)
+{
+ return waitpid((pid_t)-1, status, 0);
+}
diff --git a/libc/musl/src/process/waitid.c b/libc/musl/src/process/waitid.c
new file mode 100644
index 0000000000..d688650d85
--- /dev/null
+++ b/libc/musl/src/process/waitid.c
@@ -0,0 +1,7 @@
+#include <sys/wait.h>
+#include "syscall.h"
+
+int waitid(idtype_t type, id_t id, siginfo_t *info, int options)
+{
+ return syscall_cp(SYS_waitid, type, id, info, options, 0);
+}
diff --git a/libc/musl/src/process/waitpid.c b/libc/musl/src/process/waitpid.c
new file mode 100644
index 0000000000..1b65bf0512
--- /dev/null
+++ b/libc/musl/src/process/waitpid.c
@@ -0,0 +1,7 @@
+#include <sys/wait.h>
+#include "syscall.h"
+
+pid_t waitpid(pid_t pid, int *status, int options)
+{
+ return syscall_cp(SYS_wait4, pid, status, options, 0);
+}
diff --git a/libc/musl/src/process/x32/vfork.s b/libc/musl/src/process/x32/vfork.s
new file mode 100644
index 0000000000..0f0ca3ee48
--- /dev/null
+++ b/libc/musl/src/process/x32/vfork.s
@@ -0,0 +1,10 @@
+.global vfork
+.type vfork,@function
+vfork:
+ pop %rdx
+ mov $0x4000003a,%eax /* SYS_vfork */
+ syscall
+ push %rdx
+ mov %rax,%rdi
+ .hidden __syscall_ret
+ jmp __syscall_ret
diff --git a/libc/musl/src/process/x86_64/vfork.s b/libc/musl/src/process/x86_64/vfork.s
new file mode 100644
index 0000000000..9114439031
--- /dev/null
+++ b/libc/musl/src/process/x86_64/vfork.s
@@ -0,0 +1,10 @@
+.global vfork
+.type vfork,@function
+vfork:
+ pop %rdx
+ mov $58,%eax
+ syscall
+ push %rdx
+ mov %rax,%rdi
+ .hidden __syscall_ret
+ jmp __syscall_ret