/****************************************************************
* iDiRT 1.x *
* 1994-1996 by Illusion *
****************************************************************/
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include "kernel.h"
#include <errno.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include "jmp.h"
#ifdef VARGS
#include <stdarg.h>
#endif
#include "mud.h"
#include "log.h"
#include "bootstrap.h"
#include "sendsys.h"
#include "mobile.h"
#include "commands.h"
#include "timing.h"
#include "exit.h"
#include "s_socket.h"
#include "locations.h"
#include "pflags.h"
#include "update.h"
#include "climate.h"
#include "reboot.h"
#include "objsys.h"
#include "bprintf.h"
#include "zones.h"
#include "uaf.h"
#include "fight.h"
#include "rooms.h"
#include "ver.h"
#include "main.h"
#if USE_IDENT
#include "ident.h"
#endif
static int xmain (int fd);
static int xmain_reboot (int fd);
static int go_background (int pid_fd);
static int check_pid (void);
static void get_options (int argc, char **argv);
static void usage (void);
static void fullusage (void);
static void rm_pid_file (void);
static void end_connection (void);
static void new_connection (int fd);
static void handle_packet (int fd);
static void sig_handler (int sig);
static void main_loop (int m_socket);
#define MAX_PLAYERS 50
#define F_OK 0
#define EXEC_LOC "../bin"
/* Some local variables */
fd_set sockets_fds;
fd_set buffer_fds;
int mud_port = PORT;
int main_socket;
int width;
int fildes[2];
char pidfile[50];
Boolean kill_other_mud = False;
Boolean clear_syslog_file = False;
Boolean stay_foreground = False;
Boolean sig_term_happened = False;
Boolean sig_timer_happened = False;
Boolean auto_open = False;
int old_proc_num = 0;
int update = 0;
static int inp_buf_c = 0;
static struct timeval zerotime =
{0, 0};
int
main (int argc, char **argv, char **ep)
{
int fd, x;
envp = ep;
progname = argv[0];
get_options (argc, argv); /* Parse command line */
printf ("\n%s #%d Daemon Loading...\n", VERSION, linknumber ());
if (data_dir == NULL) {
printf (" iDiRT Daemon Error: data_dir is a NULL value.\n");
printf (" Halting Daemon!\n");
exit (1);
}
printf (" Data Directory: %s\n", data_dir);
printf (" Maximum Players: %d\n", max_players);
printf (" Port Selected: %d\n", mud_port);
printf (" Clear System Log: %s\n", clear_syslog_file ? "Yes" : "No");
sprintf (pidfile, "%spid", data_dir);
if (!access (pidfile, 0))
printf (" Kill Other MUD: %s\n", kill_other_mud ? "Yes" : "Ask User");
chdir (data_dir);
/* Check if the PID_FILE exists, and what it contains if it does */
fd = check_pid ();
/* Check to see if the MUD should be opened automatically */
if (auto_open) {
printf (" Automatically opening MUD\n");
sprintf (pidfile, "%snologin", data_dir);
remove (pidfile);
}
/* We arrive here only if we are to continue and now we are alone. */
/* Also, the PID_FILE is opened */
if (!old_proc_num)
x = xmain (fd);
else
x = xmain_reboot (fd);
unlink (PID_FILE);
if (x < 0) {
mudlog ("BOOTUP: Abnormal termination of mud");
exit (1);
}
mudlog ("BOOTUP: Normal termination of mud");
exit(0);
}
static void
connect_ok (char *h, int port)
{
char b[80];
sprintf (b, " Connected to port %d on %s.\n", port, h);
if (stay_foreground) {
printf ("%s", b);
} else {
write (fildes[1], b, sizeof (b));
close (fildes[1]);
}
}
static int
xmain (int fd)
{
int s, k;
/* We arrive here only if we are to continue and now we are alone. */
/* Also, the PID_FILE is opened */
if (open_logfile (LOG_FILE, clear_syslog_file) < 0) {
close (fd);
return -1;
}
if (bootstrap () < 0) { /* Initialize data structures */
printf ("\n\nBootstrap Has Failed, Please Read %s%s.\n",
data_dir, LOG_FILE);
close (fd);
return -1;
}
/* Now we go background */
if (go_background (fd) < 0) {
return -1;
}
k = 10;
while ((main_socket = make_service (mud_port, my_hostname,
sizeof (my_hostname),
&my_hostent, &s_in)) == -4
&& errno == EADDRINUSE && --k >= 0) {
sleep (2);
}
s = main_socket;
if (s < 0) {
mudlog ("BOOTUP: Error code %d from make_service", s);
progerror ("make_service");
return -1;
}
if (s > 0) { /* We want the main socket at fd 0 */
dup2 (s, 0);
close (s);
s = main_socket = 0;
}
width = 1;
connect_ok (my_hostname, mud_port);
FD_ZERO (&sockets_fds);
FD_ZERO (&buffer_fds);
FD_SET (s, &sockets_fds);
/* Initialize Variables */
numresets = 0;
numreboots = 0;
numcrashes = 0;
/* Initialize MUD Daemon Startup Time */
time (&last_startup);
/* Initialize MUD Time System */
_set_time (1, 1, 0, 0);
the_climate->daytime = False;
/* Main program loop */
main_loop (s);
mudlog ("SYSTEM: Closing listening socket");
close (s);
return 0;
}
/* BSD style daemonizing */
static int
go_background (int fd)
{
char b[80];
int tty;
/* Go background */
signal (SIGHUP, SIG_IGN);
signal (SIGINT, SIG_IGN);
signal (SIGQUIT, SIG_IGN);
signal (SIGTSTP, SIG_DFL);
signal (SIGTTOU, SIG_DFL);
signal (SIGTTIN, SIG_DFL);
if (!stay_foreground) {
if (pipe (fildes) < 0) {
progerror ("go_background/pipe");
exit (1);
}
switch (pid = fork ()) {
case -1:
progerror ("fork");
close (fd);
return -1;
case 0:
break;
default:
printf (" PID: %d\n", pid);
close (fd);
close (fildes[1]);
fflush (stdout); /* Flush stdout */
read (fildes[0], b, sizeof (b));
printf ("%s", b);
exit (0); /* Let our parent process die */
}
fclose (stdin);
fclose (stdout);
close (fildes[0]);
}
pid = getpid (); /* Get our process id */
sprintf (b, "%d\n", pid);
write (fd, b, strlen (b));
close (fd);
if (!stay_foreground) {
if ((tty = open ("/dev/tty", O_RDWR, S_IRUSR | S_IWUSR)) >= 0) {
if (ioctl (tty, TIOCNOTTY, 0) < 0) {
progerror ("ioctl,TIOCNOTTY");
return -1;
}
close (tty);
#ifdef _LINUX_ /* Linux made it alot simpler */
setpgrp (); /* Make our own process group */
#else
setpgrp (pid, pid); /* Make our own process group */
#endif
} else if (errno != ENXIO) {
progerror ("open,tty");
return -1;
}
signal (SIGHUP, SIG_IGN);
signal (SIGINT, SIG_IGN);
signal (SIGQUIT, SIG_IGN);
} else {
signal (SIGHUP, SIG_DFL);
signal (SIGINT, sig_handler);
signal (SIGQUIT, SIG_DFL);
}
signal (SIGTERM, sig_handler);
signal (SIGTSTP, SIG_DFL);
signal (SIGCONT, SIG_DFL);
signal (SIGTTOU, SIG_DFL);
signal (SIGTTIN, SIG_DFL);
signal (SIGSEGV, sig_handler);/* Segmentation fault */
signal (SIGBUS, sig_handler); /* Bus error */
signal (SIGSYS, sig_handler); /* Bad argument to system call */
signal (SIGPIPE, SIG_IGN); /* Broken pipe */
signal (SIGUSR1, sig_handler);/* User defined signal */
signal (SIGUSR2, sig_handler);/* User defined signal */
return 0;
}
static int
check_pid (void)
{
int fd;
int pid = -1;
int c;
FILE *f;
char b[80];
if ((fd = open (PID_FILE, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0) {
/* The file exist already */
if (errno == EEXIST) {
if ((f = fopen (PID_FILE, "r")) != NULL) {
fgets (b, sizeof b, f);
pid = atoi (b);
fclose (f);
} else {
perror ("fopen," PID_FILE);
exit (1);
}
if (pid > 0) {
if (!kill_other_mud) {
printf (" iDiRT is still running (or the PID file still exists), kill it? ");
while ((c = getchar ()) != 'N' && c != 'n' && c != 'Y' &&
c != 'y' && c != '\n' && c != '\r') ;
if (c == 'Y' || c == 'y')
kill_other_mud = True;
}
if (!kill_other_mud) {
printf (" Aborting loading of this MUD.\n");
exit (0);
}
printf (" Killing other MUD, loading this one (Old PID: %d)\n", pid);
if (kill (pid, SIGTERM) < 0) {
if (errno != ESRCH) {
perror ("kill");
exit (1);
} else if (unlink (PID_FILE) < 0) { /* PID_FILE without process */
perror ("unlink");
exit (1);
}
}
} else {
if (unlink (PID_FILE) < 0) { /* PID_FILE without process */
perror ("unlink");
exit (1);
}
}
c = 6;
while (True) {
sleep (1);
if ((fd = open (PID_FILE, O_WRONLY | O_CREAT | O_EXCL,
S_IRUSR | S_IWUSR)) >= 0)
break;
if (--c < 0) {
printf (" Inactivity Timeout. Not loading MUD.\n");
exit (0);
}
}
} else {
perror ("open " PID_FILE);
exit (1);
}
}
return fd;
}
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;
kill_other_mud = False;
mud_port = PORT;
max_players = 32;
return;
}
while (--argc > 0) {
s = *++argv;
if (*s++ != '-') {
usage ();
exit (1);
}
x = *s++;
switch (x) {
case 'a':
break;
case 'h':
usage ();
break;
case 'H':
fullusage ();
break;
case 'p':
if (*s != '\0' || (--argc > 0 && *(s = *++argv) != '\0')) {
if ((mud_port = atoi (s)) < 1000 || mud_port > 65535) {
mud_port = PORT;
}
}
break;
case 'f':
stay_foreground = True;
break;
case 'k':
kill_other_mud = True;
break;
case 'c':
clear_syslog_file = True;
break;
case 'o':
auto_open = True;
break;
case 'v':
printf ("%s #%d (%s)\n", VERSION, linknumber (), _HEADER_);
exit (0);
break;
case 'V':
printf ("\niDiRT Version Information\n");
printf ("-------------------------\n");
printf ("%s #%d (%s)\n", VERSION, linknumber (), _HEADER_);
printf ("1994-1996 by Illusion\n\n");
printf ("Derived from AberMUD DIRT (3.1.2)\n");
printf ("1990, 1993 by Alf and Nicknack\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 (1);
}
}
if (argc > 0) {
usage ();
exit (1);
}
}
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);
exit (1);
}
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 iDiRT 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 iDiRT in the foreground.\n");
fprintf (stderr, " -k : Automatically kill any other iDiRT Daemons that are running.\n");
fprintf (stderr, " -c : Automatically clear system log.\n");
fprintf (stderr, " -v : Display version.\n");
fprintf (stderr, " -V : Display version information.\n");
fprintf (stderr, " -o : Automatically open MUD.\n\n");
exit (1);
}
static void new_connection (int fd);
static void
main_loop (int m_socket)
{
int w;
int v, i;
int fd;
int plx = 0;
struct timeval *tv;
fd_set r_fds, e_fds;
time (&global_clock);
time (&last_autosave);
time (&last_healall);
breset = False;
norun = False;
if (!old_proc_num)
mudlog ("SYSTEM: iDiRT %s Daemon Started (PID: %d)", _VERSION_, getpid ());
else
mudlog ("SYSTEM: %s Successful, iDiRT Daemon Restarted",
update ? "Update" : "Reboot");
if (clear_syslog_file)
mudlog ("SYSTEM: System Log Cleared");
/* Reset everything */
if (!update) {
last_reset = global_clock;
setqdflags (0);
for (i = 0; i < numzon; i++) {
move_pouncie ();
reset_zone (i, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
}
cur_player = NULL;
quit_list = -1;
signal (SIGALRM, sig_handler);
set_timer ();
while (!sig_term_happened) {
switch (v = setjmp (to_main_loop)) {
case JMP_QUITTING:
bflush ();
end_connection ();
setup_globals (-1);
++fd;
break;
}
if (sig_timer_happened) {
sig_timer_happened = False;
signal (SIGALRM, sig_handler);
setup_globals (-1); /* bflush() and disable mynum */
set_timer ();
on_timer ();
} else {
while (quit_list >= 0)
end_connection ();
r_fds = e_fds = sockets_fds;
if (inp_buf_c > 0)
tv = &zerotime;
else
tv = NULL;
#ifdef SYS_HP_UX
if ((v = select (width, (int *) &r_fds, NULL, (int *) &e_fds, tv)) < 0) {
#else
if ((v = select (width, &r_fds, NULL, &e_fds, tv)) < 0) {
#endif
if (errno == EINTR)
continue;
progerror ("select");
exit (1);
}
for (fd = 0, w = width; fd < w; fd++) {
if (FD_ISSET (fd, &e_fds)) {
#ifdef LOG_FDPEND
mudlog ("SOCKET: Exception pending with fd = %d", fd);
#endif
--v;
}
if (FD_ISSET (fd, &r_fds) || FD_ISSET (fd, &buffer_fds)) {
--v;
if (fd == m_socket) {
new_connection (fd);
} else {
handle_packet (fd);
}
bflush ();
}
while (quit_list >= 0)
end_connection ();
}
}
}
mudlog ("SIGNAL: SIGTERM Handled");
for (plx = 0; plx < max_players; plx++) {
if (!EMPTY (pname (plx))) {
setup_globals (plx);
crapup ("\tSomething very unpleasant seems to have happened...\n",
CRAP_UNALIAS | CRAP_SAVE | CRAP_RETURN);
}
}
rm_pid_file ();
}
static void
rm_pid_file (void)
{
if (unlink (PID_FILE) < 0) {
progerror ("rm_pid_file");
}
}
static void
end_connection (void)
{
INP_HANDLER *i, *j;
int fd;
int me = real_mynum;
int x;
if ((x = quit_list) < 0)
return;
if (x == real_mynum)
me = -1;
setup_globals (x);
quit_list = cur_player->quit_next;
cur_player->quit_next = -2;
fd = cur_player->fil_des;
bflush ();
i = cur_player->inp_handler;
while (i != NULL) {
j = i;
i = i->next;
FREE (j);
}
cur_player->inp_handler = NULL;
if (FD_ISSET (fd, &buffer_fds))
inp_buf_c--;
FD_CLR (fd, &sockets_fds);
FD_CLR (fd, &buffer_fds);
close (fd);
fclose (cur_player->stream);
cur_player->stream = NULL;
cur_player->inp_buf_p = cur_player->inp_buf_end = cur_player->inp_buffer;
cur_player->sock_buf_p = cur_player->sock_buf_end = cur_player->sock_buffer;
cur_player->is_conn = False;
setup_globals (me);
}
#ifdef SYS_INET_NTOA_BUG
/* If the system include file for inet_ntoa contains erroneous
* prototypes.
*/
static char *
my_inet_ntoa (struct in_addr *in)
{
static char addr[20];
sprintf (addr, "%d.%d.%d.%d",
(int) ((in->s_addr >> 24) & 0xff),
(int) ((in->s_addr >> 16) & 0xff),
(int) ((in->s_addr >> 8) & 0xff),
(int) (in->s_addr & 0xff));
return addr;
}
#endif
static void
new_connection (int m_socket)
{
PLAYER_REC *pl;
FILE *f;
struct hostent *h;
int plx;
int fd;
int sin_len;
Boolean host_banned = False, host_b2 = False;
Boolean user_banned = False, user_b2 = False;
Boolean login_banned = False, login_b2 = False;
struct sockaddr_in sin;
char *host, *tmphost;
char hostnum[MAXHOSTNAMELEN];
bzero ((char *) &sin, sizeof (struct sockaddr_in));
sin_len = sizeof (struct sockaddr_in);
if ((fd = accept (m_socket, (struct sockaddr *) &sin, &sin_len)) < 0) {
progerror ("accept");
} else if ((f = fdopen (fd, "w")) == NULL) {
progerror ("fdopen");
exit (1);
} else {
#ifdef SYS_INET_NTOA_BUG
strcpy (hostnum, my_inet_ntoa (&sin.sin_addr));
#else
strcpy (hostnum, inet_ntoa (sin.sin_addr));
#endif
host_b2 = is_host_banned (hostnum);
user_b2 = is_host_user_banned (hostnum);
login_b2 = is_login_banned (hostnum);
host = hostnum;
if ((tmphost = read_hosts (host)) != NULL) {
host = tmphost;
} else {
if ((h = gethostbyaddr ((char *) &sin.sin_addr, sizeof (sin.sin_addr),
AF_INET)) == NULL) {
#ifdef LOG_GETHOST
mudlog ("SOCKET: gethostbyaddr: Couldn't find hostentry for %s", hostnum);
#endif
} else {
host_banned = is_host_banned ((char *) h->h_name);
user_banned = is_host_user_banned ((char *) h->h_name);
login_banned = is_login_banned ((char *) h->h_name);
host = (char *) h->h_name;
}
}
if (login_banned || login_b2) {
send_msg (DEST_ALL, MODE_PFLAG | MP (PFL_SEESOCKET), LVL_WIZARD,
LVL_MAX, NOBODY, NOBODY, "&+W[&+CSocket (%d): &+wBanned Login: "
"&+C%s&+W]\n&+W[&+CSocket (%d): &+wClosing Connection&+W]\n",
fd, host, fd);
fprintf (f, "\nSorry, but your host is banned from logging in.\n");
fflush (f);
fclose (f);
return;
}
if ((plx = find_free_player_slot ()) < 0) {
fprintf (f, "\nSorry, but this mud is full, please come back later.\n");
fflush (f);
fclose (f);
return;
}
setup_globals (plx);
pl = cur_player;
pl->host_ban = False;
pl->user_ban = False;
pl->sock_buf_p = pl->sock_buf_end = pl->sock_buffer;
pl->sin_len = sin_len;
pl->sin = sin;
pl->fil_des = fd;
pl->stream = f;
strcpy (pl->hostname, host);
if (host_banned || host_b2)
pl->host_ban = True;
if (user_banned || user_b2)
pl->user_ban = True;
/* Include this socket as a socket to listen to */
if (fd >= width)
width = fd + 1;
FD_SET (fd, &sockets_fds);
#if USE_IDENT
new_player (ident_id (fd, 0));
#else
new_player (NULL);
#endif
}
}
/************************************************************************
* iDiRT Packet Handler 2.20 *
* By Hastur, Changes by Illusion *
************************************************************************/
void handle_packet (int fd) {
static char *sock_msg[] = {
"Connection Reset by Peer (ECONNRESET)",
"No Route to Host (EHOSTUNREACH)",
"Connection Timed Out (ETIMEDOUT)",
"Network Unreachable (ENETUNREACH)",
"Network Dropped Connection on Reset (ENETRESET)",
"Network is Down (ENETDOWN)"
"Empty Packets"
};
int plx = find_pl_index (fd);
int x, y, g, msg;
char *b, *p, *c, *k;
x = y = g = msg = 0;
setup_globals (plx);
if (!cur_player->inp_handler || !cur_player->inp_handler->inp_handler) {
mudlog ("SYSTEM: %s Lost Input Handler", pname (mynum));
crapup ("\tInternal Error Has Occured: Lost Your Input Handler", CRAP_UNALIAS | CRAP_RETURN);
return;
}
g = 0;
if (cur_player->inp_buf_p >= cur_player->inp_buf_end) {
errno = 0;
bzero (cur_player->inp_buffer, sizeof (cur_player->inp_buffer));
if ((x = read (fd, cur_player->inp_buffer, MAX_COM_LEN-32)) < 0) {
if (errno == ECONNRESET ||/* Connection reset by peer */
errno == EHOSTUNREACH || /* No route to host */
errno == ETIMEDOUT || /* Connection timed out */
errno == ENETUNREACH || /* Network is unreachable */
errno == ENETRESET || /* Network dropped connect on reset */
errno == ENETDOWN || /* Network is down */
!x) { /* Empty packets */
switch (errno) {
case ECONNRESET:
msg = 0;
mudlog ("SYSTEM: %s Connection Reset", pname (mynum));
break;
case EHOSTUNREACH:
msg = 1;
mudlog ("SYSTEM: %s Host Unreachable", pname (mynum));
break;
case ETIMEDOUT:
msg = 2;
mudlog ("SYSTEM: %s Timed Out", pname (mynum));
break;
case ENETUNREACH:
msg = 3;
mudlog ("SYSTEM: %s Network Unreachable", pname (mynum));
break;
case ENETRESET:
msg = 4;
mudlog ("SYSTEM: %s Network Reset", pname (mynum));
break;
case ENETDOWN:
msg = 5;
mudlog ("SYSTEM: %s Network Down", pname (mynum));
break;
}
if (!x)
msg = 6;
if (cur_player->iamon) {
send_msg (DEST_ALL, 0, max (pvis (mynum), LVL_MIN), LVL_WIZARD - 1,
mynum, NOBODY, "%s has lost link to this realm.\n", pname (mynum));
send_msg (DEST_ALL, MODE_QUIET, max (pvis (mynum), LVL_WIZARD),
LVL_MAX, mynum, NOBODY, "&+W[&+CSocket (%d): &+C%s "
"&+whas lost link &+B(&+W%s&+B)&+W]\n",
cur_player->fil_des, pname (mynum), sock_msg[msg]);
mudlog ("SOCKET: %s has lost link (%s)", pname (mynum), sock_msg[msg]);
} else {
send_msg (DEST_ALL, MODE_PFLAG | MP (PFL_SEESOCKET), LVL_WIZARD,
LVL_MAX, mynum, NOBODY, "&+W[&+CSocket (%d): &*Connecting "
"socket has lost link &+B(&+W%s&+B)&+W]\n",
cur_player->fil_des, pname (mynum), sock_msg[msg]);
mudlog ("SOCKET: Connecting socket has lost link (%s)", sock_msg[msg]);
}
crapup (NULL, CRAP_SAVE | CRAP_UNALIAS | CRAP_RETURN);
errno = 0;
return;
}
mudlog ("SOCKET: Error reading data from %s\n", pname (mynum));
progerror (pname (mynum));
}
if (x == 0) {
if (cur_player->iamon) {
send_msg (DEST_ALL, 0, max (pvis (mynum), LVL_MIN), LVL_WIZARD - 1,
mynum, NOBODY, "%s has lost link to this realm.\n",
pname (mynum));
send_msg (DEST_ALL, MODE_QUIET, max (pvis (mynum), LVL_WIZARD),
LVL_MAX, mynum, NOBODY, "&+W[&+CSocket (%d): &+C%s "
"&+whas lost (cut) connection&+W]\n", cur_player->fil_des,
pname (mynum), sock_msg[msg]);
mudlog ("SOCKET: %s has lost (cut) connection", pname (mynum));
} else {
send_msg (DEST_ALL, MODE_PFLAG | MP (PFL_SEESOCKET),
max (pvis (mynum), LVL_WIZARD), LVL_MAX, mynum, NOBODY,
"&+W[&+CSocket (%d): &*Connecting socket has lost (cut) "
"connection&+W]\n", cur_player->fil_des, pname (mynum));
mudlog ("SOCKET: Connecting socket has lost (cut) connection");
}
crapup (NULL, CRAP_SAVE | CRAP_UNALIAS | CRAP_RETURN);
errno = 0;
quit_player ();
return;
}
if (cur_player->overwrite) {
if (strchr (cur_player->inp_buffer, '\n') ||
strchr (cur_player->inp_buffer, '\r'))
cur_player->overwrite = 0;
return;
}
inp_buf_c++;
FD_SET (fd, &buffer_fds);
b = cur_player->inp_buf_p = cur_player->inp_buffer;
cur_player->inp_buf_end = b + x;
} else {
// b is start of input buffer
// x is length of input buffer - 1
b = cur_player->inp_buf_p;
x = cur_player->inp_buf_end - b;
}
// check for some char as first char. if it's there, skip ahead 3 chars and do some other stuff.
if (*b == '\377') {
b += 3;
x -= 3;
if (x <= 0) {
inp_buf_c--;
FD_CLR (fd, &buffer_fds);
cur_player->inp_buf_p = cur_player->inp_buf_end;
cur_player->overwrite = 0;
return;
}
}
c = cur_player->sock_buf_p;
for (y = 0; y < x && c < (cur_player->sock_buffer + (MAX_COM_LEN-32)) &&
b[y] && b[y] != '\n' && b[y] != '\r'; ++y) {
if (b[y] == '\010' || b[y] == '\177') {
if (c > cur_player->sock_buffer)
c--;
} else {
*c++ = b[y];
}
}
cur_player->sock_buf_p = c;
if (y > (MAX_COM_LEN-33)) {
*--c = '\0';
y--;
bprintf ("&+B(&*Maximum Input Exceeded&+B)\n");
cur_player->overwrite = 1;
b[MAX_COM_LEN - 33] = '\n';
}
if (y < x && c < (cur_player->sock_buffer + (MAX_COM_LEN-32))) {
while (y < x && (b[y] == '\n' || b[y] == '\r' || !b[y]))
y++;
*c = 0;
k = c;
c = cur_player->sock_buffer;
for (p = c; *p; p++)
if (iscntrl (*p))
*p = ' ';
if (cur_player->logged)
write_plr_log("> %s", c);
if (cur_player->snooped > 0) {
char tmp[MAX_COM_LEN + 2];
strcpy (tmp, "\r&+GI&+W>&* ");
strcat (tmp, c);
strcat (tmp, "\n");
print_buf (tmp, True);
}
g = 1;
}
cur_player->sock_buf_p = c;
cur_player->inp_buf_p = b + y;
if (y >= x) {
FD_CLR (fd, &buffer_fds);
inp_buf_c--;
}
if (g) {
cur_player->inp_handler->inp_handler (c);
cur_player->sock_buf_p = cur_player->sock_buffer;
if (!ptstflg (mynum, PFL_IDLE)) {
plast_cmd (real_mynum) = global_clock;
}
prlast_cmd (real_mynum) = global_clock;
}
}
void
sig_handler (int sig)
{
char msg[30];
switch (sig) {
case SIGTERM:
mudlog ("SIGNAL: SIGTERM");
sig_term_happened = True;
return;
case SIGALRM:
sig_timer_happened = 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);
sprintf (msg, "SIGINT[%d]", sig);
break;
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_file ();
sig_exit (msg, sig);
}
/************************************************************************
* iDiRT Reboot Code (v1.35) *
* 1995 by Illusion *
* (Taken from Kender's Dirt 3.0 Reboot Code) *
************************************************************************/
/* 1995, Illusion */
void
initialize_slot (int plx)
{
players[plx].fil_des = -1;
players[plx].stream = NULL;
players[plx].no_echo = False;
players[plx].isawiz = False;
players[plx].ismonitored = False;
players[plx].iamon = False;
players[plx].is_conn = False;
players[plx].in_pbfr = False;
players[plx].aliased = False;
players[plx].me_ivct = 0;
players[plx].polymorphed = -1;
players[plx].i_follow = -1;
players[plx].snooptarget = -1;
players[plx].pretend = -1;
players[plx].snooped = 0;
players[plx].asmortal = 0;
players[plx].last_cmd = players[plx].logged_on = global_clock;
strcpy (players[plx].prev_com, "quit");
players[plx].quit_next = -2;
players[plx].wd_it = "pit";
players[plx].wd_them = players[plx].wd_him;
*players[plx].wd_him = *players[plx].wd_her = '\0';
players[plx].writer = NULL;
players[plx].pconverse = -1;
players[plx].overwrite = 0;
/*** Patch for now, actually needs to be written out with the user data
*** and read back into the MUD.
***/
players[plx].duration = NULL;
}
static int
xmain_reboot (int fd)
{
int pid, i, s, nplayers, nwiz_zones, plx, loc, vis, j;
char p[10], newname[256], tmpstr[50];
REBOOT_REC r_rec;
RPLR_REC p_rec;
FILE *fp;
/* Allow mud to catch signals again */
signal (SIGTERM, sig_handler);
signal (SIGTSTP, SIG_DFL);
signal (SIGCONT, SIG_DFL);
signal (SIGTTOU, SIG_DFL);
signal (SIGTTIN, SIG_DFL);
signal (SIGSEGV, sig_handler);/* Segmentation fault */
signal (SIGBUS, sig_handler); /* Bus error */
signal (SIGSYS, sig_handler); /* Bad argument to system call */
signal (SIGPIPE, SIG_IGN); /* Broken pipe */
signal (SIGUSR1, sig_handler);/* User defined signal */
signal (SIGUSR2, sig_handler);/* User defined signal */
pid = getpid (); /* Get process ID */
sprintf (p, "%d\n", pid);
write (fd, p, strlen (p));
close (fd);
sprintf (newname, "reboot_file.%d", 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;
the_climate->time = r_rec.climate_time;
the_climate->day = r_rec.climate_day;
the_climate->month = r_rec.climate_month;
nwiz_zones = r_rec.nwiz_zones;
nplayers = r_rec.nplayers;
if (bootstrap () < 0) { /* Initialize data structures */
mudlog ("REBOOT: Bootstrap failed on reboot");
return -1;
}
main_socket = s;
FD_ZERO (&sockets_fds);
FD_ZERO (&buffer_fds);
FD_SET (s, &sockets_fds);
/* Do full reset */
for (i = 0; i < numzon; i++) {
reset_zone (i, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
}
for (i = 0; i < nwiz_zones; i++) {
fread (tmpstr, 50, 1, fp);
load_zone (tmpstr, NULL, NULL, NULL, NULL, NULL, NULL);
}
for (i = 0; i < nplayers; i++) {
fread (&p_rec, sizeof (p_rec), 1, fp);
plx = p_rec.plx;
initialize_slot (plx);
setup_globals (plx);
cur_player->fil_des = p_rec.fil_des;
setpname (mynum, p_rec.pname);
cur_player->logged_on = p_rec.logged_on;
cur_player->last_cmd = p_rec.last_cmd;
cur_player->rlast_cmd = p_rec.rlast_cmd;
loc = p_rec.ploc;
vis = p_rec.pvis;
strcpy (cur_player->hostname, p_rec.hostname);
strcpy (cur_player->usrname, p_rec.usrname);
for (j = 0; j < 10; ++j)
cur_player->forget[j] = p_rec.forget[j];
if (cur_player->fil_des >= width)
width = cur_player->fil_des + 1;
FD_SET (cur_player->fil_des, &sockets_fds);
cur_player->sock_buf_p = cur_player->sock_buffer;
cur_player->sock_buf_end = cur_player->sock_buffer;
cur_player->stream = fdopen (cur_player->fil_des, "w");
getuafinfo (pname (mynum));
setpwpn (mynum, -1);
setphelping (mynum, -1);
setpfighting (mynum, -1);
setpsitting (mynum, 0);
cur_player->iamon = True;
cur_player->is_conn = True;
fetchprmpt (mynum);
push_input_handler (get_command);
get_command (NULL);
if (exists (loc))
setploc (mynum, loc);
else if (exists (phome (mynum)))
setploc (mynum, phome (mynum));
else
setploc (mynum, randperc () > 50 ? LOC_START_TEMPLE : LOC_START_CHURCH);
setpvis (mynum, vis);
setpconv (mynum, p_rec.pconv);
sprintf (cur_player->awaymsg, "%s", p_rec.awaymsg);
cur_player->Trace = p_rec.tracedata;
}
fclose (fp);
unlink (newname);
if (update) {
update_world (old_proc_num);
send_msg (DEST_ALL, 0, LVL_MIN, LVL_MAX, NOBODY, NOBODY,
"You open your eyes and see the %s beginning to fade "
"back\ninto reality. Suddenly, the world rearranges "
"itself back to the way it was.\n", MUD_NAME);
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_MAX, NOBODY, NOBODY,
"You open your eyes and see the %s beginning to fade "
"back\ninto reality. It all seems the same, yet somehow "
"different.\n", MUD_NAME);
send_msg (DEST_ALL, 0, LVL_WIZARD, LVL_MAX, NOBODY, NOBODY,
"&+W[&+CReboot Completed&+W]\n");
}
/* Update Climate */
which_season ();
the_climate->daytime = climate_day ();
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, nwiz_zones, new, nplayers;
char exec_path[256], new_path[256], filename[256];
char port[10], max[10], pid[10], *intest;
REBOOT_REC reboot_rec;
RPLR_REC rplr_rec;
FILE *fp;
intest = strstr (progname, EXEC_LOC);
if (intest == NULL) {
sprintf (exec_path, EXEC_LOC "/%s", progname);
sprintf (new_path, EXEC_LOC "/%s.new", progname);
} else {
sprintf (exec_path, "%s", progname);
sprintf (new_path, "%s.new", progname);
}
if (access (new_path, F_OK) != -1)
new = 1;
else if (access (exec_path, F_OK) != -1)
new = 0;
else {
bprintf ("Could not find an executable to reboot the MUD.\n");
mudlog ("REBOOT: Error: Could not find executable");
return;
}
signal (SIGALRM, SIG_IGN);
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_MAX, NOBODY, NOBODY,
"A cry is heard from the heavens as the Gods lose control "
"over the\n%s. The world begins to shake violently as a "
"giant\nearthquake swallows you as the Gods reconstruct "
"the world..\n", MUD_NAME);
mudlog ("REBOOT: 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_MAX, NOBODY, NOBODY,
"The %s begin to move and shift violently around you. "
"You\nclose your eyes tight, hoping that this will all "
"end soon..\n", MUD_NAME);
mudlog ("UPDATE: Update %sby %s", new ? "New " : "", pname (mynum));
} else if (breset) {
send_msg (DEST_ALL, 0, LVL_MIN, LVL_MAX, NOBODY, NOBODY,
"The %s begin to move and shift violently around you. "
"You\nclose your eyes tight, hoping that this will all "
"end soon..\n", MUD_NAME);
mudlog ("REBOOT: 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_MAX, NOBODY, NOBODY,
"The %s begin to move and shift violently around you. "
"You\nclose your eyes tight, hoping that this will all "
"end soon..\n", MUD_NAME);
mudlog ("REBOOT: Rebooted %sby %s", new ? "New " : "", pname (mynum));
}
if (crash)
++numcrashes;
else
++numreboots;
sprintf (filename, "reboot_file.%d", getpid ());
for (i = num_const_zon, nwiz_zones = 0; i < numzon; ++i)
if (!ztemporary (i))
nwiz_zones++;
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.climate_time = the_climate->time;
reboot_rec.climate_day = the_climate->day;
reboot_rec.climate_month = the_climate->month;
reboot_rec.nwiz_zones = nwiz_zones;
reboot_rec.nplayers = nplayers;
if ((fp = fopen (filename, "wb")) == NULL)
mudlog ("ERROR: open() failed");
fwrite (&reboot_rec, sizeof (reboot_rec), 1, fp);
for (i = num_const_zon; i < numzon; ++i)
if (!ztemporary (i))
fwrite (zname (i), 50, 1, fp);
for (plx = 0; plx < max_players; ++plx) {
if (!players[plx].inp_handler)
continue;
setup_globals (plx);
if (!players[plx].iamon) {
bprintf ("%s is currently rebooting, please reconnect momentarily.\n",
MUD_NAME);
bflush ();
close (cur_player->fil_des);
fclose (cur_player->stream);
send_msg (DEST_ALL, MODE_PFLAG | MP (PFL_SEESOCKET), LVL_MIN, LVL_MAX,
NOBODY, NOBODY, "&+W[&+CSocket (%d): &+wConnection from %s "
"disconnected for reboot&+W]\n", players[plx].fil_des, players[plx].hostname);
} else {
saveme ();
rplr_rec.plx = plx;
rplr_rec.fil_des = cur_player->fil_des;
strcpy (rplr_rec.pname, pname (mynum));
rplr_rec.logged_on = cur_player->logged_on;
rplr_rec.last_cmd = cur_player->last_cmd;
rplr_rec.rlast_cmd = cur_player->rlast_cmd;
rplr_rec.ploc = ploc (mynum);
rplr_rec.pvis = pvis (mynum);
rplr_rec.pconv = pconv (mynum);
strcpy (rplr_rec.hostname, cur_player->hostname);
strcpy (rplr_rec.usrname, cur_player->usrname);
sprintf (rplr_rec.awaymsg, "%s", cur_player->awaymsg);
for (i = 0; i < 10; ++i)
rplr_rec.forget[i] = cur_player->forget[i];
rplr_rec.tracedata = cur_player->Trace;
fwrite (&rplr_rec, sizeof (rplr_rec), 1, fp);
}
}
fclose (fp);
for (i = 0; i < max_players; ++i) {
if (players[i].iamon) {
setup_globals (i);
bflush ();
}
}
if (will_update) {
run_update ();
}
if (new) {
unlink (exec_path);
link (new_path, exec_path);
unlink (new_path);
}
if (!access (PID_FILE, 0))
unlink (PID_FILE);
sprintf (port, "%d", mud_port);
sprintf (max, "%d", max_players);
sprintf (pid, "%d", getpid ());
if (mud_port != PORT)
if (max_players != MAX_PLAYERS)
execl (exec_path, exec_path, "-p", port, "-n", max, will_update ? "-u" : "-r", pid, NULL);
else
execl (exec_path, exec_path, "-p", port, will_update ? "-u" : "-r", pid, NULL);
else if (max_players != MAX_PLAYERS)
execl (exec_path, exec_path, "-n", max, will_update ? "-u" : "-r", pid, NULL);
else
execl (exec_path, exec_path, will_update ? "-u" : "-r", pid, NULL);
}
/************************************************************************
* iDiRT Hosts Code (v1.00) *
* 1995 by Illusion *
* The following code reads the iDiRT hosts file to get different *
* hostnames for certain IP addresses. *
************************************************************************/
void
process_data (char data[300], char *ip, char *host)
{
int i = 0, j = 0;
while (!isspace (data[i])) {
ip[i] = data[i];
++i;
}
ip[i] = '\0';
for (j = 0; i < strlen (data); ++j) {
++i;
host[j] = data[i];
}
host[j - 2] = '\0';
}
char *
read_hosts (char search[20])
{
static char host[256];
char data[300];
char ip[20];
FILE *fp;
if ((fp = fopen (HOSTS, "rt")) == NULL)
return NULL;
while (!feof (fp)) {
fgets (data, 300, fp);
process_data (data, ip, host);
if (strstr (search, ip)) {
fclose (fp);
return host;
}
}
fclose (fp);
return NULL;
}
void
usesocketcom (void)
{
int fd, ct;
bprintf ("&+wTotal Sockets Allocated: &+W%d\n", width);
bprintf ("&+B------------------------------------------------------------------------------\n");
for (fd = 0, ct = 1; fd < width; fd++, ct++) {
bprintf ("FD %d: %s", fd, fd == main_socket ? "MainSock" :
FD_ISSET (fd, &sockets_fds) ? "InUse" : "Unused");
if ((ct % 6 == 5) || (fd == width - 1))
bprintf ("\n");
else
bprintf ("\t");
}
bprintf ("&+B------------------------------------------------------------------------------\n");
}