#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>

#define errhnd(...) _errhnd (__LINE__, __VA_ARGS__)

extern int errno;
char **child_argv;
volatile int flag_term = 0;

void _errhnd (int line, int rs)
{
	if (rs != -1)
		return;

	fprintf (stderr, "Błąd w linii %d: %s.\n", line, strerror(errno));
	_exit (-1);
}

void spawn_chld (void);

void hnd_chld (int signo)
{
	while (waitpid(-1, NULL, WNOHANG) > 0);
	signal (SIGCHLD, hnd_chld);
	spawn_chld();
}

void hnd_alrm (int signo)
{
	alarm (0);
	spawn_chld();
	signal (SIGALRM, hnd_alrm);
}

void hnd_term (int signo)
{
	flag_term = signo;
	signal (signo, hnd_term);
}

void spawn_chld (void)
{
	static time_t last_spawn = 0;
	time_t this_spawn = time(NULL);
	pid_t pid;

	if (this_spawn < last_spawn)
		fprintf (stderr, "timer wstecz?\n");
	else if (this_spawn - last_spawn < 5) {
		fprintf (stderr, "child spawnujący za często, ograniczono do 5 sekund.\n");
		alarm (5 - (this_spawn - last_spawn));
		return;
	}

	last_spawn = this_spawn;
	errhnd (pid = fork());
	if (pid) {
		fprintf (stderr, "respawning, child pid = %u.\n", pid);
		return;
	}

	errhnd (execve(child_argv[0], child_argv, NULL));
}

int main (int argc, char **argv)
{
	pid_t pid;

	if (argc < 2)
		_exit (1);

	errhnd (pid = fork());
	if (pid)
		_exit (0);
	errhnd (setsid());

	child_argv = argv + 1;
	errhnd (signal(SIGCHLD, hnd_chld) == SIG_ERR ? -1 : 0);
	errhnd (signal(SIGALRM, hnd_alrm) == SIG_ERR ? -1 : 0);
	errhnd (signal(SIGTERM, hnd_term) == SIG_ERR ? -1 : 0);
	errhnd (signal(SIGINT, hnd_term) == SIG_ERR ? -1 : 0);
	spawn_chld();
	while (!flag_term) usleep (100000);

	return 0;
}
