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.
This commit is contained in:
PatR
2016-06-12 17:52:12 -07:00
parent 4e12bb6144
commit 4ff8d8ac7e
5 changed files with 80 additions and 67 deletions

View File

@@ -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

View File

@@ -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[];

View File

@@ -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;
}

View File

@@ -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=<options> in %s", lastconfigfile);
Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
opt_intro[CONFIG_SLOT] = (const char *) buf;
for (i = 0; opt_intro[i]; i++)
putstr(datawin, 0, opt_intro[i]);

View File

@@ -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;