mux/src/game.cpp

Go to the documentation of this file.
00001 // game.cpp
00002 //
00003 // $Id: game.cpp,v 1.93 2006/03/12 22:45:04 sdennis Exp $
00004 //
00005 #include "copyright.h"
00006 #include "autoconf.h"
00007 #include "config.h"
00008 #include "externs.h"
00009 
00010 #include <sys/stat.h>
00011 #include <signal.h>
00012 
00013 #include "attrs.h"
00014 #include "command.h"
00015 #include "functions.h"
00016 #include "comsys.h"
00017 #include "file_c.h"
00018 #include "mguests.h"
00019 #include "muxcli.h"
00020 #include "pcre.h"
00021 #include "powers.h"
00022 #include "help.h"
00023 #ifdef REALITY_LVLS
00024 #include "levels.h"
00025 #endif /* REALITY_LVLS */
00026 
00027 void do_dump(dbref executor, dbref caller, dbref enactor, int key)
00028 {
00029     UNUSED_PARAMETER(caller);
00030     UNUSED_PARAMETER(enactor);
00031 
00032 #ifndef WIN32
00033     if (mudstate.dumping)
00034     {
00035         notify(executor, "Dumping in progress. Try again later.");
00036         return;
00037     }
00038 #endif
00039     notify(executor, "Dumping...");
00040     fork_and_dump(key);
00041 }
00042 
00043 // print out stuff into error file
00044 //
00045 void report(void)
00046 {
00047     STARTLOG(LOG_BUGS, "BUG", "INFO");
00048     log_text("Command: '");
00049     log_text(mudstate.debug_cmd);
00050     log_text("'");
00051     ENDLOG;
00052     if (Good_obj(mudstate.curr_executor))
00053     {
00054         STARTLOG(LOG_BUGS, "BUG", "INFO");
00055         log_text("Player: ");
00056         log_name_and_loc(mudstate.curr_executor);
00057         if (  mudstate.curr_enactor != mudstate.curr_executor
00058            && Good_obj(mudstate.curr_enactor))
00059         {
00060             log_text(" Enactor: ");
00061             log_name_and_loc(mudstate.curr_enactor);
00062         }
00063         ENDLOG;
00064     }
00065 }
00066 
00067 /* ----------------------------------------------------------------------
00068  * regexp_match: Load a regular expression match and insert it into
00069  * registers.
00070  */
00071 
00072 bool regexp_match
00073 (
00074     char *pattern,
00075     char *str,
00076     int case_opt,
00077     char *args[],
00078     int nargs
00079 )
00080 {
00081     int matches;
00082     int i;
00083     const char *errptr;
00084     int erroffset;
00085 
00086     /*
00087      * Load the regexp pattern. This allocates memory which must be
00088      * later freed. A free() of the regexp does free all structures
00089      * under it.
00090      */
00091 
00092     pcre *re;
00093     if (  MuxAlarm.bAlarmed
00094        || (re = pcre_compile(pattern, case_opt, &errptr, &erroffset, NULL)) == NULL)
00095     {
00096         /*
00097          * This is a matching error. We have an error message in
00098          * regexp_errbuf that we can ignore, since we're doing
00099          * command-matching.
00100          */
00101         return false;
00102     }
00103 
00104     // To capture N substrings, you need space for 3(N+1) offsets in the
00105     // offset vector. We'll allow 2N-1 substrings and possibly ignore some.
00106     //
00107     const int ovecsize = 6 * nargs;
00108     int *ovec = new int[ovecsize];
00109 
00110     /*
00111      * Now we try to match the pattern. The relevant fields will
00112      * automatically be filled in by this.
00113      */
00114     matches = pcre_exec(re, NULL, str, strlen(str), 0, 0, ovec, ovecsize);
00115     if (matches < 0)
00116     {
00117         delete [] ovec;
00118         MEMFREE(re);
00119         return false;
00120     }
00121 
00122     if (matches == 0)
00123     {
00124         // There were too many substring matches. See docs for
00125         // pcre_copy_substring().
00126         //
00127         matches = ovecsize / 3;
00128     }
00129 
00130     /*
00131      * Now we fill in our args vector. Note that in regexp matching,
00132      * 0 is the entire string matched, and the parenthesized strings
00133      * go from 1 to 9. We DO PRESERVE THIS PARADIGM, for consistency
00134      * with other languages.
00135      */
00136 
00137     for (i = 0; i < nargs; ++i)
00138     {
00139         args[i] = alloc_lbuf("regexp_match");
00140         if (pcre_copy_substring(str, ovec, matches, i,
00141                                 args[i], LBUF_SIZE) < 0)
00142         {
00143             free_lbuf(args[i]);
00144             args[i] = NULL;
00145         }
00146     }
00147 
00148     delete [] ovec;
00149     MEMFREE(re);
00150     return true;
00151 }
00152 
00153 /* ----------------------------------------------------------------------
00154  * atr_match: Check attribute list for wild card matches and queue them.
00155  */
00156 
00157 static int atr_match1
00158 (
00159     dbref thing,
00160     dbref parent,
00161     dbref player,
00162     char  type,
00163     char  *str,
00164     char  *raw_str,
00165     int   check_exclude,
00166     int   hash_insert
00167 )
00168 {
00169     // See if we can do it.  Silently fail if we can't.
00170     //
00171     if (!could_doit(player, parent, A_LUSE))
00172     {
00173         return -1;
00174     }
00175 
00176     int match = 0;
00177     if (  AMATCH_CMD == type
00178        && mudstate.bfNoCommands.IsSet(parent))
00179     {
00180         return match;
00181     }
00182     else if ( AMATCH_LISTEN == type
00183             && mudstate.bfNoListens.IsSet(parent))
00184     {
00185         return match;
00186     }
00187 
00188     bool bFoundCommands = false;
00189     bool bFoundListens  = false;
00190 
00191     char *as;
00192     atr_push();
00193     for (int atr = atr_head(parent, &as); atr; atr = atr_next(&as))
00194     {
00195         ATTR *ap = atr_num(atr);
00196 
00197         // Never check NOPROG attributes.
00198         //
00199         if (  !ap
00200            || (ap->flags & AF_NOPROG))
00201         {
00202             continue;
00203         }
00204 
00205         // We need to grab the attribute even before we know whether we'll use
00206         // it or not in order to maintain cached knowledge about ^-Commands
00207         // and $-Commands.
00208         //
00209         dbref aowner;
00210         int   aflags;
00211         char buff[LBUF_SIZE];
00212         atr_get_str(buff, parent, atr, &aowner, &aflags);
00213 
00214         if (aflags & AF_NOPROG)
00215         {
00216             continue;
00217         }
00218 
00219         char *s = NULL;
00220         if (  AMATCH_CMD    == buff[0]
00221            || AMATCH_LISTEN == buff[0])
00222         {
00223             s = strchr(buff+1, ':');
00224             if (s)
00225             {
00226                 if (AMATCH_CMD == buff[0])
00227                 {
00228                     bFoundCommands = true;
00229                 }
00230                 else
00231                 {
00232                     bFoundListens = true;
00233                 }
00234             }
00235         }
00236 
00237         // If we aren't the bottom level, check if we saw this attr
00238         // before. Also exclude it if the attribute type is PRIVATE.
00239         //
00240         if (  check_exclude
00241            && (  (ap->flags & AF_PRIVATE)
00242               || (aflags & AF_PRIVATE)
00243               || hashfindLEN(&(ap->number), sizeof(ap->number), &mudstate.parent_htab)))
00244         {
00245             continue;
00246         }
00247 
00248         // If we aren't the top level, remember this attr so we
00249         // exclude it from now on.
00250         //
00251         if (hash_insert)
00252         {
00253             hashaddLEN(&(ap->number), sizeof(ap->number), &atr, &mudstate.parent_htab);
00254         }
00255 
00256         // Check for the leadin character after excluding the attrib.
00257         // This lets non-command attribs on the child block commands
00258         // on the parent.
00259         //
00260         if (buff[0] != type)
00261         {
00262             continue;
00263         }
00264 
00265         // Was there a ':'?
00266         //
00267         if (!s)
00268         {
00269             continue;
00270         }
00271         *s++ = '\0';
00272 
00273         char *args[NUM_ENV_VARS];
00274         if (  (  0 != (aflags & AF_REGEXP)
00275             && regexp_match(buff + 1, (aflags & AF_NOPARSE) ? raw_str : str,
00276                 ((aflags & AF_CASE) ? 0 : PCRE_CASELESS), args, NUM_ENV_VARS))
00277            || (  0 == (aflags & AF_REGEXP)
00278               && wild(buff + 1, (aflags & AF_NOPARSE) ? raw_str : str,
00279                 args, NUM_ENV_VARS)))
00280         {
00281             match = 1;
00282             CLinearTimeAbsolute lta;
00283             wait_que(thing, player, player, false, lta, NOTHING, 0, s,
00284                 args, NUM_ENV_VARS, mudstate.global_regs);
00285 
00286             for (int i = 0; i < NUM_ENV_VARS; i++)
00287             {
00288                 if (args[i])
00289                 {
00290                     free_lbuf(args[i]);
00291                 }
00292             }
00293         }
00294     }
00295     atr_pop();
00296 
00297     if (bFoundCommands)
00298     {
00299         mudstate.bfNoCommands.Clear(parent);
00300         mudstate.bfCommands.Set(parent);
00301     }
00302     else
00303     {
00304         mudstate.bfCommands.Clear(parent);
00305         mudstate.bfNoCommands.Set(parent);
00306     }
00307 
00308     if (bFoundListens)
00309     {
00310         mudstate.bfNoListens.Clear(parent);
00311         mudstate.bfListens.Set(parent);
00312     }
00313     else
00314     {
00315         mudstate.bfListens.Clear(parent);
00316         mudstate.bfNoListens.Set(parent);
00317     }
00318     return match;
00319 }
00320 
00321 bool atr_match
00322 (
00323     dbref thing,
00324     dbref player,
00325     char  type,
00326     char  *str,
00327     char  *raw_str,
00328     bool check_parents
00329 )
00330 {
00331     int lev, result;
00332     bool exclude, insert;
00333     dbref parent;
00334 
00335     // If thing is halted or we are matching $-commands on a NO_COMMAND
00336     // object, don't check anything
00337     //
00338     if (  Halted(thing)
00339        || (  AMATCH_CMD == type
00340           && No_Command(thing)))
00341     {
00342         return false;
00343     }
00344 
00345     // If we're matching ^-commands, strip ANSI
00346     //
00347     if (AMATCH_LISTEN == type)
00348     {
00349         // Remember, strip_ansi returns a pointer to a static buffer
00350         // within itself.
00351         //
00352         size_t junk;
00353         str = strip_ansi(str, &junk);
00354     }
00355 
00356     // If not checking parents, just check the thing
00357     //
00358     bool match = false;
00359     if (!check_parents)
00360     {
00361         return (atr_match1(thing, thing, player, type, str, raw_str, false, false) > 0);
00362     }
00363 
00364     // Check parents, ignoring halted objects
00365     //
00366     exclude = false;
00367     insert = true;
00368     hashflush(&mudstate.parent_htab);
00369     ITER_PARENTS(thing, parent, lev)
00370     {
00371         if (!Good_obj(Parent(parent)))
00372         {
00373             insert = false;
00374         }
00375         result = atr_match1(thing, parent, player, type, str, raw_str,
00376             exclude, insert);
00377         if (result > 0)
00378         {
00379             match = true;
00380         }
00381         else if (result < 0)
00382         {
00383             return match;
00384         }
00385         exclude = true;
00386     }
00387     return match;
00388 }
00389 
00390 /* ---------------------------------------------------------------------------
00391  * notify_check: notifies the object #target of the message msg, and
00392  * optionally notify the contents, neighbors, and location also.
00393  */
00394 
00395 static bool check_filter(dbref object, dbref player, int filter, const char *msg)
00396 {
00397     int aflags;
00398     dbref aowner;
00399     char *buf, *nbuf, *cp, *dp, *str;
00400 
00401     buf = atr_pget(object, filter, &aowner, &aflags);
00402     if (!*buf)
00403     {
00404         free_lbuf(buf);
00405         return true;
00406     }
00407     char **preserve = NULL;
00408     int *preserve_len = NULL;
00409     preserve = PushPointers(MAX_GLOBAL_REGS);
00410     preserve_len = PushIntegers(MAX_GLOBAL_REGS);
00411     save_global_regs("check_filter_save", preserve, preserve_len);
00412     nbuf = dp = alloc_lbuf("check_filter");
00413     str = buf;
00414     mux_exec(nbuf, &dp, object, player, player,
00415              EV_FIGNORE | EV_EVAL | EV_TOP, &str, (char **)NULL, 0);
00416     *dp = '\0';
00417     dp = nbuf;
00418     free_lbuf(buf);
00419     restore_global_regs("check_filter_restore", preserve, preserve_len);
00420     PopIntegers(preserve_len, MAX_GLOBAL_REGS);
00421     PopPointers(preserve, MAX_GLOBAL_REGS);
00422 
00423     if (!(aflags & AF_REGEXP))
00424     {
00425         do
00426         {
00427             cp = parse_to(&dp, ',', EV_STRIP_CURLY);
00428             mudstate.wild_invk_ctr = 0;
00429             if (  MuxAlarm.bAlarmed
00430                || quick_wild(cp, msg))
00431             {
00432                 free_lbuf(nbuf);
00433                 return false;
00434             }
00435         } while (dp != NULL);
00436     }
00437     else
00438     {
00439         int case_opt = (aflags & AF_CASE) ? 0 : PCRE_CASELESS;
00440         do
00441         {
00442             int erroffset;
00443             const char *errptr;
00444             cp = parse_to(&dp, ',', EV_STRIP_CURLY);
00445             pcre *re;
00446             if (  !MuxAlarm.bAlarmed
00447                && (re = pcre_compile(cp, case_opt, &errptr, &erroffset, NULL)) != NULL)
00448             {
00449                 const int ovecsize = 33;
00450                 int ovec[ovecsize];
00451                 int matches = pcre_exec(re, NULL, msg, strlen(msg), 0, 0,
00452                     ovec, ovecsize);
00453                 if (0 <= matches)
00454                 {
00455                     MEMFREE(re);
00456                     free_lbuf(nbuf);
00457                     return false;
00458                 }
00459                 MEMFREE(re);
00460             }
00461         } while (dp != NULL);
00462     }
00463     free_lbuf(nbuf);
00464     return true;
00465 }
00466 
00467 static char *add_prefix(dbref object, dbref player, int prefix,
00468                         const char *msg, const char *dflt)
00469 {
00470     int aflags;
00471     dbref aowner;
00472     char *buf, *nbuf, *cp, *str;
00473 
00474     buf = atr_pget(object, prefix, &aowner, &aflags);
00475     if (!*buf)
00476     {
00477         cp = buf;
00478         safe_str(dflt, buf, &cp);
00479     }
00480     else
00481     {
00482         char **preserve = NULL;
00483         int *preserve_len = NULL;
00484         preserve = PushPointers(MAX_GLOBAL_REGS);
00485         preserve_len = PushIntegers(MAX_GLOBAL_REGS);
00486         save_global_regs("add_prefix_save", preserve, preserve_len);
00487 
00488         nbuf = cp = alloc_lbuf("add_prefix");
00489         str = buf;
00490         mux_exec(nbuf, &cp, object, player, player,
00491                  EV_FIGNORE | EV_EVAL | EV_TOP, &str, (char **)NULL, 0);
00492         free_lbuf(buf);
00493 
00494         restore_global_regs("add_prefix_restore", preserve, preserve_len);
00495         PopIntegers(preserve_len, MAX_GLOBAL_REGS);
00496         PopPointers(preserve, MAX_GLOBAL_REGS);
00497 
00498         buf = nbuf;
00499     }
00500     if (cp != buf)
00501     {
00502         safe_chr(' ', buf, &cp);
00503     }
00504     safe_str(msg, buf, &cp);
00505     *cp = '\0';
00506     return buf;
00507 }
00508 
00509 static char *dflt_from_msg(dbref sender, dbref sendloc)
00510 {
00511     char *tp, *tbuff;
00512 
00513     tp = tbuff = alloc_lbuf("notify_check.fwdlist");
00514     safe_str("From ", tbuff, &tp);
00515     if (Good_obj(sendloc))
00516     {
00517         safe_str(Name(sendloc), tbuff, &tp);
00518     }
00519     else
00520     {
00521         safe_str(Name(sender), tbuff, &tp);
00522     }
00523     safe_chr(',', tbuff, &tp);
00524     *tp = '\0';
00525     return tbuff;
00526 }
00527 
00528 /* Do HTML escaping, converting < to &lt;, etc.  'dest' needs to be
00529  * allocated & freed by the caller.
00530  *
00531  * If you're using this to append to a string, you can pass in the
00532  * safe_{str|chr} (char **) so we can just do the append directly,
00533  * saving you an alloc_lbuf()...free_lbuf().  If you want us to append
00534  * from the start of 'dest', just pass in a 0 for 'destp'.
00535  *
00536  * Returns 0 if the copy succeeded, 1 if it failed.
00537  */
00538 bool html_escape(const char *src, char *dest, char **destp)
00539 {
00540     const char *msg_orig;
00541     bool ret = false;
00542 
00543     if (destp == 0)
00544     {
00545         char *temp = dest;
00546         destp = &temp;
00547     }
00548 
00549     for (msg_orig = src; msg_orig && *msg_orig && !ret; msg_orig++)
00550     {
00551         char *p = *destp;
00552         switch (*msg_orig)
00553         {
00554         case '<':
00555             safe_str("&lt;", dest, destp);
00556             break;
00557 
00558         case '>':
00559             safe_str("&gt;", dest, destp);
00560             break;
00561 
00562         case '&':
00563             safe_str("&amp;", dest, destp);
00564             break;
00565 
00566         case '\"':
00567             safe_str("&quot;", dest, destp);
00568             break;
00569 
00570         default:
00571             safe_chr(*msg_orig, dest, destp);
00572             break;
00573         }
00574 
00575         // For <>&\, this may cause an extra loop around before it figures out that we are
00576         // out of buffer, but no harm is done in this, and the common case is a single character.
00577         //
00578         if (p == *destp)
00579         {
00580             ret = true;
00581         }
00582     }
00583     **destp = 0;
00584     return ret;
00585 }
00586 
00587 void notify_check(dbref target, dbref sender, const char *msg, int key)
00588 {
00589     // If speaker is invalid or message is empty, just exit.
00590     //
00591     if (  !Good_obj(target)
00592        || !msg
00593        || !*msg)
00594     {
00595         return;
00596     }
00597 
00598 #ifdef WOD_REALMS
00599     if ((key & MSG_OOC) == 0)
00600     {
00601         if ((key & MSG_SAYPOSE) != 0)
00602         {
00603             if (REALM_DO_HIDDEN_FROM_YOU == DoThingToThingVisibility(target, sender, ACTION_IS_TALKING))
00604             {
00605                 return;
00606             }
00607         }
00608         else
00609         {
00610             if (REALM_DO_HIDDEN_FROM_YOU == DoThingToThingVisibility(target, sender, ACTION_IS_MOVING))
00611             {
00612                 return;
00613             }
00614         }
00615     }
00616 #endif // WOD_REALMS
00617 
00618     // Enforce a recursion limit
00619     //
00620     mudstate.ntfy_nest_lev++;
00621     if (mudconf.ntfy_nest_lim <= mudstate.ntfy_nest_lev)
00622     {
00623         mudstate.ntfy_nest_lev--;
00624         return;
00625     }
00626 
00627     char *msg_ns, *mp, *tbuff, *tp, *buff;
00628     char *args[NUM_ENV_VARS];
00629     dbref aowner,  recip, obj;
00630     int i, nargs, aflags;
00631     FWDLIST *fp;
00632 
00633     // If we want NOSPOOF output, generate it.  It is only needed if we are
00634     // sending the message to the target object.
00635     //
00636     if (key & MSG_ME)
00637     {
00638         mp = msg_ns = alloc_lbuf("notify_check");
00639         if (  Nospoof(target)
00640            && target != sender
00641            && target != mudstate.curr_enactor
00642            && target != mudstate.curr_executor)
00643         {
00644             // I'd really like to use tprintf here but I can't because the
00645             // caller may have.  notify(target, tprintf(...)) is quite common
00646             // in the code.
00647             //
00648             tbuff = alloc_sbuf("notify_check.nospoof");
00649             safe_chr('[', msg_ns, &mp);
00650             safe_str(Name(sender), msg_ns, &mp);
00651             sprintf(tbuff, "(#%d)", sender);
00652             safe_str(tbuff, msg_ns, &mp);
00653 
00654             if (sender != Owner(sender))
00655             {
00656                 safe_chr('{', msg_ns, &mp);
00657                 safe_str(Name(Owner(sender)), msg_ns, &mp);
00658                 safe_chr('}', msg_ns, &mp);
00659             }
00660             if (sender != mudstate.curr_enactor)
00661             {
00662                 sprintf(tbuff, "<-(#%d)", mudstate.curr_enactor);
00663                 safe_str(tbuff, msg_ns, &mp);
00664             }
00665             safe_str("] ", msg_ns, &mp);
00666             free_sbuf(tbuff);
00667         }
00668         safe_str(msg, msg_ns, &mp);
00669         *mp = '\0';
00670     }
00671     else
00672     {
00673         msg_ns = NULL;
00674     }
00675 
00676     // msg contains the raw message, msg_ns contains the NOSPOOFed msg.
00677     //
00678     bool check_listens = !Halted(target);
00679     switch (Typeof(target))
00680     {
00681     case TYPE_PLAYER:
00682         if (key & MSG_ME)
00683         {
00684             if (key & MSG_HTML)
00685             {
00686                 raw_notify_html(target, msg_ns);
00687             }
00688             else
00689             {
00690                 if (Html(target))
00691                 {
00692                     char *msg_ns_escaped;
00693 
00694                     msg_ns_escaped = alloc_lbuf("notify_check_escape");
00695                     html_escape(msg_ns, msg_ns_escaped, 0);
00696                     raw_notify(target, msg_ns_escaped);
00697                     free_lbuf(msg_ns_escaped);
00698                 }
00699                 else
00700                 {
00701                     raw_notify(target, msg_ns);
00702                 }
00703             }
00704         }
00705         if (!mudconf.player_listen)
00706         {
00707             check_listens = false;
00708         }
00709 
00710         // FALLTHROUGH
00711 
00712     case TYPE_THING:
00713     case TYPE_ROOM:
00714 
00715         // If we're in a pipe, objects can receive raw_notify if
00716         // they're not a player. (players were already notified
00717         // above.
00718         //
00719         if (  mudstate.inpipe
00720            && !isPlayer(target))
00721         {
00722             raw_notify(target, msg_ns);
00723         }
00724 
00725         // Forward puppet message if it is for me.
00726         //
00727         bool has_neighbors = Has_location(target);
00728         dbref targetloc = where_is(target);
00729         bool is_audible = Audible(target);
00730 
00731         if ( (key & MSG_ME)
00732            && Puppet(target)
00733            && (target != Owner(target))
00734            && (  (key & MSG_PUP_ALWAYS)
00735               || (  targetloc != Location(Owner(target))
00736                  && targetloc != Owner(target))))
00737         {
00738             tp = tbuff = alloc_lbuf("notify_check.puppet");
00739             safe_str(Name(target), tbuff, &tp);
00740             safe_str("> ", tbuff, &tp);
00741             safe_str(msg_ns, tbuff, &tp);
00742             *tp = '\0';
00743             raw_notify(Owner(target), tbuff);
00744             free_lbuf(tbuff);
00745         }
00746 
00747         // Check for @Listen match if it will be useful.
00748         //
00749         bool pass_listen = false;
00750         nargs = 0;
00751         if (  check_listens
00752            && (key & (MSG_ME | MSG_INV_L))
00753            && H_Listen(target))
00754         {
00755             tp = atr_get(target, A_LISTEN, &aowner, &aflags);
00756             if (*tp && wild(tp, (char *)msg, args, NUM_ENV_VARS))
00757             {
00758                 for (nargs = NUM_ENV_VARS; nargs && (!args[nargs - 1] || !(*args[nargs - 1])); nargs--)
00759                 {
00760                     ; // Nothing
00761                 }
00762                 pass_listen = true;
00763             }
00764             free_lbuf(tp);
00765         }
00766 
00767         // If we matched the @listen or are monitoring, check the
00768         // USE lock.
00769         //
00770         bool pass_uselock = false;
00771         if (  (key & MSG_ME)
00772            && check_listens
00773            && (  pass_listen
00774               || Monitor(target)))
00775         {
00776             pass_uselock = could_doit(sender, target, A_LUSE);
00777         }
00778 
00779         // Process AxHEAR if we pass LISTEN, USElock and it's for me.
00780         //
00781         if (  (key & MSG_ME)
00782            && pass_listen
00783            && pass_uselock
00784            && mudstate.nHearNest <= 2)
00785         {
00786             mudstate.nHearNest++;
00787             if (sender != target)
00788             {
00789                 did_it(sender, target, 0, NULL, 0, NULL, A_AHEAR, args, nargs);
00790             }
00791             else
00792             {
00793                 did_it(sender, target, 0, NULL, 0, NULL, A_AMHEAR, args,
00794                     nargs);
00795             }
00796             did_it(sender, target, 0, NULL, 0, NULL, A_AAHEAR, args, nargs);
00797             mudstate.nHearNest--;
00798         }
00799 
00800         // Get rid of match arguments. We don't need them anymore.
00801         //
00802         if (pass_listen)
00803         {
00804             for (i = 0; i < nargs; i++)
00805             {
00806                 if (args[i] != NULL)
00807                 {
00808                     free_lbuf(args[i]);
00809                 }
00810             }
00811         }
00812 
00813         // Process ^-listens if for me, MONITOR, and we pass USElock.
00814         //
00815         if (  (key & MSG_ME)
00816            && pass_uselock
00817            && sender != target
00818            && Monitor(target))
00819         {
00820             atr_match(target, sender, AMATCH_LISTEN, (char *)msg, (char *)msg,
00821                 false);
00822         }
00823 
00824         // Deliver message to forwardlist members.
00825         //
00826         if ( (key & MSG_FWDLIST)
00827            && is_audible
00828            && check_filter(target, sender, A_FILTER, msg))
00829         {
00830             tbuff = dflt_from_msg(sender, target);
00831             buff = add_prefix(target, sender, A_PREFIX, msg, tbuff);
00832             free_lbuf(tbuff);
00833 
00834             fp = fwdlist_get(target);
00835             if (fp)
00836             {
00837                 for (i = 0; i < fp->count; i++)
00838                 {
00839                     recip = fp->data[i];
00840                     if (  !Good_obj(recip)
00841                        || recip == target)
00842                     {
00843                         continue;
00844                     }
00845                     notify_check(recip, sender, buff,
00846                              MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE);
00847                 }
00848             }
00849             free_lbuf(buff);
00850         }
00851 
00852         // Deliver message through audible exits.
00853         //
00854         if (key & MSG_INV_EXITS)
00855         {
00856             DOLIST(obj, Exits(target))
00857             {
00858                 recip = Location(obj);
00859                 if (  Audible(obj)
00860                    && (  recip != target
00861                       && check_filter(obj, sender, A_FILTER, msg)))
00862                 {
00863                     buff = add_prefix(obj, target, A_PREFIX, msg,
00864                         "From a distance,");
00865                     notify_check(recip, sender, buff,
00866                         MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE);
00867                     free_lbuf(buff);
00868                 }
00869             }
00870         }
00871 
00872         // Deliver message through neighboring audible exits.
00873         //
00874         if (  has_neighbors
00875            && (  (key & MSG_NBR_EXITS)
00876               || (  (key & MSG_NBR_EXITS_A)
00877                  && is_audible)))
00878         {
00879             // If from inside, we have to add the prefix string of
00880             // the container.
00881             //
00882             if (key & MSG_S_INSIDE)
00883             {
00884                 tbuff = dflt_from_msg(sender, target);
00885                 buff = add_prefix(target, sender, A_PREFIX, msg, tbuff);
00886                 free_lbuf(tbuff);
00887             }
00888             else
00889             {
00890                 buff = (char *)msg;
00891             }
00892 
00893             DOLIST(obj, Exits(Location(target)))
00894             {
00895                 recip = Location(obj);
00896                 if (  Good_obj(recip)
00897                    && Audible(obj)
00898                    && recip != targetloc
00899                    && recip != target
00900                    && check_filter(obj, sender, A_FILTER, msg))
00901                 {
00902                     tbuff = add_prefix(obj, target, A_PREFIX, buff,
00903                         "From a distance,");
00904                     notify_check(recip, sender, tbuff,
00905                         MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE);
00906                     free_lbuf(tbuff);
00907                 }
00908             }
00909             if (key & MSG_S_INSIDE)
00910             {
00911                 free_lbuf(buff);
00912             }
00913         }
00914 
00915         // Deliver message to contents.
00916         //
00917         if (  (  (key & MSG_INV)
00918               || (  (key & MSG_INV_L)
00919                  && pass_listen))
00920            && check_filter(target, sender, A_INFILTER, msg))
00921         {
00922             // Don't prefix the message if we were given the MSG_NOPREFIX key.
00923             //
00924             if (key & MSG_S_OUTSIDE)
00925             {
00926                 buff = add_prefix(target, sender, A_INPREFIX, msg, "");
00927             }
00928             else
00929             {
00930                 buff = (char *)msg;
00931             }
00932             DOLIST(obj, Contents(target))
00933             {
00934                 if (obj != target)
00935                 {
00936                     notify_check(obj, sender, buff,
00937                         MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE | key & MSG_HTML);
00938                 }
00939             }
00940             if (key & MSG_S_OUTSIDE)
00941             {
00942                 free_lbuf(buff);
00943             }
00944         }
00945 
00946         // Deliver message to neighbors.
00947         //
00948         if (  has_neighbors
00949            && (  (key & MSG_NBR)
00950               || (  (key & MSG_NBR_A)
00951                  && is_audible
00952                  && check_filter(target, sender, A_FILTER, msg))))
00953         {
00954             if (key & MSG_S_INSIDE)
00955             {
00956                 tbuff = dflt_from_msg(sender, target);
00957                 buff = add_prefix(target, sender, A_PREFIX, msg, "");
00958                 free_lbuf(tbuff);
00959             }
00960             else
00961             {
00962                 buff = (char *)msg;
00963             }
00964             DOLIST(obj, Contents(targetloc))
00965             {
00966                 if (  obj != target
00967                    && obj != targetloc)
00968                 {
00969                     notify_check(obj, sender, buff,
00970                     MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE);
00971                 }
00972             }
00973             if (key & MSG_S_INSIDE)
00974             {
00975                 free_lbuf(buff);
00976             }
00977         }
00978 
00979         // Deliver message to container.
00980         //
00981         if (  has_neighbors
00982            && (  (key & MSG_LOC)
00983               || ( (key & MSG_LOC_A)
00984                  && is_audible
00985                  && check_filter(target, sender, A_FILTER, msg))))
00986         {
00987             if (key & MSG_S_INSIDE)
00988             {
00989                 tbuff = dflt_from_msg(sender, target);
00990                 buff = add_prefix(target, sender, A_PREFIX, msg, tbuff);
00991                 free_lbuf(tbuff);
00992             }
00993             else
00994             {
00995                 buff = (char *)msg;
00996             }
00997             notify_check(targetloc, sender, buff,
00998                 MSG_ME | MSG_F_UP | MSG_S_INSIDE);
00999             if (key & MSG_S_INSIDE)
01000             {
01001                 free_lbuf(buff);
01002             }
01003         }
01004     }
01005     if (msg_ns)
01006     {
01007         free_lbuf(msg_ns);
01008     }
01009     mudstate.ntfy_nest_lev--;
01010 }
01011 
01012 void notify_except(dbref loc, dbref player, dbref exception, const char *msg, int key)
01013 {
01014     dbref first;
01015 
01016     if (loc != exception)
01017     {
01018         notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A | key));
01019     }
01020     DOLIST(first, Contents(loc))
01021     {
01022         if (first != exception)
01023         {
01024             notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE | key));
01025         }
01026     }
01027 }
01028 
01029 void notify_except2(dbref loc, dbref player, dbref exc1, dbref exc2, const char *msg)
01030 {
01031     dbref first;
01032 
01033     if (  loc != exc1
01034        && loc != exc2)
01035     {
01036         notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A));
01037     }
01038     DOLIST(first, Contents(loc))
01039     {
01040         if (  first != exc1
01041            && first != exc2)
01042         {
01043             notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE));
01044         }
01045     }
01046 }
01047 
01048 /* ----------------------------------------------------------------------
01049  * Reporting of CPU information.
01050  */
01051 
01052 static void report_timecheck
01053 (
01054     dbref player,
01055     bool yes_screen,
01056     bool yes_log,
01057     bool yes_clear
01058 )
01059 {
01060     int thing, obj_counted;
01061     CLinearTimeDelta ltdPeriod, ltdTotal;
01062     CLinearTimeAbsolute ltaNow;
01063     ltaNow.GetUTC();
01064     ltdPeriod = ltaNow - mudstate.cpu_count_from;
01065 
01066     if (  yes_log
01067        && (LOG_TIMEUSE & mudconf.log_options))
01068     {
01069         start_log("OBJ", "CPU");
01070         log_name(player);
01071         log_text(" checks object time use over ");
01072         log_number(ltdPeriod.ReturnSeconds());
01073         log_text(" seconds" ENDLINE);
01074     }
01075     else
01076     {
01077         yes_log = false;
01078         STARTLOG(LOG_ALWAYS, "WIZ", "TIMECHECK");
01079         log_name(player);
01080         log_text(" checks object time use over ");
01081         log_number(ltdPeriod.ReturnSeconds());
01082         log_text(" seconds");
01083         ENDLOG;
01084     }
01085 
01086     obj_counted = 0;
01087     ltdTotal.Set100ns(0);
01088 
01089     // Step through the db. Care only about the ones that are nonzero.
01090     //
01091     DO_WHOLE_DB(thing)
01092     {
01093         CLinearTimeDelta &ltd = db[thing].cpu_time_used;
01094         if (ltd.Return100ns())
01095         {
01096             ltdTotal += ltd;
01097             long used_msecs = ltd.ReturnMilliseconds();
01098             obj_counted++;
01099             if (yes_log)
01100             {
01101                 Log.tinyprintf("#%d\t%ld" ENDLINE, thing, used_msecs);
01102             }
01103             if (yes_screen)
01104             {
01105                 raw_notify(player, tprintf("#%d\t%ld", thing, used_msecs));
01106             }
01107             if (yes_clear)
01108             {
01109                 ltd.Set100ns(0);
01110             }
01111         }
01112     }
01113 
01114     long lTotal = ltdTotal.ReturnMilliseconds();
01115     long lPeriod = ltdPeriod.ReturnSeconds();
01116 
01117     if (yes_screen)
01118     {
01119         raw_notify(player,
01120             tprintf("Counted %d objects using %ld msecs over %d seconds.",
01121             obj_counted, lTotal, lPeriod));
01122     }
01123 
01124     if (yes_log)
01125     {
01126         Log.tinyprintf("Counted %d objects using %ld msecs over %d seconds.",
01127             obj_counted, lTotal, lPeriod);
01128         end_log();
01129     }
01130 
01131     if (yes_clear)
01132     {
01133         mudstate.cpu_count_from = ltaNow;
01134     }
01135 }
01136 
01137 void do_timecheck(dbref executor, dbref caller, dbref enactor, int key)
01138 {
01139     UNUSED_PARAMETER(caller);
01140     UNUSED_PARAMETER(enactor);
01141 
01142     bool yes_screen, yes_log, yes_clear;
01143 
01144     yes_screen = yes_log = yes_clear = false;
01145 
01146     if (key == 0)
01147     {
01148         // No switches, default to printing to screen and clearing counters.
01149         //
01150         yes_screen = true;
01151         yes_clear = true;
01152     }
01153     else
01154     {
01155         if (key & TIMECHK_RESET)
01156         {
01157             yes_clear = true;
01158         }
01159         if (key & TIMECHK_SCREEN)
01160         {
01161             yes_screen = true;
01162         }
01163         if (key & TIMECHK_LOG)
01164         {
01165             yes_log = true;
01166         }
01167     }
01168     report_timecheck(executor, yes_screen, yes_log, yes_clear);
01169 }
01170 
01171 void do_shutdown
01172 (
01173     dbref executor,
01174     dbref caller,
01175     dbref enactor,
01176     int   key,
01177     char *message
01178 )
01179 {
01180     UNUSED_PARAMETER(caller);
01181     UNUSED_PARAMETER(enactor);
01182 
01183     if (!Can_SiteAdmin(executor))
01184     {
01185         notify(executor, NOPERM_MESSAGE);
01186         return;
01187     }
01188 
01189     raw_broadcast(0, "GAME: Shutdown by %s", Name(Owner(executor)));
01190     STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN");
01191     log_text("Shutdown by ");
01192     log_name(executor);
01193     ENDLOG;
01194 
01195     STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN");
01196     log_text("Shutdown status: ");
01197     log_text(message);
01198     ENDLOG;
01199 
01200     int fd = open(mudconf.status_file, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0600);
01201     if (fd != -1)
01202     {
01203         write(fd, message, strlen(message));
01204         write(fd, ENDLINE, sizeof(ENDLINE)-1);
01205         DebugTotalFiles++;
01206         if (close(fd) == 0)
01207         {
01208             DebugTotalFiles--;
01209         }
01210     }
01211 
01212     // Do we perform a normal or an emergency shutdown? Normal
01213     // shutdown is handled by exiting the main loop in shovechars,
01214     // emergency shutdown is done here.
01215     //
01216     if (key & SHUTDN_PANIC)
01217     {
01218         // Close down the network interface.
01219         //
01220         emergency_shutdown();
01221 
01222         local_presync_database();
01223 
01224         // Close the attribute text db and dump the header db.
01225         //
01226 #ifndef MEMORY_BASED
01227         // Save cached modified attribute list
01228         //
01229         al_store();
01230 #endif // MEMORY_BASED
01231 
01232         pcache_sync();
01233         SYNC;
01234         CLOSE;
01235 
01236         STARTLOG(LOG_ALWAYS, "DMP", "PANIC");
01237         log_text("Panic dump: ");
01238         log_text(mudconf.crashdb);
01239         ENDLOG;
01240         dump_database_internal(DUMP_I_PANIC);
01241         STARTLOG(LOG_ALWAYS, "DMP", "DONE");
01242         log_text("Panic dump complete: ");
01243         log_text(mudconf.crashdb);
01244         ENDLOG;
01245     }
01246 
01247     // Set up for normal shutdown.
01248     //
01249     mudstate.shutdown_flag = true;
01250 }
01251 
01252 // There are several types of dumps:
01253 //
01254 // Type 0 - Normal   mudstate.dumping controlled
01255 // Type 1 - Panic    uncontrolled but only one of these happening at a time.
01256 // Type 2 - Restart  mudstate.dumping controlled.
01257 // Type 3 - FLAT     mudstate.dumping controlled.
01258 // Type 4 - signal   uncontrolled and if we fault twice, the game ends --
01259 //                   see check_panicking.
01260 //
01261 // When changing this function and to keep forking dumps safe, keep in mind
01262 // that the following combinations can be occuring at the same time. Don't
01263 // touch each other's files.
01264 //
01265 // Type 0 and 2 are allowed to touch each other's files. Type 1 and 4 should not
01266 // touch files used in Type 0 or Type 2.
01267 //
01268 typedef struct
01269 {
01270     char **ppszOutputBase;
01271     char szOutputSuffix[14];
01272     bool bUseTemporary;
01273     int  fType;
01274     char *pszErrorMessage;
01275 } DUMP_PROCEDURE;
01276 
01277 static DUMP_PROCEDURE DumpProcedures[NUM_DUMP_TYPES] =
01278 {
01279     { 0,                ""       , false, 0,                             "" }, // 0 -- Handled specially.
01280     { &mudconf.crashdb, ""       , false, UNLOAD_VERSION | UNLOAD_FLAGS, "Opening crash file" }, // 1
01281     { &mudconf.indb,    ""       , true,  OUTPUT_VERSION | OUTPUT_FLAGS, "Opening input file" }, // 2
01282     { &mudconf.indb,   ".FLAT"   , false, UNLOAD_VERSION | UNLOAD_FLAGS, "Opening flatfile"   }, // 3
01283     { &mudconf.indb,   ".SIG"    , false, UNLOAD_VERSION | UNLOAD_FLAGS, "Opening signalled flatfile"}  // 4
01284 };
01285 
01286 #ifdef WIN32
01287 #define POPEN_READ_OP "rb"
01288 #define POPEN_WRITE_OP "wb"
01289 #else // WIN32
01290 #define POPEN_READ_OP "r"
01291 #define POPEN_WRITE_OP "w"
01292 #endif // WIN32
01293 
01294 void dump_database_internal(int dump_type)
01295 {
01296     char tmpfile[SIZEOF_PATHNAME+32];
01297     char outfn[SIZEOF_PATHNAME+32];
01298     char prevfile[SIZEOF_PATHNAME+32];
01299     FILE *f;
01300 
01301     if (  dump_type < 0
01302        || NUM_DUMP_TYPES <= dump_type)
01303     {
01304         return;
01305     }
01306 
01307     bool bPotentialConflicts = false;
01308 #ifndef WIN32
01309     // If we are already dumping for some reason, and suddenly get a type 1 or
01310     // type 4 dump, basically don't touch mail and comsys files. The other
01311     // dump will take care of them as well as can be expected for now, and if
01312     // we try to, we'll just step on them.
01313     //
01314     if (  mudstate.dumping
01315        && (  dump_type == DUMP_I_PANIC
01316           || dump_type == DUMP_I_SIGNAL))
01317     {
01318         bPotentialConflicts = true;
01319     }
01320 #endif
01321 
01322     // Call the local dump function only if another dump is not already
01323     // in progress.
01324     //
01325     local_dump_database(dump_type);
01326 
01327     if (0 < dump_type)
01328     {
01329         DUMP_PROCEDURE *dp = &DumpProcedures[dump_type];
01330 
01331         sprintf(outfn, "%s%s", *(dp->ppszOutputBase), dp->szOutputSuffix);
01332         if (dp->bUseTemporary)
01333         {
01334             sprintf(tmpfile, "%s.#%d#", outfn, mudstate.epoch);
01335             RemoveFile(tmpfile);
01336             f = fopen(tmpfile, "wb");
01337         }
01338         else
01339         {
01340             RemoveFile(outfn);
01341             f = fopen(outfn, "wb");
01342         }
01343 
01344         if (f)
01345         {
01346             DebugTotalFiles++;
01347             setvbuf(f, NULL, _IOFBF, 16384);
01348             db_write(f, F_MUX, dp->fType);
01349             if (fclose(f) == 0)
01350             {
01351                 DebugTotalFiles--;
01352             }
01353 
01354             if (dp->bUseTemporary)
01355             {
01356                 ReplaceFile(tmpfile, outfn);
01357             }
01358         }
01359         else
01360         {
01361             log_perror("DMP", "FAIL", dp->pszErrorMessage, outfn);
01362         }
01363 
01364         if (!bPotentialConflicts)
01365         {
01366             if (mudconf.have_mailer)
01367             {
01368                 f = fopen(mudconf.mail_db, "wb");
01369                 if (f)
01370                 {
01371                     DebugTotalFiles++;
01372                     dump_mail(f);
01373                     if (fclose(f) == 0)
01374                     {
01375                         DebugTotalFiles--;
01376                     }
01377                 }
01378             }
01379             if (mudconf.have_comsys)
01380             {
01381                 save_comsys(mudconf.comsys_db);
01382             }
01383         }
01384         return;
01385     }
01386 
01387     // Nuke our predecessor
01388     //
01389     if (mudconf.compress_db)
01390     {
01391         sprintf(prevfile, "%s.prev.gz", mudconf.outdb);
01392         sprintf(tmpfile, "%s.#%d#.gz", mudconf.outdb, mudstate.epoch - 1);
01393         RemoveFile(tmpfile);
01394         sprintf(tmpfile, "%s.#%d#.gz", mudconf.outdb, mudstate.epoch);
01395         strcpy(outfn, mudconf.outdb);
01396         strcat(outfn, ".gz");
01397 
01398         f = popen(tprintf("%s > %s", mudconf.compress, tmpfile), POPEN_WRITE_OP);
01399         if (f)
01400         {
01401             DebugTotalFiles++;
01402             setvbuf(f, NULL, _IOFBF, 16384);
01403             db_write(f, F_MUX, OUTPUT_VERSION | OUTPUT_FLAGS);
01404             if (pclose(f) != -1)
01405             {
01406                 DebugTotalFiles--;
01407             }
01408             ReplaceFile(outfn, prevfile);
01409             if (ReplaceFile(tmpfile, outfn) < 0)
01410             {
01411                 log_perror("SAV", "FAIL", "Renaming output file to DB file", tmpfile);
01412             }
01413         }
01414         else
01415         {
01416             log_perror("SAV", "FAIL", "Opening", tmpfile);
01417         }
01418     }
01419     else
01420     {
01421         sprintf(prevfile, "%s.prev", mudconf.outdb);
01422         sprintf(tmpfile, "%s.#%d#", mudconf.outdb, mudstate.epoch - 1);
01423         RemoveFile(tmpfile);
01424         sprintf(tmpfile, "%s.#%d#", mudconf.outdb, mudstate.epoch);
01425 
01426         f = fopen(tmpfile, "wb");
01427         if (f)
01428         {
01429             DebugTotalFiles++;
01430             setvbuf(f, NULL, _IOFBF, 16384);
01431             db_write(f, F_MUX, OUTPUT_VERSION | OUTPUT_FLAGS);
01432             if (fclose(f) == 0)
01433             {
01434                 DebugTotalFiles--;
01435             }
01436             ReplaceFile(mudconf.outdb, prevfile);
01437             if (ReplaceFile(tmpfile, mudconf.outdb) < 0)
01438             {
01439                 log_perror("SAV", "FAIL", "Renaming output file to DB file", tmpfile);
01440             }
01441         }
01442         else
01443         {
01444             log_perror("SAV", "FAIL", "Opening", tmpfile);
01445         }
01446     }
01447 
01448     if (mudconf.have_mailer)
01449     {
01450         f = fopen(mudconf.mail_db, "wb");
01451         if (f)
01452         {
01453             DebugTotalFiles++;
01454             dump_mail(f);
01455             if (fclose(f) == 0)
01456             {
01457                 DebugTotalFiles--;
01458             }
01459         }
01460     }
01461 
01462     if (mudconf.have_comsys)
01463     {
01464         save_comsys(mudconf.comsys_db);
01465     }
01466 }
01467 
01468 static void dump_database(void)
01469 {
01470     char *buff;
01471 
01472     mudstate.epoch++;
01473 
01474 #ifndef WIN32
01475     if (mudstate.dumping)
01476     {
01477         STARTLOG(LOG_DBSAVES, "DMP", "DUMP");
01478         log_text("Waiting on previously-forked child before dumping... ");
01479         ENDLOG;
01480 
01481         while (mudstate.dumping)
01482         {
01483             // We have a forked dump in progress, so we will wait until the
01484             // child exits.
01485             //
01486             MuxAlarm.Sleep(time_1s);
01487         }
01488     }
01489     mudstate.dumping = true;
01490     mudstate.dumped  = 0;
01491 #endif
01492     buff = alloc_mbuf("dump_database");
01493     sprintf(buff, "%s.#%d#", mudconf.outdb, mudstate.epoch);
01494 
01495     STARTLOG(LOG_DBSAVES, "DMP", "DUMP");
01496     log_text("Dumping: ");
01497     log_text(buff);
01498     ENDLOG;
01499 
01500     local_presync_database();
01501 
01502 #ifndef MEMORY_BASED
01503     // Save cached modified attribute list
01504     //
01505     al_store();
01506 #endif // MEMORY_BASED
01507 
01508     pcache_sync();
01509 
01510     dump_database_internal(DUMP_I_NORMAL);
01511     SYNC;
01512 
01513     STARTLOG(LOG_DBSAVES, "DMP", "DONE")
01514     log_text("Dump complete: ");
01515     log_text(buff);
01516     ENDLOG;
01517     free_mbuf(buff);
01518 
01519 #ifndef WIN32
01520     // This doesn't matter. We are about the stop the game. However,
01521     // leave it in.
01522     //
01523     mudstate.dumping = false;
01524     local_dump_complete_signal();
01525 #endif
01526 }
01527 
01528 void fork_and_dump(int key)
01529 {
01530 #ifndef WIN32
01531     static volatile bool bRequestAccepted = false;
01532 
01533     // fork_and_dump is never called with mudstate.dumping true, but we'll
01534     // ensure that assertion now.
01535     //
01536     if (  bRequestAccepted
01537        || mudstate.dumping)
01538     {
01539         return;
01540     }
01541     bRequestAccepted = true;
01542 #endif
01543 
01544     // If no options were given, then it means DUMP_TEXT+DUMP_STRUCT.
01545     //
01546     if (key == 0)
01547     {
01548         key = DUMP_TEXT+DUMP_STRUCT;
01549     }
01550 
01551     if (*mudconf.dump_msg)
01552     {
01553         raw_broadcast(0, "%s", mudconf.dump_msg);
01554     }
01555     check_mail_expiration();
01556     char *buff = alloc_lbuf("fork_and_dump");
01557     if (key & (DUMP_TEXT|DUMP_STRUCT))
01558     {
01559         STARTLOG(LOG_DBSAVES, "DMP", "CHKPT");
01560         if (key & DUMP_TEXT)
01561         {
01562             log_text("SYNCing");
01563             if (key & DUMP_STRUCT)
01564             {
01565                 log_text(" and ");
01566             }
01567         }
01568         if (key & DUMP_STRUCT)
01569         {
01570             mudstate.epoch++;
01571             sprintf(buff, "%s.#%d#", mudconf.outdb, mudstate.epoch);
01572             log_text("Checkpointing: ");
01573             log_text(buff);
01574         }
01575         ENDLOG;
01576     }
01577     if (key & DUMP_FLATFILE)
01578     {
01579         STARTLOG(LOG_DBSAVES, "DMP", "FLAT");
01580         log_text("Creating flatfile: ");
01581         sprintf(buff, "%s.FLAT", mudconf.outdb);
01582         log_text(buff);
01583         ENDLOG;
01584     }
01585     free_lbuf(buff);
01586 
01587     local_presync_database();
01588 
01589 #ifndef MEMORY_BASED
01590     // Save cached modified attribute list
01591     //
01592     al_store();
01593 #endif // MEMORY_BASED
01594 
01595     pcache_sync();
01596     SYNC;
01597 
01598 #ifndef WIN32
01599     mudstate.write_protect = true;
01600     int child = 0;
01601     bool bChildExists = false;
01602     mudstate.dumping = true;
01603     mudstate.dumped  = 0;
01604     bool bAttemptFork = mudconf.fork_dump;
01605 #if !defined(HAVE_PREAD) \
01606  || !defined(HAVE_PWRITE)
01607     if (key & DUMP_FLATFILE)
01608     {
01609         // Don't attempt a fork()'ed @dump/flat without pread()/pwrite()
01610         // support.
01611         //
01612         bAttemptFork = false;
01613     }
01614 #endif // !HAVE_PREAD !HAVE_PWRITE
01615 #endif // WIN32
01616     if (key & (DUMP_STRUCT|DUMP_FLATFILE))
01617     {
01618 #ifndef WIN32
01619         if (bAttemptFork)
01620         {
01621             child = fork();
01622         }
01623         if (child == 0)
01624         {
01625             // If we don't clear this alarm, the child will eventually receive a
01626             // SIG_PROF.
01627             //
01628             MuxAlarm.Clear();
01629 #endif
01630             if (key & DUMP_STRUCT)
01631             {
01632                 dump_database_internal(DUMP_I_NORMAL);
01633             }
01634             if (key & DUMP_FLATFILE)
01635             {
01636                 dump_database_internal(DUMP_I_FLAT);
01637             }
01638 #ifndef WIN32
01639             if (mudconf.fork_dump)
01640             {
01641                 _exit(0);
01642             }
01643         }
01644         else if (child < 0)
01645         {
01646             log_perror("DMP", "FORK", NULL, "fork()");
01647         }
01648         else
01649         {
01650             mudstate.dumper = child;
01651             if (mudstate.dumper == mudstate.dumped)
01652             {
01653                 // The child process executed and exited before fork() returned
01654                 // to the parent process.  Without a process id, the parent's
01655                 // SIGCHLD handler could not be certain that the pid of the
01656                 // exiting process would match the pid of this child.
01657                 //
01658                 // At the this point, we can be sure, however, there's
01659                 // nothing much left to do.
01660                 //
01661                 // See SIGCHLD handler in bsd.cpp.
01662                 //
01663                 mudstate.dumper = 0;
01664                 mudstate.dumped = 0;
01665             }
01666             else
01667             {
01668                 bChildExists = true;
01669             }
01670         }
01671 #endif
01672     }
01673 
01674 #ifndef WIN32
01675     mudstate.write_protect = false;
01676     if (!bChildExists)
01677     {
01678         // We have the ability to fork children, but we are not configured to
01679         // use it; or, we tried to fork a child and failed; or, we didn't
01680         // need to dump the structure or a flatfile; or, the child has finished
01681         // dumping already.
01682         //
01683         mudstate.dumper = 0;
01684         mudstate.dumping = false;
01685         local_dump_complete_signal();
01686     }
01687     bRequestAccepted = false;
01688 #endif
01689 
01690     if (*mudconf.postdump_msg)
01691     {
01692         raw_broadcast(0, "%s", mudconf.postdump_msg);
01693     }
01694 }
01695 
01696 #define LOAD_GAME_SUCCESS           0
01697 #define LOAD_GAME_NO_INPUT_DB     (-1)
01698 #define LOAD_GAME_CANNOT_OPEN     (-2)
01699 #define LOAD_GAME_LOADING_PROBLEM (-3)
01700 
01701 #ifdef MEMORY_BASED
01702 static int load_game(void)
01703 #else // MEMORY_BASED
01704 static int load_game(int ccPageFile)
01705 #endif // MEMORY_BASED
01706 {
01707     FILE *f = NULL;
01708     char infile[SIZEOF_PATHNAME+8];
01709     struct stat statbuf;
01710     int db_format, db_version, db_flags;
01711 
01712     bool compressed = false;
01713 
01714     if (mudconf.compress_db)
01715     {
01716         strcpy(infile, mudconf.indb);
01717         strcat(infile, ".gz");
01718         if (stat(infile, &statbuf) == 0)
01719         {
01720             f = popen(tprintf(" %s < %s", mudconf.uncompress, infile), POPEN_READ_OP);
01721             if (f != NULL)
01722             {
01723                 DebugTotalFiles++;
01724                 compressed = true;
01725             }
01726         }
01727     }
01728 
01729     if (!compressed)
01730     {
01731         strcpy(infile, mudconf.indb);
01732         if (stat(infile, &statbuf) != 0)
01733         {
01734             // Indicate that we couldn't load because the input db didn't
01735             // exist.
01736             //
01737             return LOAD_GAME_NO_INPUT_DB;
01738         }
01739         if ((f = fopen(infile, "rb")) == NULL)
01740         {
01741             return LOAD_GAME_CANNOT_OPEN;
01742         }
01743         DebugTotalFiles++;
01744         setvbuf(f, NULL, _IOFBF, 16384);
01745     }
01746 
01747     // Ok, read it in.
01748     //
01749     STARTLOG(LOG_STARTUP, "INI", "LOAD")
01750     log_text("Loading: ");
01751     log_text(infile);
01752     ENDLOG
01753     if (db_read(f, &db_format, &db_version, &db_flags) < 0)
01754     {
01755         // Everything is not ok.
01756         //
01757         if (compressed)
01758         {
01759             if (pclose(f) != -1)
01760             {
01761                 DebugTotalFiles--;
01762             }
01763         }
01764         else
01765         {
01766             if (fclose(f) == 0)
01767             {
01768                 DebugTotalFiles--;
01769             }
01770         }
01771         f = 0;
01772 
01773         STARTLOG(LOG_ALWAYS, "INI", "FATAL")
01774         log_text("Error loading ");
01775         log_text(infile);
01776         ENDLOG
01777         return LOAD_GAME_LOADING_PROBLEM;
01778     }
01779 
01780     // Everything is ok.
01781     //
01782     if (compressed)
01783     {
01784         if (pclose(f) != -1)
01785         {
01786             DebugTotalFiles--;
01787         }
01788     }
01789     else
01790     {
01791         if (fclose(f) == 0)
01792         {
01793             DebugTotalFiles--;
01794         }
01795     }
01796     f = 0;
01797 
01798 #ifndef MEMORY_BASED
01799     if (db_flags & V_DATABASE)
01800     {
01801         // It loaded an output file.
01802         //
01803         if (ccPageFile == HF_OPEN_STATUS_NEW)
01804         {
01805             STARTLOG(LOG_STARTUP, "INI", "LOAD");
01806             log_text("Attributes are not present in either the input file or the attribute database.");
01807             ENDLOG;
01808         }
01809     }
01810     else
01811     {
01812         // It loaded a flatfile.
01813         //
01814         if (ccPageFile == HF_OPEN_STATUS_OLD)
01815         {
01816             STARTLOG(LOG_STARTUP, "INI", "LOAD");
01817             log_text("Attributes present in both the input file and the attribute database.");
01818             ENDLOG;
01819         }
01820     }
01821 #endif // !MEMORY_BASED
01822 
01823     if (mudconf.have_comsys)
01824     {
01825         load_comsys(mudconf.comsys_db);
01826     }
01827 
01828     if (mudconf.have_mailer)
01829     {
01830         f = fopen(mudconf.mail_db, "rb");
01831         if (f)
01832         {
01833             DebugTotalFiles++;
01834             setvbuf(f, NULL, _IOFBF, 16384);
01835             Log.tinyprintf("LOADING: %s" ENDLINE, mudconf.mail_db);
01836             load_mail(f);
01837             Log.tinyprintf("LOADING: %s (done)" ENDLINE, mudconf.mail_db);
01838             if (fclose(f) == 0)
01839             {
01840                 DebugTotalFiles--;
01841             }
01842             f = 0;
01843         }
01844     }
01845     STARTLOG(LOG_STARTUP, "INI", "LOAD");
01846     log_text("Load complete.");
01847     ENDLOG;
01848 
01849     return LOAD_GAME_SUCCESS;
01850 }
01851 
01852 
01853 /*
01854  * match a list of things, using the no_command flag
01855  *
01856  * This seems to be always called with type == AMATCH_CMD...
01857  * So the fact that ansi_strip is done within atr_match only
01858  * brings about a if () performance hit...
01859  *
01860  */
01861 
01862 bool list_check
01863 (
01864     dbref thing,
01865     dbref player,
01866     char  type,
01867     char  *str,
01868     char  *raw_str,
01869     bool check_parent
01870 )
01871 {
01872     bool bMatch = false;
01873 
01874     int limit = mudstate.db_top;
01875     while (NOTHING != thing)
01876     {
01877 #ifdef REALITY_LVLS
01878         if ((thing != player)
01879            && (!(No_Command(thing)))
01880            && IsReal(thing, player))
01881 #else
01882         if (  thing != player
01883            && !No_Command(thing))
01884 #endif /* REALITY_LVLS */
01885         {
01886             bMatch |= atr_match(thing, player, type, str, raw_str, check_parent);
01887         }
01888 
01889         // Non-authoritative test of circular reference.
01890         //
01891         dbref next;
01892         if (  thing == (next = Next(thing))
01893            || --limit < 0
01894            || MuxAlarm.bAlarmed)
01895         {
01896             break;
01897         }
01898         thing = next;
01899     }
01900     return bMatch;
01901 }
01902 
01903 bool Hearer(dbref thing)
01904 {
01905     if (  mudstate.inpipe
01906        && thing == mudstate.poutobj)
01907     {
01908         return true;
01909     }
01910 
01911     if (  Connected(thing)
01912        || Puppet(thing)
01913        || H_Listen(thing))
01914     {
01915         return true;
01916     }
01917 
01918     if (Monitor(thing))
01919     {
01920         if (mudstate.bfListens.IsSet(thing))
01921         {
01922             return true;
01923         }
01924         else if (mudstate.bfNoListens.IsSet(thing))
01925         {
01926             return false;
01927         }
01928         else
01929         {
01930             bool bFoundCommands = false;
01931 
01932             char *buff = alloc_lbuf("Hearer");
01933             char *as;
01934             atr_push();
01935             for (int atr = atr_head(thing, &as); atr; atr = atr_next(&as))
01936             {
01937                 ATTR *ap = atr_num(atr);
01938                 if (  !ap
01939                    || (ap->flags & AF_NOPROG))
01940                 {
01941                     continue;
01942                 }
01943 
01944                 int   aflags;
01945                 dbref aowner;
01946                 atr_get_str(buff, thing, atr, &aowner, &aflags);
01947 
01948                 if (aflags & AF_NOPROG)
01949                 {
01950                     continue;
01951                 }
01952 
01953                 char *s = NULL;
01954                 if (  AMATCH_CMD    == buff[0]
01955                    || AMATCH_LISTEN == buff[0])
01956                 {
01957                     s = strchr(buff+1, ':');
01958                     if (s)
01959                     {
01960                         if (AMATCH_CMD == buff[0])
01961                         {
01962                             bFoundCommands = true;
01963                         }
01964                         else
01965                         {
01966                             free_lbuf(buff);
01967                             atr_pop();
01968                             mudstate.bfListens.Set(thing);
01969                             return true;
01970                         }
01971                     }
01972                 }
01973             }
01974             free_lbuf(buff);
01975             atr_pop();
01976 
01977             mudstate.bfNoListens.Set(thing);
01978 
01979             if (bFoundCommands)
01980             {
01981                 mudstate.bfNoCommands.Clear(thing);
01982                 mudstate.bfCommands.Set(thing);
01983             }
01984             else
01985             {
01986                 mudstate.bfCommands.Clear(thing);
01987                 mudstate.bfNoCommands.Set(thing);
01988             }
01989         }
01990     }
01991     return false;
01992 }
01993 
01994 void do_readcache(dbref executor, dbref caller, dbref enactor, int key)
01995 {
01996     UNUSED_PARAMETER(caller);
01997     UNUSED_PARAMETER(enactor);
01998     UNUSED_PARAMETER(key);
01999 
02000     helpindex_load(executor);
02001     fcache_load(executor);
02002 }
02003 
02004 static void process_preload(void)
02005 {
02006     dbref thing, parent, aowner;
02007     int aflags, lev;
02008     char *tstr;
02009     FWDLIST *fp;
02010 
02011     fp = (FWDLIST *) alloc_lbuf("process_preload.fwdlist");
02012     tstr = alloc_lbuf("process_preload.string");
02013     DO_WHOLE_DB(thing)
02014     {
02015         // Ignore GOING objects.
02016         //
02017         if (Going(thing))
02018         {
02019             continue;
02020         }
02021 
02022         scheduler.RunTasks(10);
02023 
02024         // Look for a STARTUP attribute in parents.
02025         //
02026         if (mudconf.run_startup)
02027         {
02028             ITER_PARENTS(thing, parent, lev)
02029             {
02030                 if (Flags(thing) & HAS_STARTUP)
02031                 {
02032                     did_it(Owner(thing), thing, 0, NULL, 0, NULL, A_STARTUP,
02033                         (char **)NULL, 0);
02034 
02035                     // Process queue entries as we add them.
02036                     //
02037                     scheduler.RunTasks(10);
02038                     break;
02039                  }
02040             }
02041         }
02042 
02043         // Look for a FORWARDLIST attribute.
02044         //
02045         if (H_Fwdlist(thing))
02046         {
02047             atr_get_str(tstr, thing, A_FORWARDLIST, &aowner, &aflags);
02048             if (*tstr)
02049             {
02050                 fwdlist_load(fp, GOD, tstr);
02051                 if (fp->count > 0)
02052                 {
02053                     fwdlist_set(thing, fp);
02054                 }
02055             }
02056         }
02057     }
02058     free_lbuf(fp);
02059     free_lbuf(tstr);
02060 }
02061 
02062 #ifndef MEMORY_BASED
02063 
02064 /*
02065  * ---------------------------------------------------------------------------
02066  * * info: display info about the file being read or written.
02067  */
02068 
02069 static void info(int fmt, int flags, int ver)
02070 {
02071     const char *cp;
02072 
02073     if (fmt == F_MUX)
02074     {
02075         cp = "MUX";
02076     }
02077     else
02078     {
02079         cp = "*unknown*";
02080     }
02081     Log.tinyprintf("%s version %d:", cp, ver);
02082     if ((flags & MANDFLAGS) != MANDFLAGS)
02083     {
02084         Log.WriteString(" Unsupported flags");
02085     }
02086     if (flags & V_DATABASE)
02087         Log.WriteString(" Database");
02088     if (flags & V_ATRNAME)
02089         Log.WriteString(" AtrName");
02090     if (flags & V_ATRKEY)
02091         Log.WriteString(" AtrKey");
02092     if (flags & V_ATRMONEY)
02093         Log.WriteString(" AtrMoney");
02094     Log.WriteString("\n");
02095 }
02096 
02097 static char *standalone_infile = NULL;
02098 static char *standalone_outfile = NULL;
02099 static char *standalone_basename = NULL;
02100 static bool standalone_check = false;
02101 static bool standalone_load = false;
02102 static bool standalone_unload = false;
02103 
02104 static void dbconvert(void)
02105 {
02106     int setflags, clrflags, ver;
02107     int db_ver, db_format, db_flags;
02108 
02109     Log.SetBasename("-");
02110     Log.StartLogging();
02111 
02112     SeedRandomNumberGenerator();
02113 
02114     pool_init(POOL_LBUF, LBUF_SIZE);
02115     pool_init(POOL_MBUF, MBUF_SIZE);
02116     pool_init(POOL_SBUF, SBUF_SIZE);
02117     pool_init(POOL_BOOL, sizeof(struct boolexp));
02118 
02119     cf_init();
02120 
02121     // Decide what conversions to do and how to format the output file.
02122     //
02123     setflags = clrflags = ver = 0;
02124     bool do_redirect = false;
02125 
02126     bool do_write = true;
02127     if (standalone_check)
02128     {
02129         do_write = false;
02130     }
02131     if (standalone_load)
02132     {
02133         clrflags = 0xffffffff;
02134         setflags = OUTPUT_FLAGS;
02135         ver = OUTPUT_VERSION;
02136         do_redirect = true;
02137     }
02138     else if (standalone_unload)
02139     {
02140         clrflags = 0xffffffff;
02141         setflags = UNLOAD_FLAGS;
02142         ver = UNLOAD_VERSION;
02143     }
02144 
02145     // Open the database
02146     //
02147     init_attrtab();
02148 
02149     char dirfile[SIZEOF_PATHNAME];
02150     char pagfile[SIZEOF_PATHNAME];
02151     strcpy(dirfile, standalone_basename);
02152     strcat(dirfile, ".dir");
02153     strcpy(pagfile, standalone_basename);
02154     strcat(pagfile, ".pag");
02155 
02156     int cc = init_dbfile(dirfile, pagfile, 650);
02157     if (cc == HF_OPEN_STATUS_ERROR)
02158     {
02159         Log.tinyprintf("Can't open database in (%s, %s) files\n", dirfile, pagfile);
02160         exit(1);
02161     }
02162     else if (cc == HF_OPEN_STATUS_OLD)
02163     {
02164         if (setflags == OUTPUT_FLAGS)
02165         {
02166             Log.tinyprintf("Would overwrite existing database (%s, %s)\n", dirfile, pagfile);
02167             CLOSE;
02168             exit(1);
02169         }
02170     }
02171     else if (cc == HF_OPEN_STATUS_NEW)
02172     {
02173         if (setflags == UNLOAD_FLAGS)
02174         {
02175             Log.tinyprintf("Database (%s, %s) is empty.\n", dirfile, pagfile);
02176             CLOSE;
02177             exit(1);
02178         }
02179     }
02180 
02181     FILE *fpIn = fopen(standalone_infile, "rb");
02182     if (!fpIn)
02183     {
02184         exit(1);
02185     }
02186 
02187     // Go do it.
02188     //
02189     if (do_redirect)
02190     {
02191         cache_redirect();
02192     }
02193     setvbuf(fpIn, NULL, _IOFBF, 16384);
02194     db_read(fpIn, &db_format, &db_ver, &db_flags);
02195     if (do_redirect)
02196     {
02197         cache_pass2();
02198     }
02199     Log.WriteString("Input: ");
02200     info(db_format, db_flags, db_ver);
02201 
02202     if (standalone_check)
02203     {
02204         do_dbck(NOTHING, NOTHING, NOTHING, DBCK_FULL);
02205     }
02206     fclose(fpIn);
02207 
02208     if (do_write)
02209     {
02210         FILE *fpOut = fopen(standalone_outfile, "wb");
02211         if (!fpOut)
02212         {
02213             exit(1);
02214         }
02215 
02216         db_flags = (db_flags & ~clrflags) | setflags;
02217         if (db_format != F_MUX)
02218         {
02219             db_ver = 3;
02220         }
02221         if (ver != 0)
02222         {
02223             db_ver = ver;
02224         }
02225         Log.WriteString("Output: ");
02226         info(F_MUX, db_flags, db_ver);
02227         setvbuf(fpOut, NULL, _IOFBF, 16384);
02228 #ifndef MEMORY_BASED
02229         // Save cached modified attribute list
02230         //
02231         al_store();
02232 #endif // MEMORY_BASED
02233         db_write(fpOut, F_MUX, db_ver | db_flags);
02234         fclose(fpOut);
02235     }
02236     CLOSE;
02237     db_free();
02238     exit(0);
02239 }
02240 #endif // MEMORY_BASED
02241 
02242 static void write_pidfile(const char *pFilename)
02243 {
02244     FILE *fp = fopen(pFilename, "wb");
02245     if (fp)
02246     {
02247         fprintf(fp, "%d" ENDLINE, game_pid);
02248         fclose(fp);
02249     }
02250     else
02251     {
02252         STARTLOG(LOG_ALWAYS, "PID", "FAIL");
02253         Log.tinyprintf("Failed to write pidfile %s\n", pFilename);
02254         ENDLOG;
02255     }
02256 }
02257 
02258 long DebugTotalFiles = 3;
02259 long DebugTotalSockets = 0;
02260 #ifdef WIN32
02261 long DebugTotalThreads = 1;
02262 long DebugTotalSemaphores = 0;
02263 #endif
02264 #ifdef MEMORY_ACCOUNTING
02265 long DebugTotalMemory = 0;
02266 #endif
02267 
02268 #define CLI_DO_CONFIG_FILE CLI_USER+0
02269 #define CLI_DO_MINIMAL     CLI_USER+1
02270 #define CLI_DO_VERSION     CLI_USER+2
02271 #define CLI_DO_USAGE       CLI_USER+3
02272 #define CLI_DO_INFILE      CLI_USER+4
02273 #define CLI_DO_OUTFILE     CLI_USER+5
02274 #define CLI_DO_CHECK       CLI_USER+6
02275 #define CLI_DO_LOAD        CLI_USER+7
02276 #define CLI_DO_UNLOAD      CLI_USER+8
02277 #define CLI_DO_BASENAME    CLI_USER+9
02278 #define CLI_DO_PID_FILE    CLI_USER+10
02279 #define CLI_DO_ERRORPATH   CLI_USER+11
02280 
02281 static bool bMinDB = false;
02282 static bool bSyntaxError = false;
02283 static char *conffile = NULL;
02284 static bool bVersion = false;
02285 static char *pErrorBasename = "";
02286 static bool bServerOption = false;
02287 
02288 #ifdef MEMORY_BASED
02289 #define NUM_CLI_OPTIONS 6
02290 #else
02291 #define NUM_CLI_OPTIONS 12
02292 #endif
02293 
02294 static CLI_OptionEntry OptionTable[NUM_CLI_OPTIONS] =
02295 {
02296     { "c", CLI_REQUIRED, CLI_DO_CONFIG_FILE },
02297     { "s", CLI_NONE,     CLI_DO_MINIMAL     },
02298     { "v", CLI_NONE,     CLI_DO_VERSION     },
02299     { "h", CLI_NONE,     CLI_DO_USAGE       },
02300 #ifndef MEMORY_BASED
02301     { "i", CLI_REQUIRED, CLI_DO_INFILE      },
02302     { "o", CLI_REQUIRED, CLI_DO_OUTFILE     },
02303     { "k", CLI_NONE,     CLI_DO_CHECK       },
02304     { "l", CLI_NONE,     CLI_DO_LOAD        },
02305     { "u", CLI_NONE,     CLI_DO_UNLOAD      },
02306     { "d", CLI_REQUIRED, CLI_DO_BASENAME    },
02307 #endif // MEMORY_BASED
02308     { "p", CLI_REQUIRED, CLI_DO_PID_FILE    },
02309     { "e", CLI_REQUIRED, CLI_DO_ERRORPATH   }
02310 };
02311 
02312 static void CLI_CallBack(CLI_OptionEntry *p, char *pValue)
02313 {
02314     if (p)
02315     {
02316         switch (p->m_Unique)
02317         {
02318         case CLI_DO_PID_FILE:
02319             bServerOption = true;
02320             mudconf.pid_file = pValue;
02321             break;
02322 
02323         case CLI_DO_CONFIG_FILE:
02324             bServerOption = true;
02325             conffile = pValue;
02326             break;
02327 
02328         case CLI_DO_MINIMAL:
02329             bServerOption = true;
02330             bMinDB = true;
02331             break;
02332 
02333         case CLI_DO_VERSION:
02334             bServerOption = true;
02335             bVersion = true;
02336             break;
02337 
02338         case CLI_DO_ERRORPATH:
02339             bServerOption = true;
02340             pErrorBasename = pValue;
02341             break;
02342 
02343 #ifndef MEMORY_BASED
02344         case CLI_DO_INFILE:
02345             mudstate.bStandAlone = true;
02346             standalone_infile = pValue;
02347             break;
02348 
02349         case CLI_DO_OUTFILE:
02350             mudstate.bStandAlone = true;
02351             standalone_outfile = pValue;
02352             break;
02353 
02354         case CLI_DO_CHECK:
02355             mudstate.bStandAlone = true;
02356             standalone_check = true;
02357             break;
02358 
02359         case CLI_DO_LOAD:
02360             mudstate.bStandAlone = true;
02361             standalone_load = true;
02362             break;
02363 
02364         case CLI_DO_UNLOAD:
02365             mudstate.bStandAlone = true;
02366             standalone_unload = true;
02367             break;
02368 
02369         case CLI_DO_BASENAME:
02370             mudstate.bStandAlone = true;
02371             standalone_basename = pValue;
02372             break;
02373 #endif
02374 
02375         case CLI_DO_USAGE:
02376         default:
02377             bSyntaxError = true;
02378             break;
02379         }
02380     }
02381     else
02382     {
02383         bSyntaxError = true;
02384     }
02385 }
02386 
02387 #if defined(__INTEL_COMPILER)
02388 
02389 #define CPU_FD_ID 0x00200000UL
02390 
02391 #define CPUID_0 0
02392 
02393 // GenuineIntel
02394 //
02395 #define INTEL_MFGSTR0 'uneG'
02396 #define INTEL_MFGSTR1 'letn'
02397 #define INTEL_MFGSTR2 'Ieni'
02398 
02399 // AuthenticAMD
02400 //
02401 #define AMD_MFGSTR0   'htuA'
02402 #define AMD_MFGSTR1   'DMAc'
02403 #define AMD_MFGSTR2   'itne'
02404 
02405 #define CPUID_1 1
02406 
02407 #define CPU_STEPPING(x)  ((x      ) & 0x00000000F)
02408 #define CPU_MODEL(x)     ((x >>  4) & 0x00000000F)
02409 #define CPU_FAMILY(x)    ((x >>  8) & 0x00000000F)
02410 #define CPU_TYPE(x)      ((x >> 12) & 0x00000000F)
02411 #define CPU_EXTMODEL(x)  ((x >> 16) & 0x00000000F)
02412 #define CPU_EXTFAMILY(x) ((x >> 20) & 0x00000000F)
02413 
02414 #define CPU_FEATURE_MMX  0x00800000UL
02415 #define CPU_FEATURE_FSXR 0x01000000UL
02416 #define CPU_FEATURE_SSE  0x02000000UL
02417 #define CPU_FEATURE_SSE2 0x04000000UL
02418 #define CPU_MSR_SSE3     0x00000001UL
02419 
02420 // Indicators.
02421 //
02422 // OLDOS tags indicate that the CPU supports SSE[n], but the operating system
02423 // will throw an exception when they are used.
02424 //
02425 //
02426 #define CPU_TYPE_UNSPECIALIZED               0x00000001UL
02427 #define CPU_TYPE_FAMILY_5                    0x00000002UL
02428 #define CPU_TYPE_FAMILY_6                    0x00000004UL
02429 #define CPU_TYPE_FAMILY_5_MMX                0x00000008UL
02430 #define CPU_TYPE_FAMILY_6_MMX                0x00000010UL
02431 #define CPU_TYPE_FAMILY_6_MMX_FSXR           0x00000020UL
02432 #define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE_OLDOS 0x00000040UL
02433 #define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE       0x00000080UL
02434 #define CPU_TYPE_FAMILY_F_SSE2_OLDOS         0x00000100UL
02435 #define CPU_TYPE_FAMILY_F_SSE2               0x00000200UL
02436 #define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE2      0x00000400UL
02437 #define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE3      0x00000800UL
02438 #define CPU_TYPE_FAMILY_F_SSE3               0x00000800UL
02439 
02440 static void cpu_init(void)
02441 {
02442     UINT32 dwCPUID;
02443 
02444     // Determine whether CPUID instruction is supported.
02445     //
02446     __asm
02447     {
02448         // Obtain a copy of the flags register.
02449         //
02450         pushfd
02451         pop     eax
02452         mov     dwCPUID,eax
02453 
02454         // Attempt to flip the ID bit.
02455         //
02456         xor     eax,CPU_FD_ID
02457         push    eax
02458         popfd
02459 
02460         // Obtain a second copy of the flags register.
02461         //
02462         pushfd
02463         pop     eax
02464         xor     dwCPUID,eax
02465     }
02466 
02467     // If the ID bit didn't toggle, the CPUID instruction is not supported.
02468     //
02469     if (CPU_FD_ID != dwCPUID)
02470     {
02471         // CPUID instruction is not supported.
02472         //
02473         __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED;
02474         return;
02475     }
02476 
02477     UINT32 dwHighest;
02478     UINT32 dwMfgStr0;
02479     UINT32 dwMfgStr1;
02480     UINT32 dwMfgStr2;
02481 
02482     // CPUID is supported.
02483     //
02484     __asm
02485     {
02486         mov eax,CPUID_0
02487         cpuid
02488         mov dwHighest,eax
02489         mov dwMfgStr0,ebx
02490         mov dwMfgStr1,ecx
02491         mov dwMfgStr2,edx
02492     }
02493 
02494     if (0 == dwHighest)
02495     {
02496         // We can't decipher anything with only CPUID (EAX=$0) available.
02497         //
02498         __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED;
02499         return;
02500     }
02501 
02502     typedef enum
02503     {
02504         Intel = 0,
02505         AMD
02506     } CPUMaker;
02507 
02508     CPUMaker maker;
02509     if (  INTEL_MFGSTR0 == dwMfgStr0
02510        && INTEL_MFGSTR1 == dwMfgStr1
02511        && INTEL_MFGSTR2 == dwMfgStr2)
02512     {
02513         maker = Intel;
02514     }
02515     else if (  AMD_MFGSTR0 == dwMfgStr0
02516             && AMD_MFGSTR1 == dwMfgStr1
02517             && AMD_MFGSTR2 == dwMfgStr2)
02518     {
02519         maker = AMD;
02520     }
02521     else
02522     {
02523         // It's not Intel or AMD.
02524         //
02525         __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED;
02526         return;
02527     }
02528 
02529     UINT32 dwSignature;
02530     UINT32 dwBrand;
02531     UINT32 dwMSR;
02532     UINT32 dwFeatures;
02533 
02534     __asm
02535     {
02536         mov eax,CPUID_1
02537         cpuid
02538         mov dwSignature,eax
02539         mov dwBrand,ebx
02540         mov dwMSR,ecx
02541         mov dwFeatures,edx
02542     }
02543 
02544     (void)(dwBrand);
02545 
02546     // Develop 'Effective' Family and Model.
02547     //
02548     UINT32 dwEffFamily;
02549     if (CPU_FAMILY(dwSignature) == 0xF)
02550     {
02551         dwEffFamily = CPU_FAMILY(dwSignature) + CPU_EXTFAMILY(dwSignature);
02552     }
02553     else
02554     {
02555         dwEffFamily = CPU_FAMILY(dwSignature);
02556     }
02557     UINT32 dwEffModel;
02558     if (CPU_MODEL(dwSignature) == 0xF)
02559     {
02560         dwEffModel = CPU_MODEL(dwSignature) + (CPU_EXTMODEL(dwSignature) << 4);
02561     }
02562     else
02563     {
02564         dwEffModel = CPU_MODEL(dwSignature);
02565     }
02566 
02567 #define ADVF_MMX  0x00000001UL
02568 #define ADVF_FSXR 0x00000002UL
02569 #define ADVF_SSE  0x00000004UL
02570 #define ADVF_SSE2 0x00000008UL
02571 #define ADVF_SSE3 0x00000010UL
02572 
02573     UINT32 dwAdvFeatures = 0;
02574 
02575     // Decode the features the chips claim to possess.
02576     //
02577     if (dwFeatures & CPU_FEATURE_MMX)
02578     {
02579         dwAdvFeatures |= ADVF_MMX;
02580     }
02581     if (dwFeatures & CPU_FEATURE_FSXR)
02582     {
02583         dwAdvFeatures |= ADVF_FSXR;
02584     }
02585     if (dwFeatures & CPU_FEATURE_SSE)
02586     {
02587         dwAdvFeatures |= ADVF_SSE;
02588     }
02589     if (dwFeatures & CPU_FEATURE_SSE2)
02590     {
02591         dwAdvFeatures |= ADVF_SSE2;
02592     }
02593     if (  dwEffFamily <= 5
02594        && dwMSR & CPU_MSR_SSE3)
02595     {
02596         dwAdvFeatures |= ADVF_SSE3;
02597     }
02598 
02599     // Test whether operating system will allow use of these extensions.
02600     //
02601     UINT32 dwUseable = dwAdvFeatures;
02602     if (dwUseable & ADVF_MMX)
02603     {
02604         try
02605         {
02606             __asm
02607             {
02608                 // Let's try a MMX instruction.
02609                 //
02610                 emms
02611             }
02612         }
02613         catch (...)
02614         {
02615             dwUseable &= ~(ADVF_MMX|ADVF_SSE|ADVF_SSE2|ADVF_SSE3);
02616         }
02617     }
02618 
02619     if (dwUseable & ADVF_SSE)
02620     {
02621         try
02622         {
02623             __asm
02624             {
02625                 // Let's try a SSE instruction.
02626                 //
02627                 xorps xmm0, xmm0
02628             }
02629         }
02630         catch (...)
02631         {
02632             dwUseable &= ~(ADVF_SSE|ADVF_SSE2|ADVF_SSE3);
02633         }
02634     }
02635 
02636     if (dwUseable & ADVF_SSE2)
02637     {
02638         try
02639         {
02640             __asm
02641             {
02642                 // Let's try a SSE2 instruction.
02643                 //
02644                 xorpd xmm0, xmm0
02645             }
02646         }
02647         catch (...)
02648         {
02649             dwUseable &= ~(ADVF_SSE2|ADVF_SSE3);
02650         }
02651     }
02652 
02653     if (dwUseable & ADVF_SSE3)
02654     {
02655         try
02656         {
02657             __asm
02658             {
02659                 // Let's try a SSE3 instruction.
02660                 //
02661                 haddpd xmm1,xmm2
02662             }
02663         }
02664         catch (...)
02665         {
02666             dwUseable &= ~(ADVF_SSE3);
02667         }
02668     }
02669 
02670     // Map tested features to an indicator for CPU dispatching.
02671     //
02672     if (dwEffFamily <= 4)
02673     {
02674         __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED;
02675     }
02676     else if (5 == dwEffFamily)
02677     {
02678         if (dwUseable & ADVF_MMX)
02679         {
02680             __intel_cpu_indicator = CPU_TYPE_FAMILY_5_MMX;
02681         }
02682         else
02683         {
02684             __intel_cpu_indicator = CPU_TYPE_FAMILY_5;
02685         }
02686     }
02687     else
02688     {
02689         if (dwUseable & ADVF_MMX)
02690         {
02691             if (dwUseable & ADVF_FSXR)
02692             {
02693                 if (dwUseable & ADVF_SSE)
02694                 {
02695                     if (dwUseable & ADVF_SSE2)
02696                     {
02697                         if (dwUseable & ADVF_SSE3)
02698                         {
02699                             if (dwEffFamily < 15)
02700                             {
02701                                 __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR_SSE3;
02702                             }
02703                             else
02704                             {
02705                                 __intel_cpu_indicator = CPU_TYPE_FAMILY_F_SSE3;
02706                             }
02707                         }
02708                         else
02709                         {
02710                             if (dwEffFamily < 15)
02711                             {
02712                                 __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR_SSE2;
02713                             }
02714                             else
02715                             {
02716                                 __intel_cpu_indicator = CPU_TYPE_FAMILY_F_SSE2;
02717                             }
02718                         }
02719                     }
02720                     else
02721                     {
02722                         __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR_SSE;
02723                     }
02724                 }
02725                 else
02726                 {
02727                     __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR;
02728                 }
02729             }
02730             else
02731             {
02732                 __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX;
02733             }
02734         }
02735         else
02736         {
02737             __intel_cpu_indicator = CPU_TYPE_FAMILY_6;
02738         }
02739     }
02740 
02741     // Report findings to the log.
02742     //
02743     fprintf(stderr, "cpu_init: %s, Family %u, Model %u, %s%s%s%s%s" ENDLINE,
02744         (Intel == maker ? "Intel" : (AMD == maker ? "AMD" : "Unknown")),
02745         dwEffFamily,
02746         dwEffModel,
02747         (dwUseable & ADVF_MMX)  ? "MMX " : "",
02748         (dwUseable & ADVF_FSXR) ? "FSXR ": "",
02749         (dwUseable & ADVF_SSE)  ? "SSE ": "",
02750         (dwUseable & ADVF_SSE2) ? "SSE2 ": "",
02751         (dwUseable & ADVF_SSE3) ? "SSE3 ": "");
02752 
02753     if (dwUseable != dwAdvFeatures)
02754     {
02755         UINT32 dw = dwAdvFeatures & (~dwUseable);
02756         fprintf(stderr, "cpu_init: %s%s%s%s%s unsupported by OS." ENDLINE,
02757             (dw & ADVF_MMX)  ? "MMX ": "",
02758             (dw & ADVF_FSXR) ? "FSXR ": "",
02759             (dw & ADVF_SSE)  ? "SSE ": "",
02760             (dw & ADVF_SSE2) ? "SSE2 ": "",
02761             (dw & ADVF_SSE3) ? "SSE3 ": "");
02762     }
02763 }
02764 
02765 #endif
02766 
02767 #define DBCONVERT_NAME1 "dbconvert"
02768 #define DBCONVERT_NAME2 "dbconvert.exe"
02769 
02770 int DCL_CDECL main(int argc, char *argv[])
02771 {
02772 #if defined(__INTEL_COMPILER)
02773     cpu_init();
02774 #endif
02775 
02776     build_version();
02777 
02778     // Look for dbconvert[.exe] in the program name.
02779     //
02780     size_t nProg = strlen(argv[0]);
02781     const char *pProg = argv[0] + nProg - 1;
02782     while (  nProg
02783           && (  mux_isalpha(*pProg)
02784              || *pProg == '.'))
02785     {
02786         nProg--;
02787         pProg--;
02788     }
02789     pProg++;
02790     mudstate.bStandAlone = false;
02791     if (  mux_stricmp(pProg, DBCONVERT_NAME1) == 0
02792        || mux_stricmp(pProg, DBCONVERT_NAME2) == 0)
02793     {
02794         mudstate.bStandAlone = true;
02795     }
02796 
02797     mudconf.pid_file = "netmux.pid";
02798 
02799     // Parse the command line
02800     //
02801     CLI_Process(argc, argv, OptionTable,
02802         sizeof(OptionTable)/sizeof(CLI_OptionEntry), CLI_CallBack);
02803 
02804 #ifndef MEMORY_BASED
02805     if (mudstate.bStandAlone)
02806     {
02807         int n = 0;
02808         if (standalone_check)
02809         {
02810             n++;
02811         }
02812         if (standalone_load)
02813         {
02814             n++;
02815         }
02816         if (standalone_unload)
02817         {
02818             n++;
02819         }
02820         if (  !standalone_basename
02821            || !standalone_infile
02822            || !standalone_outfile
02823            || n != 1
02824            || bServerOption)
02825         {
02826             bSyntaxError = true;
02827         }
02828         else
02829         {
02830             dbconvert();
02831             return 0;
02832         }
02833     }
02834     else
02835 #endif // MEMORY_BASED
02836 
02837     if (bVersion)
02838     {
02839         fprintf(stderr, "Version: %s" ENDLINE, mudstate.version);
02840         return 1;
02841     }
02842     if (  bSyntaxError
02843        || conffile == NULL
02844        || !bServerOption)
02845     {
02846         fprintf(stderr, "Version: %s" ENDLINE, mudstate.version);
02847         if (mudstate.bStandAlone)
02848         {
02849             fprintf(stderr, "Usage: %s -d <dbname> -i <infile> [-o <outfile>] [-l|-u|-k]" ENDLINE, pProg);
02850             fprintf(stderr, "  -d  Basename." ENDLINE);
02851             fprintf(stderr, "  -i  Input file." ENDLINE);
02852             fprintf(stderr, "  -k  Check." ENDLINE);
02853             fprintf(stderr, "  -l  Load." ENDLINE);
02854             fprintf(stderr, "  -o  Output file." ENDLINE);
02855             fprintf(stderr, "  -u  Unload." ENDLINE);
02856         }
02857         else
02858         {
02859             fprintf(stderr, "Usage: %s [-c <filename>] [-p <filename>] [-h] [-s] [-v]" ENDLINE, pProg);
02860             fprintf(stderr, "  -c  Specify configuration file." ENDLINE);
02861             fprintf(stderr, "  -e  Specify logfile basename (or '-' for stderr)." ENDLINE);
02862             fprintf(stderr, "  -h  Display this help." ENDLINE);
02863             fprintf(stderr, "  -p  Specify process ID file." ENDLINE);
02864             fprintf(stderr, "  -s  Start with a minimal database." ENDLINE);
02865             fprintf(stderr, "  -v  Display version string." ENDLINE ENDLINE);
02866         }
02867         return 1;
02868     }
02869 
02870     mudstate.bStandAlone = false;
02871 
02872     FLOAT_Initialize();
02873     TIME_Initialize();
02874     SeedRandomNumberGenerator();
02875 
02876     Log.SetBasename(pErrorBasename);
02877     Log.StartLogging();
02878     game_pid = getpid();
02879     write_pidfile(mudconf.pid_file);
02880 
02881     BuildSignalNamesTable();
02882 
02883 #ifdef MEMORY_ACCOUNTING
02884     extern CHashFile hfAllocData;
02885     extern CHashFile hfIdentData;
02886     extern bool bMemAccountingInitialized;
02887     hfAllocData.Open("svdptrs.dir", "svdptrs.pag", 40);
02888     hfIdentData.Open("svdlines.dir", "svdlines.pag", 40);
02889     bMemAccountingInitialized = true;
02890 #endif
02891 
02892 #ifdef WIN32
02893     // Find which version of Windows we are using - Completion ports do
02894     // not work with Windows 95/98
02895 
02896     OSVERSIONINFO VersionInformation;
02897 
02898     VersionInformation.dwOSVersionInfoSize = sizeof (VersionInformation);
02899     GetVersionEx(&VersionInformation);
02900     platform = VersionInformation.dwPlatformId;
02901     hGameProcess = GetCurrentProcess();
02902     if (platform == VER_PLATFORM_WIN32_NT)
02903     {
02904         Log.WriteString("Running under Windows NT" ENDLINE);
02905 
02906         // Get a handle to the kernel32 DLL
02907         //
02908         HINSTANCE hInstKernel32 = LoadLibrary("kernel32");
02909         if (!hInstKernel32)
02910         {
02911             Log.WriteString("LoadLibrary of kernel32 for a CancelIo entry point failed. Cannot continue." ENDLINE);
02912             return 1;
02913         }
02914 
02915         // Find the entry point for CancelIO so we can use it. This is done
02916         // dynamically because Windows 95/98 doesn't have a CancelIO entry
02917         // point. If it were done at load time, it would always fail on
02918         // Windows 95/98...even though we don't use it or depend on it in
02919         // that case.
02920         //
02921         fpCancelIo = (FCANCELIO *)GetProcAddress(hInstKernel32, "CancelIo");
02922         if (fpCancelIo == NULL)
02923         {
02924             Log.WriteString("GetProcAddress of _CancelIo failed. Cannot continue." ENDLINE);
02925             return 1;
02926         }
02927         fpGetProcessTimes = (FGETPROCESSTIMES *)GetProcAddress(hInstKernel32, "GetProcessTimes");
02928         if (fpGetProcessTimes == NULL)
02929         {
02930             Log.WriteString("GetProcAddress of GetProcessTimes failed. Cannot continue." ENDLINE);
02931             return 1;
02932         }
02933     }
02934     else
02935     {
02936         Log.WriteString("Running under Windows 95/98" ENDLINE);
02937     }
02938 
02939     // Initialize WinSock.
02940     //
02941     WORD wVersionRequested = MAKEWORD(2,2);
02942     WSADATA wsaData;
02943     if (WSAStartup(wVersionRequested, &wsaData) != 0)
02944     {
02945         Log.WriteString("ERROR: Could not initialize WinSock." ENDLINE);
02946         return 101;
02947     }
02948 
02949     if (  LOBYTE(wsaData.wVersion) != 2
02950        || HIBYTE(wsaData.wVersion) != 2)
02951     {
02952         // We can't run on this version of WinSock.
02953         //
02954         Log.tinyprintf("INFO: WinSock v%d.%d instead of v2.2." ENDLINE,
02955             LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
02956         //WSACleanup();
02957         //return 102;
02958     }
02959     if (!bCryptoAPI)
02960     {
02961         Log.WriteString("Crypto API unavailable.\r\n");
02962     }
02963 #endif // WIN32
02964 
02965     mudstate.start_time.GetLocal();
02966     mudstate.cpu_count_from.GetUTC();
02967     pool_init(POOL_LBUF, LBUF_SIZE);
02968     pool_init(POOL_MBUF, MBUF_SIZE);
02969     pool_init(POOL_SBUF, SBUF_SIZE);
02970     pool_init(POOL_BOOL, sizeof(struct boolexp));
02971 
02972     pool_init(POOL_DESC, sizeof(DESC));
02973     pool_init(POOL_QENTRY, sizeof(BQUE));
02974     tcache_init();
02975     pcache_init();
02976     cf_init();
02977 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
02978     init_rlimit();
02979 #endif // HAVE_SETRLIMIT RLIMIT_NOFILE
02980     init_cmdtab();
02981     init_logout_cmdtab();
02982     init_flagtab();
02983     init_powertab();
02984     init_functab();
02985     init_attrtab();
02986     init_version();
02987 
02988     mudconf.config_file = StringClone(conffile);
02989     cf_read();
02990 
02991     fcache_init();
02992     helpindex_init();
02993 
02994 #ifdef MEMORY_BASED
02995     db_free();
02996 #else // MEMORY_BASED
02997     if (bMinDB)
02998     {
02999         RemoveFile(mudconf.game_dir);
03000         RemoveFile(mudconf.game_pag);
03001     }
03002     int ccPageFile = init_dbfile(mudconf.game_dir, mudconf.game_pag, mudconf.cache_pages);
03003     if (HF_OPEN_STATUS_ERROR == ccPageFile)
03004     {
03005         STARTLOG(LOG_ALWAYS, "INI", "LOAD");
03006         log_text("Couldn't load text database: ");
03007         log_text(mudconf.game_dir);
03008         log_text(mudconf.game_pag);
03009         ENDLOG;
03010         return 2;
03011     }
03012 #endif // MEMORY_BASED
03013 
03014     mudstate.record_players = 0;
03015 
03016     if (bMinDB)
03017     {
03018         db_make_minimal();
03019     }
03020     else
03021     {
03022 #ifdef MEMORY_BASED
03023         int ccInFile = load_game();
03024 #else // MEMORY_BASED
03025         int ccInFile = load_game(ccPageFile);
03026 #endif // MEMORY_BASED
03027         if (LOAD_GAME_NO_INPUT_DB == ccInFile)
03028         {
03029             // The input file didn't exist.
03030             //
03031 #ifndef MEMORY_BASED
03032             if (HF_OPEN_STATUS_NEW == ccPageFile)
03033             {
03034                 // Since the .db file didn't exist, and the .pag/.dir files
03035                 // were newly created, just create a minimal DB.
03036                 //
03037 #endif // !MEMORY_BASED
03038                 db_make_minimal();
03039                 ccInFile = LOAD_GAME_SUCCESS;
03040 #ifndef MEMORY_BASED
03041             }
03042 #endif // !MEMORY_BASED
03043         }
03044         if (ccInFile != LOAD_GAME_SUCCESS)
03045         {
03046             STARTLOG(LOG_ALWAYS, "INI", "LOAD")
03047             log_text("Couldn't load: ");
03048             log_text(mudconf.indb);
03049             ENDLOG
03050             return 2;
03051         }
03052     }
03053     set_signals();
03054     Guest.StartUp();
03055 
03056     // Do a consistency check and set up the freelist
03057     //
03058     do_dbck(NOTHING, NOTHING, NOTHING, 0);
03059 
03060     // Reset all the hash stats
03061     //
03062     hashreset(&mudstate.command_htab);
03063     hashreset(&mudstate.channel_htab);
03064     hashreset(&mudstate.mail_htab);
03065     hashreset(&mudstate.logout_cmd_htab);
03066     hashreset(&mudstate.func_htab);
03067     hashreset(&mudstate.flags_htab);
03068     hashreset(&mudstate.attr_name_htab);
03069     hashreset(&mudstate.player_htab);
03070     hashreset(&mudstate.fwdlist_htab);
03071     hashreset(&mudstate.desc_htab);
03072 
03073     int i;
03074     for (i = 0; i < MAX_GLOBAL_REGS; i++)
03075     {
03076         mudstate.global_regs[i] = alloc_lbuf("main.global_reg");
03077         mudstate.glob_reg_len[i] = 0;
03078     }
03079 
03080     ValidateConfigurationDbrefs();
03081     process_preload();
03082 
03083 #ifndef WIN32
03084     load_restart_db();
03085     if (!mudstate.restarting)
03086 #endif // !WIN32
03087     {
03088         if (fclose(stdout) == 0)
03089         {
03090             DebugTotalFiles--;
03091         }
03092         if (fclose(stdin) == 0)
03093         {
03094             DebugTotalFiles--;
03095         }
03096     }
03097     SetupPorts(&nMainGamePorts, aMainGamePorts, &mudconf.ports);
03098     boot_slave(GOD, GOD, GOD, 0);
03099 #ifdef QUERY_SLAVE
03100     boot_sqlslave(GOD, GOD, GOD, 0);
03101 #endif // QUERY_SLAVE
03102 
03103     // All intialization should be complete, allow the local
03104     // extensions to configure themselves.
03105     //
03106     local_startup();
03107 
03108     init_timer();
03109 
03110 #ifdef WIN32
03111     if (platform == VER_PLATFORM_WIN32_NT)
03112     {
03113         process_output = process_outputNT;
03114         shovecharsNT(nMainGamePorts, aMainGamePorts);
03115     }
03116     else
03117     {
03118         process_output = process_output9x;
03119         shovechars9x(nMainGamePorts, aMainGamePorts);
03120     }
03121 #else // WIN32
03122     shovechars(nMainGamePorts, aMainGamePorts);
03123 #endif // WIN32
03124 
03125     close_sockets(false, "Going down - Bye");
03126     dump_database();
03127 
03128     // All shutdown, barring logfiles, should be done, shutdown the
03129     // local extensions.
03130     //
03131     local_shutdown();
03132     CLOSE;
03133 
03134 #ifndef WIN32
03135     CleanUpSlaveSocket();
03136     CleanUpSlaveProcess();
03137 #endif
03138 #ifdef QUERY_SLAVE
03139     CleanUpSQLSlaveSocket();
03140     CleanUpSQLSlaveProcess();
03141 #endif
03142 
03143     // Go ahead and explicitly free the memory for these things so
03144     // that it's easy to spot unintentional memory leaks.
03145     //
03146     for (i = 0; i < mudstate.nHelpDesc; i++)
03147     {
03148         helpindex_clean(i);
03149     }
03150 
03151     db_free();
03152 
03153 #ifdef WIN32
03154     // Critical section not needed any more.
03155     //
03156     if (platform == VER_PLATFORM_WIN32_NT)
03157     {
03158         DeleteCriticalSection(&csDescriptorList);
03159     }
03160     WSACleanup();
03161 #endif // WIN32
03162 
03163     return 0;
03164 }
03165 
03166 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
03167 void init_rlimit(void)
03168 {
03169     struct rlimit *rlp;
03170 
03171     rlp = (struct rlimit *)alloc_lbuf("rlimit");
03172 
03173     if (getrlimit(RLIMIT_NOFILE, rlp))
03174     {
03175         log_perror("RLM", "FAIL", NULL, "getrlimit()");
03176         free_lbuf(rlp);
03177         return;
03178     }
03179     rlp->rlim_cur = rlp->rlim_max;
03180     if (setrlimit(RLIMIT_NOFILE, rlp))
03181     {
03182         log_perror("RLM", "FAIL", NULL, "setrlimit()");
03183     }
03184     free_lbuf(rlp);
03185 
03186 }
03187 #endif // HAVE_SETRLIMIT RLIMIT_NOFILE

Generated on Mon May 28 04:40:10 2007 for MUX by  doxygen 1.4.7