/* (c) Copyright 2007 Daniel Hokka Zakrisson
   Released under the terms of the GNU GPL v2

   Build with gcc ... -osigrelay sigrelay
 */

#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 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 (kill(child, signal) == -1)
			perror(PREFIX "kill");
	}
}

#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;
	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;

	SETSIG(SIGCHLD)
	child = fork();
	if (child == 0) {
		if (new_group && setsid() == -1) {
			perror(PREFIX "setsid");
			exit(111);
		}
		execvp(argv[optind], argv+optind);
		perror(PREFIX "execvp");
		exit(111);
	}
	else if (child == -1) {
		perror(PREFIX "fork");
		exit(111);
	}
	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;
}