1 /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
2 Copyright (c) 2011, 2018, MariaDB Corporation
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
16
17 /****************************************************************************
18 Add all options from files named "group".cnf from the default_directories
19 before the command line arguments.
20 On Windows defaults will also search in the Windows directory for a file
21 called 'group'.ini
22 As long as the program uses the last argument for conflicting
23 options one only have to add a call to "load_defaults" to enable
24 use of default values.
25 pre- and end 'blank space' are removed from options and values. The
26 following escape sequences are recognized in values: \b \t \n \r \\
27
28 The following arguments are handled automatically; If used, they must be
29 first argument on the command line!
30 --no-defaults ; no options are read.
31 --defaults-file=full-path-to-default-file ; Only this file will be read.
32 --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
33 --defaults-group-suffix ; Also read groups with concat(group, suffix)
34 --print-defaults ; Print the modified command line and exit
35 ****************************************************************************/
36
37 #include "mysys_priv.h"
38 #include <my_default.h>
39 #include <m_string.h>
40 #include <m_ctype.h>
41 #include <my_dir.h>
42 #ifdef __WIN__
43 #include <winbase.h>
44 #endif
45
46 /**
47 arguments separator
48
49 load_defaults() loads arguments from config file and put them
50 before the arguments from command line, this separator is used to
51 separate the arguments loaded from config file and arguments user
52 provided on command line.
53
54 Options with value loaded from config file are always in the form
55 '--option=value', while for command line options, the value can be
56 given as the next argument. Thus we used a separator so that
57 handle_options() can distinguish them.
58
59 Note: any other places that does not need to distinguish them
60 should skip the separator.
61
62 The content of arguments separator does not matter, one should only
63 check the pointer, use "----args-separator----" here to ease debug
64 if someone misused it.
65
66 The args separator will only be added when
67 my_getopt_use_args_seprator is set to TRUE before calling
68 load_defaults();
69
70 See BUG#25192
71 */
72 static const char *args_separator= "----args-separator----";
73 inline static void set_args_separator(char** arg)
74 {
75 DBUG_ASSERT(my_getopt_use_args_separator);
76 *arg= (char*)args_separator;
77 }
78 my_bool my_getopt_use_args_separator= FALSE;
79 my_bool my_getopt_is_args_separator(const char* arg)
80 {
81 return (arg == args_separator);
82 }
my_cpu_init(void)83 const char *my_defaults_file=0;
84 const char *my_defaults_group_suffix=0;
85 const char *my_defaults_extra_file=0;
86
87 static char my_defaults_file_buffer[FN_REFLEN];
88 static char my_defaults_extra_file_buffer[FN_REFLEN];
89
90 static my_bool defaults_already_read= FALSE;
91
92 /* Which directories are searched for options (and in which order) */
93
94 #define MAX_DEFAULT_DIRS 7
95 #define DEFAULT_DIRS_SIZE (MAX_DEFAULT_DIRS + 1) /* Terminate with NULL */
96 static const char **default_directories = NULL;
97
98 #ifdef __WIN__
99 static const char *f_extensions[]= { ".ini", ".cnf", 0 };
100 #define NEWLINE "\r\n"
101 #else
102 static const char *f_extensions[]= { ".cnf", 0 };
103 #define NEWLINE "\n"
104 #endif
105
106 static int handle_default_option(void *, const char *, const char *);
107
108 /*
109 This structure defines the context that we pass to callback
110 function 'handle_default_option' used in search_default_file
111 to process each option. This context is used if search_default_file
112 was called from load_defaults.
113 */
114
115 struct handle_option_ctx
116 {
117 MEM_ROOT *alloc;
118 DYNAMIC_ARRAY *args;
119 TYPELIB *group;
120 };
121
122 static int search_default_file(Process_option_func func, void *func_ctx,
123 const char *dir, const char *config_file);
124 static int search_default_file_with_ext(Process_option_func func,
125 void *func_ctx,
126 const char *dir, const char *ext,
127 const char *config_file, int recursion_level);
128
129
130 /**
131 Create the list of default directories.
132
133 @param alloc MEM_ROOT where the list of directories is stored
134
135 @details
136 The directories searched, in order, are:
137 - Windows: GetSystemWindowsDirectory()
138 - Windows: GetWindowsDirectory()
139 - Windows: C:/
140 - Windows: Directory above where the executable is located
141 - Unix: /etc/ or the value of DEFAULT_SYSCONFDIR, if defined
142 - Unix: /etc/mysql/ unless DEFAULT_SYSCONFDIR is defined
143 - ALL: getenv("MYSQL_HOME")
144 - ALL: --defaults-extra-file=<path> (run-time option)
145 - Unix: ~/
146
147 On all systems, if a directory is already in the list, it will be moved
148 to the end of the list. This avoids reading defaults files multiple times,
149 while ensuring the correct precedence.
150
151 @retval NULL Failure (out of memory, probably)
152 @retval other Pointer to NULL-terminated array of default directories
153 */
154
155 static const char **init_default_directories(MEM_ROOT *alloc);
156
157
158 static char *remove_end_comment(char *ptr);
159
160
161 /*
162 Expand a file name so that the current working directory is added if
163 the name is relative.
164
165 RETURNS
166 0 All OK
167 2 Out of memory or path to long
168 3 Not able to get working directory
169 */
170
171 static int
172 fn_expand(const char *filename, char *result_buf)
173 {
174 char dir[FN_REFLEN];
175 const int flags= MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_RELATIVE_PATH;
176 DBUG_ENTER("fn_expand");
177 DBUG_PRINT("enter", ("filename: %s, result_buf: %p",
178 filename, result_buf));
179 if (my_getwd(dir, sizeof(dir), MYF(0)))
180 DBUG_RETURN(3);
181 DBUG_PRINT("debug", ("dir: %s", dir));
182 if (fn_format(result_buf, filename, dir, "", flags) == NULL)
183 DBUG_RETURN(2);
184 DBUG_PRINT("return", ("result: %s", result_buf));
185 DBUG_RETURN(0);
186 }
187
188 /*
189 Process config files in default directories.
190
191 SYNOPSIS
192 my_search_option_files()
193 conf_file Basename for configuration file to search for.
194 If this is a path, then only this file is read.
195 argc Pointer to argc of original program
196 argv Pointer to argv of original program
197 args_used Pointer to variable for storing the number of
198 arguments used.
199 func Pointer to the function to process options
200 func_ctx It's context. Usually it is the structure to
201 store additional options.
202 DESCRIPTION
203 Process the default options from argc & argv
204 Read through each found config file looks and calls 'func' to process
205 each option.
206
207 NOTES
208 --defaults-group-suffix is only processed if we are called from
209 load_defaults().
210
211
212 RETURN
213 0 ok
214 1 given cinf_file doesn't exist
215 2 out of memory
216 3 Can't get current working directory
217
218 The global variable 'my_defaults_group_suffix' is updated with value for
219 --defaults_group_suffix
220 */
221
222 int my_search_option_files(const char *conf_file, int *argc, char ***argv,
223 uint *args_used, Process_option_func func,
224 void *func_ctx, const char **default_directories)
225 {
226 const char **dirs, *forced_default_file, *forced_extra_defaults;
227 int error= 0;
228 DBUG_ENTER("my_search_option_files");
229
230 /* Check if we want to force the use a specific default file */
231 *args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
232 (char **) &forced_default_file,
233 (char **) &forced_extra_defaults,
234 (char **) &my_defaults_group_suffix);
235
236 if (! my_defaults_group_suffix)
237 my_defaults_group_suffix= getenv("MYSQL_GROUP_SUFFIX");
238
239 if (forced_extra_defaults && !defaults_already_read)
240 {
241 int error= fn_expand(forced_extra_defaults, my_defaults_extra_file_buffer);
242 if (error)
243 DBUG_RETURN(error);
244 my_defaults_extra_file= my_defaults_extra_file_buffer;
245 }
246
247 if (forced_default_file && !defaults_already_read)
248 {
249 int error= fn_expand(forced_default_file, my_defaults_file_buffer);
250 if (error)
251 DBUG_RETURN(error);
252 my_defaults_file= my_defaults_file_buffer;
253 }
254
255 defaults_already_read= TRUE;
256
257 /*
258 We can only handle 'defaults-group-suffix' if we are called from
259 load_defaults() as otherwise we can't know the type of 'func_ctx'
260 */
261
262 if (my_defaults_group_suffix && func == handle_default_option)
263 {
264 /* Handle --defaults-group-suffix= */
265 uint i;
266 const char **extra_groups;
267 const size_t instance_len= strlen(my_defaults_group_suffix);
268 struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
269 char *ptr;
270 TYPELIB *group= ctx->group;
271
272 if (!(extra_groups=
273 (const char**)alloc_root(ctx->alloc,
274 (2*group->count+1)*sizeof(char*))))
275 DBUG_RETURN(2);
276
277 for (i= 0; i < group->count; i++)
278 {
279 size_t len;
280 extra_groups[i]= group->type_names[i]; /** copy group */
281
282 len= strlen(extra_groups[i]);
283 if (!(ptr= alloc_root(ctx->alloc, (uint) (len+instance_len+1))))
284 DBUG_RETURN(2);
285
286 extra_groups[i+group->count]= ptr;
287
288 /** Construct new group */
289 memcpy(ptr, extra_groups[i], len);
290 memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
291 }
292
293 group->count*= 2;
294 group->type_names= extra_groups;
295 group->type_names[group->count]= 0;
296 }
297
298 if (my_defaults_file)
299 {
300 if ((error= search_default_file_with_ext(func, func_ctx, "", "",
301 my_defaults_file, 0)) < 0)
302 goto err;
303 if (error > 0)
304 {
305 fprintf(stderr, "Could not open required defaults file: %s\n",
306 my_defaults_file);
307 goto err;
308 }
309 }
310 else if (dirname_length(conf_file))
311 {
312 if ((error= search_default_file(func, func_ctx, NullS, conf_file)) < 0)
313 goto err;
314 }
315 else
316 {
317 for (dirs= default_directories ; *dirs; dirs++)
318 {
319 if (**dirs)
320 {
321 if (search_default_file(func, func_ctx, *dirs, conf_file) < 0)
322 goto err;
323 }
324 else if (my_defaults_extra_file)
325 {
326 if ((error= search_default_file_with_ext(func, func_ctx, "", "",
327 my_defaults_extra_file, 0)) < 0)
328 goto err; /* Fatal error */
329 if (error > 0)
330 {
331 fprintf(stderr, "Could not open required defaults file: %s\n",
332 my_defaults_extra_file);
333 goto err;
334 }
335 }
336 }
337 }
338
339 DBUG_RETURN(0);
340
341 err:
342 fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
343 DBUG_RETURN(1);
344 }
345
346
347 /*
348 The option handler for load_defaults.
349
350 SYNOPSIS
351 handle_deault_option()
352 in_ctx Handler context. In this case it is a
353 handle_option_ctx structure.
354 group_name The name of the group the option belongs to.
355 option The very option to be processed. It is already
356 prepared to be used in argv (has -- prefix). If it
357 is NULL, we are handling a new group (section).
358
359 DESCRIPTION
360 This handler checks whether a group is one of the listed and adds an option
361 to the array if yes. Some other handler can record, for instance, all
362 groups and their options, not knowing in advance the names and amount of
363 groups.
364
365 RETURN
366 0 - ok
367 1 - error occurred
368 */
369
370 static int handle_default_option(void *in_ctx, const char *group_name,
371 const char *option)
372 {
373 char *tmp;
374 struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
375
376 if (!option)
377 return 0;
378
379 if (find_type((char *)group_name, ctx->group, FIND_TYPE_NO_PREFIX))
380 {
381 if (!(tmp= alloc_root(ctx->alloc, strlen(option) + 1)))
382 return 1;
383 if (insert_dynamic(ctx->args, (uchar*) &tmp))
384 return 1;
385 strmov(tmp, option);
386 }
387
388 return 0;
389 }
390
391
392 /*
393 Gets options from the command line
394
395 SYNOPSIS
396 get_defaults_options()
397 argc Pointer to argc of original program
398 argv Pointer to argv of original program
399 defaults --defaults-file option
400 extra_defaults --defaults-extra-file option
401
402 RETURN
403 # Number of arguments used from *argv
404 defaults and extra_defaults will be set to option of the appropriate
405 items of argv array, or to NULL if there are no such options
406 */
407
408 int get_defaults_options(int argc, char **argv,
409 char **defaults,
410 char **extra_defaults,
411 char **group_suffix)
412 {
413 int org_argc= argc;
414 *defaults= *extra_defaults= *group_suffix= 0;
415
416 while (argc >= 2)
417 {
418 /* Skip program name or previously handled argument */
419 argv++;
420 if (!*defaults && is_prefix(*argv,"--defaults-file="))
421 {
422 *defaults= *argv + sizeof("--defaults-file=")-1;
423 argc--;
424 continue;
425 }
426 if (!*extra_defaults && is_prefix(*argv,"--defaults-extra-file="))
427 {
428 *extra_defaults= *argv + sizeof("--defaults-extra-file=")-1;
429 argc--;
430 continue;
431 }
432 if (!*group_suffix && is_prefix(*argv, "--defaults-group-suffix="))
433 {
434 *group_suffix= *argv + sizeof("--defaults-group-suffix=")-1;
435 argc--;
436 continue;
437 }
438 break;
439 }
440 return org_argc - argc;
441 }
442
443 /*
444 Wrapper around my_load_defaults() for interface compatibility.
445
446 SYNOPSIS
447 load_defaults()
448 conf_file Basename for configuration file to search for.
449 If this is a path, then only this file is read.
450 groups Which [group] entrys to read.
451 Points to an null terminated array of pointers
452 argc Pointer to argc of original program
453 argv Pointer to argv of original program
454
455 NOTES
456
457 This function is NOT thread-safe as it uses a global pointer internally.
458 See also notes for my_load_defaults().
459
460 RETURN
461 0 ok
462 1 The given conf_file didn't exists
463 */
464 int load_defaults(const char *conf_file, const char **groups,
465 int *argc, char ***argv)
466 {
467 return my_load_defaults(conf_file, groups, argc, argv, &default_directories);
468 }
469
470 /*
471 Read options from configurations files
472
473 SYNOPSIS
474 my_load_defaults()
475 conf_file Basename for configuration file to search for.
476 If this is a path, then only this file is read.
477 groups Which [group] entrys to read.
478 Points to an null terminated array of pointers
479 argc Pointer to argc of original program
480 argv Pointer to argv of original program
481 default_directories Pointer to a location where a pointer to the list
482 of default directories will be stored
483
484 IMPLEMENTATION
485
486 Read options from configuration files and put them BEFORE the arguments
487 that are already in argc and argv. This way the calling program can
488 easily command line options override options in configuration files
489
490 NOTES
491 In case of fatal error, the function will print a warning and returns 2
492
493 To free used memory one should call free_defaults() with the argument
494 that was put in *argv
495
496 RETURN
497 - If successful, 0 is returned. If 'default_directories' is not NULL,
498 a pointer to the array of default directory paths is stored to a location
499 it points to. That stored value must be passed to my_search_option_files()
500 later.
501
502 - 1 is returned if the given conf_file didn't exist. In this case, the
503 value pointed to by default_directories is undefined.
504 */
505
506
507 int my_load_defaults(const char *conf_file, const char **groups,
508 int *argc, char ***argv, const char ***default_directories)
509 {
510 DYNAMIC_ARRAY args;
511 TYPELIB group;
512 my_bool found_print_defaults= 0;
513 uint args_used= 0;
514 int error= 0;
515 MEM_ROOT alloc;
516 char *ptr,**res;
517 struct handle_option_ctx ctx;
518 const char **dirs;
519 uint args_sep= my_getopt_use_args_separator ? 1 : 0;
520 DBUG_ENTER("load_defaults");
521
522 init_alloc_root(&alloc, "my_load_defaults", 512, 0, MYF(0));
523 if ((dirs= init_default_directories(&alloc)) == NULL)
524 goto err;
525 /*
526 Check if the user doesn't want any default option processing
527 --no-defaults is always the first option
528 */
529 if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
530 {
531 /* remove the --no-defaults argument and return only the other arguments */
532 uint i, j;
533 if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
534 (*argc + 1)*sizeof(char*))))
535 goto err;
536 res= (char**) (ptr+sizeof(alloc));
537 res[0]= **argv; /* Copy program name */
538 j= 1; /* Start from 1 for the reset result args */
539 if (my_getopt_use_args_separator)
540 {
541 /* set arguments separator */
542 set_args_separator(&res[1]);
543 j++;
544 }
545 for (i=2 ; i < (uint) *argc ; i++, j++)
546 res[j]=argv[0][i];
547 res[j]=0; /* End pointer */
548 /*
549 Update the argc, if have not added args separator, then we have
550 to decrease argc because we have removed the "--no-defaults".
551 */
552 if (!my_getopt_use_args_separator)
553 (*argc)--;
554 *argv=res;
555 *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
556 if (default_directories)
557 *default_directories= dirs;
558 DBUG_RETURN(0);
559 }
560
561 group.count=0;
562 group.name= "defaults";
563 group.type_names= groups;
564
565 for (; *groups ; groups++)
566 group.count++;
567
568 if (my_init_dynamic_array(&args, sizeof(char*), 128, 64, MYF(0)))
569 goto err;
570
571 ctx.alloc= &alloc;
572 ctx.args= &args;
573 ctx.group= &group;
574
575 if ((error= my_search_option_files(conf_file, argc, argv, &args_used,
576 handle_default_option, (void *) &ctx,
577 dirs)))
578 {
579 delete_dynamic(&args);
580 free_root(&alloc,MYF(0));
581 DBUG_RETURN(error);
582 }
583 /*
584 Here error contains <> 0 only if we have a fully specified conf_file
585 or a forced default file
586 */
587 if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
588 (args.elements + *argc + 1 + args_sep) *sizeof(char*))))
589 goto err;
590 res= (char**) (ptr+sizeof(alloc));
591
592 /* copy name + found arguments + command line arguments to new array */
593 res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */
594 memcpy((uchar*) (res+1), args.buffer, args.elements*sizeof(char*));
595 /* Skip --defaults-xxx options */
596 (*argc)-= args_used;
597 (*argv)+= args_used;
598
599 /*
600 Check if we want to see the new argument list
601 This options must always be the last of the default options
602 */
603 if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
604 {
605 found_print_defaults=1;
606 --*argc; ++*argv; /* skip argument */
607 }
608
609 if (my_getopt_use_args_separator)
610 {
611 /* set arguments separator for arguments from config file and
612 command line */
613 set_args_separator(&res[args.elements+1]);
614 }
615
616 if (*argc)
617 memcpy((uchar*) (res+1+args.elements+args_sep), (char*) ((*argv)+1),
618 (*argc-1)*sizeof(char*));
619 res[args.elements+ *argc+args_sep]=0; /* last null */
620
621 (*argc)+=args.elements+args_sep;
622 *argv= (char**) res;
623 *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
624 delete_dynamic(&args);
625 if (found_print_defaults)
626 {
627 int i;
628 printf("%s would have been started with the following arguments:\n",
629 **argv);
630 for (i=1 ; i < *argc ; i++)
631 if (!my_getopt_is_args_separator((*argv)[i])) /* skip arguments separator */
632 printf("%s ", (*argv)[i]);
633 puts("");
634 DBUG_RETURN(4);
635 }
636
637 if (default_directories)
638 *default_directories= dirs;
639
640 DBUG_RETURN(0);
641
642 err:
643 fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
644 DBUG_RETURN(2);
645 }
646
647
648 void free_defaults(char **argv)
649 {
650 MEM_ROOT ptr;
651 memcpy(&ptr, ((char *) argv) - sizeof(ptr), sizeof(ptr));
652 free_root(&ptr,MYF(0));
653 }
654
655
656 static int search_default_file(Process_option_func opt_handler,
657 void *handler_ctx,
658 const char *dir,
659 const char *config_file)
660 {
661 char **ext;
662 const char *empty_list[]= { "", 0 };
663 my_bool have_ext= fn_ext(config_file)[0] != 0;
664 const char **exts_to_use= have_ext ? empty_list : f_extensions;
665
666 for (ext= (char**) exts_to_use; *ext; ext++)
667 {
668 int error;
669 if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
670 dir, *ext,
671 config_file, 0)) < 0)
672 return error;
673 }
674 return 0;
675 }
676
677
678 /*
679 Skip over keyword and get argument after keyword
680
681 SYNOPSIS
682 get_argument()
683 keyword Include directive keyword
684 kwlen Length of keyword
685 ptr Pointer to the keword in the line under process
686 line line number
687
688 RETURN
689 0 error
690 # Returns pointer to the argument after the keyword.
691 */
692
693 static char *get_argument(const char *keyword, size_t kwlen,
694 char *ptr, char *name, uint line)
695 {
696 char *end;
697
698 /* Skip over "include / includedir keyword" and following whitespace */
699
700 for (ptr+= kwlen - 1;
701 my_isspace(&my_charset_latin1, ptr[0]);
702 ptr++)
703 {}
704
705 /*
706 Trim trailing whitespace from directory name
707 The -1 below is for the newline added by fgets()
708 Note that my_isspace() is true for \r and \n
709 */
710 for (end= ptr + strlen(ptr) - 1;
711 my_isspace(&my_charset_latin1, *(end - 1));
712 end--)
713 {}
714 end[0]= 0; /* Cut off end space */
715
716 /* Print error msg if there is nothing after !include* directive */
717 if (end <= ptr)
718 {
719 fprintf(stderr,
720 "error: Wrong '!%s' directive in config file: %s at line %d\n",
721 keyword, name, line);
722 return 0;
723 }
724 return ptr;
725 }
726
727
728 /*
729 Open a configuration file (if exists) and read given options from it
730
731 SYNOPSIS
732 search_default_file_with_ext()
733 opt_handler Option handler function. It is used to process
734 every separate option.
735 handler_ctx Pointer to the structure to store actual
736 parameters of the function.
737 dir directory to read
738 ext Extension for configuration file
739 config_file Name of configuration file
740 group groups to read
741 recursion_level the level of recursion, got while processing
742 "!include" or "!includedir"
743
744 RETURN
745 0 Success
746 -1 Fatal error, abort
747 1 File not found (Warning)
748 */
749
750 static int search_default_file_with_ext(Process_option_func opt_handler,
751 void *handler_ctx,
752 const char *dir,
753 const char *ext,
754 const char *config_file,
755 int recursion_level)
756 {
757 char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
758 char *value, option[4096+2], tmp[FN_REFLEN];
759 static const char includedir_keyword[]= "includedir";
760 static const char include_keyword[]= "include";
761 const int max_recursion_level= 10;
762 MYSQL_FILE *fp;
763 uint line=0;
764 my_bool found_group=0;
765 uint i;
766 MY_DIR *search_dir;
767 FILEINFO *search_file;
768
769 if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
770 return 0; /* Ignore wrong paths */
771 if (dir)
772 {
773 end=convert_dirname(name, dir, NullS);
774 if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
775 *end++='.';
776 strxmov(end,config_file,ext,NullS);
777 }
778 else
779 {
780 strmov(name,config_file);
781 }
782 fn_format(name,name,"","",4);
783 #if !defined(__WIN__)
784 {
785 MY_STAT stat_info;
786 if (!my_stat(name,&stat_info,MYF(0)))
787 return 1;
788 /*
789 Ignore world-writable regular files.
790 This is mainly done to protect us to not read a file created by
791 the mysqld server, but the check is still valid in most context.
792 */
793 if ((stat_info.st_mode & S_IWOTH) &&
794 (stat_info.st_mode & S_IFMT) == S_IFREG)
795 {
796 fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
797 name);
798 return 0;
799 }
800 }
801 #endif
802 if (!(fp= mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0))))
803 return 1; /* Ignore wrong files */
804
805 while (mysql_file_fgets(buff, sizeof(buff) - 1, fp))
806 {
807 line++;
808 /* Ignore comment and empty lines */
809 for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++)
810 {}
811
812 if (*ptr == '#' || *ptr == ';' || !*ptr)
813 continue;
814
815 /* Configuration File Directives */
816 if (*ptr == '!')
817 {
818 if (recursion_level >= max_recursion_level)
819 {
820 for (end= ptr + strlen(ptr) - 1;
821 my_isspace(&my_charset_latin1, *(end - 1));
822 end--)
823 {}
824 end[0]= 0;
825 fprintf(stderr,
826 "Warning: skipping '%s' directive as maximum include"
827 "recursion level was reached in file %s at line %d\n",
828 ptr, name, line);
829 continue;
830 }
831
832 /* skip over `!' and following whitespace */
833 for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++)
834 {}
835
836 if ((!strncmp(ptr, includedir_keyword,
837 sizeof(includedir_keyword) - 1)) &&
838 my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1]))
839 {
840 if (!(ptr= get_argument(includedir_keyword,
841 sizeof(includedir_keyword),
842 ptr, name, line)))
843 goto err;
844
845 if (!(search_dir= my_dir(ptr, MYF(MY_WME | MY_WANT_SORT))))
846 goto err;
847
848 for (i= 0; i < (uint) search_dir->number_of_files; i++)
849 {
850 search_file= search_dir->dir_entry + i;
851 ext= fn_ext2(search_file->name);
852
853 /* check extension */
854 for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
855 {
856 if (!strcmp(ext, *tmp_ext))
857 break;
858 }
859
860 if (*tmp_ext)
861 {
862 fn_format(tmp, search_file->name, ptr, "",
863 MY_UNPACK_FILENAME | MY_SAFE_PATH);
864
865 search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp,
866 recursion_level + 1);
867 }
868 }
869
870 my_dirend(search_dir);
871 }
872 else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
873 my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1]))
874 {
875 if (!(ptr= get_argument(include_keyword,
876 sizeof(include_keyword), ptr,
877 name, line)))
878 goto err;
879
880 search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
881 recursion_level + 1);
882 }
883
884 continue;
885 }
886
887 if (*ptr == '[') /* Group name */
888 {
889 found_group=1;
890 if (!(end=(char *) strchr(++ptr,']')))
891 {
892 fprintf(stderr,
893 "error: Wrong group definition in config file: %s at line %d\n",
894 name,line);
895 goto err;
896 }
897 /* Remove end space */
898 for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
899 end[0]=0;
900
901 strmake(curr_gr, ptr, MY_MIN((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
902
903 /* signal that a new group is found */
904 opt_handler(handler_ctx, curr_gr, NULL);
905
906 continue;
907 }
908 if (!found_group)
909 {
910 fprintf(stderr,
911 "error: Found option without preceding group in config file: %s at line: %d\n",
912 name,line);
913 goto err;
914 }
915
916
917 end= remove_end_comment(ptr);
918 if ((value= strchr(ptr, '=')))
919 end= value;
920 for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
921 if (!value)
922 {
923 strmake(strmov(option,"--"),ptr, (size_t) (end-ptr));
924 if (opt_handler(handler_ctx, curr_gr, option))
925 goto err;
926 }
927 else
928 {
929 /* Remove pre- and end space */
930 char *value_end;
931 for (value++ ; my_isspace(&my_charset_latin1,*value); value++) ;
932 value_end=strend(value);
933 /*
934 We don't have to test for value_end >= value as we know there is
935 an '=' before
936 */
937 for ( ; my_isspace(&my_charset_latin1,value_end[-1]) ; value_end--) ;
938 if (value_end < value) /* Empty string */
939 value_end=value;
940
941 /* remove quotes around argument */
942 if ((*value == '\"' || *value == '\'') && /* First char is quote */
943 (value + 1 < value_end ) && /* String is longer than 1 */
944 *value == value_end[-1] ) /* First char is equal to last char */
945 {
946 value++;
947 value_end--;
948 }
949 ptr=strnmov(strmov(option,"--"),ptr,(size_t) (end-ptr));
950 *ptr++= '=';
951
952 for ( ; value != value_end; value++)
953 {
954 if (*value == '\\' && value != value_end-1)
955 {
956 switch(*++value) {
957 case 'n':
958 *ptr++='\n';
959 break;
960 case 't':
961 *ptr++= '\t';
962 break;
963 case 'r':
964 *ptr++ = '\r';
965 break;
966 case 'b':
967 *ptr++ = '\b';
968 break;
969 case 's':
970 *ptr++= ' '; /* space */
971 break;
972 case '\"':
973 *ptr++= '\"';
974 break;
975 case '\'':
976 *ptr++= '\'';
977 break;
978 case '\\':
979 *ptr++= '\\';
980 break;
981 default: /* Unknown; Keep '\' */
982 *ptr++= '\\';
983 *ptr++= *value;
984 break;
985 }
986 }
987 else
988 *ptr++= *value;
989 }
990 *ptr=0;
991 if (opt_handler(handler_ctx, curr_gr, option))
992 goto err;
993 }
994 }
995 mysql_file_fclose(fp, MYF(0));
996 return(0);
997
998 err:
999 mysql_file_fclose(fp, MYF(0));
1000 return -1; /* Fatal error */
1001 }
1002
1003
1004 static char *remove_end_comment(char *ptr)
1005 {
1006 char quote= 0; /* we are inside quote marks */
1007 char escape= 0; /* symbol is protected by escape chagacter */
1008
1009 for (; *ptr; ptr++)
1010 {
1011 if ((*ptr == '\'' || *ptr == '\"') && !escape)
1012 {
1013 if (!quote)
1014 quote= *ptr;
1015 else if (quote == *ptr)
1016 quote= 0;
1017 }
1018 /* We are not inside a string */
1019 if (!quote && *ptr == '#')
1020 {
1021 *ptr= 0;
1022 return ptr;
1023 }
1024 escape= (quote && *ptr == '\\' && !escape);
1025 }
1026 return ptr;
1027 }
1028
1029
1030 void my_print_default_files(const char *conf_file)
1031 {
1032 const char *empty_list[]= { "", 0 };
1033 my_bool have_ext= fn_ext(conf_file)[0] != 0;
1034 const char **exts_to_use= have_ext ? empty_list : f_extensions;
1035 char name[FN_REFLEN], **ext;
1036
1037 puts("\nDefault options are read from the following files in the given order:");
1038 if (my_defaults_file)
1039 {
1040 puts(my_defaults_file);
1041 return;
1042 }
1043
1044 if (dirname_length(conf_file))
1045 fputs(conf_file,stdout);
1046 else
1047 {
1048 const char **dirs;
1049 MEM_ROOT alloc;
1050 init_alloc_root(&alloc, "my_print_defaults", 512, 0, MYF(0));
1051
1052 if ((dirs= init_default_directories(&alloc)) == NULL)
1053 {
1054 fputs("Internal error initializing default directories list", stdout);
1055 }
1056 else
1057 {
1058 for ( ; *dirs; dirs++)
1059 {
1060 for (ext= (char**) exts_to_use; *ext; ext++)
1061 {
1062 const char *pos;
1063 char *end;
1064 if (**dirs)
1065 pos= *dirs;
1066 else if (my_defaults_extra_file)
1067 {
1068 pos= my_defaults_extra_file;
1069 fputs(pos, stdout);
1070 fputs(" ", stdout);
1071 continue;
1072 }
1073 else
1074 continue;
1075 end= convert_dirname(name, pos, NullS);
1076 if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
1077 *end++= '.';
1078 strxmov(end, conf_file, *ext, " ", NullS);
1079 fputs(name, stdout);
1080 }
1081 }
1082 }
1083
1084 free_root(&alloc, MYF(0));
1085 }
1086 puts("");
1087 }
1088
1089 void print_defaults(const char *conf_file, const char **groups)
1090 {
1091 const char **groups_save= groups;
1092 my_print_default_files(conf_file);
1093
1094 fputs("The following groups are read:",stdout);
1095 for ( ; *groups ; groups++)
1096 {
1097 fputc(' ',stdout);
1098 fputs(*groups,stdout);
1099 }
1100
1101 if (my_defaults_group_suffix)
1102 {
1103 groups= groups_save;
1104 for ( ; *groups ; groups++)
1105 {
1106 fputc(' ',stdout);
1107 fputs(*groups,stdout);
1108 fputs(my_defaults_group_suffix,stdout);
1109 }
1110 }
1111 puts("\nThe following options may be given as the first argument:\n\
1112 --print-defaults Print the program argument list and exit.\n\
1113 --no-defaults Don't read default options from any option file.\n\
1114 The following specify which files/extra groups are read (specified before remaining options):\n\
1115 --defaults-file=# Only read default options from the given file #.\n\
1116 --defaults-extra-file=# Read this file after the global files are read.\n\
1117 --defaults-group-suffix=# Additionally read default groups with # appended as a suffix.");
1118 }
1119
1120
1121 static int add_directory(MEM_ROOT *alloc, const char *dir, const char **dirs)
1122 {
1123 char buf[FN_REFLEN];
1124 size_t len;
1125 char *p;
1126 my_bool err __attribute__((unused));
1127
1128 len= normalize_dirname(buf, dir);
1129 if (!(p= strmake_root(alloc, buf, len)))
1130 return 1; /* Failure */
1131 /* Should never fail if DEFAULT_DIRS_SIZE is correct size */
1132 err= array_append_string_unique(p, dirs, DEFAULT_DIRS_SIZE);
1133 DBUG_ASSERT(err == FALSE);
1134
1135 return 0;
1136 }
1137
1138 #ifdef __WIN__
1139 static const char *my_get_module_parent(char *buf, size_t size)
1140 {
1141 char *last= NULL;
1142 char *end;
1143 if (!GetModuleFileName(NULL, buf, (DWORD) size))
1144 return NULL;
1145 end= strend(buf);
1146
1147 /*
1148 Look for the second-to-last \ in the filename, but hang on
1149 to a pointer after the last \ in case we're in the root of
1150 a drive.
1151 */
1152 for ( ; end > buf; end--)
1153 {
1154 if (*end == FN_LIBCHAR)
1155 {
1156 if (last)
1157 {
1158 /* Keep the last '\' as this works both with D:\ and a directory */
1159 end[1]= 0;
1160 break;
1161 }
1162 last= end;
1163 }
1164 }
1165
1166 return buf;
1167 }
1168 #endif /* __WIN__ */
1169
1170
1171 static const char **init_default_directories(MEM_ROOT *alloc)
1172 {
1173 const char **dirs;
1174 char *env;
1175 int errors= 0;
1176 DBUG_ENTER("init_default_directories");
1177
1178 dirs= (const char **)alloc_root(alloc, DEFAULT_DIRS_SIZE * sizeof(char *));
1179 if (dirs == NULL)
1180 DBUG_RETURN(NULL);
1181 bzero((char *) dirs, DEFAULT_DIRS_SIZE * sizeof(char *));
1182
1183 #ifdef __WIN__
1184
1185 {
1186 char fname_buffer[FN_REFLEN];
1187 if (GetSystemWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
1188 errors += add_directory(alloc, fname_buffer, dirs);
1189
1190 if (GetWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
1191 errors += add_directory(alloc, fname_buffer, dirs);
1192
1193 errors += add_directory(alloc, "C:/", dirs);
1194
1195 if (my_get_module_parent(fname_buffer, sizeof(fname_buffer)) != NULL)
1196 {
1197 errors += add_directory(alloc, fname_buffer, dirs);
1198
1199 strcat_s(fname_buffer, sizeof(fname_buffer), "/data");
1200 errors += add_directory(alloc, fname_buffer, dirs);
1201 }
1202 }
1203
1204 #else
1205
1206 #if defined(DEFAULT_SYSCONFDIR)
1207 if (DEFAULT_SYSCONFDIR[0])
1208 errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs);
1209 #else
1210 errors += add_directory(alloc, "/etc/", dirs);
1211 errors += add_directory(alloc, "/etc/mysql/", dirs);
1212 #endif /* DEFAULT_SYSCONFDIR */
1213
1214 #endif
1215
1216 if ((env= getenv("MYSQL_HOME")))
1217 errors += add_directory(alloc, env, dirs);
1218
1219 /* Placeholder for --defaults-extra-file=<path> */
1220 errors += add_directory(alloc, "", dirs);
1221
1222 #if !defined(__WIN__)
1223 errors += add_directory(alloc, "~/", dirs);
1224 #endif
1225
1226 DBUG_RETURN(errors > 0 ? NULL : dirs);
1227 }
1228