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