| /* |
| * 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 <errno.h> |
| #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; |
| } |