/***************************************************/
/* program1.c                                      */
/* Justin Hartman                                  */
/* EECS 338 - Spring 2003                          */
/* Assignment 2                                    */
/***************************************************/

/***************************************************/
/* Written in Microsoft Visual C++ 6.0             */
/* Compiled and executed on CWRU's EECS department */
/* lab's (Olin 404.5) SUN boxes using SSH and      */
/* secure FTP                                      */
/***************************************************/

#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

int file_des;			/* File handle */
FILE *fd;				/* File descriptor */
int num_users;
int signal_count = 0;
pid_t** pid_list;		/* List of process IDs */
char *filename;

int main(int argc, char* argv[]) {
	void signal_catcher(int);
	time_t t;
	struct flock lock;
	int i;
	pid_t pid;

	/* Store the filename in a global variable */
	filename = argv[1];

	/* Check arg usage */
	if (argc != 3) {
		printf("Usage: %s filename num_users\n", argv[0]);
		exit(1);
	}

	/* Make sure the last param is numeric */
	if (sscanf(argv[2], "%d", &num_users) != 1) {
		printf("Usage: %s filename num_users\n", argv[0]);
		exit(2);
	}

	/* Set the signal handler */
	if (sigset(SIGUSR1, signal_catcher) == SIG_ERR) {
		perror("Error setting signal handler for SIGUSR1");
		exit(3);
	}

	/* Open a file handle to the output file, creating if necessary */
	if ((file_des = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
		perror("Error opening file for output");
		exit(4);
	}

	/* Open a file descriptor to write to the output file */
	if ((fd = fdopen(file_des, "w")) < 0) {
		perror("Error opening file for output");
		exit(5);
	}

	t = time(NULL);
	fprintf(fd, "%s started on %s, process ID %d\n", argv[0], ctime(&t), (int)getpid());

	/* Set up a write lock on the open file */
	lock.l_type = F_WRLCK;
	lock.l_whence = 0;
	lock.l_start = 0L;
	lock.l_len = 0L;

	if (fcntl(file_des, F_SETLK, &lock) < 0) {
		perror("Error locking output file from writes");
		exit(6);
	}

	/* malloc an list for the process IDs */
	pid_list = (pid_t **) malloc(num_users * sizeof(pid_t *));

	for (i=0; i<num_users; i++) {
		if ((pid = fork()) == 0) {
			/* We're in the child process */
			execlp("./program2", "./program2", argv[1], (char *)NULL);
			exit(0);
		} else {
			/* We're in the parent process, so add the pid to the list */
			pid_list[i] = (pid_t *) malloc(sizeof(pid_t));
			*pid_list[i] = pid;
		}
	}

	/* Wait for all the SIGUSR1s to come in */
	while (signal_count < num_users) {
		sigpause(SIGUSR1);
	}

	/* Unlock the write lock on the output file */
	lock.l_type = F_UNLCK;
	lock.l_whence = 0;
	lock.l_start = 0L;
	lock.l_len = 0L;

	if (fcntl(file_des, F_SETLK, &lock) < 0) {
		perror("Error unlocking output file");
		exit(7);
	}

	/* Close the file descriptor and handle */
	fclose(fd);

	/* Send all the SIGUSR2s and exit */
	for (i=0; i<num_users; i++) {
		kill(*pid_list[i], SIGUSR2);
	}

	exit(0);
}

void signal_catcher(int the_sig) {
	time_t t;

	/* Hold all incoming SIGUSR1s */
	sighold(SIGUSR1);

	if (the_sig == SIGUSR1) {
		printf("\nSIGUSR1 received\n");
		fflush(stdout);

		/* Write the event to the file */
		t = time(NULL);
		fprintf(fd, "SIGUSR1 received on %s, process ID %d\n", ctime(&t), (int)getpid());
		fflush(stdout);
		signal_count++;
	}

	/* Release all pending SIGUSR1s */
	sigrelse(SIGUSR1);
}
