void double_fork() { pid_t child, grandchild, wresult; int status; /* Fork once, then again, to disassociate the child from the command shell process group. */ child = fork(); if (child < 0) { /* Failure to fork. */ perror("fork"); exit(1); } if (child == 0) { /* Child. Fork again. */ grandchild = fork(); if (grandchild < 0) { perror("fork"); exit(1); } if (grandchild == 0) { /* Grandchild. Begin useful work. */ do_autorestart(); /* Shouldn't get here. */ exit(1); } /* Child. Report the new pid, then terminate gracefully. */ fprintf(stderr, "Spawned, monitoring pid is %d.\n", grandchild); exit(0); } /* Parent. Wait for the child to terminate, then return. */ wresult = waitpid(child, &status, 0); if (wresult < 0) { perror("waitpid"); exit(1); } if (!WIFEXITED(status)) { if (WIFSIGNALED(status)) { fprintf(stderr, "child caught signal %d unexpectedly.\n", WTERMSIG(status)); } else { fprintf(stderr, "child exited with status %d.\n", WEXITSTATUS(status)); } exit(1); } }
int main(int argc, char *argv[]) { extern char *optarg; extern int optind; /* The initial '+' instructs GNU getopt not to reorder switches. */ static const char *optflags = "+l:p:fntr:s:c:d:W:U:G:D:h"; int flag; flag = getopt(argc, argv, optflags); while (flag != EOF) { switch (flag) { case 'l': logfile_name = optarg; break; case 'p': pidfile_name = optarg; break; case 'f': dont_fork = 1; break; case 'n': stop_always = 1; break; case 't': stop_on_terminate = 1; break; case 'r': parse_int_triplet(optarg, &spam_respawn_count, &spam_respawn_time, &spam_restart_delay_time); break; case 's': respawn_script = optarg; break; case 'c': respawn_count_time = atoi(optarg); break; case 'd': respawn_delay_time = atoi(optarg); break; case 'W': parse_watchdog(optarg); break; case 'U': startup_username = optarg; break; case 'G': startup_groupname = optarg; break; case 'D': startup_chdir = optarg; break; case 'h': help(); return 1; case '?': case '+': usage(); return 1; default: fprintf(stderr, "Unhandled switch: -%c\n", flag); return 1; } flag = getopt(argc, argv, optflags); } argc -= (optind - 1); argv += (optind - 1); if (argc < 2) { fprintf(stderr, "No program to execute given.\n"); usage(); return 1; } params = &argv[1]; if (logfile_name != NULL) { logfile_fd = open(logfile_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (logfile_fd < 0) { fprintf(stderr, "Cannot write to logfile %s: %s\n", logfile_name, strerror(errno)); return 1; } fprintf(stderr, "Generating output to %s.\n", logfile_name); } if (startup_chdir != NULL) { if (chdir(startup_chdir) != 0) { perror(startup_chdir); return 1; } } if (startup_groupname != NULL) { struct group *grp; grp = getgrnam(startup_groupname); if (grp == NULL) { perror(startup_groupname); return 1; } if (setgid(grp->gr_gid) != 0) { perror(startup_groupname); return 1; } } if (startup_username != NULL) { struct passwd *pwd; pwd = getpwnam(startup_username); if (pwd == NULL) { perror(startup_username); return 1; } if (setuid(pwd->pw_uid) != 0) { perror(startup_username); return 1; } } if (dont_fork) { do_autorestart(); } else { double_fork(); } return 0; }