blob: 13e9fbe922b2c0aeeaa47281130819005dbff4e6 [file] [log] [blame]
/*
* system.c
*
* The system() function. If this turns out to actually be *used*,
* we may want to try to detect the very simple cases (no shell magic)
* and handle them internally, instead of requiring that /bin/sh be
* present.
*/
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
int system(const char *string)
{
pid_t pid;
struct sigaction ignore, old_int, old_quit;
sigset_t masked, oldmask;
static const char *argv[] = { "/bin/sh", "-c", NULL, NULL };
int status;
/* Block SIGCHLD and ignore SIGINT and SIGQUIT */
/* Do this before the fork() to avoid races */
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
ignore.sa_flags = 0;
sigaction(SIGINT, &ignore, &old_int);
sigaction(SIGQUIT, &ignore, &old_quit);
sigemptyset(&masked);
sigaddset(&masked, SIGCHLD);
sigprocmask(SIG_BLOCK, &masked, &oldmask);
pid = fork();
if (pid < 0)
return -1;
else if (pid == 0) {
sigaction(SIGINT, &old_int, NULL);
sigaction(SIGQUIT, &old_quit, NULL);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
argv[2] = string;
execve(argv[0], (char *const *)argv, (char *const *)environ);
_exit(127);
}
/* else... */
waitpid(pid, &status, 0);
sigaction(SIGINT, &old_int, NULL);
sigaction(SIGQUIT, &old_quit, NULL);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return status;
}