/* Timeout killer program for Verkel :-)
 * Author: Miika Pekkarinen <miipekk@ihme.org>
 */

#include <sys/types.h>
#include <stdio.h>
#include <signal.h>

static int finished = 0;
static int alarm_got = 0;
static int timeout;
static const char *str = "\
I will wait and wait until it's the time for the action...\n\
\\\r-\r/\r-\r\ This is pretty boring... \n\
\\\r-\r/\r-\r\ Nothing more but wait...\n\
\\\r-\r/\r-\r\ Argh :)\n\
";


void sig_child (int sig)
{
	printf ("Your journey is over, process!\n");
	finished = 1;
}

void sig_alarm (int sig)
{
	printf ("Timeout! ... ");
	if (timeout > 600) {
		printf ("At last, it was VERY boring to wait!\n");
	} else if (timeout > 300) {
		printf ("Finally, it was quite boring to wait.\n");
	} else {
		printf ("Huh, it was little boring to wait.\n");
	}
	
	alarm_got = 1;
}

int main (int argc, char **argv)
{
	int i = 0;
	int len = strlen(str);
	pid_t child_pid;
	/* int timeout; */
	
	/* Initialize signal handlers */
	if (signal (SIGCHLD, sig_child) < 0 || signal (SIGALRM, sig_alarm) < 0) {
		fprintf (stderr, "Grr, can't initialize signal handlers\n");
		exit (-2);
	}
	
	if (argc < 3) {
		fprintf (stderr,
			 "Usage: %s TIMEOUT COMMAND [ARGUMENTS]\n", argv[0]);
		return -3;
	}
	
	printf ("Forking a child...\n");
	
	child_pid = fork ();
	timeout = atoi(argv[1]);
	
	switch (child_pid) {
	case -1: /* fork failed */
		perror ("Fork failed, maybe your system is full of the damned processes!");
		exit (-1);
		break;
		
	case 0: /* child */
		/* Execute program, i.e. change program context */
		
	  fclose(stdout);
		if (execvp(argv[2], &argv[2]) < 0) {
			perror ("execvp failed");
			printf ("Hmm, I think you gave me something not interesting at all! (%s)\n", argv[1]);
			exit (-2);
		}
		break;
		
	}
	
	/* Parent */
	printf ("Child forked [PID %d]\n", child_pid);
	
	if (alarm (timeout) < 0) {
		printf ("Argh, can't set an alarm. Exiting.\n");
		kill (child_pid, SIGKILL);
		return -1;
	}
	
	printf ("Waiting %d seconds ...\n", timeout);
	while (!finished && !alarm_got) {
		usleep (500000);
		if (i < len) {
			printf("%c", str[i]);
			fflush (stdout);
			i++;
		}
		
	}
	
	if (finished) {
		printf ("Ah, I see.. Process already died and there was no need for me at all!\n");
	}
	
	if (alarm_got) {
		printf ("Great, now it has come the moment of truth! Bye bye :)\n");
		kill (child_pid, SIGTERM);
		sleep (2);
		
		if (!finished) {
			printf ("Hmm, we need to give a great beat for the process! Lets start.\n");
			kill (child_pid, SIGKILL);
			sleep (1);
			if (!finished) {
				printf ("You have become a zombie.. If I would be the kernel of the system then you should beware!\n");
			} else {
				printf ("Finally it was your last second, process!\n");
			}
		}
	}
	
	printf ("Done :)\n");
	
	return 0;
}

