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