From 1d219b4e1bdf89a85714ab4d8939b89f9cd03ec7 Mon Sep 17 00:00:00 2001 From: keni Date: Fri, 27 Jan 2012 20:15:31 +0000 Subject: [PATCH] SYSCF bits (This covers some thing that Pat found and some things I found while working on those.) Unscramble duplicate use of GREPPATH and GDBPATH symbols. Add some more info to config.h. Make missing SYSCF_FILE a fatal error. Make a parse error in SYSCF_FILE a fatal error. Rename PANICTRACE_GLIBC (et al) to PANICTRACE_LIBC (et al) since FreeBSD and Mac OS X (at least) also implement the needed API. Allow SYSCF_FILE to be unreadable by the user (for setgid installs). If SYSCF, do NOT fall back to the compiled in WIZARD account. Put WIZARD into sysopt and remove special cases in authorize_wizard_mode(). --- include/config.h | 14 +++++++++- include/extern.h | 8 +++++- include/global.h | 5 +++- include/sys.h | 4 +-- src/end.c | 64 ++++++++++++++++++++++----------------------- src/files.c | 41 +++++++++++++++++++---------- src/options.c | 8 +++++- src/sys.c | 27 ++++++++++++------- sys/unix/sysconf | 8 +++--- sys/unix/unixmain.c | 35 +++++++++++++------------ sys/unix/unixunix.c | 15 +++++++++++ 11 files changed, 147 insertions(+), 82 deletions(-) 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 -- 2.40.0