/* 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 */