#include <stdio.h> #include <math.h> #include <setjmp.h> #include <errno.h> #include <signal.h> #ifndef SIGCLD #define SIGCLD SIGCHLD #endif #if defined(AMIGA) #include <stdarg.h> #endif #ifdef NeXT #include <sys/param.h> #endif #include "lint.h" #include "interpret.h" #include "object.h" #include "config.h" #include "lex.h" #include "patchlevel.h" #ifdef AMIGA #include "hosts/amiga/ixfile.h" #include "hosts/amiga/socket.h" #endif 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 comp_flag = 0; /* Trace compilations */ long time_to_swap = TIME_TO_SWAP; /* marion - invocation parameter */ #ifdef D_FLAG int D_flag; /* Log specific trace messages to /log/D_TRACE */ #endif #ifdef YYDEBUG extern int yydebug; #endif int port_number = PORTNO; #ifdef CATCH_UDP_PORT int udp_port = CATCH_UDP_PORT; #endif int out_of_memory = 0; int malloc_privilege = MALLOC_USER; char *reserved_user_area = 0, *reserved_master_area = 0, *reserved_system_area = 0; /* reserved for malloc() */ mp_int reserved_user_size = RESERVED_USER_SIZE; /* for statistical purposes */ mp_int reserved_master_size = RESERVED_MASTER_SIZE; mp_int reserved_system_size = RESERVED_SYSTEM_SIZE; #ifdef MAX_MALLOCED mp_int max_malloced = MAX_MALLOCED; mp_int max_small_malloced = MAX_SMALL_MALLOCED; #endif struct svalue const0, const1; extern struct svalue assoc_shared_string_key; double consts[5]; extern struct error_recovery_info toplevel_error_recovery_info; extern struct object *master_ob; struct wiz_list *back_bone_uid; char *mud_lib; /* store the path so that it can be restored later quickly */ #ifdef COMPAT_MODE char master_name[100] = "obj/master"; #else char master_name[100] = "secure/master"; #endif struct object dummy_current_object_for_loads = {0}; /* To have an object to assign array usage to */ int main(argc, argv) int argc; char **argv; { extern void init_shared_strings(); extern void init_otable(); extern int game_is_being_shut_down; extern int current_time; extern int32 initial_eval_cost, eval_cost, assigned_eval_cost; extern struct svalue walk_mapping_string_svalue; int i, new_mudlib = 0; int no_ip_demon = 0; char *p; #ifndef COMPAT_MODE struct svalue *ret; #endif #ifdef MALLOC_gc extern void gc_init(); #endif #ifdef MALLOC_gc gc_init(); #endif const0.type = T_NUMBER; const0.u.number = 0; const1.type = T_NUMBER; const1.u.number = 1; assoc_shared_string_key.type = T_STRING; assoc_shared_string_key.x.string_type = STRING_SHARED; /* * 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 #ifdef RAND srand(get_current_time()); #else fprintf(stderr, "No random generator specified!\n"); #endif /* RAND */ #endif /* RANDOM */ #endif /* DRAND48 */ current_time = get_current_time(); #if defined(AMIGA) { extern void amiga_init(), amiga_end(); amiga_init(); /* Will exit(20) on wrong OS */ atexit (amiga_end); } #endif /* * The flags are parsed twice ! * The first time, we search for the -m flag, which specifies * another mudlib, -Dmacro flags, so that they will be available * when compiling master.c , -N, -rsize and the -o flag. */ for (i=1; i < argc; i++) { 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 *) alloca(sizeof(struct lpc_predef_s)); if (!tmp) fatal("alloca failed\n"); tmp->flag = argv[i]+2; tmp->next = lpc_predefs; lpc_predefs = tmp; continue; } break; case 'o': fprintf(stderr, "-o is an obsolete flag. Use COMPAT_MODE in config.h.\n"); exit(0); break; case 'N': no_ip_demon++; continue; case 'M': p = argv[i] + 2; if (!*p && ++i < argc) p = argv[i]; if (strlen(p) >= sizeof(master_name)) { /* master_name needs to have space for \0 */ fprintf(stderr, "Too long master name '%s'\n", p); exit(1); } strcpy(master_name, p); continue; case 'm': p = argv[i] + 2; if (!*p && ++i < argc) p = argv[i]; if (chdir(p) == -1) { fprintf(stderr, "Bad mudlib directory: %s\n", p); exit(1); } new_mudlib = 1; break; case 'r': { mp_int *sizep; p = argv[i] + 2; switch(*p++) { default: p--; case 'u': sizep = &reserved_user_size; break; case 'm': sizep = &reserved_master_size; break; case 's': sizep = &reserved_system_size; break; } *sizep = strtol(p, (char**)0, 0); break; } case 'E': initial_eval_cost = -atoi(&argv[i][2]); break; case '-': p = argv[i] + 2; #ifdef MAX_MALLOCED if ( !strncmp(p, "max_malloced", 12) ) { if ( !*(p+=12) ) { i++; p = argv[i]; } max_malloced = strtol(p, (char **)0, 0); if (!max_malloced) fatal("0 max_malloced\n"); break; } if ( !strncmp(p, "max_small_malloced", 18) ) { if ( !*(p+=18) && ++i < argc) { p = argv[i]; } max_small_malloced = strtol(p, (char **)0, 0); break; } #endif if ( !strcmp(p, "version") ) { printf("Version %5.5s%s\nRelease date: %s\ncompiled %s\n", GAME_VERSION, PATCH_LEVEL, RELEASE_DATE, __DATE__ ); exit(0); } fprintf(stderr, "Unknown flag: %s\n", argv[i]); exit(1); } } #ifdef MIN_MALLOCED xfree(xalloc(MIN_MALLOCED)); #endif #ifdef MALLOC_smalloc if (reserved_system_size > 0) reserved_system_area = xalloc(reserved_system_size); if (reserved_master_size > 0) reserved_master_area = xalloc(reserved_master_size); #endif if (reserved_user_size > 0) reserved_user_area = xalloc(reserved_user_size); init_shared_strings(); walk_mapping_string_svalue.x.string_type = STRING_SHARED; init_otable(); for (i=0; i < sizeof consts / sizeof consts[0]; i++) consts[i] = exp(- i / 900.0); init_num_args(); reset_machine(1); CLEAR_EVAL_COST; if (!new_mudlib && chdir(MUD_LIB) == -1) { fprintf(stderr, "Bad mudlib directory: %s\n", MUD_LIB); exit(1); } { #ifdef MAXPATHLEN char path[MAXPATHLEN]; #else char path[2048]; #endif #ifdef HAVE_GETCWD (void)getcwd(path, sizeof(path) ); #else (void)getwd(path); #endif mud_lib = string_copy(path); } #ifndef NO_IP_DEMON { static void start_ip_demon(); if (!no_ip_demon) start_ip_demon(); } #endif /* if we get low on file descriptors, the descriptor for debug_message * should be there */ debug_message( (char*)0 ); current_object = &dummy_current_object_for_loads; if (setjmp(toplevel_error_recovery_info.context)) { clear_state(); add_message("Anomaly in the fabric of world space.\n"); } else { toplevel_error_recovery_info.type = ERROR_RECOVERY_BACKEND; master_ob = load_object(master_name, 0, 60); } current_object = master_ob; toplevel_error_recovery_info.type = ERROR_RECOVERY_NONE; if (master_ob == 0) { fprintf(stderr, "The file %s must be loadable.\n", master_name); exit(1); } /* * Make sure master_ob is never made a dangling pointer. * Look at apply_master_ob() for more details. */ add_ref(master_ob, "main"); #ifndef COMPAT_MODE ret = apply_master_ob("get_root_uid", 0); if (ret == 0 || ret->type != T_STRING) { fprintf(stderr, "get_root_uid() in %s does not work\n", master_name); #ifdef NATIVE_MODE exit(1); #endif } else { master_ob->user = add_name(ret->u.string); master_ob->eff_user = master_ob->user; } ret = apply_master_ob("get_bb_uid", 0); if (ret == 0 || ret->type != T_STRING) { fprintf(stderr, "get_bb_uid() in %s does not work\n", master_name); #ifdef NATIVE_MODE exit(1); #endif } else { back_bone_uid = add_name(ret->u.string); } #endif apply_master_ob("inaugurate_master", 0); setup_print_block_dispatcher(); for (i=1; i < argc; i++) { if (atoi(argv[i])) port_number = atoi(argv[i]); else if (argv[i][0] != '-') { fprintf(stderr, "Bad argument %s\n", argv[i]); exit(1); } else { /* * Look at flags. -m and -o have already been tested. */ switch(argv[i][1]) { case 'f': push_constant_string(argv[i]+2); (void)apply_master_ob("flag", 1); if (game_is_being_shut_down) { fprintf(stderr, "Shutdown by master object.\n"); exit(0); } continue; case 'D': if (argv[i][2]) { /* Amylaar : allow flags to be passed down to the LPC preprocessor */ continue; } #ifdef D_FLAG D_flag++; continue; #else fprintf(stderr, "'-D' is not supported\n"); exit(1); #endif case 'e': e_flag++; continue; case '-': { p = argv[i] + 2; if (p[-1] == '-') { if (!strcmp(p, "max_malloced") || !strcmp(p, "max_small_malloced") ) { i++; } } } case 'M': case 'm': if (!argv[i][2]) i++; /* fall through */ case 'o': case 'N': case 'r': case 'E': continue; /* these flags have been recognized above */ case 'd': d_flag++; continue; case 'c': comp_flag++; continue; case 't': t_flag++; continue; #ifdef CATCH_UDP_PORT case 'u': udp_port = atoi(&argv[i][2]); continue; #endif #if TIME_TO_SWAP > 0 case 's': time_to_swap = atoi (&argv[i][2]); if (time_to_swap < 0) time_to_swap = (unsigned)-1>>1; continue; #endif #ifdef YYDEBUG case 'y': yydebug = 1; continue; #endif default: fprintf(stderr, "Unknown flag: %s\n", argv[i]); exit(1); } } } get_simul_efun_object(); if (game_is_being_shut_down) exit(1); load_wiz_file(); set_inc_list(apply_master_ob("define_include_dirs", 0)); #ifdef COMPAT_MODE load_first_objects(); (void)apply_master_ob("epilog", 0); #else preload_objects(e_flag); #endif backend(); return 0; } #ifdef string_copy char *_string_copy(str, file, line) char *str, *file; int line; { char *p; p = smalloc(strlen(str)+1, file, line); if (p) { (void)strcpy(p, str); } return p; } #else char *string_copy(str) char *str; { char *p; p = xalloc(strlen(str)+1); if (p) { (void)strcpy(p, str); } return p; } #endif #if defined(AMIGA) void debug_message(char *a, ...) #else /*VARARGS1*/ void debug_message(a, b, c, d, e, f, g, h, i, j) char *a; int b, c, d, e, f, g, h, i, j; #endif { static FILE *fp = NULL; char deb[100]; char name[100]; #if defined(AMIGA) va_list va; #endif #if defined(AMIGA) va_start(va, a); #endif if (fp == NULL) { #ifndef MSDOS gethostname(name,sizeof name); sprintf(deb,"%s.debug.log",name); #else strcpy(deb,"debug.log"); #endif #ifndef AMIGA fp = fopen(deb, "w"); #else fp = fopen(deb, "a"); #endif if (fp == NULL) { perror(deb); abort(); } if (!a) return; } #if defined(AMIGA) (void)vfprintf(fp, a, va); va_end(va); #else (void)fprintf(fp, a, b, c, d, e, f, g, h, i, j); #endif (void)fflush(fp); } void debug_message_svalue(v) 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; #ifndef MALLOC_smalloc POINTER xalloc(size) size_t size; { char *p; static int going_to_exit; if (going_to_exit) exit(3); if (size == 0) fatal("Tried to allocate 0 bytes.\n"); #ifdef MAX_MALLOCED { static mp_int total_malloced = 0; if ((total_malloced += size + sizeof(p_int)) > max_malloced) { total_malloced -= size + sizeof(p_int); p = 0; } else { p = malloc(size); } } #else p = malloc(size); #endif if (p == 0) { if (reserved_user_area) { extern int garbage_collect_to_do; extern int extra_jobs_to_do; free(reserved_user_area); p = "Temporary out of MEMORY. Freeing reserve.\n"; write(1, p, strlen(p)); reserved_user_area = 0; garbage_collect_to_do = 1; extra_jobs_to_do = 1; return xalloc(size); /* Try again */ } /* We can hardly survive out of memory without the garbage collector */ going_to_exit = 1; p = "Totally out of MEMORY.\n"; write(1, p, strlen(p)); (void)dump_trace(0); exit(2); } return p; } #endif /* MALLOC_smalloc */ void reallocate_reserved_areas() { malloc_privilege = MALLOC_USER; if (reserved_system_size && !reserved_system_area) { if ( !(reserved_system_area = xalloc(reserved_system_size)) ) { slow_shut_down_to_do = 1; return; } } if (reserved_master_size && !reserved_master_area) { if ( !(reserved_master_area = xalloc(reserved_master_size)) ) { slow_shut_down_to_do = 1; return; } } if (reserved_user_size && !reserved_user_area) { if ( !(reserved_user_area = xalloc(reserved_user_size)) ) slow_shut_down_to_do = 6; } } #ifndef NO_IP_DEMON static void start_ip_demon() { extern FILE *f_ip_demon, *f_ip_demon_wr; void nonblock_by_ip_demon(); 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; } (void)signal(SIGCLD, SIG_IGN); /* don't create zombie processes */ 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]); } nonblock_by_ip_demon(); } #endif