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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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
****************************************************************************/
38
#include <drizzled/internal/my_sys.h>
39
#include <drizzled/internal/m_string.h>
40
#include <drizzled/charset_info.h>
41
#include <drizzled/typelib.h>
42
#include <drizzled/configmake.h>
43
#include <drizzled/gettext.h>
44
#include <drizzled/dynamic_array.h>
45
#include <drizzled/cached_directory.h>
47
#ifdef HAVE_SYS_STAT_H
48
# include <sys/stat.h>
61
const char *my_defaults_file=0;
62
const char *my_defaults_group_suffix=0;
63
char *my_defaults_extra_file=0;
65
/* Which directories are searched for options (and in which order) */
67
#define MAX_DEFAULT_DIRS 6
68
const char *default_directories[MAX_DEFAULT_DIRS + 1];
70
static const char *f_extensions[]= { ".cnf", 0 };
72
int handle_default_option(void *in_ctx, const char *group_name,
76
This structure defines the context that we pass to callback
77
function 'handle_default_option' used in search_default_file
78
to process each option. This context is used if search_default_file
79
was called from load_defaults.
82
struct handle_option_ctx
89
static int search_default_file(Process_option_func func, void *func_ctx,
90
const char *dir, const char *config_file);
91
static int search_default_file_with_ext(Process_option_func func,
93
const char *dir, const char *ext,
94
const char *config_file, int recursion_level);
99
Create the list of default directories.
102
On all systems, if a directory is already in the list, it will be moved
103
to the end of the list. This avoids reading defaults files multiple times,
104
while ensuring the correct precedence.
109
static void init_default_directories(void);
112
static char *remove_end_comment(char *ptr);
116
Process config files in default directories.
119
my_search_option_files()
120
conf_file Basename for configuration file to search for.
121
If this is a path, then only this file is read.
122
argc Pointer to argc of original program
123
argv Pointer to argv of original program
124
args_used Pointer to variable for storing the number of
126
func Pointer to the function to process options
127
func_ctx It's context. Usually it is the structure to
128
store additional options.
130
Process the default options from argc & argv
131
Read through each found config file looks and calls 'func' to process
135
--defaults-group-suffix is only processed if we are called from
141
1 given cinf_file doesn't exist
143
The global variable 'my_defaults_group_suffix' is updated with value for
144
--defaults_group_suffix
147
int my_search_option_files(const char *conf_file, int *argc, char ***argv,
148
uint32_t *args_used, Process_option_func func,
151
const char **dirs, *forced_default_file, *forced_extra_defaults;
154
/* Check if we want to force the use a specific default file */
155
*args_used+= get_defaults_options(*argc - *args_used, *argv + *args_used,
156
(char **) &forced_default_file,
157
(char **) &forced_extra_defaults,
158
(char **) &my_defaults_group_suffix);
160
if (! my_defaults_group_suffix)
161
my_defaults_group_suffix= getenv("DRIZZLE_GROUP_SUFFIX");
163
if (forced_extra_defaults)
164
my_defaults_extra_file= (char *) forced_extra_defaults;
166
if (forced_default_file)
167
my_defaults_file= forced_default_file;
170
We can only handle 'defaults-group-suffix' if we are called from
171
load_defaults() as otherwise we can't know the type of 'func_ctx'
174
if (my_defaults_group_suffix && (func == handle_default_option))
176
/* Handle --defaults-group-suffix= */
178
const char **extra_groups;
179
const size_t instance_len= strlen(my_defaults_group_suffix);
180
struct handle_option_ctx *ctx= (struct handle_option_ctx*) func_ctx;
182
TYPELIB *group= ctx->group;
185
(const char**)ctx->alloc->alloc_root(
186
(2*group->count+1)*sizeof(char*))))
189
for (i= 0; i < group->count; i++)
192
extra_groups[i]= group->type_names[i]; /** copy group */
194
len= strlen(extra_groups[i]);
195
if (!(ptr= (char *)ctx->alloc->alloc_root( len+instance_len+1)))
198
extra_groups[i+group->count]= ptr;
200
/** Construct new group */
201
memcpy(ptr, extra_groups[i], len);
202
memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
206
group->type_names= extra_groups;
207
group->type_names[group->count]= 0;
210
if (forced_default_file)
212
if ((error= search_default_file_with_ext(func, func_ctx, "", "",
213
forced_default_file, 0)) < 0)
217
fprintf(stderr, "Could not open required defaults file: %s\n",
218
forced_default_file);
222
else if (dirname_length(conf_file))
224
if ((error= search_default_file(func, func_ctx, NULL, conf_file)) < 0)
229
for (dirs= default_directories ; *dirs; dirs++)
233
if (search_default_file(func, func_ctx, *dirs, conf_file) < 0)
236
else if (my_defaults_extra_file)
238
if ((error= search_default_file_with_ext(func, func_ctx, "", "",
239
my_defaults_extra_file, 0)) < 0)
240
goto err; /* Fatal error */
243
fprintf(stderr, "Could not open required defaults file: %s\n",
244
my_defaults_extra_file);
254
fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
260
The option handler for load_defaults.
263
handle_deault_option()
264
in_ctx Handler context. In this case it is a
265
handle_option_ctx structure.
266
group_name The name of the group the option belongs to.
267
option The very option to be processed. It is already
268
prepared to be used in argv (has -- prefix). If it
269
is NULL, we are handling a new group (section).
272
This handler checks whether a group is one of the listed and adds an option
273
to the array if yes. Some other handler can record, for instance, all
274
groups and their options, not knowing in advance the names and amount of
282
int handle_default_option(void *in_ctx, const char *group_name,
286
struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
291
if (ctx->group->find_type(const_cast<char*>(group_name), 3))
293
if (!(tmp= (char *)ctx->alloc->alloc_root(strlen(option) + 1)))
295
ctx->args->push_back(&tmp);
304
Gets options from the command line
307
get_defaults_options()
308
argc Pointer to argc of original program
309
argv Pointer to argv of original program
310
defaults --defaults-file option
311
extra_defaults --defaults-extra-file option
314
# Number of arguments used from *argv
315
defaults and extra_defaults will be set to option of the appropriate
316
items of argv array, or to NULL if there are no such options
319
int get_defaults_options(int argc, char **argv,
321
char **extra_defaults,
324
int org_argc= argc, prev_argc= 0;
325
*defaults= *extra_defaults= *group_suffix= 0;
327
const std::string DEFAULTS_FILE("--defaults-file=");
328
const std::string DEFAULTS_EXTRA_FILE("--defaults-extra-file=");
329
const std::string DEFAULTS_GROUP_SUFFIX("--defaults-group-suffix=");
331
while (argc >= 2 && argc != prev_argc)
333
/* Skip program name or previously handled argument */
335
prev_argc= argc; /* To check if we found */
336
if (!*defaults && (strncmp(*argv,
337
DEFAULTS_FILE.c_str(),
338
DEFAULTS_FILE.size()) == 0))
340
*defaults= *argv + DEFAULTS_FILE.size();
344
if (!*extra_defaults && (strncmp(*argv,
345
DEFAULTS_EXTRA_FILE.c_str(),
346
DEFAULTS_EXTRA_FILE.size()) == 0))
348
*extra_defaults= *argv + DEFAULTS_EXTRA_FILE.size();
352
if (!*group_suffix && (strncmp(*argv,
353
DEFAULTS_GROUP_SUFFIX.c_str(),
354
DEFAULTS_GROUP_SUFFIX.size()) == 0))
357
*group_suffix= *argv + DEFAULTS_GROUP_SUFFIX.size();
362
return org_argc - argc;
367
Read options from configurations files
371
conf_file Basename for configuration file to search for.
372
If this is a path, then only this file is read.
373
groups Which [group] entrys to read.
374
Points to an null terminated array of pointers
375
argc Pointer to argc of original program
376
argv Pointer to argv of original program
380
Read options from configuration files and put them BEFORE the arguments
381
that are already in argc and argv. This way the calling program can
382
easily command line options override options in configuration files
385
In case of fatal error, the function will print a warning and do
388
To free used memory one should call free_defaults() with the argument
389
that was put in *argv
393
1 The given conf_file didn't exists
397
int load_defaults(const char *conf_file, const char **groups,
398
int *argc, char ***argv)
402
uint32_t args_used= 0;
404
memory::Root alloc(512);
406
struct handle_option_ctx ctx;
408
init_default_directories();
410
Check if the user doesn't want any default option processing
411
--no-defaults is always the first option
413
if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
415
/* remove the --no-defaults argument and return only the other arguments */
417
if (!(ptr=(char*) alloc.alloc_root(sizeof(alloc)+ (*argc + 1)*sizeof(char*))))
419
res= (char**) (ptr+sizeof(alloc));
420
memset(res,0,(*argc + 1));
421
res[0]= **argv; /* Copy program name */
422
for (i=2 ; i < (uint32_t) *argc ; i++)
424
res[i-1]=0; /* End pointer */
427
*(memory::Root*) ptr= alloc; /* Save alloc root for free */
432
group.name= "defaults";
433
group.type_names= groups;
435
for (; *groups ; groups++)
438
if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
445
error= my_search_option_files(conf_file, argc, argv, &args_used,
446
handle_default_option, (void *) &ctx);
448
Here error contains <> 0 only if we have a fully specified conf_file
449
or a forced default file
451
if (!(ptr=(char*) alloc.alloc_root(sizeof(alloc)+ (args.size() + *argc +1) *sizeof(char*))))
453
res= (char**) (ptr+sizeof(alloc));
455
/* copy name + found arguments + command line arguments to new array */
456
res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */
457
memcpy(res+1, args.buffer, args.size()*sizeof(char*));
458
/* Skip --defaults-xxx options */
463
Check if we wan't to see the new argument list
464
This options must always be the last of the default options
467
memcpy(res+1+args.size(), *argv + 1, (*argc-1)*sizeof(char*));
468
res[args.size()+ *argc]=0; /* last null */
470
(*argc)+=int(args.size());
471
*argv= static_cast<char**>(res);
472
*(memory::Root*) ptr= alloc; /* Save alloc root for free */
473
delete_dynamic(&args);
478
fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
483
void free_defaults(char **argv)
486
memcpy(&ptr, (char*) argv - sizeof(ptr), sizeof(ptr));
487
ptr.free_root(MYF(0));
491
static int search_default_file(Process_option_func opt_handler,
494
const char *config_file)
497
const char *empty_list[]= { "", 0 };
498
bool have_ext= fn_ext(config_file)[0] != 0;
499
const char **exts_to_use= have_ext ? empty_list : f_extensions;
501
for (ext= (char**) exts_to_use; *ext; ext++)
504
if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
506
config_file, 0)) < 0)
514
Skip over keyword and get argument after keyword
518
keyword Include directive keyword
519
kwlen Length of keyword
520
ptr Pointer to the keword in the line under process
525
# Returns pointer to the argument after the keyword.
528
static char *get_argument(const char *keyword, size_t kwlen,
529
char *ptr, char *name, uint32_t line)
533
/* Skip over "include / includedir keyword" and following whitespace */
535
for (ptr+= kwlen - 1;
536
my_isspace(&my_charset_utf8_general_ci, ptr[0]);
541
Trim trailing whitespace from directory name
542
The -1 below is for the newline added by fgets()
543
Note that my_isspace() is true for \r and \n
545
for (end= ptr + strlen(ptr) - 1;
546
my_isspace(&my_charset_utf8_general_ci, *(end - 1));
549
end[0]= 0; /* Cut off end space */
551
/* Print error msg if there is nothing after !include* directive */
555
"error: Wrong '!%s' directive in config file: %s at line %d\n",
556
keyword, name, line);
564
Open a configuration file (if exists) and read given options from it
567
search_default_file_with_ext()
568
opt_handler Option handler function. It is used to process
569
every separate option.
570
handler_ctx Pointer to the structure to store actual
571
parameters of the function.
572
dir directory to read
573
ext Extension for configuration file
574
config_file Name of configuration file
576
recursion_level the level of recursion, got while processing
577
"!include" or "!includedir"
581
-1 Fatal error, abort
582
1 File not found (Warning)
585
static int search_default_file_with_ext(Process_option_func opt_handler,
589
const char *config_file,
592
char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
593
char *value, option[4096], tmp[FN_REFLEN];
594
static const char includedir_keyword[]= "includedir";
595
static const char include_keyword[]= "include";
596
const int max_recursion_level= 10;
601
if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
602
return 0; /* Ignore wrong paths */
605
end=convert_dirname(name, dir, NULL);
606
if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
608
sprintf(end,"%s%s",config_file,ext);
612
strcpy(name,config_file);
614
fn_format(name,name,"","",4);
616
struct stat stat_info;
617
if (stat(name,&stat_info))
620
Ignore world-writable regular files.
621
This is mainly done to protect us to not read a file created by
622
the mysqld server, but the check is still valid in most context.
624
if ((stat_info.st_mode & S_IWOTH) &&
625
(stat_info.st_mode & S_IFMT) == S_IFREG)
627
fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
632
if (!(fp= fopen(name, "r")))
633
return 1; /* Ignore wrong files */
635
memset(buff,0,sizeof(buff));
636
while (fgets(buff, sizeof(buff) - 1, fp))
639
/* Ignore comment and empty lines */
640
for (ptr= buff; my_isspace(&my_charset_utf8_general_ci, *ptr); ptr++)
643
if (*ptr == '#' || *ptr == ';' || !*ptr)
646
/* Configuration File Directives */
649
if (recursion_level >= max_recursion_level)
651
for (end= ptr + strlen(ptr) - 1;
652
my_isspace(&my_charset_utf8_general_ci, *(end - 1));
657
"Warning: skipping '%s' directive as maximum include"
658
"recursion level was reached in file %s at line %d\n",
663
/* skip over `!' and following whitespace */
664
for (++ptr; my_isspace(&my_charset_utf8_general_ci, ptr[0]); ptr++)
667
if ((!strncmp(ptr, includedir_keyword,
668
sizeof(includedir_keyword) - 1)) &&
669
my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(includedir_keyword) - 1]))
671
if (!(ptr= get_argument(includedir_keyword,
672
sizeof(includedir_keyword),
676
CachedDirectory dir_cache(ptr);
678
if (dir_cache.fail())
682
* Since clients still use this code, we use fprintf here.
683
* This fprintf needs to be turned into errmsg_printf
684
* as soon as the client programs no longer use mysys
685
* and can use the pluggable error message system.
687
fprintf(stderr, _("error: could not open directory: %s\n"), ptr);
691
CachedDirectory::Entries files= dir_cache.getEntries();
692
CachedDirectory::Entries::iterator file_iter= files.begin();
694
while (file_iter != files.end())
696
CachedDirectory::Entry *entry= *file_iter;
697
ext= fn_ext(entry->filename.c_str());
699
/* check extension */
700
for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
702
if (!strcmp(ext, *tmp_ext))
704
fn_format(tmp, entry->filename.c_str(), ptr, "",
705
MY_UNPACK_FILENAME | MY_SAFE_PATH);
707
search_default_file_with_ext(opt_handler, handler_ctx, "", "",
708
tmp, recursion_level + 1);
715
else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
716
my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(include_keyword)-1]))
718
if (!(ptr= get_argument(include_keyword,
719
sizeof(include_keyword), ptr,
723
search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
724
recursion_level + 1);
730
if (*ptr == '[') /* Group name */
733
if (!(end=(char *) strchr(++ptr,']')))
736
"error: Wrong group definition in config file: %s at line %d\n",
740
/* Remove end space */
741
for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) ; end--) ;
744
strncpy(curr_gr, ptr, min((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
745
curr_gr[min((size_t)(end-ptr)+1, sizeof(curr_gr)-1)] = '\0';
747
/* signal that a new group is found */
748
opt_handler(handler_ctx, curr_gr, NULL);
755
"error: Found option without preceding group in config file: %s at line: %d\n",
761
end= remove_end_comment(ptr);
762
if ((value= strchr(ptr, '=')))
763
end= value; /* Option without argument */
764
for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) || end[-1]== '\n'; end--) ;
767
strncpy(strcpy(option,"--")+2,ptr,strlen(ptr)+1);
768
if (opt_handler(handler_ctx, curr_gr, option))
773
/* Remove pre- and end space */
775
for (value++ ; my_isspace(&my_charset_utf8_general_ci,*value); value++) ;
776
value_end= strchr(value, '\0');
778
We don't have to test for value_end >= value as we know there is
781
for ( ; my_isspace(&my_charset_utf8_general_ci,value_end[-1]) ; value_end--) ;
782
if (value_end < value) /* Empty string */
785
/* remove quotes around argument */
786
if ((*value == '\"' || *value == '\'') && /* First char is quote */
787
(value + 1 < value_end ) && /* String is longer than 1 */
788
*value == value_end[-1] ) /* First char is equal to last char */
794
memset(option,0,2+(size_t)(end-ptr)+1);
795
ptr= strncpy(strcpy(option,"--")+2,ptr,(size_t) (end-ptr));
800
for ( ; value != value_end; value++)
802
if (*value == '\\' && value != value_end-1)
818
*ptr++= ' '; /* space */
829
default: /* Unknown; Keep '\' */
839
if (opt_handler(handler_ctx, curr_gr, option))
849
return -1; /* Fatal error */
853
static char *remove_end_comment(char *ptr)
855
char quote= 0; /* we are inside quote marks */
856
char escape= 0; /* symbol is protected by escape chagacter */
860
if ((*ptr == '\'' || *ptr == '\"') && !escape)
864
else if (quote == *ptr)
867
/* We are not inside a string */
868
if (!quote && *ptr == '#')
873
escape= (quote && *ptr == '\\' && !escape);
878
void my_print_default_files(const char *conf_file)
880
const char *empty_list[]= { "", 0 };
881
bool have_ext= fn_ext(conf_file)[0] != 0;
882
const char **exts_to_use= have_ext ? empty_list : f_extensions;
883
char name[FN_REFLEN], **ext;
886
init_default_directories();
887
puts("\nDefault options are read from the following files in the given order:");
889
if (dirname_length(conf_file))
890
fputs(conf_file,stdout);
893
for (dirs=default_directories ; *dirs; dirs++)
895
for (ext= (char**) exts_to_use; *ext; ext++)
901
else if (my_defaults_extra_file)
902
pos= my_defaults_extra_file;
905
end= convert_dirname(name, pos, NULL);
906
if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
908
sprintf(end,"%s%s ",conf_file, *ext);
916
void print_defaults(const char *conf_file, const char **groups)
918
const char **groups_save= groups;
919
my_print_default_files(conf_file);
921
fputs("The following groups are read:",stdout);
922
for ( ; *groups ; groups++)
925
fputs(*groups,stdout);
928
if (my_defaults_group_suffix)
931
for ( ; *groups ; groups++)
934
fputs(*groups,stdout);
935
fputs(my_defaults_group_suffix,stdout);
938
puts("\nThe following options may be given as the first argument:\n\
939
--no-defaults Don't read default options from any options file\n\
940
--defaults-file=# Only read default options from the given file #\n\
941
--defaults-extra-file=# Read this file after the global files are read");
945
This extra complexity is to avoid declaring 'rc' if it won't be
948
static void add_directory(const char* dir)
950
array_append_string_unique(dir, default_directories, array_elements(default_directories));
953
static void add_common_directories()
955
const char *env= getenv("DRIZZLE_HOME");
958
// Placeholder for --defaults-extra-file=<path>
963
Initialize default directories for Unix
968
3. --sysconfdir=<path> (compile-time option)
969
4. getenv("DRIZZLE_HOME")
970
5. --defaults-extra-file=<path> (run-time option)
974
static void init_default_directories(void)
976
memset(default_directories, 0, sizeof(default_directories));
977
add_directory("/etc/");
978
add_directory("/etc/drizzle/");
979
add_directory(SYSCONFDIR);
980
add_common_directories();
984
} /* namespace internal */
985
} /* namespace drizzled */