/* note that there is no documentation on how to write a masterobject, * I try to use comments in this object instead. */ #pragma strict_types #include "../include/signal.h" /* * This function should return 1 if the program is allowed to enter the mud. * If it returns 2 then other objects will be automaticly approved if they * inherit that program. */ int query_approve(string name) { switch(name) { case "std/object": case "std/room": return 2; } if(name[0..7]=="inherit/" || name[0..3]=="obj/" || name[0..3]=="std/" || name[0..6]=="secure/") return 1; return 0; } /* * if an argument on the command line to the driver starts with -f * whatever is after it will be sent with a call to this function. * To test a new function xx in object yy, do * parse "-fcall yy xx arg" "-fshutdown" */ static void flag(string str) { string file, arg,func; int num_arg; int *foo; int e; write("Master: Doing Flag '"+str+"'\n"); if (str == "shutdown") { write("Cpu usage in master "+object_cpu(this_object())+"\n"); shutdown(); return; } if(str=="for-test") { for(write("e=0;\n"),e=0;write("e<10;\n"),e<10;write("e++;\n"),e++) write("e="+e+"\n"); shutdown(); } if (sscanf(str, "echo %s", arg) == 1) { write(arg + "\n"); return; } if (sscanf(str, "call %s %s %s", file, func, arg)) { object o; mixed d; o=clone_object(file); d=(mixed)call_function(get_function(o,func), arg); write("Calling "+func+" in "+file+" with "+arg+"\n"); write("Got "+sprintf("%O",d)+" back.\n"); return; } write("master: Unknown flag " + str + "\n"); } /* * Write an error message into a log file. The error occured in the object * 'file', giving the error message 'message'. This function is never * called in script mode */ void log_error(string file, string message) { string name; name = "log"; sscanf(file,"/w/%s/",name); write_file("/log/"+name, message); } /* * When an object is destructed, this function is called with every * item in that room. We get the chance to save players ! * If nothing is done, the object is destructed. */ void destruct_environment_of(object ob) { return; ob->catch_tell("Everything you see is disolved. Luckily, you are transported somewhere...\n"); ob->move_player("is transfered#room/void"); } /* * Define where the '#include' statement is supposed to search for files. * "." will automatically be searched first, followed in order as given * below. The path should contain a '%s', which will be replaced by the file * searched for. */ string *define_include_dirs() { return ({"/include/%s",}); } /* The master is given the uid and euid that this function returns. */ string get_root_uid() { return "Root"; } /* May previous_object destruct o? If so, this function should return 1 */ int query_valid_destruct(object o) { if(geteuid(previous_object())==get_root_uid()) return 1; return 0; } /* When an object is cloned, this function is called to give it an uid and * euid, if it doesn't return a string, the cloning will be considered illigal. * This function might also want to look at this_player() and previous_object() * to figure out what uid/euid to give the new object. */ mixed creator_file(string file) { string *str; if (!file || !stringp(file)) return "NOONE"; str = explode(file, "/"); if (sizeof(str)<2) return 0; if (str[0] == "secure") return get_root_uid(); if (str[0] == "global" || str[0] == "std" || str[0] =="room" || str[0] == "obj") return "Backbone"; if (str[0] == "tmp") return str[1]; if (str[0] == "include") return 0; if (str[0] == "failsafe") return "failsafe"; if (sizeof(str) > 2 && str[0] == "d") return "Dom: "+str[1]; if (sizeof(str) == 2 && str[1] == "common" && str[0] == "w") return "womble-frog"; if (sizeof(str) < 3 || str[0] != "w" ) return 0; return str[1]; } /* This function is called whenever a write to a file is executed, * euid the euid of the object that wants to write, path is the file it wants * to write to, and func is a string that describes what it is trying to do. * valid_write should return 1 if the object is allowed to write. * This function is not called in script mode, it is assumed that the user * is allowed to write anywhere in script mode. */ int valid_write(string path, string euid, string func) { string *b; if(euid==get_root_uid()) return 1; b=explode(path,"/"); while(sizeof(b) && b[0]=="") b=b[1..sizeof(b)-1]; if(sizeof(b)<2) return 0; switch(b[0]) { case "save": case "obj": if(euid=="Backbone") return 1; case "open": case "log": return 1; case "w": return b[1]==euid; } } /* this function is like valid_write, but affects reads */ int valid_read(string path, string euid, string func) { string *b; if(valid_write(path,euid,func)) return 1; if(euid=="Backbone") return 1; b=explode(path,"/"); while(sizeof(b) && b[0]=="") b=b[1..sizeof(b)-1]; if(sizeof(b)<2) return 0; switch(b[0]) { case "std": case "log": case "doc": case "players": case "etc": case "open": return 1; case "w": return b[1]==euid; } } /* This function is called whenever an error occurs, It is up to this * function to deliver the error message to the wizard who made it. * Note that this function is called after the error has been cleared, * it is therefor impossible to use previous_objects() to gain further * information about the error. The arguments are: * error, as string describing the error * current, the object the error occured in * prog_name, the name of the program it occured in * ob_name, the name of the object it occured in, if any * initer, previous_objects()[0] when the error occured. * linenumber, what line it occured on. */ void handle_error(string error, object current, string prog_name, string ob_name, object initer, int linenumber) { if(this_player()) { if(1 /* put a test if the player is wizard here */ ) { this_player()->catch_tell( sprintf("Error %sIn %s (%s) line %d\n", error, ob_name, prog_name, linenumber)); }else{ this_player()->catch_tell( "You think you see some gremlins in the corner of your eye.\n"); } this_player()->fflush(); } } /* May the object o set it's euid to euid? if so, this function should * return 1 */ int valid_seteuid(object o,string euid) { if(o==this_object() || geteuid(o)==get_root_uid()) return 1; return 0; } /* Is the object ob allowed to do the action 'action' on a socket? * info is an array containing more precise information about what it's * trying to do, and on what socket. */ int valid_socket(object ob,string action,mixed *info) { if(geteuid(ob)!=get_root_uid()) return 1; return 1; } /* The driver catches signals, they all wind up here, sig is a bitfield * containing all signals ( or rather: 1<<signal_number ) received or:ed * together. Currently SIGTERM, SIGINT, SIGUSR1 and SIGUSR2 are catched and * if the driver is compiled without DEBUG defined, SIGSEGV, SIGFPE, SIGBUS * and SIGQUIT are also catched. If this function returns 0 a 'default' action * for that signal is executed. Note that this function can be called when * other code is executing therefor special care has to be taken so that * it does not interfere with that code. */ int signal(int sig) { perror(sprintf("master: Got signal %x.\n",sig)); return 0; } /* This function is called whenever the driver receives something on stdin. * It can be used to make it possible to login from stdin for easy debugging. */ void stdin(string s) {} /* this function is called when the memory is low, generally, it should * try to finish the mud in a nice manner within a few minutes. It is also * the default action for SIGUSR1 */ void shut() { } /* is previous_object() allowed to use add_worth() ? * if so, this function should return 1 */ int valid_add_worth() { return 1; } /* this function is called when the driver is runned in script mode * see doc/script_mode for further details (not lib/doc/script_mode) */ int batch(string arg,string *argv,string *env) { write("Wrong master for script mode.\n"); exit(1); } /* this function is called when the -I option is used, it will probably only * be used when running the driver from /etc/services */ void stdin_is_sock(int script_mode) { } /* When the driver casts a string to an object, and can't find a program to * use for cloning, this function is called, it is supposed to return an * object which will be given the name 'file' in the hashtable. */ object compile_object(string file) { object o; string who, where; if(sscanf(file,"w/%s/%s",who,where)) { o=call_other("/w/"+who+"/vcompile","compile_object",file); }else if(sscanf(file,"%s#%s",who,where)){ o=clone_object(who); } if(!o) return o; if(o->query_prevent_virtual(file)) destruct(o); return o; } /* This function is called when an error occurs in the heart_beat of object o, * it can be used either to restart it, or to write some messages to that * object and whatever objects are around. */ void kill_heart_beat(object o) {} /* This function is called just before the mud is being shut down. */ void game_shutting_down() {} /* all the setup isn't done when create() in master.c is called, * (include dires for instance) so we wait 1 second and load the rest * here */ void load_ip() { function f; foreach(get_function_list((object)"/secure/simul_efun"),f) add_simul_efun(function_name(f),f); (object)"/secure/ip"; } /* Start everything */ void create() { write("Starting mud "+ctime(time())+".\n"); call_out(load_ip,1); } /* This function should return an array of strings which will be bound * when compiling programs. Every entry in this array will use 2 bytes * per program, but calling these functions will be quicker because the * driver won't have to search for them. * Sorting these functions so the one used most is first is a little * (probably very little) quicker. */ string *get_cached_functions() { return ({"id","short","long","catch_input"}); } /* This function should return 1 if the object o may replace the * efun/simul_efun name with the optional argument f. If f==0 it means * that o wants to turn the simulation of that function off. */ int valid_add_simul_efun(object o,string name,function f) { if(geteuid(o)==getuid(this_object())) return 1; } /* This function isn't used yet, but it will be in a near future. * It is meant to regulate the usage of efun:: */ int valid_override() { return 1; }