#include #include #include #include #include #include #include #include #include #include /* compile with -D_XOPEN_SOURCE=500 */ int main(int argc, char *argv[]) { long ps_delay = 250000, fork_delay = 100000; char c; pid_t ps_pid, pid; sigset_t set; while ((c = getopt(argc, argv, "p:f:")) != -1) { switch (c) { case 'p': ps_delay = strtol(optarg, NULL, 0); if (errno != 0 || ps_delay < 0) return EXIT_FAILURE; break; case 'f': fork_delay = strtol(optarg, NULL, 0); if (errno != 0 || fork_delay < 0) return EXIT_FAILURE; break; default: return EXIT_FAILURE; } } for (;;) { ps_pid = fork(); if (ps_pid > 0) break; else if (ps_pid < 0) { if (errno == EAGAIN) errno = 0; else return EXIT_FAILURE; } else { int fd = open("/dev/null", 0); if (fd < 0) return EXIT_FAILURE; if (dup2(fd, STDIN_FILENO) != STDIN_FILENO) return EXIT_FAILURE; if (dup2(fd, STDOUT_FILENO) != STDOUT_FILENO) return EXIT_FAILURE; if (dup2(fd, STDERR_FILENO) != STDERR_FILENO) return EXIT_FAILURE; if (close(fd) != 0) return EXIT_FAILURE; for (;;) { if (system("ps -elf") == 0) { if (usleep(ps_delay) != 0) return EXIT_FAILURE; } else if (errno == EAGAIN) errno = 0; else return EXIT_FAILURE; } return EXIT_SUCCESS; } } sigfillset(&set); if (sigprocmask(SIG_BLOCK, &set, NULL) != 0) return EXIT_FAILURE; for (;;) { int ret; for (;;) { pid = fork(); if (pid == 0) return EXIT_SUCCESS; else if (pid > 0) break; else if (errno != EAGAIN) goto cleanup_ps; } ret = waitpid(pid, NULL, 0); if (ret == -1) goto cleanup_ps; /* check up on ps child */ ret = waitpid(ps_pid, NULL, WNOHANG); /* * panic and leave mess on error * or exit without doing anything if ps child died */ if (ret == -1 || ret == ps_pid) return EXIT_FAILURE; sigfillset(&set); if (sigpending(&set) != 0) goto cleanup_ps; if (sigismember(&set, SIGHUP) || sigismember(&set, SIGINT) || sigismember(&set, SIGQUIT) || sigismember(&set, SIGILL) || sigismember(&set, SIGABRT) || sigismember(&set, SIGFPE) || sigismember(&set, SIGKILL) || sigismember(&set, SIGSEGV) || sigismember(&set, SIGPIPE) || sigismember(&set, SIGALRM) || sigismember(&set, SIGTERM) || sigismember(&set, SIGUSR1) || sigismember(&set, SIGUSR2) || sigismember(&set, SIGSTOP) || sigismember(&set, SIGTSTP) || sigismember(&set, SIGTTIN) || sigismember(&set, SIGTTOU)) goto cleanup_ps; if (usleep(fork_delay) != 0) goto cleanup_ps; } return EXIT_SUCCESS; cleanup_ps: /* clean up ps child, ignoring errors */ kill(ps_pid, SIGKILL); waitpid(ps_pid, NULL, 0); return EXIT_FAILURE; }