blob: 038f8a086f11a7343e937af785b102bd4217f472 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// master.c -- master object
4//
5// $Id: master.c 9530 2016-03-17 19:59:01Z Zesstra $
Zesstra9dd50132019-11-28 21:42:14 +01006#pragma strict_types
7#pragma no_clone
8#pragma no_shadow
9#pragma no_inherit
10#pragma verbose_errors
11#pragma combine_strings
12//#pragma pedantic
MG Mud User88f12472016-06-24 23:31:02 +020013#pragma range_check
14#pragma warn_deprecated
15
16#include "/sys/files.h"
17#include "/sys/interactive_info.h"
18#include "/sys/driver_info.h"
19
MG Mud User88f12472016-06-24 23:31:02 +020020//for limited, set_limit(), etc. Abs. Pfad noetig, da noch kein Include-Hook
21#include "/sys/rtlimits.h"
22#include "/sys/debug_info.h"
MG Mud User88f12472016-06-24 23:31:02 +020023#include "/sys/configuration.h"
Zesstraa6068542019-09-30 23:21:45 +020024#include "/sys/driver_hook.h"
MG Mud User88f12472016-06-24 23:31:02 +020025#include "/sys/regexp.h"
26
Zesstra9dd50132019-11-28 21:42:14 +010027#include "/secure/master.h"
28#include "/secure/config.h"
MG Mud User88f12472016-06-24 23:31:02 +020029// Module des Master einfuegen. Per #include, damits geringfuegig schneller.
30// Da die Module ja nirgendwo sonst geerbt werden koennten, ist dies
31// ausnahmsweise OK. ;)
32#include "/secure/master/destruct.c"
Zesstra9dd50132019-11-28 21:42:14 +010033#include "/secure/master/userinfo.c"
34#include "/secure/master/file_access.c"
35#include "/secure/master/misc.c"
36#include "/secure/master/players_deny.c"
MG Mud User88f12472016-06-24 23:31:02 +020037#include "/secure/master/autoinclude.c"
Zesstra9dd50132019-11-28 21:42:14 +010038#include "/secure/master/network.c"
39#include "/secure/master/domain.c"
40#include "/secure/master/guild.c"
41
MG Mud User88f12472016-06-24 23:31:02 +020042
43// Fuer Logfile(-Rotation)
44#define RESETINT 3600 // jede Stunde
45#define LOGROTATE (24*2) // alle 48h
46#define LOGFILEAGE (RESETINT*LOGROTATE) // alle 2 tage wechseln
47#define LOGNUM 3 // Anzahl der Logfiles
48
49private nosave int logrotate_counter; //READ_FILE alle LOGROTATE Resets rotieren
50// Wird gerade versucht, die simul_efuns zu laden? Wenn ja, duerfen keine
51// sefuns gerufen werden.
52private nosave int loading_simul_efuns;
53// wird gerade ein Fehler bearbeitet? Dient zur Erkennung von Rekursionen in
54// der Fehlerbehandlung
55private nosave int handling_error;
56
57// #####################
58//######################## Start des Masters ############################
59// #####################
60
61// Initialisierung des Masters
62//arg==0: Mud startet gerade, arg==1: Master wurde reaktiviert,
63//arg==2: Master reaktiviert (Variablen weg), arg==3: Master wurde
64//neugeladen.
65protected void inaugurate_master(int arg) {
66
67 set_driver_hook(H_REGEXP_PACKAGE, RE_TRADITIONAL);
Bugfix05c09d72017-02-14 21:26:20 +010068
Zesstra86607bb2017-06-17 19:02:40 +020069 efun::configure_object(this_object(), OC_EUID, ROOTID);
Bugfix05c09d72017-02-14 21:26:20 +010070
71 // Bei Neustart wizinfo initialisieren und ggf. Ordner in /data erstellen.
72 if (!arg)
73 {
74 set_extra_wizinfo(0, allocate(BACKBONE_WIZINFO_SIZE));
75 CreateDataDirectories();
76 }
77
Zesstra9dd50132019-11-28 21:42:14 +010078 userinfo_init();
MG Mud User88f12472016-06-24 23:31:02 +020079 LoadPLDenylists();
80
81 // Was soll vor jede Datei geschrieben werden?
82 set_driver_hook(H_AUTO_INCLUDE, #'autoincludehook);
83
84 //div. Listen einlesen
85 ReloadBanishFile();
86 ReloadDeputyFile();
87 ReloadInsecureFile();
Bugfix05c09d72017-02-14 21:26:20 +010088
MG Mud User88f12472016-06-24 23:31:02 +020089 //simul_efun.c nach inaugurate_master() starten und initialisieren,
90 //(so richtig seh ich den Sinn hier momentan nicht ein...
91 //call_out("start_simul_efun",0);
92
93 // Reset festsetzen (1h)
94 set_next_reset(RESETINT);
95
96 // Driver konfigurieren
97 // Lagerkennung erst ne Minute spaeter, waehrend preload darfs momentan
98 // ruhig laggen (Zeit: vorlaeufig 1min)
Zesstra92bb2dd2019-11-28 21:45:19 +010099 call_out(#'configure_driver, 60, DC_LONG_EXEC_TIME, 200000);
Zesstra879e6e12019-09-27 16:23:49 +0200100
MG Mud User88f12472016-06-24 23:31:02 +0200101 // Hooks setzen
Zesstra879e6e12019-09-27 16:23:49 +0200102
103 // Standard-Encoding fuer Dateien
104 set_driver_hook(H_FILE_ENCODING, "UTF-8");
105 // Und Encoding fuer Dateinamen im Filesystem
106 configure_driver(DC_FILESYSTEM_ENCODING, "UTF-8");
107
MG Mud User88f12472016-06-24 23:31:02 +0200108 // Standardincludeverzeichnisse fuer #include <>
109 set_driver_hook(H_INCLUDE_DIRS, ({"/secure/","/sys/"}) );
Zesstra879e6e12019-09-27 16:23:49 +0200110
MG Mud User88f12472016-06-24 23:31:02 +0200111 //Nach dem Laden/Clonen create() im Objekt rufen
112 set_driver_hook(H_CREATE_CLONE, "create");
113 set_driver_hook(H_CREATE_OB, "create");
114 set_driver_hook(H_CREATE_SUPER, "create_super");
115
116 // Bei Reset reset() im Objekt aufrufen
117 set_driver_hook(H_RESET, "reset");
Zesstra879e6e12019-09-27 16:23:49 +0200118
MG Mud User88f12472016-06-24 23:31:02 +0200119 // Zum Aufraeumen clean_up() im Objekt aufrufen
120 set_driver_hook(H_CLEAN_UP, "clean_up");
121
122 // Jede Eingabe wird ueber modify_command gelenkt
123 set_driver_hook(H_MODIFY_COMMAND, "modify_command");
124 // Dieser Hook ist mandatory, aber wird nur benutzt, wenn via
125 // set_modify_command() aktiviert - was wir nicht (mehr) tun. Insofern ist
126 // das Relikt aus alten Zeiten.
127 //set_driver_hook(H_MODIFY_COMMAND_FNAME, "modify_command");
128
129 // Standard-Fehlermeldung
130 //set_driver_hook(H_NOTIFY_FAIL, "Wie bitte?\n");
131 set_driver_hook(H_NOTIFY_FAIL, function string (string cmd, object tp)
Zesstrad872d182019-11-28 20:13:02 +0100132 {if (tp && stringp(cmd=({string})tp->QueryProp(P_DEFAULT_NOTIFY_FAIL)))
MG Mud User88f12472016-06-24 23:31:02 +0200133 return(cmd);
134 return("Wie bitte?\n");});
135
136 // Was machen bei telnet_neg
137 set_driver_hook(H_TELNET_NEG,"telnet_neg");
MG Mud User88f12472016-06-24 23:31:02 +0200138
139 // Promptbehandlung: Defaultprompt setzen und dafuer sorgen, dass alle
140 // Promptausgaben durch print_prompt im Interactive laufen, damit das EOR
141 // angehaengt wird.
142 set_driver_hook(H_PRINT_PROMPT, "print_prompt");
143 set_driver_hook(H_DEFAULT_PROMPT, "> ");
144
145 // EUID und UID muessen neue Objekte auch noch kriegen, Hooks dafuer setzen
146 set_driver_hook(H_LOAD_UIDS, #'load_uid_hook);
147 set_driver_hook(H_CLONE_UIDS, #'clone_uid_hook);
148
149 // Meldung bei vollem Mud
150 set_driver_hook(H_NO_IPC_SLOT, "Momentan sind leider zuviele Spieler im "
151 +MUDNAME+" eingeloggt.\nBitte komm doch etwas spaeter nochmal "
152 "vorbei!\n");
153
154 // Nun der beruechtigte Move-Hook ...
155 // (bewegt objekt und ruft alle notwendigen inits auf)
156 // Hier wird H_MOVE_OBJECT0 benutzt, d.h. die lambda wird an das aktuelle
157 // Objekt vor Ausfuehrung gebunden, nicht an 'item', was move_objet()
158 // uebergeben wurde.
159 set_driver_hook(H_MOVE_OBJECT0,
160 unbound_lambda(({'item,'dest}),
161 ({#',, // item!=this_object?
162 ({#'?,({#'!=,'item,({#'this_object})}),
163 ({#'raise_error, // ->Fehler!
164 "Illegal to move other object than this_object()\n"}) }),
Zesstra1b809c72018-03-02 00:31:58 +0100165 ({#'=,'oldenv,({#'environment,'item}) }), // altes Env merken
MG Mud User88f12472016-06-24 23:31:02 +0200166 ({#'efun::set_environment,'item,'dest}), // item nach dest bewegen
167 ({#'?,
168 ({#'living,'item}), // living(item)?
169 ({#',,
170 ({#'efun::set_this_player,'item}), // set_this_player(item)
Zesstra1b809c72018-03-02 00:31:58 +0100171 ({#'call_other,'dest,"init",'oldenv}),// dest->init(oldenv)
MG Mud User88f12472016-06-24 23:31:02 +0200172 ({#'?!,
173 ({#'&&, // !objectp(item)||
174 ({#'objectp, 'item}), // env(item)!=dest?
175 ({#'==,({#'environment, 'item}),'dest})}),
176 ({#'return})})})}), // -> fertig
177 ({#'=,'others,({#'-,({#'all_inventory,'dest}),({#'({,'item})})}),
178#ifdef EMACS_NERV
179 }) // Emacs kann ({#'({ nicht parsen // others=all_inv(dest)-
180#endif // ({item})
Zesstra1b809c72018-03-02 00:31:58 +0100181 ({#'filter,'others,lambda(({'ob,'item,'lastenv}),
MG Mud User88f12472016-06-24 23:31:02 +0200182 ({#'?,
183 ({#'&&,
184 ({#'objectp,'item}), // objectp(item)&&
185 ({#'living,'ob}), // living(ob)&&
186 ({#'==,({#'environment,'item}),({#'environment,'ob})})}),
187 ({#',, // env(item)==env(ob)?
188 ({#'efun::set_this_player, 'ob}), // set_this_player(ob)
Zesstra1b809c72018-03-02 00:31:58 +0100189 ({#'call_other,'item, "init",'lastenv}) // item->init(lastenv)
190 })})),'item,'oldenv}),
MG Mud User88f12472016-06-24 23:31:02 +0200191 ({#'?,
192 ({#'living,'item}), // living(item)?
193 ({#',,
194 ({#'efun::set_this_player,'item}), // set_this_player(item)
Zesstra1b809c72018-03-02 00:31:58 +0100195 ({#'filter,'others,lambda(({'ob,'item,'lastenv}),
MG Mud User88f12472016-06-24 23:31:02 +0200196 ({#'?,
197 ({#'&&,
198 ({#'objectp,'item}), // objectp(item)&&
199 ({#'objectp,'ob}), // objectp(ob)&&
200 ({#'==,({#'environment,'item}),({#'environment,'ob})})
201 }), // env(item)==env(ob)?
Zesstra1b809c72018-03-02 00:31:58 +0100202 ({#'call_other,'ob,"init",'lastenv}) // ob->init(lastenv)
203 })),'item, 'oldenv})})}),
MG Mud User88f12472016-06-24 23:31:02 +0200204 ({#'?,
205 ({#'&&,
206 ({#'objectp,'item}), // objectp(item)&&
207 ({#'living,'dest}), // living(dest)&&
208 ({#'==,({#'environment,'item}),'dest})// env(item)==dest?
209 }),
210 ({#',,
211 ({#'efun::set_this_player,'dest}), // set_this_player(dest)
Zesstra1b809c72018-03-02 00:31:58 +0100212 ({#'call_other,'item,"init",'oldenv})})})}))); //item->init(oldenv)
MG Mud User88f12472016-06-24 23:31:02 +0200213 DEBUG("Master inaugurated");
214 return;
215}
216
217// epilog() gibt die Dateien zurueck, die vorgeladen werden muessen
218protected string *epilog(int eflag) {
219 string *files, *domains;
220 int i;
221
Zesstra86607bb2017-06-17 19:02:40 +0200222 efun::configure_object(this_object(), OC_EUID, ROOTID);
MG Mud User88f12472016-06-24 23:31:02 +0200223 ReloadBanishFile();
224 ReloadDeputyFile();
225 ReloadInsecureFile();
226
227 if (eflag) {
Zesstrad77ab422019-09-27 17:39:27 +0200228 debug_message(
229 "epilog(): -e angegeben -> Preloading unterdrueckt ...\n",
230 DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200231 return 0;
232 }
233
Zesstrad77ab422019-09-27 17:39:27 +0200234 debug_message("Preloading gestartet.\n", DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200235
236 //Files fuers Preloading und Regionen holen
237 files=explode_files("/std/preload_file") + explode_files("/d/preload_file");
238 domains=get_domains() + ({"erzmagier"}); // EM haben auch ein Preload File
239
240 for (i=sizeof(domains);i--;)
241 files+=explode_files("/d/"+domains[i]+"/preload_file");
Zesstrad77ab422019-09-27 17:39:27 +0200242
MG Mud User88f12472016-06-24 23:31:02 +0200243 return files;
244}
245
246// preload() wird fuer jeder Datei im Preload einmal durchlaufen
247protected void preload(string file) {
248 string err;
249 string name;
250 int *res, zeit;
251
252 // Kein richtiger Dateiname: fertig
253 if(!file || !file[0] || file[0] == ';' || file_size(file+".c") < 0) return;
254
255 // Kein Besitzer -> Meldung ausgeben, fertig
256 if (!(name=creator_file(file)))
257 {
Zesstrad77ab422019-09-27 17:39:27 +0200258 debug_message(
259 sprintf("preload: Kein Besitzer gefunden fuer Datei %s.\n",file),
260 DMSG_STDOUT|DMSG_STDERR);
MG Mud User88f12472016-06-24 23:31:02 +0200261 return;
262 }
263
Zesstra86607bb2017-06-17 19:02:40 +0200264 efun::configure_object(this_object(), OC_EUID, name);
MG Mud User88f12472016-06-24 23:31:02 +0200265
266 // Dann mal laden .. dabei Zeit messen
267 zeit = apply(#'+,rusage()[0..1]);
268
269 // Waehrend des Preloads sind 1.5MTicks leider nicht soviel, insb. wenn
270 // sowas wie der channeld jede menge Objekte laden muss, die wiederum erst
271 // das ganze Geraffel aus /std/ laden. Daher hier einfach mal fuers Preload
272 // die Grenze hoch.
273 err = catch(limited(#'load_object,({5000000}),file));
274
275 if (err != 0)
Zesstrad77ab422019-09-27 17:39:27 +0200276 debug_message(sprintf("\nFehler beim Laden von %s:\n%s\n",file,err),
277 DMSG_STDOUT|DMSG_STDERR);
MG Mud User88f12472016-06-24 23:31:02 +0200278 else
279 {
Zesstrad77ab422019-09-27 17:39:27 +0200280 // Datei, Besitzer und Ladezeit ausgeben
MG Mud User88f12472016-06-24 23:31:02 +0200281 zeit=apply(#'+,rusage()[0..1])-zeit;
Zesstrad77ab422019-09-27 17:39:27 +0200282 debug_message(sprintf("%-50s%-15s (%2d.%:02d s)\n",
283 file, name, zeit/1000,zeit%1000));
MG Mud User88f12472016-06-24 23:31:02 +0200284 }
285
286 // Noch EUID zuruecksetzen
Zesstra86607bb2017-06-17 19:02:40 +0200287 efun::configure_object(this_object(), OC_EUID, ROOTID);
MG Mud User88f12472016-06-24 23:31:02 +0200288
289 return;
290}
291
292//simul_efun.c laden oder die spare_simul_efun.c als Fallback
293//es ist moeglich, hier ein Array von strings zurueckzugeben. Die
294//nachfolgenden gelten als Backup-Objekte, falls eine sefun im Hauptobjekt
295//nicht gefunden wird.
296protected string *get_simul_efun() {
297 string err;
298
299 ++loading_simul_efuns;
300
301 if (!(err=catch(SIMUL_EFUN_FILE->start_simul_efun())) ) {
302 --loading_simul_efuns;
303 return ({SIMUL_EFUN_FILE});
304 }
Zesstrad77ab422019-09-27 17:39:27 +0200305
MG Mud User88f12472016-06-24 23:31:02 +0200306 debug_message("Failed to load simul efun " + SIMUL_EFUN_FILE +
Zesstrad77ab422019-09-27 17:39:27 +0200307 " " + err, DMSG_STDOUT | DMSG_LOGFILE | DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200308
309 if (!(err=catch(SPARE_SIMUL_EFUN_FILE->start_simul_efun())) ) {
310 --loading_simul_efuns;
311 return ({SPARE_SIMUL_EFUN_FILE});
312 }
MG Mud User88f12472016-06-24 23:31:02 +0200313
Zesstrad77ab422019-09-27 17:39:27 +0200314 debug_message("Failed to load spare simul efun " + SPARE_SIMUL_EFUN_FILE +
315 " " + err, DMSG_STDOUT | DMSG_LOGFILE | DMSG_STAMP);
316
317
MG Mud User88f12472016-06-24 23:31:02 +0200318 efun::shutdown();
Zesstrad77ab422019-09-27 17:39:27 +0200319
MG Mud User88f12472016-06-24 23:31:02 +0200320 return 0;
321}
322
323protected mixed call_sefun(string sefun, varargs mixed args) {
324 if (!loading_simul_efuns)
325 return apply(symbol_function(sefun), args);
326 else {
327 switch(sefun) {
328 case "log_file":
329 case "secure_level":
330 case "secure_euid":
331 case "find_player":
332 case "find_netdead":
333 case "find_living":
334 case "process_call":
335 case "replace_personal":
336 case "file_time":
337 return 0;
338 case "dtime":
339 if (pointerp(args) && sizeof(args))
340 return strftime("%a %d. %b %Y, %H:%M:%S",args[0]);
341 else
342 return strftime("%a %d. %b %Y, %H:%M:%S");
343 case "uptime":
344 return to_string(time()-__BOOT_TIME__) + " Sekunden";
345 }
346 }
347 return 0;
348}
349
350
351// Preload manuell wiederholen; Keine GD-Funktion
352void redo_preload()
353{
354 string *to_preload;
355 int i,j;
356
357 to_preload=epilog(0);
358 j=sizeof(to_preload);
359 for (i=0;i<j;i++)
360 catch(preload(to_preload[i]));
361 return;
362}
363
364// ##################
365//########################## Standard-Lfuns #############################
366// ##################
367
368// Keine GD-Funktion, aber sinnvoll.
369public varargs int remove(int silent)
370{
371 write("Der Master will aber nicht zerstoert werden!\n");
372 return 0;
373}
374
375// Einige repetitiven Taetigkeiten kann der Reset erledigen
376protected void reset()
377{
378 int i, *date;
379 mixed *wl;
380
381 //Darf nicht von Hand aufgerufen werden!
382 if (TI||TP) return;
383
384 // Naechsten Reset setzen
385 set_next_reset(RESETINT);
386
387 // Userinfo aufraeumen
388 _cleanup_uinfo();
389
390 // Projekt-Cache loeschen
391 _cleanup_projects();
392
393 // Wenn Zeit abgelaufen, dann READ_FILE-Log rotieren
394 if (!logrotate_counter--)
395 {
396 i=time()/LOGFILEAGE;
397 date=get_dir(sprintf("%s.%d", READ_FILE,i%LOGNUM), GETDIR_DATES);
398 if (pointerp(date)&&sizeof(date)&&
399 (date[0]/LOGFILEAGE)==i) return;
400 if (file_size(READ_FILE)>0)
401 rename(READ_FILE, sprintf("%s.%d", READ_FILE,i%LOGNUM));
402 logrotate_counter=LOGROTATE;
403 }
404 // einmal am Tag die UIDAliase resetten. Hierzu wird der logrotate_counter
405 // missbraucht.
406 if (!(logrotate_counter%24)) {
407 ResetUIDAliase();
408#ifdef _PUREFTPD_
409 expire_ftp_user();
410#endif
411 }
412
413 // Wizlist altert
414 wl = wizlist_info();
415 for (i=sizeof(wl); i--; )
416 set_extra_wizinfo(wl[i][WL_NAME], wl[i][WL_EXTRA] * 99 / 100);
417
MG Mud User88f12472016-06-24 23:31:02 +0200418 return;
419}
420
421
422// #################
423//########################## ID-Management ##############################
424// #################
425
426// Magier-ID fuer Datei str (als Objekt oder als String) ermitteln
427string creator_file(mixed str) {
428 string *strs,tmp;
429 int s;
430
Zesstraa43be352018-11-06 22:40:32 +0100431 // path_array nach strs
MG Mud User88f12472016-06-24 23:31:02 +0200432 // TODO: was ist mit clones?
433 if(objectp(str))
Zesstraccc58df2018-11-07 23:25:20 +0100434 strs=path_array(object_name(str));
MG Mud User88f12472016-06-24 23:31:02 +0200435 else if(stringp(str))
Zesstraccc58df2018-11-07 23:25:20 +0100436 strs=path_array(str);
MG Mud User88f12472016-06-24 23:31:02 +0200437 else return NOBODY;
438
439 // absolute Pfade interessieren hier gerade nicht.
440 strs -= ({""});
441
442 s=sizeof(strs);
443 if(s<2) return NOBODY;
444
445 switch(strs[0]) {
446 case DOMAINDIR:
447 // Fuer Nicht-Magier bzw. "Pseudo-"Magier die Regionskennung
448 if( s==2 || WIZLVLS[strs[2]] || !IS_LEARNER(strs[2]) )
449 return strs[1];
450
451 // in /d/erzmagier gibt es Magier-IDs
452 if (strs[1]=="erzmagier") return strs[2];
453
454 // Ansonsten d.region.magiername
455 return sprintf("d.%s.%s", strs[1], strs[2]);
456
457 case PROJECTDIR:
458 // In p.service gibt es ids mit uid
459 if (s>2 && strs[1]=="service") return "p.service."+strs[2];
460
461 // Ansonsten nur p.projekt (p.service ist auch hier drin)
462 return "p."+strs[1];
463
464 case WIZARDDIR:
465 if (s>2)
466 return strs[1];
467 if (s==2 && file_size(strs[0]+"/"+strs[1])==FSIZE_DIR)
468 return strs[1];
469 return NOBODY;
470
471 case SECUREDIR:
472 return ROOTID;
473
474 case GUILDDIR:
475 case SPELLBOOKDIR:
476 tmp=strs[1];
477 if (tmp[<2..<2]==".") tmp=tmp[0..<3];
478 if ((s=member(tmp,'.'))>0) tmp=tmp[s+1..];
479 return "GUILD."+tmp;
480
481 case LIBROOMDIR:
482 return ROOMID;
483
484 case STDDIR:
485 case LIBOBJDIR:
486 return BACKBONEID;
487
488 case DOCDIR:
489 return DOCID;
490
491 case MAILDIR:
492 return MAILID;
493 case NEWSDIR:
494 return NEWSID;
495
496 case LIBITEMDIR:
497 return ITEMID;
498
499 /* Fall-Through */
500 default:
501 return NOBODY;
502
503 }
504 return NOBODY; //should never be reached.
505}
506
507// UID und EUID an Objekt geben (oder eben nicht)
508// Keine GD-Funktion, aber von Hooks aufgerufen
Zesstraaed340b2019-11-28 21:26:49 +0100509protected mixed give_uid_to_object(string datei, object po)
MG Mud User88f12472016-06-24 23:31:02 +0200510{
511 string creator,pouid;
512
513 // Parameter testen
514 if (!stringp(datei)||!objectp(po)) return 1;
515
516 // Keine Objekte in /log, /open oder /data
517 if (strstr(datei, "/"LIBDATADIR"/") == 0
518 || strstr(datei, "/"LIBLOGDIR"/") == 0
519 || strstr(datei, "/"FTPDIR"/") == 0
520 )
521 return 1;
522
523 // Datei muss Besitzer haben
524 if (!(creator=creator_file(datei))) return 1;
525
526 // Hack, damit simul_efun geladen werden kann
527 if (creator==ROOTID && po==TO) return ROOTID;
528
529 // Keine euid, kein Laden ...
530 if (!(pouid=geteuid(po))) return 1; // Disallow if no euid in po
531
532 // Root generiert keine Root-Objekte ;-)
533 // Nur UID setzen
534 if (pouid==ROOTID)
535 return ({creator,NOBODY}); // root does not create root objects!
536
537 // EUID mitsetzen, wenn PO==creator oder creator==BACKBONEID
538 if (creator==pouid || creator==BACKBONEID)
539 return pouid;
540
541 return ({creator,NOBODY});
542}
543
544// Die System-IDs muessen bekannt sein
545string get_master_uid() { return ROOTID;}
546string get_bb_uid() { return BACKBONEID; }
MG Mud User88f12472016-06-24 23:31:02 +0200547
548// ##########################
549//###################### Sonstige GD-Funktionen #########################
550// ##########################
551
552// Spieler hat sich eingeloggt
553protected object connect()
554{
555 string err;
556 int errno;
557 object ob,bp;
558
559#if defined(SSLPORT) && __EFUN_DEFINED__(tls_available)
560 if (efun::interactive_info(this_player(), II_MUD_PORT) == SSLPORT) {
561 // reject connection of TLS is not available
562 if (!tls_available())
563 return 0;
564 // establish TLS
565 errno=tls_init_connection();
566 if (errno < 0) {
567 // Fehler im Vebindungsaufbau
568 printf("Can't establish a TLS/SSL encrypted connection: %s\n",
569 tls_error(errno));
570 return 0; // this will close the connection to the client.
571 }
572 }
573#endif
574
575 // Blueprint im Environment? Das geht nun wirklich nicht ...
576 if ((bp=find_object("/secure/login")) && environment(bp))
577 catch(destruct(bp);publish);
578
579 // Login-Shell clonen
580 err = catch(ob = clone_object("secure/login"); publish);
581
582 if (errno == 0 && err)
583 write("Fehler beim Laden von /secure/login.c\n"+err+"\n");
584
585 return ob;
586}
587
588// Was machen bei disconnect?
589protected void disconnect(object who, string remaining) {
590 who->NetDead(); return;
591}
592
593// Es gibt kein File 'filename'. VC aktivieren so vorhanden ...
594protected object compile_object(string filename)
595{
596 object ret;
597 string *str;
598 string compiler;
599
600 if (!sizeof(filename)) return 0;
601 str=efun::explode(filename,"/");
602
603 if(sizeof(str)<2) return 0;
604 compiler=implode(str[0..<2],"/")+"/virtual_compiler";
605
606 if (find_object(compiler)
607 || file_size(compiler+".c")>0)
608 {
609 if(catch(
Zesstrad872d182019-11-28 20:13:02 +0100610 ret=({object})call_other(compiler,"compile_object",str[<1]); publish))
MG Mud User88f12472016-06-24 23:31:02 +0200611 return 0;
612 }
613 else
614 return(0);
615
616 if ( objectp(ret) && efun::explode(creator_file(filename), ".")[<1] !=
617 REAL_EUID(ret) ){
618 funcall( symbol_function('log_file/*'*/), "ARCH/VC_MISSBRAUCH",
619 sprintf( "%s: %s versucht per VC %s zu %s umzubenennen!\n",
620 funcall( symbol_function('dtime/*'*/), time() ),
621 (this_interactive() ? getuid(this_interactive()):
622 object_name(previous_object())), object_name(ret),
623 filename) );
624
625 return 0;
626 }
627 return ret;
628}
629
630// ############
631//############################ Shutdown #################################
632// ############
633
634// Spieler bei Shutdown entfernen
635protected void remove_player(object victim)
636{
637 catch(victim->quit());
638 if (victim) catch(victim->remove());
639 if (victim) destruct(victim);
640 return;
641}
642
643// Langsamer Shutdown
644protected void slow_shut_down(int minutes)
645{
646 //sollte nur vom GD gerufen werden. Oder allenfalls Master selbst
647 filter(users(),#'tell_object,
648 "Der Gamedriver ruft: Der Speicher wird knapp ! Bereitet euch auf das Ende vor !\n");
649 "/obj/shut"->shut(minutes);
650 return;
651}
652
653
654// In LD varargs void notify_shutdown(string crash_reason)
655protected varargs void notify_shutdown (string crash_reason) {
656
657 if (PO && PO != TO)
658 return;
659 if (crash_reason) {
660 //Uhoh... Verdammter Crash. :-( Zumindest mal mitloggen,
661 //was der Driver sagt...
662 write_file(CRASH_LOG,sprintf(
663 "\n%s: The driver crashed! Reason: %s\n",
664 ctime(time()),crash_reason));
665 }
666
667 filter(users(), #'tell_object,
668 "Game driver shouts: LDmud shutting down immediately.\n");
669 save_wiz_file();
670 return;
671}
672
673// ##################
674//########################## Berechtigungen #############################
675// ##################
676
677// Darf Verbindung durch name von obfrom nach ob gelegt werden?
678
679//int valid_exec(string name) {return 1;}
680
681int valid_exec(string name, object ob, object obfrom)
682{
683 // Ungueltige Parameter oder Aufruf durch process_string -> Abbruch
684 if (!objectp(ob) || !objectp(obfrom)
685 || !stringp(name) || !sizeof(name)
686 || funcall(symbol_function('process_call)) )
687 return 0;
688
689 // renew_player_object() darf ...
690 if (name=="/secure/master/misc.c"
691 || name=="secure/master/misc.c")
692 return 1;
693
694 // Ansonsten darf sich nur die Shell selber aendern ...
695 if (previous_object() != obfrom) return 0;
696
697 // Die Login-Shell zu jedem Objekt ...
698 if (name=="/secure/login.c"
699 || name=="secure/login.c")
700 return 1;
701
702 // Magier per exec nur, wenn sie damit keine Fremde uid/euid bekommen
703 if (this_interactive() == obfrom && getuid(obfrom) == getuid(ob)
704 && geteuid(obfrom) == geteuid(ob))
705 return 1;
706
707 // Sonst darf niemand was
708 return 0;
709}
710
711
712// Darf me you snoopen?
713int valid_snoop(object me, object you) {
714 return getuid(PO) == ROOTID;
715}
716
717// Darf wiz wissen, ob er gesnoopt wird?
718int valid_query_snoop(object wiz) {
719 return getuid(PO) == ROOTID;
720}
721
722// Darf ob seine EUID auf neweuid setzen?
723int valid_seteuid(object ob, string neweuid)
724{
725 return (ob==this_object() ||
726 getuid(ob) == ROOTID ||
727 getuid(ob) == neweuid ||
728 creator_file(object_name(ob)) == neweuid);
729}
730
731// Darf getraced werden?
732int valid_trace(string what, mixed arg) {
733 return IS_ARCH(TI);
734}
735
736
737// valid_write() und
738// valid_read() befinden sich in file_access.c
739
740
741// Darf PO ob shadowen?
742int query_allow_shadow(object ob)
743{
744 // ROOT darf nicht geshadowed werden
745 if(getuid(ob) == ROOTID)
746 return 0;
747
748 // Access-Rights auch nicht
749 if (efun::explode(object_name(ob),"#")[0][<14..]=="/access_rights")
750 return 0;
751
752 // Ansonsten query_prevent_shadow fragen ...
Zesstrad872d182019-11-28 20:13:02 +0100753 return !({int})ob->query_prevent_shadow(PO);
MG Mud User88f12472016-06-24 23:31:02 +0200754}
755
756
757/* privilege_violation is called when objects try to do illegal things,
758 * or files being compiled request a privileged efun.
759 *
760 * return values:
761 * 1: The caller/file is allowed to use the privilege.
762 * 0: The caller was probably misleaded; try to fix the error.
763 * -1: A real privilege violation. Handle it as error.
764 */
765int privilege_violation(string op, mixed who, mixed arg1, mixed arg2)
766{
767
768 if (objectp(who) &&
769 (who==this_object() || geteuid(who)==ROOTID))
770 return 1;
771
772 switch(op)
773 {
774 case "call_out_info":
775 return -1;
776 case "send_udp":
777 return 1;
778
779 case "nomask simul_efun":
780 // <who> ist in diesem Fall ein string (Filename) und damit von dem
781 // Check da oben nicht abgedeckt. Daher explizite Behandlung hier.
782 // Ausserdem hat der Pfad (zur Zeit noch) keinen fuehrenden '/'.
783 // Falls das jemand einschraenken will: der Kram fuer die simul_efuns
784 // muss das duerfen!
785 if (stringp(who)
786 && strstr(who,"secure/") == 0)
787 return 1;
788 return 0; // alle andere nicht.
789
790 case "get_extra_wizinfo":
791 // benutzt von /secure/memory.c und /secure/simul_efun.c
792 case "set_extra_wizinfo":
793 // wird benutzt von simul_efun.c, welche aber als ROOT-Objekt implizit
794 // erlaubt ist (s.o.)
795 return -1; // fuer allen nicht erlaubt.
796
797 case "rename_object":
798 if (object_name(who)=="/secure/impfetch" ||
799 BLUE_NAME(who)=="/secure/login")
800 return 1;
801 return(-1);
802
803 case "configure_driver":
804 return call_sefun("secure_level") >= ARCH_LVL;
805
806 case "limited":
807 // Spielershells duerfen sich zusaetzliche Ticks fuer den Aufruf von
808 // ::die() beschaffen, damit der Tod nicht wegen wenig Ticks buggt.
809 if (strstr(load_name(who), "/std/shells/") == 0
810 && get_type_info(arg1, 2) == who
811 && get_type_info(arg1, 3) == "/std/living/life"
812// && get_type_info(arg1, 4) == "die"
813 && arg2[LIMIT_EVAL] <= 10000000 ) {
814 return 1;
815 }
816 //DEBUG(sprintf("%O, %O, %O", who, arg1, arg2));
817 int *limits=efun::driver_info(DI_CURRENT_RUNTIME_LIMITS);
818 // LIMIT_EVAL darf verringert werden. Alle anderen Limits duerfen nicht
819 // geaendert werden. Achja, LIMIT_EVAL darf nicht 0 (LIMIT_UNLIMITED)
820 // sein. *g*
821 // LIMIT_COST darf entweder 0 oder -100 sein.
822 if (arg2[LIMIT_EVAL]>1000 && (arg2[LIMIT_EVAL] < get_eval_cost())-500
823 && arg2[LIMIT_ARRAY] == limits[LIMIT_ARRAY]
824 && arg2[LIMIT_MAPPING_KEYS] == limits[LIMIT_MAPPING_KEYS]
825 && arg2[LIMIT_MAPPING_SIZE] == limits[LIMIT_MAPPING_SIZE]
826 && arg2[LIMIT_BYTE] == limits[LIMIT_BYTE]
827 && arg2[LIMIT_FILE] == limits[LIMIT_FILE]
828 && arg2[LIMIT_CALLOUTS] == limits[LIMIT_CALLOUTS]
829 && (arg2[LIMIT_COST] == 0 || arg2[LIMIT_COST] == -100) )
830 return(1);
831 //sonst verweigern.
832 return(-1);
833
834 case "sqlite_pragma":
835 return 1;
836 case "attach_erq_demon":
837 case "bind_lambda":
838 case "configure_interactive":
839 case "configure_object":
840 case "execute_command":
841 case "erq":
842 case "input_to":
843 case "mysql":
844 case "net_connect":
845 case "pgsql":
846 case "set_driver_hook":
847 case "set_this_object":
848 case "shadow_add_action":
849 case "symbol_variable":
850 case "variable_list":
851 case "wizlist_info":
852 default:
853 return(-1);
854 }
855 return -1;
856}
857
858// ####################
859//######################## Fehlerbehandlung #############################
860// ####################
861
862// Behandlung von Fehler im Heart_Beat
863protected int heart_beat_error( object culprit, string error, string program,
864 string current_object, int line, int caught)
865{
866 if (!objectp(culprit)) return 0;
867 if (interactive(culprit))
868 {
869 tell_object(culprit,"Der GameDriver teilt Dir mit: "
870 "Dein Herzschlag hat ausgesetzt!\n");
871 if (IS_LEARNER(culprit))
872 tell_object(culprit,
873 sprintf("Fehler: %sProgamm: %s, CurrObj: %s, Zeile: %d, "
874 "the error was %scaught at higher level.\n",
875 error,program,current_object,line,
876 caught ? "" : "not"));
877 }
878
879 if (efun::object_info(culprit, OI_ONCE_INTERACTIVE))
880 call_out("restart_heart_beat", 5, culprit);
881 else
882 catch(culprit->make_immortal(); publish);
883 return 0;
884}
885
886// Ausgabe einer Meldung an Spieler mit Level >= minlevel. Wird genutzt, um
887// Magier ueber Fehler zu informieren, die nicht normal behandelt werden
888// (z.B. rekursive Fehler, d.h. Fehler in der Fehlerbehandlung)
889private void tell_players(string msg, int minlevel) {
890 msg = efun::sprintf("%=-78s","Master: " + msg); // umbrechen
891 efun::filter(efun::users(), function int (object pl)
892 {
893 if (query_wiz_level(pl) >= minlevel)
894 efun::tell_object(pl, msg);
895 return 0;
896 } );
897}
898
899/**
900 * \brief Error handling fuer Fehler beim Compilieren.
901 *
902 * log_error() wird vom GameDriver aufgerufen, wenn zur Compile-Zeit ein
903 * Fehler auftrat. Die Fehlermeldung wird unter /log/error geloggt.
904 * Falls this_interactive() ein Magier ist, bekommt er die Fehlermeldung
905 * direkt angezeigt.
906 * Sollte das Logfile 50kB ueberschreiten, wird es rotiert. Auf [Entwicklung]
907 * wird dann eine Fehlermeldung abgesetzt.
908 *
909 * @param file Die Datei, in der der Fehler auftrat.
910 * @param message Die Fehlermeldung.
911 * @param warn Warnung (warn!=0) oder Fehler (warn==0)?
912 * */
913
914protected void log_error(string file, string message, int warn) {
915 string lfile;
916 string cr;
917 mixed *lfile_size;
918
919 if (handling_error == efun::time()) {
920 // Fehler im Verlauf einer Fehlerbehandlung: Fehlerbehandlung minimieren,
921 // nur Meldung an eingeloggte Erzmagier.
922 tell_players("log_error(): Rekursiver Fehler in Fehlerbehandlung. "
923 "Bitte Debuglog beachten. Aktueller Fehler in " + file + ": "
924 + message, ARCH_LVL);
925 return;
926 }
927 handling_error = efun::time();
928
929 //Fehlerdaten an den Errord zur Speicherung weitergeben, falls wir sowas
930 //haben.
931#ifdef ERRORD
932 // Only call the errord if we are _not_ compiling the sefuns. It uses sefuns
933 // and it will cause a recursing call to get_simul_efuns() which is bound to
934 // fail.
935 if (!loading_simul_efuns) {
936 catch(limited(#'call_other,({200000}),ERRORD,"LogCompileProblem",
937 file,message,warn);publish );
938 }
939#endif // ERRORD
940
941 // Logfile bestimmen
942 cr=creator_file(file);
943 if (!cr) lfile="NOBODY.err";
944 else if (cr==ROOTID) lfile="ROOT";
945 else if (efun::member(cr,' ')!=-1) lfile="STD";
946 else lfile=cr;
947 //je nach Warnung oder Fehler Verzeichnis und Suffix bestimmen
948 if (warn) {
949 lfile="/log/warning/" + lfile + ".warn";
950 }
951 else {
952 lfile="/log/error/" + lfile + ".err";
953 }
954
955 // Bei Bedarf Rotieren des Logfiles
956 if ( !loading_simul_efuns
957 && sizeof(lfile_size = get_dir(lfile,2))
958 && lfile_size[0] >= MAX_ERRLOG_SIZE )
959 {
960 catch(rename(lfile, lfile + ".old"); publish); /* No panic if failure */
961 if (!loading_simul_efuns)
962 {
963 catch(send_channel_msg("Entwicklung","<MasteR>",
964 "Logfile rotiert: "+lfile+"."));
965 }
966 }
967
968 efun::write_file(lfile,message);
969
970 // Magier bekommen die Fehlermeldung angezeigt
971 if (IS_LEARNER(TI)) efun::tell_object(TI, message);
972
973 handling_error = 0;
974}
975
976/* Gegenmassnahme gegen 'too long eval' im Handler vom runtime error:
977 Aufsplitten des Handlers und Nutzung von limited() */
978//keine GD-Funktion
979private void handle_runtime_error(string err, string prg, string curobj,
980 int line, mixed culprit, int caught, object po, int issueid)
981{
982 string code;
983 string debug_txt;
984 object ob, titp;
985
986 //DEBUG(sprintf("Callerstack: (handle_runtime_error()): %O\n",
987 // caller_stack(1)));
988 // Fehlermeldung bauen
989 if (!stringp(err)) err="<NULL>";
990 if (!stringp(prg)) prg="<NULL>";
991 if (!stringp(curobj)) curobj="<NULL>";
992 debug_txt=efun::sprintf("Fehler: %O, Objekt: %s, Programm: %O, Zeile %O (%s), "
993 "ID: %d",
994 err[0..<2], curobj, (prg[0]!='<'?"/":"")+prg, line,
995 (TI?efun::capitalize(efun::getuid(TI)):"<Unbekannt>"),
996 issueid);
997
998 titp = TI || TP;
999 // Fehlermeldung an Kanaele schicken, aber nur wenn der aktuelle Fehler
1000 // nicht waehrend des ladens der simulefuns auftrat, bei der Ausgabe der
1001 // Meldung ueber die Kaenaele wieder sefuns genutzt werden.
1002 if (!loading_simul_efuns) {
1003 if (titp && (IS_LEARNER(titp) || (titp->QueryProp(P_TESTPLAYER))))
1004 {
1005 catch(send_channel_msg("Entwicklung",
1006 capitalize(objectp(po) ? REAL_UID(po) : ""),
1007 debug_txt));
1008 }
1009 else
1010 {
1011 catch(send_channel_msg("Debug",
1012 capitalize(objectp(po) ? REAL_UID(po) : ""),
1013 debug_txt));
1014 }
1015 }
1016
1017 if (!titp) return;
1018
1019 // Fehlermeldung an Benutzer
1020 if (IS_LEARNER(titp))
1021 efun::tell_object(titp,
1022 efun::sprintf("%'-'78.78s\nfile: %s line: %d object: %s\n" +
1023 "%serror: %s%'-'78.78s\n","",prg,line,curobj,
1024 (prg&&(code=efun::read_file("/"+prg,line,1))?
1025 "\n"+code+"\n":""),err,""));
1026 else
1027 efun::tell_object(titp, "Du siehst einen Fehler im Raum-Zeit-Gefuege.\n");
1028}
1029
1030//Keine GD-Funktion, limitiert die Kosten fuer den handler
1031private void call_runtime_error(string err, string prg, string curobj,
1032 int line, mixed culprit, int caught, object po)
1033{
1034 if (handling_error == efun::time())
1035 {
1036 // Fehler im Verlauf einer Fehlerbehandlung: Fehlerbehandlung minimieren,
1037 // nur Meldung an eingeloggte Regionsmagier.
1038 tell_players("call_runtime_error(): Rekursiver Fehler in "
1039 "Fehlerbehandlung. Bitte Debuglog beachten. Aktueller Fehler in "
1040 + curobj + ": " + err, LORD_LVL);
1041 return;
1042 }
1043 handling_error = efun::time();
1044
1045 //Fehlerdaten an den Errord zur Speicherung weitergeben, falls wir sowas
1046 //haben.
MG Mud User88f12472016-06-24 23:31:02 +02001047 int issueid;
Christian Georg Beckerd66c9602017-01-09 10:37:51 +02001048#ifdef ERRORD
MG Mud User88f12472016-06-24 23:31:02 +02001049 // Wenn die sefuns gerade geladen werden, erfolgt keine Weitergabe an den
1050 // ErrorD, da dabei wieder sefuns gerufen werden, was zu einer Rekursion
1051 // fuehrt.
1052 if (!loading_simul_efuns) {
1053 catch(issueid=efun::limited(#'call_other,({200000}),ERRORD,"LogError",
1054 err,prg,curobj,line,culprit,caught);publish);
1055 }
1056#endif // ERRORD
1057
1058 //eigenen Errorhandler laufzeitbegrenzt rufen
1059 efun::limited(#'handle_runtime_error, ({ 200000 }), err, prg, curobj,
1060 line,culprit,caught, po, issueid);
1061
1062 handling_error = 0;
1063}
1064
1065// Laufzeitfehlerbehandlung, hebt Evalcost-Beschraenkung auf und reicht weiter
1066// an call_runtime_error, die die Grenze wieder auf einen bestimmten Wert
1067// festlegt.
1068protected void runtime_error(string err ,string prg, string curobj, int line,
1069 mixed culprit, int caught) {
1070
1071 //DEBUG(sprintf("Callerstack: (runtime_error()): %O\nPO: %O\nPO(0): %O\n",
1072 // caller_stack(1),previous_object(),previous_object(0)));
1073
1074 limited(#'call_runtime_error, ({ LIMIT_UNLIMITED }),
1075 err,prg,curobj,line,culprit,caught,previous_object());
1076}
1077
1078//Warnungen mitloggen
1079protected void runtime_warning( string msg, string curobj, string prog, int line,
1080 int inside_catch)
1081{
1082 string code;
1083 string debug_txt;
1084 object titp;
1085
1086 //DEBUG(sprintf("Callerstack: in runtime_warning(): %O\nPO(0): %O\n",
1087 // caller_stack(1),previous_object(0)));
1088
1089 //Daten der Warnung an den Errord zur Speicherung weitergeben, falls wir
1090 //sowas haben.
1091 int issueid;
1092#ifdef ERRORD
1093 catch(issueid=limited(#'call_other,({200000}),ERRORD,"LogWarning",
1094 msg,prog,curobj,line,inside_catch); publish);
1095#endif // ERRORD
1096
1097 // Fehlermeldung bauen
1098 if (!stringp(msg)) msg="<NULL>";
1099 if (!stringp(prog)) prog="<NULL>";
1100 if (!stringp(curobj)) curobj="<NULL>";
1101 debug_txt=sprintf("Warnung: %O, Objekt: %s, Programm: %O, Zeile %O (%s) "
1102 "ID: %d",
1103 msg[0..<2], curobj, (prog[0]!='<'?"/":"")+prog, line,
1104 (TI?capitalize(getuid(TI)):"<Unbekannt>"),
1105 issueid);
1106
1107 //Fehlermeldungen an -warnungen schicken
1108 catch(send_channel_msg("Warnungen",
1109 capitalize(objectp(previous_object()) ?
1110 REAL_UID(previous_object()) : ""),
1111 debug_txt));
1112
1113 titp = TI || TP;
1114
1115 if (!titp) return;
1116
1117 // Fehlermeldung an Benutzer
1118 if (IS_LEARNER(titp))
1119 tell_object(titp,
1120 sprintf("%'-'78.78s\nfile: %s line: %d object: %s\n" +
1121 "%sWarnung: %s%'-'78.78s\n","",prog,line,curobj,
1122 (prog&&(code=read_file("/"+prog,line,1))?
1123 "\n"+code+"\n":""),msg,""));
1124 return;
1125}
1126
1127
1128// #####################
1129//######################## Einrichten des ED ############################
1130// #####################
1131
1132// Setup speichern
1133protected int save_ed_setup(object who, int code)
1134{
1135 string file;
1136
1137 if (!intp(code)) return 0;
1138 file = sprintf("/players/%s/.edrc",geteuid(who));
1139 rm(file);
1140 return write_file(file,(string)code);
1141}
1142
1143// Setup einladen
1144protected int retrieve_ed_setup(object who)
1145{
1146 string file;
1147
1148 file = sprintf("/players/%s/.edrc",getuid(who));
1149 if (file_size(file)<1) return 0;
1150 return (int)read_file(file);
1151}
1152
1153// Wo werden Dateien gespeichert?
1154string get_ed_buffer_save_file_name(string file)
1155{
1156 return sprintf("/players/%s/.dead_ed_files/%s",
1157 getuid(this_player()),efun::explode(file, "/")[<1]);
1158}
1159
1160// ################################
1161//################### Ungenutzte Pflichtfunktionen ######################
1162// ################################
1163
1164// Nichts zu tun beim Master-Neustart
1165protected void external_master_reload() { return; }
1166
1167// Keine externen Master-Flags
1168protected void flag(string str) { return; }
1169
1170// Wird benoetigt, falls ERQ angeschlossen ist
1171protected void stale_erq(closure callback) { return; }
1172
1173// Zerstoerten Master wiederbeleben ...
1174// nicht viel zu tun, wenn flag gesetzt ist. Wenn aber nicht, sind alle
1175// Variablen auf 0. Nach dieser Funktion wird wieder inaugurate_master()
1176// gerufen.
1177protected void reactivate_destructed_master(int flag) {
1178 if (flag) {
1179 //re-init
1180 //was machen? TODO
1181 }
1182 return;
1183}
1184
1185// Kein Quota-Demon (potentielles TODO)
1186//Handle quotas in times of memory shortage.
1187//is called during the final phase of a garbage collection, if the user
1188//reserve could not be re-allocated. Last (!) Chance to free (active) objects
1189//from the system and prevent call to slow_shut_down()!
1190protected void quota_demon() {
1191 //was kann man machen?
1192 //uebervolle Seherhaeuser leeren?
1193 return;
1194}
1195
1196// Keine Prepositionen in parse_command
1197//string *parse_command_prepos_list() { return ({}); }
1198
1199// Wie lautet das Wort fuer 'alle' ?
1200//string *parse_command_all_word() { return ({}); }
1201
1202
1203// Keine Besonderen Objektnamen
1204string printf_obj_name(object ob) { return 0; }
1205
1206// ###################
1207//######################### Sonstiges/Hooks #############################
1208// ###################
1209
1210//TODO: save_wiz_file in shutdown() integrieren?
1211// Wizliste speichern: Zeile generieren
1212static string _save_wiz_file_loop(mixed *a)
1213{
1214 return sprintf("%s %d %d\n",a[WL_NAME],a[WL_COMMANDS],a[WL_EXTRA]);
1215}
1216
1217// Wizliste speichern
1218protected void save_wiz_file()
1219{
1220 rm("/WIZLIST");
1221 write_file("/WIZLIST",implode(
1222 map(wizlist_info(),#'_save_wiz_file_loop),""));
1223}
1224
MG Mud User88f12472016-06-24 23:31:02 +02001225// EUID und UID werden von give_uid_to_object() vergeben, diese sind in
1226// inaugurate_master() als driver hooks angemeldet.
1227
MG Mud User88f12472016-06-24 23:31:02 +02001228protected mixed load_uid_hook(string datei) {
Zesstraaed340b2019-11-28 21:26:49 +01001229 return(give_uid_to_object(datei, previous_object()));
MG Mud User88f12472016-06-24 23:31:02 +02001230}
1231
Zesstraaed340b2019-11-28 21:26:49 +01001232protected mixed clone_uid_hook(object blueprint, string new_name) {
1233 return(give_uid_to_object(new_name, previous_object()));
MG Mud User88f12472016-06-24 23:31:02 +02001234}
1235