diff --git a/include/config.h b/include/config.h index 23b2b35bf..13adba0d4 100644 --- a/include/config.h +++ b/include/config.h @@ -150,7 +150,8 @@ * If SYSCF is defined, the following configuration info is * available in a global config space, with the compiled-in * entries as defaults: - * WIZARDS ( a value of * allows anyone to be wizard) + * WIZARDS (a value of * allows anyone to be wizard) + * (this does NOT default to compiled-in value) * MAXPLAYERS (see MAX_NR_OF_PLAYERS above and nethack.sh) * SUPPORT (how to get local support)(no default) * RECOVER (how to recover a game at your site)(no default) @@ -164,6 +165,10 @@ * * The following options select how the config space is stored: * SYSCF_FILE in the named file + * + * The following options pertain to crash reporting: + * GREPPATH (the path to the system grep(1) utility) + * GDBPATH (the path to the system gdb(1) program) */ #ifndef WIZARD /* allow for compile-time or Makefile changes */ @@ -177,6 +182,13 @@ # endif #endif +#ifndef GDBPATH +# define GDBPATH "/usr/bin/gdb" +#endif +#ifndef GREPPATH +# define GREPPATH "/bin/grep" +#endif + #define LOGFILE "logfile" /* larger file for debugging purposes */ #define NEWS "news" /* the file containing the latest hack news */ #define PANICLOG "paniclog" /* log of panic and impossible events */ diff --git a/include/extern.h b/include/extern.h index 1e8f1683b..19f00a20d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -742,7 +742,7 @@ E void FDECL(unlock_file, (const char *)); #ifdef USER_SOUNDS E boolean FDECL(can_read_file, (const char *)); #endif -E void FDECL(read_config_file, (const char *, int)); +E boolean FDECL(read_config_file, (const char *, int)); E void FDECL(check_recordfile, (const char *)); #if defined(WIZARD) E void NDECL(read_wizkit); @@ -2357,6 +2357,9 @@ E void NDECL(port_help); E void FDECL(sethanguphandler, (void (*)(int))); E boolean NDECL(authorize_wizard_mode); E boolean FDECL(check_user_string, (char *)); +# ifdef SYSCF_FILE +E void NDECL(assure_syscf_file); +# endif #endif /* UNIX */ /* ### unixtty.c ### */ @@ -2384,6 +2387,9 @@ E int NDECL(dosh); # if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER) E int FDECL(child, (int)); # endif +# ifdef PANICTRACE +E boolean FDECL(file_exists, (const char *)); +# endif #endif /* UNIX */ /* ### unixres.c ### */ diff --git a/include/global.h b/include/global.h index f728c33c7..f7514f44f 100644 --- a/include/global.h +++ b/include/global.h @@ -382,7 +382,10 @@ struct savefile_info { #endif /* The following are meaningless if PANICTRACE is not defined: */ #if defined(__linux__) && defined(__GLIBC__) && (__GLIBC__ >= 2) -# define PANICTRACE_GLIBC +# define PANICTRACE_LIBC +#endif +#if defined(MACOSX) +# define PANICTRACE_LIBC #endif #ifdef UNIX # define PANICTRACE_GDB diff --git a/include/sys.h b/include/sys.h index a45478fc4..24d27daa7 100644 --- a/include/sys.h +++ b/include/sys.h @@ -25,8 +25,8 @@ struct sysopt { char *gdbpath; char *greppath; int panictrace_gdb; -# ifdef PANICTRACE_GLIBC - int panictrace_glibc; +# ifdef PANICTRACE_LIBC + int panictrace_libc; # endif #endif int seduce; diff --git a/src/end.c b/src/end.c index 332a6277a..40dc61d22 100644 --- a/src/end.c +++ b/src/end.c @@ -77,13 +77,13 @@ extern void FDECL(nethack_exit,(int)); #ifdef PANICTRACE # include -# ifdef PANICTRACE_GLIBC +# ifdef PANICTRACE_LIBC # include # endif /* What do we try and in what order? Tradeoffs: - * glibc: +no external programs required - * -requires newish glibc + * libc: +no external programs required + * -requires newish libc/glibc * -requires -rdynamic * gdb: +gives more detailed information * +works on more OS versions @@ -91,17 +91,17 @@ extern void FDECL(nethack_exit,(int)); */ # ifdef SYSCF # define SYSOPT_PANICTRACE_GDB sysopt.panictrace_gdb -# ifdef PANICTRACE_GLIBC -# define SYSOPT_PANICTRACE_GLIBC sysopt.panictrace_glibc +# ifdef PANICTRACE_LIBC +# define SYSOPT_PANICTRACE_LIBC sysopt.panictrace_libc # else -# define SYSOPT_PANICTRACE_GLIBC 0 +# define SYSOPT_PANICTRACE_LIBC 0 # endif # else # define SYSOPT_PANICTRACE_GDB (nh_getenv("NETHACK_USE_GDB")==0?0:2) -# ifdef PANICTRACE_GLIBC -# define SYSOPT_PANICTRACE_GLIBC 1 +# ifdef PANICTRACE_LIBC +# define SYSOPT_PANICTRACE_LIBC 1 # else -# define SYSOPT_PANICTRACE_GLIBC 0 +# define SYSOPT_PANICTRACE_LIBC 0 # endif # endif @@ -109,7 +109,7 @@ static void NDECL(NH_abort); # ifndef NO_SIGNAL static void FDECL(panictrace_handler, (int)); # endif -static boolean NDECL(NH_panictrace_glibc); +static boolean NDECL(NH_panictrace_libc); static boolean NDECL(NH_panictrace_gdb); # ifndef NO_SIGNAL @@ -163,19 +163,19 @@ static void NH_abort() { int gdb_prio = SYSOPT_PANICTRACE_GDB; - int glibc_prio = SYSOPT_PANICTRACE_GLIBC; + int libc_prio = SYSOPT_PANICTRACE_LIBC; static boolean aborting = FALSE; if(aborting) return; aborting = TRUE; # ifndef VMS - if(gdb_prio == glibc_prio && gdb_prio > 0) gdb_prio++; + if(gdb_prio == libc_prio && gdb_prio > 0) gdb_prio++; - if(gdb_prio > glibc_prio){ - NH_panictrace_gdb() || (glibc_prio && NH_panictrace_glibc()); + if(gdb_prio > libc_prio){ + NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc()); } else { - NH_panictrace_glibc() || (gdb_prio && NH_panictrace_gdb()); + NH_panictrace_libc() || (gdb_prio && NH_panictrace_gdb()); } # else /* VMS */ @@ -183,7 +183,7 @@ NH_abort() traceback and exit; 2 = show traceback and stay in debugger */ /* if (wizard && gdb_prio == 1) gdb_prio = 2; */ vms_traceback(gdb_prio); - (void)glibc_prio; /* half-hearted attempt at lint suppression */ + (void)libc_prio; /* half-hearted attempt at lint suppression */ # endif /* ?VMS */ @@ -194,9 +194,9 @@ NH_abort() } static boolean -NH_panictrace_glibc() +NH_panictrace_libc() { -# ifdef PANICTRACE_GLIBC +# ifdef PANICTRACE_LIBC void *bt[20]; size_t count; char **info; @@ -212,22 +212,22 @@ NH_panictrace_glibc() return TRUE; # else return FALSE; -# endif /* !PANICTRACE_GLIBC */ +# endif /* !PANICTRACE_LIBC */ } +/* + * fooPATH file system path for foo + * fooVAR (possibly const) variable containing fooPATH + */ # ifdef PANICTRACE_GDB # ifdef SYSCF -# define GDBPATH sysopt.gdbpath -# define GREPPATH sysopt.greppath -# else -# ifndef GDBPATH -# define GDBPATH "/usr/bin/gdb" -# endif -# ifndef GREPPATH -# define GREPPATH "/bin/grep" -# endif -# endif /* !SYSCF */ -# endif /* PANICTRACE_GDB */ +# define GDBVAR sysopt.gdbpath +# define GREPVAR sysopt.greppath +# else /* SYSCF */ +# define GDBVAR GDBPATH +# define GREPVAR GREPPATH +# endif /* SYSCF */ +# endif /* PANICTRACE_GDB */ static boolean NH_panictrace_gdb() @@ -235,8 +235,8 @@ NH_panictrace_gdb() # ifdef PANICTRACE_GDB /* A (more) generic method to get a stack trace - invoke * gdb on ourself. */ - char *gdbpath = GDBPATH; - char *greppath = GREPPATH; + char *gdbpath = GDBVAR; + char *greppath = GREPVAR; char buf[BUFSZ]; FILE *gdb; diff --git a/src/files.c b/src/files.c index 107c20574..05afa7602 100644 --- a/src/files.c +++ b/src/files.c @@ -183,7 +183,7 @@ STATIC_DCL void FDECL(docompress_file, (const char *,BOOLEAN_P)); STATIC_DCL boolean FDECL(make_compressed_name, (const char *, char *)); #endif STATIC_DCL char *FDECL(make_lockname, (const char *,char *)); -STATIC_DCL FILE *FDECL(fopen_config_file, (const char *)); +STATIC_DCL FILE *FDECL(fopen_config_file, (const char *, int)); STATIC_DCL int FDECL(get_uchars, (FILE *,char *,char *,uchar *,BOOLEAN_P,int,const char *)); int FDECL(parse_config_line, (FILE *,char *,char *,char *,int)); #ifdef LOADSYMSETS @@ -1772,8 +1772,9 @@ const char *backward_compat_configfile = "nethack.cnf"; #endif STATIC_OVL FILE * -fopen_config_file(filename) +fopen_config_file(filename, src) const char *filename; +int src; { FILE *fp; #if defined(UNIX) || defined(VMS) @@ -1781,16 +1782,18 @@ const char *filename; char *envp; #endif - /* "filename" is an environment variable, so it should hang around */ - /* if set, it is expected to be a full path name (if relevant) */ + /* If src != SET_IN_SYS, "filename" is an environment variable, so it + * should hang around. If set, it is expected to be a full path name + * (if relevant) */ if (filename) { #ifdef UNIX - if (access(filename, 4) == -1) { + if ((src!=SET_IN_SYS) && access(filename, 4) == -1) { /* 4 is R_OK on newer systems */ /* nasty sneaky attempt to read file through * NetHack's setuid permissions -- this is the only * place a file name may be wholly under the player's - * control + * control (but SYSCF_FILE is not under the player's + * control so it's OK). */ raw_printf("Access to %s denied (%d).", filename, errno); @@ -2148,16 +2151,16 @@ int src; } sysopt.pointsmin = temp; # ifdef PANICTRACE -# ifdef PANICTRACE_GLIBC +# ifdef PANICTRACE_LIBC } else if (src == SET_IN_SYS && - match_varname(buf, "PANICTRACE_GLIBC", 16)) { + match_varname(buf, "PANICTRACE_LIBC", 15)) { int temp = atoi(bufp); if (temp < 0 || temp > 2) { - raw_printf("Illegal value in PANICTRACE_GLIBC (not 0,1,2)."); + raw_printf("Illegal value in PANICTRACE_LIBC (not 0,1,2)."); return 0; } - sysopt.panictrace_glibc = temp; -# endif /* PANICTRACE_GLIBC */ + sysopt.panictrace_libc = temp; +# endif /* PANICTRACE_LIBC */ } else if (src == SET_IN_SYS && match_varname(buf, "PANICTRACE_GDB", 14)) { int temp = atoi(bufp); @@ -2167,10 +2170,18 @@ int src; } sysopt.panictrace_gdb = temp; } else if ( (src==SET_IN_SYS) && match_varname(buf, "GDBPATH", 7)) { + if(!file_exists(bufp)){ + raw_printf("File specified in GDBPATH does not exist."); + return 0; + } if(sysopt.gdbpath) free(sysopt.gdbpath); sysopt.gdbpath = (char*)alloc(strlen(bufp)+1); Strcpy(sysopt.gdbpath, bufp); } else if ( (src==SET_IN_SYS) && match_varname(buf, "GREPPATH", 7)) { + if(!file_exists(bufp)){ + raw_printf("File specified in GREPPATH does not exist."); + return 0; + } if(sysopt.greppath) free(sysopt.greppath); sysopt.greppath = (char*)alloc(strlen(bufp)+1); Strcpy(sysopt.greppath, bufp); @@ -2377,7 +2388,7 @@ const char *filename; } #endif /* USER_SOUNDS */ -void +boolean read_config_file(filename, src) const char *filename; int src; @@ -2397,8 +2408,9 @@ int src; #endif char buf[4*BUFSZ]; FILE *fp; + boolean rv = TRUE; /* assume successful parse */ - if (!(fp = fopen_config_file(filename))) return; + if (!(fp = fopen_config_file(filename, src))) return FALSE; #if defined(MICRO) || defined(WIN32) # ifdef MFLOPPY @@ -2422,6 +2434,7 @@ OR: Forbid multiline stuff for alternate config sources. if (!parse_config_line(fp, buf, tmp_ramdisk, tmp_levels, src)) { raw_printf("Bad option line: \"%.50s\"", buf); wait_synch(); + rv = FALSE; } } (void) fclose(fp); @@ -2445,7 +2458,7 @@ OR: Forbid multiline stuff for alternate config sources. Strcpy(bones, levels); # endif /* MFLOPPY */ #endif /* MICRO */ - return; + return rv; } #ifdef WIZARD diff --git a/src/options.c b/src/options.c index 220506ff8..ab93220d5 100644 --- a/src/options.c +++ b/src/options.c @@ -572,7 +572,13 @@ initoptions() #ifdef SYSCF /* someday there may be other SYSCF alternatives besides text file */ # ifdef SYSCF_FILE - read_config_file(SYSCF_FILE, SET_IN_SYS); + /* If SYSCF_FILE is specified, it _must_ exist... */ + assure_syscf_file(); + /* ... and _must_ parse correctly. */ + if(!read_config_file(SYSCF_FILE, SET_IN_SYS)){ + raw_printf("Error(s) found in SYSCF_FILE, quitting."); + terminate(EXIT_FAILURE); + } # endif #endif initoptions_finish(); diff --git a/src/sys.c b/src/sys.c index be2aaf5fa..595373308 100644 --- a/src/sys.c +++ b/src/sys.c @@ -4,16 +4,25 @@ #include "hack.h" +/* for KR1ED config, WIZARD is 0 or 1 and WIZARD_NAME is a string; + for usual config, WIZARD is the string; forcing WIZARD_NAME to match it + eliminates conditional testing for which one to use in string ops */ +#ifndef KR1ED +# undef WIZARD_NAME +# define WIZARD_NAME WIZARD +#endif + struct sysopt sysopt; void sys_early_init(){ sysopt.support = NULL; sysopt.recover = NULL; -#ifdef notyet - /* replace use of WIZARD vs WIZARD_NAME vs KR1ED, by filling this in */ -#endif +#ifdef SYSCF sysopt.wizards = NULL; +#else + sysopt.wizards = WIZARD_NAME; +#endif sysopt.shellers = NULL; sysopt.maxplayers = 0; /* XXX eventually replace MAX_NR_OF_PLAYERS */ @@ -32,17 +41,17 @@ sys_early_init(){ #ifdef PANICTRACE /* panic options */ - sysopt.gdbpath = NULL; - sysopt.greppath = NULL; + sysopt.gdbpath = strdup(GDBPATH); + sysopt.greppath = strdup(GREPPATH); # ifdef BETA sysopt.panictrace_gdb = 1; -# ifdef PANICTRACE_GLIBC - sysopt.panictrace_glibc = 2; +# ifdef PANICTRACE_LIBC + sysopt.panictrace_libc = 2; # endif # else sysopt.panictrace_gdb = 0; -# ifdef PANICTRACE_GLIBC - sysopt.panictrace_glibc = 0; +# ifdef PANICTRACE_LIBC + sysopt.panictrace_libc = 0; # endif # endif #endif diff --git a/sys/unix/sysconf b/sys/unix/sysconf index 1f9da26ee..34efdcb8a 100644 --- a/sys/unix/sysconf +++ b/sys/unix/sysconf @@ -41,12 +41,12 @@ MAXPLAYERS=10 # Try to get more info in case of a program bug or crash. Using GDB can # get more information and works on more systems but requires gdb be available; -# using GLIBC only works if NetHack is linked with glibc. Both require -# certain compilation options. See src/end.c and sys/unix/hints/* for -# more information. +# using LIBC only works if NetHack is linked with a libc that supports the +# backtrace(3) API. Both require certain compilation options. See +# src/end.c and sys/unix/hints/* for more information. GDBPATH=/usr/bin/gdb GREPPATH=/bin/grep # Values are priorities: 0 - do not use this method, 1 - low priority, # 2 - high priority. Non-zero priority methods are tried in order. PANICTRACE_GDB=1 -PANICTRACE_GLIBC=2 +PANICTRACE_LIBC=2 diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 55a429f4e..be3617170 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -555,26 +555,15 @@ port_help() } #endif -/* for KR1ED config, WIZARD is 0 or 1 and WIZARD_NAME is a string; - for usual config, WIZARD is the string; forcing WIZARD_NAME to match it - eliminates conditional testing for which one to use in string ops */ -#ifndef KR1ED -# undef WIZARD_NAME -# define WIZARD_NAME WIZARD -#endif - /* validate wizard mode if player has requested access to it */ boolean authorize_wizard_mode() { #ifdef WIZARD struct passwd *pw = get_unix_pw(); -#ifdef SYSCF if (pw && sysopt.wizards && sysopt.wizards[0]) { if(check_user_string(sysopt.wizards)) return TRUE; - } else -#endif - if (pw && !strcmp(pw->pw_name, WIZARD_NAME)) return TRUE; + } #endif /* WIZARD */ wiz_error_flag = TRUE; /* not being allowed into wizard mode */ return FALSE; @@ -585,17 +574,12 @@ wd_message() { if (wiz_error_flag) { #ifdef WIZARD -# ifdef SYSCF if (sysopt.wizards && sysopt.wizards[0]) { char *tmp = build_english_list(sysopt.wizards); pline("Only user%s %s may access debug (wizard) mode.", index(sysopt.wizards, ' ')?"s":"", tmp); free(tmp); } else -# else - pline("Only user \"%s\" may access debug (wizard) mode.", - WIZARD_NAME); -# endif #else pline("Debug mode is not available."); #endif @@ -675,4 +659,21 @@ get_unix_pw() } return pw; } + +#ifdef SYSCF_FILE +void +assure_syscf_file(){ + /* All we really care about is the end result - can we read the file? + * So just check that directly. */ + int fd; + fd = open(SYSCF_FILE, O_RDONLY); + if(fd >= 0){ + /* readable */ + close(fd); + return; + } + raw_printf("Unable to open SYSCF_FILE.\n"); + exit(EXIT_FAILURE); +} +#endif /*unixmain.c*/ diff --git a/sys/unix/unixunix.c b/sys/unix/unixunix.c index 3078dacef..978dd477a 100644 --- a/sys/unix/unixunix.c +++ b/sys/unix/unixunix.c @@ -371,3 +371,18 @@ gid_t } #endif /* GETRES_SUPPORT */ + +/* XXX should be ifdef PANICTRACE_GDB, but there's no such symbol yet */ +#ifdef PANICTRACE +boolean +file_exists(const char *path){ + /* Just see if it's there - trying to figure out if we can actually + * execute it in all cases is too hard - we really just want to + * catch typos in SYSCF. */ + struct stat sb; + if(stat(path, &sb)){ + return FALSE; + } + return TRUE; +} +#endif