/* file      : signal.c
 * date      : May 9th, 2003
 * version   : 0.2
 *
 * This file contains the signal handling code for
 * SocketMud(tm). It requires the event scheduler patch,
 * but besides that, it should be possible to install
 * this snippet into any SocketMud(tm) based product.
 */

#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include "mud.h"

bool sigGuard = FALSE;

void crashguard(int i)
{
  FILE *fp;
  ITERATOR *pIter;
  D_MOBILE *xMob;
  char buf[100];

  /* if signal handling is not yet enabled, we will
   * set the signal handling for SIGSEGV to the default
   * value, and then send a SIGSEGV to the MUD (again)
   */
  if (!sigGuard)
  {
    signal(SIGSEGV, SIG_DFL);
    raise(SIGSEGV);
    return;
  }

  /* fork the MUD, allowing one process to continue and
   * the other to die, creating a coredump for debugging.
   */
  if (fork() <= 0)
  {
    signal(SIGSEGV, SIG_DFL);
    raise(SIGSEGV);
    return;
  }
  wait(NULL);

  /* log the attempt to do a copyover */
  bug("SocketMud crashed, attempting to do a copyover.");

  /* attempt to open the copyover file to store sockets */
  if ((fp = fopen(COPYOVER_FILE, "w")) == NULL)
  {
    bug("Failed to open %s, aborting.", COPYOVER_FILE);
    exit(1);
  }

  /* write error message */
  sprintf(buf, "\n\r <*>            SocketMud Has Crashed....             <*>\n\r");

  /* inform all players of the crash, and turn off compression */
  pIter = AllocIterator(dmobile_list);
  while ((xMob = (D_MOBILE *) NextInList(pIter)) != NULL)
   {
//  for (dsock = dsock_list; dsock ; dsock = dsock_next)
//  {
//    dsock_next = dsock->next;

    compressEnd(xMob->socket, xMob->socket->compressing, FALSE);

/*    if (xMob->socket->state != STATE_PLAYING)
    {
      text_to_socket(dMob->socket, "\n\rSorry, we are rebooting. Come back in a few minutes.\n\r");
      close_socket(dsock, FALSE);
    }*/
      fprintf(fp, "%d %s %s\n",
        xMob->socket->control, xMob->name, xMob->socket->hostname);

      save_player(xMob->socket->player);

      text_to_socket(xMob->socket, buf);
  }

  /* close copyover file */
  fprintf (fp, "-1\n");
  fclose (fp);

  /* recycle sockets */
  recycle_sockets();

  /* attempt to execute SocketMud again */
  sprintf(buf, "%d", control);
  execl(EXE_FILE, "SocketMud", "crashguard", buf, (char *) NULL, (char *) NULL);

  /* log failed attempt */
  bug("Attempt to restore MUD failed.");
  exit(1);
}

void termguard(int i)
{
  ITERATOR *pIter;
//  D_SOCKET *dsock;
  char buf[200];

  bug("The server is shutting down, attempting to close MUD.");

  sprintf(buf, "\n\rServer Reboot - Stand By!!\n\r");

  pIter = AllocIterator(dmobile_list);
  /* inform all players and save them */
/*  for (dsock = dmobile_list; dsock; dsock = dsock->next)
  {
    text_to_socket(dsock, buf);

    if (dsock->state == STATE_PLAYING && dsock->player)
      save_player(dsock->player);
  }*/

  /* close MUD */
  exit(1);
}

bool event_game_sigguard(EVENT_DATA *event)
{
  sigGuard = TRUE;

  return FALSE;
}

void init_sigguard()
{
  EVENT_DATA *event;

  /* set the handlers for SIGSEGV (crash)
   * and SIGTERM (unexpected shutdown)
   */
  signal(SIGSEGV, crashguard);
  signal(SIGTERM, termguard);

  /* enqueue the event that will enable
   * the signal guard. We delay this by
   * 10 seconds to prevent spam-copyover.
   */
  event = alloc_event();
  event->fun = &event_game_sigguard;
  event->type = EVENT_GAME_SIGGUARD;
  add_event_game(event, 10 * PULSES_PER_SECOND);
}