From 707f42a6b988d94630f3e43dad410311f40ac4f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Nov 2007 15:23:50 -0700 Subject: Bug #20748: Configuration files should not be read more than once A user could not override system-wide settings in their ~/.my.cnf, because the DEFAULT_SYSCONFDIR was being searched last. Also, in some configurations (especially when the --sysconfdir compile-time option is set to /etc or /etc/mysql), the system-wide my.cnf file was read multiple times, causing confusion and potential problems. Rearrange default directories to conform to the manual and logic. Move --sysconfdir= (DEFAULT_SYSCONFDIR) from the last default directory to the middle of the list. $HOME/.my.cnf should be last, so the user is able to override the system-wide settings. Change init_default_directories() to remove duplicates from the list. include/my_sys.h: Add array_append_string_unique(), from mf_arr_appstr.c libmysql/Makefile.shared: Add new mf_arr_appstr.lo object mysys/CMakeLists.txt: Add new mf_arr_appstr.c source. mysys/Makefile.am: Add new mf_arr_appstr.c source. mysys/default.c: Change order in which defaults files are added to default_directories, in order to conform to the manual (and to common sense). This fixes a particularly bad problem on Unix, where ~/.my.cnf was read before /usr/local/etc/my.cnf. Also, don't add duplicate entries; move the existing entry to the end of the list instead. Here is a comparison of the order of defaults files, BEFORE and AFTER this patch. On Windows: BEFORE: C:\, GetWindowsDirectory(), GetSystemWindowsDirectory(), $MYSQL_HOME, defaults-extra-file, INSTALLDIR AFTER: GetSystemWindowsDirectory(), GetWindowsDirectory(), C:\, INSTALLDIR, $MYSQL_HOME, defaults-extra-file GetSystemWindowsDirectory() is moved before GetWindowsDirectory() because the former is shared by all Terminal Services users, while the latter is private for each user. On Netware (no change): BEFORE: sys:/etc/, $MYSQL_HOME, defaults-extra-file AFTER: sys:/etc, $MYSQL_HOME, defaults-extra-file On OS/2: BEFORE: $ETC, /etc, $MYSQL_HOME, defaults-extra-file AFTER: /etc, $ETC, $MYSQL_HOME, defaults-extra-file On everything else (general Unix): BEFORE: /etc, $MYSQL_HOME, defaults-extra-file, ~/, --sysconfdir AFTER: /etc/, --sysconfdir, $MYSQL_HOME, defaults-extra-file, ~/ The BEFORE code added --sysconfdir on all systems, but only the Unix build system actually defined a value for it. mysys/mf_arr_appstr.c: BitKeeper file /home/tsmith/m/bk/build/50-b20748/mysys/mf_arr_appstr.c --- mysys/default.c | 192 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 129 insertions(+), 63 deletions(-) (limited to 'mysys/default.c') diff --git a/mysys/default.c b/mysys/default.c index aff38b6af0b..74d016ce53c 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -47,7 +47,7 @@ char *my_defaults_extra_file=0; /* Which directories are searched for options (and in which order) */ -#define MAX_DEFAULT_DIRS 7 +#define MAX_DEFAULT_DIRS 6 const char *default_directories[MAX_DEFAULT_DIRS + 1]; #ifdef __WIN__ @@ -83,7 +83,22 @@ static int search_default_file_with_ext(Process_option_func func, void *func_ctx, const char *dir, const char *ext, const char *config_file, int recursion_level); -static void init_default_directories(); + + + +/** + Create the list of default directories. + + @details + 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 +*/ + +static void (*init_default_directories)(); + static char *remove_end_comment(char *ptr); @@ -913,6 +928,25 @@ void print_defaults(const char *conf_file, const char **groups) #include +#define ADD_DIRECTORY(DIR) \ + do { \ + my_bool rc= \ + array_append_string_unique((DIR), default_directories, \ + array_elements(default_directories)); \ + DBUG_ASSERT(rc == FALSE); /* Success */ \ + } while (0) + + +#define ADD_COMMON_DIRECTORIES() \ + do { \ + char *env; \ + if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) \ + ADD_DIRECTORY(env); \ + /* Placeholder for --defaults-extra-file= */ \ + ADD_DIRECTORY(""); \ + } while (0) + + #ifdef __WIN__ /* This wrapper for GetSystemWindowsDirectory() will dynamically bind to the @@ -947,73 +981,33 @@ static uint my_get_system_windows_directory(char *buffer, uint size) } return count; } -#endif -/* - Create the list of default directories. +/** + Initialize default directories for Microsoft Windows - On Microsoft Windows, this is: - 1. C:/ + @details + 1. GetSystemWindowsDirectory() 2. GetWindowsDirectory() - 3. GetSystemWindowsDirectory() - 4. getenv(DEFAULT_HOME_ENV) - 5. Directory above where the executable is located - 6. "" - 7. --sysconfdir= - - On Novell NetWare, this is: - 1. sys:/etc/ - 2. getenv(DEFAULT_HOME_ENV) - 3. "" - 4. --sysconfdir= - - On OS/2, this is: - 1. getenv(ETC) - 2. /etc/ - 3. getenv(DEFAULT_HOME_ENV) - 4. "" - 5. "~/" - 6. --sysconfdir= - - Everywhere else, this is: - 1. /etc/ - 2. getenv(DEFAULT_HOME_ENV) - 3. "" - 4. "~/" - 5. --sysconfdir= - - */ + 3. C:/ + 4. Directory above where the executable is located + 5. getenv(DEFAULT_HOME_ENV) + 6. --defaults-extra-file= (run-time option) +*/ -static void init_default_directories() +static void init_default_directories_win() { - const char *env, **ptr= default_directories; + bzero(default_directories, sizeof(default_directories)); -#ifdef __WIN__ - *ptr++= "C:/"; + 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))) - *ptr++= (char*)&system_dir; - if (my_get_system_windows_directory(shared_system_dir, - sizeof(shared_system_dir)) && - strcmp(system_dir, shared_system_dir)) - *ptr++= (char *)&shared_system_dir; + ADD_DIRECTORY(&system_dir); + + ADD_DIRECTORY("C:/"); -#elif defined(__NETWARE__) - *ptr++= "sys:/etc/"; -#else -#if defined(__EMX__) || defined(OS2) - if ((env= getenv("ETC"))) - *ptr++= env; -#endif - *ptr++= "/etc/"; -#endif - if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) - *ptr++= env; - *ptr++= ""; /* Place for defaults_extra_file */ -#if !defined(__WIN__) && !defined(__NETWARE__) - *ptr++= "~/";; -#elif defined(__WIN__) if (GetModuleFileName(NULL, config_dir, sizeof(config_dir))) { char *last= NULL, *end= strend(config_dir); @@ -1043,12 +1037,84 @@ static void init_default_directories() last= end; } } - *ptr++= (char *)&config_dir; + ADD_DIRECTORY(&config_dir); } -#endif + + ADD_COMMON_DIRECTORIES(); +} + +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= (run-time option) +*/ + +static void init_default_directories_netware() +{ + bzero(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= (run-time option) +*/ + +static void init_default_directories_os2() +{ + const char *env; + + bzero(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 + +/** + Initialize default directories for Unix + + @details + 1. /etc/ + 2. --sysconfdir= (compile-time option) + 3. getenv(DEFAULT_HOME_ENV) + 4. --defaults-extra-file= (run-time option) + 5. "~/" +*/ + +static void init_default_directories_unix() +{ + bzero(default_directories, sizeof(default_directories)); + ADD_DIRECTORY("/etc/"); #ifdef DEFAULT_SYSCONFDIR if (DEFAULT_SYSCONFDIR != "") - *ptr++= DEFAULT_SYSCONFDIR; + ADD_DIRECTORY(DEFAULT_SYSCONFDIR); #endif - *ptr= 0; /* end marker */ + ADD_COMMON_DIRECTORIES(); + ADD_DIRECTORY("~/"); } + +static void (*init_default_directories)()= init_default_directories_unix; + +#endif -- cgit v1.2.1