cdirt/ascii/
cdirt/data/BULL/
cdirt/data/ZONES/PENDING/
cdirt/pending/
cdirt/src/utils/
cdirt/utils/
/****************************************************************
 * C-Dirt 2.41							*
 * (C) 1999 G. Castrataro					*
 ****************************************************************/

#include "main.h"

void save_pid(void) {
  char pidfile[50];
  FILE *pidptr;

  sprintf (pidfile, "%s/%s.%d", data_dir, PID_FILE, mud_port);
  if ((pidptr = FOPEN(pidfile, "w"))) {
    fprintf(pidptr, "%d\n", getpid());
    FCLOSE(pidptr);
  }
}

void rm_pid(void) {
  char pidfile[50];
 
  sprintf(pidfile, "%s/%s.%d", data_dir, PID_FILE, mud_port);
  unlink(pidfile);
}

int main (int argc, char **argv, char **ep) {
  int x;
  char nologin[50];
  envp = ep;
  progname = argv[0];

  srand48(time(NULL));          /* init random numbers */
  srand((int) time(NULL));

  get_options (argc, argv);     /* Parse command line */

  if (!old_proc_num)
    fprintf(stderr, "%s Daemon Loading...\n", VERSION);

  if (!quiet) {
    if (data_dir == NULL) {
      fprintf (stderr, "  C-Dirt Daemon Error: data_dir is a NULL value.\n");
      fprintf (stderr, "  Halting Daemon!\n");
      exit (1);
    }
    fprintf (stderr, "\n  Data Directory:   %s\n", data_dir);
    fprintf (stderr, "  Maximum Players:  %d\n", max_players);
    fprintf (stderr, "  Port Selected:    %d\n", mud_port);
    fprintf (stderr, "  Clear System Log: %s\n", clear_syslog_file ?"Yes":"No");
    fprintf (stderr, "  Kill Other MUD:   %s\n", kill_other_mud ?"Yes":"Ask User");
    fprintf (stderr, "  Auto Open Game:   %s\n", auto_open ? "Yes" : "No");
  }

  chdir (data_dir);

  if (auto_open) {
    sprintf (nologin, "%s/%s.%d", data_dir, NOLOGIN, mud_port);
    remove (nologin);
  }

  for (x = 0 ; x < MAX_FDS ; x++)
    sock_fds[x] = -1;

  if (!old_proc_num) {
    check_pid();
    x = xmain ();
  }
  else
    x = xmain_reboot ();

  rm_pid();

  if (x < 0)
    mudlog ("BOOTUP: Abnormal termination of mud");
  else
    mudlog ("BOOTUP: Normal termination of mud");

  return(0);
}

int msock(int port) {
  int s;
  struct sockaddr_in server;
  struct hostent *h;
  int opt;

  s = socket(AF_INET, SOCK_STREAM, 0);

  if (s == -1) {
    fprintf(stderr, "(Bootup): Error creating stream socket\n");
    exit(1);
  }

  opt = 1;
  if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) == -1)
  {
    fprintf(stderr, "(Bootup): Error in setsockopt\n");
    exit(2);
  }

  if (!(h = gethostbyname(_HOSTNAME_))) {
    fprintf(stderr, "Unable to bind to hostname you chose. Run configure.\n");
    exit(3);
  }

  server.sin_family = AF_INET;
  server.sin_port = htons (port);
  bcopy (h->h_addr_list[0], &(server.sin_addr), h->h_length);  

  if (bind (s, (struct sockaddr *) & server, sizeof (server))) {
    fprintf(stderr, "(Bootup): Error binding stream socket\n");
    close(s);
    exit(4);
  }
  listen (s, 5);
  return s;
}

static int xmain () {

  /* We arrive here only if we are to continue and now we are alone. */

  if (open_logfile(clear_syslog_file) || bootstrap() || go_background()) {
    fprintf(stderr, "Error during bootstrap.\n");
    return -1;
  }

  main_socket = msock(mud_port);

  numresets = 0;
  numreboots = 0;
  numcrashes = 0;

  /* Initialize MUD Daemon Startup Time */
  time (&last_startup);

  /* Main program loop */
  main_loop(main_socket);
          
  mudlog ("&+WSYSTEM:&N Closing listening socket");
  close(main_socket);
  return(0);
}

/* BSD style daemonizing */

static int go_background () {
  int pid;

  if (!stay_foreground) {
    if ((pid = fork())) {
      fflush (stdout);
      exit (3);
    }
    fclose (stdin);
    fclose (stdout);

    #ifdef _LINUX_
      setpgrp ();
    #else
      setpgrp (pid, pid);
    #endif
  }
  save_pid();

  signal (SIGHUP, SIG_IGN);
  signal (SIGINT, SIG_IGN);
  signal (SIGQUIT, SIG_IGN);
  signal (SIGPIPE, SIG_IGN);            /* Broken pipe */
  signal (SIGTSTP, SIG_DFL);
  signal (SIGTTOU, SIG_DFL);
  signal (SIGTTIN, SIG_DFL);
  signal (SIGINT, sig_handler);
  signal (SIGTERM, sig_handler);
  signal (SIGSEGV, sig_handler);	/* Segmentation fault */
  signal (SIGBUS, sig_handler);	        /* Bus error */
  signal (SIGSYS, sig_handler);	        /* Bad argument to system call */
  signal (SIGUSR1, sig_handler);	/* User defined signal */
  signal (SIGUSR2, sig_handler);	/* User defined signal */
  return 0;
}
 
/* check if the pid exists, if so, ask to kill it */

void check_pid(void) {
  FILE *pidptr;
  char c;
  int oldpid;
  char pidfile[50];

  sprintf (pidfile, "%s/%s.%d", data_dir, PID_FILE, mud_port);
  if (!(pidptr = FOPEN(pidfile, "r")))
    return;

  fscanf(pidptr, "%d", &oldpid);
  FCLOSE(pidptr);

  if (kill(oldpid, SIGCONT) == -1) {
    if (errno == EPERM) {
      printf("  Aberd is already running under a different user.\n");
      exit(4);
    }
  }
  else {
    printf("  Aberd is already running, kill it? ");
    if (tolower(c = getchar()) == 'y') {
      kill(oldpid, SIGTERM);
        while(!access(pidfile, F_OK))    /* sleep until other mud dies */
          sleep(1);
      printf("  Other MUD killed, loading...\n");
    }
    else {
      printf("Aborted aberd loading.\n");
      exit(5);
    }
  }
}

static void usage (void);

static void
get_options (int argc, char **argv)
{
  char *s;
  int x;

  if (argc == 1) {
    stay_foreground = False;
    clear_syslog_file = False;
    mud_port = PORT;
    max_players = 32;
    return;
  }
  while (--argc > 0) {
    s = *++argv;
    if (*s++ != '-') {
      usage ();
      exit (0);
    }
    x = *s++;
    switch (x) {
    case 'a':
      break;
    case 'h':
      usage ();
      exit(0);
    case 'H':
      fullusage ();
      exit(0);
    case 'p':
      if (*s != '\0' || (--argc > 0 && *(s = *++argv) != '\0')) {
	if ((mud_port = atoi (s)) < 1000 || mud_port > 65535) {
	  mud_port = PORT + 5;
	}
      }
      break;
    case 'f':
      stay_foreground = True;
      break;
    case 'k':
      kill_other_mud = True;
      break;
    case 'c':
      clear_syslog_file = True;
      break;
    case 'v':
      quiet = False;
      break;
    case 'o':
      auto_open = True;
      break;
    case 'V':
      printf ("\nC-Dirt Version Information\n");
      printf ("-------------------------\n");
      printf ("%s (%s/%s)\n", VERSION, _ARCH_, _OS_);
      printf ("1999, G. Castrataro\n\n");
      printf ("Derived from iDirt (1.82)\n");
      printf ("(C) 1994-1997, Illusion\n\n");
      exit (0);
      break;
    case 'u':
      update = 1;
    case 'r':
      if (*s != '\0' || (--argc > 0 && *(s = *++argv) != '\0'))
	old_proc_num = atoi (s);
      break;
    case 'n':
      if (*s != '\0' || (--argc > 0 && *(s = *++argv) != '\0')) {
	if ((max_players = atoi (s)) < 1 || max_players > 1000) {
	  max_players = 32;
	}
      }
      break;
    case 'd':
      if (*s != '\0' || (--argc > 0 && *(s = *++argv) != '\0')) {
	data_dir = s;
      }
      break;
    default:
      usage ();
      exit (6);
    }
  }
  if (argc > 0) {
    usage ();
    exit (7);
  }
}

static void usage (void)
{
  fprintf (stderr, "usage: %s [-p port] [-d path] [-n #] [-f] [-k] [-c] [-v] [-V] [-o] [-H]\n", progname);
  fprintf (stderr, "(%s -H for detailed help)\n", progname);
}

static void fullusage (void)
{
  fprintf (stderr, "usage: %s [-p port] [-d path] [-n #] [-f] [-k] [-c] [-v] [-V] [-o] [-H]\n", progname);
  fprintf (stderr, "  -p port     : Alternate port to attach C-Dirt to.\n");
  fprintf (stderr, "  -d path     : Path to data files.\n");
  fprintf (stderr, "  -n #        : Maximum number of players (Default is 32).\n");
  fprintf (stderr, "  -f          : Run C-Dirt in the foreground.\n");
  fprintf (stderr, "  -k          : Automatically kill any other C-Dirt Daemons that are running.\n");
  fprintf (stderr, "  -c          : Automatically clear system log.\n");
  fprintf (stderr, "  -v          : Run in verbose startup mode.\n");
  fprintf (stderr, "  -V          : Display version information.\n");
  fprintf (stderr, "  -o          : Automatically open MUD.\n\n");
}

Boolean is_identing(int fd) {
  int i;
 
  for (i = 0 ; i < max_players ; i++)
   if (resfd(i) == fd)
     return(True);
  return(False);
}

void set_fd(int fd, Boolean output) {
  if (fd == -1)
    return;
  if (output)
    FD_SET(fd, &output_set);
  if (fd >= width)
    width = fd + 1;
  FD_SET(fd, &input_set);
}

extern void dnsboot(void);

static void main_loop (int listen_socket) {
  int i, fd, plx, fds;
  struct timeval timeout, slice;

  time (&global_clock);
  time (&last_autosave);
  time (&last_healall);
  breset = False;

  if (!old_proc_num)
    mudlog ("&+WSYSTEM:&N C-Dirt %s Booted (PID: %d)", VERSION, getpid());
  else
    mudlog ("&+WSYSTEM:&N %s Successful, C-Dirt Daemon Restarted",
	    update ? "Update" : "Reboot");

  if (clear_syslog_file)
    mudlog ("&+WSYSTEM:&N System Log Cleared");

  if (!update) {
    last_reset = global_clock;
    setqdflags (0);

    for (i = 0; i < numzon; i++) {
      move_pouncie ();
      reset_zone (i, NULL, NULL, NULL, NULL);
    }
    scatter_potions();
  }

  setup_globals(-1);
  timeout.tv_sec = 2;
  timeout.tv_usec = 0;

#ifdef ABERCHAT
  if (mud_port == PORT)                          /* do not run on test mud */
    aberchat_boot();
#endif

  dnsboot();

  while (1) {
    FD_ZERO(&input_set);                           /* zero out all fd_sets */
    FD_ZERO(&output_set);
    FD_ZERO(&exception_set);
     
    set_fd(listen_socket, False);
    set_fd(aberfd, aber_output);
    set_fd(dnsfd, dns_output);

    for (plx = 0 ; plx < max_players ; plx++)      /* add player fds */
      if (is_conn(plx) && !linkdead(plx)) {
        if (resolved(plx) && ident(plx) && limbo(plx))
          enter_game(plx);
        set_fd(fildes(plx), output(plx));
        if (!ident(plx))
          set_fd(players[plx].resfd, players[plx].respos != -1);
      }

    if (crashing)
      flush_mud(False);

    fds = select(width, &input_set, &output_set, &exception_set, &timeout);
    if (fds == -1) {
      if (errno == EINTR)
        continue;   
      else if (errno == EBADF) {
	progerror ("select");
        rm_pid();
	exit(8);
      }
    } 

    gettimeofday(&slice, (struct timezone *) NULL);
    timeout.tv_usec = 1000000 - slice.tv_usec;
    timeout.tv_sec = (slice.tv_sec + 1) % 2;

    if (!fds) {
      on_timer();
      continue;
    }
      
    for (fd = 0 ; fds > 0; fd++) {
      if (FD_ISSET (fd, &exception_set)) {
	mudlog ("SOCKET: Exception pending with fd = %d", fd);
	fds--;
      }
      if (FD_ISSET (fd, &input_set)) {
        if (fd == listen_socket)
          new_connection(fd);
        else if (fd == aberfd)
          aberchat_readpacket(fd);
        else if (fd == dnsfd)
          read_dns(fd);
        else if (is_identing(fd))
          read_ident(fd);
        else
          read_packet(fd);
        fds--;
      }
      if (FD_ISSET (fd, &output_set)) {
        if (fd == aberfd) 
          aberchat_writepacket(fd); 
        else if (fd == dnsfd)
          send_dns(fd);
        else if (is_identing(fd))
          send_ident(fd);
        else
	  write_packet(fd);
	fds--;
      }
    }
  }
}

void write_packet(int fd) {
  int len, n_wrote, me;
  
  me = find_pl_index(fd);          

  if (me < 0) return;
  len = out_write(me) - out_read(me);

  if (len > M_BUFFLEN)
    len = M_BUFFLEN;

  n_wrote = write(fd, out_read(me), len);

#ifdef IO_STATS
  bytes_sent += n_wrote;
#endif

  if (*(out_read(me) + n_wrote))          /* more bytes to send */
    out_read(me) += n_wrote;
  else {
    if (out_size(me) > M_BUFFLEN) {       /* shrink buffer */
      FREE(out_buffer(me));
      out_size(me) = M_BUFFLEN;
      out_buffer(me) = NEW(char, M_BUFFLEN);
    }
    out_write(me) = out_buffer(me);
    out_read(me) = out_buffer(me);
    output(me) = False;

    if (hasquit(me)) {
      setup_globals(me);
      sock_msg("&+C%H &+Wclosed");
      close_sock(fd);
    }
  }
}

void close_sock(int fd) {
  int i, new_width;

  setup_globals(find_pl_index(fd));

  shutdown(fd, 2);
  if (cur_player->iamon)
    remove_from_game();

  free_player();
  cur_player->iamon = False;
  cur_player->is_conn = False;
  sock_fds[fd] = -1;

  for (i = 0, new_width = 0 ; i < width ; i++)
    if (sock_fds[i] != -1)
      new_width = i;

  width = new_width; 
  close(fd);
}

char *test_multi_connects (struct in_addr *in) {
  static char inet_str[16];
  int host_connects;
  int i;

  strcpy(inet_str, inet_ntoa(*in));
  host_connects = 0;

  for (i = 0, host_connects = 0 ; i < max_players ; i++)
    if (is_conn(i) && *(ip_addr(i)) &&
	!strcmp(strchr(ip_addr(i), '.'), strchr(inet_str, '.')))
      host_connects++;
	
  if (host_connects > MAX_CONNECTS || !strcmp(inet_str, "0.0.0.0"))
    return NULL;
  else
    return inet_str;
}

void closemsg(int fd, char *msg) {
  write(fd, msg, strlen(msg));
  shutdown(fd, 2);
  close(fd);
}

static void new_connection (int listen_socket) {
  int plx;
  int fd;
  int sin_len;
  struct sockaddr_in sin;
  char *ip_addr;

  bzero ((char *) &sin, sizeof (struct sockaddr_in));
  sin_len = sizeof (struct sockaddr_in);

  if ((fd = accept (listen_socket, (struct sockaddr *) &sin, &sin_len)) < 0)
    return;
  if (fcntl (fd, F_SETFL, FNDELAY) == -1)
    return;
  if ((ip_addr = test_multi_connects(&sin.sin_addr)) == NULL) {
    closemsg(fd, "Too many connects from your domain.\n");
    return;
  }
  if ((plx = find_free_player_slot ()) < 0) {
    sock_msg("Connection refused (MUD full): %s", ip_addr);
    closemsg(fd, "\nSorry, but this mud is full, please come back later.\n");
    return;
  }
  setup_io (plx, fd);
  setup_globals (plx);

#ifdef IO_STATS
  sock_conns++;
#endif

  strcpy(ip_addr(plx), ip_addr);
  strcpy(hostname(plx), ip_addr);
  strcpy(username(plx), ip_addr);
  port(plx) = (int) ntohs(sin.sin_port);

  setpname (mynum, "<Logging In>");
  dns_output = True;
  ident_player();
  setup_globals(-1);
}

void setup_io(int plx, int fd) {
  sock_fds[fd] = plx;
  rplrs[plx].fil_des = fd;
  players[plx].resfd = -1;
  out_buffer(plx) = NEW (char, M_BUFFLEN);
  out_size(plx) = M_BUFFLEN;
  out_read(plx) = out_buffer(plx);
  out_write(plx) = out_buffer(plx);
  inp_ptr(plx) = inp_buffer(plx);
  *inp_buffer(plx) = *out_buffer(plx) = 0;
  ignore_input(plx) = False;
  is_conn(plx) = True;
  limbo(plx) = True;
}

void read_packet (int fd) {
  char *ptr, *buffptr, *buff_start;
  int num_read, me;

  me = find_pl_index(fd);                       /* real player giving input */
  if (me < 0) return;

  setup_globals(me);

  buff_start = inp_buffer(me);
  buffptr = inp_ptr(me);

  if ((num_read = read (fd, buffptr, CUTOFF_LEN - (buffptr - buff_start))) < 1)
    {
      if (!num_read)                      /* 0-byte packets = connection cut */
	quit_player(-1);
      else
	quit_player(errno);
      return;
    }

#ifdef IO_STATS
  bytes_read += num_read;
#endif  

  *(buffptr + num_read) = 0;

  if (!isascii(*buffptr)) {
/*  if (!isprint(*buffptr) && !isspace(*buffer)) {         telnetresponse */
    inp_ptr(me) = inp_buffer(me);
    return;
  }

  /* lines below are for the end of a spam of text */
  
  else if (num_read + (buffptr - buff_start) < CUTOFF_LEN) {
    if (ignore_input(me) && strchr(buffptr, '\n')) {
      inp_ptr(me) = inp_buffer(me);
      ignore_input(me) = False;
      return;
    }
  }

  else {                                                   /* packet too big */
    ptr = buff_start + CUTOFF_LEN;
    if (!ignore_input(me)) {                        /* first oversize packet */
      *ptr = 0;
      bprintf ("&+B(&*Maximum Input Exceeded&+B)\n"
               "&+B(&*Input Cut Off After: &+W%s&+B)\n", ptr - 16);
      strcat(buff_start, "\r\n"); 
      ignore_input(me) = True;
    }
    else {
      inp_ptr(me) = inp_buffer(me);               /* don't add to buff */
      return;
    }
  }

  if (!strchr(buff_start, '\n') && !strchr(buff_start, '\r'))
    inp_ptr(me) += num_read;
  else  if (limbo(me))                     /* player is resolvin, susp */
    inp_ptr(me) += num_read;
  else if ((!inp_handler(me) || !phandler(me))) {
    bprintf("\tInternal Error Has Occurred: Lost Your Input Handler");
    quit_player(-3);
  }
  else
    do_packet(me, buff_start);
  setup_globals(-1);
}

/* this function deals with a complete & valid packet which may
   have multiple lines of text separated by \n, \r, \r\n or \n\r */

void do_packet(int me, char *packet) {
  static char buff[MAX_COM_LEN];
  static char *bptr, *tptr;                 /* buff ptr, text ptr */
  static int plx;

  if (snooped(me)) {
    for (plx = 0 ; plx < max_players ; plx++)
      if (snooptarget(plx) == me) {
	setup_globals(plx);
	bprintf("\n&+r[&+WSnoop: %s&+r]&N %s", pname(me), packet);
      }
    setup_globals(me);
  }

  if (islogged(me))
    write_plr_log(packet);

  /* copy command to buffer, exec command, repeat */

  for (tptr = packet, bptr = buff ; *tptr ; tptr++) {
    if (!iscntrl(*tptr))
      *bptr++ = *tptr;
    else if (*tptr == '\n' || *tptr == '\r' ) {
      if (*(tptr + 1) == '\n' || *(tptr + 1) == '\r')
        tptr++;
      *bptr = 0;
      exec_cmd(me, buff);
      bptr = buff;
    } 
    else if (*tptr == '\b' && bptr > buff)
      bptr--;
  }
  inp_ptr(me) = inp_buffer(me);
}

/* actually execute the mud command */

void exec_cmd(int me, char *text) {

#ifdef LOG_INPUT
  if (plogptr) {
    fprintf(plogptr, "(%s) %s:%s\n", 
      time2ascii(global_clock) + 11, pname(mynum), text);
    fflush(plogptr);
  }
#endif

  if (!inp_handler(me))
    return;
  
  if (!ptstflg (me, PFL_IDLE))
    plast_cmd (me) = global_clock;
  prlast_cmd (me) = global_clock;
  
  in_cmd(me) = True;

  (phandler(me))(text);

  if (me != real_mynum)
    setup_globals(me);

  in_cmd(me) = False;

  if (!hasquit(me))
    bprintf("%s", cur_player->cprompt);
}

void sig_handler (int sig) {
  char msg[30];

  switch (sig) {
  case SIGTERM:
    mudlog ("SIGNAL: SIGTERM");
    sigterm_exit();
    flush_mud(True);
    return;
  case SIGSEGV:
    mudlog ("SIGNAL: SIGSEGV[%d]", sig);
    sprintf (msg, "SIGSEGV[%d]", sig);
    break;
  case SIGBUS:
    mudlog ("SIGNAL: SIGBUS[%d]", sig);
    sprintf (msg, "SIGBUS[%d]", sig);
    break;
  case SIGINT:
    mudlog ("SIGNAL: SIGINT[%d]", sig);
    sigterm_exit();
    flush_mud(True);
    return;
  case SIGUSR1:
    mudlog ("SIGNAL: SIGUSR1[%d]", sig);
    sprintf (msg, "SIGUSR1[%d]", sig);
    break;
  case SIGUSR2:
    mudlog ("SIGNAL: SIGUSR2[%d]", sig);
    sprintf (msg, "SIGUSR2[%d]", sig);
    break;
  default:
    mudlog ("SIGNAL: %d", sig);
    sprintf (msg, "Unknown - %d", sig);
    break;
  }
  rm_pid();
  sig_exit (msg, sig);
}

/* stuff that's not worth keeping over an update */

void initialize_slot (int plx) {
  ublock[plx].angry = -1;
  ublock[plx].pfighting = -1;
  ublock[plx].phelping = -1;
  players[plx].wd_them = rplrs[plx].wd_him;
  players[plx].iamon = True;
}

#define WIZ_BUFF_LEN 300
static int xmain_reboot (void)
{
  int i, s, nplayers, plx;
  char newname[256], zonename[30];
  REBOOT_REC r_rec;
  RPLR_REC p_rec;
  FILE *fp, *zfp;

  /* Allow mud to catch signals again */
  signal (SIGTSTP, SIG_DFL);
  signal (SIGCONT, SIG_DFL);
  signal (SIGTTOU, SIG_DFL);
  signal (SIGTTIN, SIG_DFL);
  signal (SIGPIPE, SIG_IGN);            /* Broken pipe */
  signal (SIGTERM, sig_handler);        /* CTRL-C or kill -2 */
  signal (SIGSEGV, sig_handler);	/* Segmentation fault */
  signal (SIGBUS, sig_handler);	        /* Bus error */
  signal (SIGSYS, sig_handler);	        /* Bad argument to system call */
  signal (SIGUSR1, sig_handler);	/* User defined signal */
  signal (SIGUSR2, sig_handler);	/* User defined signal */

  if (open_logfile (clear_syslog_file) < 0)
    return -1;

  save_pid();

  sprintf (newname, "%s/reboot_file.%d", TEMP_DIR, old_proc_num);
  if ((fp = FOPEN(newname, "rb")) == NULL) {
    mudlog ("REBOOT: Datafile %s could not be opened for reading", newname);
    return -1;
  }
  fread (&r_rec, sizeof (r_rec), 1, fp);

  if (!EQ (r_rec.version, VERSION))
    mudlog ("UPGRADE: Old Ver: %s; New Ver: %s", r_rec.version, VERSION);

  s = r_rec.main_socket;
  last_startup = r_rec.last_startup;
  numresets = r_rec.numresets;
  numreboots = r_rec.numreboots;
  numcrashes = r_rec.numcrashes;
  last_reset = r_rec.last_reset;
  nplayers = r_rec.nplayers;
  the_world->q_done = r_rec.q_done;

#ifdef IO_STATS
  bytes_read = r_rec.bytes_read;
  bytes_sent = r_rec.bytes_sent;
  unres_hosts = r_rec.unres_hosts;
  sock_conns = r_rec.sock_conns;
  cut_conns = r_rec.cut_conns;
#endif
  

  if (bootstrap () < 0) {	/* Initialize data structures */
    mudlog ("REBOOT: Bootstrap failed on reboot");
    return -1;
  }
  main_socket = s;

  sprintf (newname, "%s/update.zones.%d", TEMP_DIR, old_proc_num);
  if ((zfp = FOPEN(newname, "r")) != NULL) {
    while (!feof(zfp)) {
      fscanf(zfp, "%s\n", zonename);
      load_zone(zonename, NULL, NULL, NULL, NULL, NULL, NULL);
    }
    FCLOSE(zfp);
  }
  for (i = 0; i < nplayers; i++) {
    fread (&p_rec, sizeof (p_rec), 1, fp);
    plx = p_rec.plx;
    memcpy(&rplrs[plx], &p_rec, sizeof(RPLR_REC));
    memset(&players[plx], 0, sizeof(PLAYER_REC));
    memset(&ublock[plx], 0, sizeof(UBLOCK_REC));

    setup_io(plx, fildes(plx));
    setup_globals(plx);
    getuafinfo(p_rec.pname);
    initialize_slot(plx);
    setploc(plx, p_rec.ploc);
    setpvis(plx, p_rec.pvis);
    setpwpn(plx, p_rec.pweapon);
    push_input_handler (get_command);
    get_command (NULL);
  }

  FCLOSE(fp);
  unlink (newname);

  if (update) {
    for (i = 0; i < numzon; i++)
      reset_zone (i, NULL, NULL, NULL, NULL);

    update_world (old_proc_num);

    send_msg (DEST_ALL, 0, LVL_MIN, LVL_WIZARD, NOBODY, NOBODY,
	      "You open your eyes and see " MUD_NAME " beginning "
	      "to fade back\ninto reality. Suddenly, the world rearranges "
	      "itself back to the way it was.\n");

    send_msg (DEST_ALL, 0, LVL_WIZARD, LVL_MAX, NOBODY, NOBODY,
	      "&+W[&+CUpdate Completed&+W]\n");
  } 
  else {
    send_msg (DEST_ALL, 0, LVL_MIN, LVL_WIZARD, NOBODY, NOBODY,
	      "You open your eyes and see " MUD_NAME " beginning "
	      "to fade back\ninto reality. It all seems the same, yet "
	      "somehow different.\n");

    send_msg (DEST_ALL, 0, LVL_WIZARD, LVL_MAX, NOBODY, NOBODY,
	      "&+W[&+CReboot Completed&+W]\n");
  }
  
  main_loop (s);

  mudlog ("REBOOT: Closing listening socket");
  close (s);
  return 0;
}

void rebootcom (void)
{
  if (!ptstflg (mynum, PFL_REBOOT)) {
    bprintf ("You cannot reboot the MUD.\n");
    return;
  } 
  run_reboot (False, False);
}

void updatecom (void)
{
  if (!ptstflg (mynum, PFL_REBOOT)) {
    bprintf ("You cannot update the MUD.\n");
    return;
  }
  run_reboot (False, True);
}

void run_reboot (Boolean crash, Boolean will_update)
{
  int i, plx, new, nplayers;
  char newpath[256], oldpath[256], datafile[256], bindir[256], port[10];
  char max[10], pid[10], *prog;
  REBOOT_REC reboot_rec;
  RPLR_REC rplr_rec;
  FILE *fp;

  if ((prog = strrchr(progname, '/')))   prog++;
  else prog = progname; 

  sprintf(newpath, "%s/bin/%s.new", BASE_LOC, prog);
  sprintf(oldpath, "%s/bin/%s", BASE_LOC, prog);
  sprintf(bindir, "%s/bin", BASE_LOC);

  if (access(newpath, F_OK) != -1)
    new = 1;
  else if (access(oldpath, F_OK) != -1)
    new = 0;
  else {
    bprintf("Error: could not boot mud from requested executable:\n\n");
    mudlog ("REBOOT: Error: Could not find executable");
    return;
  }

  if (crash)
    new = 0;

  for (i = 0 ; i < max_players ; i++)
    if (players[i].iamon)
      wipe_duration(i);

  autosave();

  if (aberfd != -1)
    aberchat_shutdown();

  if (dnsfd != -1)
    close(dnsfd);

  if (crash) {
    send_msg (DEST_ALL, 0, LVL_WIZARD, LVL_MAX, NOBODY, NOBODY,
	      "&+W[&+CEmergency %s To Prevent Crash&+W]\n",
	      will_update ? "Update" : "Reboot");
    send_msg (DEST_ALL, 0, LVL_MIN, LVL_WIZARD, NOBODY, NOBODY, 
              "\001f%s\003", CRASH_UPDATE);
    mudlog ("&+RREBOOT:&N Crash has occured, rebooting system");
  } 
  else if (will_update) {
    send_msg (DEST_ALL, 0, LVL_WIZARD, LVL_MAX, NOBODY, NOBODY,
	      "&+W[&+wUpdate %sby &+C\001p%s\003&+W]\n",
	      new ? "&+WNew &+w" : "", pname (mynum));
    send_msg (DEST_ALL, 0, LVL_MIN, LVL_WIZARD, NOBODY, NOBODY,
	      "\001f%s\003", UPDATE);
    mudlog ("&+WUPDATE:&N Update %sby %s", new ? "New " : "", pname (mynum));
  } 
  else if (breset) {
    send_msg (DEST_ALL, 0, LVL_MIN, LVL_WIZARD, NOBODY, NOBODY,
	      MUD_NAME "\001f%s\003", UPDATE);
    mudlog ("&+WREBOOT:&N Rebooted %sby BootReset", new ? "New " : "");
  } 
  else {
    send_msg (DEST_ALL, 0, LVL_WIZARD, LVL_MAX, NOBODY, NOBODY,
	      "&+W[&+wReboot %sby &+C\001p%s\003&+W]\n",
	      new ? "&+WNew &+w" : "", pname (mynum));
    send_msg (DEST_ALL, 0, LVL_MIN, LVL_WIZARD, NOBODY, NOBODY,
	      "\001f%s\003", UPDATE);
    mudlog ("&+WREBOOT:&N Rebooted %sby %s", new ? "New " : "", pname (mynum));
  }

  if (crash)
    ++numcrashes;
  else
    ++numreboots;

  if (!will_update)
    the_world->q_done = 0;

  sprintf (datafile, "%s/reboot_file.%d", TEMP_DIR, getpid());

  for (i = 0, nplayers = 0; i < max_players; ++i)
    if (players[i].iamon)
      nplayers++;

  strcpy (reboot_rec.version, VERSION);
  reboot_rec.main_socket = main_socket;
  reboot_rec.last_startup = last_startup;
  reboot_rec.numresets = numresets;
  reboot_rec.numreboots = numreboots;
  reboot_rec.numcrashes = numcrashes;
  reboot_rec.last_reset = last_reset;
  reboot_rec.nplayers = nplayers;
  reboot_rec.q_done = the_world->q_done;    

#ifdef IO_STATS
  reboot_rec.bytes_read = bytes_read;
  reboot_rec.bytes_sent = bytes_sent;
  reboot_rec.unres_hosts = unres_hosts;
  reboot_rec.sock_conns = sock_conns;
  reboot_rec.cut_conns = cut_conns;
#endif

  if ((fp = FOPEN(datafile, "wb")) == NULL)
    mudlog ("REBOOT: Error writing reboot datafile");

  fwrite (&reboot_rec, sizeof (reboot_rec), 1, fp);

  for (plx = 0; plx < max_players; ++plx) {
    if (!is_conn(plx))
      continue;

    setup_globals (plx);

    if (!cur_player->iamon) {
      bprintf ("%s is currently rebooting.\n", MUD_NAME);
      quit_player(-4);
    } 
    else {
      write_packet(fildes(plx));
      memcpy(&rplr_rec, &rplrs[plx], sizeof(RPLR_REC));
      strcpy (rplr_rec.pname, pname(plx));
      rplr_rec.plx = plx;
      rplr_rec.ploc = ploc (plx);
      rplr_rec.pvis = pvis (plx);
      rplr_rec.pweapon = pwpn(plx);
      fwrite (&rplr_rec, sizeof (rplr_rec), 1, fp);
    }
  }
  FCLOSE(fp);

  if (will_update)
    run_update ();

  close_mudfiles();

  if (new) {
    unlink (oldpath);
    rename(newpath, oldpath);
  }

  sprintf (port, "%d", mud_port);
  sprintf (max, "%d", max_players);
  sprintf (pid, "%d", getpid());
  chdir(bindir);
  execl(prog, prog, "-p", port, "-n", max, will_update ? "-u" : "-r", pid,NULL);
}

/* Flush all io before a crash */

#define FLUSH_TIMEOUT 5

void flush_mud(Boolean init) {
  int plx;
  static int t_elapsed;

  if (init) {
    t_elapsed = global_clock;
    crashing = True;
  }

  if (global_clock - t_elapsed < FLUSH_TIMEOUT)
    for (plx = 0 ; plx < max_players ; plx++)
      if (output(plx))
        return;
  exit(0);
}