/* * bsd.c */ /* * $Id: bsd.c,v 1.4 1995/12/03 09:18:32 root Exp root $ */ #include "copyright.h" #include "autoconf.h" #ifdef VMS #include "multinet_root:[multinet.include.sys]file.h" #include "multinet_root:[multinet.include.sys]ioctl.h" #include "multinet_root:[multinet.include]errno.h" #else #include <sys/file.h> #include <sys/ioctl.h> #include <sys/wait.h> #endif #include <signal.h> #include "mudconf.h" #include "config.h" #include "db.h" #include "file_c.h" #include "externs.h" #include "interface.h" #include "flags.h" #include "powers.h" #include "alloc.h" #include "command.h" #include "slave.h" #include "attrs.h" #ifdef SOLARIS extern const int _sys_nsig; #define NSIG _sys_nsig #endif #ifdef CONCENTRATE extern struct descriptor_data *ccontrol; extern void FDECL(send_killconcid, (DESC *)); extern long NDECL(make_concid); #endif extern void NDECL(dispatch); extern void NDECL(dump_restart_db); extern void FDECL(dump_database_internal, (int)); int sock; int ndescriptors = 0; int maxd = 0; DESC *descriptor_list = NULL; pid_t slave_pid; int slave_socket = -1; DESC *FDECL(initializesock, (int, struct sockaddr_in *)); DESC *FDECL(new_connection, (int)); int FDECL(process_output, (DESC *)); int FDECL(process_input, (DESC *)); /* * get a result from the slave */ static int get_slave_result() { char *buf; char *token; char *os; char *userid; char *host; int local_port, remote_port; char *p; DESC *d; unsigned long addr; int len; buf = alloc_lbuf("slave_buf"); len = read(slave_socket, buf, LBUF_SIZE - 1); if (len < 0) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { free_lbuf(buf); return (-1); } close(slave_socket); slave_socket = -1; free_lbuf(buf); return (-1); } else if (len == 0) { free_lbuf(buf); return (-1); } buf[len] = '\0'; token = alloc_lbuf("slave_token"); os = alloc_lbuf("slave_os"); userid = alloc_lbuf("slave_userid"); host = alloc_lbuf("slave_host"); if (sscanf(buf, "%s %s", host, token) != 2) { free_lbuf(buf); free_lbuf(token); free_lbuf(os); free_lbuf(userid); free_lbuf(host); return (0); } p = strchr(buf, '\n'); *p = '\0'; for (d = descriptor_list; d; d = d->next) { if (strcmp(d->addr, host)) continue; if (mudconf.use_hostname) { StringCopyTrunc(d->addr, token, 50); d->addr[50] = '\0'; if (d->player != 0) { if (d->username[0]) atr_add_raw(d->player, A_LASTSITE, tprintf("%s@%s", d->username, d->addr)); else atr_add_raw(d->player, A_LASTSITE, d->addr); } } } if (sscanf(p + 1, "%s %d , %d : %s : %s : %s", host, &remote_port, &local_port, token, os, userid) != 6) { free_lbuf(buf); free_lbuf(token); free_lbuf(os); free_lbuf(userid); free_lbuf(host); return (0); } for (d = descriptor_list; d; d = d->next) { if (ntohs((d->address).sin_port) != remote_port) continue; StringCopyTrunc(d->username, userid, 10); d->username[10] = '\0'; if (d->player != 0) { atr_add_raw(d->player, A_LASTSITE, tprintf("%s@%s", d->username, d->addr)); } free_lbuf(buf); free_lbuf(token); free_lbuf(os); free_lbuf(userid); free_lbuf(host); return (0); } free_lbuf(buf); free_lbuf(token); free_lbuf(os); free_lbuf(userid); free_lbuf(host); return (0); } void boot_slave() { int sv[2]; int i; int maxfds; #ifdef HAVE_GETDTABLESIZE maxfds = getdtablesize(); #else maxfds = sysconf(_SC_OPEN_MAX); #endif if (slave_socket != -1) { close(slave_socket); slave_socket = -1; } if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) { return; } /* * set to nonblocking */ if (fcntl(sv[0], F_SETFL, FNDELAY) == -1) { close(sv[0]); close(sv[1]); return; } slave_pid = vfork(); switch (slave_pid) { case -1: close(sv[0]); close(sv[1]); return; case 0: /* * * child */ close(sv[0]); close(0); close(1); if (dup2(sv[1], 0) == -1) { _exit(1); } if (dup2(sv[1], 1) == -1) { _exit(1); } for (i = 3; i < maxfds; ++i) { close(i); } execlp("bin/slave", "slave", NULL); _exit(1); } close(sv[1]); if (fcntl(sv[0], F_SETFL, FNDELAY) == -1) { close(sv[0]); return; } slave_socket = sv[0]; } int make_socket(port) int port; { int s, opt; struct sockaddr_in server; s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { log_perror("NET", "FAIL", NULL, "creating master socket"); exit(3); } opt = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) { log_perror("NET", "FAIL", NULL, "setsockopt"); } server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(port); if (!mudstate.restarting) if (bind(s, (struct sockaddr *)&server, sizeof(server))) { log_perror("NET", "FAIL", NULL, "bind"); close(s); exit(4); } listen(s, 5); return s; } #ifndef HAVE_GETTIMEOFDAY #define get_tod(x) { (x)->tv_sec = time(NULL); (x)->tv_usec = 0; } #else #define get_tod(x) gettimeofday(x, (struct timezone *)0) #endif void shovechars(port) int port; { fd_set input_set, output_set; struct timeval last_slice, current_time, next_slice, timeout, slice_timeout; int found, check; DESC *d, *dnext, *newd; int avail_descriptors, maxfds; #define CheckInput(x) FD_ISSET(x, &input_set) #define CheckOutput(x) FD_ISSET(x, &output_set) mudstate.debug_cmd = (char *)"< shovechars >"; if (!mudstate.restarting) { sock = make_socket(port); } if (!mudstate.restarting) maxd = sock + 1; get_tod(&last_slice); #ifdef HAVE_GETDTABLESIZE maxfds = getdtablesize(); #else maxfds = sysconf(_SC_OPEN_MAX); #endif avail_descriptors = maxfds - 7; while (mudstate.shutdown_flag == 0) { get_tod(¤t_time); last_slice = update_quotas(last_slice, current_time); process_commands(); if (mudstate.shutdown_flag) break; /* * test for events */ dispatch(); /* * any queued robot commands waiting? */ timeout.tv_sec = que_next(); timeout.tv_usec = 0; next_slice = msec_add(last_slice, mudconf.timeslice); slice_timeout = timeval_sub(next_slice, current_time); FD_ZERO(&input_set); FD_ZERO(&output_set); /* * Listen for new connections if there are free descriptors */ if (ndescriptors < avail_descriptors) { FD_SET(sock, &input_set); } /* * Listen for replies from the slave socket */ if (slave_socket != -1) { FD_SET(slave_socket, &input_set); } /* * Mark sockets that we want to test for change in status */ DESC_ITER_ALL(d) { if (!d->input_head) FD_SET(d->descriptor, &input_set); if (d->output_head) FD_SET(d->descriptor, &output_set); } /* * Wait for something to happen */ found = select(maxd, &input_set, &output_set, (fd_set *) NULL, &timeout); if (found < 0) { if (errno != EINTR) { log_perror("NET", "FAIL", "checking for activity", "select"); } continue; } /* * if !found then time for robot commands */ if (!found) { if (mudconf.queue_chunk) do_top(mudconf.queue_chunk); continue; } else { do_top(mudconf.active_q_chunk); } /* * Get usernames and hostnames */ if (slave_socket != -1 && FD_ISSET(slave_socket, &input_set)) { while (get_slave_result() == 0) ; } /* * Check for new connection requests */ if (CheckInput(sock)) { newd = new_connection(sock); if (!newd) { check = (errno && (errno != EINTR) && (errno != EMFILE) && (errno != ENFILE)); if (check) { log_perror("NET", "FAIL", NULL, "new_connection"); } } else { if (newd->descriptor >= maxd) maxd = newd->descriptor + 1; } } /* * Check for activity on user sockets */ DESC_SAFEITER_ALL(d, dnext) { /* * Process input from sockets with pending input */ if (CheckInput(d->descriptor)) { /* * Undo autodark */ if (d->flags & DS_AUTODARK) { d->flags &= ~DS_AUTODARK; s_Flags(d->player, Flags(d->player) & ~DARK); } /* * Process received data */ #ifdef CONCENTRATE if (!(d->cstatus & C_REMOTE)) #endif if (!process_input(d)) { shutdownsock(d, R_SOCKDIED); continue; } } /* * Process output for sockets with pending output */ if (CheckOutput(d->descriptor)) { if (!process_output(d)) { #ifdef CONCENTRATE if (!(d->cstatus & C_CCONTROL)) #endif shutdownsock(d, R_SOCKDIED); } } } } } DESC *new_connection(sock) int sock; { int newsock; char *buff, *buff1, *cmdsave; DESC *d; struct sockaddr_in addr; int addr_len, len; char *buf; char *chp; cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< new_connection >"; addr_len = sizeof(struct sockaddr); newsock = accept(sock, (struct sockaddr *)&addr, &addr_len); if (newsock < 0) return 0; if (site_check(addr.sin_addr, mudstate.access_list) == H_FORBIDDEN) { STARTLOG(LOG_NET | LOG_SECURITY, "NET", "SITE") buff = alloc_mbuf("new_connection.LOG.badsite"); sprintf(buff, "[%d/%s] Connection refused. (Remote port %d)", newsock, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); log_text(buff); free_mbuf(buff); ENDLOG fcache_rawdump(newsock, FC_CONN_SITE); shutdown(newsock, 2); close(newsock); errno = 0; d = NULL; } else { buff = alloc_mbuf("new_connection.address"); buf = alloc_lbuf("new_connection.write"); StringCopy(buff, inet_ntoa(addr.sin_addr)); /* * Ask slave process for host and username */ if ((slave_socket != -1) && mudconf.use_hostname) { sprintf(buf, "%s\n%s,%d,%d\n", inet_ntoa(addr.sin_addr), inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), mudconf.port); len = strlen(buf); if (WRITE(slave_socket, buf, len) < 0) { close(slave_socket); slave_socket = -1; } } free_lbuf(buf); STARTLOG(LOG_NET, "NET", "CONN") buff1 = alloc_mbuf("new_connection.LOG.open"); sprintf(buff1, "[%d/%s] Connection opened (remote port %d)", newsock, buff, ntohs(addr.sin_port)); log_text(buff1); free_mbuf(buff1); ENDLOG d = initializesock(newsock, &addr); mudstate.debug_cmd = cmdsave; free_mbuf(buff); } mudstate.debug_cmd = cmdsave; return (d); } /* * Disconnect reasons that get written to the logfile */ static const char *disc_reasons[] = { "Unspecified", "Quit", "Inactivity Timeout", "Booted", "Remote Close or Net Failure", "Game Shutdown", "Login Retry Limit", "Logins Disabled", "Logout (Connection Not Dropped)", "Too Many Connected Players" }; /* * Disconnect reasons that get fed to A_ADISCONNECT via announce_disconnect */ static const char *disc_messages[] = { "unknown", "quit", "timeout", "boot", "netdeath", "shutdown", "badlogin", "nologins", "logout" }; void shutdownsock(d, reason) DESC *d; int reason; { char *buff, *buff2; time_t now; int i; if ((reason == R_LOGOUT) && (site_check((d->address).sin_addr, mudstate.access_list) == H_FORBIDDEN)) reason = R_QUIT; if (d->flags & DS_CONNECTED) { /* * Do the disconnect stuff if we aren't doing a LOGOUT * * * * * * * (which keeps the connection open so the player can * * * connect * * * * to a different character). */ if (reason != R_LOGOUT) { fcache_dump(d, FC_QUIT); STARTLOG(LOG_NET | LOG_LOGIN, "NET", "DISC") buff = alloc_mbuf("shutdownsock.LOG.disconn"); sprintf(buff, "[%d/%s] Logout by ", d->descriptor, d->addr); log_text(buff); log_name(d->player); sprintf(buff, " <Reason: %s>", disc_reasons[reason]); log_text(buff); free_mbuf(buff); ENDLOG } else { STARTLOG(LOG_NET | LOG_LOGIN, "NET", "LOGO") buff = alloc_mbuf("shutdownsock.LOG.logout"); sprintf(buff, "[%d/%s] Logout by ", d->descriptor, d->addr); log_text(buff); log_name(d->player); sprintf(buff, " <Reason: %s>", disc_reasons[reason]); log_text(buff); free_mbuf(buff); ENDLOG } /* * If requested, write an accounting record of the form: * * * * * * * Plyr# Flags Cmds ConnTime Loc Money [Site] * <DiscRsn> * * * Name */ STARTLOG(LOG_ACCOUNTING, "DIS", "ACCT") now = mudstate.now - d->connected_at; buff = alloc_lbuf("shutdownsock.LOG.accnt"); buff2 = decode_flags(GOD, Flags(d->player), Flags2(d->player), Flags3(d->player)); sprintf(buff, "%d %s %d %d %d %d [%s] <%s> %s", d->player, buff2, d->command_count, now, Location(d->player), Pennies(d->player), d->addr, disc_reasons[reason], Name(d->player)); log_text(buff); free_lbuf(buff); free_sbuf(buff2); ENDLOG announce_disconnect(d->player, d, disc_messages[reason]); } else { if (reason == R_LOGOUT) reason = R_QUIT; STARTLOG(LOG_SECURITY | LOG_NET, "NET", "DISC") buff = alloc_mbuf("shutdownsock.LOG.neverconn"); sprintf(buff, "[%d/%s] Connection closed, never connected. <Reason: %s>", d->descriptor, d->addr, disc_reasons[reason]); log_text(buff); free_mbuf(buff); ENDLOG } process_output(d); clearstrings(d); if (reason == R_LOGOUT) { d->flags &= ~DS_CONNECTED; d->connected_at = mudstate.now; d->retries_left = mudconf.retry_limit; d->command_count = 0; d->timeout = mudconf.idle_timeout; d->player = 0; d->doing[0] = '\0'; d->quota = mudconf.cmd_quota_max; d->last_time = 0; d->host_info = site_check((d->address).sin_addr, mudstate.access_list) | site_check((d->address).sin_addr, mudstate.suspect_list); d->input_tot = d->input_size; d->output_tot = 0; welcome_user(d); } else { #ifdef CONCENTRATE if (!(d->cstatus & C_REMOTE)) { if (d->cstatus & C_CCONTROL) { register struct descriptor_data *k; for (k = descriptor_list; k; k = k->next) if (k->parent == d) shutdownsock(k, R_QUIT); } #endif shutdown(d->descriptor, 2); close(d->descriptor); #ifdef CONCENTRATE } else { register struct descriptor_data *k; for (k = descriptor_list; k; k = k->next) if (d->parent == k) send_killconcid(d); } #endif freeqs(d); *d->prev = d->next; if (d->next) d->next->prev = d->prev; /* * Is this desc still in interactive mode? */ if (d->program_data != NULL) { free(d->program_data); } free_desc(d); #ifdef CONCENTRATE if (!(d->cstatus & C_REMOTE)) #endif ndescriptors--; } } void make_nonblocking(s) int s; { #ifdef HAVE_LINGER struct linger ling; #endif #ifdef FNDELAY if (fcntl(s, F_SETFL, FNDELAY) == -1) { log_perror("NET", "FAIL", "make_nonblocking", "fcntl"); } #else if (fcntl(s, F_SETFL, O_NDELAY) == -1) { log_perror("NET", "FAIL", "make_nonblocking", "fcntl"); } #endif #ifdef HAVE_LINGER ling.l_onoff = 0; ling.l_linger = 0; if (setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling)) < 0) { log_perror("NET", "FAIL", "linger", "setsockopt"); } #endif } DESC *initializesock(s, a) int s; struct sockaddr_in *a; { DESC *d; int i; ndescriptors++; d = alloc_desc("init_sock"); d->descriptor = s; #ifdef CONCENTRATE d->concid = make_concid(); d->cstatus = 0; d->parent = 0; #endif d->flags = 0; d->connected_at = mudstate.now; d->retries_left = mudconf.retry_limit; d->command_count = 0; d->timeout = mudconf.idle_timeout; d->host_info = site_check((*a).sin_addr, mudstate.access_list) | site_check((*a).sin_addr, mudstate.suspect_list); d->player = 0; /* * be sure #0 isn't wizard. Shouldn't be. */ d->addr[0] = '\0'; d->doing[0] = '\0'; d->username[0] = '\0'; make_nonblocking(s); d->output_prefix = NULL; d->output_suffix = NULL; d->output_size = 0; d->output_tot = 0; d->output_lost = 0; d->output_head = NULL; d->output_tail = NULL; d->input_head = NULL; d->input_tail = NULL; d->input_size = 0; d->input_tot = 0; d->input_lost = 0; d->raw_input = NULL; d->raw_input_at = NULL; d->quota = mudconf.cmd_quota_max; d->program_data = NULL; d->last_time = 0; d->address = *a; /* * added 5/3/90 SCG */ if (descriptor_list) descriptor_list->prev = &d->next; d->hashnext = NULL; d->next = descriptor_list; d->prev = &descriptor_list; StringCopyTrunc(d->addr, inet_ntoa(a->sin_addr), 50); descriptor_list = d; welcome_user(d); return d; } int process_output(d) DESC *d; { TBLOCK *tb, *save; int cnt; char *cmdsave; static char buf[LBUF_SIZE]; int len; cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< process_output >"; tb = d->output_head; #ifdef CONCENTRATE if (d->cstatus & C_REMOTE) { static char buf[10]; static char obuf[2048]; int buflen, k, j; sprintf(buf, "%d ", d->concid); buflen = strlen(buf); bcopy(buf, obuf, buflen); j = buflen; while (tb != NULL) { for (k = 0; k < tb->hdr.nchars; k++) { obuf[j++] = tb->hdr.start[k]; if (tb->hdr.start[k] == '\n') { if (d->parent) queue_write(d->parent, obuf, j); bcopy(buf, obuf, buflen); j = buflen; } } d->output_size -= tb->hdr.nchars; save = tb; tb = tb->hdr.nxt; free(save); d->output_head = tb; if (tb == NULL) d->output_tail = NULL; } if (j > buflen) queue_write(d, obuf + buflen, j - buflen); return 1; } else { #endif while (tb != NULL) { while (tb->hdr.nchars > 0) { /* * len = string_compress(tb->hdr.start, buf); * * WRITE(d->descriptor, tprintf("%d", len), 10); */ cnt = WRITE(d->descriptor, tb->hdr.start, tb->hdr.nchars); /* * cnt = WRITE(d->descriptor, buf, len); */ if (cnt < 0) { mudstate.debug_cmd = cmdsave; if (errno == EWOULDBLOCK) return 1; return 0; } d->output_size -= cnt; tb->hdr.nchars -= cnt; tb->hdr.start += cnt; } save = tb; tb = tb->hdr.nxt; free(save); d->output_head = tb; if (tb == NULL) d->output_tail = NULL; } #ifdef CONCENTRATE } #endif mudstate.debug_cmd = cmdsave; return 1; } int process_input(d) DESC *d; { static char buf[LBUF_SIZE]; int got, in, lost; char *p, *pend, *q, *qend; char *cmdsave; cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *)"< process_input >"; got = in = READ(d->descriptor, buf, sizeof buf); if (got <= 0) { mudstate.debug_cmd = cmdsave; return 0; } if (!d->raw_input) { d->raw_input = (CBLK *) alloc_lbuf("process_input.raw"); d->raw_input_at = d->raw_input->cmd; } p = d->raw_input_at; pend = d->raw_input->cmd + LBUF_SIZE - sizeof(CBLKHDR) - 1; lost = 0; for (q = buf, qend = buf + got; q < qend; q++) { if (*q == '\n') { *p = '\0'; if (p > d->raw_input->cmd) { save_command(d, d->raw_input); d->raw_input = (CBLK *) alloc_lbuf("process_input.raw"); p = d->raw_input_at = d->raw_input->cmd; pend = d->raw_input->cmd + LBUF_SIZE - sizeof(CBLKHDR) - 1; } else { in -= 1; /* * for newline */ } } else if ((*q == '\b') || (*q == 127)) { if (*q == 127) queue_string(d, "\b \b"); else queue_string(d, " \b"); in -= 2; if (p > d->raw_input->cmd) p--; if (p < d->raw_input_at) (d->raw_input_at)--; } else if (p < pend && isascii(*q) && isprint(*q)) { *p++ = *q; } else { in--; if (p >= pend) lost++; } } if (p > d->raw_input->cmd) { d->raw_input_at = p; } else { free_lbuf(d->raw_input); d->raw_input = NULL; d->raw_input_at = NULL; } d->input_tot += got; d->input_size += in; d->input_lost += lost; mudstate.debug_cmd = cmdsave; return 1; } void close_sockets(emergency, message) int emergency; char *message; { DESC *d, *dnext; DESC_SAFEITER_ALL(d, dnext) { if (emergency) { WRITE(d->descriptor, message, strlen(message)); if (shutdown(d->descriptor, 2) < 0) log_perror("NET", "FAIL", NULL, "shutdown"); close(d->descriptor); } else { queue_string(d, message); queue_write(d, "\r\n", 2); shutdownsock(d, R_GOING_DOWN); } } close(sock); } void NDECL(emergency_shutdown) { close_sockets(1, (char *)"Going down - Bye"); } /* * --------------------------------------------------------------------------- * * Signal handling routines. */ #ifndef SIGCHLD #define SIGCHLD SIGCLD #endif static RETSIGTYPE sighandler(); /* *INDENT-OFF* */ NAMETAB sigactions_nametab[] = { {(char *)"exit", 3, 0, SA_EXIT}, {(char *)"default", 1, 0, SA_DFLT}, { NULL, 0, 0, 0}}; /* *INDENT-ON* */ void NDECL(set_signals) { signal(SIGALRM, sighandler); signal(SIGCHLD, sighandler); signal(SIGHUP, sighandler); signal(SIGINT, sighandler); signal(SIGQUIT, sighandler); signal(SIGTERM, sighandler); signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, sighandler); signal(SIGTRAP, sighandler); #ifdef SIGXCPU signal(SIGXCPU, sighandler); #endif signal(SIGILL, sighandler); #ifdef __linux__ signal(SIGFPE, SIG_IGN); #else signal(SIGFPE, sighandler); #endif signal(SIGSEGV, sighandler); signal(SIGABRT, sighandler); #ifdef SIGFSZ signal(SIGXFSZ, sighandler); #endif #ifdef SIGEMT signal(SIGEMT, sighandler); #endif #ifdef SIGBUS signal(SIGBUS, sighandler); #endif #ifdef SIGSYS signal(SIGSYS, sighandler); #endif } static void unset_signals() { int i; for (i = 0; i < NSIG; i++) signal(i, SIG_DFL); abort(); } static void check_panicking(sig) int sig; { int i; /* * If we are panicking, turn off signal catching and resignal */ if (mudstate.panicking) { for (i = 0; i < NSIG; i++) signal(i, SIG_DFL); kill(getpid(), sig); } mudstate.panicking = 1; } void log_signal(signame) const char *signame; { STARTLOG(LOG_PROBLEMS, "SIG", "CATCH") log_text((char *)"Caught signal "); log_text((char *)signame); ENDLOG } #ifdef HAVE_STRUCT_SIGCONTEXT static RETSIGTYPE sighandler(sig, code, scp) int sig, code; struct sigcontext *scp; #else static RETSIGTYPE sighandler(sig, code) int sig, code; #endif { #ifdef SYS_SIGLIST_DECLARED #define signames sys_siglist #else static const char *signames[] = { "SIGZERO", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGLOST", "SIGUSR1", "SIGUSR2"}; #endif char buff[32]; #ifdef HAVE_UNION_WAIT union wait stat; #else int stat; #endif switch (sig) { case SIGUSR1: shutdown(slave_socket, 2); kill(slave_pid, SIGKILL); alarm(0); dump_restart_db(); execl("bin/netmux", "netmux", mudconf.config_file, NULL); break; case SIGALRM: /* * Timer */ mudstate.alarm_triggered = 1; break; case SIGCHLD: /* * Change in child status */ #ifndef SIGNAL_SIGCHLD_BRAINDAMAGE signal(SIGCHLD, sighandler); #endif #ifdef HAVE_WAIT3 while (wait3(&stat, WNOHANG, NULL) > 0) ; #else wait(&stat); #endif break; case SIGHUP: /* * Perform a database dump */ log_signal(signames[sig]); mudstate.dump_counter = 0; break; case SIGINT: /* * Log + ignore */ log_signal(signames[sig]); break; case SIGQUIT: /* * Normal shutdown */ case SIGTERM: #ifdef SIGXCPU case SIGXCPU: #endif check_panicking(sig); log_signal(signames[sig]); sprintf(buff, "Caught signal %s", signames[sig]); do_shutdown(NOTHING, NOTHING, 0, buff); break; case SIGILL: /* * Panic save + restart */ case SIGFPE: case SIGSEGV: case SIGTRAP: #ifdef SIGXFSZ case SIGXFSZ: #endif #ifdef SIGEMT case SIGEMT: #endif #ifdef SIGBUS case SIGBUS: #endif #ifdef SIGSYS case SIGSYS: #endif check_panicking(sig); log_signal(signames[sig]); report(); if (mudconf.sig_action != SA_EXIT) { char outdb[128]; char indb[128]; raw_broadcast(0, "Game: Fatal signal %s caught, restarting with previous database.", signames[sig]); pcache_sync(); SYNC; CLOSE; dump_database_internal(1); shutdown(slave_socket, 2); kill(slave_pid, SIGKILL); /* * Try our best to dump a core first */ if (!fork()) { unset_signals(); exit(1); } if (mudconf.compress_db) { sprintf(outdb, "%s.Z", mudconf.outdb); sprintf(indb, "%s.Z", mudconf.indb); rename(outdb, indb); } else { rename(mudconf.outdb, mudconf.indb); } alarm(0); dump_restart_db(); execl("bin/netmux", "netmux", mudconf.config_file, NULL); break; } else { unset_signals(); signal(sig, SIG_DFL); exit(1); } case SIGABRT: /* * Coredump. */ check_panicking(sig); log_signal(signames[sig]); report(); unset_signals(); signal(sig, SIG_DFL); exit(1); } signal(sig, sighandler); mudstate.panicking = 0; #ifdef VMS return 1; #else return; #endif }