From 4ff8d8ac7e4382bab89e267e32d485c1b7d53c58 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 12 Jun 2016 17:52:12 -0700 Subject: [PATCH] fix #H4060 - sysconf is re-read if no config file Config file handling remembers the name of the last config file read in order for options processing to use it in messages, but it was also reused as default config file name if user-supplied config file name failed access() test. So the SYSCF file became the default user config file after it was used. The config file handling was a real mess. This patch fixes it for Unix but there is a lot of scope for typos in the changes for other platforms. Testing is needed. --- doc/fixes36.1 | 2 + include/decl.h | 2 - src/files.c | 131 ++++++++++++++++++++++++--------------------- src/options.c | 10 ++-- sys/amiga/winreq.c | 2 +- 5 files changed, 80 insertions(+), 67 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 7a87418db..ec56d335f 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -288,6 +288,8 @@ using /? to look up something by name, supplying multiple spaces (with no add support for the 'altmeta' option to the 'what-does' command ('&' or '?f') when wielded weapon becomes untouchable (after alignment change or polymorph) hero could be 'blasted by its power' twice in succession +at startup, if sysconf had been read but user's own config file couldn't be + read, sysconf got processed again as if it contained user's options Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/include/decl.h b/include/decl.h index 7898d17ce..21edb3cac 100644 --- a/include/decl.h +++ b/include/decl.h @@ -185,8 +185,6 @@ E NEARDATA struct kinfo { } killer; E long done_money; -E const char *configfile; -E char lastconfigfile[BUFSZ]; /* used for messaging */ E NEARDATA char plname[PL_NSIZ]; E NEARDATA char dogname[]; E NEARDATA char catname[]; diff --git a/src/files.c b/src/files.c index b505a4db7..51a76f188 100644 --- a/src/files.c +++ b/src/files.c @@ -188,6 +188,7 @@ STATIC_DCL boolean FDECL(make_compressed_name, (const char *, char *)); #ifndef USE_FCNTL STATIC_DCL char *FDECL(make_lockname, (const char *, char *)); #endif +STATIC_DCL void FDECL(set_configfile_name, (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 *)); @@ -1821,7 +1822,7 @@ const char *filename; /* ---------- BEGIN CONFIG FILE HANDLING ----------- */ -const char *configfile = +const char *default_configfile = #ifdef UNIX ".nethackrc"; #else @@ -1837,7 +1838,7 @@ const char *configfile = #endif /* used for messaging */ -char lastconfigfile[BUFSZ]; +char configfile[BUFSZ]; #ifdef MSDOS /* conflict with speed-dial under windows @@ -1850,6 +1851,16 @@ char lastconfigfile[BUFSZ]; const char *backward_compat_configfile = "nethack.cnf"; #endif +/* remember the name of the file we're accessing; + if may be used in option reject messages */ +STATIC_OVL void +set_configfile_name(fname) +const char *fname; +{ + (void) strncpy(configfile, fname, sizeof configfile - 1); + configfile[sizeof configfile - 1] = '\0'; +} + #ifndef MFLOPPY #define fopenp fopen #endif @@ -1865,84 +1876,86 @@ int src; char *envp; #endif + if (src == SET_IN_SYS) { + /* SYSCF_FILE; if we can't open it, caller will bail */ + if (filename && *filename) { + set_configfile_name(fqname(filename, SYSCONFPREFIX, 0)); + fp = fopenp(configfile, "r"); + } else + fp = (FILE *) 0; + return fp; + } /* 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) { + * (if relevant) + */ + if (filename && *filename) { + set_configfile_name(filename); #ifdef UNIX - if ((src != SET_IN_SYS) && access(filename, 4) == -1) { - /* 4 is R_OK on newer systems */ + if (access(configfile, 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 (but SYSCF_FILE is not under the player's * control so it's OK). */ - raw_printf("Access to %s denied (%d).", filename, errno); + raw_printf("Access to %s denied (%d).", configfile, errno); wait_synch(); /* fall through to standard names */ } else #endif -#ifdef PREFIXES_IN_USE - if (src == SET_IN_SYS) { - (void) strncpy(lastconfigfile, fqname(filename, SYSCONFPREFIX, 0), - BUFSZ - 1); - } else -#endif - /* always honor sysconf first before anything else */ - (void) strncpy(lastconfigfile, filename, BUFSZ - 1); - lastconfigfile[BUFSZ - 1] = '\0'; - if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) - return fp; - if ((fp = fopenp(filename, "r")) != (FILE *) 0) { + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) { return fp; #if defined(UNIX) || defined(VMS) } else { /* access() above probably caught most problems for UNIX */ raw_printf("Couldn't open requested config file %s (%d).", - filename, errno); + configfile, errno); wait_synch(); -/* fall through to standard names */ #endif } } + /* fall through to standard names */ #if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) - if ((fp = fopenp(fqname(configfile, CONFIGPREFIX, 0), "r")) != (FILE *) 0) - return fp; - if ((fp = fopenp(configfile, "r")) != (FILE *) 0) + set_configfile_name(fqname(default_configfile, CONFIGPREFIX, 0)): + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) { return fp; + } else if (strcmp(default_configfile, configfile)) { + set_configfile_name(default_configfile); + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) + return fp; + } #ifdef MSDOS - if ((fp = fopenp(fqname(backward_compat_configfile, CONFIGPREFIX, 0), - "r")) != (FILE *) 0) - return fp; - if ((fp = fopenp(backward_compat_configfile, "r")) != (FILE *) 0) + set_configfile_name(fqname(backward_compat_configfile, CONFIGPREFIX, 0)); + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) { return fp; + } else if (strcmp(backwad_compat_configfile, configfile)) { + set_configfile_name(backward_compat_configfile); + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) + return fp; + } #endif #else /* constructed full path names don't need fqname() */ #ifdef VMS - (void) strncpy(lastconfigfile, fqname("nethackini", CONFIGPREFIX, 0), - BUFSZ - 1); - lastconfigfile[BUFSZ - 1] = '\0'; - if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) { + /* no punctuation, so might be a logical name */ + set_configfile_name(fqname("nethackini", CONFIGPREFIX, 0)); + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) return fp; - } - (void) strncpy(lastconfigfile, "sys$login:nethack.ini", BUFSZ - 1); - lastconfigfile[BUFSZ - 1] = '\0'; - if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) { + set_configfile_name("sys$login:nethack.ini"); + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) return fp; - } envp = nh_getenv("HOME"); - if (!envp) + if (!envp || !*envp) Strcpy(tmp_config, "NetHack.cnf"); else - Sprintf(tmp_config, "%s%s", envp, "NetHack.cnf"); - - (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1); - lastconfigfile[BUFSZ - 1] = '\0'; - if ((fp = fopenp(tmp_config, "r")) != (FILE *) 0) + Sprintf(tmp_config, "%s%s%s", envp, + !index(":]>/", envp[strlen(envp) - 1]) ? "/" : "", + "NetHack.cnf"); + set_configfile_name(tmp_config); + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) return fp; #else /* should be only UNIX left */ envp = nh_getenv("HOME"); @@ -1951,43 +1964,41 @@ int src; else Sprintf(tmp_config, "%s/%s", envp, ".nethackrc"); - (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1); - lastconfigfile[BUFSZ - 1] = '\0'; - if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) + set_configfile_name(tmp_config); + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) return fp; -#if defined(__APPLE__) +#if defined(__APPLE__) /* UNIX+__APPLE__ => MacOSX */ /* try an alternative */ if (envp) { + /* OSX-style configuration settings */ Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults"); - (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1); - lastconfigfile[BUFSZ - 1] = '\0'; - if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) + set_configfile_name(tmp_config); + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) return fp; + /* may be easier for user to edit if filename as '.txt' suffix */ Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults.txt"); - (void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1); - lastconfigfile[BUFSZ - 1] = '\0'; - if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) + set_configfile_name(tmp_config); + if ((fp = fopenp(configfile, "r")) != (FILE *) 0) return fp; } -#endif +#endif /*__APPLE__*/ if (errno != ENOENT) { const char *details; -/* e.g., problems when setuid NetHack can't search home - * directory restricted to user */ - + /* e.g., problems when setuid NetHack can't search home + directory restricted to user */ #if defined(NHSTDC) && !defined(NOTSTDC) if ((details = strerror(errno)) == 0) #endif details = ""; raw_printf("Couldn't open default config file %s %s(%d).", - lastconfigfile, details, errno); + configfile, details, errno); wait_synch(); } -#endif /* Unix */ -#endif +#endif /* !VMS => Unix */ +#endif /* !(MICRO || MAC || __BEOS__ || WIN32) */ return (FILE *) 0; } diff --git a/src/options.c b/src/options.c index 69db5926f..1245c276b 100644 --- a/src/options.c +++ b/src/options.c @@ -420,6 +420,8 @@ static struct Comp_Opt { #else /* use rest of file */ +extern char configfile[]; /* for messages */ + extern struct symparse loadsyms[]; static boolean need_redraw; /* for doset() */ @@ -917,10 +919,10 @@ rejectoption(optname) const char *optname; { #ifdef MICRO - pline("\"%s\" settable only from %s.", optname, lastconfigfile); + pline("\"%s\" settable only from %s.", optname, configfile); #else pline("%s can be set only from NETHACKOPTIONS or %s.", optname, - lastconfigfile); + configfile); #endif } @@ -941,7 +943,7 @@ const char *opts; #endif if (from_file) - raw_printf("Bad syntax in OPTIONS in %s: %s%s.\n", lastconfigfile, + raw_printf("Bad syntax in OPTIONS in %s: %s%s.\n", configfile, #ifdef WIN32 "\n", #else @@ -5318,7 +5320,7 @@ option_help() winid datawin; datawin = create_nhwindow(NHW_TEXT); - Sprintf(buf, "Set options as OPTIONS= in %s", lastconfigfile); + Sprintf(buf, "Set options as OPTIONS= in %s", configfile); opt_intro[CONFIG_SLOT] = (const char *) buf; for (i = 0; opt_intro[i]; i++) putstr(datawin, 0, opt_intro[i]); diff --git a/sys/amiga/winreq.c b/sys/amiga/winreq.c index a5e4b95fb..3d59f5960 100644 --- a/sys/amiga/winreq.c +++ b/sys/amiga/winreq.c @@ -55,7 +55,7 @@ void ClearCol(struct Window *w); void EditColor() { - extern const char *configfile; + extern char configfile[]; int i, done = 0, okay = 0; long code, qual, class; register struct Gadget *gd, *dgad; -- 2.40.0