base system() on posix_spawn
[musl] / src / process / system.c
index 0cc8b81..0aa34cd 100644 (file)
@@ -2,6 +2,7 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <sys/wait.h>
+#include <spawn.h>
 #include <errno.h>
 #include "pthread_impl.h"
 #include "libc.h"
@@ -12,57 +13,41 @@ static void dummy_0()
 weak_alias(dummy_0, __acquire_ptc);
 weak_alias(dummy_0, __release_ptc);
 
-pid_t __vfork(void);
-void __testcancel(void);
+extern char **environ;
 
 int system(const char *cmd)
 {
        pid_t pid;
-       sigset_t old;
+       sigset_t old, reset;
        struct sigaction sa = { .sa_handler = SIG_IGN }, oldint, oldquit;
-       int status = -1, i;
+       int status = 0x7f00, ret;
+       posix_spawnattr_t attr;
 
-       __testcancel();
+       pthread_testcancel();
 
        if (!cmd) return 1;
 
        sigaction(SIGINT, &sa, &oldint);
        sigaction(SIGQUIT, &sa, &oldquit);
-       sigprocmask(SIG_BLOCK, SIGALL_SET, &old);
-
-       __acquire_ptc();
-       pid = __vfork();
-
-       if (pid) __release_ptc();
-
-       if (pid > 0) {
-               sigset_t new = old;
-               sigaddset(&new, SIGCHLD);
-               sigprocmask(SIG_BLOCK, &new, 0);
-               while (waitpid(pid, &status, 0) && errno == EINTR);
-       }
-
-       if (pid) {
-               sigaction(SIGINT, &oldint, NULL);
-               sigaction(SIGQUIT, &oldquit, NULL);
-               sigprocmask(SIG_SETMASK, &old, NULL);
-               return status;
-       }
-
-       /* Before we can unblock signals in the child, all signal
-        * handlers must be eliminated -- even implementation-internal
-        * ones. Otherwise, a signal handler could run in the child
-        * and clobber the parent's memory (due to vfork). */
-       for (i=1; i<=8*__SYSCALL_SSLEN; i++) {
-               struct sigaction sa;
-               __libc_sigaction(i, 0, &sa);
-               if (sa.sa_handler!=SIG_IGN && sa.sa_handler!=SIG_DFL) {
-                       sa.sa_handler = SIG_DFL;
-                       __libc_sigaction(i, &sa, 0);
-               }
-       }
-
+       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);
-       execl("/bin/sh", "sh", "-c", cmd, (char *)0);
-       _exit(127);
+
+       if (ret) errno = ret;
+       return status;
 }