mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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.
This commit is contained in:
298
mysys/default.c
298
mysys/default.c
@ -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,
|
|||||||
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,
|
|||||||
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,34 +879,49 @@ 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)
|
||||||
{
|
{
|
||||||
for (ext= (char**) exts_to_use; *ext; ext++)
|
fputs("Internal error initializing default directories list", stdout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( ; *dirs; dirs++)
|
||||||
{
|
{
|
||||||
const char *pos;
|
for (ext= (char**) exts_to_use; *ext; ext++)
|
||||||
char *end;
|
{
|
||||||
if (**dirs)
|
const char *pos;
|
||||||
pos= *dirs;
|
char *end;
|
||||||
else if (my_defaults_extra_file)
|
if (**dirs)
|
||||||
pos= my_defaults_extra_file;
|
pos= *dirs;
|
||||||
else
|
else if (my_defaults_extra_file)
|
||||||
continue;
|
pos= my_defaults_extra_file;
|
||||||
end= convert_dirname(name, pos, NullS);
|
else
|
||||||
if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
|
continue;
|
||||||
*end++='.';
|
end= convert_dirname(name, pos, NullS);
|
||||||
strxmov(end, conf_file, *ext, " ", NullS);
|
if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
|
||||||
fputs(name,stdout);
|
*end++= '.';
|
||||||
|
strxmov(end, conf_file, *ext, " ", NullS);
|
||||||
|
fputs(name, stdout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_root(&alloc, MYF(0));
|
||||||
}
|
}
|
||||||
puts("");
|
puts("");
|
||||||
}
|
}
|
||||||
@ -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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
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,
|
char *last= NULL, *end= strend(buf);
|
||||||
sizeof(shared_system_dir)))
|
/*
|
||||||
ADD_DIRECTORY(shared_system_dir);
|
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
|
||||||
if (GetWindowsDirectory(system_dir,sizeof(system_dir)))
|
a drive.
|
||||||
ADD_DIRECTORY(system_dir);
|
*/
|
||||||
|
for ( ; end > buf; end--)
|
||||||
ADD_DIRECTORY("C:/");
|
|
||||||
|
|
||||||
if (GetModuleFileName(NULL, config_dir, sizeof(config_dir)))
|
|
||||||
{
|
{
|
||||||
char *last= NULL, *end= strend(config_dir);
|
if (*end == FN_LIBCHAR)
|
||||||
/*
|
|
||||||
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
|
|
||||||
a drive.
|
|
||||||
*/
|
|
||||||
for ( ; end > config_dir; end--)
|
|
||||||
{
|
{
|
||||||
if (*end == FN_LIBCHAR)
|
if (last)
|
||||||
{
|
{
|
||||||
if (last)
|
/* Keep the last '\' as this works both with D:\ and a directory */
|
||||||
{
|
end[1]= 0;
|
||||||
if (end != config_dir)
|
break;
|
||||||
{
|
|
||||||
/* Keep the last '\' as this works both with D:\ and a directory */
|
|
||||||
end[1]= 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* No parent directory (strange). Use current dir + '\' */
|
|
||||||
last[1]= 0;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
|
static const char **init_default_directories(MEM_ROOT *alloc)
|
||||||
|
{
|
||||||
|
const char **dirs;
|
||||||
|
char *env;
|
||||||
|
int errors= 0;
|
||||||
|
|
||||||
|
dirs= (const char **)alloc_root(alloc, DEFAULT_DIRS_SIZE * sizeof(char *));
|
||||||
|
if (dirs == NULL)
|
||||||
|
return NULL;
|
||||||
|
bzero((char *) dirs, DEFAULT_DIRS_SIZE * sizeof(char *));
|
||||||
|
|
||||||
|
#ifdef __WIN__
|
||||||
|
|
||||||
|
{
|
||||||
|
char fname_buffer[FN_REFLEN];
|
||||||
|
if (my_get_system_windows_directory(fname_buffer, sizeof(fname_buffer)))
|
||||||
|
errors += add_directory(alloc, fname_buffer, dirs);
|
||||||
|
|
||||||
|
if (GetWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
|
||||||
|
errors += add_directory(alloc, fname_buffer, dirs);
|
||||||
|
|
||||||
|
errors += add_directory(alloc, "C:/", dirs);
|
||||||
|
|
||||||
|
if (my_get_module_parent(fname_buffer, sizeof(fname_buffer)) != NULL)
|
||||||
|
errors += add_directory(alloc, fname_buffer, dirs);
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(__NETWARE__)
|
#elif defined(__NETWARE__)
|
||||||
|
|
||||||
/**
|
errors += add_directory(alloc, "sys:/etc/", dirs);
|
||||||
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()
|
|
||||||
{
|
|
||||||
bzero((char *) default_directories, sizeof(default_directories));
|
|
||||||
ADD_DIRECTORY("sys:/etc/");
|
|
||||||
ADD_COMMON_DIRECTORIES();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void (*init_default_directories)()= init_default_directories_netware;
|
|
||||||
|
|
||||||
#elif defined(__EMX__) || defined(OS2)
|
|
||||||
|
|
||||||
/**
|
|
||||||
Initialize default directories for OS/2
|
|
||||||
|
|
||||||
@details
|
|
||||||
1. /etc/
|
|
||||||
2. getenv(ETC)
|
|
||||||
3. getenv(DEFAULT_HOME_ENV)
|
|
||||||
4. --defaults-extra-file=<path> (run-time option)
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void init_default_directories_os2()
|
|
||||||
{
|
|
||||||
const char *env;
|
|
||||||
|
|
||||||
bzero((char *) default_directories, sizeof(default_directories));
|
|
||||||
ADD_DIRECTORY("/etc/");
|
|
||||||
if ((env= getenv("ETC")))
|
|
||||||
ADD_DIRECTORY(env);
|
|
||||||
ADD_COMMON_DIRECTORIES();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void (*init_default_directories)()= init_default_directories_os2;
|
|
||||||
|
|
||||||
#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("~/");
|
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
|
||||||
|
|
||||||
|
return (errors > 0 ? NULL : dirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void (*init_default_directories)()= init_default_directories_unix;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
Reference in New Issue
Block a user