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>
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
if (insert_dynamic(ctx->args, (unsigned char*) &tmp))
305
Gets options from the command line
308
get_defaults_options()
309
argc Pointer to argc of original program
310
argv Pointer to argv of original program
311
defaults --defaults-file option
312
extra_defaults --defaults-extra-file option
315
# Number of arguments used from *argv
316
defaults and extra_defaults will be set to option of the appropriate
317
items of argv array, or to NULL if there are no such options
320
int get_defaults_options(int argc, char **argv,
322
char **extra_defaults,
325
int org_argc= argc, prev_argc= 0;
326
*defaults= *extra_defaults= *group_suffix= 0;
328
const std::string DEFAULTS_FILE("--defaults-file=");
329
const std::string DEFAULTS_EXTRA_FILE("--defaults-extra-file=");
330
const std::string DEFAULTS_GROUP_SUFFIX("--defaults-group-suffix=");
332
while (argc >= 2 && argc != prev_argc)
334
/* Skip program name or previously handled argument */
336
prev_argc= argc; /* To check if we found */
337
if (!*defaults && (strncmp(*argv,
338
DEFAULTS_FILE.c_str(),
339
DEFAULTS_FILE.size()) == 0))
341
*defaults= *argv + DEFAULTS_FILE.size();
345
if (!*extra_defaults && (strncmp(*argv,
346
DEFAULTS_EXTRA_FILE.c_str(),
347
DEFAULTS_EXTRA_FILE.size()) == 0))
349
*extra_defaults= *argv + DEFAULTS_EXTRA_FILE.size();
353
if (!*group_suffix && (strncmp(*argv,
354
DEFAULTS_GROUP_SUFFIX.c_str(),
355
DEFAULTS_GROUP_SUFFIX.size()) == 0))
358
*group_suffix= *argv + DEFAULTS_GROUP_SUFFIX.size();
363
return org_argc - argc;
368
Read options from configurations files
372
conf_file Basename for configuration file to search for.
373
If this is a path, then only this file is read.
374
groups Which [group] entrys to read.
375
Points to an null terminated array of pointers
376
argc Pointer to argc of original program
377
argv Pointer to argv of original program
381
Read options from configuration files and put them BEFORE the arguments
382
that are already in argc and argv. This way the calling program can
383
easily command line options override options in configuration files
386
In case of fatal error, the function will print a warning and do
389
To free used memory one should call free_defaults() with the argument
390
that was put in *argv
394
1 The given conf_file didn't exists
398
int load_defaults(const char *conf_file, const char **groups,
399
int *argc, char ***argv)
403
uint32_t args_used= 0;
405
memory::Root alloc(512);
407
struct handle_option_ctx ctx;
409
init_default_directories();
411
Check if the user doesn't want any default option processing
412
--no-defaults is always the first option
414
if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
416
/* remove the --no-defaults argument and return only the other arguments */
418
if (!(ptr=(char*) alloc.alloc_root(sizeof(alloc)+ (*argc + 1)*sizeof(char*))))
420
res= (char**) (ptr+sizeof(alloc));
421
memset(res,0,(*argc + 1));
422
res[0]= **argv; /* Copy program name */
423
for (i=2 ; i < (uint32_t) *argc ; i++)
425
res[i-1]=0; /* End pointer */
428
*(memory::Root*) ptr= alloc; /* Save alloc root for free */
433
group.name= "defaults";
434
group.type_names= groups;
436
for (; *groups ; groups++)
439
if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
446
error= my_search_option_files(conf_file, argc, argv, &args_used,
447
handle_default_option, (void *) &ctx);
449
Here error contains <> 0 only if we have a fully specified conf_file
450
or a forced default file
452
if (!(ptr=(char*) alloc.alloc_root(sizeof(alloc)+ (args.elements + *argc +1) *sizeof(char*))))
454
res= (char**) (ptr+sizeof(alloc));
456
/* copy name + found arguments + command line arguments to new array */
457
res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */
458
memcpy(res+1, args.buffer, args.elements*sizeof(char*));
459
/* Skip --defaults-xxx options */
464
Check if we wan't to see the new argument list
465
This options must always be the last of the default options
468
memcpy(res+1+args.elements, *argv + 1, (*argc-1)*sizeof(char*));
469
res[args.elements+ *argc]=0; /* last null */
471
(*argc)+=int(args.elements);
472
*argv= static_cast<char**>(res);
473
*(memory::Root*) ptr= alloc; /* Save alloc root for free */
474
delete_dynamic(&args);
479
fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
484
void free_defaults(char **argv)
487
memcpy(&ptr, (char*) argv - sizeof(ptr), sizeof(ptr));
488
ptr.free_root(MYF(0));
492
static int search_default_file(Process_option_func opt_handler,
495
const char *config_file)
498
const char *empty_list[]= { "", 0 };
499
bool have_ext= fn_ext(config_file)[0] != 0;
500
const char **exts_to_use= have_ext ? empty_list : f_extensions;
502
for (ext= (char**) exts_to_use; *ext; ext++)
505
if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
507
config_file, 0)) < 0)
515
Skip over keyword and get argument after keyword
519
keyword Include directive keyword
520
kwlen Length of keyword
521
ptr Pointer to the keword in the line under process
526
# Returns pointer to the argument after the keyword.
529
static char *get_argument(const char *keyword, size_t kwlen,
530
char *ptr, char *name, uint32_t line)
534
/* Skip over "include / includedir keyword" and following whitespace */
536
for (ptr+= kwlen - 1;
537
my_isspace(&my_charset_utf8_general_ci, ptr[0]);
542
Trim trailing whitespace from directory name
543
The -1 below is for the newline added by fgets()
544
Note that my_isspace() is true for \r and \n
546
for (end= ptr + strlen(ptr) - 1;
547
my_isspace(&my_charset_utf8_general_ci, *(end - 1));
550
end[0]= 0; /* Cut off end space */
552
/* Print error msg if there is nothing after !include* directive */
556
"error: Wrong '!%s' directive in config file: %s at line %d\n",
557
keyword, name, line);
565
Open a configuration file (if exists) and read given options from it
568
search_default_file_with_ext()
569
opt_handler Option handler function. It is used to process
570
every separate option.
571
handler_ctx Pointer to the structure to store actual
572
parameters of the function.
573
dir directory to read
574
ext Extension for configuration file
575
config_file Name of configuration file
577
recursion_level the level of recursion, got while processing
578
"!include" or "!includedir"
582
-1 Fatal error, abort
583
1 File not found (Warning)
586
static int search_default_file_with_ext(Process_option_func opt_handler,
590
const char *config_file,
593
char name[FN_REFLEN + 10], buff[4096], curr_gr[4096], *ptr, *end, **tmp_ext;
594
char *value, option[4096], tmp[FN_REFLEN];
595
static const char includedir_keyword[]= "includedir";
596
static const char include_keyword[]= "include";
597
const int max_recursion_level= 10;
602
if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
603
return 0; /* Ignore wrong paths */
606
end=convert_dirname(name, dir, NULL);
607
if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
609
sprintf(end,"%s%s",config_file,ext);
613
strcpy(name,config_file);
615
fn_format(name,name,"","",4);
617
struct stat stat_info;
618
if (stat(name,&stat_info))
621
Ignore world-writable regular files.
622
This is mainly done to protect us to not read a file created by
623
the mysqld server, but the check is still valid in most context.
625
if ((stat_info.st_mode & S_IWOTH) &&
626
(stat_info.st_mode & S_IFMT) == S_IFREG)
628
fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
633
if (!(fp= fopen(name, "r")))
634
return 1; /* Ignore wrong files */
636
memset(buff,0,sizeof(buff));
637
while (fgets(buff, sizeof(buff) - 1, fp))
640
/* Ignore comment and empty lines */
641
for (ptr= buff; my_isspace(&my_charset_utf8_general_ci, *ptr); ptr++)
644
if (*ptr == '#' || *ptr == ';' || !*ptr)
647
/* Configuration File Directives */
650
if (recursion_level >= max_recursion_level)
652
for (end= ptr + strlen(ptr) - 1;
653
my_isspace(&my_charset_utf8_general_ci, *(end - 1));
658
"Warning: skipping '%s' directive as maximum include"
659
"recursion level was reached in file %s at line %d\n",
664
/* skip over `!' and following whitespace */
665
for (++ptr; my_isspace(&my_charset_utf8_general_ci, ptr[0]); ptr++)
668
if ((!strncmp(ptr, includedir_keyword,
669
sizeof(includedir_keyword) - 1)) &&
670
my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(includedir_keyword) - 1]))
672
if (!(ptr= get_argument(includedir_keyword,
673
sizeof(includedir_keyword),
677
CachedDirectory dir_cache(ptr);
679
if (dir_cache.fail())
683
* Since clients still use this code, we use fprintf here.
684
* This fprintf needs to be turned into errmsg_printf
685
* as soon as the client programs no longer use mysys
686
* and can use the pluggable error message system.
688
fprintf(stderr, _("error: could not open directory: %s\n"), ptr);
692
CachedDirectory::Entries files= dir_cache.getEntries();
693
CachedDirectory::Entries::iterator file_iter= files.begin();
695
while (file_iter != files.end())
697
CachedDirectory::Entry *entry= *file_iter;
698
ext= fn_ext(entry->filename.c_str());
700
/* check extension */
701
for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
703
if (!strcmp(ext, *tmp_ext))
705
fn_format(tmp, entry->filename.c_str(), ptr, "",
706
MY_UNPACK_FILENAME | MY_SAFE_PATH);
708
search_default_file_with_ext(opt_handler, handler_ctx, "", "",
709
tmp, recursion_level + 1);
716
else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
717
my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(include_keyword)-1]))
719
if (!(ptr= get_argument(include_keyword,
720
sizeof(include_keyword), ptr,
724
search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
725
recursion_level + 1);
731
if (*ptr == '[') /* Group name */
734
if (!(end=(char *) strchr(++ptr,']')))
737
"error: Wrong group definition in config file: %s at line %d\n",
741
/* Remove end space */
742
for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) ; end--) ;
745
strncpy(curr_gr, ptr, min((size_t) (end-ptr)+1, sizeof(curr_gr)-1));
746
curr_gr[min((size_t)(end-ptr)+1, sizeof(curr_gr)-1)] = '\0';
748
/* signal that a new group is found */
749
opt_handler(handler_ctx, curr_gr, NULL);
756
"error: Found option without preceding group in config file: %s at line: %d\n",
762
end= remove_end_comment(ptr);
763
if ((value= strchr(ptr, '=')))
764
end= value; /* Option without argument */
765
for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) || end[-1]== '\n'; end--) ;
768
strncpy(strcpy(option,"--")+2,ptr,strlen(ptr)+1);
769
if (opt_handler(handler_ctx, curr_gr, option))
774
/* Remove pre- and end space */
776
for (value++ ; my_isspace(&my_charset_utf8_general_ci,*value); value++) ;
777
value_end= strchr(value, '\0');
779
We don't have to test for value_end >= value as we know there is
782
for ( ; my_isspace(&my_charset_utf8_general_ci,value_end[-1]) ; value_end--) ;
783
if (value_end < value) /* Empty string */
786
/* remove quotes around argument */
787
if ((*value == '\"' || *value == '\'') && /* First char is quote */
788
(value + 1 < value_end ) && /* String is longer than 1 */
789
*value == value_end[-1] ) /* First char is equal to last char */
795
memset(option,0,2+(size_t)(end-ptr)+1);
796
ptr= strncpy(strcpy(option,"--")+2,ptr,(size_t) (end-ptr));
801
for ( ; value != value_end; value++)
803
if (*value == '\\' && value != value_end-1)
819
*ptr++= ' '; /* space */
830
default: /* Unknown; Keep '\' */
840
if (opt_handler(handler_ctx, curr_gr, option))
850
return -1; /* Fatal error */
854
static char *remove_end_comment(char *ptr)
856
char quote= 0; /* we are inside quote marks */
857
char escape= 0; /* symbol is protected by escape chagacter */
861
if ((*ptr == '\'' || *ptr == '\"') && !escape)
865
else if (quote == *ptr)
868
/* We are not inside a string */
869
if (!quote && *ptr == '#')
874
escape= (quote && *ptr == '\\' && !escape);
879
void my_print_default_files(const char *conf_file)
881
const char *empty_list[]= { "", 0 };
882
bool have_ext= fn_ext(conf_file)[0] != 0;
883
const char **exts_to_use= have_ext ? empty_list : f_extensions;
884
char name[FN_REFLEN], **ext;
887
init_default_directories();
888
puts("\nDefault options are read from the following files in the given order:");
890
if (dirname_length(conf_file))
891
fputs(conf_file,stdout);
894
for (dirs=default_directories ; *dirs; dirs++)
896
for (ext= (char**) exts_to_use; *ext; ext++)
902
else if (my_defaults_extra_file)
903
pos= my_defaults_extra_file;
906
end= convert_dirname(name, pos, NULL);
907
if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
909
sprintf(end,"%s%s ",conf_file, *ext);
917
void print_defaults(const char *conf_file, const char **groups)
919
const char **groups_save= groups;
920
my_print_default_files(conf_file);
922
fputs("The following groups are read:",stdout);
923
for ( ; *groups ; groups++)
926
fputs(*groups,stdout);
929
if (my_defaults_group_suffix)
932
for ( ; *groups ; groups++)
935
fputs(*groups,stdout);
936
fputs(my_defaults_group_suffix,stdout);
939
puts("\nThe following options may be given as the first argument:\n\
940
--no-defaults Don't read default options from any options file\n\
941
--defaults-file=# Only read default options from the given file #\n\
942
--defaults-extra-file=# Read this file after the global files are read");
946
This extra complexity is to avoid declaring 'rc' if it won't be
949
static void add_directory(const char* dir)
951
array_append_string_unique(dir, default_directories, array_elements(default_directories));
954
static void add_common_directories()
956
const char *env= getenv("DRIZZLE_HOME");
959
// Placeholder for --defaults-extra-file=<path>
964
Initialize default directories for Unix
969
3. --sysconfdir=<path> (compile-time option)
970
4. getenv("DRIZZLE_HOME")
971
5. --defaults-extra-file=<path> (run-time option)
975
static void init_default_directories(void)
977
memset(default_directories, 0, sizeof(default_directories));
978
add_directory("/etc/");
979
add_directory("/etc/drizzle/");
980
add_directory(SYSCONFDIR);
981
add_common_directories();
985
} /* namespace internal */
986
} /* namespace drizzled */