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-1301, 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*/
72static const char *args_separator= "----args-separator----";
73inline static void set_args_separator(char** arg)
74{
75 DBUG_ASSERT(my_getopt_use_args_separator);
76 *arg= (char*)args_separator;
77}
78my_bool my_getopt_use_args_separator= FALSE;
79my_bool my_getopt_is_args_separator(const char* arg)
80{
81 return (arg == args_separator);
82}
83const char *my_defaults_file=0;
84const char *my_defaults_group_suffix=0;
85const char *my_defaults_extra_file=0;
86
87static char my_defaults_file_buffer[FN_REFLEN];
88static char my_defaults_extra_file_buffer[FN_REFLEN];
89
90static 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 */
96static const char **default_directories = NULL;
97
98#ifdef __WIN__
99static const char *f_extensions[]= { ".ini", ".cnf", 0 };
100#define NEWLINE "\r\n"
101#else
102static const char *f_extensions[]= { ".cnf", 0 };
103#define NEWLINE "\n"
104#endif
105
106static 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
115struct handle_option_ctx
116{
117 MEM_ROOT *alloc;
118 DYNAMIC_ARRAY *args;
119 TYPELIB *group;
120};
121
122static int search_default_file(Process_option_func func, void *func_ctx,
123 const char *dir, const char *config_file);
124static 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
155static const char **init_default_directories(MEM_ROOT *alloc);
156
157
158static 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
171static int
172fn_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
222int 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
341err:
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
370static 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
408int 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*/
464int 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
507int 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
648void 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
656static 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
693static 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
750static 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
1004static 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
1030void 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
1039 if (dirname_length(conf_file))
1040 fputs(conf_file,stdout);
1041 else
1042 {
1043 const char **dirs;
1044 MEM_ROOT alloc;
1045 init_alloc_root(&alloc, "my_print_defaults", 512, 0, MYF(0));
1046
1047 if ((dirs= init_default_directories(&alloc)) == NULL)
1048 {
1049 fputs("Internal error initializing default directories list", stdout);
1050 }
1051 else
1052 {
1053 for ( ; *dirs; dirs++)
1054 {
1055 for (ext= (char**) exts_to_use; *ext; ext++)
1056 {
1057 const char *pos;
1058 char *end;
1059 if (**dirs)
1060 pos= *dirs;
1061 else if (my_defaults_extra_file)
1062 pos= my_defaults_extra_file;
1063 else
1064 continue;
1065 end= convert_dirname(name, pos, NullS);
1066 if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
1067 *end++= '.';
1068 strxmov(end, conf_file, *ext, " ", NullS);
1069 fputs(name, stdout);
1070 }
1071 }
1072 }
1073
1074 free_root(&alloc, MYF(0));
1075 }
1076 puts("");
1077}
1078
1079void print_defaults(const char *conf_file, const char **groups)
1080{
1081 const char **groups_save= groups;
1082 my_print_default_files(conf_file);
1083
1084 fputs("The following groups are read:",stdout);
1085 for ( ; *groups ; groups++)
1086 {
1087 fputc(' ',stdout);
1088 fputs(*groups,stdout);
1089 }
1090
1091 if (my_defaults_group_suffix)
1092 {
1093 groups= groups_save;
1094 for ( ; *groups ; groups++)
1095 {
1096 fputc(' ',stdout);
1097 fputs(*groups,stdout);
1098 fputs(my_defaults_group_suffix,stdout);
1099 }
1100 }
1101 puts("\nThe following options may be given as the first argument:\n\
1102--print-defaults Print the program argument list and exit.\n\
1103--no-defaults Don't read default options from any option file.\n\
1104The following specify which files/extra groups are read (specified before remaining options):\n\
1105--defaults-file=# Only read default options from the given file #.\n\
1106--defaults-extra-file=# Read this file after the global files are read.\n\
1107--defaults-group-suffix=# Additionally read default groups with # appended as a suffix.");
1108}
1109
1110
1111static int add_directory(MEM_ROOT *alloc, const char *dir, const char **dirs)
1112{
1113 char buf[FN_REFLEN];
1114 size_t len;
1115 char *p;
1116 my_bool err __attribute__((unused));
1117
1118 len= normalize_dirname(buf, dir);
1119 if (!(p= strmake_root(alloc, buf, len)))
1120 return 1; /* Failure */
1121 /* Should never fail if DEFAULT_DIRS_SIZE is correct size */
1122 err= array_append_string_unique(p, dirs, DEFAULT_DIRS_SIZE);
1123 DBUG_ASSERT(err == FALSE);
1124
1125 return 0;
1126}
1127
1128#ifdef __WIN__
1129static const char *my_get_module_parent(char *buf, size_t size)
1130{
1131 char *last= NULL;
1132 char *end;
1133 if (!GetModuleFileName(NULL, buf, (DWORD) size))
1134 return NULL;
1135 end= strend(buf);
1136
1137 /*
1138 Look for the second-to-last \ in the filename, but hang on
1139 to a pointer after the last \ in case we're in the root of
1140 a drive.
1141 */
1142 for ( ; end > buf; end--)
1143 {
1144 if (*end == FN_LIBCHAR)
1145 {
1146 if (last)
1147 {
1148 /* Keep the last '\' as this works both with D:\ and a directory */
1149 end[1]= 0;
1150 break;
1151 }
1152 last= end;
1153 }
1154 }
1155
1156 return buf;
1157}
1158#endif /* __WIN__ */
1159
1160
1161static const char **init_default_directories(MEM_ROOT *alloc)
1162{
1163 const char **dirs;
1164 char *env;
1165 int errors= 0;
1166 DBUG_ENTER("init_default_directories");
1167
1168 dirs= (const char **)alloc_root(alloc, DEFAULT_DIRS_SIZE * sizeof(char *));
1169 if (dirs == NULL)
1170 DBUG_RETURN(NULL);
1171 bzero((char *) dirs, DEFAULT_DIRS_SIZE * sizeof(char *));
1172
1173#ifdef __WIN__
1174
1175 {
1176 char fname_buffer[FN_REFLEN];
1177 if (GetSystemWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
1178 errors += add_directory(alloc, fname_buffer, dirs);
1179
1180 if (GetWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
1181 errors += add_directory(alloc, fname_buffer, dirs);
1182
1183 errors += add_directory(alloc, "C:/", dirs);
1184
1185 if (my_get_module_parent(fname_buffer, sizeof(fname_buffer)) != NULL)
1186 {
1187 errors += add_directory(alloc, fname_buffer, dirs);
1188
1189 strcat_s(fname_buffer, sizeof(fname_buffer), "/data");
1190 errors += add_directory(alloc, fname_buffer, dirs);
1191 }
1192 }
1193
1194#else
1195
1196#if defined(DEFAULT_SYSCONFDIR)
1197 if (DEFAULT_SYSCONFDIR[0])
1198 errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs);
1199#else
1200 errors += add_directory(alloc, "/etc/", dirs);
1201 errors += add_directory(alloc, "/etc/mysql/", dirs);
1202#endif /* DEFAULT_SYSCONFDIR */
1203
1204#endif
1205
1206 if ((env= getenv("MYSQL_HOME")))
1207 errors += add_directory(alloc, env, dirs);
1208
1209 /* Placeholder for --defaults-extra-file=<path> */
1210 errors += add_directory(alloc, "", dirs);
1211
1212#if !defined(__WIN__)
1213 errors += add_directory(alloc, "~/", dirs);
1214#endif
1215
1216 DBUG_RETURN(errors > 0 ? NULL : dirs);
1217}
1218