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 Mark file names in argv[]. File marker is *always* followed by a file name
48 All options after it come from that file.
49 Empty file name ("") means command line.
50 */
51 static char *file_marker= (char*)"----file-marker----";
52 my_bool my_defaults_mark_files= FALSE;
is_file_marker(const char * arg)53 my_bool is_file_marker(const char* arg)
54 {
55 return arg == file_marker;
56 }
57
58 my_bool my_no_defaults=FALSE, my_print_defaults= FALSE;
59 const char *my_defaults_file=0;
60 const char *my_defaults_group_suffix=0;
61 const char *my_defaults_extra_file=0;
62
63 /* Which directories are searched for options (and in which order) */
64
65 #define MAX_DEFAULT_DIRS 7
66 #define DEFAULT_DIRS_SIZE (MAX_DEFAULT_DIRS + 1) /* Terminate with NULL */
67 static const char **default_directories = NULL;
68
69 #ifdef __WIN__
70 static const char *f_extensions[]= { ".ini", ".cnf", 0 };
71 #define NEWLINE "\r\n"
72 #else
73 static const char *f_extensions[]= { ".cnf", 0 };
74 #define NEWLINE "\n"
75 #endif
76
77 struct handle_option_ctx
78 {
79 MEM_ROOT *alloc;
80 DYNAMIC_ARRAY *args;
81 TYPELIB *group;
82 };
83
84 static int search_default_file(struct handle_option_ctx *,
85 const char *, const char *);
86 static int search_default_file_with_ext(struct handle_option_ctx *,
87 const char *, const char *,
88 const char *, int);
89
90
91 /**
92 Create the list of default directories.
93
94 @param alloc MEM_ROOT where the list of directories is stored
95
96 @details
97 The directories searched, in order, are:
98 - Windows: GetSystemWindowsDirectory()
99 - Windows: GetWindowsDirectory()
100 - Windows: C:/
101 - Windows: Directory above where the executable is located
102 - Unix: /etc/ or the value of DEFAULT_SYSCONFDIR, if defined
103 - Unix: /etc/mysql/ unless DEFAULT_SYSCONFDIR is defined
104 - ALL: getenv("MYSQL_HOME")
105 - ALL: --defaults-extra-file=<path> (run-time option)
106 - Unix: ~/
107
108 On all systems, if a directory is already in the list, it will be moved
109 to the end of the list. This avoids reading defaults files multiple times,
110 while ensuring the correct precedence.
111
112 @retval NULL Failure (out of memory, probably)
113 @retval other Pointer to NULL-terminated array of default directories
114 */
115
116 static const char **init_default_directories(MEM_ROOT *alloc);
117
118
119 static char *remove_end_comment(char *ptr);
120
121
122 /*
123 Process config files in default directories.
124
125 SYNOPSIS
126 my_search_option_files()
127 conf_file Basename for configuration file to search for.
128 If this is a path, then only this file is read.
129 argc Pointer to argc of original program
130 argv Pointer to argv of original program
131 func Pointer to the function to process options
132 func_ctx It's context. Usually it is the structure to
133 store additional options.
134 DESCRIPTION
135 Process the default options from argc & argv
136 Read through each found config file looks and calls 'func' to process
137 each option.
138
139 NOTES
140 --defaults-group-suffix is only processed if we are called from
141 load_defaults().
142
143
144 RETURN
145 0 ok
146 1 given cinf_file doesn't exist
147 2 out of memory
148 3 Can't get current working directory
149
150 The global variable 'my_defaults_group_suffix' is updated with value for
151 --defaults_group_suffix
152 */
153
my_search_option_files(const char * conf_file,struct handle_option_ctx * ctx,const char ** default_directories)154 static int my_search_option_files(const char *conf_file,
155 struct handle_option_ctx *ctx,
156 const char **default_directories)
157 {
158 const char **dirs;
159 int error= 0;
160 DBUG_ENTER("my_search_option_files");
161
162 if (my_defaults_group_suffix)
163 {
164 /* Handle --defaults-group-suffix= */
165 uint i;
166 const char **extra_groups;
167 const size_t instance_len= strlen(my_defaults_group_suffix);
168 char *ptr;
169 TYPELIB *group= ctx->group;
170
171 if (!(extra_groups=
172 (const char**)alloc_root(ctx->alloc,
173 (2*group->count+1)*sizeof(char*))))
174 DBUG_RETURN(2);
175
176 for (i= 0; i < group->count; i++)
177 {
178 size_t len;
179 extra_groups[i]= group->type_names[i]; /** copy group */
180
181 len= strlen(extra_groups[i]);
182 if (!(ptr= alloc_root(ctx->alloc, (uint) (len+instance_len+1))))
183 DBUG_RETURN(2);
184
185 extra_groups[i+group->count]= ptr;
186
187 /** Construct new group */
188 memcpy(ptr, extra_groups[i], len);
189 memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
190 }
191
192 group->count*= 2;
193 group->type_names= extra_groups;
194 group->type_names[group->count]= 0;
195 }
196
197 if (my_defaults_file)
198 {
199 if ((error= search_default_file_with_ext(ctx, "", "",
200 my_defaults_file, 0)) < 0)
201 goto err;
202 if (error > 0)
203 {
204 fprintf(stderr, "Could not open required defaults file: %s\n",
205 my_defaults_file);
206 goto err;
207 }
208 }
209 else if (dirname_length(conf_file))
210 {
211 if ((error= search_default_file(ctx, NullS, conf_file)) < 0)
212 goto err;
213 }
214 else
215 {
216 for (dirs= default_directories ; *dirs; dirs++)
217 {
218 if (**dirs)
219 {
220 if (search_default_file(ctx, *dirs, conf_file) < 0)
221 goto err;
222 }
223 else if (my_defaults_extra_file)
224 {
225 if ((error= search_default_file_with_ext(ctx, "", "",
226 my_defaults_extra_file, 0)) < 0)
227 goto err; /* Fatal error */
228 if (error > 0)
229 {
230 fprintf(stderr, "Could not open required defaults file: %s\n",
231 my_defaults_extra_file);
232 goto err;
233 }
234 }
235 }
236 }
237
238 DBUG_RETURN(0);
239
240 err:
241 fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
242 DBUG_RETURN(1);
243 }
244
245
246 /*
247 adds an option to the array of options
248
249 SYNOPSIS
250 add_option()
251 in_ctx Handler context.
252 option The very option to be processed. It is already
253 prepared to be used in argv (has -- prefix).
254
255 RETURN
256 0 - ok
257 1 - error occurred
258 */
259
add_option(struct handle_option_ctx * ctx,const char * option)260 static int add_option(struct handle_option_ctx *ctx, const char *option)
261 {
262 char *tmp= strdup_root(ctx->alloc, option);
263 return !tmp || insert_dynamic(ctx->args, (uchar*) &tmp);
264 }
265
266
267 /*
268 Gets options from the command line
269
270 SYNOPSIS
271 get_defaults_options()
272 argv Pointer to argv of original program
273
274 DESCRIPTION
275 Sets my_no_defaults, my_defaults_file, my_defaults_extra_file,
276 my_defaults_group_suffix, my_print_defaults
277
278 RETURN
279 # Number of arguments used from *argv
280 */
281
get_defaults_options(char ** argv)282 int get_defaults_options(char **argv)
283 {
284 static char file_buffer[FN_REFLEN];
285 static char extra_file_buffer[FN_REFLEN];
286 char **orig_argv= argv;
287
288 argv++; /* Skip program name */
289
290 my_defaults_file= my_defaults_group_suffix= my_defaults_extra_file= 0;
291 my_no_defaults= my_print_defaults= FALSE;
292
293 if (*argv && !strcmp(*argv, "--no-defaults"))
294 {
295 my_no_defaults= 1;
296 argv++;
297 }
298 else
299 for(; *argv; argv++)
300 {
301 if (!my_defaults_file && is_prefix(*argv, "--defaults-file="))
302 my_defaults_file= *argv + sizeof("--defaults-file=")-1;
303 else
304 if (!my_defaults_extra_file && is_prefix(*argv, "--defaults-extra-file="))
305 my_defaults_extra_file= *argv + sizeof("--defaults-extra-file=")-1;
306 else
307 if (!my_defaults_group_suffix && is_prefix(*argv, "--defaults-group-suffix="))
308 my_defaults_group_suffix= *argv + sizeof("--defaults-group-suffix=")-1;
309 else
310 break;
311 }
312
313 if (*argv && !strcmp(*argv, "--print-defaults"))
314 {
315 my_print_defaults= 1;
316 my_defaults_mark_files= FALSE;
317 argv++;
318 }
319
320 if (! my_defaults_group_suffix)
321 my_defaults_group_suffix= getenv("MYSQL_GROUP_SUFFIX");
322
323 if (my_defaults_extra_file && my_defaults_extra_file != extra_file_buffer)
324 {
325 my_realpath(extra_file_buffer, my_defaults_extra_file, MYF(0));
326 my_defaults_extra_file= extra_file_buffer;
327 }
328
329 if (my_defaults_file && my_defaults_file != file_buffer)
330 {
331 my_realpath(file_buffer, my_defaults_file, MYF(0));
332 my_defaults_file= file_buffer;
333 }
334
335 return (int)(argv - orig_argv);
336 }
337
338 /*
339 Wrapper around my_load_defaults() for interface compatibility.
340
341 SYNOPSIS
342 load_defaults()
343 conf_file Basename for configuration file to search for.
344 If this is a path, then only this file is read.
345 groups Which [group] entrys to read.
346 Points to an null terminated array of pointers
347 argc Pointer to argc of original program
348 argv Pointer to argv of original program
349
350 NOTES
351
352 This function is NOT thread-safe as it uses a global pointer internally.
353 See also notes for my_load_defaults().
354
355 RETURN
356 0 ok
357 1 The given conf_file didn't exists
358 */
load_defaults(const char * conf_file,const char ** groups,int * argc,char *** argv)359 int load_defaults(const char *conf_file, const char **groups,
360 int *argc, char ***argv)
361 {
362 return my_load_defaults(conf_file, groups, argc, argv, &default_directories);
363 }
364
365 /*
366 Read options from configurations files
367
368 SYNOPSIS
369 my_load_defaults()
370 conf_file Basename for configuration file to search for.
371 If this is a path, then only this file is read.
372 groups Which [group] entrys to read.
373 Points to an null terminated array of pointers
374 argc Pointer to argc of original program
375 argv Pointer to argv of original program
376 default_directories Pointer to a location where a pointer to the list
377 of default directories will be stored
378
379 IMPLEMENTATION
380
381 Read options from configuration files and put them BEFORE the arguments
382 that are already in argc and argv. This way the calling program can
383 easily command line options override options in configuration files
384
385 NOTES
386 In case of fatal error, the function will print a warning and returns 2
387
388 To free used memory one should call free_defaults() with the argument
389 that was put in *argv
390
391 RETURN
392 - If successful, 0 is returned. If 'default_directories' is not NULL,
393 a pointer to the array of default directory paths is stored to a location
394 it points to. That stored value must be passed to my_search_option_files()
395 later.
396
397 - 1 is returned if the given conf_file didn't exist. In this case, the
398 value pointed to by default_directories is undefined.
399 */
400
401
my_load_defaults(const char * conf_file,const char ** groups,int * argc,char *** argv,const char *** default_directories)402 int my_load_defaults(const char *conf_file, const char **groups, int *argc,
403 char ***argv, const char ***default_directories)
404 {
405 DYNAMIC_ARRAY args;
406 int args_used= 0;
407 int error= 0;
408 MEM_ROOT alloc;
409 char *ptr,**res;
410 const char **dirs;
411 DBUG_ENTER("my_load_defaults");
412
413 init_alloc_root(key_memory_defaults, &alloc, 512, 0, MYF(0));
414 if ((dirs= init_default_directories(&alloc)) == NULL)
415 goto err;
416
417 args_used= get_defaults_options(*argv);
418
419 if (my_init_dynamic_array(key_memory_defaults, &args, sizeof(char*), 128, 64,
420 MYF(0)))
421 goto err;
422
423 insert_dynamic(&args, *argv);/* Name MUST be set, even by embedded library */
424
425 *argc-= args_used;
426 *argv+= args_used;
427
428 if (!my_no_defaults)
429 {
430 TYPELIB group; // XXX
431 struct handle_option_ctx ctx;
432
433 group.count=0;
434 group.name= "defaults";
435 group.type_names= groups;
436
437 for (; *groups ; groups++)
438 group.count++;
439
440 ctx.alloc= &alloc;
441 ctx.args= &args;
442 ctx.group= &group;
443
444 if ((error= my_search_option_files(conf_file, &ctx, dirs)))
445 {
446 delete_dynamic(&args);
447 free_root(&alloc,MYF(0));
448 DBUG_RETURN(error);
449 }
450 }
451
452 if (!(ptr=(char*) alloc_root(&alloc, sizeof(alloc) +
453 (args.elements + *argc + 3) * sizeof(char*))))
454 goto err;
455 res= (char**) (ptr+sizeof(alloc));
456
457 /* found arguments + command line arguments to new array */
458 memcpy(res, args.buffer, args.elements * sizeof(char*));
459
460 if (my_defaults_mark_files)
461 {
462 res[args.elements++]= file_marker;
463 res[args.elements++]= (char*)"";
464 }
465
466 if (*argc)
467 memcpy(res + args.elements, *argv, *argc * sizeof(char*));
468
469 (*argc)+= args.elements;
470 *argv= res;
471 (*argv)[*argc]= 0;
472 *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
473 delete_dynamic(&args);
474 if (my_print_defaults)
475 {
476 int i;
477 printf("%s would have been started with the following arguments:\n",
478 **argv);
479 for (i=1 ; i < *argc ; i++)
480 printf("%s ", (*argv)[i]);
481 puts("");
482 DBUG_RETURN(4);
483 }
484
485 if (default_directories)
486 *default_directories= dirs;
487
488 DBUG_RETURN(0);
489
490 err:
491 fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
492 DBUG_RETURN(2);
493 }
494
495
free_defaults(char ** argv)496 void free_defaults(char **argv)
497 {
498 MEM_ROOT ptr;
499 memcpy(&ptr, ((char *) argv) - sizeof(ptr), sizeof(ptr));
500 free_root(&ptr,MYF(0));
501 }
502
503
search_default_file(struct handle_option_ctx * ctx,const char * dir,const char * config_file)504 static int search_default_file(struct handle_option_ctx *ctx, const char *dir,
505 const char *config_file)
506 {
507 char **ext;
508 const char *empty_list[]= { "", 0 };
509 my_bool have_ext= fn_ext(config_file)[0] != 0;
510 const char **exts_to_use= have_ext ? empty_list : f_extensions;
511
512 for (ext= (char**) exts_to_use; *ext; ext++)
513 {
514 int error;
515 if ((error= search_default_file_with_ext(ctx, dir, *ext, config_file, 0)) < 0)
516 return error;
517 }
518 return 0;
519 }
520
521
522 /*
523 Skip over keyword and get argument after keyword
524
525 SYNOPSIS
526 get_argument()
527 keyword Include directive keyword
528 kwlen Length of keyword
529 ptr Pointer to the keword in the line under process
530 line line number
531
532 RETURN
533 0 error
534 # Returns pointer to the argument after the keyword.
535 */
536
get_argument(const char * keyword,size_t kwlen,char * ptr,char * name,uint line)537 static char *get_argument(const char *keyword, size_t kwlen,
538 char *ptr, char *name, uint line)
539 {
540 char *end;
541
542 /* Skip over "include / includedir keyword" and following whitespace */
543
544 for (ptr+= kwlen - 1;
545 my_isspace(&my_charset_latin1, ptr[0]);
546 ptr++)
547 {}
548
549 /*
550 Trim trailing whitespace from directory name
551 The -1 below is for the newline added by fgets()
552 Note that my_isspace() is true for \r and \n
553 */
554 for (end= ptr + strlen(ptr) - 1;
555 my_isspace(&my_charset_latin1, *(end - 1));
556 end--)
557 {}
558 end[0]= 0; /* Cut off end space */
559
560 /* Print error msg if there is nothing after !include* directive */
561 if (end <= ptr)
562 {
563 fprintf(stderr,
564 "error: Wrong '!%s' directive in config file: %s at line %d\n",
565 keyword, name, line);
566 return 0;
567 }
568 return ptr;
569 }
570
571
572 /*
573 Open a configuration file (if exists) and read given options from it
574
575 SYNOPSIS
576 search_default_file_with_ext()
577 ctx Pointer to the structure to store actual
578 parameters of the function.
579 dir directory to read
580 ext Extension for configuration file
581 config_file Name of configuration file
582 group groups to read
583 recursion_level the level of recursion, got while processing
584 "!include" or "!includedir"
585
586 RETURN
587 0 Success
588 -1 Fatal error, abort
589 1 File not found (Warning)
590 */
591
search_default_file_with_ext(struct handle_option_ctx * ctx,const char * dir,const char * ext,const char * config_file,int recursion_level)592 static int search_default_file_with_ext(struct handle_option_ctx *ctx,
593 const char *dir, const char *ext,
594 const char *config_file,
595 int recursion_level)
596 {
597 char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
598 char *value, option[4096+2], tmp[FN_REFLEN];
599 static const char includedir_keyword[]= "includedir";
600 static const char include_keyword[]= "include";
601 const int max_recursion_level= 10;
602 MYSQL_FILE *fp;
603 uint line=0;
604 enum { NONE, PARSE, SKIP } found_group= NONE;
605 uint i;
606 MY_DIR *search_dir;
607 FILEINFO *search_file;
608
609 if (safe_strlen(dir) + strlen(config_file) >= FN_REFLEN-3)
610 return 0; /* Ignore wrong paths */
611 if (dir)
612 {
613 end=convert_dirname(name, dir, NullS);
614 if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
615 *end++='.';
616 strxmov(end,config_file,ext,NullS);
617 }
618 else
619 {
620 strmov(name,config_file);
621 }
622 fn_format(name,name,"","",4);
623 #if !defined(__WIN__)
624 {
625 MY_STAT stat_info;
626 if (!my_stat(name,&stat_info,MYF(0)))
627 return 1;
628 /*
629 Ignore world-writable regular files.
630 This is mainly done to protect us to not read a file created by
631 the mysqld server, but the check is still valid in most context.
632 */
633 if ((stat_info.st_mode & S_IWOTH) &&
634 (stat_info.st_mode & S_IFMT) == S_IFREG)
635 {
636 fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
637 name);
638 return 0;
639 }
640 }
641 #endif
642 if (!(fp= mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0))))
643 return 1; /* Ignore wrong files */
644
645 if (my_defaults_mark_files)
646 if (insert_dynamic(ctx->args, (uchar*) &file_marker) ||
647 add_option(ctx, name))
648 goto err;
649
650 while (mysql_file_fgets(buff, sizeof(buff) - 1, fp))
651 {
652 line++;
653 /* Ignore comment and empty lines */
654 for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++)
655 {}
656
657 if (*ptr == '#' || *ptr == ';' || !*ptr)
658 continue;
659
660 /* Configuration File Directives */
661 if (*ptr == '!')
662 {
663 if (recursion_level >= max_recursion_level)
664 {
665 for (end= ptr + strlen(ptr) - 1;
666 my_isspace(&my_charset_latin1, *(end - 1));
667 end--)
668 {}
669 end[0]= 0;
670 fprintf(stderr,
671 "Warning: skipping '%s' directive as maximum include"
672 "recursion level was reached in file %s at line %d\n",
673 ptr, name, line);
674 continue;
675 }
676
677 /* skip over `!' and following whitespace */
678 for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++)
679 {}
680
681 if ((!strncmp(ptr, includedir_keyword,
682 sizeof(includedir_keyword) - 1)) &&
683 my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1]))
684 {
685 if (!(ptr= get_argument(includedir_keyword,
686 sizeof(includedir_keyword),
687 ptr, name, line)))
688 goto err;
689
690 if (!(search_dir= my_dir(ptr, MYF(MY_WME | MY_WANT_SORT))))
691 goto err;
692
693 for (i= 0; i < (uint) search_dir->number_of_files; i++)
694 {
695 search_file= search_dir->dir_entry + i;
696 ext= fn_ext2(search_file->name);
697
698 /* check extension */
699 for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
700 {
701 if (!strcmp(ext, *tmp_ext))
702 break;
703 }
704
705 if (*tmp_ext)
706 {
707 fn_format(tmp, search_file->name, ptr, "",
708 MY_UNPACK_FILENAME | MY_SAFE_PATH);
709
710 search_default_file_with_ext(ctx, "", "", tmp, recursion_level + 1);
711 }
712 }
713
714 my_dirend(search_dir);
715 }
716 else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
717 my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1]))
718 {
719 if (!(ptr= get_argument(include_keyword,
720 sizeof(include_keyword), ptr,
721 name, line)))
722 goto err;
723
724 search_default_file_with_ext(ctx, "", "", ptr, recursion_level + 1);
725 }
726
727 continue;
728 }
729
730 if (*ptr == '[') /* Group name */
731 {
732 if (!(end=(char *) strchr(++ptr,']')))
733 {
734 fprintf(stderr,
735 "error: Wrong group definition in config file: %s at line %d\n",
736 name,line);
737 goto err;
738 }
739 /* Remove end space */
740 for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
741 end[0]=0;
742
743 strmake(curr_gr, ptr, MY_MIN((size_t) (end-ptr), sizeof(curr_gr)-1));
744 found_group= find_type(curr_gr, ctx->group, FIND_TYPE_NO_PREFIX)
745 ? PARSE : SKIP;
746 continue;
747 }
748 switch (found_group)
749 {
750 case NONE:
751 fprintf(stderr,
752 "error: Found option without preceding group in config file: %s at line: %d\n",
753 name,line);
754 goto err;
755 case PARSE:
756 break;
757 case SKIP:
758 continue;
759 }
760
761 end= remove_end_comment(ptr);
762 if ((value= strchr(ptr, '=')))
763 end= value;
764 for ( ; my_isspace(&my_charset_latin1,end[-1]) ; end--) ;
765 ptr= strmake(strmov(option,"--"), ptr, (size_t) (end-ptr));
766 if (value)
767 {
768 /* Remove pre- and end space */
769 char *value_end;
770 for (value++ ; my_isspace(&my_charset_latin1,*value); value++) ;
771 value_end=strend(value);
772 /*
773 We don't have to test for value_end >= value as we know there is
774 an '=' before
775 */
776 for ( ; my_isspace(&my_charset_latin1,value_end[-1]) ; value_end--) ;
777 if (value_end < value) /* Empty string */
778 value_end=value;
779
780 /* remove quotes around argument */
781 if ((*value == '\"' || *value == '\'') && /* First char is quote */
782 (value + 1 < value_end ) && /* String is longer than 1 */
783 *value == value_end[-1] ) /* First char is equal to last char */
784 {
785 value++;
786 value_end--;
787 }
788 *ptr++= '=';
789 for ( ; value != value_end; value++)
790 {
791 if (*value == '\\' && value != value_end-1)
792 {
793 switch(*++value) {
794 case 'n':
795 *ptr++='\n';
796 break;
797 case 't':
798 *ptr++= '\t';
799 break;
800 case 'r':
801 *ptr++ = '\r';
802 break;
803 case 'b':
804 *ptr++ = '\b';
805 break;
806 case 's':
807 *ptr++= ' '; /* space */
808 break;
809 case '\"':
810 *ptr++= '\"';
811 break;
812 case '\'':
813 *ptr++= '\'';
814 break;
815 case '\\':
816 *ptr++= '\\';
817 break;
818 default: /* Unknown; Keep '\' */
819 *ptr++= '\\';
820 *ptr++= *value;
821 break;
822 }
823 }
824 else
825 *ptr++= *value;
826 }
827 *ptr=0;
828 }
829
830 if (add_option(ctx, option))
831 goto err;
832 }
833 mysql_file_fclose(fp, MYF(0));
834 return(0);
835
836 err:
837 mysql_file_fclose(fp, MYF(0));
838 return -1; /* Fatal error */
839 }
840
841
remove_end_comment(char * ptr)842 static char *remove_end_comment(char *ptr)
843 {
844 char quote= 0; /* we are inside quote marks */
845 char escape= 0; /* symbol is protected by escape chagacter */
846
847 for (; *ptr; ptr++)
848 {
849 if ((*ptr == '\'' || *ptr == '\"') && !escape)
850 {
851 if (!quote)
852 quote= *ptr;
853 else if (quote == *ptr)
854 quote= 0;
855 }
856 /* We are not inside a string */
857 if (!quote && *ptr == '#')
858 {
859 *ptr= 0;
860 return ptr;
861 }
862 escape= (quote && *ptr == '\\' && !escape);
863 }
864 return ptr;
865 }
866
867
my_print_default_files(const char * conf_file)868 void my_print_default_files(const char *conf_file)
869 {
870 const char *empty_list[]= { "", 0 };
871 my_bool have_ext= fn_ext(conf_file)[0] != 0;
872 const char **exts_to_use= have_ext ? empty_list : f_extensions;
873 char name[FN_REFLEN], **ext;
874
875 puts("\nDefault options are read from the following files in the given order:");
876 if (my_defaults_file)
877 {
878 puts(my_defaults_file);
879 return;
880 }
881
882 if (dirname_length(conf_file))
883 fputs(conf_file,stdout);
884 else
885 {
886 const char **dirs;
887 MEM_ROOT alloc;
888 init_alloc_root(key_memory_defaults, &alloc, 512, 0, MYF(0));
889
890 if ((dirs= init_default_directories(&alloc)) == NULL)
891 {
892 fputs("Internal error initializing default directories list", stdout);
893 }
894 else
895 {
896 for ( ; *dirs; dirs++)
897 {
898 for (ext= (char**) exts_to_use; *ext; ext++)
899 {
900 const char *pos;
901 char *end;
902 if (**dirs)
903 pos= *dirs;
904 else if (my_defaults_extra_file)
905 {
906 pos= my_defaults_extra_file;
907 fputs(pos, stdout);
908 fputs(" ", stdout);
909 continue;
910 }
911 else
912 continue;
913 end= convert_dirname(name, pos, NullS);
914 if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
915 *end++= '.';
916 strxmov(end, conf_file, *ext, " ", NullS);
917 fputs(name, stdout);
918 }
919 }
920 }
921
922 free_root(&alloc, MYF(0));
923 }
924 puts("");
925 }
926
print_defaults(const char * conf_file,const char ** groups)927 void print_defaults(const char *conf_file, const char **groups)
928 {
929 const char **groups_save= groups;
930 my_print_default_files(conf_file);
931
932 fputs("The following groups are read:",stdout);
933 for ( ; *groups ; groups++)
934 {
935 fputc(' ',stdout);
936 fputs(*groups,stdout);
937 }
938
939 if (my_defaults_group_suffix)
940 {
941 groups= groups_save;
942 for ( ; *groups ; groups++)
943 {
944 fputc(' ',stdout);
945 fputs(*groups,stdout);
946 fputs(my_defaults_group_suffix,stdout);
947 }
948 }
949 puts("\nThe following options may be given as the first argument:\n\
950 --print-defaults Print the program argument list and exit.\n\
951 --no-defaults Don't read default options from any option file.\n\
952 The following specify which files/extra groups are read (specified before remaining options):\n\
953 --defaults-file=# Only read default options from the given file #.\n\
954 --defaults-extra-file=# Read this file after the global files are read.\n\
955 --defaults-group-suffix=# Additionally read default groups with # appended as a suffix.");
956 }
957
958
add_directory(MEM_ROOT * alloc,const char * dir,const char ** dirs)959 static int add_directory(MEM_ROOT *alloc, const char *dir, const char **dirs)
960 {
961 char buf[FN_REFLEN];
962 size_t len;
963 char *p;
964 my_bool err __attribute__((unused));
965
966 len= normalize_dirname(buf, dir);
967 if (!(p= strmake_root(alloc, buf, len)))
968 return 1; /* Failure */
969 /* Should never fail if DEFAULT_DIRS_SIZE is correct size */
970 err= array_append_string_unique(p, dirs, DEFAULT_DIRS_SIZE);
971 DBUG_ASSERT(err == FALSE);
972
973 return 0;
974 }
975
976 #ifdef __WIN__
my_get_module_parent(char * buf,size_t size)977 static const char *my_get_module_parent(char *buf, size_t size)
978 {
979 char *last= NULL;
980 char *end;
981 if (!GetModuleFileName(NULL, buf, (DWORD) size))
982 return NULL;
983 end= strend(buf);
984
985 /*
986 Look for the second-to-last \ in the filename, but hang on
987 to a pointer after the last \ in case we're in the root of
988 a drive.
989 */
990 for ( ; end > buf; end--)
991 {
992 if (*end == FN_LIBCHAR)
993 {
994 if (last)
995 {
996 /* Keep the last '\' as this works both with D:\ and a directory */
997 end[1]= 0;
998 break;
999 }
1000 last= end;
1001 }
1002 }
1003
1004 return buf;
1005 }
1006 #endif /* __WIN__ */
1007
1008
init_default_directories(MEM_ROOT * alloc)1009 static const char **init_default_directories(MEM_ROOT *alloc)
1010 {
1011 const char **dirs;
1012 char *env;
1013 int errors= 0;
1014 DBUG_ENTER("init_default_directories");
1015
1016 dirs= (const char **)alloc_root(alloc, DEFAULT_DIRS_SIZE * sizeof(char *));
1017 if (dirs == NULL)
1018 DBUG_RETURN(NULL);
1019 bzero((char *) dirs, DEFAULT_DIRS_SIZE * sizeof(char *));
1020
1021 #ifdef __WIN__
1022
1023 {
1024 char fname_buffer[FN_REFLEN];
1025 if (GetSystemWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
1026 errors += add_directory(alloc, fname_buffer, dirs);
1027
1028 if (GetWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
1029 errors += add_directory(alloc, fname_buffer, dirs);
1030
1031 errors += add_directory(alloc, "C:/", dirs);
1032
1033 if (my_get_module_parent(fname_buffer, sizeof(fname_buffer)) != NULL)
1034 {
1035 errors += add_directory(alloc, fname_buffer, dirs);
1036
1037 strcat_s(fname_buffer, sizeof(fname_buffer), "/data");
1038 errors += add_directory(alloc, fname_buffer, dirs);
1039 }
1040 }
1041
1042 #else
1043
1044 #if defined(DEFAULT_SYSCONFDIR)
1045 if (DEFAULT_SYSCONFDIR[0])
1046 errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs);
1047 #else
1048 errors += add_directory(alloc, "/etc/", dirs);
1049 errors += add_directory(alloc, "/etc/mysql/", dirs);
1050 #endif /* DEFAULT_SYSCONFDIR */
1051
1052 #endif
1053
1054 if ((env= getenv("MYSQL_HOME")))
1055 errors += add_directory(alloc, env, dirs);
1056
1057 /* Placeholder for --defaults-extra-file=<path> */
1058 errors += add_directory(alloc, "", dirs);
1059
1060 #if !defined(__WIN__)
1061 errors += add_directory(alloc, "~/", dirs);
1062 #endif
1063
1064 DBUG_RETURN(errors > 0 ? NULL : dirs);
1065 }
1066