#include "headers.h"

int main(int argc, char *argv[]){
  extern int errno;
  int sem_id;
  /* Struct for waiting on the semaphore */
  static struct sembuf sem_wait[] = { 0, -1, 0 };
  /* Struct for signalling on the semaphore */
  static struct sembuf sem_signal[] = { 0, +1, 0 };
  /* We want our fifo mode to be readable and writable only to us */
  mode_t fifo_mode = 0x00000180;
  const char *fifopath = "/tmp/alarm_fifo";
  int fd;
  pid_t child_alive = 0;
  pid_t child_pid = 1; /* Just for initialization purposes */
  int foo; /* Dumb value for the signal handler */
  
  /* Install a new signal handler */
  signal(SIGUSR1, new_handler);
  
  /* We need to create a semaphore set */
  /* First check if it is already there */
  if((sem_id = semget(0x1014fbad, 0, 0)) == -1){
    /* Need to create the set */
    if((sem_id = semget(0x1014fbad, 1, IPC_CREAT | IPC_EXCL | SEM_PERM)) != -1){
      /* We need to initialize the new semaphore set */
      union semun arg;
      ushort init_v[] = { 1 };
      arg.array = init_v;
      if(semctl(sem_id, 1, SETALL, arg) == -1){
        fprintf(stderr, "%s: semctl in parent\n", strerror(errno));
        abort();
      }
    }
  }
  
  child_alive = find_child();
  /* If the child is dead, we need to see if the semaphore is set properly.
   * It may not be if the child died abnormally.
   */
  if(!child_alive){
    /* Reset the semaphore set, just in case... */
    union semun arg;
    ushort init_v[] = { 1 };
    arg.array = init_v;
    if(semctl(sem_id, 1, SETALL, arg) == -1){
      fprintf(stderr, "%s: semctl() in parent\n", strerror(errno));
      abort();
    }
  }
  /* Now we wait */
  if(semop(sem_id, sem_wait, 1) < 0){
    fprintf(stderr, "%s: semop() in parent\n", strerror(errno));
    abort();
  }
  if(child_alive){
    /* Signal our child to wake up */
    if(kill(child_alive, SIGUSR1) < 0){
      fprintf(stderr, "%s: sending signal to child\n", strerror(errno));
      abort();
    }
  }
  /* First try to open our FIFO; if it doesn't open, create it, then open */
  if((fd = open(fifopath, O_RDWR)) == -1){
    /* We don't have a FIFO, make one */
    if(mkfifo(fifopath, fifo_mode)){ /* Create a FIFO */
      fprintf(stderr, "%s: mkfifo() in parent\n", strerror(errno));
      abort();
    }
    else{
      if((fd = open(fifopath, O_RDWR)) == -1){
        fprintf(stderr, "%s: open() of FIFO in parent\n", strerror(errno));
        abort();
      }
    }
  }
  
  /* Fork an itty bitty child... */
  if(!child_alive){
    if((child_pid = fork()) == -1){
      fprintf(stderr, "%s: fork()\n", strerror(errno));
      abort();
    }
  }
  
  if(child_pid == 0)
    new_handler(foo);
  else
    client(fd, sem_id);
  return 0;
}