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>
40
#include <drizzled/configmake.h>
44
const char *my_defaults_file=0;
45
const char *my_defaults_group_suffix=0;
46
char *my_defaults_extra_file=0;
48
/* Which directories are searched for options (and in which order) */
50
#define MAX_DEFAULT_DIRS 6
51
const char *default_directories[MAX_DEFAULT_DIRS + 1];
53
static const char *f_extensions[]= { ".cnf", 0 };
55
int handle_default_option(void *in_ctx, const char *group_name,
59
This structure defines the context that we pass to callback
60
function 'handle_default_option' used in search_default_file
61
to process each option. This context is used if search_default_file
62
was called from load_defaults.
65
struct handle_option_ctx
72
static int search_default_file(Process_option_func func, void *func_ctx,
73
const char *dir, const char *config_file);
74
static int search_default_file_with_ext(Process_option_func func,
76
const char *dir, const char *ext,
77
const char *config_file, int recursion_level);
82
Create the list of default directories.
85
On all systems, if a directory is already in the list, it will be moved
86
to the end of the list. This avoids reading defaults files multiple times,
87
while ensuring the correct precedence.
92
static void init_default_directories(void);
95
static char *remove_end_comment(char *ptr);
99
Process config files in default directories.
102
my_search_option_files()
103
conf_file Basename for configuration file to search for.
104
If this is a path, then only this file is read.
105
argc Pointer to argc of original program
106
argv Pointer to argv of original program
107
args_used Pointer to variable for storing the number of
109
func Pointer to the function to process options
110
func_ctx It's context. Usually it is the structure to
111
store additional options.
113
Process the default options from argc & argv
114
Read through each found config file looks and calls 'func' to process
118
--defaults-group-suffix is only processed if we are called from
124
1 given cinf_file doesn't exist
126
The global variable 'my_defaults_group_suffix' is updated with value for
127
--defaults_group_suffix
130
int my_search_option_files(const char *conf_file, int *argc, char ***argv,
131
uint32_t *args_used, Process_option_func func,
134
const char **dirs, *forced_default_file, *forced_extra_defaults;
137
/* Check if we want to force the use a specific default file */
138
*args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
139
(char **) &forced_default_file,
140
(char **) &forced_extra_defaults,
141
(char **) &my_defaults_group_suffix);
143
if (! my_defaults_group_suffix)
144
my_defaults_group_suffix= getenv("DRIZZLE_GROUP_SUFFIX");
146
if (forced_extra_defaults)
147
my_defaults_extra_file= (char *) forced_extra_defaults;
149
if (forced_default_file)
150
my_defaults_file= forced_default_file;
153
We can only handle 'defaults-group-suffix' if we are called from
154
load_defaults() as otherwise we can't know the type of 'func_ctx'
157
if (my_defaults_group_suffix && (func == handle_default_option))
159
/* Handle --defaults-group-suffix= */
161
const char **extra_groups;
162
const uint32_t instance_len= strlen(my_defaults_group_suffix);
163
struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
165
TYPELIB *group= ctx->group;
168
(const char**)alloc_root(ctx->alloc,
169
(2*group->count+1)*sizeof(char*))))
172
for (i= 0; i < group->count; i++)
175
extra_groups[i]= group->type_names[i]; /** copy group */
177
len= strlen(extra_groups[i]);
178
if (!(ptr= (char *)alloc_root(ctx->alloc, len+instance_len+1)))
181
extra_groups[i+group->count]= ptr;
183
/** Construct new group */
184
memcpy(ptr, extra_groups[i], len);
185
memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
189
group->type_names= extra_groups;
190
group->type_names[group->count]= 0;
193
if (forced_default_file)
195
if ((error= search_default_file_with_ext(func, func_ctx, "", "",
196
forced_default_file, 0)) < 0)
200
fprintf(stderr, "Could not open required defaults file: %s\n",
201
forced_default_file);
205
else if (dirname_length(conf_file))
207
if ((error= search_default_file(func, func_ctx, NULL, conf_file)) < 0)
212
for (dirs= default_directories ; *dirs; dirs++)
216
if (search_default_file(func, func_ctx, *dirs, conf_file) < 0)
219
else if (my_defaults_extra_file)
221
if ((error= search_default_file_with_ext(func, func_ctx, "", "",
222
my_defaults_extra_file, 0)) < 0)
223
goto err; /* Fatal error */
226
fprintf(stderr, "Could not open required defaults file: %s\n",
227
my_defaults_extra_file);
237
fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
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
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))
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");
474
void free_defaults(char **argv)
477
memcpy(&ptr, (char*) argv - sizeof(ptr), sizeof(ptr));
478
free_root(&ptr,MYF(0));
482
static int search_default_file(Process_option_func opt_handler,
485
const char *config_file)
488
const char *empty_list[]= { "", 0 };
489
bool have_ext= fn_ext(config_file)[0] != 0;
490
const char **exts_to_use= have_ext ? empty_list : f_extensions;
492
for (ext= (char**) exts_to_use; *ext; ext++)
495
if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
497
config_file, 0)) < 0)
505
Skip over keyword and get argument after keyword
509
keyword Include directive keyword
510
kwlen Length of keyword
511
ptr Pointer to the keword in the line under process
516
# Returns pointer to the argument after the keyword.
519
static char *get_argument(const char *keyword, size_t kwlen,
520
char *ptr, char *name, uint32_t line)
524
/* Skip over "include / includedir keyword" and following whitespace */
526
for (ptr+= kwlen - 1;
527
my_isspace(&my_charset_utf8_general_ci, ptr[0]);
532
Trim trailing whitespace from directory name
533
The -1 below is for the newline added by fgets()
534
Note that my_isspace() is true for \r and \n
536
for (end= ptr + strlen(ptr) - 1;
537
my_isspace(&my_charset_utf8_general_ci, *(end - 1));
540
end[0]= 0; /* Cut off end space */
542
/* Print error msg if there is nothing after !include* directive */
546
"error: Wrong '!%s' directive in config file: %s at line %d\n",
547
keyword, name, line);
555
Open a configuration file (if exists) and read given options from it
558
search_default_file_with_ext()
559
opt_handler Option handler function. It is used to process
560
every separate option.
561
handler_ctx Pointer to the structure to store actual
562
parameters of the function.
563
dir directory to read
564
ext Extension for configuration file
565
config_file Name of configuration file
567
recursion_level the level of recursion, got while processing
568
"!include" or "!includedir"
572
-1 Fatal error, abort
573
1 File not found (Warning)
576
static int search_default_file_with_ext(Process_option_func opt_handler,
580
const char *config_file,
583
char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
584
char *value, option[4096], tmp[FN_REFLEN];
585
static const char includedir_keyword[]= "includedir";
586
static const char include_keyword[]= "include";
587
const int max_recursion_level= 10;
593
FILEINFO *search_file;
595
if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
596
return 0; /* Ignore wrong paths */
599
end=convert_dirname(name, dir, NULL);
600
if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
602
sprintf(end,"%s%s",config_file,ext);
606
strcpy(name,config_file);
608
fn_format(name,name,"","",4);
610
struct stat stat_info;
611
if (stat(name,&stat_info))
614
Ignore world-writable regular files.
615
This is mainly done to protect us to not read a file created by
616
the mysqld server, but the check is still valid in most context.
618
if ((stat_info.st_mode & S_IWOTH) &&
619
(stat_info.st_mode & S_IFMT) == S_IFREG)
621
fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
626
if (!(fp= my_fopen(name, O_RDONLY, MYF(0))))
627
return 1; /* Ignore wrong files */
629
while (fgets(buff, sizeof(buff) - 1, fp))
632
/* Ignore comment and empty lines */
633
for (ptr= buff; my_isspace(&my_charset_utf8_general_ci, *ptr); ptr++)
636
if (*ptr == '#' || *ptr == ';' || !*ptr)
639
/* Configuration File Directives */
642
if (recursion_level >= max_recursion_level)
644
for (end= ptr + strlen(ptr) - 1;
645
my_isspace(&my_charset_utf8_general_ci, *(end - 1));
650
"Warning: skipping '%s' directive as maximum include"
651
"recursion level was reached in file %s at line %d\n",
656
/* skip over `!' and following whitespace */
657
for (++ptr; my_isspace(&my_charset_utf8_general_ci, ptr[0]); ptr++)
660
if ((!strncmp(ptr, includedir_keyword,
661
sizeof(includedir_keyword) - 1)) &&
662
my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(includedir_keyword) - 1]))
664
if (!(ptr= get_argument(includedir_keyword,
665
sizeof(includedir_keyword),
669
if (!(search_dir= my_dir(ptr, MYF(MY_WME))))
672
for (i= 0; i < (uint) search_dir->number_off_files; i++)
674
search_file= search_dir->dir_entry + i;
675
ext= fn_ext(search_file->name);
677
/* check extension */
678
for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
680
if (!strcmp(ext, *tmp_ext))
686
fn_format(tmp, search_file->name, ptr, "",
687
MY_UNPACK_FILENAME | MY_SAFE_PATH);
689
search_default_file_with_ext(opt_handler, handler_ctx, "", "", tmp,
690
recursion_level + 1);
694
my_dirend(search_dir);
696
else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
697
my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(include_keyword)-1]))
699
if (!(ptr= get_argument(include_keyword,
700
sizeof(include_keyword), ptr,
704
search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
705
recursion_level + 1);
711
if (*ptr == '[') /* Group name */
714
if (!(end=(char *) strchr(++ptr,']')))
717
"error: Wrong group definition in config file: %s at line %d\n",
721
/* Remove end space */
722
for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) ; end--) ;
725
strncpy(curr_gr, ptr, cmin((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
726
curr_gr[cmin((size_t)(end-ptr)+1, sizeof(curr_gr)-1)] = '\0';
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
strncpy(strcpy(option,"--")+2,ptr,strlen(ptr)+1);
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= strncpy(strcpy(option,"--")+2,ptr,(size_t) (end-ptr));
778
for ( ; value != value_end; value++)
780
if (*value == '\\' && value != value_end-1)
796
*ptr++= ' '; /* space */
807
default: /* Unknown; Keep '\' */
817
if (opt_handler(handler_ctx, curr_gr, option))
821
my_fclose(fp,MYF(0));
825
my_fclose(fp,MYF(0));
826
return -1; /* Fatal error */
830
static char *remove_end_comment(char *ptr)
832
char quote= 0; /* we are inside quote marks */
833
char escape= 0; /* symbol is protected by escape chagacter */
837
if ((*ptr == '\'' || *ptr == '\"') && !escape)
841
else if (quote == *ptr)
844
/* We are not inside a string */
845
if (!quote && *ptr == '#')
850
escape= (quote && *ptr == '\\' && !escape);
855
void my_print_default_files(const char *conf_file)
857
const char *empty_list[]= { "", 0 };
858
bool have_ext= fn_ext(conf_file)[0] != 0;
859
const char **exts_to_use= have_ext ? empty_list : f_extensions;
860
char name[FN_REFLEN], **ext;
863
init_default_directories();
864
puts("\nDefault options are read from the following files in the given order:");
866
if (dirname_length(conf_file))
867
fputs(conf_file,stdout);
870
for (dirs=default_directories ; *dirs; dirs++)
872
for (ext= (char**) exts_to_use; *ext; ext++)
878
else if (my_defaults_extra_file)
879
pos= my_defaults_extra_file;
882
end= convert_dirname(name, pos, NULL);
883
if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
885
sprintf(end,"%s%s ",conf_file, *ext);
893
void print_defaults(const char *conf_file, const char **groups)
895
const char **groups_save= groups;
896
my_print_default_files(conf_file);
898
fputs("The following groups are read:",stdout);
899
for ( ; *groups ; groups++)
902
fputs(*groups,stdout);
905
if (my_defaults_group_suffix)
908
for ( ; *groups ; groups++)
911
fputs(*groups,stdout);
912
fputs(my_defaults_group_suffix,stdout);
915
puts("\nThe following options may be given as the first argument:\n\
916
--print-defaults Print the program argument list and exit\n\
917
--no-defaults Don't read default options from any options file\n\
918
--defaults-file=# Only read default options from the given file #\n\
919
--defaults-extra-file=# Read this file after the global files are read");
923
This extra complexity is to avoid declaring 'rc' if it won't be
926
#define ADD_DIRECTORY(DIR) (void) array_append_string_unique((DIR), default_directories, \
927
array_elements(default_directories))
929
#define ADD_COMMON_DIRECTORIES() \
932
if ((env= getenv("DRIZZLE_HOME"))) \
933
ADD_DIRECTORY(env); \
934
/* Placeholder for --defaults-extra-file=<path> */ \
940
Initialize default directories for Unix
945
3. --sysconfdir=<path> (compile-time option)
946
4. getenv("DRIZZLE_HOME")
947
5. --defaults-extra-file=<path> (run-time option)
951
static void init_default_directories(void)
953
memset(default_directories, 0, sizeof(default_directories));
954
ADD_DIRECTORY("/etc/");
955
ADD_DIRECTORY("/etc/drizzle/");
956
ADD_DIRECTORY(SYSCONFDIR);
957
ADD_COMMON_DIRECTORIES();