Commit d5977e4c authored by Timothy Smith's avatar Timothy Smith

Bug #20748: Configuration files should not be read more than once

Normalize directory names before adding them to default_directories.


mysys/default.c:
  Normalize directory names with unpack_dirname() before adding them
  to default_directories.  This way, /etc/ and /etc will not count as
  duplicates.
  
  Because this entails allocating memory to store the normalized names,
  add error handling and ensure that it doesn't leak memory in case
  both my_print_defaults() and load_defaults() are called.
  
  Clean up the Windows code that finds the exe's parent directory, and
  pull it out into a separate function.
  
  Reorganize the code into a single init_default_directories() function,
  with internal #ifdefs, instead of init_default_directories_<system>()
  functions which were accessed via a function pointer.  This is more in
  line with normal MySQL coding style, and easier to read for some.
parent 07350a6c
...@@ -48,13 +48,12 @@ char *my_defaults_extra_file=0; ...@@ -48,13 +48,12 @@ char *my_defaults_extra_file=0;
/* Which directories are searched for options (and in which order) */ /* Which directories are searched for options (and in which order) */
#define MAX_DEFAULT_DIRS 6 #define MAX_DEFAULT_DIRS 6
const char *default_directories[MAX_DEFAULT_DIRS + 1]; #define DEFAULT_DIRS_SIZE (MAX_DEFAULT_DIRS + 1) /* Terminate with NULL */
static const char **default_directories = NULL;
#ifdef __WIN__ #ifdef __WIN__
static const char *f_extensions[]= { ".ini", ".cnf", 0 }; static const char *f_extensions[]= { ".ini", ".cnf", 0 };
#define NEWLINE "\r\n" #define NEWLINE "\r\n"
static char system_dir[FN_REFLEN], shared_system_dir[FN_REFLEN],
config_dir[FN_REFLEN];
#else #else
static const char *f_extensions[]= { ".cnf", 0 }; static const char *f_extensions[]= { ".cnf", 0 };
#define NEWLINE "\n" #define NEWLINE "\n"
...@@ -85,19 +84,34 @@ static int search_default_file_with_ext(Process_option_func func, ...@@ -85,19 +84,34 @@ static int search_default_file_with_ext(Process_option_func func,
const char *config_file, int recursion_level); const char *config_file, int recursion_level);
/** /**
Create the list of default directories. Create the list of default directories.
@param alloc MEM_ROOT where the list of directories is stored
@details @details
The directories searched, in order, are:
- Windows: GetSystemWindowsDirectory()
- Windows: GetWindowsDirectory()
- Windows: C:/
- Windows: Directory above where the executable is located
- Netware: sys:/etc/
- Unix & OS/2: /etc/
- Unix: --sysconfdir=<path> (compile-time option)
- OS/2: getenv(ETC)
- ALL: getenv(DEFAULT_HOME_ENV)
- ALL: --defaults-extra-file=<path> (run-time option)
- Unix: ~/
On all systems, if a directory is already in the list, it will be moved On all systems, if a directory is already in the list, it will be moved
to the end of the list. This avoids reading defaults files multiple times, to the end of the list. This avoids reading defaults files multiple times,
while ensuring the correct precedence. while ensuring the correct precedence.
@return void @retval NULL Failure (out of memory, probably)
@retval other Pointer to NULL-terminated array of default directories
*/ */
static void (*init_default_directories)(); static const char **init_default_directories(MEM_ROOT *alloc);
static char *remove_end_comment(char *ptr); static char *remove_end_comment(char *ptr);
...@@ -386,8 +400,9 @@ int load_defaults(const char *conf_file, const char **groups, ...@@ -386,8 +400,9 @@ int load_defaults(const char *conf_file, const char **groups,
struct handle_option_ctx ctx; struct handle_option_ctx ctx;
DBUG_ENTER("load_defaults"); DBUG_ENTER("load_defaults");
init_default_directories();
init_alloc_root(&alloc,512,0); init_alloc_root(&alloc,512,0);
if ((default_directories= init_default_directories(&alloc)) == NULL)
goto err;
/* /*
Check if the user doesn't want any default option processing Check if the user doesn't want any default option processing
--no-defaults is always the first option --no-defaults is always the first option
...@@ -864,16 +879,28 @@ void my_print_default_files(const char *conf_file) ...@@ -864,16 +879,28 @@ void my_print_default_files(const char *conf_file)
my_bool have_ext= fn_ext(conf_file)[0] != 0; my_bool have_ext= fn_ext(conf_file)[0] != 0;
const char **exts_to_use= have_ext ? empty_list : f_extensions; const char **exts_to_use= have_ext ? empty_list : f_extensions;
char name[FN_REFLEN], **ext; char name[FN_REFLEN], **ext;
const char **dirs;
init_default_directories();
puts("\nDefault options are read from the following files in the given order:"); puts("\nDefault options are read from the following files in the given order:");
if (dirname_length(conf_file)) if (dirname_length(conf_file))
fputs(conf_file,stdout); fputs(conf_file,stdout);
else else
{ {
for (dirs=default_directories ; *dirs; dirs++) /*
If default_directories is already initialized, use it. Otherwise,
use a private MEM_ROOT.
*/
const char **dirs = default_directories;
MEM_ROOT alloc;
init_alloc_root(&alloc,512,0);
if (!dirs && (dirs= init_default_directories(&alloc)) == NULL)
{
fputs("Internal error initializing default directories list", stdout);
}
else
{
for ( ; *dirs; dirs++)
{ {
for (ext= (char**) exts_to_use; *ext; ext++) for (ext= (char**) exts_to_use; *ext; ext++)
{ {
...@@ -887,11 +914,14 @@ void my_print_default_files(const char *conf_file) ...@@ -887,11 +914,14 @@ void my_print_default_files(const char *conf_file)
continue; continue;
end= convert_dirname(name, pos, NullS); end= convert_dirname(name, pos, NullS);
if (name[0] == FN_HOMELIB) /* Add . to filenames in home */ if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
*end++='.'; *end++= '.';
strxmov(end, conf_file, *ext, " ", NullS); strxmov(end, conf_file, *ext, " ", NullS);
fputs(name,stdout); fputs(name, stdout);
}
} }
} }
free_root(&alloc, MYF(0));
} }
puts(""); puts("");
} }
...@@ -928,32 +958,23 @@ void print_defaults(const char *conf_file, const char **groups) ...@@ -928,32 +958,23 @@ void print_defaults(const char *conf_file, const char **groups)
#include <help_end.h> #include <help_end.h>
/* static int add_directory(MEM_ROOT *alloc, const char *dir, const char **dirs)
This extra complexity is to avoid declaring 'rc' if it won't be {
used. char buf[FN_REFLEN];
*/ uint len;
#define ADD_DIRECTORY_INTERNAL(DIR) \ char *p;
array_append_string_unique((DIR), default_directories, \ my_bool err __attribute__((unused));
array_elements(default_directories))
#ifdef DBUG_OFF
# define ADD_DIRECTORY(DIR) (void) ADD_DIRECTORY_INTERNAL(DIR)
#else
#define ADD_DIRECTORY(DIR) \
do { \
my_bool rc= ADD_DIRECTORY_INTERNAL(DIR); \
DBUG_ASSERT(rc == FALSE); /* Success */ \
} while (0)
#endif
/* Normalize directory name */
len= unpack_dirname(buf, dir);
if (!(p= strmake_root(alloc, buf, len)))
return 1; /* Failure */
/* Should never fail if DEFAULT_DIRS_SIZE is correct size */
err= array_append_string_unique(p, dirs, DEFAULT_DIRS_SIZE);
DBUG_ASSERT(err == FALSE);
#define ADD_COMMON_DIRECTORIES() \ return 0;
do { \ }
char *env; \
if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) \
ADD_DIRECTORY(env); \
/* Placeholder for --defaults-extra-file=<path> */ \
ADD_DIRECTORY(""); \
} while (0)
#ifdef __WIN__ #ifdef __WIN__
...@@ -992,138 +1013,91 @@ static uint my_get_system_windows_directory(char *buffer, uint size) ...@@ -992,138 +1013,91 @@ static uint my_get_system_windows_directory(char *buffer, uint size)
} }
/** static const char *my_get_module_parent(char *buf, size_t size)
Initialize default directories for Microsoft Windows
@details
1. GetSystemWindowsDirectory()
2. GetWindowsDirectory()
3. C:/
4. Directory above where the executable is located
5. getenv(DEFAULT_HOME_ENV)
6. --defaults-extra-file=<path> (run-time option)
*/
static void init_default_directories_win()
{ {
bzero((char *) default_directories, sizeof(default_directories)); if (!GetModuleFileName(NULL, buf, size))
return NULL;
if (my_get_system_windows_directory(shared_system_dir,
sizeof(shared_system_dir)))
ADD_DIRECTORY(shared_system_dir);
if (GetWindowsDirectory(system_dir,sizeof(system_dir)))
ADD_DIRECTORY(system_dir);
ADD_DIRECTORY("C:/"); char *last= NULL, *end= strend(buf);
if (GetModuleFileName(NULL, config_dir, sizeof(config_dir)))
{
char *last= NULL, *end= strend(config_dir);
/* /*
Look for the second-to-last \ in the filename, but hang on Look for the second-to-last \ in the filename, but hang on
to a pointer after the last \ in case we're in the root of to a pointer after the last \ in case we're in the root of
a drive. a drive.
*/ */
for ( ; end > config_dir; end--) for ( ; end > buf; end--)
{ {
if (*end == FN_LIBCHAR) if (*end == FN_LIBCHAR)
{ {
if (last) if (last)
{
if (end != config_dir)
{ {
/* Keep the last '\' as this works both with D:\ and a directory */ /* Keep the last '\' as this works both with D:\ and a directory */
end[1]= 0; end[1]= 0;
}
else
{
/* No parent directory (strange). Use current dir + '\' */
last[1]= 0;
}
break; break;
} }
last= end; last= end;
} }
} }
ADD_DIRECTORY(config_dir);
}
ADD_COMMON_DIRECTORIES(); return buf;
} }
#endif /* __WIN__ */
static void (*init_default_directories)()= init_default_directories_win;
#elif defined(__NETWARE__)
/**
Initialize default directories for Novell Netware
@details
1. sys:/etc/
2. getenv(DEFAULT_HOME_ENV)
3. --defaults-extra-file=<path> (run-time option)
*/
static void init_default_directories_netware() static const char **init_default_directories(MEM_ROOT *alloc)
{ {
bzero((char *) default_directories, sizeof(default_directories)); const char **dirs;
ADD_DIRECTORY("sys:/etc/"); char *env;
ADD_COMMON_DIRECTORIES(); int errors= 0;
}
static void (*init_default_directories)()= init_default_directories_netware; dirs= (const char **)alloc_root(alloc, DEFAULT_DIRS_SIZE * sizeof(char *));
if (dirs == NULL)
return NULL;
bzero((char *) dirs, DEFAULT_DIRS_SIZE * sizeof(char *));
#elif defined(__EMX__) || defined(OS2) #ifdef __WIN__
/** {
Initialize default directories for OS/2 char fname_buffer[FN_REFLEN];
if (my_get_system_windows_directory(fname_buffer, sizeof(fname_buffer)))
errors += add_directory(alloc, fname_buffer, dirs);
@details if (GetWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
1. /etc/ errors += add_directory(alloc, fname_buffer, dirs);
2. getenv(ETC)
3. getenv(DEFAULT_HOME_ENV)
4. --defaults-extra-file=<path> (run-time option)
*/
static void init_default_directories_os2() errors += add_directory(alloc, "C:/", dirs);
{
const char *env;
bzero((char *) default_directories, sizeof(default_directories)); if (my_get_module_parent(fname_buffer, sizeof(fname_buffer)) != NULL)
ADD_DIRECTORY("/etc/"); errors += add_directory(alloc, fname_buffer, dirs);
if ((env= getenv("ETC"))) }
ADD_DIRECTORY(env);
ADD_COMMON_DIRECTORIES();
}
static void (*init_default_directories)()= init_default_directories_os2; #elif defined(__NETWARE__)
errors += add_directory(alloc, "sys:/etc/", dirs);
#else #else
/** errors += add_directory(alloc, "/etc/", dirs);
Initialize default directories for Unix
@details #if defined(__EMX__) || defined(OS2)
1. /etc/ if ((env= getenv("ETC")))
2. --sysconfdir=<path> (compile-time option) errors += add_directory(alloc, env, dirs);
3. getenv(DEFAULT_HOME_ENV) #elif defined(DEFAULT_SYSCONFDIR)
4. --defaults-extra-file=<path> (run-time option)
5. "~/"
*/
static void init_default_directories_unix()
{
bzero((char *) default_directories, sizeof(default_directories));
ADD_DIRECTORY("/etc/");
#ifdef DEFAULT_SYSCONFDIR
if (DEFAULT_SYSCONFDIR != "") if (DEFAULT_SYSCONFDIR != "")
ADD_DIRECTORY(DEFAULT_SYSCONFDIR); errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs);
#endif /* __EMX__ || __OS2__ */
#endif #endif
ADD_COMMON_DIRECTORIES();
ADD_DIRECTORY("~/");
}
static void (*init_default_directories)()= init_default_directories_unix; if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV))))
errors += add_directory(alloc, env, dirs);
/* Placeholder for --defaults-extra-file=<path> */
errors += add_directory(alloc, "", dirs);
#if !defined(__WIN__) && !defined(__NETWARE__) && \
!defined(__EMX__) && !defined(OS2)
errors += add_directory(alloc, "~/", dirs);
#endif #endif
return (errors > 0 ? NULL : dirs);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment