/**************************************************************** * 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); }