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