/* game.c -- initialization stuff */ #include "autoconf.h" #include "copyright.h" #ifndef lint static char *RCSid = "$Id: game.c,v 1.9 1995/03/21 00:00:27 ambar Exp $"; USE(RCSid); #endif #include "interface.h" #include "file_c.h" #include "match.h" #include "flags.h" #include "attrs.h" #include "rwho_clilib.h" extern void NDECL(init_attrtab); extern void NDECL(init_cmdtab); extern void NDECL(cf_init); extern void NDECL(pcache_init); extern int FDECL(cf_read, (char *fn)); extern void NDECL(init_functab); extern void FDECL(close_sockets, (int emergency, char *message)); extern void NDECL(init_version); extern void NDECL(init_logout_cmdtab); extern void NDECL(init_timer); extern void FDECL(raw_notify, (dbref, const char *)); extern void NDECL(do_second); extern void FDECL(do_dbck, (dbref, dbref, int)); void FDECL(fork_and_dump, (int)); void NDECL(dump_database); void NDECL(pcache_sync); static void FDECL(dump_database_internal, (int)); static void NDECL(init_rlimit); int reserved; /* * used to allocate storage for temporary stuff, cleared before command * execution */ void do_dump(player, cause, key) dbref player, cause; int key; { notify(player, "Dumping..."); fork_and_dump(key); } /* print out stuff into error file */ void NDECL(report) { STARTLOG(LOG_BUGS, "BUG", "INFO") log_text((char *) "Command: '"); log_text(mudstate.debug_cmd); log_text((char *) "'"); ENDLOG if (Good_obj(mudstate.curr_player)) { STARTLOG(LOG_BUGS, "BUG", "INFO") log_text((char *) "Player: "); log_name_and_loc(mudstate.curr_player); if ((mudstate.curr_enactor != mudstate.curr_player) && Good_obj(mudstate.curr_enactor)) { log_text((char *) " Enactor: "); log_name_and_loc(mudstate.curr_enactor); } ENDLOG } } /* ---------------------------------------------------------------------- * atr_match: Check attribute list for wild card matches and queue them. */ static int atr_match1(thing, parent, player, type, str, raw_str, check_exclude, hash_insert) dbref thing, parent, player; char type, *str, *raw_str; int check_exclude, hash_insert; { dbref aowner; int match, attr, aflags, i; char *buff, *s, *as; char *args[10]; ATTR *ap; /* See if we can do it. Silently fail if we can't. */ if (!could_doit(player, parent, A_LUSE)) return -1; match = 0; buff = alloc_lbuf("atr_match1"); atr_push(); for (attr = atr_head(parent, &as); attr; attr = atr_next(&as)) { ap = atr_num(attr); /* Never check NOPROG attributes. */ if (!ap || (ap->flags & AF_NOPROG)) continue; /* If we aren't the bottom level check if we saw this attr * before. Also exclude it if the attribute type is PRIVATE. */ if (check_exclude && ((ap->flags & AF_PRIVATE) || nhashfind(ap->number, &mudstate.parent_htab))) { continue; } atr_get_str(buff, parent, attr, &aowner, &aflags); /* Skip if private and on a parent */ if (check_exclude && (aflags & AF_PRIVATE)) { continue; } /* If we aren't the top level remember this attr so we exclude * it from now on. */ if (hash_insert) nhashadd(ap->number, (int *) &attr, &mudstate.parent_htab); /* Check for the leadin character after excluding the attrib * This lets non-command attribs on the child block commands * on the parent. */ if ((buff[0] != type) || (aflags & AF_NOPROG)) continue; /* decode it: search for first un escaped : */ for (s = buff + 1; *s && (*s != ':'); s++); if (!*s) continue; *s++ = 0; if (wild_match(buff + 1, ((aflags & AF_NOPARSE) ? raw_str : str), args, 10, 0)) { match = 1; wait_que(thing, player, 0, NOTHING, s, args, 10, mudstate.global_regs); for (i = 0; i < 10; i++) { if (args[i]) free_lbuf(args[i]); } } } atr_pop(); free_lbuf(buff); return (match); } int atr_match(thing, player, type, str, raw_str, check_parents) dbref thing, player; char type, *str, *raw_str; int check_parents; { int match, lev, result, exclude, insert; dbref parent; /* If thing is halted, or it doesn't have a COMMANDS flag and we're * we're doing a $-match, don't check it. */ if (((type == AMATCH_CMD) && !Has_Commands(thing) && mudconf.req_cmds_flag) || Halted(thing)) return 0; /* If not checking parents, just check the thing */ match = 0; if (!check_parents) return atr_match1(thing, thing, player, type, str, raw_str, 0, 0); /* Check parents, ignoring halted objects */ exclude = 0; insert = 1; nhashflush(&mudstate.parent_htab, 0); ITER_PARENTS(thing, parent, lev) { if (!Good_obj(Parent(parent))) insert = 0; result = atr_match1(thing, parent, player, type, str, raw_str, exclude, insert); if (result > 0) { match = 1; } else if (result < 0) { return match; } exclude = 1; } return match; } /* --------------------------------------------------------------------------- * notify_check: notifies the object #target of the message msg, and * optionally notify the contents, neighbors, and location also. */ int check_filter(object, player, filter, msg) dbref object, player; int filter; const char *msg; { int aflags; dbref aowner; char *buf, *nbuf, *cp, *dp, *preserve[MAX_GLOBAL_REGS]; buf = atr_pget(object, filter, &aowner, &aflags); if (!*buf) { free_lbuf(buf); return (1); } save_global_regs("check_filter_save", preserve); dp = nbuf = exec(object, player, EV_FIGNORE | EV_EVAL | EV_TOP, buf, (char **) NULL, 0); free_lbuf(buf); restore_global_regs("check_filter_restore", preserve); do { cp = parse_to(&dp, ',', EV_STRIP); if (quick_wild(cp, (char *) msg)) { free_lbuf(nbuf); return (0); } } while (dp != NULL); free_lbuf(nbuf); return (1); } static char * add_prefix(object, player, prefix, msg, dflt) dbref object, player; int prefix; const char *msg, *dflt; { int aflags; dbref aowner; char *buf, *nbuf, *cp, *preserve[MAX_GLOBAL_REGS]; buf = atr_pget(object, prefix, &aowner, &aflags); if (!*buf) { cp = buf; safe_str((char *) dflt, buf, &cp); } else { save_global_regs("add_prefix_save", preserve); nbuf = exec(object, player, EV_FIGNORE | EV_EVAL | EV_TOP, buf, (char **) NULL, 0); free_lbuf(buf); restore_global_regs("add_prefix_restore", preserve); buf = nbuf; cp = &buf[strlen(buf)]; } if (cp != buf) safe_str((char *) " ", buf, &cp); safe_str((char *) msg, buf, &cp); return (buf); } static char * dflt_from_msg(sender, sendloc) dbref sender, sendloc; { char *tp, *tbuff; tp = tbuff = alloc_lbuf("notify_check.fwdlist"); safe_str((char *) "From ", tbuff, &tp); if (Good_obj(sendloc)) safe_str(Name(sendloc), tbuff, &tp); else safe_str(Name(sender), tbuff, &tp); safe_chr(',', tbuff, &tp); return tbuff; } #ifdef PUEBLO_SUPPORT /* Do HTML escaping, converting < to <, etc. 'dest' needs to be * allocated & freed by the caller. * * If you're using this to append to a string, you can pass in the * safe_{str|chr} (char **) so we can just do the append directly, * saving you an alloc_lbuf()...free_lbuf(). If you want us to append * from the start of 'dest', just pass in a 0 for 'destp'. * * Returns 0 if the copy succeeded, 1 if it failed. */ int html_escape(src, dest, destp) const char *src; char *dest; char **destp; { static char new_buf[LBUF_SIZE * 5]; const char *msg_orig; char *mp_escaped; char *temp, *bufp; if (destp == 0) { temp = dest; destp = &temp; } for (*new_buf = '\0', bufp = new_buf, msg_orig = src; msg_orig && *msg_orig; msg_orig++) { switch (*msg_orig) { case '<': *bufp = '\0'; strcat(new_buf, (char *) "<"); bufp += 4; break; case '>': *bufp = '\0'; strcat(new_buf, (char *) ">"); bufp += 4; break; case '&': *bufp = '\0'; strcat(new_buf, (char *) "&"); bufp += 5; break; case '\"': *bufp = '\0'; strcat(new_buf, (char *) """); bufp += 6; break; default: *bufp++ = *msg_orig; break; } } *bufp = '\0'; safe_str(new_buf, dest, destp); destp = '\0'; return; } #endif /* PUEBLO_SUPPORT */ void notify_check(target, sender, msg, key) dbref target, sender; int key; const char *msg; { char *msg_ns, *mp, *tbuff, *tp, *buff; char *args[10]; dbref aowner, targetloc, recip, obj; int i, nargs, aflags, has_neighbors, pass_listen; int check_listens, pass_uselock, is_audible; FWDLIST *fp; /* If speaker is invalid or message is empty, just exit */ if (!Good_obj(target) || !msg || !*msg) return; /* Enforce a recursion limit */ mudstate.ntfy_nest_lev++; if (mudstate.ntfy_nest_lev >= mudconf.ntfy_nest_lim) { mudstate.ntfy_nest_lev--; return; } /* If we want NOSPOOF output, generate it. It is only needed if * we are sending the message to the target object */ if (key & MSG_ME) { mp = msg_ns = alloc_lbuf("notify_check"); if (Nospoof(target) && (target != sender) && (target != mudstate.curr_enactor) && (target != mudstate.curr_player)) { /* I'd really like to use tprintf here but I can't * because the caller may have. * notify(target, tprintf(...)) is quite common in * the code. */ tbuff = alloc_sbuf("notify_check.nospoof"); safe_chr('[', msg_ns, &mp); safe_str(Name(sender), msg_ns, &mp); *tbuff = '('; tbuff[1] = '#'; ltos(&tbuff[2], sender); safe_str(tbuff, msg_ns, &mp); safe_chr(')', msg_ns, &mp); if (sender != Owner(sender)) { safe_chr('{', msg_ns, &mp); safe_str(Name(Owner(sender)), msg_ns, &mp); safe_chr('}', msg_ns, &mp); } if (sender != mudstate.curr_enactor) { strcpy(tbuff, (const char *) "<-(#"); ltos(&tbuff[4], mudstate.curr_enactor); safe_str(tbuff, msg_ns, &mp); safe_chr(')', msg_ns, &mp); } safe_str((char *) "] ", msg_ns, &mp); free_sbuf(tbuff); } safe_long_str((char *) msg, msg_ns, &mp); } else { msg_ns = NULL; } /* msg contains the raw message, msg_ns contains the NOSPOOFed msg */ check_listens = Halted(target) ? 0 : 1; switch (Typeof(target)) { case TYPE_PLAYER: #ifndef PUEBLO_SUPPORT if (key & MSG_ME) raw_notify(target, msg_ns); #else if (key & MSG_ME) { if (key & MSG_HTML) { raw_notify_html(target, msg_ns); } else { if (Html(target)) { char *msg_ns_escaped; msg_ns_escaped = alloc_lbuf("notify_check_escape"); html_escape(msg_ns, msg_ns_escaped, 0); raw_notify(target, msg_ns_escaped); free_lbuf(msg_ns_escaped); } else { raw_notify(target, msg_ns); } } } #endif /* ! PUEBLO_SUPPORT */ if (!mudconf.player_listen) check_listens = 0; case TYPE_THING: case TYPE_ROOM: /* Forward puppet message if it is for me */ has_neighbors = Has_location(target); targetloc = where_is(target); is_audible = Audible(target); if ((key & MSG_ME) && Puppet(target) && (target != Owner(target)) && ((key & MSG_PUP_ALWAYS) || ((targetloc != Location(Owner(target))) && (targetloc != Owner(target))))) { tp = tbuff = alloc_lbuf("notify_check.puppet"); safe_str(Name(target), tbuff, &tp); safe_str((char *) "> ", tbuff, &tp); safe_str(msg_ns, tbuff, &tp); raw_notify(Owner(target), tbuff); free_lbuf(tbuff); } /* Check for @Listen match if it will be useful */ pass_listen = 0; nargs = 0; if (check_listens && (key & (MSG_ME | MSG_INV_L)) && H_Listen(target)) { tp = atr_get(target, A_LISTEN, &aowner, &aflags); if (*tp && wild_match(tp, (char *) msg, args, 10, 0)) { for (nargs = 10; nargs && (!args[nargs - 1] || !(*args[nargs - 1])); nargs--); pass_listen = 1; } free_lbuf(tp); } /* If we matched the @listen or are monitoring, check the * USE lock */ pass_uselock = 0; if ((key & MSG_ME) && check_listens && (pass_listen || Monitor(target))) pass_uselock = could_doit(sender, target, A_LUSE); /* Process AxHEAR if we pass LISTEN, USElock and it's for me */ if ((key & MSG_ME) && pass_listen && pass_uselock) { if (sender != target) did_it(sender, target, 0, NULL, 0, NULL, A_AHEAR, args, nargs); else did_it(sender, target, 0, NULL, 0, NULL, A_AMHEAR, args, nargs); did_it(sender, target, 0, NULL, 0, NULL, A_AAHEAR, args, nargs); } /* Get rid of match arguments. We don't need them anymore */ if (pass_listen) { for (i = 0; i < nargs; i++) if (args[i] != NULL) free_lbuf(args[i]); } /* Process ^-listens if for me, MONITOR, and we pass USElock */ if ((key & MSG_ME) && pass_uselock && (sender != target) && Monitor(target)) { (void) atr_match(target, sender, AMATCH_LISTEN, (char *) msg, (char *) msg, 0); } /* Deliver message to forwardlist members */ if ((key & MSG_FWDLIST) && Audible(target) && check_filter(target, sender, A_FILTER, msg)) { tbuff = dflt_from_msg(sender, target); buff = add_prefix(target, sender, A_PREFIX, msg, tbuff); free_lbuf(tbuff); fp = fwdlist_get(target); if (fp) { for (i = 0; i < fp->count; i++) { recip = fp->data[i]; if (!Good_obj(recip) || (recip == target)) continue; notify_check(recip, sender, buff, (MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE)); } } free_lbuf(buff); } /* Deliver message through audible exits */ if (key & MSG_INV_EXITS) { DOLIST(obj, Exits(target)) { recip = Location(obj); if (Audible(obj) && ((recip != target) && check_filter(obj, sender, A_FILTER, msg))) { buff = add_prefix(obj, target, A_PREFIX, msg, "From a distance,"); notify_check(recip, sender, buff, MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE); free_lbuf(buff); } } } /* Deliver message through neighboring audible exits */ if (has_neighbors && ((key & MSG_NBR_EXITS) || ((key & MSG_NBR_EXITS_A) && is_audible))) { /* If from inside, we have to add the prefix string of * the container. */ if (key & MSG_S_INSIDE) { tbuff = dflt_from_msg(sender, target); buff = add_prefix(target, sender, A_PREFIX, msg, tbuff); free_lbuf(tbuff); } else { buff = (char *) msg; } DOLIST(obj, Exits(Location(target))) { recip = Location(obj); if (Good_obj(recip) && Audible(obj) && (recip != targetloc) && (recip != target) && check_filter(obj, sender, A_FILTER, msg)) { tbuff = add_prefix(obj, target, A_PREFIX, buff, "From a distance,"); notify_check(recip, sender, tbuff, MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE); free_lbuf(tbuff); } } if (key & MSG_S_INSIDE) { free_lbuf(buff); } } if (Bouncer(target)) pass_listen = 1; /* Deliver message to contents */ if (((key & MSG_INV) || ((key & MSG_INV_L) && pass_listen)) && (check_filter(target, sender, A_INFILTER, msg))) { /* Don't prefix the message if we were given the * MSG_NOPREFIX key. */ if (key & MSG_S_OUTSIDE) { buff = add_prefix(target, sender, A_INPREFIX, msg, ""); } else { buff = (char *) msg; } DOLIST(obj, Contents(target)) { if (obj != target) { #ifdef PUEBLO_SUPPORT notify_check(obj, sender, buff, MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE | (key & MSG_HTML)); #else notify_check(obj, sender, buff, MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE); #endif /* PUEBLO_SUPPORT */ } } if (key & MSG_S_OUTSIDE) free_lbuf(buff); } /* Deliver message to neighbors */ if (has_neighbors && ((key & MSG_NBR) || ((key & MSG_NBR_A) && is_audible && check_filter(target, sender, A_FILTER, msg)))) { if (key & MSG_S_INSIDE) { tbuff = dflt_from_msg(sender, target); buff = add_prefix(target, sender, A_PREFIX, msg, ""); free_lbuf(tbuff); } else { buff = (char *) msg; } DOLIST(obj, Contents(targetloc)) { if ((obj != target) && (obj != targetloc)) { notify_check(obj, sender, buff, MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE); } } if (key & MSG_S_INSIDE) { free_lbuf(buff); } } /* Deliver message to container */ if (has_neighbors && ((key & MSG_LOC) || ((key & MSG_LOC_A) && is_audible && check_filter(target, sender, A_FILTER, msg)))) { if (key & MSG_S_INSIDE) { tbuff = dflt_from_msg(sender, target); buff = add_prefix(target, sender, A_PREFIX, msg, tbuff); free_lbuf(tbuff); } else { buff = (char *) msg; } notify_check(targetloc, sender, buff, MSG_ME | MSG_F_UP | MSG_S_INSIDE); if (key & MSG_S_INSIDE) { free_lbuf(buff); } } } if (msg_ns) free_lbuf(msg_ns); mudstate.ntfy_nest_lev--; } void notify_except(loc, player, exception, msg) dbref loc, player, exception; const char *msg; { dbref first; if (loc != exception) notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A)); DOLIST(first, Contents(loc)) { if (first != exception) { notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE)); } } } void notify_except2(loc, player, exc1, exc2, msg) dbref loc, player, exc1, exc2; const char *msg; { dbref first; if ((loc != exc1) && (loc != exc2)) notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A)); DOLIST(first, Contents(loc)) { if (first != exc1 && first != exc2) { notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE)); } } } void do_shutdown(player, cause, key, message) dbref player, cause; int key; char *message; { int fd; if (key & SHUTDN_COREDUMP) { if (player != NOTHING) { raw_broadcast(0, "Game: Aborted by %s", Name(Owner(player))); STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN") log_text((char *) "Abort and coredump by "); log_name(player); ENDLOG } /* Don't bother to even shut down the network or dump. Die. Die now. */ abort(); } if (player != NOTHING) { raw_broadcast(0, "Game: Shutdown by %s", Name(Owner(player))); STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN") log_text((char *) "Shutdown by "); log_name(player); ENDLOG } else { raw_broadcast(0, "Game: Fatal Error: %s", message); STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN") log_text((char *) "Fatal error: "); log_text(message); ENDLOG } STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN") log_text((char *) "Shutdown status: "); log_text(message); ENDLOG fd = tf_open(mudconf.status_file, O_RDWR | O_CREAT | O_TRUNC); (void) write(fd, message, strlen(message)); (void) write(fd, (char *) "\n", 1); tf_close(fd); /* Do we perform a normal or an emergency shutdown? Normal shutdown * is handled by exiting the main loop in shovechars, emergency * shutdown is done here. */ if (key & SHUTDN_PANIC) { /* Close down the network interface */ emergency_shutdown(); /* Close the attribute text db and dump the header db */ pcache_sync(); SYNC; CLOSE; STARTLOG(LOG_ALWAYS, "DMP", "PANIC") log_text((char *) "Panic dump: "); log_text(mudconf.crashdb); ENDLOG dump_database_internal(1); STARTLOG(LOG_ALWAYS, "DMP", "DONE") log_text((char *) "Panic dump complete: "); log_text(mudconf.crashdb); ENDLOG } /* Set up for normal shutdown */ mudstate.shutdown_flag = 1; return; } static void dump_database_internal(panic_dump) int panic_dump; { char tmpfile[256], prevfile[256]; FILE *f; if (panic_dump) { unlink(mudconf.crashdb); f = tf_fopen(mudconf.crashdb, O_WRONLY | O_CREAT | O_TRUNC); if (f != NULL) { db_write(f, F_MUSH, OUTPUT_VERSION | OUTPUT_FLAGS); tf_fclose(f); } else { log_perror("DMP", "FAIL", "Opening crash file", mudconf.crashdb); } return; } sprintf(prevfile, "%s.prev", mudconf.outdb); #ifdef VMS sprintf(tmpfile, "%s.-%d-", mudconf.outdb, mudstate.epoch - 1); unlink(tmpfile); /* nuke our predecessor */ sprintf(tmpfile, "%s.-%d-", mudconf.outdb, mudstate.epoch); #else sprintf(tmpfile, "%s.#%d#", mudconf.outdb, mudstate.epoch - 1); unlink(tmpfile); /* nuke our predecessor */ sprintf(tmpfile, "%s.#%d#", mudconf.outdb, mudstate.epoch); #endif /* VMS */ f = tf_fopen(tmpfile, O_WRONLY | O_CREAT | O_TRUNC); if (f) { db_write(f, F_MUSH, OUTPUT_VERSION | OUTPUT_FLAGS); tf_fclose(f); rename(mudconf.outdb, prevfile); if (rename(tmpfile, mudconf.outdb) < 0) log_perror("SAV", "FAIL", "Renaming output file to DB file", tmpfile); } else { log_perror("SAV", "FAIL", "Opening", tmpfile); } } void NDECL(dump_database) { char *buff; mudstate.epoch++; buff = alloc_mbuf("dump_database"); #ifdef VMS sprintf(buff, "%s.-%d-", mudconf.outdb, mudstate.epoch); #else sprintf(buff, "%s.#%d#", mudconf.outdb, mudstate.epoch); #endif /* VMS */ STARTLOG(LOG_DBSAVES, "DMP", "DUMP") log_text((char *) "Dumping: "); log_text(buff); ENDLOG pcache_sync(); SYNC; dump_database_internal(0); STARTLOG(LOG_DBSAVES, "DMP", "DONE") log_text((char *) "Dump complete: "); log_text(buff); ENDLOG free_mbuf(buff); } void fork_and_dump(key) int key; { int child; char *buff; if (*mudconf.dump_msg) raw_broadcast(0, "%s", mudconf.dump_msg); mudstate.epoch++; buff = alloc_mbuf("fork_and_dump"); #ifdef VMS sprintf(buff, "%s.-%d-", mudconf.outdb, mudstate.epoch); #else sprintf(buff, "%s.#%d#", mudconf.outdb, mudstate.epoch); #endif /* VMS */ STARTLOG(LOG_DBSAVES, "DMP", "CHKPT") if (!key || (key & DUMP_TEXT)) { log_text((char *) "SYNCing"); if (!key || (key & DUMP_STRUCT)) log_text((char *) " and "); } if (!key || (key & DUMP_STRUCT)) { log_text((char *) "Checkpointing: "); log_text(buff); } ENDLOG free_mbuf(buff); al_store(); /* Save cached modified attribute list */ if (!key || (key & DUMP_TEXT)) pcache_sync(); SYNC; if (!key || (key & DUMP_STRUCT)) { #ifndef VMS if (mudconf.fork_dump) { if (mudconf.fork_vfork) { child = vfork(); } else { child = fork(); } } else { child = 0; } #else child = 0; #endif /* VMS */ if (child == 0) { dump_database_internal(0); #ifndef VMS if (mudconf.fork_dump) _exit(0); #endif /* VMS */ } else if (child < 0) { log_perror("DMP", "FORK", NULL, "fork()"); } } if (*mudconf.postdump_msg) raw_broadcast(0, "%s", mudconf.postdump_msg); } static int NDECL(load_game) { FILE *f = NULL; char infile[256]; int db_format, db_version, db_flags; strcpy(infile, mudconf.indb); if ((f = tf_fopen(mudconf.indb, O_RDONLY)) == NULL) return -1; /* ok, read it in */ STARTLOG(LOG_STARTUP, "INI", "LOAD") log_text((char *) "Loading: "); log_text(infile); ENDLOG if (db_read(f, &db_format, &db_version, &db_flags) < 0) { STARTLOG(LOG_ALWAYS, "INI", "FATAL") log_text((char *) "Error loading "); log_text(infile); ENDLOG return -1; } STARTLOG(LOG_STARTUP, "INI", "LOAD") log_text((char *) "Load complete."); ENDLOG /* everything ok */ tf_fclose(f); return (0); } /* match a list of things */ int list_check(thing, player, type, str, raw_str, check_parent, stop_status) dbref thing, player; char type, *str, *raw_str; int check_parent; int *stop_status; { int match; match = 0; while (thing != NOTHING) { if ((thing != player) && (atr_match(thing, player, type, str, raw_str, check_parent) > 0)) { match = 1; if (Stop_Match(thing)) { *stop_status = 1; return match; } } thing = Next(thing); } return match; } int Hearer(thing) dbref thing; { char *as, *buff, *s; dbref aowner; int attr, aflags; ATTR *ap; if (Connected(thing) || Puppet(thing)) return 1; if (Monitor(thing)) buff = alloc_lbuf("Hearer"); else buff = NULL; atr_push(); for (attr = atr_head(thing, &as); attr; attr = atr_next(&as)) { if (attr == A_LISTEN) { if (buff) free_lbuf(buff); atr_pop(); return 1; } if (Monitor(thing)) { ap = atr_num(attr); if (!ap || (ap->flags & AF_NOPROG)) continue; atr_get_str(buff, thing, attr, &aowner, &aflags); /* Make sure we can execute it */ if ((buff[0] != AMATCH_LISTEN) || (aflags & AF_NOPROG)) continue; /* Make sure there's a : in it */ for (s = buff + 1; *s && (*s != ':'); s++); if (s) { free_lbuf(buff); atr_pop(); return 1; } } } if (buff) free_lbuf(buff); atr_pop(); return 0; } void do_rwho(player, cause, key) dbref player, cause; int key; { #ifdef RWHO_IN_USE if (key == RWHO_START) { if (!mudstate.rwho_on) { rwhocli_setup(mudconf.rwho_host, mudconf.rwho_info_port, mudconf.rwho_pass, mudconf.mud_name, mudstate.short_ver); rwho_update(); if (!Quiet(player)) notify(player, "RWHO transmission started."); mudstate.rwho_on = 1; } else { notify(player, "RWHO transmission already on."); } } else if (key == RWHO_STOP) { if (mudstate.rwho_on) { rwhocli_shutdown(); if (!Quiet(player)) notify(player, "RWHO transmission stopped."); mudstate.rwho_on = 0; } else { notify(player, "RWHO transmission already off."); } } else { notify(player, "Illegal combination of switches."); } #else notify(player, "RWHO support has not been compiled in to the server."); #endif } void do_readcache(player, cause, key) dbref player, cause; int key; { helpindex_load(player); fcache_load(player); } static void NDECL(process_preload) { dbref thing, parent, aowner; int aflags, lev, i; char *tstr; FWDLIST *fp; fp = (FWDLIST *) alloc_lbuf("process_preload.fwdlist"); tstr = alloc_lbuf("process_preload.string"); i = 0; DO_WHOLE_DB(thing) { /* Ignore GOING objects */ if (Going(thing)) continue; do_top(10); /* Look for a STARTUP attribute in parents */ ITER_PARENTS(thing, parent, lev) { if (Flags(thing) & HAS_STARTUP) { did_it(Owner(thing), thing, 0, NULL, 0, NULL, A_STARTUP, (char **) NULL, 0); /* Process queue entries as we add them */ do_second(); do_top(10); cache_reset(0); break; } } /* Look for a FORWARDLIST attribute */ if (H_Fwdlist(thing)) { (void) atr_get_str(tstr, thing, A_FORWARDLIST, &aowner, &aflags); if (*tstr) { fwdlist_load(fp, GOD, tstr); if (fp->count > 0) fwdlist_set(thing, fp); cache_reset(0); } } } free_lbuf(fp); free_lbuf(tstr); } #ifndef VMS void #endif /* VMS */ main(argc, argv) int argc; char *argv[]; { int mindb; if ((argc > 2) && (!strcmp(argv[1], "-s") && (argc > 3))) { fprintf(stderr, "Usage: %s [-s] [config-file]\n", argv[0]); exit(1); } /* fclose(stdin); fclose(stdout); */ tf_init(); #ifdef IN_MEM_COMPRESSION init_string_compress(); #endif mindb = 0; /* Are we creating a new db? */ time(&mudstate.start_time); pool_init(POOL_LBUF, LBUF_SIZE); pool_init(POOL_MBUF, MBUF_SIZE); pool_init(POOL_SBUF, SBUF_SIZE); pool_init(POOL_BOOL, sizeof(struct boolexp)); pool_init(POOL_DESC, sizeof(DESC)); pool_init(POOL_QENTRY, sizeof(BQUE)); tcache_init(); pcache_init(); cf_init(); init_rlimit(); init_cmdtab(); init_logout_cmdtab(); init_flagtab(); init_functab(); init_attrtab(); init_version(); hashinit(&mudstate.player_htab, 511); nhashinit(&mudstate.fwdlist_htab, 57); nhashinit(&mudstate.parent_htab, 57); nhashinit(&mudstate.desc_htab, 37); if (argc > 1 && !strcmp(argv[1], "-s")) { mindb = 1; if (argc == 3) cf_read(argv[2]); else cf_read((char *) CONF_FILE); } else if (argc == 2) { cf_read(argv[1]); } else { cf_read((char *) CONF_FILE); } fcache_init(); helpindex_init(); if (mindb) unlink(mudconf.gdbm); if (init_gdbm_db(mudconf.gdbm) < 0) { STARTLOG(LOG_ALWAYS, "INI", "LOAD") log_text((char *) "Couldn't load text database: "); log_text(mudconf.gdbm); ENDLOG exit(2); } if (mindb) db_make_minimal(); else if (load_game() < 0) { STARTLOG(LOG_ALWAYS, "INI", "LOAD") log_text((char *) "Couldn't load: "); log_text(mudconf.indb); ENDLOG exit(2); } srandom(getpid()); set_signals(); /* Do a consistency check and set up the freelist */ do_dbck(NOTHING, NOTHING, 0); /* Reset all the hash stats */ hashreset(&mudstate.command_htab); hashreset(&mudstate.logout_cmd_htab); hashreset(&mudstate.func_htab); hashreset(&mudstate.flags_htab); hashreset(&mudstate.attr_name_htab); nhashreset(&mudstate.attr_num_htab); hashreset(&mudstate.player_htab); nhashreset(&mudstate.fwdlist_htab); hashreset(&mudstate.news_htab); hashreset(&mudstate.help_htab); hashreset(&mudstate.wizhelp_htab); nhashreset(&mudstate.desc_htab); for (mindb = 0; mindb < MAX_GLOBAL_REGS; mindb++) mudstate.global_regs[mindb] = alloc_lbuf("main.global_reg"); mudstate.now = time(NULL); process_preload(); STARTLOG(LOG_STARTUP, "INI", "LOAD") log_text((char *) "Startup processing complete."); ENDLOG if (mudconf.rwho_transmit) do_rwho(NOTHING, NOTHING, RWHO_START); /* go do it */ mudstate.now = time(NULL); init_timer(); shovechars(mudconf.port); close_sockets(0, (char *) "Going down - Bye"); dump_database(); CLOSE; exit(0); } static void NDECL(init_rlimit) { #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) struct rlimit *rlp; rlp = (struct rlimit *) alloc_lbuf("rlimit"); if (getrlimit(RLIMIT_NOFILE, rlp)) { log_perror("RLM", "FAIL", NULL, "getrlimit()"); free_lbuf(rlp); return; } rlp->rlim_cur = rlp->rlim_max; if (setrlimit(RLIMIT_NOFILE, rlp)) log_perror("RLM", "FAIL", NULL, "setrlimit()"); free_lbuf(rlp); #else #if defined(_SEQUENT_) && defined(NUMFDS_LIMIT) setdtablesize(NUMFDS_LIMIT); #endif /* Sequent and unlimiting #define'd */ #endif /* HAVE_SETRLIMIT */ }