diff options
author | Rich Felker <dalias@aerifal.cx> | 2013-02-03 18:21:04 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2013-02-03 18:21:04 -0500 |
commit | a8799356d560d3b02a19a4bda4a638a4a9a80856 (patch) | |
tree | 1aadcc506af8b0a041435d80795fc553a4927040 | |
parent | 4862864fc1a6d162b297db09c216b136db83d7dd (diff) | |
download | musl-a8799356d560d3b02a19a4bda4a638a4a9a80856.tar.gz musl-a8799356d560d3b02a19a4bda4a638a4a9a80856.tar.xz musl-a8799356d560d3b02a19a4bda4a638a4a9a80856.zip |
base system() on posix_spawn
this avoids duplicating the fragile logic for executing an external program without fork.
-rw-r--r-- | src/process/system.c | 67 |
1 files changed, 26 insertions, 41 deletions
diff --git a/src/process/system.c b/src/process/system.c index 0cc8b810..0aa34cd0 100644 --- a/src/process/system.c +++ b/src/process/system.c @@ -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; } |