/*
Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/
#ifndef lint
static char RCSid[] = "$Header: /usr/users/mjr/hacks/umud/RCS/mud.c,v 1.4 91/08/18 21:49:48 mjr Exp $";
#endif
/* configure all options BEFORE including system stuff. */
#include "config.h"
#include <stdio.h>
#ifdef NOSYSTYPES_H
#include <types.h>
#else
#include <sys/types.h>
#endif
#ifndef VMS
#include <sys/param.h>
#endif
#ifdef DAEMON
#include <signal.h>
#endif
#include "mud.h"
#include "sbuf.h"
#include "vars.h"
/* GLOBAL !*/
int cron_quantum = 3600; /* one hour */
static int mud_running = 1;
static char *mud_myname = (char *)0;
time_t cronlast;
time_t currtime;
static int
usage()
{
fprintf(stderr,"usage: mud -c configfile -s startupfile\n");
return(1);
}
/* choke down a file full of commands */
static int
boot_file(path)
char *path;
{
FILE *bfp;
char ibuf[BUFSIZ];
if((bfp = fopen(path,"r")) == (FILE *)0) {
logf("can't open ",path,": ",(char *)-1,"\n",(char *)0);
return(1);
}
while(fgets(ibuf,sizeof(ibuf),bfp) != (char *)0)
if(ibuf[0] != '#' && ibuf[0] != '\n')
(void)run_boot(ibuf);
fclose(bfp);
return(0);
}
/* initiate shutdown (used in signal handlers) */
static void
shutdown_mud()
{
logf("mud is down.\n",(char *)0);
mud_running = 0;
}
/* as simple as possible */
main(ac,av)
int ac;
char *av[];
{
int x;
char *config = (char *)0;
char *startup = (char *)0;
for(x = 1; x < ac; x++) {
if(av[x][0] == '-') {
switch(av[x][1]) {
case 'c':
config = av[++x];
break;
case 's':
startup = av[++x];
break;
default:
exit(usage());
}
} else {
exit(usage());
}
}
/* if there is a configuration file, run it */
if(config != (char *)0 && boot_file(config))
fatal("configure failed.\n",(char *)0);
syminit();
if(io_init()) {
fatal("network init failed\n",(char *)0);
exit(1);
}
if(cache_init()) {
fatal("cache init failed\n",(char *)0);
exit(1);
}
if(DB_INIT()) {
fatal("database init failed\n",(char *)0);
exit(1);
}
/* all I/O layers are initialized, now run startup file if one */
if(startup != (char *)0 && boot_file(startup))
fatal("startup failed.\n",(char *)0);
/* MUD name must be set */
if(mud_myname == (char *)0)
fatal("mud server name is unset\n",(char *)0);
#ifdef DAEMON
(void)signal(SIGINT,shutdown_mud);
(void)signal(SIGTERM,shutdown_mud);
(void)signal(SIGQUIT,shutdown_mud);
#endif
while(mud_running) {
if(io_loop() != 0)
break;
/* flush I/O buffers */
io_sync();
/* reset cache pointers */
cache_reset();
/* maintenance/cron routines ? */
(void)time(&currtime);
if(currtime - cronlast > cron_quantum) {
(void)cron_run(currtime);
cronlast = currtime;
}
/* free any temporarily allocated memory */
tmp_sync();
}
/* orderly shutdown */
(void)cache_sync();
DB_CLOSE();
#ifdef USE_RWHO
rwhocli_shutdown();
#endif
exit(0);
}
/* return our protected name */
char *
mud_getname()
{
return(mud_myname);
}
/* ARGSUSED */
cmd__mudconfig(ac,av,who,aswho)
int ac;
char *av[];
char *who;
char *aswho;
{
if(!strcmp(av[1],"shutdown")) {
logf("shutdown by ",who,"\n",(char *)0);
shutdown_mud();
return(0);
}
if(!strcmp(av[1],"log")) {
if(ac != 3)
return(1);
if(logf_open(av[2]))
return(1);
logf("log is now ",av[2],"\n",(char *)0);
return(0);
}
if(!strcmp(av[1],"chdir")) {
if(ac != 3) {
logf("chdir: must provide directory.\n",(char *)0);
return(1);
}
if(chdir(av[2])) {
logf("cannot cd to ",av[2]," ",(char *)-1,"\n",(char *)0);
return(1);
}
logf("working directory is now ",av[2],"\n",(char *)0);
return(0);
}
if(!strcmp(av[1],"name")) {
if(ac != 3 || av[2][0] == '\0') {
logf("must provide mud name.\n",(char *)0);
return(1);
}
if(mud_myname != (char *)0) {
logf("mud name is already set!\n",(char *)0);
return(1);
}
mud_myname = (char *)malloc((unsigned)strlen(av[2]) + 1);
if(mud_myname == (char *)0)
fatal("cannot allocate mud name buffer!\n",(char *)0);
(void)strcpy(mud_myname,av[2]);
logf("mud name is ",mud_myname,"\n",(char *)0);
return(0);
}
#ifdef DAEMON
/* daemonize ourself */
if(!strcmp(av[1],"daemonize")) {
(void)signal(SIGHUP,SIG_IGN);
(void)signal(SIGCHLD,SIG_IGN);
(void)signal(SIGALRM,SIG_IGN);
if(fork())
exit(0);
#ifdef SETSID
(void)setsid();
#endif
logf("daemonized.\n",(char *)0);
return(0);
}
#endif
/* define a known remote MUD */
if(!strcmp(av[1],"defmud")) {
char *timp = (char *)0;
if(ac < 9 || ac > 10) {
logf("usage: defmud name host symbolichost remotepassword localpassword port playerport [timeout]\n",(char *)0);
return(1);
}
if(ac == 10)
timp = av[9];
if(xmit_def_mudent(av[2],av[3],av[4],av[5],av[6],av[7],av[8],timp)) {
logf("mud entry ",av[2]," NOT defined\n",(char *)0);
return(1);
}
logf("added mud entry ",av[2],"\n",(char *)0);
return(1);
}
if (!strcmp(av[1], "defknownmud")) {
if (ac != 3) {
logf("usage: defknownmud name\n", (char *) 0);
return 1;
}
if (xmit_def_knownmud(av[2])) {
logf("known-mud entry ", av[2], " NOT defined\n", (char *)0);
return 1;
}
logf("added known mud ", av[2], "\n", (char *) 0);
return 1;
}
/* define a global macro */
if(!strcmp(av[1],"defmac")) {
if(ac != 4) {
logf("usage: defmac name macro\n",(char *)0);
return(1);
}
if(symdef(av[2],av[3])) {
logf("macro defn failed ",(char *)-1,"\n",(char *)0);
return(1);
}
logf("defn macro ",av[2],"\n",(char *)0);
return(0);
}
/* UNdefine a global macro */
if(!strcmp(av[1],"undefmac")) {
if(ac != 3) {
logf("usage: undefmac name\n",(char *)0);
return(1);
}
if(symundef(av[2])) {
logf("macro undefined: ",av[2],"\n",(char *)0);
return(1);
}
logf("undefn macro ",av[2],"\n",(char *)0);
return(0);
}
#ifdef USE_RWHO
if(!strcmp(av[1],"rwhoserver")) {
char *info;
if(ac < 4) {
logf("usage: rwhoserver hostname password\n",(char *)0);
return(1);
}
info = ac > 4 ? av[4] : version;
if(mud_myname == (char *)0) {
logf("must set MUD name first\n",(char *)0);
return(1);
}
if(rwhocli_setup(av[2],av[3],mud_myname,info)) {
logf("could not establish RWHO server\n",(char *)0);
return(1);
}
return(0);
}
if(!strcmp(av[1],"rwhodown")) {
rwhocli_shutdown();
logf("rwho service shut down\n",(char *)0);
return(0);
}
if(!strcmp(av[1],"rwhoupdate")) {
update_rwho();
return(0);
}
#endif
/* backup */
if(!strcmp(av[1],"backup")) {
int sequence;
int modulus = 0;
char nxbuf[MAXOID];
char filename[MAXPATHLEN];
FILE *fp;
if(ac != 3 && ac != 4) {
logf("usage: backup <filename> [modulus]\n",(char *)0);
return(1);
}
/* check for modulus */
if( ac == 4 )
modulus = atoi(av[3]);
/* get the backup sequence number */
if(ut_getnum(system_object,var_bsequence,&sequence))
sequence = 0;
sequence++;
if(modulus > 0)
sequence %= modulus;
/* assume this works */
ut_setnum(who,system_object,var_bsequence,sequence);
itoa(sequence,nxbuf);
if(cache_sync()) {
logf("couldn't sync cache for backup #",
nxbuf,"\n",(char *)0);
return(1);
}
sprintf(filename,"%s.%s",av[2],nxbuf);
if(DB_BACKUP(filename)) {
logf("couldn't write backup file ",filename,"\n",
(char *)0);
return(1);
}
logf("wrote backup file ",filename,"\n",(char *)0);
return(0);
}
if(!strcmp(av[1],"help")) {
say(who,av[0]," shutdown\n",(char *)0);
say(who,av[0]," log file-name\n",(char *)0);
say(who,av[0]," chdir directory-name\n",(char *)0);
say(who,av[0]," name mud-name\n",(char *)0);
#ifdef DAEMON
say(who,av[0]," daemonize\n",(char *)0);
#endif
say(who,av[0]," defmud MUDname hostIP-addr hostname remotepassword localpassword serverport playerport [timeout]\n",(char *)0);
say(who,av[0]," defknownmud MUDname\n",(char *)0);
say(who,av[0]," defmac name macro\n",(char *)0);
say(who,av[0]," undefmac name\n",(char *)0);
#ifdef USE_RWHO
say(who,av[0]," rwhoserver hostname password [comment]\n",(char *)0);
say(who,av[0]," rwhodown\n",(char *)0);
#endif
say(who,av[0]," backup file-name [modulus]\n",(char *)0);
return(0);
}
logf("_mudconfig: I don't understand ",av[1],"\n",(char *)0);
return(0);
}