/* (c) Copyright 2007 Daniel Hokka Zakrisson
Released under the terms of the GNU GPL v2
Build with gcc ... -osigrelay sigrelay
*/
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#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] <program> <args>*\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;
}