/* bsd.c */ #include "autoconf.h" #include "copyright.h" #ifndef lint static char RCSid[] = "$Id: bsd.c,v 1.7 1995/03/20 23:59:45 ambar Exp $"; USE(RCSid); #endif #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> #endif #include <signal.h> #include "interface.h" #include "file_c.h" #include "flags.h" #include "command.h" #ifdef TLI #include <sys/stream.h> #include <sys/tiuser.h> #include <sys/tihdr.h> #include <stropts.h> #include <poll.h> #define SOCKETCLOSE(x) t_unbind(x); \ t_close(x); extern int t_errno; extern char *t_errlist[]; #else #define SOCKETCLOSE(x) if (shutdown((x), 2) < 0) \ log_perror("NET", "FAIL", NULL, "shutdown"); \ close(x); #endif /* TLI */ extern void NDECL(dispatch); static int sock; static int ndescriptors = 0; DESC *descriptor_list = NULL; DESC *FDECL(initializesock, (int, struct sockaddr_in *, char *)); DESC *FDECL(new_connection, (int)); int FDECL(process_output, (DESC *)); int FDECL(process_input, (DESC *)); int make_socket(port) int port; { int s, opt; #ifdef TLI struct t_bind *bindreq, *bindret; struct sockaddr_in *serverreq, *serverret; #else struct sockaddr_in server; #endif #ifdef TLI s = t_open(TLI_TCP, (O_RDWR | O_NDELAY), NULL); #else s = socket(AF_INET, SOCK_STREAM, 0); #endif if (s < 0) { log_perror("NET", "FAIL", NULL, "creating master socket"); exit(3); } #ifdef TLI bindreq = (struct t_bind *) t_alloc(s, T_BIND, T_ALL); if (!bindreq) { log_perror("NET", "FAIL", NULL, "t_alloc(req)"); t_close(s); exit(4); } bindret = (struct t_bind *) t_alloc(s, T_BIND, T_ALL); if (!bindret) { log_perror("NET", "FAIL", NULL, "t_alloc(ret)"); t_close(s); exit(4); } serverreq = (struct sockaddr_in *) bindreq->addr.buf; serverreq->sin_family = AF_INET; serverreq->sin_addr.s_addr = INADDR_ANY; serverreq->sin_port = htons(port); bindreq->addr.len = sizeof(struct sockaddr_in); bindret->addr.maxlen = sizeof(struct sockaddr_in); bindreq->qlen = 5; if (t_bind(s, bindreq, bindret) < 0) { log_perror("NET", "FAIL", NULL, "t_bind"); t_close(s); exit(5); } serverret = (struct sockaddr_in *) bindret->addr.buf; if (serverreq->sin_port != serverret->sin_port) { log_perror("NET", "FAIL", NULL, "t_bind(portinuse)"); t_close(s); exit(6); } #else 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 (bind(s, (struct sockaddr *) &server, sizeof(server))) { log_perror("NET", "FAIL", NULL, "bind"); close(s); exit(4); } listen(s, 5); #endif /* TLI */ 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 maxd, found, check; DESC *d, *dnext, *newd; int avail_descriptors, maxfds; #ifdef TLI struct pollfd *fds; int i; #define CheckInput(x) ((fds[x].revents & POLLIN) == POLLIN) #define CheckOutput(x) ((fds[x].revents & POLLOUT) == POLLOUT) #else #define CheckInput(x) FD_ISSET(x, &input_set) #define CheckOutput(x) FD_ISSET(x, &output_set) #endif mudstate.debug_cmd = (char *) "< shovechars >"; sock = make_socket(port); maxd = sock + 1; get_tod(&last_slice); #ifdef HAVE_GETDTABLESIZE maxfds = getdtablesize(); #else maxfds = sysconf(_SC_OPEN_MAX); #endif #ifdef TLI fds = (struct pollfd *) XMALLOC(sizeof(struct pollfd) * maxfds, "shovechars"); #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); #ifdef TLI for (i = 0; i < maxfds; i++) fds[i].fd = -1; #else FD_ZERO(&input_set); FD_ZERO(&output_set); #endif /* Listen for new connections if there are free descriptors */ if (ndescriptors < avail_descriptors) { #ifdef TLI fds[sock].fd = sock; fds[sock].events = POLLIN; #else FD_SET(sock, &input_set); #endif } /* Mark sockets that we want to test for change in status */ DESC_ITER_ALL(d) { #ifdef TLI if (!d->input_head || d->output_head) { fds[d->descriptor].fd = d->descriptor; fds[d->descriptor].events = 0; if (!d->input_head) fds[d->descriptor].events |= POLLIN; if (d->output_head) fds[d->descriptor].events |= POLLOUT; } #else if (!d->input_head) FD_SET(d->descriptor, &input_set); if (d->output_head) FD_SET(d->descriptor, &output_set); #endif } /* Wait for something to happen */ #ifdef TLI found = poll(fds, maxfds, timeout.tv_sec); #else found = select(maxd, &input_set, &output_set, (fd_set *) NULL, &timeout); #endif if (found < 0) { if (errno != EINTR) { log_perror("NET", "FAIL", "checking for activity", "select"); } continue; } /* if !found then time for robot commands */ if (!found) { do_top(mudconf.queue_chunk); continue; } else { do_top(mudconf.active_q_chunk); } /* Check for new connection requests */ check = CheckInput(sock); if (check) { newd = new_connection(sock); if (!newd) { #ifdef TLI check = (errno && (errno != ENFILE)); #else check = (errno && (errno != EINTR) && (errno != EMFILE) && (errno != ENFILE)); #endif 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 */ check = CheckInput(d->descriptor); if (check) { /* Undo autodark */ d->last_time = mudstate.now; if (d->flags & DS_AUTODARK) { d->flags &= ~DS_AUTODARK; s_Flags(d->player, Flags(d->player) & ~DARK); } /* Process received data */ if (!process_input(d)) { shutdownsock(d, R_SOCKDIED); continue; } } /* Process output for sockets with pending output */ check = CheckOutput(d->descriptor); if (check) { if (!process_output(d)) { shutdownsock(d, R_SOCKDIED); } } } } } const char * addrout(a) struct in_addr a; { extern char *inet_ntoa(); if (mudconf.use_hostname) { struct hostent *he; he = gethostbyaddr((char *) &a.s_addr, sizeof(a.s_addr), AF_INET); if (he) return he->h_name; else return (inet_ntoa(a)); } else return (inet_ntoa(a)); } #ifdef TLI static void log_tli_error(key, routine, err, t_err) const char *key, *routine; int err, t_err; { char *buff; STARTLOG(LOG_NET, "NET", "BIND") buff = alloc_mbuf("log_tli_error"); sprintf(buff, "%s failed, errno=%d(%s), t_errno=%d(%s)", routine, err, sys_errlist[err], t_err, t_errlist[t_err]); log_text(buff); free_mbuf(buff); ENDLOG } #endif #ifdef TLI struct t_call *nc_call = (struct t_call *) NULL; #endif DESC * new_connection(sock) int sock; { int newsock; char *buff, *buff1, *cmdsave; DESC *d; struct sockaddr_in addr; #ifndef TLI int addr_len; #else int ret; #endif cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *) "< new_connection >"; #ifdef TLI if (!nc_call) { nc_call = (struct t_call *) t_alloc(sock, T_CALL, T_ALL); if (!nc_call) return 0; } if (t_listen(sock, nc_call) < 0) return 0; sighold(SIGALRM); newsock = t_open(TLI_TCP, (O_RDWR | O_NDELAY), NULL); sigrelse(SIGALRM); if (newsock < 0) { log_tli_error("RES", "t_open", errno, t_errno); return (0); } sighold(SIGALRM); ret = t_bind(newsock, NULL, NULL); sigrelse(SIGALRM); if (ret < 0) { log_tli_error("BIND", "t_bind", errno, t_errno); t_close(newsock); return (0); } sighold(SIGALRM); ret = t_accept(sock, newsock, nc_call); sigrelse(SIGALRM); if (ret < 0) { log_tli_error("RES", "t_accept", errno, t_errno); t_close(newsock); return (0); } /* push the read/write support module on the stream */ sighold(SIGALRM); ret = ioctl(newsock, I_PUSH, "tirdwr"); sigrelse(SIGALRM); if (ret < 0) { log_tli_error("STRM", "ioctl I_PUSH", errno, t_errno); t_close(newsock); return 0; } bcopy(nc_call->addr.buf, &addr, sizeof(struct sockaddr_in)); #else addr_len = sizeof(struct sockaddr); newsock = accept(sock, (struct sockaddr *) &addr, &addr_len); if (newsock < 0) return 0; #endif /* TLI */ 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, addrout(addr.sin_addr), ntohs(addr.sin_port)); log_text(buff); free_mbuf(buff); ENDLOG fcache_rawdump(newsock, FC_CONN_SITE); SOCKETCLOSE(newsock); errno = 0; d = NULL; } else { buff = alloc_mbuf("new_connection.sitename"); strcpy(buff, addrout(addr.sin_addr)); 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, buff); free_mbuf(buff); mudstate.debug_cmd = cmdsave; } 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; 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, " <%s: %d cmds, %d bytes in, %d bytes out, %d secs>", disc_reasons[reason], d->command_count, d->input_tot, d->output_tot, time(NULL) - d->connected_at); 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, " <%s: %d cmds, %d bytes in, %d bytes out, %d secs>", disc_reasons[reason], d->command_count, d->input_tot, d->output_tot, time(NULL) - d->connected_at); 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), TYPE_PLAYER); sprintf(buff, "%d %s %d %d %d %d [%s] <%s> %s", d->player, buff2, d->command_count, (int) 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 { SOCKETCLOSE(d->descriptor); freeqs(d); *d->prev = d->next; if (d->next) d->next->prev = d->prev; free_desc(d); ndescriptors--; } } void make_nonblocking(s) int s; { #ifndef TLI #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 #endif /* not TLI */ } DESC * initializesock(s, a, addr) int s; struct sockaddr_in *a; char *addr; { DESC *d; ndescriptors++; d = alloc_desc("init_sock"); d->descriptor = s; 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'; 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->last_time = 0; strncpy(d->addr, addr, 50); 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; descriptor_list = d; welcome_user(d); return d; } int process_output(d) DESC *d; { TBLOCK *tb, *save; int cnt; char *cmdsave; cmdsave = mudstate.debug_cmd; mudstate.debug_cmd = (char *) "< process_output >"; tb = d->output_head; while (tb != NULL) { while (tb->hdr.nchars > 0) { cnt = WRITE(d->descriptor, tb->hdr.start, tb->hdr.nchars); 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_lbuf(save); d->output_head = tb; if (tb == NULL) d->output_tail = NULL; } 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; do_rwho(NOTHING, NOTHING, RWHO_STOP); DESC_SAFEITER_ALL(d, dnext) { if (emergency) { WRITE(d->descriptor, message, strlen(message)); SOCKETCLOSE(d->descriptor); } else { queue_string(d, message); queue_write(d, "\r\n", 2); shutdownsock(d, R_GOING_DOWN); } } SOCKETCLOSE(sock); } void NDECL(emergency_shutdown) { close_sockets(1, (char *) "Going down - Bye"); } /* --------------------------------------------------------------------------- * Signal handling routines. */ #ifndef SIGCHLD #define SIGCHLD SIGCLD #endif static RETSIGTYPE sighandler(); NAMETAB sigactions_nametab[] = { {(char *) "resignal", 3, 0, SA_RESIG}, {(char *) "retry", 3, 0, SA_RETRY}, {(char *) "default", 1, 0, SA_DFLT}, {NULL, 0, 0, 0}}; 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); #ifdef SIGXCPU signal(SIGXCPU, sighandler); #endif #ifndef linux /* linux generates SIGFPE for all exceptions */ signal(SIGFPE, sighandler); #else signal(SIGFPE, SIG_IGN); #endif /* linux */ if (mudconf.sig_action != SA_DFLT) { signal(SIGILL, sighandler); signal(SIGTRAP, sighandler); 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 HAVE_SYS_SIGLIST #ifdef NEED_SYS_SIGLIST_DCL extern char *sys_siglist[]; #endif #define signames sys_siglist #else /* HAVE_SYS_SIGLIST */ #ifdef HAVE__SYS_SIGLIST #ifdef NEED__SYS_SIGLIST_DCL extern char *_sys_siglist[]; #endif #define signames _sys_siglist #else /* HAVE__SYS_SIGLIST */ 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 /* HAVE__SYS_SIGLIST */ #endif /* HAVE_SYS_SIGLIST */ char buff[32]; #ifdef HAVE_UNION_WAIT union wait stat; #else int stat; #endif switch (sig) { 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 + coredump */ case SIGTRAP: case SIGFPE: case SIGSEGV: #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(); sprintf(buff, "Caught signal %s", signames[sig]); do_shutdown(NOTHING, NOTHING, SHUTDN_PANIC, buff); /* Either resignal, or clear signal handling and retry the * failed operation. It should still fail, we haven't done * anything to fix it, but it just _might_ succeed. If * that happens things will go downhill rapidly because we * have closed all our files and cleaned up. On the other * hand, retrying the failing operation usually gets a * usable coredump, whereas aborting from within the * signal handler often doesn't. */ unset_signals(); if (mudconf.sig_action == SA_RESIG) signal(sig, SIG_DFL); else return; exit(1); case SIGABRT: /* Coredump. */ check_panicking(sig); log_signal(signames[sig]); report(); unset_signals(); if (mudconf.sig_action == SA_RESIG) signal(sig, SIG_DFL); else return; exit(1); } signal(sig, sighandler); mudstate.panicking = 0; #ifdef VMS return 1; #else return; #endif } #ifdef LOCAL_RWHO_SERVER void dump_rusers(call_by) DESC *call_by; { struct sockaddr_in addr; struct hostent *hp; char *rbuf, *p, *srv; int fd, red; if (!(mudconf.control_flags & CF_ALLOW_RWHO)) { queue_string(call_by, "RWHO is not available now.\r\n"); return; } p = srv = mudconf.rwho_host; while ((*p != '\0') && ((*p == '.') || isdigit(*p))) p++; if (*p != '\0') { if ((hp = gethostbyname(srv)) == (struct hostent *) NULL) { queue_string(call_by, "Error connecting to rwho.\r\n"); return; } (void) bcopy(hp->h_addr, (char *) &addr.sin_addr, hp->h_length); } else { unsigned long f; if ((f = inet_addr(srv)) == -1L) { queue_string(call_by, "Error connecting to rwho.\r\n"); return; } (void) bcopy((char *) &f, (char *) &addr.sin_addr, sizeof(f)); } addr.sin_port = htons(mudconf.rwho_data_port); addr.sin_family = AF_INET; #ifdef TLI fd = tf_topen(TLI_TCP, O_RDWR); if (fd = <0) { queue_string(call_by, "Error in connecting to rwhod.\r\n"); return; } if (t_bind(fd, NULL, NULL) < 0) { tf_close(fd); queue_string(call_by, "Error in connecting to rwhod.\r\n"); return; } call = (struct t_call *) t_alloc(fd, T_CALL, T_ALL); if (call == NULL) { tf_close(fd); queue_string(call_by, "Error in connecting to rwhod.\r\n"); return; } bcopy(addr, pbuf->addr.buf, sizeof(struct sockaddr_in)); call->addr.len = sizeof(struct sockaddr_in); #else fd = tf_socket(AF_INET, SOCK_STREAM); if (fd < 0) { queue_string(call_by, "Error in connecting to rwhod.\r\n"); return; } #endif #ifdef TLI if (t_connect(fd, call, NULL) < 0) queue_string(call_by, "Error in connecting to rwhod.\r\n"); tf_close(fd); return; } if (ioctl(fd, I_PUSH, "tirdwr") < 0) { queue_string(call_by, "Error in connecting to rwhod.\r\n"); tf_close(fd); return; } #else if (connect(fd, &addr, sizeof(addr)) < 0) { queue_string(call_by, "Error in connecting to rwhod.\r\n"); tf_close(fd); return; } #endif rbuf = alloc_lbuf("dump_rusers"); red = 0; while ((red = READ(fd, rbuf, LBUF_SIZE)) > 0) { rbuf[red] = '\0'; queue_string(call_by, rbuf); } free_lbuf(rbuf); tf_close(fd); } #endif /* LOCAL_RWHO_SERVER */