/* man posix_spawn(3) gcc -g -Wall -o test_posix_spawn test_posix_spawn.c $ ./a.out date PID of child: 7634 Tue Feb 1 19:47:50 CEST 2011 Child status: exited, status=0 $ ./a.out -c date PID of child: 7636 date: write error: Bad file descriptor Child status: exited, status=1 $ ./a.out -s sleep 60 & [1] 7637 $ PID of child: 7638 $ kill 7638 $ kill -KILL 7638 $ Child status: killed by signal 9 [1]+ Done ./a.out -s sleep 60 $ ./a.out xxxxx PID of child: 10190 Child status: exited, status=127 Hurd: ./test_posix_spawn xxxx posix_spawn: No such file or directory */ #include #include #include #include #include #include #include #define errExit(msg) do { perror(msg); \ exit(EXIT_FAILURE); } while (0) #define errExitEN(en, msg) \ do { errno = en; perror(msg); \ exit(EXIT_FAILURE); } while (0) char **environ; int main(int argc, char *argv[]) { pid_t child_pid; int s, opt, status; sigset_t mask; posix_spawnattr_t attr; posix_spawnattr_t *attrp; posix_spawn_file_actions_t file_actions; posix_spawn_file_actions_t *file_actionsp; /* Parse command-line options, which can be used to specify an attributes object and file actions object for the child. */ attrp = NULL; file_actionsp = NULL; while ((opt = getopt(argc, argv, "sc")) != -1) { switch (opt) { case 'c': /* -c: close standard output in child */ /* Create a file actions object and add a "close" action to it */ s = posix_spawn_file_actions_init(&file_actions); if (s != 0) errExitEN(s, "posix_spawn_file_actions_init"); s = posix_spawn_file_actions_addclose(&file_actions, STDOUT_FILENO); if (s != 0) errExitEN(s, "posix_spawn_file_actions_addclose"); file_actionsp = &file_actions; break; case 's': /* -s: block all signals in child */ /* Create an attributes object and add a "set signal mask" action to it */ s = posix_spawnattr_init(&attr); if (s != 0) errExitEN(s, "posix_spawnattr_init"); s = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK); if (s != 0) errExitEN(s, "posix_spawnattr_setflags"); sigfillset(&mask); s = posix_spawnattr_setsigmask(&attr, &mask); if (s != 0) errExitEN(s, "posix_spawnattr_setsigmask"); attrp = &attr; break; } } /* Spawn the child. The name of the program to execute and the command-line arguments are taken from the command-line arguments of this program. The environment of the program execed in the child is made the same as the parent's environment. */ s = posix_spawnp(&child_pid, argv[optind], file_actionsp, attrp, &argv[optind], environ); if (s != 0) errExitEN(s, "posix_spawn"); /* Destroy any objects that we created earlier */ if (attrp != NULL) { s = posix_spawnattr_destroy(attrp); if (s != 0) errExitEN(s, "posix_spawnattr_destroy"); } if (file_actionsp != NULL) { s = posix_spawn_file_actions_destroy(file_actionsp); if (s != 0) errExitEN(s, "posix_spawn_file_actions_destroy"); } printf("PID of child: %ld\n", (long) child_pid); /* Monitor status of the child until it terminates */ do { #ifndef __GNU__ s = waitpid(child_pid, &status, WUNTRACED | WCONTINUED); #else s = waitpid(child_pid, &status, WUNTRACED); #endif if (s == -1) errExit("waitpid"); printf("Child status: "); if (WIFEXITED(status)) { printf("exited, status=%d\n", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("killed by signal %d\n", WTERMSIG(status)); } else if (WIFSTOPPED(status)) { printf("stopped by signal %d\n", WSTOPSIG(status)); #ifndef __GNU__ } else if (WIFCONTINUED(status)) { printf("continued\n"); #endif } } while (!WIFEXITED(status) && !WIFSIGNALED(status)); exit(EXIT_SUCCESS); }