base system() on posix_spawn
[musl] / src / process / system.c
index 0f1c07b..0aa34cd 100644 (file)
@@ -2,44 +2,52 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <sys/wait.h>
+#include <spawn.h>
 #include <errno.h>
+#include "pthread_impl.h"
+#include "libc.h"
+
+static void dummy_0()
+{
+}
+weak_alias(dummy_0, __acquire_ptc);
+weak_alias(dummy_0, __release_ptc);
+
+extern char **environ;
 
 int system(const char *cmd)
 {
        pid_t pid;
-       sigset_t old, new;
-       struct sigaction sa, oldint, oldquit;
-       int status;
+       sigset_t old, reset;
+       struct sigaction sa = { .sa_handler = SIG_IGN }, oldint, oldquit;
+       int status = 0x7f00, ret;
+       posix_spawnattr_t attr;
 
-       if (!cmd) return 1;
+       pthread_testcancel();
 
-       sa.sa_handler = SIG_IGN;
-       sigemptyset(&sa.sa_mask);
-       sa.sa_flags = 0;
+       if (!cmd) return 1;
 
        sigaction(SIGINT, &sa, &oldint);
        sigaction(SIGQUIT, &sa, &oldquit);
        sigaddset(&sa.sa_mask, SIGCHLD);
-       sigprocmask(SIG_BLOCK, &new, &old);
-
-       pid = fork();
-       if (pid <= 0) {
-               sigaction(SIGINT, &oldint, NULL);
-               sigaction(SIGQUIT, &oldquit, NULL);
-               sigprocmask(SIG_SETMASK, &old, NULL);
-               if (pid == 0) {
-                       execl("/bin/sh", "sh", "-c", cmd, (char *)0);
-                       _exit(127);
-               }
-               return -1;
-       }
-       while (waitpid(pid, &status, 0) == -1)
-               if (errno != EINTR) {
-                       status = -1;
-                       break;
-               }
+       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;
 }