diff options
author | Timothy Smith <timothy.smith@sun.com> | 2008-06-24 19:25:23 -0600 |
---|---|---|
committer | Timothy Smith <timothy.smith@sun.com> | 2008-06-24 19:25:23 -0600 |
commit | bbe19e1360ec5b7dd33721b3cf19c6275c172021 (patch) | |
tree | 3d43edb300e41e75d201f36e255d247615807eb0 /mysys | |
parent | c1a597cdf6daf2cde246453e23581d781799bd7d (diff) | |
download | mariadb-git-bbe19e1360ec5b7dd33721b3cf19c6275c172021.tar.gz |
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.
Diffstat (limited to 'mysys')
-rw-r--r-- | mysys/default.c | 284 |
1 files changed, 129 insertions, 155 deletions
diff --git a/mysys/default.c b/mysys/default.c index e58903d6d64..eb7721acaed 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -48,13 +48,12 @@ char *my_defaults_extra_file=0; /* Which directories are searched for options (and in which order) */ #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__ static const char *f_extensions[]= { ".ini", ".cnf", 0 }; #define NEWLINE "\r\n" -static char system_dir[FN_REFLEN], shared_system_dir[FN_REFLEN], - config_dir[FN_REFLEN]; #else static const char *f_extensions[]= { ".cnf", 0 }; #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); - /** Create the list of default directories. + @param alloc MEM_ROOT where the list of directories is stored + @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 to the end of the list. This avoids reading defaults files multiple times, 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); @@ -386,8 +400,9 @@ int load_defaults(const char *conf_file, const char **groups, struct handle_option_ctx ctx; DBUG_ENTER("load_defaults"); - init_default_directories(); 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 --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; const char **exts_to_use= have_ext ? empty_list : f_extensions; char name[FN_REFLEN], **ext; - const char **dirs; - init_default_directories(); puts("\nDefault options are read from the following files in the given order:"); if (dirname_length(conf_file)) fputs(conf_file,stdout); 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; - char *end; - if (**dirs) - pos= *dirs; - else if (my_defaults_extra_file) - pos= my_defaults_extra_file; - else - continue; - end= convert_dirname(name, pos, NullS); - if (name[0] == FN_HOMELIB) /* Add . to filenames in home */ - *end++='.'; - strxmov(end, conf_file, *ext, " ", NullS); - fputs(name,stdout); + for (ext= (char**) exts_to_use; *ext; ext++) + { + const char *pos; + char *end; + if (**dirs) + pos= *dirs; + else if (my_defaults_extra_file) + pos= my_defaults_extra_file; + else + continue; + end= convert_dirname(name, pos, NullS); + if (name[0] == FN_HOMELIB) /* Add . to filenames in home */ + *end++= '.'; + strxmov(end, conf_file, *ext, " ", NullS); + fputs(name, stdout); + } } } + + free_root(&alloc, MYF(0)); } puts(""); } @@ -928,32 +958,23 @@ void print_defaults(const char *conf_file, const char **groups) #include <help_end.h> -/* - This extra complexity is to avoid declaring 'rc' if it won't be - used. -*/ -#define ADD_DIRECTORY_INTERNAL(DIR) \ - array_append_string_unique((DIR), default_directories, \ - 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 - +static int add_directory(MEM_ROOT *alloc, const char *dir, const char **dirs) +{ + char buf[FN_REFLEN]; + uint len; + char *p; + my_bool err __attribute__((unused)); + + /* 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() \ - do { \ - char *env; \ - if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) \ - ADD_DIRECTORY(env); \ - /* Placeholder for --defaults-extra-file=<path> */ \ - ADD_DIRECTORY(""); \ - } while (0) + return 0; +} #ifdef __WIN__ @@ -992,138 +1013,91 @@ static uint my_get_system_windows_directory(char *buffer, uint 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() +static const char *my_get_module_parent(char *buf, size_t size) { - bzero((char *) default_directories, sizeof(default_directories)); - - 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); + if (!GetModuleFileName(NULL, buf, size)) + return NULL; - ADD_DIRECTORY("C:/"); - - if (GetModuleFileName(NULL, config_dir, sizeof(config_dir))) + char *last= NULL, *end= strend(buf); + /* + 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 > buf; end--) { - char *last= NULL, *end= strend(config_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 - a drive. - */ - for ( ; end > config_dir; 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 */ - end[1]= 0; - } - else - { - /* No parent directory (strange). Use current dir + '\' */ - last[1]= 0; - } - break; - } - last= end; + /* Keep the last '\' as this works both with D:\ and a directory */ + end[1]= 0; + break; } + 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)); - ADD_DIRECTORY("sys:/etc/"); - ADD_COMMON_DIRECTORIES(); -} + const char **dirs; + char *env; + 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 - 1. /etc/ - 2. getenv(ETC) - 3. getenv(DEFAULT_HOME_ENV) - 4. --defaults-extra-file=<path> (run-time option) -*/ + if (GetWindowsDirectory(fname_buffer, sizeof(fname_buffer))) + errors += add_directory(alloc, fname_buffer, dirs); -static void init_default_directories_os2() -{ - const char *env; + errors += add_directory(alloc, "C:/", dirs); - bzero((char *) default_directories, sizeof(default_directories)); - ADD_DIRECTORY("/etc/"); - if ((env= getenv("ETC"))) - ADD_DIRECTORY(env); - ADD_COMMON_DIRECTORIES(); -} + if (my_get_module_parent(fname_buffer, sizeof(fname_buffer)) != NULL) + errors += add_directory(alloc, fname_buffer, dirs); + } -static void (*init_default_directories)()= init_default_directories_os2; +#elif defined(__NETWARE__) -#else + errors += add_directory(alloc, "sys:/etc/", dirs); -/** - Initialize default directories for Unix +#else - @details - 1. /etc/ - 2. --sysconfdir=<path> (compile-time option) - 3. getenv(DEFAULT_HOME_ENV) - 4. --defaults-extra-file=<path> (run-time option) - 5. "~/" -*/ + errors += add_directory(alloc, "/etc/", dirs); -static void init_default_directories_unix() -{ - bzero((char *) default_directories, sizeof(default_directories)); - ADD_DIRECTORY("/etc/"); -#ifdef DEFAULT_SYSCONFDIR +#if defined(__EMX__) || defined(OS2) + if ((env= getenv("ETC"))) + errors += add_directory(alloc, env, dirs); +#elif defined(DEFAULT_SYSCONFDIR) if (DEFAULT_SYSCONFDIR != "") - ADD_DIRECTORY(DEFAULT_SYSCONFDIR); + errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs); +#endif /* __EMX__ || __OS2__ */ + #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 + + return (errors > 0 ? NULL : dirs); +} |