1
/* Copyright (C) 2000-2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/****************************************************************************
17
Add all options from files named "group".cnf from the default_directories
18
before the command line arguments.
19
On Windows defaults will also search in the Windows directory for a file
21
As long as the program uses the last argument for conflicting
22
options one only have to add a call to "load_defaults" to enable
23
use of default values.
24
pre- and end 'blank space' are removed from options and values. The
25
following escape sequences are recognized in values: \b \t \n \r \\
27
The following arguments are handled automaticly; If used, they must be
28
first argument on the command line!
29
--no-defaults ; no options are read.
30
--defaults-file=full-path-to-default-file ; Only this file will be read.
31
--defaults-extra-file=full-path-to-default-file ; Read this file before ~/
32
--defaults-group-suffix ; Also read groups with concat(group, suffix)
33
--print-defaults ; Print the modified command line and exit
34
****************************************************************************/
36
#include "mysys_priv.h"
37
#include <mystrings/m_string.h>
38
#include <mystrings/m_ctype.h>
39
#include <mysys/my_dir.h>
43
const char *my_defaults_file=0;
44
const char *my_defaults_group_suffix=0;
45
char *my_defaults_extra_file=0;
47
/* Which directories are searched for options (and in which order) */
49
#define MAX_DEFAULT_DIRS 6
50
const char *default_directories[MAX_DEFAULT_DIRS + 1];
52
static const char *f_extensions[]= { ".cnf", 0 };
54
static int handle_default_option(void *in_ctx, const char *group_name,
58
This structure defines the context that we pass to callback
59
function 'handle_default_option' used in search_default_file
60
to process each option. This context is used if search_default_file
61
was called from load_defaults.
64
struct handle_option_ctx
71
static int search_default_file(Process_option_func func, void *func_ctx,
72
const char *dir, const char *config_file);
73
static int search_default_file_with_ext(Process_option_func func,
75
const char *dir, const char *ext,
76
const char *config_file, int recursion_level);
81
Create the list of default directories.
84
On all systems, if a directory is already in the list, it will be moved
85
to the end of the list. This avoids reading defaults files multiple times,
86
while ensuring the correct precedence.
91
static void init_default_directories(void);
94
static char *remove_end_comment(char *ptr);
98
Process config files in default directories.
101
my_search_option_files()
102
conf_file Basename for configuration file to search for.
103
If this is a path, then only this file is read.
104
argc Pointer to argc of original program
105
argv Pointer to argv of original program
106
args_used Pointer to variable for storing the number of
108
func Pointer to the function to process options
109
func_ctx It's context. Usually it is the structure to
110
store additional options.
112
Process the default options from argc & argv
113
Read through each found config file looks and calls 'func' to process
117
--defaults-group-suffix is only processed if we are called from
123
1 given cinf_file doesn't exist
125
The global variable 'my_defaults_group_suffix' is updated with value for
126
--defaults_group_suffix
129
int my_search_option_files(const char *conf_file, int *argc, char ***argv,
130
uint32_t *args_used, Process_option_func func,
133
const char **dirs, *forced_default_file, *forced_extra_defaults;
136
/* Check if we want to force the use a specific default file */
137
*args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
138
(char **) &forced_default_file,
139
(char **) &forced_extra_defaults,
140
(char **) &my_defaults_group_suffix);
142
if (! my_defaults_group_suffix)
143
my_defaults_group_suffix= getenv(STRINGIFY_ARG(DEFAULT_GROUP_SUFFIX_ENV));
145
if (forced_extra_defaults)
146
my_defaults_extra_file= (char *) forced_extra_defaults;
148
if (forced_default_file)
149
my_defaults_file= forced_default_file;
152
We can only handle 'defaults-group-suffix' if we are called from
153
load_defaults() as otherwise we can't know the type of 'func_ctx'
156
if (my_defaults_group_suffix && func == handle_default_option)
158
/* Handle --defaults-group-suffix= */
160
const char **extra_groups;
161
const uint32_t instance_len= strlen(my_defaults_group_suffix);
162
struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
164
TYPELIB *group= ctx->group;
167
(const char**)alloc_root(ctx->alloc,
168
(2*group->count+1)*sizeof(char*))))
171
for (i= 0; i < group->count; i++)
174
extra_groups[i]= group->type_names[i]; /** copy group */
176
len= strlen(extra_groups[i]);
177
if (!(ptr= (char *)alloc_root(ctx->alloc, len+instance_len+1)))
180
extra_groups[i+group->count]= ptr;
182
/** Construct new group */
183
memcpy(ptr, extra_groups[i], len);
184
memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
188
group->type_names= extra_groups;
189
group->type_names[group->count]= 0;
192
if (forced_default_file)
194
if ((error= search_default_file_with_ext(func, func_ctx, "", "",
195
forced_default_file, 0)) < 0)
199
fprintf(stderr, "Could not open required defaults file: %s\n",
200
forced_default_file);
204
else if (dirname_length(conf_file))
206
if ((error= search_default_file(func, func_ctx, NULL, conf_file)) < 0)
211
for (dirs= default_directories ; *dirs; dirs++)
215
if (search_default_file(func, func_ctx, *dirs, conf_file) < 0)
218
else if (my_defaults_extra_file)
220
if ((error= search_default_file_with_ext(func, func_ctx, "", "",
221
my_defaults_extra_file, 0)) < 0)
222
goto err; /* Fatal error */
225
fprintf(stderr, "Could not open required defaults file: %s\n",
226
my_defaults_extra_file);
236
fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
238
return 0; /* Keep compiler happy */
243
The option handler for load_defaults.
246
handle_deault_option()
247
in_ctx Handler context. In this case it is a
248
handle_option_ctx structure.
249
group_name The name of the group the option belongs to.
250
option The very option to be processed. It is already
251
prepared to be used in argv (has -- prefix). If it
252
is NULL, we are handling a new group (section).
255
This handler checks whether a group is one of the listed and adds an option
256
to the array if yes. Some other handler can record, for instance, all
257
groups and their options, not knowing in advance the names and amount of
265
static int handle_default_option(void *in_ctx, const char *group_name,
269
struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
274
if (find_type((char *)group_name, ctx->group, 3))
276
if (!(tmp= (char *)alloc_root(ctx->alloc, strlen(option) + 1)))
278
if (insert_dynamic(ctx->args, (unsigned char*) &tmp))
280
my_stpcpy(tmp, option);
288
Gets options from the command line
291
get_defaults_options()
292
argc Pointer to argc of original program
293
argv Pointer to argv of original program
294
defaults --defaults-file option
295
extra_defaults --defaults-extra-file option
298
# Number of arguments used from *argv
299
defaults and extra_defaults will be set to option of the appropriate
300
items of argv array, or to NULL if there are no such options
303
int get_defaults_options(int argc, char **argv,
305
char **extra_defaults,
308
int org_argc= argc, prev_argc= 0;
309
*defaults= *extra_defaults= *group_suffix= 0;
311
while (argc >= 2 && argc != prev_argc)
313
/* Skip program name or previously handled argument */
315
prev_argc= argc; /* To check if we found */
316
if (!*defaults && is_prefix(*argv,"--defaults-file="))
318
*defaults= *argv + sizeof("--defaults-file=")-1;
322
if (!*extra_defaults && is_prefix(*argv,"--defaults-extra-file="))
324
*extra_defaults= *argv + sizeof("--defaults-extra-file=")-1;
328
if (!*group_suffix && is_prefix(*argv, "--defaults-group-suffix="))
330
*group_suffix= *argv + sizeof("--defaults-group-suffix=")-1;
335
return org_argc - argc;
340
Read options from configurations files
344
conf_file Basename for configuration file to search for.
345
If this is a path, then only this file is read.
346
groups Which [group] entrys to read.
347
Points to an null terminated array of pointers
348
argc Pointer to argc of original program
349
argv Pointer to argv of original program
353
Read options from configuration files and put them BEFORE the arguments
354
that are already in argc and argv. This way the calling program can
355
easily command line options override options in configuration files
358
In case of fatal error, the function will print a warning and do
361
To free used memory one should call free_defaults() with the argument
362
that was put in *argv
366
1 The given conf_file didn't exists
370
int load_defaults(const char *conf_file, const char **groups,
371
int *argc, char ***argv)
375
bool found_print_defaults= 0;
376
uint32_t args_used= 0;
380
struct handle_option_ctx ctx;
382
init_default_directories();
383
init_alloc_root(&alloc,512,0);
385
Check if the user doesn't want any default option processing
386
--no-defaults is always the first option
388
if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
390
/* remove the --no-defaults argument and return only the other arguments */
392
if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
393
(*argc + 1)*sizeof(char*))))
395
res= (char**) (ptr+sizeof(alloc));
396
res[0]= **argv; /* Copy program name */
397
for (i=2 ; i < (uint) *argc ; i++)
399
res[i-1]=0; /* End pointer */
402
*(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
407
group.name= "defaults";
408
group.type_names= groups;
410
for (; *groups ; groups++)
413
if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
420
error= my_search_option_files(conf_file, argc, argv, &args_used,
421
handle_default_option, (void *) &ctx);
423
Here error contains <> 0 only if we have a fully specified conf_file
424
or a forced default file
426
if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
427
(args.elements + *argc +1) *sizeof(char*))))
429
res= (char**) (ptr+sizeof(alloc));
431
/* copy name + found arguments + command line arguments to new array */
432
res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */
433
memcpy(res+1, args.buffer, args.elements*sizeof(char*));
434
/* Skip --defaults-xxx options */
439
Check if we wan't to see the new argument list
440
This options must always be the last of the default options
442
if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
444
found_print_defaults=1;
445
--*argc; ++*argv; /* skip argument */
449
memcpy(res+1+args.elements, *argv + 1, (*argc-1)*sizeof(char*));
450
res[args.elements+ *argc]=0; /* last null */
452
(*argc)+=args.elements;
454
*(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
455
delete_dynamic(&args);
456
if (found_print_defaults)
459
printf("%s would have been started with the following arguments:\n",
461
for (i=1 ; i < *argc ; i++)
462
printf("%s ", (*argv)[i]);
469
fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
471
return 0; /* Keep compiler happy */
475
void free_defaults(char **argv)
478
memcpy(&ptr, (char*) argv - sizeof(ptr), sizeof(ptr));
479
free_root(&ptr,MYF(0));
483
static int search_default_file(Process_option_func opt_handler,
486
const char *config_file)
489
const char *empty_list[]= { "", 0 };
490
bool have_ext= fn_ext(config_file)[0] != 0;
491
const char **exts_to_use= have_ext ? empty_list : f_extensions;
493
for (ext= (char**) exts_to_use; *ext; ext++)
496
if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
498
config_file, 0)) < 0)
506
Skip over keyword and get argument after keyword
510
keyword Include directive keyword
511
kwlen Length of keyword
512
ptr Pointer to the keword in the line under process
517
# Returns pointer to the argument after the keyword.
520
static char *get_argument(const char *keyword, size_t kwlen,
521
char *ptr, char *name, uint32_t line)
525
/* Skip over "include / includedir keyword" and following whitespace */
527
for (ptr+= kwlen - 1;
528
my_isspace(&my_charset_utf8_general_ci, ptr[0]);
533
Trim trailing whitespace from directory name
534
The -1 below is for the newline added by fgets()
535
Note that my_isspace() is true for \r and \n
537
for (end= ptr + strlen(ptr) - 1;
538
my_isspace(&my_charset_utf8_general_ci, *(end - 1));
541
end[0]= 0; /* Cut off end space */
543
/* Print error msg if there is nothing after !include* directive */
547
"error: Wrong '!%s' directive in config file: %s at line %d\n",
548
keyword, name, line);
556
Open a configuration file (if exists) and read given options from it
559
search_default_file_with_ext()
560
opt_handler Option handler function. It is used to process
561
every separate option.
562
handler_ctx Pointer to the structure to store actual
563
parameters of the function.
564
dir directory to read
565
ext Extension for configuration file
566
config_file Name of configuration file
568
recursion_level the level of recursion, got while processing
569
"!include" or "!includedir"
573
-1 Fatal error, abort
574
1 File not found (Warning)
577
static int search_default_file_with_ext(Process_option_func opt_handler,
581
const char *config_file,
584
char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
585
char *value, option[4096], tmp[FN_REFLEN];
586
static const char includedir_keyword[]= "includedir";
587
static const char include_keyword[]= "include";
588
const int max_recursion_level= 10;
594
FILEINFO *search_file;
596
if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
597
return 0; /* Ignore wrong paths */
600
end=convert_dirname(name, dir, NULL);
601
if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
603
strxmov(end,config_file,ext,NULL);
607
my_stpcpy(name,config_file);
609
fn_format(name,name,"","",4);
611
struct stat stat_info;
612
if (stat(name,&stat_info))
615
Ignore world-writable regular files.
616
This is mainly done to protect us to not read a file created by
617
the mysqld server, but the check is still valid in most context.
619
if ((stat_info.st_mode & S_IWOTH) &&
620
(stat_info.st_mode & S_IFMT) == S_IFREG)
622
fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
627
if (!(fp= my_fopen(name, O_RDONLY, MYF(0))))
628
return 1; /* Ignore wrong files */
630
while (fgets(buff, sizeof(buff) - 1, fp))
633
/* Ignore comment and empty lines */
634
for (ptr= buff; my_isspace(&my_charset_utf8_general_ci, *ptr); ptr++)
637
if (*ptr == '#' || *ptr == ';' || !*ptr)
640
/* Configuration File Directives */
643
if (recursion_level >= max_recursion_level)
645
for (end= ptr + strlen(ptr) - 1;
646
my_isspace(&my_charset_utf8_general_ci, *(end - 1));
651
"Warning: skipping '%s' directive as maximum include"
652
"recursion level was reached in file %s at line %d\n",
657
/* skip over `!' and following whitespace */
658
for (++ptr; my_isspace(&my_charset_utf8_general_ci, ptr[0]); ptr++)
661
if ((!strncmp(ptr, includedir_keyword,
662
sizeof(includedir_keyword) - 1)) &&
663
my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(includedir_keyword) - 1]))
665
if (!(ptr= get_argument(includedir_keyword,
666
sizeof(includedir_keyword),
670
if (!(search_dir= my_dir(ptr, MYF(MY_WME))))
673
for (i= 0; i < (uint) search_dir->number_off_files; i++)
675
search_file= search_dir->dir_entry + i;
676
ext= fn_ext(search_file->name);
678
/* check extension */
679
for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
681
if (!strcmp(ext, *tmp_ext))
687
fn_format(tmp, search_file->name, ptr, "",
688
MY_UNPACK_FILENAME | MY_SAFE_PATH);
690
search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp,
691
recursion_level + 1);
695
my_dirend(search_dir);
697
else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
698
my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(include_keyword)-1]))
700
if (!(ptr= get_argument(include_keyword,
701
sizeof(include_keyword), ptr,
705
search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
706
recursion_level + 1);
712
if (*ptr == '[') /* Group name */
715
if (!(end=(char *) strchr(++ptr,']')))
718
"error: Wrong group definition in config file: %s at line %d\n",
722
/* Remove end space */
723
for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) ; end--) ;
726
strmake(curr_gr, ptr, cmin((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
728
/* signal that a new group is found */
729
opt_handler(handler_ctx, curr_gr, NULL);
736
"error: Found option without preceding group in config file: %s at line: %d\n",
742
end= remove_end_comment(ptr);
743
if ((value= strchr(ptr, '=')))
744
end= value; /* Option without argument */
745
for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) ; end--) ;
748
strmake(my_stpcpy(option,"--"),ptr, (size_t) (end-ptr));
749
if (opt_handler(handler_ctx, curr_gr, option))
754
/* Remove pre- and end space */
756
for (value++ ; my_isspace(&my_charset_utf8_general_ci,*value); value++) ;
757
value_end= strchr(value, '\0');
759
We don't have to test for value_end >= value as we know there is
762
for ( ; my_isspace(&my_charset_utf8_general_ci,value_end[-1]) ; value_end--) ;
763
if (value_end < value) /* Empty string */
766
/* remove quotes around argument */
767
if ((*value == '\"' || *value == '\'') && /* First char is quote */
768
(value + 1 < value_end ) && /* String is longer than 1 */
769
*value == value_end[-1] ) /* First char is equal to last char */
774
ptr=my_stpncpy(my_stpcpy(option,"--"),ptr,(size_t) (end-ptr));
777
for ( ; value != value_end; value++)
779
if (*value == '\\' && value != value_end-1)
795
*ptr++= ' '; /* space */
806
default: /* Unknown; Keep '\' */
816
if (opt_handler(handler_ctx, curr_gr, option))
820
my_fclose(fp,MYF(0));
824
my_fclose(fp,MYF(0));
825
return -1; /* Fatal error */
829
static char *remove_end_comment(char *ptr)
831
char quote= 0; /* we are inside quote marks */
832
char escape= 0; /* symbol is protected by escape chagacter */
836
if ((*ptr == '\'' || *ptr == '\"') && !escape)
840
else if (quote == *ptr)
843
/* We are not inside a string */
844
if (!quote && *ptr == '#')
849
escape= (quote && *ptr == '\\' && !escape);
854
void my_print_default_files(const char *conf_file)
856
const char *empty_list[]= { "", 0 };
857
bool have_ext= fn_ext(conf_file)[0] != 0;
858
const char **exts_to_use= have_ext ? empty_list : f_extensions;
859
char name[FN_REFLEN], **ext;
862
init_default_directories();
863
puts("\nDefault options are read from the following files in the given order:");
865
if (dirname_length(conf_file))
866
fputs(conf_file,stdout);
869
for (dirs=default_directories ; *dirs; dirs++)
871
for (ext= (char**) exts_to_use; *ext; ext++)
877
else if (my_defaults_extra_file)
878
pos= my_defaults_extra_file;
881
end= convert_dirname(name, pos, NULL);
882
if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
884
strxmov(end, conf_file, *ext, " ", NULL);
892
void print_defaults(const char *conf_file, const char **groups)
894
const char **groups_save= groups;
895
my_print_default_files(conf_file);
897
fputs("The following groups are read:",stdout);
898
for ( ; *groups ; groups++)
901
fputs(*groups,stdout);
904
if (my_defaults_group_suffix)
907
for ( ; *groups ; groups++)
910
fputs(*groups,stdout);
911
fputs(my_defaults_group_suffix,stdout);
914
puts("\nThe following options may be given as the first argument:\n\
915
--print-defaults Print the program argument list and exit\n\
916
--no-defaults Don't read default options from any options file\n\
917
--defaults-file=# Only read default options from the given file #\n\
918
--defaults-extra-file=# Read this file after the global files are read");
922
This extra complexity is to avoid declaring 'rc' if it won't be
925
#define ADD_DIRECTORY(DIR) (void) array_append_string_unique((DIR), default_directories, \
926
array_elements(default_directories))
928
#define ADD_COMMON_DIRECTORIES() \
931
if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) \
932
ADD_DIRECTORY(env); \
933
/* Placeholder for --defaults-extra-file=<path> */ \
939
Initialize default directories for Unix
944
3. --sysconfdir=<path> (compile-time option)
945
4. getenv(DEFAULT_HOME_ENV)
946
5. --defaults-extra-file=<path> (run-time option)
950
static void init_default_directories(void)
952
memset(default_directories, 0, sizeof(default_directories));
953
ADD_DIRECTORY("/etc/");
954
ADD_DIRECTORY("/etc/drizzle/");
955
#if defined(DEFAULT_SYSCONFDIR)
956
ADD_DIRECTORY(DEFAULT_SYSCONFDIR);
958
ADD_COMMON_DIRECTORIES();