39 #include "../mysys/mysys_priv.h"
40 #include "my_default.h"
41 #include "my_default_priv.h"
51 #ifdef HAVE_PSI_INTERFACE
52 extern PSI_file_key key_file_cnf;
82 static const char *args_separator=
"----args-separator----";
83 inline static void set_args_separator(
char** arg)
85 DBUG_ASSERT(my_getopt_use_args_separator);
86 *arg= (
char*)args_separator;
95 my_bool my_getopt_use_args_separator= FALSE;
96 my_bool my_getopt_is_args_separator(
const char* arg)
98 return (arg == args_separator);
100 const char *my_defaults_file=0;
101 const char *my_defaults_group_suffix=0;
102 const char *my_defaults_extra_file=0;
104 static const char *my_login_path= 0;
106 static char my_defaults_file_buffer[FN_REFLEN];
107 static char my_defaults_extra_file_buffer[FN_REFLEN];
109 static char my_login_file[FN_REFLEN];
110 static char my_key[LOGIN_KEY_LEN];
112 static my_bool defaults_already_read= FALSE;
115 static my_bool found_no_defaults= FALSE;
118 static my_bool is_login_file= FALSE;
122 #define MAX_DEFAULT_DIRS 6
123 #define DEFAULT_DIRS_SIZE (MAX_DEFAULT_DIRS + 1)
124 static const char **default_directories = NULL;
127 static const char *f_extensions[]= {
".ini",
".cnf", 0 };
128 #define NEWLINE "\r\n"
130 static const char *f_extensions[]= {
".cnf", 0 };
134 static int handle_default_option(
void *in_ctx,
const char *group_name,
151 static int search_default_file(Process_option_func func,
void *func_ctx,
152 const char *dir,
const char *config_file);
153 static int search_default_file_with_ext(Process_option_func func,
155 const char *dir,
const char *ext,
156 const char *config_file,
int recursion_level);
158 static int check_file_permissions(
const char *file_name);
187 static const char **init_default_directories(
MEM_ROOT *alloc);
190 static char *remove_end_comment(
char *ptr);
204 fn_expand(
const char *filename,
char *result_buf)
207 const int flags= MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_RELATIVE_PATH;
208 DBUG_ENTER(
"fn_expand");
209 DBUG_PRINT(
"enter", (
"filename: %s, result_buf: 0x%lx",
210 filename, (
unsigned long) result_buf));
211 if (my_getwd(dir,
sizeof(dir), MYF(0)))
213 DBUG_PRINT(
"debug", (
"dir: %s", dir));
214 if (fn_format(result_buf, filename, dir,
"", flags) == NULL)
216 DBUG_PRINT(
"return", (
"result: %s", result_buf));
256 int my_search_option_files(
const char *conf_file,
int *argc,
char ***argv,
257 uint *args_used, Process_option_func func,
258 void *func_ctx,
const char **default_directories)
260 const char **dirs, *forced_default_file, *forced_extra_defaults;
262 DBUG_ENTER(
"my_search_option_files");
268 *args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
269 (
char **) &forced_default_file,
270 (
char **) &forced_extra_defaults,
271 (
char **) &my_defaults_group_suffix,
272 (
char **) &my_login_path);
274 if (! my_defaults_group_suffix)
275 my_defaults_group_suffix= getenv(STRINGIFY_ARG(DEFAULT_GROUP_SUFFIX_ENV));
277 if (forced_extra_defaults && !defaults_already_read)
279 int error= fn_expand(forced_extra_defaults,
280 my_defaults_extra_file_buffer);
284 my_defaults_extra_file= my_defaults_extra_file_buffer;
287 if (forced_default_file && !defaults_already_read)
289 int error= fn_expand(forced_default_file, my_defaults_file_buffer);
292 my_defaults_file= my_defaults_file_buffer;
295 defaults_already_read= TRUE;
302 if (my_defaults_group_suffix && func == handle_default_option)
306 const char **extra_groups;
307 const size_t instance_len= strlen(my_defaults_group_suffix);
313 (
const char**)alloc_root(ctx->alloc,
314 (2*group->count+1)*
sizeof(
char*))))
317 for (i= 0; i < group->count; i++)
320 extra_groups[
i]= group->type_names[
i];
322 len= strlen(extra_groups[i]);
323 if (!(ptr= (
char *) alloc_root(ctx->alloc,
324 (uint) (len + instance_len + 1))))
327 extra_groups[i+group->count]= ptr;
330 memcpy(ptr, extra_groups[i], len);
331 memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
335 group->type_names= extra_groups;
336 group->type_names[group->count]= 0;
339 else if (my_login_path && func == handle_default_option)
344 const char **extra_groups;
345 size_t instance_len= 0;
350 if (!(extra_groups= (
const char**)alloc_root(ctx->alloc,
355 for (i= 0; i < group->count; i++)
357 extra_groups[
i]= group->type_names[
i];
360 extra_groups[
i]= my_login_path;
362 if (my_defaults_group_suffix && func == handle_default_option)
364 instance_len= strlen(my_defaults_group_suffix);
365 len= strlen(extra_groups[i]);
367 if (!(ptr= (
char *) alloc_root(ctx->alloc,
368 (uint) (len + instance_len + 1))))
371 extra_groups[i + 1]= ptr;
374 memcpy(ptr, extra_groups[i], len);
375 memcpy(ptr+len, my_defaults_group_suffix, instance_len + 1);
380 group->type_names= extra_groups;
381 group->type_names[group->count]= 0;
385 if (dirname_length(conf_file))
387 if ((error= search_default_file(func, func_ctx, NullS, conf_file)) < 0)
391 else if (my_defaults_file)
393 if ((error= search_default_file_with_ext(func, func_ctx,
"",
"",
394 my_defaults_file, 0)) < 0)
398 fprintf(stderr,
"Could not open required defaults file: %s\n",
403 else if (! found_no_defaults)
405 for (dirs= default_directories ; *dirs; dirs++)
409 if (search_default_file(func, func_ctx, *dirs, conf_file) < 0)
412 else if (my_defaults_extra_file)
414 if ((error= search_default_file_with_ext(func, func_ctx,
"",
"",
415 my_defaults_extra_file, 0)) < 0)
419 fprintf(stderr,
"Could not open required defaults file: %s\n",
420 my_defaults_extra_file);
430 fprintf(stderr,
"Fatal error in defaults handling. Program aborted\n");
458 static int handle_default_option(
void *in_ctx,
const char *group_name,
467 if (find_type((
char *)group_name, ctx->group, FIND_TYPE_NO_PREFIX))
469 if (!(tmp= (
char *) alloc_root(ctx->alloc, strlen(option) + 1)))
471 if (insert_dynamic(ctx->args, &tmp))
500 int get_defaults_options(
int argc,
char **argv,
502 char **extra_defaults,
506 int org_argc= argc, prev_argc= 0, default_option_count= 0;
507 *defaults= *extra_defaults= *group_suffix= *login_path= 0;
509 while (argc >= 2 && argc != prev_argc)
515 if (is_prefix(*argv,
"--no-defaults") && ! default_option_count)
518 default_option_count ++;
521 if (!*defaults && is_prefix(*argv,
"--defaults-file=") && ! found_no_defaults)
523 *defaults= *argv +
sizeof(
"--defaults-file=")-1;
525 default_option_count ++;
528 if (!*extra_defaults && is_prefix(*argv,
"--defaults-extra-file=")
529 && ! found_no_defaults)
531 *extra_defaults= *argv +
sizeof(
"--defaults-extra-file=")-1;
533 default_option_count ++;
536 if (!*group_suffix && is_prefix(*argv,
"--defaults-group-suffix="))
538 *group_suffix= *argv +
sizeof(
"--defaults-group-suffix=")-1;
540 default_option_count ++;
543 if (!*login_path && is_prefix(*argv,
"--login-path="))
545 *login_path= *argv +
sizeof(
"--login-path=")-1;
547 default_option_count ++;
551 return org_argc - argc;
575 int load_defaults(
const char *conf_file,
const char **groups,
576 int *argc,
char ***argv)
578 return my_load_defaults(conf_file, groups, argc, argv, &default_directories);
619 int my_load_defaults(
const char *conf_file,
const char **groups,
620 int *argc,
char ***argv,
const char ***default_directories)
624 my_bool found_print_defaults= 0;
631 uint args_sep= my_getopt_use_args_separator ? 1 : 0;
632 DBUG_ENTER(
"load_defaults");
634 init_alloc_root(&alloc,512,0);
635 if ((dirs= init_default_directories(&alloc)) == NULL)
641 if (*argc >= 2 && !strcmp(argv[0][1],
"--no-defaults"))
642 found_no_defaults= TRUE;
645 group.name=
"defaults";
646 group.type_names= groups;
648 for (; *groups ; groups++)
651 if (my_init_dynamic_array(&args,
sizeof(
char*),*argc, 32))
658 if ((error= my_search_option_files(conf_file, argc, argv,
659 &args_used, handle_default_option,
660 (
void *) &ctx, dirs)))
662 free_root(&alloc,MYF(0));
668 if (my_default_get_login_file(my_login_file,
sizeof(my_login_file)) &&
669 (error= my_search_option_files(my_login_file,argc, argv, &args_used,
670 handle_default_option, (
void *) &ctx,
673 free_root(&alloc,MYF(0));
676 is_login_file= FALSE;
682 if (!(ptr=(
char*) alloc_root(&alloc,
sizeof(alloc)+
683 (args.elements + *argc + 1 + args_sep) *
sizeof(
char*))))
685 res= (
char**) (ptr+
sizeof(alloc));
689 memcpy((uchar*) (res+1), args.buffer, args.elements*
sizeof(
char*));
698 if (*argc >= 2 && !strcmp(argv[0][1],
"--print-defaults"))
700 found_print_defaults=1;
704 if (my_getopt_use_args_separator)
708 set_args_separator(&res[args.elements+1]);
712 memcpy((uchar*) (res+1+args.elements+args_sep), (
char*) ((*argv)+1),
713 (*argc-1)*
sizeof(
char*));
714 res[args.elements+ *argc+args_sep]=0;
716 (*argc)+=args.elements+args_sep;
719 delete_dynamic(&args);
721 if (default_directories)
722 *default_directories= dirs;
724 if (found_no_defaults)
727 if (found_print_defaults)
730 printf(
"%s would have been started with the following arguments:\n",
732 for (i=1 ; i < *argc ; i++)
733 if (!my_getopt_is_args_separator((*argv)[i]))
734 printf(
"%s ", (*argv)[i]);
742 fprintf(stderr,
"Fatal error in defaults handling. Program aborted\n");
748 void free_defaults(
char **argv)
751 memcpy(&ptr, ((
char *) argv) -
sizeof(ptr),
sizeof(ptr));
752 free_root(&ptr,MYF(0));
756 static int search_default_file(Process_option_func opt_handler,
759 const char *config_file)
762 const char *empty_list[]= {
"", 0 };
763 my_bool have_ext= fn_ext(config_file)[0] != 0;
764 const char **exts_to_use= have_ext ? empty_list : f_extensions;
766 for (ext= (
char**) exts_to_use; *ext; ext++)
769 if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
771 config_file, 0)) < 0)
793 static char *get_argument(
const char *keyword,
size_t kwlen,
794 char *ptr,
char *
name, uint line)
800 for (ptr+= kwlen - 1;
801 my_isspace(&my_charset_latin1, ptr[0]);
810 for (end= ptr + strlen(ptr) - 1;
811 my_isspace(&my_charset_latin1, *(end - 1));
820 "error: Wrong '!%s' directive in config file: %s at line %d\n",
821 keyword, name, line);
850 static int search_default_file_with_ext(Process_option_func opt_handler,
854 const char *config_file,
857 char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
858 char *value, option[4096+2], tmp[FN_REFLEN];
859 static const char includedir_keyword[]=
"includedir";
860 static const char include_keyword[]=
"include";
861 const int max_recursion_level= 10;
864 my_bool found_group=0;
869 if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
873 end=convert_dirname(name, dir, NullS);
874 if (dir[0] == FN_HOMELIB)
876 strxmov(end,config_file,ext,NullS);
880 strmov(name,config_file);
882 fn_format(name,name,
"",
"",4);
884 if ((rc= check_file_permissions(name)) < 2)
899 while (mysql_file_getline(buff,
sizeof(buff) - 1, fp))
903 for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++)
906 if (*ptr ==
'#' || *ptr ==
';' || !*ptr)
912 if (recursion_level >= max_recursion_level)
914 for (end= ptr + strlen(ptr) - 1;
915 my_isspace(&my_charset_latin1, *(end - 1));
920 "Warning: skipping '%s' directive as maximum include"
921 "recursion level was reached in file %s at line %d\n",
927 for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++)
930 if ((!strncmp(ptr, includedir_keyword,
931 sizeof(includedir_keyword) - 1)) &&
932 my_isspace(&my_charset_latin1, ptr[
sizeof(includedir_keyword) - 1]))
934 if (!(ptr= get_argument(includedir_keyword,
935 sizeof(includedir_keyword),
939 if (!(search_dir= my_dir(ptr, MYF(MY_WME))))
942 for (i= 0; i < (uint) search_dir->number_off_files; i++)
944 search_file= search_dir->dir_entry +
i;
945 ext= fn_ext(search_file->name);
948 for (tmp_ext= (
char**) f_extensions; *tmp_ext; tmp_ext++)
950 if (!strcmp(ext, *tmp_ext))
956 fn_format(tmp, search_file->name, ptr,
"",
957 MY_UNPACK_FILENAME | MY_SAFE_PATH);
959 search_default_file_with_ext(opt_handler, handler_ctx,
"",
"", tmp,
960 recursion_level + 1);
964 my_dirend(search_dir);
966 else if ((!strncmp(ptr, include_keyword,
sizeof(include_keyword) - 1)) &&
967 my_isspace(&my_charset_latin1, ptr[
sizeof(include_keyword)-1]))
969 if (!(ptr= get_argument(include_keyword,
970 sizeof(include_keyword), ptr,
974 search_default_file_with_ext(opt_handler, handler_ctx,
"",
"", ptr,
975 recursion_level + 1);
984 if (!(end=(
char *) strchr(++ptr,
']')))
987 "error: Wrong group definition in config file: %s at line %d\n",
992 for ( ; my_isspace(&my_charset_latin1, end[-1]); end --)
997 strmake(curr_gr, ptr, MY_MIN((
size_t) (end-ptr)+1,
sizeof(curr_gr)-1));
1000 opt_handler(handler_ctx, curr_gr, NULL);
1007 "error: Found option without preceding group in config file: %s at line: %d\n",
1013 end= remove_end_comment(ptr);
1014 if ((value= strchr(ptr,
'=')))
1016 for ( ; my_isspace(&my_charset_latin1, end[-1]) ; end--)
1021 strmake(strmov(option,
"--"),ptr, (
size_t) (end-ptr));
1022 if (opt_handler(handler_ctx, curr_gr, option))
1029 for (value++ ; my_isspace(&my_charset_latin1, *value); value ++)
1032 value_end=strend(value);
1037 for ( ; my_isspace(&my_charset_latin1, value_end[-1]); value_end --)
1040 if (value_end < value)
1044 if ((*value ==
'\"' || *value ==
'\'') &&
1045 (value + 1 < value_end ) &&
1046 *value == value_end[-1] )
1051 ptr=strnmov(strmov(option,
"--"),ptr,(
size_t) (end-ptr));
1054 for ( ; value != value_end; value++)
1056 if (*value ==
'\\' && value != value_end-1)
1093 if (opt_handler(handler_ctx, curr_gr, option))
1106 static char *remove_end_comment(
char *ptr)
1113 if ((*ptr ==
'\'' || *ptr ==
'\"') && !escape)
1117 else if (quote == *ptr)
1121 if (!quote && *ptr ==
'#')
1126 escape= (quote && *ptr ==
'\\' && !escape);
1147 uchar cipher[4096], len_buf[MAX_CIPHER_STORE_LEN];
1148 int length= 0, cipher_len= 0;
1157 MYF(MY_WME)) != LOGIN_KEY_LEN)
1162 MYF(MY_WME)) == MAX_CIPHER_STORE_LEN)
1164 cipher_len= sint4korr(len_buf);
1165 if (cipher_len > size)
1172 if ((length= my_aes_decrypt((
const char *) cipher, cipher_len, str,
1173 my_key, LOGIN_KEY_LEN)) < 0)
1191 void my_print_default_files(
const char *conf_file)
1193 const char *empty_list[]= {
"", 0 };
1194 my_bool have_ext= fn_ext(conf_file)[0] != 0;
1195 const char **exts_to_use= have_ext ? empty_list : f_extensions;
1196 char name[FN_REFLEN], **ext;
1198 puts(
"\nDefault options are read from the following files in the given order:");
1200 if (dirname_length(conf_file))
1201 fputs(conf_file,stdout);
1206 init_alloc_root(&alloc,512,0);
1208 if ((dirs= init_default_directories(&alloc)) == NULL)
1210 fputs(
"Internal error initializing default directories list", stdout);
1214 for ( ; *dirs; dirs++)
1216 for (ext= (
char**) exts_to_use; *ext; ext++)
1222 else if (my_defaults_extra_file)
1223 pos= my_defaults_extra_file;
1226 end= convert_dirname(name, pos, NullS);
1227 if (name[0] == FN_HOMELIB)
1230 if (my_defaults_extra_file == pos)
1231 end[(strlen(end)-1)] =
' ';
1233 strxmov(end, conf_file, *ext ,
" ", NullS);
1234 fputs(name, stdout);
1239 free_root(&alloc, MYF(0));
1244 void print_defaults(
const char *conf_file,
const char **groups)
1246 const char **groups_save= groups;
1247 my_print_default_files(conf_file);
1249 fputs(
"The following groups are read:",stdout);
1250 for ( ; *groups ; groups++)
1253 fputs(*groups,stdout);
1256 if (my_defaults_group_suffix)
1258 groups= groups_save;
1259 for ( ; *groups ; groups++)
1262 fputs(*groups,stdout);
1263 fputs(my_defaults_group_suffix,stdout);
1266 puts(
"\nThe following options may be given as the first argument:\n\
1267 --print-defaults Print the program argument list and exit.\n\
1268 --no-defaults Don't read default options from any option file,\n\
1269 except for login file.\n\
1270 --defaults-file=# Only read default options from the given file #.\n\
1271 --defaults-extra-file=# Read this file after the global files are read.\n\
1272 --defaults-group-suffix=#\n\
1273 Also read groups with concat(group, suffix)\n\
1274 --login-path=# Read this path from the login file.");
1278 static int add_directory(
MEM_ROOT *alloc,
const char *dir,
const char **dirs)
1280 char buf[FN_REFLEN];
1283 my_bool err __attribute__((unused));
1285 len= normalize_dirname(buf, dir);
1286 if (!(p= strmake_root(alloc, buf, len)))
1289 err= array_append_string_unique(p, dirs, DEFAULT_DIRS_SIZE);
1290 DBUG_ASSERT(err == FALSE);
1304 typedef UINT (WINAPI *GET_SYSTEM_WINDOWS_DIRECTORY)(LPSTR, UINT);
1306 static size_t my_get_system_windows_directory(
char *buffer,
size_t size)
1309 GET_SYSTEM_WINDOWS_DIRECTORY
1310 func_ptr= (GET_SYSTEM_WINDOWS_DIRECTORY)
1311 GetProcAddress(GetModuleHandle(
"kernel32.dll"),
1312 "GetSystemWindowsDirectoryA");
1315 return func_ptr(buffer, (uint) size);
1322 count= GetSystemDirectory(buffer, (uint) size);
1323 if (count > 8 && stricmp(buffer+(count-8),
"\\System32") == 0)
1326 buffer[count] =
'\0';
1332 static const char *my_get_module_parent(
char *buf,
size_t size)
1336 if (!GetModuleFileName(NULL, buf, (DWORD) size))
1345 for ( ; end >
buf; end--)
1347 if (*end == FN_LIBCHAR)
1364 static const char **init_default_directories(
MEM_ROOT *alloc)
1370 dirs= (
const char **)alloc_root(alloc, DEFAULT_DIRS_SIZE *
sizeof(
char *));
1373 memset(dirs, 0, DEFAULT_DIRS_SIZE *
sizeof(
char *));
1378 char fname_buffer[FN_REFLEN];
1379 if (my_get_system_windows_directory(fname_buffer,
sizeof(fname_buffer)))
1380 errors += add_directory(alloc, fname_buffer, dirs);
1382 if (GetWindowsDirectory(fname_buffer,
sizeof(fname_buffer)))
1383 errors += add_directory(alloc, fname_buffer, dirs);
1385 errors += add_directory(alloc,
"C:/", dirs);
1387 if (my_get_module_parent(fname_buffer,
sizeof(fname_buffer)) != NULL)
1388 errors += add_directory(alloc, fname_buffer, dirs);
1393 errors += add_directory(alloc,
"/etc/", dirs);
1394 errors += add_directory(alloc,
"/etc/mysql/", dirs);
1396 #if defined(DEFAULT_SYSCONFDIR)
1397 if (DEFAULT_SYSCONFDIR[0])
1398 errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs);
1403 if ((env= getenv(
"MYSQL_HOME")))
1404 errors += add_directory(alloc, env, dirs);
1407 errors += add_directory(alloc,
"", dirs);
1409 #if !defined(__WIN__)
1410 errors += add_directory(alloc,
"~/", dirs);
1413 return (errors > 0 ? NULL : dirs);
1426 int my_default_get_login_file(
char *file_name,
size_t file_name_size)
1430 if (getenv(
"MYSQL_TEST_LOGIN_FILE"))
1431 rc= my_snprintf(file_name, file_name_size,
"%s",
1432 getenv(
"MYSQL_TEST_LOGIN_FILE"));
1434 else if (getenv(
"APPDATA"))
1435 rc= my_snprintf(file_name, file_name_size,
"%s\\MySQL\\.mylogin.cnf",
1438 else if (getenv(
"HOME"))
1439 rc= my_snprintf(file_name, file_name_size,
"%s/.mylogin.cnf",
1444 memset(file_name, 0, file_name_size);
1463 static int check_file_permissions(
const char *file_name)
1465 #if !defined(__WIN__)
1468 if (!my_stat(file_name,&stat_info,MYF(0)))
1474 if (is_login_file && (stat_info.st_mode & (S_IXUSR | S_IRWXG | S_IRWXO))
1475 && (stat_info.st_mode & S_IFMT) == S_IFREG)
1477 fprintf(stderr,
"Warning: %s should be readable/writable only by "
1478 "current user.\n", file_name);
1486 else if ((stat_info.st_mode & S_IWOTH) &&
1487 (stat_info.st_mode & S_IFMT) == S_IFREG)
1490 fprintf(stderr,
"Warning: World-writable config file '%s' is ignored\n",