#include "config.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <memory.h> #if defined(_SEQUENT_) #include <malloc.h> #endif #include <stdio.h> #include <string.h> #include <math.h> #include <setjmp.h> #include <varargs.h> #include <signal.h> #if defined(sun) #include <alloca.h> #endif #include "lint.h" #include "interpret.h" #include "object.h" #include "lex.h" #include "exec.h" extern char *prog; extern int current_line; int d_flag = 0; /* Run with debug */ int t_flag = 0; /* Disable heart beat and reset */ int e_flag = 0; /* Load empty, without castles. */ int s_flag = 0; /* Make statistics and dump to /MUDstatistics */ int comp_flag = 0; /* Trace compilations */ int driver_mtime; #ifdef YYDEBUG extern int yydebug; #endif int port_number = PORTNO; #ifdef CATCH_UDP_PORT int udp_port = CATCH_UDP_PORT; #endif #ifdef SERVICE_PORT int service_port = SERVICE_PORT; #endif char *reserved_area; /* reserved for malloc() */ struct svalue const0, const1; double consts[5]; extern jmp_buf error_recovery_context; extern int error_recovery_context_exists; extern struct object *vbfc_object; extern struct object *master_ob; static void start_ip_demon(); static void update_current_time() { extern int current_time, get_current_time(); current_time = get_current_time(); } int main(int argc, char **argv) { extern void init_shared_strings(); extern int game_is_being_shut_down; extern int current_time; int i, new_mudlib = 0; int no_ip_demon = 0; char *p; struct svalue *ret; extern char* make_shared_string(char *); extern struct svalue catch_value; extern void init_cfuns(); char *dpath; struct stat c_st; #ifdef MALLOC_debugmalloc extern void malloc_setup_hook(); malloc_setup_hook(); #endif #ifdef MALLOC_gc extern void gc_init(); gc_init(); #endif #ifdef MALLOC_sysmalloc extern void sysmalloc_init(); sysmalloc_init(); #endif #ifdef MALLOC_bibopmalloc extern void bibop_init(); bibop_init(); #endif #ifdef _SEQUENT_ setdtablesize(1024); #endif const0.type = T_NUMBER; const0.u.number = 0; const1.type = T_NUMBER; const1.u.number = 1; catch_value = const0; /* * Check that the definition of EXTRACT_UCHAR() is correct. */ p = (char *)&i; *p = -10; if (EXTRACT_UCHAR(p) != 0x100 - 10) { fprintf(stderr, "Bad definition of EXTRACT_UCHAR() in config.h.\n"); exit(1); } #ifdef DRAND48 srand48(get_current_time()); #else #ifdef RANDOM srandom(get_current_time()); #else fprintf(stderr, "No random generator specified!\n"); #endif /* RANDOM */ #endif /* DRAND48 */ current_time = get_current_time();; signal(SIGALRM, update_current_time); ualarm(1000000/TIME_RES, 1000000/TIME_RES); if (RESERVED_SIZE > 0) reserved_area = malloc(RESERVED_SIZE); for (i=0; i < sizeof consts / sizeof consts[0]; i++) consts[i] = exp(- i / 900.0); init_num_args(); reset_machine(1); init_cfuns(); /* * Set up the signal handling. */ init_signals(); #ifdef BINARIES /* * Find the modification time of the driver. For reasons of binary * integrity we only accept compiled binaries younger than the * driver. This is not foolproof, we might start an old version, but * this will normally work fine. */ dpath = (char *) xalloc(strlen(argv[0]) + 1); strcpy(dpath, argv[0]); if (stat(dpath, &c_st) != -1) driver_mtime = c_st.st_mtime; else { fprintf(stderr,"Can't find myself %s, ignoring old binaries.\n", dpath); driver_mtime = current_time; } free(dpath); #endif /* * The flags are parsed twice ! * The first time, we only search for the -m flag, which specifies * another mudlib, and the D-flags, so that they will be available * when compiling master.c. */ for (i = 1; i < argc; i++) { if (atoi(argv[i])) port_number = atoi(argv[i]); else if (argv[i][0] != '-') continue; switch(argv[i][1]) { case 'D': if (argv[i][2]) { /* Amylaar : allow flags to be passed down to the LPC preprocessor */ struct lpc_predef_s *tmp; tmp = (struct lpc_predef_s *) xalloc(sizeof(struct lpc_predef_s)); if (!tmp) fatal("alloca failed"); tmp->flag = argv[i]+2; tmp->next = lpc_predefs; lpc_predefs = tmp; continue; } fprintf(stderr, "Illegal flag syntax: %s\n", argv[i]); exit(1); case 'N': no_ip_demon++; continue; case 'm': if (chdir(argv[i]+2) == -1) { fprintf(stderr, "Bad mudlib directory: %s\n", argv[i]+2); exit(1); } new_mudlib = 1; break; } } init_shared_strings(); if (!new_mudlib && chdir(MUD_LIB) == -1) { fprintf(stderr, "Bad mudlib directory: %s\n", MUD_LIB); exit(1); } /* Initialize swap */ init_swap(); #ifndef NO_IP_DEMON if (!no_ip_demon) start_ip_demon(); #endif if (setjmp(error_recovery_context)) { clear_state(); add_message("Anomaly in the fabric of world space.\n"); } else { error_recovery_context_exists = 1; get_simul_efun(); master_ob = load_object("secure/master", 1, 0); if (master_ob) { extern void master_ob_loaded(void); /* * Make sure master_ob is never made a dangling pointer. * Look at apply_master_ob() for more details. */ add_ref(master_ob, "main"); master_ob->prog->flags |= PRAGMA_RESIDENT; master_ob_loaded(); create_object(master_ob); clear_state(); } } error_recovery_context_exists = 0; if (master_ob == 0) { fprintf(stderr, "The file secure/master must be loadable.\n"); exit(1); } set_inc_list(apply_master_ob(M_DEFINE_INCLUDE_DIRS, 0)); { struct svalue* ret; ret = apply_master_ob(M_PREDEF_DEFINES, 0); if (ret && ret->type == T_POINTER) { int i; struct lpc_predef_s *tmp; for (i = 0; i < ret->u.vec->size; i++) if (ret->u.vec->item[i].type == T_STRING) { tmp = (struct lpc_predef_s *) xalloc(sizeof(struct lpc_predef_s)); tmp->flag = string_copy(ret->u.vec->item[i].u.string); tmp->next = lpc_predefs; lpc_predefs = tmp; } } } for (i = 1; i < argc; i++) { if (atoi(argv[i])) ; else if (argv[i][0] != '-') { fprintf(stderr, "Bad argument %s\n", argv[i]); exit(1); } else { /* * Look at flags. -m has already been tested. */ switch(argv[i][1]) { case 'f': push_string(argv[i]+2, STRING_MALLOC); (void)apply_master_ob(M_FLAG, 1); if (game_is_being_shut_down) { fprintf(stderr, "Shutdown by master object.\n"); exit(0); } continue; case 'e': e_flag++; continue; case 'D': continue; case 'N': continue; case 'm': continue; case 'd': d_flag = atoi(argv[i] + 2); continue; case 'c': comp_flag++; continue; case 't': t_flag++; continue; case 'S': s_flag++; mudstatus_set(1, -1, -1); /* Statistics, default limits */ continue; #ifdef CATCH_UDP_PORT case 'u': udp_port = atoi (&argv[i][2]); continue; #endif #ifdef SERVICE_PORT case 'p': service_port = atoi (&argv[i][2]); continue; #endif #ifdef YYDEBUG case 'y': yydebug = 1; continue; #endif default: fprintf(stderr, "Unknown flag: %s\n", argv[i]); exit(1); } } } /* See to it that the mud name is always defined in compiled files */ ret = apply_master_ob(M_GET_MUD_NAME, 0); if (ret && ret->type == T_STRING) { struct lpc_predef_s *tmp; tmp = (struct lpc_predef_s *) alloca(sizeof(struct lpc_predef_s)); if (!tmp) fatal("alloca failed"); tmp->flag = string_copy(ret->u.string); tmp->next = lpc_predefs; lpc_predefs = tmp; } ret = apply_master_ob(M_GET_VBFC_OBJECT, 0); if (ret && ret->type == T_OBJECT) { vbfc_object = ret->u.ob; vbfc_object->ref++; } else vbfc_object = 0; if (game_is_being_shut_down) exit(1); preload_objects(e_flag); apply_master_ob(M_FINAL_BOOT, 0); backend(); return 0; } char *string_copy(str) char *str; { char *p; p = xalloc(strlen(str)+1); (void)strcpy(p, str); return p; } /*VARARGS1*/ void debug_message(va_alist) va_dcl { va_list argp; char *fmt, *f; static FILE *fp = NULL; char deb[100]; char name[100]; if (fp == NULL) { #ifdef _SEQUENT_ strcpy(deb, "log/debug.log"); #else gethostname(name,sizeof name); if ((f = strchr(name, '.')) != NULL) *f = '\0'; sprintf(deb,"%s.debug.log",name); #endif fp = fopen(deb, "w"); if (fp == NULL) { perror(deb); abort(); } } va_start(argp); fmt = va_arg(argp, char *); vfprintf(fp, fmt, argp); (void)fflush(fp); } void debug_message_svalue(struct svalue *v) { if (v == 0) { debug_message("<NULL>"); return; } switch(v->type) { case T_NUMBER: debug_message("%d", v->u.number); return; case T_STRING: debug_message("\"%s\"", v->u.string); return; case T_OBJECT: debug_message("OBJ(%s)", v->u.ob->name); return; case T_LVALUE: debug_message("Pointer to "); debug_message_svalue(v->u.lvalue); return; default: debug_message("<INVALID>\n"); return; } } int slow_shut_down_to_do = 0; #if 1 #ifdef malloc #undef malloc #endif #endif /*#define MALLOCSIZE*/ extern void *bmalloc(); char * xalloc(int size) { char *p; static int going_to_exit; if (going_to_exit) exit(3); if (size == 0) size = 1; #ifdef MALLOCSIZE { #define MSMAX 1000 static int msize[MSMAX]; static int mbig; static int mcnt; if (size > MSMAX) mbig++; else msize[size]++; if (++mcnt % 50000 == 0) { int i; fprintf(stderr, "Malloc stats (%d):\n", mcnt); for(i = 0; i<MSMAX; i++) if (msize[i]) fprintf(stderr, "%4d %5d\n", i, msize[i]); fprintf(stderr, ">%d %d\n", i, mbig); } } #endif p = (char *)malloc(size); if (p == 0) { if (reserved_area) { extern void look_for_objects_to_swap(int); extern struct object *swap_ob; free(reserved_area); reserved_area = 0; p = "Temporary out of MEMORY. Freeing reserve.\n"; write(1, p, strlen(p)); slow_shut_down_to_do = 6; return xalloc(size); /* Try again */ } going_to_exit = 1; p = "Totally out of MEMORY.\n"; write(1, p, strlen(p)); (void)dump_trace(0); exit(2); } return p; } #ifndef NO_IP_DEMON static void start_ip_demon() { extern FILE *f_ip_demon, *f_ip_demon_wr; char path[100]; int tochild[2], fromchild[2]; int pid; char c; if(pipe(tochild) < 0) return; if(pipe(fromchild) < 0) { close(tochild[0]); close(tochild[1]); return; } if((pid = fork()) == 0) { /* Child */ dup2(tochild[0], 0); dup2(fromchild[1], 1); close(tochild[0]); close(tochild[1]); close(fromchild[0]); close(fromchild[1]); if (strlen(BINDIR) + 7 <= sizeof path) { sprintf(path, "%s/hname", BINDIR); execl((char *)path, "hname", 0); } write(1, "0", 1); /* indicate failure */ fprintf(stderr, "exec of hname failed.\n"); _exit(1); } if(pid == -1) { close(tochild[0]); close(tochild[1]); close(fromchild[0]); close(fromchild[1]); return; } close(tochild[0]); close(fromchild[1]); read(fromchild[0], &c, 1); if (c == '0') { close(tochild[1]); close(fromchild[0]); return; } f_ip_demon_wr = fdopen(tochild[1], "w"); f_ip_demon = fdopen(fromchild[0], "r"); if (f_ip_demon == NULL || f_ip_demon_wr == NULL) { f_ip_demon = NULL; close(tochild[1]); close(fromchild[0]); } } #endif