00001
00002
00003
00004
00005 #include "copyright.h"
00006 #include "config.h"
00007
00008 #include <sys/stat.h>
00009 #include <signal.h>
00010 #include <event.h>
00011 #include <regex.h>
00012
00013 #include "mudconf.h"
00014 #include "config.h"
00015 #include "file_c.h"
00016 #include "db.h"
00017 #include "interface.h"
00018 #include "match.h"
00019 #include "externs.h"
00020 #include "flags.h"
00021 #include "powers.h"
00022 #include "attrs.h"
00023 #include "alloc.h"
00024 #include "vattr.h"
00025 #include "commac.h"
00026 #ifdef SQL_SUPPORT
00027 #include "sqlchild.h"
00028 #endif
00029
00030 #ifndef NEXT
00031 #endif
00032
00033 #ifdef HAVE_IEEEFP_H
00034 #include <ieeefp.h>
00035 #endif
00036 #ifdef HAVE_SYS_UCONTEXT_H
00037 #include <sys/ucontext.h>
00038 #endif
00039
00040 #define NSUBEXP 10
00041
00042 extern void init_attrtab(void);
00043 extern void init_cmdtab(void);
00044 extern void init_mactab(void);
00045 extern void init_chantab(void);
00046 extern void cf_init(void);
00047 extern void pcache_init(void);
00048 extern int cf_read(char *fn);
00049 extern void init_functab(void);
00050 extern void close_sockets(int emergency, char *message);
00051 extern void init_version(void);
00052 extern void init_logout_cmdtab(void);
00053 extern void init_timer(void);
00054 extern void raw_notify(dbref, const char *);
00055 extern void do_second(void);
00056 extern void do_dbck(dbref, dbref, int);
00057
00058 #ifdef ARBITRARY_LOGFILES
00059 void logcache_init();
00060 void logcache_destruct();
00061 #endif
00062
00063 #ifdef HUDINFO_SUPPORT
00064 extern void init_hudinfo(void);
00065 #endif
00066
00067 void fork_and_dump(int);
00068 void dump_database(void);
00069 void do_dump_optimize(dbref, dbref, int);
00070 void pcache_sync(void);
00071 void dump_database_internal(int);
00072 static void init_rlimit(void);
00073
00074 int reserved;
00075
00076 extern int corrupt;
00077
00078
00079
00080
00081
00082
00083 void do_dump(dbref player, dbref cause, int key)
00084 {
00085 notify(player, "Dumping...");
00086
00087
00088
00089
00090
00091
00092
00093 if(key & DUMP_OPTIMIZE)
00094 do_dump_optimize(player, cause, key);
00095 else
00096 fork_and_dump(key);
00097 }
00098
00099 void do_dump_optimize(dbref player, dbref cause, int key)
00100 {
00101 raw_notify(player, "Database is memory based.");
00102 }
00103
00107 void report(void)
00108 {
00109 STARTLOG(LOG_BUGS, "BUG", "INFO") {
00110 log_text((char *) "Command: '");
00111 log_text(mudstate.debug_cmd);
00112 log_text((char *) "'");
00113 ENDLOG;
00114 } if(Good_obj(mudstate.curr_player)) {
00115 STARTLOG(LOG_BUGS, "BUG", "INFO") {
00116 log_text((char *) "Player: ");
00117 log_name_and_loc(mudstate.curr_player);
00118 if((mudstate.curr_enactor != mudstate.curr_player) &&
00119 Good_obj(mudstate.curr_enactor)) {
00120 log_text((char *) " Enactor: ");
00121 log_name_and_loc(mudstate.curr_enactor);
00122 }
00123 ENDLOG;
00124 }}
00125 }
00126
00127
00128
00129
00130
00131 int regexp_match(char *pattern, char *str, char *args[], int nargs)
00132 {
00133 regex_t re;
00134 int got_match;
00135 regmatch_t pmatch[NSUBEXP];
00136 int i, len;
00137
00138
00139
00140
00141
00142
00143
00144 if(regcomp(&re, pattern, REG_EXTENDED) != 0) {
00145
00146
00147
00148
00149
00150 return 0;
00151 }
00152
00153
00154
00155
00156
00157 got_match = (regexec(&re, str, NSUBEXP, pmatch, 0) == 0);
00158 if(!got_match) {
00159 regfree(&re);
00160 return 0;
00161 }
00162
00163
00164
00165
00166
00167
00168
00169
00170 for(i = 0; i < nargs; i++) {
00171 args[i] = NULL;
00172 }
00173
00174
00175
00176
00177
00178
00179 for(i = 0; (i < NSUBEXP) && (pmatch[i].rm_so != -1) && (pmatch[i].rm_eo != -1); i++) {
00180 len = pmatch[i].rm_eo - pmatch[i].rm_so;
00181 args[i] = alloc_lbuf("regexp_match");
00182 memset(args[i], 0, LBUF_SIZE);
00183 strncpy(args[i], str + pmatch[i].rm_so, len);
00184 args[i][len] = '\0';
00185 }
00186
00187 regfree(&re);
00188 return 1;
00189 }
00190
00194 static int atr_match1(dbref thing, dbref parent, dbref player, char type,
00195 char *str, int check_exclude, int hash_insert)
00196 {
00197 dbref aowner;
00198 int match, attr, aflags, i;
00199 char buff[LBUF_SIZE], *s, *as;
00200 char *args[10];
00201 ATTR *ap;
00202
00203 memset(args, 0, sizeof(args));
00204
00205
00206
00207
00208
00209 if(!could_doit(player, parent, A_LUSE))
00210 return -1;
00211
00212 match = 0;
00213 for(attr = atr_head(parent, &as); attr; attr = atr_next(&as)) {
00214 ap = atr_num(attr);
00215
00216
00217
00218
00219
00220 if(!ap || (ap->flags & AF_NOPROG))
00221 continue;
00222
00223
00224
00225
00226
00227
00228
00229 if(check_exclude && ((ap->flags & AF_PRIVATE) ||
00230 nhashfind(ap->number, &mudstate.parent_htab))) {
00231 continue;
00232 }
00233 atr_get_str(buff, parent, attr, &aowner, &aflags);
00234
00235
00236
00237
00238
00239 if(check_exclude && (aflags & AF_PRIVATE)) {
00240 continue;
00241 }
00242
00243
00244
00245
00246
00247 if(hash_insert)
00248 nhashadd(ap->number, (int *) &attr, &mudstate.parent_htab);
00249
00250
00251
00252
00253
00254
00255
00256 if((buff[0] != type) || (aflags & AF_NOPROG))
00257 continue;
00258
00259
00260
00261
00262
00263 for(s = buff + 1; *s && (*s != ':'); s++);
00264 if(!*s)
00265 continue;
00266 *s++ = 0;
00267 if(((aflags & AF_REGEXP) && regexp_match(buff + 1, str, args, 10))
00268 || wild(buff + 1, str, args, 10)) {
00269 match = 1;
00270 wait_que(thing, player, 0, NOTHING, 0, s, args, 10,
00271 mudstate.global_regs);
00272 for(i = 0; i < 10; i++) {
00273 if(args[i])
00274 free_lbuf(args[i]);
00275 }
00276 }
00277 }
00278 return (match);
00279 }
00280
00281 int atr_match(dbref thing, dbref player, char type, char *str,
00282 int check_parents)
00283 {
00284 int match, lev, result, exclude, insert;
00285 dbref parent;
00286
00287
00288
00289
00290
00291 if(Halted(thing))
00292 return 0;
00293
00294
00295
00296
00297
00298 match = 0;
00299 if(!check_parents)
00300 return atr_match1(thing, thing, player, type, str, 0, 0);
00301
00302
00303
00304
00305
00306 exclude = 0;
00307 insert = 1;
00308 nhashflush(&mudstate.parent_htab, 0);
00309 ITER_PARENTS(thing, parent, lev) {
00310 if(!Good_obj(Parent(parent)))
00311 insert = 0;
00312 result =
00313 atr_match1(thing, parent, player, type, str, exclude, insert);
00314 if(result > 0) {
00315 match = 1;
00316 } else if(result < 0) {
00317 return match;
00318 }
00319 exclude = 1;
00320 }
00321
00322 return match;
00323 }
00324
00329 int check_filter(dbref object, dbref player, int filter, const char *msg)
00330 {
00331 int aflags;
00332 dbref aowner;
00333 char *buf, *nbuf, *cp, *dp, *str;
00334
00335 buf = atr_pget(object, filter, &aowner, &aflags);
00336 if(!*buf) {
00337 free_lbuf(buf);
00338 return (1);
00339 }
00340 nbuf = dp = alloc_lbuf("check_filter");
00341 str = buf;
00342 exec(nbuf, &dp, 0, object, player, EV_FIGNORE | EV_EVAL | EV_TOP, &str,
00343 (char **) NULL, 0);
00344 *dp = '\0';
00345 dp = nbuf;
00346 free_lbuf(buf);
00347 do {
00348 cp = parse_to(&dp, ',', EV_STRIP);
00349 if(quick_wild(cp, (char *) msg)) {
00350 free_lbuf(nbuf);
00351 return (0);
00352 }
00353 } while (dp != NULL);
00354 free_lbuf(nbuf);
00355 return (1);
00356 }
00357
00358 static char *add_prefix(dbref object, dbref player, int prefix,
00359 const char *msg, const char *dflt)
00360 {
00361 int aflags;
00362 dbref aowner;
00363 char *buf, *nbuf, *cp, *bp, *str;
00364
00365 buf = atr_pget(object, prefix, &aowner, &aflags);
00366 if(!*buf) {
00367 cp = buf;
00368 safe_str((char *) dflt, buf, &cp);
00369 } else {
00370 nbuf = bp = alloc_lbuf("add_prefix");
00371 str = buf;
00372 exec(nbuf, &bp, 0, object, player, EV_FIGNORE | EV_EVAL | EV_TOP,
00373 &str, (char **) NULL, 0);
00374 *bp = '\0';
00375 free_lbuf(buf);
00376 buf = nbuf;
00377 cp = &buf[strlen(buf)];
00378 }
00379 if(cp != buf)
00380 safe_str((char *) " ", buf, &cp);
00381 safe_str((char *) msg, buf, &cp);
00382 *cp = '\0';
00383 return (buf);
00384 }
00385
00386 static char *dflt_from_msg(dbref sender, dbref sendloc)
00387 {
00388 char *tp, *tbuff;
00389
00390 tp = tbuff = alloc_lbuf("notify_checked.fwdlist");
00391 safe_str((char *) "From ", tbuff, &tp);
00392 if(Good_obj(sendloc))
00393 safe_str(Name(sendloc), tbuff, &tp);
00394 else
00395 safe_str(Name(sender), tbuff, &tp);
00396 safe_chr(',', tbuff, &tp);
00397 *tp = '\0';
00398 return tbuff;
00399 }
00400
00401 char *colorize(dbref player, char *from);
00402
00403 void notify_checked(dbref target, dbref sender, const char *msg, int key)
00404 {
00405 char *msg_ns, *mp, *tbuff, *tp, *buff, *colbuf = NULL;
00406 char *args[10];
00407 dbref aowner, targetloc, recip, obj;
00408 int i, nargs, aflags, has_neighbors, pass_listen;
00409 int check_listens, pass_uselock, is_audible;
00410 FWDLIST *fp;
00411
00412
00413
00414
00415
00416 if(!Good_obj(target) || !msg || !*msg)
00417 return;
00418
00419
00420
00421
00422
00423 mudstate.ntfy_nest_lev++;
00424 if(mudstate.ntfy_nest_lev >= mudconf.ntfy_nest_lim) {
00425 mudstate.ntfy_nest_lev--;
00426 return;
00427 }
00428
00429
00430
00431
00432
00433 if(key & MSG_ME) {
00434 mp = msg_ns = alloc_lbuf("notify_checked");
00435 if(Nospoof(target) && (target != sender) &&
00436 (target != mudstate.curr_enactor) &&
00437 (target != mudstate.curr_player && Good_obj(sender))) {
00438
00439
00440
00441
00442
00443
00444
00445
00446 tbuff = alloc_sbuf("notify_checked.nospoof");
00447 safe_chr('[', msg_ns, &mp);
00448 safe_str(Name(sender), msg_ns, &mp);
00449 sprintf(tbuff, "(#%d)", sender);
00450 safe_str(tbuff, msg_ns, &mp);
00451
00452 if(sender != Owner(sender)) {
00453 safe_chr('{', msg_ns, &mp);
00454 safe_str(Name(Owner(sender)), msg_ns, &mp);
00455 safe_chr('}', msg_ns, &mp);
00456 }
00457 if(sender != mudstate.curr_enactor) {
00458 sprintf(tbuff, "<-(#%d)", mudstate.curr_enactor);
00459 safe_str(tbuff, msg_ns, &mp);
00460 }
00461 safe_str((char *) "] ", msg_ns, &mp);
00462 free_sbuf(tbuff);
00463 }
00464 safe_str((char *) msg, msg_ns, &mp);
00465 *mp = '\0';
00466 } else {
00467 msg_ns = NULL;
00468 }
00469
00470
00471
00472
00473
00474 check_listens = Halted(target) ? 0 : 1;
00475 switch (Typeof(target)) {
00476 case TYPE_PLAYER:
00477 if(key & MSG_ME) {
00478 if(key & MSG_COLORIZE)
00479 colbuf = colorize(target, msg_ns);
00480 raw_notify(target, colbuf ? colbuf : msg_ns);
00481
00482
00483 }
00484
00485 if(colbuf)
00486 free_lbuf(colbuf);
00487 if(!mudconf.player_listen)
00488 check_listens = 0;
00489 case TYPE_THING:
00490 case TYPE_ROOM:
00491
00492
00493
00494
00495
00496 if(mudstate.inpipe && (!isPlayer(target) || (isPlayer(target) &&
00497 !Connected(target)))) {
00498 raw_notify(target, msg_ns);
00499 }
00500
00501
00502
00503
00504
00505 has_neighbors = Has_location(target);
00506 targetloc = where_is(target);
00507 is_audible = Audible(target);
00508
00509 if((key & MSG_ME) && Puppet(target) && (target != Owner(target))
00510 && ((key & MSG_PUP_ALWAYS) ||
00511 ((targetloc != Location(Owner(target))) &&
00512 (targetloc != Owner(target))))) {
00513 tp = tbuff = alloc_lbuf("notify_checked.puppet");
00514 safe_str(Name(target), tbuff, &tp);
00515 safe_str((char *) "> ", tbuff, &tp);
00516 if(key & MSG_COLORIZE)
00517 colbuf = colorize(Owner(target), msg_ns);
00518 safe_str(colbuf ? colbuf : msg_ns, tbuff, &tp);
00519 *tp = '\0';
00520 raw_notify(Owner(target), tbuff);
00521 if(colbuf)
00522 free_lbuf(colbuf);
00523 free_lbuf(tbuff);
00524 }
00525
00526
00527
00528
00529 pass_listen = 0;
00530 nargs = 0;
00531 if(check_listens && (key & (MSG_ME | MSG_INV_L)) && H_Listen(target)) {
00532 tp = atr_get(target, A_LISTEN, &aowner, &aflags);
00533 if(*tp && wild(tp, (char *) msg, args, 10)) {
00534 for(nargs = 10;
00535 nargs && (!args[nargs - 1] || !(*args[nargs - 1]));
00536 nargs--);
00537 pass_listen = 1;
00538 }
00539 free_lbuf(tp);
00540 }
00541
00542
00543
00544
00545
00546 if(sender < 0)
00547 sender = GOD;
00548 pass_uselock = 0;
00549 if((key & MSG_ME) && check_listens && (pass_listen ||
00550 Monitor(target)))
00551 pass_uselock = could_doit(sender, target, A_LUSE);
00552
00553
00554
00555
00556
00557 if((key & MSG_ME) && pass_listen && pass_uselock) {
00558 if(sender != target)
00559 did_it(sender, target, 0, NULL, 0, NULL, A_AHEAR, args,
00560 nargs);
00561 else
00562 did_it(sender, target, 0, NULL, 0, NULL, A_AMHEAR, args,
00563 nargs);
00564 did_it(sender, target, 0, NULL, 0, NULL, A_AAHEAR, args, nargs);
00565 }
00566
00567
00568
00569
00570 if(pass_listen) {
00571 for(i = 0; i < 10; i++)
00572 if(args[i] != NULL)
00573 free_lbuf(args[i]);
00574 }
00575
00576
00577
00578
00579
00580
00581
00582 if((key & MSG_ME) && (sender != target || Staff(target))
00583 && pass_uselock && Monitor(target)) {
00584 (void) atr_match(target, sender, AMATCH_LISTEN, (char *) msg, 0);
00585 }
00586
00587
00588
00589
00590 if((key & MSG_FWDLIST) && Audible(target) &&
00591 check_filter(target, sender, A_FILTER, msg)) {
00592 tbuff = dflt_from_msg(sender, target);
00593 buff = add_prefix(target, sender, A_PREFIX, msg, tbuff);
00594 free_lbuf(tbuff);
00595
00596 fp = fwdlist_get(target);
00597 if(fp) {
00598 for(i = 0; i < fp->count; i++) {
00599 recip = fp->data[i];
00600 if(!Good_obj(recip) || (recip == target))
00601 continue;
00602 notify_checked(recip, sender, buff,
00603 (MSG_ME | MSG_F_UP | MSG_F_CONTENTS |
00604 MSG_S_INSIDE));
00605 }
00606 }
00607 free_lbuf(buff);
00608 }
00609
00610
00611
00612
00613 if(key & MSG_INV_EXITS) {
00614 DOLIST(obj, Exits(target)) {
00615 recip = Location(obj);
00616 if(Audible(obj) && ((recip != target) &&
00617 check_filter(obj, sender, A_FILTER,
00618 msg))) {
00619 buff =
00620 add_prefix(obj, target, A_PREFIX, msg,
00621 "From a distance,");
00622 notify_checked(recip, sender, buff,
00623 MSG_ME | MSG_F_UP | MSG_F_CONTENTS |
00624 MSG_S_INSIDE);
00625 free_lbuf(buff);
00626 }
00627 }
00628 }
00629
00630
00631
00632
00633 if(has_neighbors && ((key & MSG_NBR_EXITS) ||
00634 ((key & MSG_NBR_EXITS_A) && is_audible))) {
00635
00636
00637
00638
00639
00640
00641
00642 if(key & MSG_S_INSIDE) {
00643 tbuff = dflt_from_msg(sender, target);
00644 buff = add_prefix(target, sender, A_PREFIX, msg, tbuff);
00645 free_lbuf(tbuff);
00646 } else {
00647 buff = (char *) msg;
00648 }
00649
00650 DOLIST(obj, Exits(Location(target))) {
00651 recip = Location(obj);
00652 if(Good_obj(recip) && Audible(obj) && (recip != targetloc)
00653 && (recip != target) &&
00654 check_filter(obj, sender, A_FILTER, msg)) {
00655 tbuff =
00656 add_prefix(obj, target, A_PREFIX, buff,
00657 "From a distance,");
00658 notify_checked(recip, sender, tbuff,
00659 MSG_ME | MSG_F_UP | MSG_F_CONTENTS |
00660 MSG_S_INSIDE);
00661 free_lbuf(tbuff);
00662 }
00663 }
00664 if(key & MSG_S_INSIDE) {
00665 free_lbuf(buff);
00666 }
00667 }
00668
00669
00670
00671
00672 if(((key & MSG_INV) || ((key & MSG_INV_L) && pass_listen)) &&
00673 (check_filter(target, sender, A_INFILTER, msg))) {
00674
00675
00676
00677
00678
00679
00680 if(key & MSG_S_OUTSIDE) {
00681 buff = add_prefix(target, sender, A_INPREFIX, msg, "");
00682 } else {
00683 buff = (char *) msg;
00684 }
00685 DOLIST(obj, Contents(target)) {
00686 if(Slave(obj) && (key & MSG_NO_SLAVE))
00687 continue;
00688 if(obj != target) {
00689 notify_checked(obj, sender, buff,
00690 MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE );
00691 }
00692 }
00693 if(key & MSG_S_OUTSIDE)
00694 free_lbuf(buff);
00695 }
00696
00697
00698
00699
00700 if(has_neighbors && ((key & MSG_NBR) || ((key & MSG_NBR_A) &&
00701 is_audible &&
00702 check_filter(target, sender,
00703 A_FILTER,
00704 msg)))) {
00705 if(key & MSG_S_INSIDE) {
00706 tbuff = dflt_from_msg(sender, target);
00707 buff = add_prefix(target, sender, A_PREFIX, msg, "");
00708 free_lbuf(tbuff);
00709 } else {
00710 buff = (char *) msg;
00711 }
00712 DOLIST(obj, Contents(targetloc)) {
00713 if((obj != target) && (obj != targetloc)) {
00714 notify_checked(obj, sender, buff,
00715 MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE | (key
00716 &
00717 MSG_COLORIZE));
00718 }
00719 }
00720 if(key & MSG_S_INSIDE) {
00721 free_lbuf(buff);
00722 }
00723 }
00724
00725
00726
00727
00728 if(has_neighbors && ((key & MSG_LOC) || ((key & MSG_LOC_A) &&
00729 is_audible &&
00730 check_filter(target, sender,
00731 A_FILTER,
00732 msg)))) {
00733 if(key & MSG_S_INSIDE) {
00734 tbuff = dflt_from_msg(sender, target);
00735 buff = add_prefix(target, sender, A_PREFIX, msg, tbuff);
00736 free_lbuf(tbuff);
00737 } else {
00738 buff = (char *) msg;
00739 }
00740 notify_checked(targetloc, sender, buff,
00741 MSG_ME | MSG_F_UP | MSG_S_INSIDE);
00742 if(key & MSG_S_INSIDE) {
00743 free_lbuf(buff);
00744 }
00745 }
00746 }
00747 if(msg_ns)
00748 free_lbuf(msg_ns);
00749 mudstate.ntfy_nest_lev--;
00750 }
00751
00752 void notify_except(dbref loc, dbref player, dbref exception, const char *msg)
00753 {
00754 dbref first;
00755
00756 if(loc != exception)
00757 notify_checked(loc, player, msg,
00758 (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE |
00759 MSG_NBR_EXITS_A));
00760 DOLIST(first, Contents(loc)) {
00761 if(exception == NOSLAVE)
00762 if(Slave(first))
00763 continue;
00764 if(first != exception)
00765 notify_checked(first, player, msg,
00766 (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE |
00767 (exception == NOSLAVE ? MSG_NO_SLAVE : 0)));
00768 }
00769 }
00770
00771 void notify_except2(dbref loc, dbref player, dbref exc1, dbref exc2,
00772 const char *msg)
00773 {
00774 dbref first;
00775
00776 if((loc != exc1) && (loc != exc2))
00777 notify_checked(loc, player, msg,
00778 (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE |
00779 MSG_NBR_EXITS_A));
00780 DOLIST(first, Contents(loc)) {
00781 if(first != exc1 && first != exc2) {
00782 notify_checked(first, player, msg,
00783 (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE));
00784 }
00785 }
00786 }
00787
00788 void do_shutdown(dbref player, dbref cause, int key, char *message)
00789 {
00790 FILE *fs;
00791
00792 ResetSpecialObjects();
00793 if(player != NOTHING) {
00794 raw_broadcast(0, "Game: Shutdown by %s", Name(Owner(player)));
00795 STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN") {
00796 log_text((char *) "Shutdown by ");
00797 log_name(player);
00798 ENDLOG;
00799 }
00800 } else {
00801 raw_broadcast(0, "Game: Fatal Error: %s", message);
00802 STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN") {
00803 log_text((char *) "Fatal error: ");
00804 log_text(message);
00805 ENDLOG;
00806 }
00807 }
00808 STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN") {
00809 log_text((char *) "Shutdown status: ");
00810 log_text(message);
00811 ENDLOG;
00812 }
00813
00814 fs = fopen(mudconf.status_file, "w");
00815 fprintf(fs, "%s\n", message);
00816 fclose(fs);
00817
00818
00819
00820
00821
00822
00823
00824 if(key & SHUTDN_PANIC) {
00825
00826
00827
00828
00829
00830 emergency_shutdown();
00831
00832
00833
00834
00835
00836 pcache_sync();
00837 STARTLOG(LOG_ALWAYS, "DMP", "PANIC") {
00838 log_text((char *) "Panic dump: ");
00839 log_text(mudconf.crashdb);
00840 ENDLOG;
00841 } dump_database_internal(DUMP_CRASHED);
00842
00843 STARTLOG(LOG_ALWAYS, "DMP", "DONE") {
00844 log_text((char *) "Panic dump complete: ");
00845 log_text(mudconf.crashdb);
00846 ENDLOG;
00847 }
00848 }
00849
00850
00851
00852
00853 mudstate.shutdown_flag = 1;
00854 event_loopexit(NULL);
00855 return;
00856 }
00857
00858 void dump_database_internal(int dump_type)
00859 {
00860 char tmpfile[256], outfn[256], prevfile[256];
00861 FILE *f;
00862
00863 #ifdef USE_PYTHON
00864 runPythonHook("save");
00865 #endif
00866
00867 if(dump_type == DUMP_CRASHED) {
00868 unlink(mudconf.crashdb);
00869 f = fopen(mudconf.crashdb, "w");
00870 if(f != NULL) {
00871 db_write(f, F_MUX, UNLOAD_VERSION | UNLOAD_OUTFLAGS);
00872 fclose(f);
00873 } else {
00874 log_perror("DMP", "FAIL", "Opening crash file", mudconf.crashdb);
00875 }
00876 if(mudconf.have_mailer)
00877 if((f = fopen(mudconf.mail_db, "w"))) {
00878 dump_mail(f);
00879 fclose(f);
00880 }
00881 if(mudconf.have_comsys || mudconf.have_macros)
00882 save_comsys_and_macros(mudconf.commac_db);
00883 SaveSpecialObjects(DUMP_CRASHED);
00884 return;
00885 }
00886
00887 if(dump_type == DUMP_RESTART) {
00888 f = fopen(mudconf.indb, "w");
00889 if(f != NULL) {
00890
00891 db_write(f, F_MUX, UNLOAD_VERSION | UNLOAD_OUTFLAGS);
00892 fclose(f);
00893 } else {
00894 log_perror("DMP", "FAIL", "Opening restart file", mudconf.indb);
00895 }
00896 if(mudconf.have_mailer)
00897 if((f = fopen(mudconf.mail_db, "w"))) {
00898 dump_mail(f);
00899 fclose(f);
00900 }
00901 if(mudconf.have_comsys || mudconf.have_macros)
00902 save_comsys_and_macros(mudconf.commac_db);
00903 if(mudconf.have_specials)
00904 SaveSpecialObjects(DUMP_RESTART);
00905 return;
00906 }
00907 if(dump_type == DUMP_KILLED) {
00908 sprintf(tmpfile, "%s.KILLED", mudconf.indb);
00909 f = fopen(tmpfile, "w");
00910 if(f != NULL) {
00911
00912 db_write(f, F_MUX, UNLOAD_VERSION | UNLOAD_OUTFLAGS);
00913 fclose(f);
00914 } else {
00915 log_perror("DMP", "FAIL", "Opening killed file", mudconf.indb);
00916 }
00917 if(mudconf.have_mailer)
00918 if((f = fopen(mudconf.mail_db, "w"))) {
00919 dump_mail(f);
00920 fclose(f);
00921 }
00922 if(mudconf.have_comsys || mudconf.have_macros)
00923 save_comsys_and_macros(mudconf.commac_db);
00924 if(mudconf.have_specials)
00925 SaveSpecialObjects(DUMP_KILLED);
00926 return;
00927 }
00928
00929 sprintf(prevfile, "%s.prev", mudconf.outdb);
00930 sprintf(tmpfile, "%s.#%d#", mudconf.outdb, mudstate.epoch - 1);
00931 unlink(tmpfile);
00932
00933
00934 sprintf(tmpfile, "%s.#%d#", mudconf.outdb, mudstate.epoch);
00935
00936 if(mudconf.compress_db) {
00937 sprintf(tmpfile, "%s.#%d#.gz", mudconf.outdb, mudstate.epoch - 1);
00938 unlink(tmpfile);
00939 sprintf(tmpfile, "%s.#%d#.gz", mudconf.outdb, mudstate.epoch);
00940 StringCopy(outfn, mudconf.outdb);
00941 strcat(outfn, ".gz");
00942 f = popen(tprintf("%s > %s", mudconf.compress, tmpfile), "w");
00943 if(f) {
00944 db_write(f, F_MUX, OUTPUT_VERSION | OUTPUT_FLAGS);
00945 pclose(f);
00946 rename(mudconf.outdb, prevfile);
00947 if(rename(tmpfile, outfn) < 0)
00948 log_perror("SAV", "FAIL",
00949 "Renaming output file to DB file", tmpfile);
00950 } else {
00951 log_perror("SAV", "FAIL", "Opening", tmpfile);
00952 }
00953 } else {
00954 f = fopen(tmpfile, "w");
00955 if(f) {
00956 db_write(f, F_MUX, OUTPUT_VERSION | OUTPUT_FLAGS);
00957 fclose(f);
00958 rename(mudconf.outdb, prevfile);
00959 if(rename(tmpfile, mudconf.outdb) < 0)
00960 log_perror("SAV", "FAIL",
00961 "Renaming output file to DB file", tmpfile);
00962 } else {
00963 log_perror("SAV", "FAIL", "Opening", tmpfile);
00964 }
00965 rename(prevfile, mudconf.indb);
00966 }
00967
00968 if(mudconf.have_mailer)
00969 if((f = fopen(mudconf.mail_db, "w"))) {
00970 dump_mail(f);
00971 fclose(f);
00972 }
00973 if(mudconf.have_comsys || mudconf.have_macros)
00974 save_comsys_and_macros(mudconf.commac_db);
00975 if(mudconf.have_specials)
00976 SaveSpecialObjects(DUMP_NORMAL);
00977 }
00978
00979 void dump_database(void)
00980 {
00981 char *buff;
00982
00983 mudstate.epoch++;
00984 mudstate.dumping = 1;
00985 buff = alloc_mbuf("dump_database");
00986 sprintf(buff, "%s.#%d#", mudconf.outdb, mudstate.epoch);
00987 STARTLOG(LOG_DBSAVES, "DMP", "DUMP") {
00988 log_text((char *) "Dumping: ");
00989 log_text(buff);
00990 ENDLOG;
00991 } pcache_sync();
00992
00993 dump_database_internal(DUMP_NORMAL);
00994 STARTLOG(LOG_DBSAVES, "DMP", "DONE") {
00995 log_text((char *) "Dump complete: ");
00996 log_text(buff);
00997 ENDLOG;
00998 } free_mbuf(buff);
00999
01000 mudstate.dumping = 0;
01001 }
01002
01003 void fork_and_dump(int key)
01004 {
01005 char *buff;
01006
01007 if(*mudconf.dump_msg)
01008 raw_broadcast(0, "%s", mudconf.dump_msg);
01009
01010 check_mail_expiration();
01011 mudstate.epoch++;
01012 mudstate.dumping = 1;
01013 buff = alloc_mbuf("fork_and_dump");
01014 sprintf(buff, "%s.#%d#", mudconf.outdb, mudstate.epoch);
01015
01016 log_error(LOG_DBSAVES, "DMP", "CHKPT", "Saving database: %s", buff);
01017
01018 pcache_sync();
01019
01020 if(!key || (key & DUMP_STRUCT)) {
01021 if(!fork()) {
01022 dprintk("child database write process starting.");
01023 unbind_signals();
01024 dump_database_internal(DUMP_NORMAL);
01025 dprintk("child database write process finished.");
01026 exit(0);
01027 }
01028 }
01029
01030 mudstate.dumping = 0;
01031
01032 if(*mudconf.postdump_msg)
01033 raw_broadcast(0, "%s", mudconf.postdump_msg);
01034 }
01035
01036 static int load_game(void)
01037 {
01038 FILE *f;
01039 int compressed;
01040 char infile[256];
01041 struct stat statbuf;
01042 int db_format, db_version, db_flags;
01043
01044 f = NULL;
01045 compressed = 0;
01046 if(mudconf.compress_db) {
01047 StringCopy(infile, mudconf.indb);
01048 strcat(infile, ".gz");
01049 if(stat(infile, &statbuf) == 0) {
01050 if((f = popen(tprintf(" %s < %s", mudconf.uncompress,
01051 infile), "r")) != NULL)
01052 compressed = 1;
01053 }
01054 }
01055 if(compressed == 0) {
01056 StringCopy(infile, mudconf.indb);
01057 if((f = fopen(mudconf.indb, "r")) == NULL)
01058 return -1;
01059 }
01060
01061
01062
01063
01064 STARTLOG(LOG_STARTUP, "INI", "LOAD") {
01065 log_text((char *) "Loading: ");
01066 log_text(infile);
01067 ENDLOG;
01068 };
01069 if(db_read(f, &db_format, &db_version, &db_flags) < 0) {
01070 STARTLOG(LOG_ALWAYS, "INI", "FATAL") {
01071 log_text((char *) "Error loading ");
01072 log_text(infile);
01073 ENDLOG;
01074 }
01075 if(compressed)
01076 pclose(f);
01077 else
01078 fclose(f);
01079 return -1;
01080 }
01081 if(compressed)
01082 pclose(f);
01083 else
01084 fclose(f);
01085
01086 if(mudconf.have_comsys || mudconf.have_macros)
01087 load_comsys_and_macros(mudconf.commac_db);
01088
01089
01090 if(mudconf.have_specials)
01091 LoadSpecialObjects();
01092
01093 if(mudconf.have_mailer)
01094 if((f = fopen(mudconf.mail_db, "r"))) {
01095 load_mail(f);
01096 fclose(f);
01097 }
01098 STARTLOG(LOG_STARTUP, "INI", "LOAD") {
01099 log_text((char *) "Load complete.");
01100 ENDLOG;
01101 }
01102
01103
01104
01105 return (0);
01106 }
01107
01111 int list_check(dbref thing, dbref player, char type, char *str,
01112 int check_parent)
01113 {
01114 int match, limit;
01115
01116 match = 0;
01117 limit = mudstate.db_top;
01118 while (thing != NOTHING) {
01119 if((thing != player) && (!(No_Command(thing)))) {
01120 if(atr_match(thing, player, type, str, check_parent) > 0)
01121 match = 1;
01122 }
01123 thing = Next(thing);
01124 if(--limit < 0)
01125 return match;
01126 }
01127 return match;
01128 }
01129
01130 int Hearer(dbref thing)
01131 {
01132 char *as, *buff, *s;
01133 dbref aowner;
01134 int attr, aflags;
01135 ATTR *ap;
01136
01137 if(mudstate.inpipe && (thing == mudstate.poutobj))
01138 return 1;
01139
01140 if(Connected(thing) || Puppet(thing))
01141 return 1;
01142
01143 if(Monitor(thing))
01144 buff = alloc_lbuf("Hearer");
01145 else
01146 buff = NULL;
01147 for(attr = atr_head(thing, &as); attr; attr = atr_next(&as)) {
01148 if(attr == A_LISTEN) {
01149 if(buff)
01150 free_lbuf(buff);
01151 return 1;
01152 }
01153 if(Monitor(thing)) {
01154 ap = atr_num(attr);
01155 if(!ap || (ap->flags & AF_NOPROG))
01156 continue;
01157
01158 atr_get_str(buff, thing, attr, &aowner, &aflags);
01159
01160
01161
01162
01163
01164 if((buff[0] != AMATCH_LISTEN) || (aflags & AF_NOPROG))
01165 continue;
01166
01167
01168
01169
01170
01171 for(s = buff + 1; *s && (*s != ':'); s++);
01172 if(s) {
01173 free_lbuf(buff);
01174 return 1;
01175 }
01176 }
01177 }
01178 if(buff)
01179 free_lbuf(buff);
01180 return 0;
01181 }
01182
01183 void do_readcache(dbref player, dbref cause, int key)
01184 {
01185 helpindex_load(player);
01186 fcache_load(player);
01187 }
01188
01189 static void process_preload(void)
01190 {
01191 dbref thing, parent, aowner;
01192 int aflags, lev, i;
01193 char *tstr;
01194 FWDLIST *fp;
01195
01196 fp = (FWDLIST *) alloc_lbuf("process_preload.fwdlist");
01197 tstr = alloc_lbuf("process_preload.string");
01198 i = 0;
01199 DO_WHOLE_DB(thing) {
01200
01201
01202
01203
01204
01205 if(Going(thing))
01206 continue;
01207
01208 do_top(10);
01209
01210
01211
01212
01213
01214 ITER_PARENTS(thing, parent, lev) {
01215 if(Flags(thing) & HAS_STARTUP) {
01216 did_it(Owner(thing), thing, 0, NULL, 0, NULL, A_STARTUP,
01217 (char **) NULL, 0);
01218
01219
01220
01221
01222 do_second();
01223 do_top(10);
01224 break;
01225 }
01226 }
01227
01228
01229
01230
01231
01232 if(H_Fwdlist(thing)) {
01233 (void) atr_get_str(tstr, thing, A_FORWARDLIST, &aowner, &aflags);
01234 if(*tstr) {
01235 fwdlist_load(fp, GOD, tstr);
01236 if(fp->count > 0)
01237 fwdlist_set(thing, fp);
01238 }
01239 }
01240 }
01241 free_lbuf(fp);
01242 free_lbuf(tstr);
01243 }
01244
01245 int main(int argc, char *argv[])
01246 {
01247 int mindb;
01248
01249 if((argc > 2) && (!strcmp(argv[1], "-s") && (argc > 3))) {
01250 fprintf(stderr, "Usage: %s [-s] [config-file]\n", argv[0]);
01251 exit(1);
01252 }
01253
01254 event_init();
01255
01256 #if defined(HAVE_IEEEFP_H) && defined(HAVE_SYS_UCONTEXT_H)
01257
01258
01259
01260
01261 fpsetmask(fpgetmask() & ~FP_X_OFL);
01262 #endif
01263
01264 mindb = 0;
01265 corrupt = 0;
01266 memset(&mudstate, 0, sizeof(mudstate));
01267 time(&mudstate.start_time);
01268 time(&mudstate.restart_time);
01269 mudstate.executable_path = strdup(argv[0]);
01270 mudstate.db_top = -1;
01271 tcache_init();
01272 pcache_init();
01273 cf_init();
01274 init_rlimit();
01275 init_cmdtab();
01276 init_mactab();
01277 init_chantab();
01278 init_logout_cmdtab();
01279 init_flagtab();
01280 init_powertab();
01281 init_functab();
01282 init_attrtab();
01283 init_version();
01284
01285 #ifdef HUDINFO_SUPPORT
01286 init_hudinfo();
01287 #endif
01288
01289 hashinit(&mudstate.player_htab, 250 * HASH_FACTOR);
01290 nhashinit(&mudstate.mail_htab, 50 * HASH_FACTOR);
01291 nhashinit(&mudstate.fwdlist_htab, 25 * HASH_FACTOR);
01292 nhashinit(&mudstate.parent_htab, 5 * HASH_FACTOR);
01293 mudstate.desctree = rb_init(desc_cmp, NULL);
01294 vattr_init();
01295
01296 if(argc > 1 && !strcmp(argv[1], "-s")) {
01297 mindb = 1;
01298 if(argc == 3)
01299 cf_read(argv[2]);
01300 else
01301 cf_read((char *) CONF_FILE);
01302 } else if(argc == 2) {
01303 cf_read(argv[1]);
01304 } else {
01305 cf_read((char *) CONF_FILE);
01306 }
01307
01308 fcache_init();
01309 helpindex_init();
01310 db_free();
01311
01312 mudstate.record_players = 0;
01313
01314 if(mindb)
01315 db_make_minimal();
01316 else if(load_game() < 0) {
01317 STARTLOG(LOG_ALWAYS, "INI", "LOAD") {
01318 log_text((char *) "Couldn't load: ");
01319 log_text(mudconf.indb);
01320 ENDLOG;
01321 } exit(2);
01322 }
01323 #ifdef USE_PYTHON
01324 MUXPy_Init();
01325 runPythonHook("load");
01326 #endif
01327
01328
01329 srandom(getpid());
01330
01331 bind_signals();
01332
01333
01334
01335
01336
01337 do_dbck(NOTHING, NOTHING, 0);
01338
01339
01340
01341
01342
01343 hashreset(&mudstate.command_htab);
01344 hashreset(&mudstate.macro_htab);
01345 hashreset(&mudstate.channel_htab);
01346 nhashreset(&mudstate.mail_htab);
01347 hashreset(&mudstate.logout_cmd_htab);
01348 hashreset(&mudstate.func_htab);
01349 hashreset(&mudstate.flags_htab);
01350 hashreset(&mudstate.attr_name_htab);
01351 hashreset(&mudstate.player_htab);
01352 nhashreset(&mudstate.fwdlist_htab);
01353 hashreset(&mudstate.news_htab);
01354 hashreset(&mudstate.help_htab);
01355 hashreset(&mudstate.wizhelp_htab);
01356 hashreset(&mudstate.plushelp_htab);
01357 hashreset(&mudstate.wiznews_htab);
01358
01359 for(mindb = 0; mindb < MAX_GLOBAL_REGS; mindb++) {
01360 mudstate.global_regs[mindb] = alloc_lbuf("main.global_reg");
01361 memset(mudstate.global_regs[mindb], 0, LBUF_SIZE);
01362 }
01363
01364 mudstate.now = time(NULL);
01365 process_preload();
01366
01367 dnschild_init();
01368
01369 if(!load_restart_db_xdr()) {
01370 load_restart_db();
01371 }
01372
01373 #ifdef SQL_SUPPORT
01374 sqlchild_init();
01375 #endif
01376
01377 #ifdef ARBITRARY_LOGFILES
01378 logcache_init();
01379 #endif
01380
01381 #ifdef MCHECK
01382 mtrace();
01383 #endif
01384
01385
01386
01387
01388
01389 mudstate.now = time(NULL);
01390 init_timer();
01391 shovechars(mudconf.port);
01392
01393 #ifdef MCHECK
01394 muntrace();
01395 #endif
01396
01397 close_sockets(0, (char *) "Going down - Bye");
01398 dump_database();
01399
01400 #ifdef ARBITRARY_LOGFILES
01401 logcache_destruct();
01402 #endif
01403 #ifdef SQL_SUPPORT
01404 sqlchild_destruct();
01405 #endif
01406
01407 exit(0);
01408 }
01409
01410 static void init_rlimit(void)
01411 {
01412 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
01413 struct rlimit *rlp;
01414
01415 rlp = (struct rlimit *) alloc_lbuf("rlimit");
01416
01417 if(getrlimit(RLIMIT_NOFILE, rlp)) {
01418 log_perror("RLM", "FAIL", NULL, "getrlimit()");
01419 free_lbuf(rlp);
01420 return;
01421 }
01422 rlp->rlim_cur = rlp->rlim_max;
01423 if(setrlimit(RLIMIT_NOFILE, rlp))
01424 log_perror("RLM", "FAIL", NULL, "setrlimit()");
01425 free_lbuf(rlp);
01426
01427 #endif
01428
01429
01430 }