/* (c) Copyright 2007 Daniel Hokka Zakrisson Released under the terms of the GNU GPL v2 Build with gcc ... -osigrelay sigrelay */ #define _GNU_SOURCE #include #include #include #include #include #include #include #define PREFIX "sigrelay: " static pid_t child; static int pipefd[2]; static void signal_handler(int signal) { /* child exited, so should we */ if (signal == SIGCHLD) { int ret; if (waitpid(child, &ret, 0) == -1) { perror(PREFIX "waitpid"); exit(111); } exit(WEXITSTATUS(ret)); } /* relay */ else { if (!write(pipefd[1], &signal, sizeof(int))) { perror(PREFIX "write"); exit(111); } } } #define SETSIG(sig) if (signal(sig, signal_handler) == SIG_ERR) { \ signal_handler(SIGTERM); \ perror(PREFIX "signal(" #sig ")"); \ exit(111); \ } int main(int argc, char *argv[]) { int opt, new_group = 0; int read_signal; while ((opt = getopt(argc, argv, "+P")) != -1) { switch (opt) { case 'P': new_group = 1; break; default: fprintf(stderr, "Usage: %s [-P] *\n", argv[0]); break; } } if (argc == optind) return 0; if (pipe2(pipefd, O_CLOEXEC) == -1) { perror(PREFIX "pipe"); exit(111); } SETSIG(SIGCHLD) child = fork(); if (child == 0) { close(pipefd[1]); if (new_group && setsid() == -1) { perror(PREFIX "setsid"); exit(111); } child = fork(); if (child == 0) { execvp(argv[optind], argv+optind); perror(PREFIX "execvp"); exit(111); } else if (child == -1) { perror(PREFIX "fork"); exit(111); } while (read(pipefd[0], &read_signal, sizeof(int)) == sizeof(int)) { if (kill(child, read_signal) == -1) perror(PREFIX "kill"); } perror(PREFIX "read"); exit(111); } else if (child == -1) { perror(PREFIX "fork"); exit(111); } close(pipefd[0]); SETSIG(SIGHUP) SETSIG(SIGINT) SETSIG(SIGSEGV) SETSIG(SIGTERM) SETSIG(SIGUSR1) SETSIG(SIGUSR2) SETSIG(SIGWINCH) SETSIG(SIGALRM) SETSIG(SIGPWR) while (1) { sleep(600); } /* never get here, signal handler exits */ return 1; }