1 /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 Without limiting anything contained in the foregoing, this file,
15 which is part of C Driver for MySQL (Connector/C), is also subject to the
16 Universal FOSS Exception, version 1.0, a copy of which can be found at
17 http://oss.oracle.com/licenses/universal-foss-exception.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License, version 2.0, for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
27
28 /****************************************************************************
29 Add all options from files named "group".cnf from the default_directories
30 before the command line arguments.
31 On Windows defaults will also search in the Windows directory for a file
32 called 'group'.ini
33 As long as the program uses the last argument for conflicting
34 options one only have to add a call to "load_defaults" to enable
35 use of default values.
36 pre- and end 'blank space' are removed from options and values. The
37 following escape sequences are recognized in values: \b \t \n \r \\
38
39 The following arguments are handled automatically; If used, they must be
40 first argument on the command line!
41 --no-defaults ; no options are read, except for the ones provided in the
42 login file.
43 --defaults-file=full-path-to-default-file ; Only this file will be read.
44 --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
45 --defaults-group-suffix ; Also read groups with concat(group, suffix)
46 --print-defaults ; Print the modified command line and exit
47 --login-path=login-path-name ; Read options under login-path-name from
48 the login file.
49 ****************************************************************************/
50
51 #include "../mysys/mysys_priv.h"
52 #include "my_default.h"
53 #include "my_default_priv.h"
54 #include "m_string.h"
55 #include "m_ctype.h"
56 #include <my_dir.h>
57 #include <my_aes.h>
58 #ifdef __WIN__
59 #include <winbase.h>
60 #endif
61
62 C_MODE_START
63 #ifdef HAVE_PSI_INTERFACE
64 extern PSI_file_key key_file_cnf;
65 #endif
66 C_MODE_END
67
68 /**
69 arguments separator
70
71 load_defaults() loads arguments from config file and put them
72 before the arguments from command line, this separator is used to
73 separate the arguments loaded from config file and arguments user
74 provided on command line.
75
76 Options with value loaded from config file are always in the form
77 '--option=value', while for command line options, the value can be
78 given as the next argument. Thus we used a separator so that
79 handle_options() can distinguish them.
80
81 Note: any other places that does not need to distinguish them
82 should skip the separator.
83
84 The content of arguments separator does not matter, one should only
85 check the pointer, use "----args-separator----" here to ease debug
86 if someone misused it.
87
88 The args seprator will only be added when
89 my_getopt_use_args_seprator is set to TRUE before calling
90 load_defaults();
91
92 See BUG#25192
93 */
94 static const char *args_separator= "----args-separator----";
set_args_separator(char ** arg)95 inline static void set_args_separator(char** arg)
96 {
97 DBUG_ASSERT(my_getopt_use_args_separator);
98 *arg= (char*)args_separator;
99 }
100
101 /*
102 This flag indicates that the argument separator string
103 (args_separator) should be added to the list of arguments,
104 in order to separate arguments received from config file
105 and command line.
106 */
107 my_bool my_getopt_use_args_separator= FALSE;
my_getopt_is_args_separator(const char * arg)108 my_bool my_getopt_is_args_separator(const char* arg)
109 {
110 return (arg == args_separator);
111 }
112 const char *my_defaults_file=0;
113 const char *my_defaults_group_suffix=0;
114 const char *my_defaults_extra_file=0;
115
116 static const char *my_login_path= 0;
117
118 static char my_defaults_file_buffer[FN_REFLEN];
119 static char my_defaults_extra_file_buffer[FN_REFLEN];
120
121 static my_bool defaults_already_read= FALSE;
122
123 /* Which directories are searched for options (and in which order) */
124
125 #define MAX_DEFAULT_DIRS 7
126 #define DEFAULT_DIRS_SIZE (MAX_DEFAULT_DIRS + 1) /* Terminate with NULL */
127 static const char **default_directories = NULL;
128
129 #ifdef __WIN__
130 static const char *f_extensions[]= { ".ini", ".cnf", 0 };
131 #define NEWLINE "\r\n"
132 #else
133 static const char *f_extensions[]= { ".cnf", 0 };
134 #define NEWLINE "\n"
135 #endif
136
137 static int handle_default_option(void *in_ctx, const char *group_name,
138 const char *option);
139
140 /*
141 This structure defines the context that we pass to callback
142 function 'handle_default_option' used in search_default_file
143 to process each option. This context is used if search_default_file
144 was called from load_defaults.
145 */
146
147 struct handle_option_ctx
148 {
149 MEM_ROOT *alloc;
150 DYNAMIC_ARRAY *args;
151 TYPELIB *group;
152 };
153
154 static int search_default_file(Process_option_func func, void *func_ctx,
155 const char *dir, const char *config_file,
156 my_bool is_login_file);
157 static int search_default_file_with_ext(Process_option_func func,
158 void *func_ctx,
159 const char *dir, const char *ext,
160 const char *config_file,
161 int recursion_level,
162 my_bool is_login_file);
163 static my_bool mysql_file_getline(char *str, int size, MYSQL_FILE *file,
164 my_bool is_login_file);
165
166 /**
167 Create the list of default directories.
168
169 @param alloc MEM_ROOT where the list of directories is stored
170
171 @details
172 The directories searched, in order, are:
173 - Windows: GetSystemWindowsDirectory()
174 - Windows: GetWindowsDirectory()
175 - Windows: C:/
176 - Windows: Directory above where the executable is located
177 - Unix: /etc/
178 - Unix: /etc/mysql/
179 - Unix: --sysconfdir=<path> (compile-time option)
180 - ALL: getenv("MYSQL_HOME")
181 - ALL: --defaults-extra-file=<path> (run-time option)
182 - Unix: ~/
183
184 On all systems, if a directory is already in the list, it will be moved
185 to the end of the list. This avoids reading defaults files multiple times,
186 while ensuring the correct precedence.
187
188 @retval NULL Failure (out of memory, probably)
189 @retval other Pointer to NULL-terminated array of default directories
190 */
191
192 static const char **init_default_directories(MEM_ROOT *alloc);
193
194
195 static char *remove_end_comment(char *ptr);
196
197
198 /*
199 Expand a file name so that the current working directory is added if
200 the name is relative.
201
202 RETURNS
203 0 All OK
204 2 Out of memory or path too long
205 3 Not able to get working directory
206 */
207
208 static int
fn_expand(const char * filename,char * result_buf)209 fn_expand(const char *filename, char *result_buf)
210 {
211 char dir[FN_REFLEN];
212 const int flags= MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_RELATIVE_PATH;
213 DBUG_ENTER("fn_expand");
214 DBUG_PRINT("enter", ("filename: %s, result_buf: 0x%lx",
215 filename, (unsigned long) result_buf));
216 if (my_getwd(dir, sizeof(dir), MYF(0)))
217 DBUG_RETURN(3);
218 DBUG_PRINT("debug", ("dir: %s", dir));
219 if (fn_format(result_buf, filename, dir, "", flags) == NULL)
220 DBUG_RETURN(2);
221 DBUG_PRINT("return", ("result: %s", result_buf));
222 DBUG_RETURN(0);
223 }
224
225 /*
226 Process config files in default directories.
227
228 SYNOPSIS
229 my_search_option_files()
230 conf_file Basename for configuration file to search for.
231 If this is a path, then only this file is read.
232 argc Pointer to argc of original program
233 argv Pointer to argv of original program
234 args_used Pointer to variable for storing the number of
235 arguments used.
236 func Pointer to the function to process options
237 func_ctx It's context. Usually it is the structure to
238 store additional options.
239 default_directories List of default directories.
240 found_no_defaults TRUE, if --no-defaults is specified.
241
242 DESCRIPTION
243 Process the default options from argc & argv
244 Read through each found config file looks and calls 'func' to process
245 each option. This function also reads options from login file.
246
247 NOTES
248 --defaults-group-suffix is only processed if we are called from
249 load_defaults().
250
251
252 RETURN
253 0 ok
254 1 given cinf_file doesn't exist
255 2 out of memory
256 3 Can't get current working directory
257
258 The global variable 'my_defaults_group_suffix' is updated with value for
259 --defaults_group_suffix
260 */
261
my_search_option_files(const char * conf_file,int * argc,char *** argv,uint * args_used,Process_option_func func,void * func_ctx,const char ** default_directories,my_bool is_login_file,my_bool found_no_defaults)262 int my_search_option_files(const char *conf_file, int *argc, char ***argv,
263 uint *args_used, Process_option_func func,
264 void *func_ctx, const char **default_directories,
265 my_bool is_login_file, my_bool found_no_defaults)
266 {
267 const char **dirs, *forced_default_file, *forced_extra_defaults;
268 int error= 0;
269 DBUG_ENTER("my_search_option_files");
270
271 /* Skip for login file. */
272 if (! is_login_file)
273 {
274 /* Check if we want to force the use a specific default file */
275 *args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
276 (char **) &forced_default_file,
277 (char **) &forced_extra_defaults,
278 (char **) &my_defaults_group_suffix,
279 (char **) &my_login_path, found_no_defaults);
280
281 if (! my_defaults_group_suffix)
282 my_defaults_group_suffix= getenv("MYSQL_GROUP_SUFFIX");
283
284 if (forced_extra_defaults && !defaults_already_read)
285 {
286 int error= fn_expand(forced_extra_defaults,
287 my_defaults_extra_file_buffer);
288 if (error)
289 DBUG_RETURN(error);
290
291 my_defaults_extra_file= my_defaults_extra_file_buffer;
292 }
293
294 if (forced_default_file && !defaults_already_read)
295 {
296 int error= fn_expand(forced_default_file, my_defaults_file_buffer);
297 if (error)
298 DBUG_RETURN(error);
299 my_defaults_file= my_defaults_file_buffer;
300 }
301
302 defaults_already_read= TRUE;
303
304 /*
305 We can only handle 'defaults-group-suffix' if we are called from
306 load_defaults() as otherwise we can't know the type of 'func_ctx'
307 */
308
309 if (my_defaults_group_suffix && func == handle_default_option)
310 {
311 /* Handle --defaults-group-suffix= */
312 uint i;
313 const char **extra_groups;
314 const size_t instance_len= strlen(my_defaults_group_suffix);
315 struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
316 char *ptr;
317 TYPELIB *group= ctx->group;
318
319 if (!(extra_groups=
320 (const char**)alloc_root(ctx->alloc,
321 (2*group->count+1)*sizeof(char*))))
322 DBUG_RETURN(2);
323
324 for (i= 0; i < group->count; i++)
325 {
326 size_t len;
327 extra_groups[i]= group->type_names[i]; /** copy group */
328
329 len= strlen(extra_groups[i]);
330 if (!(ptr= (char *) alloc_root(ctx->alloc,
331 (uint) (len + instance_len + 1))))
332 DBUG_RETURN(2);
333
334 extra_groups[i+group->count]= ptr;
335
336 /** Construct new group */
337 memcpy(ptr, extra_groups[i], len);
338 memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
339 }
340
341 group->count*= 2;
342 group->type_names= extra_groups;
343 group->type_names[group->count]= 0;
344 }
345 }
346 else if (my_login_path && func == handle_default_option)
347 {
348 /* Handle --login_path= */
349 uint i;
350 size_t len;
351 const char **extra_groups;
352 size_t instance_len= 0;
353 struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
354 char *ptr;
355 TYPELIB *group= ctx->group;
356
357 if (!(extra_groups= (const char**)alloc_root(ctx->alloc,
358 (group->count + 3)
359 * sizeof(char *))))
360 DBUG_RETURN(2);
361
362 for (i= 0; i < group->count; i++)
363 {
364 extra_groups[i]= group->type_names[i]; /** copy group */
365 }
366
367 extra_groups[i]= my_login_path;
368
369 if (my_defaults_group_suffix && func == handle_default_option)
370 {
371 instance_len= strlen(my_defaults_group_suffix);
372 len= strlen(extra_groups[i]);
373
374 if (!(ptr= (char *) alloc_root(ctx->alloc,
375 (uint) (len + instance_len + 1))))
376 DBUG_RETURN(2);
377
378 extra_groups[i + 1]= ptr;
379
380 /** Construct new group */
381 memcpy(ptr, extra_groups[i], len);
382 memcpy(ptr+len, my_defaults_group_suffix, instance_len + 1);
383 group->count += 1;
384 }
385
386 group->count += 1;
387 group->type_names= extra_groups;
388 group->type_names[group->count]= 0;
389 }
390
391 // If conf_file is an absolute path, we only read it
392 if (dirname_length(conf_file))
393 {
394 if ((error= search_default_file(func, func_ctx, NullS, conf_file,
395 is_login_file)) < 0)
396 goto err;
397 }
398 // If my defaults file is set (from a previous run), we read it
399 else if (my_defaults_file)
400 {
401 if ((error= search_default_file_with_ext(func, func_ctx, "", "",
402 my_defaults_file, 0,
403 is_login_file)) < 0)
404 goto err;
405 if (error > 0)
406 {
407 fprintf(stderr, "Could not open required defaults file: %s\n",
408 my_defaults_file);
409 goto err;
410 }
411 }
412 else if (! found_no_defaults)
413 {
414 for (dirs= default_directories ; *dirs; dirs++)
415 {
416 if (**dirs)
417 {
418 if (search_default_file(func, func_ctx, *dirs, conf_file,
419 is_login_file) < 0)
420 goto err;
421 }
422 else if (my_defaults_extra_file)
423 {
424 if ((error= search_default_file_with_ext(func, func_ctx, "", "",
425 my_defaults_extra_file, 0,
426 is_login_file)) < 0)
427 goto err; /* Fatal error */
428 if (error > 0)
429 {
430 fprintf(stderr, "Could not open required defaults file: %s\n",
431 my_defaults_extra_file);
432 goto err;
433 }
434 }
435 }
436 }
437
438 DBUG_RETURN(0);
439
440 err:
441 fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
442 DBUG_RETURN(1);
443 }
444
445
446 /*
447 The option handler for load_defaults.
448
449 SYNOPSIS
450 handle_deault_option()
451 in_ctx Handler context. In this case it is a
452 handle_option_ctx structure.
453 group_name The name of the group the option belongs to.
454 option The very option to be processed. It is already
455 prepared to be used in argv (has -- prefix). If it
456 is NULL, we are handling a new group (section).
457
458 DESCRIPTION
459 This handler checks whether a group is one of the listed and adds an option
460 to the array if yes. Some other handler can record, for instance, all
461 groups and their options, not knowing in advance the names and amount of
462 groups.
463
464 RETURN
465 0 - ok
466 1 - error occured
467 */
468
handle_default_option(void * in_ctx,const char * group_name,const char * option)469 static int handle_default_option(void *in_ctx, const char *group_name,
470 const char *option)
471 {
472 char *tmp;
473 struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
474
475 if (!option)
476 return 0;
477
478 if (find_type((char *)group_name, ctx->group, FIND_TYPE_NO_PREFIX))
479 {
480 if (!(tmp= (char *) alloc_root(ctx->alloc, strlen(option) + 1)))
481 return 1;
482 if (insert_dynamic(ctx->args, &tmp))
483 return 1;
484 strmov(tmp, option);
485 }
486
487 return 0;
488 }
489
490
491 /*
492 Gets options from the command line, however if --no-defaults
493 option is used, --defaults-file & --defaults-extra-file options
494 would be ignored.
495
496 SYNOPSIS
497 get_defaults_options()
498 argc Pointer to argc of original program
499 argv Pointer to argv of original program
500 defaults --defaults-file option
501 extra_defaults --defaults-extra-file option
502 group_suffix --defaults-group-suffix option
503 login_path --login-path option
504
505 RETURN
506 # Number of arguments used from *argv
507 defaults and extra_defaults will be set to option of the appropriate
508 items of argv array, or to NULL if there are no such options
509 */
510
get_defaults_options(int argc,char ** argv,char ** defaults,char ** extra_defaults,char ** group_suffix,char ** login_path,my_bool found_no_defaults)511 int get_defaults_options(int argc, char **argv,
512 char **defaults,
513 char **extra_defaults,
514 char **group_suffix,
515 char **login_path,
516 my_bool found_no_defaults)
517 {
518 int org_argc= argc, prev_argc= 0, default_option_count= 0;
519 *defaults= *extra_defaults= *group_suffix= *login_path= 0;
520
521 while (argc >= 2 && argc != prev_argc)
522 {
523 /* Skip program name or previously handled argument */
524 argv++;
525 prev_argc= argc; /* To check if we found */
526 /* --no-defaults is always the first option. */
527 if (is_prefix(*argv,"--no-defaults") && ! default_option_count)
528 {
529 argc--;
530 default_option_count ++;
531 continue;
532 }
533 if (!*defaults && is_prefix(*argv, "--defaults-file=") && ! found_no_defaults)
534 {
535 *defaults= *argv + sizeof("--defaults-file=")-1;
536 argc--;
537 default_option_count ++;
538 continue;
539 }
540 if (!*extra_defaults && is_prefix(*argv, "--defaults-extra-file=")
541 && ! found_no_defaults)
542 {
543 *extra_defaults= *argv + sizeof("--defaults-extra-file=")-1;
544 argc--;
545 default_option_count ++;
546 continue;
547 }
548 if (!*group_suffix && is_prefix(*argv, "--defaults-group-suffix="))
549 {
550 *group_suffix= *argv + sizeof("--defaults-group-suffix=")-1;
551 argc--;
552 default_option_count ++;
553 continue;
554 }
555 if (!*login_path && is_prefix(*argv, "--login-path="))
556 {
557 *login_path= *argv + sizeof("--login-path=")-1;
558 argc--;
559 default_option_count ++;
560 continue;
561 }
562 }
563 return org_argc - argc;
564 }
565
566 /*
567 Wrapper around my_load_defaults() for interface compatibility.
568
569 SYNOPSIS
570 load_defaults()
571 conf_file Basename for configuration file to search for.
572 If this is a path, then only this file is read.
573 groups Which [group] entrys to read.
574 Points to an null terminated array of pointers
575 argc Pointer to argc of original program
576 argv Pointer to argv of original program
577
578 NOTES
579
580 This function is NOT thread-safe as it uses a global pointer internally.
581 See also notes for my_load_defaults().
582
583 RETURN
584 0 ok
585 1 The given conf_file didn't exists
586 */
load_defaults(const char * conf_file,const char ** groups,int * argc,char *** argv)587 int load_defaults(const char *conf_file, const char **groups,
588 int *argc, char ***argv)
589 {
590 return my_load_defaults(conf_file, groups, argc, argv, &default_directories);
591 }
592
593 /** A global to turn off or on reading the mylogin file. On by default */
594 my_bool my_defaults_read_login_file= TRUE;
595 /*
596 Read options from configurations files
597
598 SYNOPSIS
599 my_load_defaults()
600 conf_file Basename for configuration file to search for.
601 If this is a path, then only this file is read.
602 groups Which [group] entrys to read.
603 Points to an null terminated array of pointers
604 argc Pointer to argc of original program
605 argv Pointer to argv of original program
606 default_directories Pointer to a location where a pointer to the list
607 of default directories will be stored
608
609 IMPLEMENTATION
610
611 Read options from configuration files and put them BEFORE the arguments
612 that are already in argc and argv. This way the calling program can
613 easily command line options override options in configuration files
614
615 NOTES
616 In case of fatal error, the function will print a warning and do
617 exit(1)
618
619 To free used memory one should call free_defaults() with the argument
620 that was put in *argv
621
622 RETURN
623 - If successful, 0 is returned. If 'default_directories' is not NULL,
624 a pointer to the array of default directory paths is stored to a location
625 it points to. That stored value must be passed to my_search_option_files()
626 later.
627
628 - 1 is returned if the given conf_file didn't exist. In this case, the
629 value pointed to by default_directories is undefined.
630 */
631
632
my_load_defaults(const char * conf_file,const char ** groups,int * argc,char *** argv,const char *** default_directories)633 int my_load_defaults(const char *conf_file, const char **groups,
634 int *argc, char ***argv, const char ***default_directories)
635 {
636 DYNAMIC_ARRAY args;
637 TYPELIB group;
638 my_bool found_print_defaults= 0;
639 uint args_used= 0;
640 int error= 0;
641 MEM_ROOT alloc;
642 char *ptr,**res;
643 struct handle_option_ctx ctx;
644 const char **dirs;
645 char my_login_file[FN_REFLEN];
646 my_bool found_no_defaults= false;
647 uint args_sep= my_getopt_use_args_separator ? 1 : 0;
648 DBUG_ENTER("load_defaults");
649
650 init_alloc_root(&alloc,512,0);
651 if ((dirs= init_default_directories(&alloc)) == NULL)
652 goto err;
653 /*
654 Check if the user doesn't want any default option processing
655 --no-defaults is always the first option
656 */
657 if (*argc >= 2 && !strcmp(argv[0][1], "--no-defaults"))
658 found_no_defaults= TRUE;
659
660 group.count=0;
661 group.name= "defaults";
662 group.type_names= groups;
663
664 for (; *groups ; groups++)
665 group.count++;
666
667 if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
668 goto err;
669
670 ctx.alloc= &alloc;
671 ctx.args= &args;
672 ctx.group= &group;
673
674 if ((error= my_search_option_files(conf_file, argc, argv,
675 &args_used, handle_default_option,
676 (void *) &ctx, dirs, false, found_no_defaults)))
677 {
678 delete_dynamic(&args);
679 free_root(&alloc,MYF(0));
680 DBUG_RETURN(error);
681 }
682
683 if (my_defaults_read_login_file)
684 {
685 /* Read options from login group. */
686 if (my_default_get_login_file(my_login_file, sizeof(my_login_file)) &&
687 (error= my_search_option_files(my_login_file, argc, argv, &args_used,
688 handle_default_option, (void *) &ctx,
689 dirs, true, found_no_defaults)))
690 {
691 delete_dynamic(&args);
692 free_root(&alloc, MYF(0));
693 DBUG_RETURN(error);
694 }
695 }
696
697 /*
698 Here error contains <> 0 only if we have a fully specified conf_file
699 or a forced default file
700 */
701 if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
702 (args.elements + *argc + 1 + args_sep) *sizeof(char*))))
703 {
704 delete_dynamic(&args);
705 goto err;
706 }
707 res= (char**) (ptr+sizeof(alloc));
708
709 /* copy name + found arguments + command line arguments to new array */
710 res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */
711 memcpy((uchar*) (res+1), args.buffer, args.elements*sizeof(char*));
712 /* Skip --defaults-xxx options */
713 (*argc)-= args_used;
714 (*argv)+= args_used;
715
716 /*
717 Check if we wan't to see the new argument list
718 This options must always be the last of the default options
719 */
720 if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
721 {
722 found_print_defaults=1;
723 --*argc; ++*argv; /* skip argument */
724 }
725
726 if (my_getopt_use_args_separator)
727 {
728 /* set arguments separator for arguments from config file and
729 command line */
730 set_args_separator(&res[args.elements+1]);
731 }
732
733 if (*argc)
734 memcpy((uchar*) (res+1+args.elements+args_sep), (char*) ((*argv)+1),
735 (*argc-1)*sizeof(char*));
736 res[args.elements+ *argc+args_sep]=0; /* last null */
737
738 (*argc)+=args.elements+args_sep;
739 *argv= (char**) res;
740 *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
741 delete_dynamic(&args);
742
743 if (default_directories)
744 *default_directories= dirs;
745
746 if (found_no_defaults)
747 DBUG_RETURN(0);
748
749 if (found_print_defaults)
750 {
751 int i;
752 printf("%s would have been started with the following arguments:\n",
753 **argv);
754 for (i=1 ; i < *argc ; i++)
755 if (!my_getopt_is_args_separator((*argv)[i])) /* skip arguments separator */
756 printf("%s ", (*argv)[i]);
757 puts("");
758 exit(0);
759 }
760
761 DBUG_RETURN(0);
762
763 err:
764 fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
765 exit(1);
766 DBUG_RETURN(0); /* Keep compiler happy */
767 }
768
769
free_defaults(char ** argv)770 void free_defaults(char **argv)
771 {
772 MEM_ROOT ptr;
773 memcpy(&ptr, ((char *) argv) - sizeof(ptr), sizeof(ptr));
774 free_root(&ptr,MYF(0));
775 }
776
777
search_default_file(Process_option_func opt_handler,void * handler_ctx,const char * dir,const char * config_file,my_bool is_login_file)778 static int search_default_file(Process_option_func opt_handler,
779 void *handler_ctx,
780 const char *dir,
781 const char *config_file,
782 my_bool is_login_file)
783 {
784 char **ext;
785 const char *empty_list[]= { "", 0 };
786 my_bool have_ext= fn_ext(config_file)[0] != 0;
787 const char **exts_to_use= have_ext ? empty_list : f_extensions;
788
789 for (ext= (char**) exts_to_use; *ext; ext++)
790 {
791 int error;
792 if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
793 dir, *ext,
794 config_file, 0, is_login_file)) < 0)
795 return error;
796 }
797 return 0;
798 }
799
800
801 /*
802 Skip over keyword and get argument after keyword
803
804 SYNOPSIS
805 get_argument()
806 keyword Include directive keyword
807 kwlen Length of keyword
808 ptr Pointer to the keword in the line under process
809 line line number
810
811 RETURN
812 0 error
813 # Returns pointer to the argument after the keyword.
814 */
815
get_argument(const char * keyword,size_t kwlen,char * ptr,char * name,uint line)816 static char *get_argument(const char *keyword, size_t kwlen,
817 char *ptr, char *name, uint line)
818 {
819 char *end;
820
821 /* Skip over "include / includedir keyword" and following whitespace */
822
823 for (ptr+= kwlen - 1;
824 my_isspace(&my_charset_latin1, ptr[0]);
825 ptr++)
826 {}
827
828 /*
829 Trim trailing whitespace from directory name
830 The -1 below is for the newline added by fgets()
831 Note that my_isspace() is true for \r and \n
832 */
833 for (end= ptr + strlen(ptr) - 1;
834 my_isspace(&my_charset_latin1, *(end - 1));
835 end--)
836 {}
837 end[0]= 0; /* Cut off end space */
838
839 /* Print error msg if there is nothing after !include* directive */
840 if (end <= ptr)
841 {
842 fprintf(stderr,
843 "error: Wrong '!%s' directive in config file: %s at line %d\n",
844 keyword, name, line);
845 return 0;
846 }
847 return ptr;
848 }
849
850
851 /*
852 Open a configuration file (if exists) and read given options from it
853
854 SYNOPSIS
855 search_default_file_with_ext()
856 opt_handler Option handler function. It is used to process
857 every separate option.
858 handler_ctx Pointer to the structure to store actual
859 parameters of the function.
860 dir directory to read
861 ext Extension for configuration file
862 config_file Name of configuration file
863 group groups to read
864 recursion_level the level of recursion, got while processing
865 "!include" or "!includedir"
866 is_login_file TRUE, when login file is being processed.
867
868 RETURN
869 0 Success
870 -1 Fatal error, abort
871 1 File not found (Warning)
872 */
873
search_default_file_with_ext(Process_option_func opt_handler,void * handler_ctx,const char * dir,const char * ext,const char * config_file,int recursion_level,my_bool is_login_file)874 static int search_default_file_with_ext(Process_option_func opt_handler,
875 void *handler_ctx,
876 const char *dir,
877 const char *ext,
878 const char *config_file,
879 int recursion_level,
880 my_bool is_login_file)
881 {
882 char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
883 char *value, option[4096+2], tmp[FN_REFLEN];
884 static const char includedir_keyword[]= "includedir";
885 static const char include_keyword[]= "include";
886 const int max_recursion_level= 10;
887 MYSQL_FILE *fp;
888 uint line=0;
889 my_bool found_group=0;
890 uint i, rc;
891 MY_DIR *search_dir;
892 FILEINFO *search_file;
893
894 if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
895 return 0; /* Ignore wrong paths */
896 if (dir)
897 {
898 end=convert_dirname(name, dir, NullS);
899 if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
900 *end++='.';
901 strxmov(end,config_file,ext,NullS);
902 }
903 else
904 {
905 strmov(name,config_file);
906 }
907 fn_format(name,name,"","",4);
908
909 if ((rc= check_file_permissions(name, is_login_file)) < 2)
910 return (int) rc;
911
912 if (is_login_file)
913 {
914 if ( !(fp = mysql_file_fopen(key_file_cnf, name, (O_RDONLY | O_BINARY),
915 MYF(0))))
916 return 1; /* Ignore wrong files. */
917 }
918 else
919 {
920 if ( !(fp = mysql_file_fopen(key_file_cnf, name, O_RDONLY, MYF(0))))
921 return 1; /* Ignore wrong files */
922 }
923
924 while (mysql_file_getline(buff, sizeof(buff) - 1, fp, is_login_file))
925 {
926 line++;
927 /* Ignore comment and empty lines */
928 for (ptr= buff; my_isspace(&my_charset_latin1, *ptr); ptr++)
929 {}
930
931 if (*ptr == '#' || *ptr == ';' || !*ptr)
932 continue;
933
934 /* Configuration File Directives */
935 if (*ptr == '!')
936 {
937 if (recursion_level >= max_recursion_level)
938 {
939 for (end= ptr + strlen(ptr) - 1;
940 my_isspace(&my_charset_latin1, *(end - 1));
941 end--)
942 {}
943 end[0]= 0;
944 fprintf(stderr,
945 "Warning: skipping '%s' directive as maximum include"
946 "recursion level was reached in file %s at line %d\n",
947 ptr, name, line);
948 continue;
949 }
950
951 /* skip over `!' and following whitespace */
952 for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++)
953 {}
954
955 if ((!strncmp(ptr, includedir_keyword,
956 sizeof(includedir_keyword) - 1)) &&
957 my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1]))
958 {
959 if (!(ptr= get_argument(includedir_keyword,
960 sizeof(includedir_keyword),
961 ptr, name, line)))
962 goto err;
963
964 if (!(search_dir= my_dir(ptr, MYF(MY_WME))))
965 goto err;
966
967 for (i= 0; i < (uint) search_dir->number_off_files; i++)
968 {
969 search_file= search_dir->dir_entry + i;
970 ext= fn_ext(search_file->name);
971
972 /* check extension */
973 for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
974 {
975 if (!strcmp(ext, *tmp_ext))
976 break;
977 }
978
979 if (*tmp_ext)
980 {
981 fn_format(tmp, search_file->name, ptr, "",
982 MY_UNPACK_FILENAME | MY_SAFE_PATH);
983
984 search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp,
985 recursion_level + 1, is_login_file);
986 }
987 }
988
989 my_dirend(search_dir);
990 }
991 else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
992 my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1]))
993 {
994 if (!(ptr= get_argument(include_keyword,
995 sizeof(include_keyword), ptr,
996 name, line)))
997 goto err;
998
999 search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
1000 recursion_level + 1, is_login_file);
1001 }
1002
1003 continue;
1004 }
1005
1006 if (*ptr == '[') /* Group name */
1007 {
1008 found_group=1;
1009 if (!(end=(char *) strchr(++ptr,']')))
1010 {
1011 fprintf(stderr,
1012 "error: Wrong group definition in config file: %s at line %d\n",
1013 name,line);
1014 goto err;
1015 }
1016 /* Remove end space */
1017 for ( ; my_isspace(&my_charset_latin1, end[-1]); end --)
1018 {}
1019
1020 end[0]=0;
1021
1022 strmake(curr_gr, ptr, MY_MIN((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
1023
1024 /* signal that a new group is found */
1025 opt_handler(handler_ctx, curr_gr, NULL);
1026
1027 continue;
1028 }
1029 if (!found_group)
1030 {
1031 fprintf(stderr,
1032 "error: Found option without preceding group in config file: %s at line: %d\n",
1033 name,line);
1034 goto err;
1035 }
1036
1037
1038 end= remove_end_comment(ptr);
1039 if ((value= strchr(ptr, '=')))
1040 end= value; /* Option without argument */
1041 for ( ; my_isspace(&my_charset_latin1, end[-1]) ; end--)
1042 {}
1043
1044 if (!value)
1045 {
1046 strmake(strmov(option,"--"),ptr, (size_t) (end-ptr));
1047 if (opt_handler(handler_ctx, curr_gr, option))
1048 goto err;
1049 }
1050 else
1051 {
1052 /* Remove pre- and end space */
1053 char *value_end;
1054 for (value++ ; my_isspace(&my_charset_latin1, *value); value ++)
1055 {}
1056
1057 value_end=strend(value);
1058 /*
1059 We don't have to test for value_end >= value as we know there is
1060 an '=' before
1061 */
1062 for ( ; my_isspace(&my_charset_latin1, value_end[-1]); value_end --)
1063 {}
1064
1065 if (value_end < value) /* Empty string */
1066 value_end=value;
1067
1068 /* remove quotes around argument */
1069 if ((*value == '\"' || *value == '\'') && /* First char is quote */
1070 (value + 1 < value_end ) && /* String is longer than 1 */
1071 *value == value_end[-1] ) /* First char is equal to last char */
1072 {
1073 value++;
1074 value_end--;
1075 }
1076 ptr=strnmov(strmov(option,"--"),ptr,(size_t) (end-ptr));
1077 *ptr++= '=';
1078
1079 for ( ; value != value_end; value++)
1080 {
1081 if (*value == '\\' && value != value_end-1)
1082 {
1083 switch(*++value) {
1084 case 'n':
1085 *ptr++='\n';
1086 break;
1087 case 't':
1088 *ptr++= '\t';
1089 break;
1090 case 'r':
1091 *ptr++ = '\r';
1092 break;
1093 case 'b':
1094 *ptr++ = '\b';
1095 break;
1096 case 's':
1097 *ptr++= ' '; /* space */
1098 break;
1099 case '\"':
1100 *ptr++= '\"';
1101 break;
1102 case '\'':
1103 *ptr++= '\'';
1104 break;
1105 case '\\':
1106 *ptr++= '\\';
1107 break;
1108 default: /* Unknown; Keep '\' */
1109 *ptr++= '\\';
1110 *ptr++= *value;
1111 break;
1112 }
1113 }
1114 else
1115 *ptr++= *value;
1116 }
1117 *ptr=0;
1118 if (opt_handler(handler_ctx, curr_gr, option))
1119 goto err;
1120 }
1121 }
1122 mysql_file_fclose(fp, MYF(0));
1123 return(0);
1124
1125 err:
1126 mysql_file_fclose(fp, MYF(0));
1127 return -1; /* Fatal error */
1128 }
1129
1130
remove_end_comment(char * ptr)1131 static char *remove_end_comment(char *ptr)
1132 {
1133 char quote= 0; /* we are inside quote marks */
1134 char escape= 0; /* symbol is protected by escape chagacter */
1135
1136 for (; *ptr; ptr++)
1137 {
1138 if ((*ptr == '\'' || *ptr == '\"') && !escape)
1139 {
1140 if (!quote)
1141 quote= *ptr;
1142 else if (quote == *ptr)
1143 quote= 0;
1144 }
1145 /* We are not inside a string */
1146 if (!quote && *ptr == '#')
1147 {
1148 *ptr= 0;
1149 return ptr;
1150 }
1151 escape= (quote && *ptr == '\\' && !escape);
1152 }
1153 return ptr;
1154 }
1155
1156
1157 /**
1158 Read one line from the specified file. In case
1159 of scrambled login file, the line read is first
1160 decrypted and then returned.
1161
1162 @param str [out] Buffer to store the read text.
1163 @param size [in] At max, size-1 bytes to be read.
1164 @param file [in] Source file.
1165 @param is_login_file [in] TRUE, when login file is being processed.
1166
1167 @return 1 Success
1168 0 Error
1169 */
1170
mysql_file_getline(char * str,int size,MYSQL_FILE * file,my_bool is_login_file)1171 static my_bool mysql_file_getline(char *str, int size, MYSQL_FILE *file,
1172 my_bool is_login_file)
1173 {
1174 uchar cipher[4096], len_buf[MAX_CIPHER_STORE_LEN];
1175 static unsigned char my_key[LOGIN_KEY_LEN];
1176 int length= 0, cipher_len= 0;
1177
1178 if (is_login_file)
1179 {
1180 if (mysql_file_ftell(file, MYF(MY_WME)) == 0)
1181 {
1182 /* Move past unused bytes. */
1183 mysql_file_fseek(file, 4, SEEK_SET, MYF(MY_WME));
1184 if (mysql_file_fread(file, my_key, LOGIN_KEY_LEN,
1185 MYF(MY_WME)) != LOGIN_KEY_LEN)
1186 return 0;
1187 }
1188
1189 if (mysql_file_fread(file, len_buf, MAX_CIPHER_STORE_LEN,
1190 MYF(MY_WME)) == MAX_CIPHER_STORE_LEN)
1191 {
1192 cipher_len= sint4korr(len_buf);
1193 if (cipher_len > size)
1194 return 0;
1195 }
1196 else
1197 return 0;
1198
1199 mysql_file_fread(file, cipher, cipher_len, MYF(MY_WME));
1200 if ((length= my_aes_decrypt(cipher, cipher_len, (unsigned char *) str,
1201 my_key, LOGIN_KEY_LEN, my_aes_128_ecb, NULL)) < 0)
1202 {
1203 /* Attempt to decrypt failed. */
1204 return 0;
1205 }
1206 str[length]= 0;
1207 return 1;
1208 }
1209 else
1210 {
1211 if (mysql_file_fgets(str, size, file))
1212 return 1;
1213 else
1214 return 0;
1215 }
1216 }
1217
1218
my_print_default_files(const char * conf_file)1219 void my_print_default_files(const char *conf_file)
1220 {
1221 const char *empty_list[]= { "", 0 };
1222 my_bool have_ext= fn_ext(conf_file)[0] != 0;
1223 const char **exts_to_use= have_ext ? empty_list : f_extensions;
1224 char name[FN_REFLEN], **ext;
1225
1226 puts("\nDefault options are read from the following files in the given order:");
1227
1228 if (dirname_length(conf_file))
1229 fputs(conf_file,stdout);
1230 else
1231 {
1232 const char **dirs;
1233 MEM_ROOT alloc;
1234 init_alloc_root(&alloc,512,0);
1235
1236 if ((dirs= init_default_directories(&alloc)) == NULL)
1237 {
1238 fputs("Internal error initializing default directories list", stdout);
1239 }
1240 else
1241 {
1242 for ( ; *dirs; dirs++)
1243 {
1244 for (ext= (char**) exts_to_use; *ext; ext++)
1245 {
1246 const char *pos;
1247 char *end;
1248 if (**dirs)
1249 pos= *dirs;
1250 else if (my_defaults_extra_file)
1251 pos= my_defaults_extra_file;
1252 else
1253 continue;
1254 end= convert_dirname(name, pos, NullS);
1255 if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
1256 *end++= '.';
1257
1258 if (my_defaults_extra_file == pos)
1259 end[(strlen(end)-1)] = ' ';
1260 else
1261 strxmov(end, conf_file, *ext , " ", NullS);
1262 fputs(name, stdout);
1263 }
1264 }
1265 }
1266
1267 free_root(&alloc, MYF(0));
1268 }
1269 puts("");
1270 }
1271
print_defaults(const char * conf_file,const char ** groups)1272 void print_defaults(const char *conf_file, const char **groups)
1273 {
1274 const char **groups_save= groups;
1275 my_print_default_files(conf_file);
1276
1277 fputs("The following groups are read:",stdout);
1278 for ( ; *groups ; groups++)
1279 {
1280 fputc(' ',stdout);
1281 fputs(*groups,stdout);
1282 }
1283
1284 if (my_defaults_group_suffix)
1285 {
1286 groups= groups_save;
1287 for ( ; *groups ; groups++)
1288 {
1289 fputc(' ',stdout);
1290 fputs(*groups,stdout);
1291 fputs(my_defaults_group_suffix,stdout);
1292 }
1293 }
1294 puts("\nThe following options may be given as the first argument:\n\
1295 --print-defaults Print the program argument list and exit.\n\
1296 --no-defaults Don't read default options from any option file,\n\
1297 except for login file.\n\
1298 --defaults-file=# Only read default options from the given file #.\n\
1299 --defaults-extra-file=# Read this file after the global files are read.\n\
1300 --defaults-group-suffix=#\n\
1301 Also read groups with concat(group, suffix)\n\
1302 --login-path=# Read this path from the login file.");
1303 }
1304
1305
add_directory(MEM_ROOT * alloc,const char * dir,const char ** dirs)1306 static int add_directory(MEM_ROOT *alloc, const char *dir, const char **dirs)
1307 {
1308 char buf[FN_REFLEN];
1309 size_t len;
1310 char *p;
1311 my_bool err MY_ATTRIBUTE((unused));
1312
1313 len= normalize_dirname(buf, dir);
1314 if (!(p= strmake_root(alloc, buf, len)))
1315 return 1; /* Failure */
1316 /* Should never fail if DEFAULT_DIRS_SIZE is correct size */
1317 err= array_append_string_unique(p, dirs, DEFAULT_DIRS_SIZE);
1318 DBUG_ASSERT(err == FALSE);
1319
1320 return 0;
1321 }
1322
1323
1324 #ifdef __WIN__
1325 /*
1326 This wrapper for GetSystemWindowsDirectory() will dynamically bind to the
1327 function if it is available, emulate it on NT4 Terminal Server by stripping
1328 the \SYSTEM32 from the end of the results of GetSystemDirectory(), or just
1329 return GetSystemDirectory().
1330 */
1331
1332 typedef UINT (WINAPI *GET_SYSTEM_WINDOWS_DIRECTORY)(LPSTR, UINT);
1333
my_get_system_windows_directory(char * buffer,size_t size)1334 static size_t my_get_system_windows_directory(char *buffer, size_t size)
1335 {
1336 size_t count;
1337 GET_SYSTEM_WINDOWS_DIRECTORY
1338 func_ptr= (GET_SYSTEM_WINDOWS_DIRECTORY)
1339 GetProcAddress(GetModuleHandle("kernel32.dll"),
1340 "GetSystemWindowsDirectoryA");
1341
1342 if (func_ptr)
1343 return func_ptr(buffer, (uint) size);
1344
1345 /*
1346 Windows NT 4.0 Terminal Server Edition:
1347 To retrieve the shared Windows directory, call GetSystemDirectory and
1348 trim the "System32" element from the end of the returned path.
1349 */
1350 count= GetSystemDirectory(buffer, (uint) size);
1351 if (count > 8 && stricmp(buffer+(count-8), "\\System32") == 0)
1352 {
1353 count-= 8;
1354 buffer[count] = '\0';
1355 }
1356 return count;
1357 }
1358
1359
my_get_module_parent(char * buf,size_t size)1360 static const char *my_get_module_parent(char *buf, size_t size)
1361 {
1362 char *last= NULL;
1363 char *end;
1364 if (!GetModuleFileName(NULL, buf, (DWORD) size))
1365 return NULL;
1366 end= strend(buf);
1367
1368 /*
1369 Look for the second-to-last \ in the filename, but hang on
1370 to a pointer after the last \ in case we're in the root of
1371 a drive.
1372 */
1373 for ( ; end > buf; end--)
1374 {
1375 if (*end == FN_LIBCHAR)
1376 {
1377 if (last)
1378 {
1379 /* Keep the last '\' as this works both with D:\ and a directory */
1380 end[1]= 0;
1381 break;
1382 }
1383 last= end;
1384 }
1385 }
1386
1387 return buf;
1388 }
1389 #endif /* __WIN__ */
1390
1391
init_default_directories(MEM_ROOT * alloc)1392 static const char **init_default_directories(MEM_ROOT *alloc)
1393 {
1394 const char **dirs;
1395 char *env;
1396 int errors= 0;
1397
1398 dirs= (const char **)alloc_root(alloc, DEFAULT_DIRS_SIZE * sizeof(char *));
1399 if (dirs == NULL)
1400 return NULL;
1401 memset(dirs, 0, DEFAULT_DIRS_SIZE * sizeof(char *));
1402
1403 #ifdef __WIN__
1404
1405 {
1406 char fname_buffer[FN_REFLEN];
1407 if (my_get_system_windows_directory(fname_buffer, sizeof(fname_buffer)))
1408 errors += add_directory(alloc, fname_buffer, dirs);
1409
1410 if (GetWindowsDirectory(fname_buffer, sizeof(fname_buffer)))
1411 errors += add_directory(alloc, fname_buffer, dirs);
1412
1413 errors += add_directory(alloc, "C:/", dirs);
1414
1415 if (my_get_module_parent(fname_buffer, sizeof(fname_buffer)) != NULL)
1416 errors += add_directory(alloc, fname_buffer, dirs);
1417 }
1418
1419 #else
1420
1421 errors += add_directory(alloc, "/etc/", dirs);
1422 errors += add_directory(alloc, "/etc/mysql/", dirs);
1423
1424 #if defined(DEFAULT_SYSCONFDIR)
1425 if (DEFAULT_SYSCONFDIR[0])
1426 {
1427 errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs);
1428 errors += add_directory(alloc, DEFAULT_SYSCONFDIR "/mysql", dirs);
1429 }
1430 #endif /* DEFAULT_SYSCONFDIR */
1431
1432 #endif
1433
1434 if ((env= getenv("MYSQL_HOME")))
1435 errors += add_directory(alloc, env, dirs);
1436
1437 /* Placeholder for --defaults-extra-file=<path> */
1438 errors += add_directory(alloc, "", dirs);
1439
1440 #if !defined(__WIN__)
1441 errors += add_directory(alloc, "~/", dirs);
1442 #endif
1443
1444 return (errors > 0 ? NULL : dirs);
1445 }
1446
1447 /**
1448 Place the login file name in the specified buffer.
1449
1450 @param file_name [out] Buffer to hold login file name
1451 @param file_name_size [in] Length of the buffer
1452
1453 @return 1 - Success
1454 0 - Failure
1455 */
1456
my_default_get_login_file(char * file_name,size_t file_name_size)1457 int my_default_get_login_file(char *file_name, size_t file_name_size)
1458 {
1459 size_t rc;
1460
1461 if (getenv("MYSQL_TEST_LOGIN_FILE"))
1462 rc= my_snprintf(file_name, file_name_size, "%s",
1463 getenv("MYSQL_TEST_LOGIN_FILE"));
1464 #ifdef _WIN32
1465 else if (getenv("APPDATA"))
1466 rc= my_snprintf(file_name, file_name_size, "%s\\MySQL\\.mylogin.cnf",
1467 getenv("APPDATA"));
1468 #else
1469 else if (getenv("HOME"))
1470 rc= my_snprintf(file_name, file_name_size, "%s/.mylogin.cnf",
1471 getenv("HOME"));
1472 #endif
1473 else
1474 {
1475 memset(file_name, 0, file_name_size);
1476 return 0;
1477 }
1478 /* Anything <= 0 will be treated as error. */
1479 if (rc <= 0)
1480 return 0;
1481
1482 return 1;
1483 }
1484
1485 /**
1486 Check file permissions of the option file.
1487
1488 @param file_name [in] Name of the option file.
1489 @param is_login_file [in] TRUE, when login file is being processed.
1490
1491 @return 0 - Non-allowable file permissions.
1492 1 - Failed to stat.
1493 2 - Success.
1494 */
check_file_permissions(const char * file_name,my_bool is_login_file)1495 int check_file_permissions(const char *file_name, my_bool is_login_file)
1496 {
1497 #if !defined(__WIN__)
1498 MY_STAT stat_info;
1499
1500 if (!my_stat(file_name,&stat_info,MYF(0)))
1501 return 0;
1502 /*
1503 Ignore .mylogin.cnf file if not exclusively readable/writable
1504 by current user.
1505 */
1506 if (is_login_file && (stat_info.st_mode & (S_IXUSR | S_IRWXG | S_IRWXO))
1507 && (stat_info.st_mode & S_IFMT) == S_IFREG)
1508 {
1509 fprintf(stderr, "Warning: %s should be readable/writable only by "
1510 "current user.\n", file_name);
1511 return 0;
1512 }
1513 /*
1514 Ignore world-writable regular files.
1515 This is mainly done to protect us to not read a file created by
1516 the mysqld server, but the check is still valid in most context.
1517 */
1518 else if ((stat_info.st_mode & S_IWOTH) &&
1519 (stat_info.st_mode & S_IFMT) == S_IFREG)
1520
1521 {
1522 fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
1523 file_name);
1524 return 0;
1525 }
1526 #endif
1527 return 2; /* Success */
1528 }
1529
1530