|
|
|
@ -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; |
|
|
|
} |
|
|
|
|