summaryrefslogtreecommitdiffstats
path: root/libc-top-half/musl/src/process
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 13:54:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 13:54:38 +0000
commit8c1ab65c0f548d20b7f177bdb736daaf603340e1 (patch)
treedf55b7e75bf43f2bf500845b105afe3ac3a5157e /libc-top-half/musl/src/process
parentInitial commit. (diff)
downloadwasi-libc-8c1ab65c0f548d20b7f177bdb736daaf603340e1.tar.xz
wasi-libc-8c1ab65c0f548d20b7f177bdb736daaf603340e1.zip
Adding upstream version 0.0~git20221206.8b7148f.upstream/0.0_git20221206.8b7148f
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libc-top-half/musl/src/process')
-rw-r--r--libc-top-half/musl/src/process/_Fork.c38
-rw-r--r--libc-top-half/musl/src/process/arm/vfork.s10
-rw-r--r--libc-top-half/musl/src/process/execl.c22
-rw-r--r--libc-top-half/musl/src/process/execle.c23
-rw-r--r--libc-top-half/musl/src/process/execlp.c22
-rw-r--r--libc-top-half/musl/src/process/execv.c8
-rw-r--r--libc-top-half/musl/src/process/execve.c8
-rw-r--r--libc-top-half/musl/src/process/execvp.c60
-rw-r--r--libc-top-half/musl/src/process/fdop.h17
-rw-r--r--libc-top-half/musl/src/process/fexecve.c16
-rw-r--r--libc-top-half/musl/src/process/fork.c86
-rw-r--r--libc-top-half/musl/src/process/i386/vfork.s12
-rw-r--r--libc-top-half/musl/src/process/posix_spawn.c214
-rw-r--r--libc-top-half/musl/src/process/posix_spawn_file_actions_addchdir.c18
-rw-r--r--libc-top-half/musl/src/process/posix_spawn_file_actions_addclose.c17
-rw-r--r--libc-top-half/musl/src/process/posix_spawn_file_actions_adddup2.c18
-rw-r--r--libc-top-half/musl/src/process/posix_spawn_file_actions_addfchdir.c18
-rw-r--r--libc-top-half/musl/src/process/posix_spawn_file_actions_addopen.c21
-rw-r--r--libc-top-half/musl/src/process/posix_spawn_file_actions_destroy.c14
-rw-r--r--libc-top-half/musl/src/process/posix_spawn_file_actions_init.c7
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_destroy.c6
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_getflags.c7
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_getpgroup.c7
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_getsigdefault.c7
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_getsigmask.c7
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_init.c7
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_sched.c25
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_setflags.c18
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_setpgroup.c7
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_setsigdefault.c7
-rw-r--r--libc-top-half/musl/src/process/posix_spawnattr_setsigmask.c7
-rw-r--r--libc-top-half/musl/src/process/posix_spawnp.c13
-rw-r--r--libc-top-half/musl/src/process/s390x/vfork.s6
-rw-r--r--libc-top-half/musl/src/process/sh/vfork.s20
-rw-r--r--libc-top-half/musl/src/process/system.c46
-rw-r--r--libc-top-half/musl/src/process/vfork.c14
-rw-r--r--libc-top-half/musl/src/process/wait.c6
-rw-r--r--libc-top-half/musl/src/process/waitid.c7
-rw-r--r--libc-top-half/musl/src/process/waitpid.c7
-rw-r--r--libc-top-half/musl/src/process/x32/vfork.s10
-rw-r--r--libc-top-half/musl/src/process/x86_64/vfork.s10
41 files changed, 893 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/process/_Fork.c b/libc-top-half/musl/src/process/_Fork.c
new file mode 100644
index 0000000..da06386
--- /dev/null
+++ b/libc-top-half/musl/src/process/_Fork.c
@@ -0,0 +1,38 @@
+#include <unistd.h>
+#include <signal.h>
+#include "syscall.h"
+#include "libc.h"
+#include "lock.h"
+#include "pthread_impl.h"
+#include "aio_impl.h"
+
+static void dummy(int x) { }
+weak_alias(dummy, __aio_atfork);
+
+pid_t _Fork(void)
+{
+ pid_t ret;
+ sigset_t set;
+ __block_all_sigs(&set);
+ __aio_atfork(-1);
+ LOCK(__abort_lock);
+#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;
+ self->next = self->prev = self;
+ __thread_list_lock = 0;
+ libc.threads_minus_1 = 0;
+ if (libc.need_locks) libc.need_locks = -1;
+ }
+ UNLOCK(__abort_lock);
+ __aio_atfork(!ret);
+ __restore_sigs(&set);
+ return __syscall_ret(ret);
+}
diff --git a/libc-top-half/musl/src/process/arm/vfork.s b/libc-top-half/musl/src/process/arm/vfork.s
new file mode 100644
index 0000000..d7ec41b
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/execl.c b/libc-top-half/musl/src/process/execl.c
new file mode 100644
index 0000000..5ee5c81
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/execle.c b/libc-top-half/musl/src/process/execle.c
new file mode 100644
index 0000000..37ca503
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/execlp.c b/libc-top-half/musl/src/process/execlp.c
new file mode 100644
index 0000000..5eed886
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/execv.c b/libc-top-half/musl/src/process/execv.c
new file mode 100644
index 0000000..2ac0dec
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/execve.c b/libc-top-half/musl/src/process/execve.c
new file mode 100644
index 0000000..70286a1
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/execvp.c b/libc-top-half/musl/src/process/execvp.c
new file mode 100644
index 0000000..ef3b9dd
--- /dev/null
+++ b/libc-top-half/musl/src/process/execvp.c
@@ -0,0 +1,60 @@
+#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 = __strchrnul(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-top-half/musl/src/process/fdop.h b/libc-top-half/musl/src/process/fdop.h
new file mode 100644
index 0000000..7cf733b
--- /dev/null
+++ b/libc-top-half/musl/src/process/fdop.h
@@ -0,0 +1,17 @@
+#define FDOP_CLOSE 1
+#define FDOP_DUP2 2
+#define FDOP_OPEN 3
+#define FDOP_CHDIR 4
+#define FDOP_FCHDIR 5
+
+struct fdop {
+ struct fdop *next, *prev;
+ int cmd, fd, srcfd, oflag;
+ mode_t mode;
+ char path[];
+};
+
+#define malloc __libc_malloc
+#define calloc __libc_calloc
+#define realloc undef
+#define free __libc_free
diff --git a/libc-top-half/musl/src/process/fexecve.c b/libc-top-half/musl/src/process/fexecve.c
new file mode 100644
index 0000000..554c198
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/fork.c b/libc-top-half/musl/src/process/fork.c
new file mode 100644
index 0000000..54bc289
--- /dev/null
+++ b/libc-top-half/musl/src/process/fork.c
@@ -0,0 +1,86 @@
+#include <unistd.h>
+#include <errno.h>
+#include "libc.h"
+#include "lock.h"
+#include "pthread_impl.h"
+#include "fork_impl.h"
+
+static volatile int *const dummy_lockptr = 0;
+
+weak_alias(dummy_lockptr, __at_quick_exit_lockptr);
+weak_alias(dummy_lockptr, __atexit_lockptr);
+weak_alias(dummy_lockptr, __dlerror_lockptr);
+weak_alias(dummy_lockptr, __gettext_lockptr);
+weak_alias(dummy_lockptr, __locale_lockptr);
+weak_alias(dummy_lockptr, __random_lockptr);
+weak_alias(dummy_lockptr, __sem_open_lockptr);
+weak_alias(dummy_lockptr, __stdio_ofl_lockptr);
+weak_alias(dummy_lockptr, __syslog_lockptr);
+weak_alias(dummy_lockptr, __timezone_lockptr);
+weak_alias(dummy_lockptr, __bump_lockptr);
+
+weak_alias(dummy_lockptr, __vmlock_lockptr);
+
+static volatile int *const *const atfork_locks[] = {
+ &__at_quick_exit_lockptr,
+ &__atexit_lockptr,
+ &__dlerror_lockptr,
+ &__gettext_lockptr,
+ &__locale_lockptr,
+ &__random_lockptr,
+ &__sem_open_lockptr,
+ &__stdio_ofl_lockptr,
+ &__syslog_lockptr,
+ &__timezone_lockptr,
+ &__bump_lockptr,
+};
+
+static void dummy(int x) { }
+weak_alias(dummy, __fork_handler);
+weak_alias(dummy, __malloc_atfork);
+weak_alias(dummy, __ldso_atfork);
+
+static void dummy_0(void) { }
+weak_alias(dummy_0, __tl_lock);
+weak_alias(dummy_0, __tl_unlock);
+
+pid_t fork(void)
+{
+ sigset_t set;
+ __fork_handler(-1);
+ __block_app_sigs(&set);
+ int need_locks = libc.need_locks > 0;
+ if (need_locks) {
+ __ldso_atfork(-1);
+ __inhibit_ptc();
+ for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
+ if (*atfork_locks[i]) LOCK(*atfork_locks[i]);
+ __malloc_atfork(-1);
+ __tl_lock();
+ }
+ pthread_t self=__pthread_self(), next=self->next;
+ pid_t ret = _Fork();
+ int errno_save = errno;
+ if (need_locks) {
+ if (!ret) {
+ for (pthread_t td=next; td!=self; td=td->next)
+ td->tid = -1;
+ if (__vmlock_lockptr) {
+ __vmlock_lockptr[0] = 0;
+ __vmlock_lockptr[1] = 0;
+ }
+ }
+ __tl_unlock();
+ __malloc_atfork(!ret);
+ for (int i=0; i<sizeof atfork_locks/sizeof *atfork_locks; i++)
+ if (*atfork_locks[i])
+ if (ret) UNLOCK(*atfork_locks[i]);
+ else **atfork_locks[i] = 0;
+ __release_ptc();
+ __ldso_atfork(!ret);
+ }
+ __restore_sigs(&set);
+ __fork_handler(!ret);
+ if (ret<0) errno = errno_save;
+ return ret;
+}
diff --git a/libc-top-half/musl/src/process/i386/vfork.s b/libc-top-half/musl/src/process/i386/vfork.s
new file mode 100644
index 0000000..3d0e6d6
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawn.c b/libc-top-half/musl/src/process/posix_spawn.c
new file mode 100644
index 0000000..728551b
--- /dev/null
+++ b/libc-top-half/musl/src/process/posix_spawn.c
@@ -0,0 +1,214 @@
+#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 "lock.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 == p) {
+ ret = -EBADF;
+ goto fail;
+ }
+ 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;
+ case FDOP_CHDIR:
+ ret = __syscall(SYS_chdir, op->path);
+ if (ret<0) goto fail;
+ break;
+ case FDOP_FCHDIR:
+ ret = __syscall(SYS_fchdir, op->fd);
+ if (ret<0) goto fail;
+ 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;
+
+ 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);
+
+ /* The lock guards both against seeing a SIGABRT disposition change
+ * by abort and against leaking the pipe fd to fork-without-exec. */
+ LOCK(__abort_lock);
+
+ if (pipe2(args.p, O_CLOEXEC)) {
+ UNLOCK(__abort_lock);
+ ec = errno;
+ goto fail;
+ }
+
+ pid = __clone(child, stack+sizeof stack,
+ CLONE_VM|CLONE_VFORK|SIGCHLD, &args);
+ close(args.p[1]);
+ UNLOCK(__abort_lock);
+
+ 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;
+
+fail:
+ pthread_sigmask(SIG_SETMASK, &args.oldmask, 0);
+ pthread_setcancelstate(cs, 0);
+
+ return ec;
+}
diff --git a/libc-top-half/musl/src/process/posix_spawn_file_actions_addchdir.c b/libc-top-half/musl/src/process/posix_spawn_file_actions_addchdir.c
new file mode 100644
index 0000000..7f2590a
--- /dev/null
+++ b/libc-top-half/musl/src/process/posix_spawn_file_actions_addchdir.c
@@ -0,0 +1,18 @@
+#include <spawn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "fdop.h"
+
+int posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t *restrict fa, const char *restrict path)
+{
+ struct fdop *op = malloc(sizeof *op + strlen(path) + 1);
+ if (!op) return ENOMEM;
+ op->cmd = FDOP_CHDIR;
+ op->fd = -1;
+ 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-top-half/musl/src/process/posix_spawn_file_actions_addclose.c b/libc-top-half/musl/src/process/posix_spawn_file_actions_addclose.c
new file mode 100644
index 0000000..0c2ef8f
--- /dev/null
+++ b/libc-top-half/musl/src/process/posix_spawn_file_actions_addclose.c
@@ -0,0 +1,17 @@
+#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)
+{
+ if (fd < 0) return EBADF;
+ 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-top-half/musl/src/process/posix_spawn_file_actions_adddup2.c b/libc-top-half/musl/src/process/posix_spawn_file_actions_adddup2.c
new file mode 100644
index 0000000..addca4d
--- /dev/null
+++ b/libc-top-half/musl/src/process/posix_spawn_file_actions_adddup2.c
@@ -0,0 +1,18 @@
+#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)
+{
+ if (srcfd < 0 || fd < 0) return EBADF;
+ 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-top-half/musl/src/process/posix_spawn_file_actions_addfchdir.c b/libc-top-half/musl/src/process/posix_spawn_file_actions_addfchdir.c
new file mode 100644
index 0000000..e89ede8
--- /dev/null
+++ b/libc-top-half/musl/src/process/posix_spawn_file_actions_addfchdir.c
@@ -0,0 +1,18 @@
+#include <spawn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "fdop.h"
+
+int posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t *fa, int fd)
+{
+ if (fd < 0) return EBADF;
+ struct fdop *op = malloc(sizeof *op);
+ if (!op) return ENOMEM;
+ op->cmd = FDOP_FCHDIR;
+ op->fd = fd;
+ if ((op->next = fa->__actions)) op->next->prev = op;
+ op->prev = 0;
+ fa->__actions = op;
+ return 0;
+}
diff --git a/libc-top-half/musl/src/process/posix_spawn_file_actions_addopen.c b/libc-top-half/musl/src/process/posix_spawn_file_actions_addopen.c
new file mode 100644
index 0000000..82bbcec
--- /dev/null
+++ b/libc-top-half/musl/src/process/posix_spawn_file_actions_addopen.c
@@ -0,0 +1,21 @@
+#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)
+{
+ if (fd < 0) return EBADF;
+ 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-top-half/musl/src/process/posix_spawn_file_actions_destroy.c b/libc-top-half/musl/src/process/posix_spawn_file_actions_destroy.c
new file mode 100644
index 0000000..3251bab
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawn_file_actions_init.c b/libc-top-half/musl/src/process/posix_spawn_file_actions_init.c
new file mode 100644
index 0000000..89d5e12
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_destroy.c b/libc-top-half/musl/src/process/posix_spawnattr_destroy.c
new file mode 100644
index 0000000..fc714a1
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_getflags.c b/libc-top-half/musl/src/process/posix_spawnattr_getflags.c
new file mode 100644
index 0000000..aa635dd
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_getpgroup.c b/libc-top-half/musl/src/process/posix_spawnattr_getpgroup.c
new file mode 100644
index 0000000..0480527
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_getsigdefault.c b/libc-top-half/musl/src/process/posix_spawnattr_getsigdefault.c
new file mode 100644
index 0000000..a49050a
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_getsigmask.c b/libc-top-half/musl/src/process/posix_spawnattr_getsigmask.c
new file mode 100644
index 0000000..f60ad7f
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_init.c b/libc-top-half/musl/src/process/posix_spawnattr_init.c
new file mode 100644
index 0000000..0dcd868
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_sched.c b/libc-top-half/musl/src/process/posix_spawnattr_sched.c
new file mode 100644
index 0000000..3143635
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_setflags.c b/libc-top-half/musl/src/process/posix_spawnattr_setflags.c
new file mode 100644
index 0000000..6878099
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_setpgroup.c b/libc-top-half/musl/src/process/posix_spawnattr_setpgroup.c
new file mode 100644
index 0000000..f39596a
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_setsigdefault.c b/libc-top-half/musl/src/process/posix_spawnattr_setsigdefault.c
new file mode 100644
index 0000000..5686972
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnattr_setsigmask.c b/libc-top-half/musl/src/process/posix_spawnattr_setsigmask.c
new file mode 100644
index 0000000..f2532f8
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/posix_spawnp.c b/libc-top-half/musl/src/process/posix_spawnp.c
new file mode 100644
index 0000000..aad6133
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/s390x/vfork.s b/libc-top-half/musl/src/process/s390x/vfork.s
new file mode 100644
index 0000000..744f9d7
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/sh/vfork.s b/libc-top-half/musl/src/process/sh/vfork.s
new file mode 100644
index 0000000..91dbde7
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/system.c b/libc-top-half/musl/src/process/system.c
new file mode 100644
index 0000000..5af59b8
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/vfork.c b/libc-top-half/musl/src/process/vfork.c
new file mode 100644
index 0000000..d430c13
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/wait.c b/libc-top-half/musl/src/process/wait.c
new file mode 100644
index 0000000..34da102
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/waitid.c b/libc-top-half/musl/src/process/waitid.c
new file mode 100644
index 0000000..d688650
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/waitpid.c b/libc-top-half/musl/src/process/waitpid.c
new file mode 100644
index 0000000..1b65bf0
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/x32/vfork.s b/libc-top-half/musl/src/process/x32/vfork.s
new file mode 100644
index 0000000..0f0ca3e
--- /dev/null
+++ b/libc-top-half/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-top-half/musl/src/process/x86_64/vfork.s b/libc-top-half/musl/src/process/x86_64/vfork.s
new file mode 100644
index 0000000..9114439
--- /dev/null
+++ b/libc-top-half/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