~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to drizzled/internal/default.cc

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2012-06-19 10:46:49 UTC
  • mfrom: (1.1.6)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20120619104649-e2l0ggd4oz3um0f4
Tags: upstream-7.1.36-stable
ImportĀ upstreamĀ versionĀ 7.1.36-stable

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2003 MySQL AB
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 as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
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.
11
 
 
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 */
15
 
 
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
20
 
 called 'group'.ini
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 \\
26
 
 
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
 
****************************************************************************/
35
 
 
36
 
#include <config.h>
37
 
 
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>
46
 
 
47
 
#ifdef HAVE_SYS_STAT_H
48
 
# include <sys/stat.h>
49
 
#endif
50
 
 
51
 
#include <cstdio>
52
 
#include <algorithm>
53
 
 
54
 
using namespace std;
55
 
 
56
 
namespace drizzled
57
 
{
58
 
namespace internal
59
 
{
60
 
 
61
 
const char *my_defaults_file=0;
62
 
const char *my_defaults_group_suffix=0;
63
 
char *my_defaults_extra_file=0;
64
 
 
65
 
/* Which directories are searched for options (and in which order) */
66
 
 
67
 
#define MAX_DEFAULT_DIRS 6
68
 
const char *default_directories[MAX_DEFAULT_DIRS + 1];
69
 
 
70
 
static const char *f_extensions[]= { ".cnf", 0 };
71
 
 
72
 
int handle_default_option(void *in_ctx, const char *group_name,
73
 
                          const char *option);
74
 
 
75
 
/*
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.
80
 
*/
81
 
 
82
 
struct handle_option_ctx
83
 
{
84
 
   memory::Root *alloc;
85
 
   DYNAMIC_ARRAY *args;
86
 
   TYPELIB *group;
87
 
};
88
 
 
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,
92
 
                                        void *func_ctx,
93
 
                                        const char *dir, const char *ext,
94
 
                                        const char *config_file, int recursion_level);
95
 
 
96
 
 
97
 
 
98
 
/**
99
 
  Create the list of default directories.
100
 
 
101
 
  @details
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.
105
 
 
106
 
  @return void
107
 
*/
108
 
 
109
 
static void init_default_directories(void);
110
 
 
111
 
 
112
 
static char *remove_end_comment(char *ptr);
113
 
 
114
 
 
115
 
/*
116
 
  Process config files in default directories.
117
 
 
118
 
  SYNOPSIS
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
125
 
                              arguments used.
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.
129
 
  DESCRIPTION
130
 
    Process the default options from argc & argv
131
 
    Read through each found config file looks and calls 'func' to process
132
 
    each option.
133
 
 
134
 
  NOTES
135
 
    --defaults-group-suffix is only processed if we are called from
136
 
    load_defaults().
137
 
 
138
 
 
139
 
  RETURN
140
 
    0  ok
141
 
    1  given cinf_file doesn't exist
142
 
 
143
 
    The global variable 'my_defaults_group_suffix' is updated with value for
144
 
    --defaults_group_suffix
145
 
*/
146
 
 
147
 
int my_search_option_files(const char *conf_file, int *argc, char ***argv,
148
 
                           uint32_t *args_used, Process_option_func func,
149
 
                           void *func_ctx)
150
 
{
151
 
  const char **dirs, *forced_default_file, *forced_extra_defaults;
152
 
  int error= 0;
153
 
 
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);
159
 
 
160
 
  if (! my_defaults_group_suffix)
161
 
    my_defaults_group_suffix= getenv("DRIZZLE_GROUP_SUFFIX");
162
 
 
163
 
  if (forced_extra_defaults)
164
 
    my_defaults_extra_file= (char *) forced_extra_defaults;
165
 
 
166
 
  if (forced_default_file)
167
 
    my_defaults_file= forced_default_file;
168
 
 
169
 
  /*
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'
172
 
  */
173
 
 
174
 
  if (my_defaults_group_suffix && (func == handle_default_option))
175
 
  {
176
 
    /* Handle --defaults-group-suffix= */
177
 
    uint32_t i;
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;
181
 
    char *ptr;
182
 
    TYPELIB *group= ctx->group;
183
 
 
184
 
    if (!(extra_groups=
185
 
          (const char**)ctx->alloc->alloc_root(
186
 
                                   (2*group->count+1)*sizeof(char*))))
187
 
      goto err;
188
 
 
189
 
    for (i= 0; i < group->count; i++)
190
 
    {
191
 
      size_t len;
192
 
      extra_groups[i]= group->type_names[i]; /** copy group */
193
 
 
194
 
      len= strlen(extra_groups[i]);
195
 
      if (!(ptr= (char *)ctx->alloc->alloc_root( len+instance_len+1)))
196
 
        goto err;
197
 
 
198
 
      extra_groups[i+group->count]= ptr;
199
 
 
200
 
      /** Construct new group */
201
 
      memcpy(ptr, extra_groups[i], len);
202
 
      memcpy(ptr+len, my_defaults_group_suffix, instance_len+1);
203
 
    }
204
 
 
205
 
    group->count*= 2;
206
 
    group->type_names= extra_groups;
207
 
    group->type_names[group->count]= 0;
208
 
  }
209
 
 
210
 
  if (forced_default_file)
211
 
  {
212
 
    if ((error= search_default_file_with_ext(func, func_ctx, "", "",
213
 
                                             forced_default_file, 0)) < 0)
214
 
      goto err;
215
 
    if (error > 0)
216
 
    {
217
 
      fprintf(stderr, "Could not open required defaults file: %s\n",
218
 
              forced_default_file);
219
 
      goto err;
220
 
    }
221
 
  }
222
 
  else if (dirname_length(conf_file))
223
 
  {
224
 
    if ((error= search_default_file(func, func_ctx, NULL, conf_file)) < 0)
225
 
      goto err;
226
 
  }
227
 
  else
228
 
  {
229
 
    for (dirs= default_directories ; *dirs; dirs++)
230
 
    {
231
 
      if (**dirs)
232
 
      {
233
 
        if (search_default_file(func, func_ctx, *dirs, conf_file) < 0)
234
 
          goto err;
235
 
      }
236
 
      else if (my_defaults_extra_file)
237
 
      {
238
 
        if ((error= search_default_file_with_ext(func, func_ctx, "", "",
239
 
                                                my_defaults_extra_file, 0)) < 0)
240
 
          goto err;                             /* Fatal error */
241
 
        if (error > 0)
242
 
        {
243
 
          fprintf(stderr, "Could not open required defaults file: %s\n",
244
 
                  my_defaults_extra_file);
245
 
          goto err;
246
 
        }
247
 
      }
248
 
    }
249
 
  }
250
 
 
251
 
  return(error);
252
 
 
253
 
err:
254
 
  fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
255
 
  exit(1);
256
 
}
257
 
 
258
 
 
259
 
/*
260
 
  The option handler for load_defaults.
261
 
 
262
 
  SYNOPSIS
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).
270
 
 
271
 
  DESCRIPTION
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
275
 
    groups.
276
 
 
277
 
  RETURN
278
 
    0 - ok
279
 
    1 - error occured
280
 
*/
281
 
 
282
 
int handle_default_option(void *in_ctx, const char *group_name,
283
 
                          const char *option)
284
 
{
285
 
  char *tmp;
286
 
  struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
287
 
 
288
 
  if (!option)
289
 
    return 0;
290
 
 
291
 
  if (ctx->group->find_type(const_cast<char*>(group_name), 3))
292
 
  {
293
 
    if (!(tmp= (char *)ctx->alloc->alloc_root(strlen(option) + 1)))
294
 
      return 1;
295
 
    ctx->args->push_back(&tmp);
296
 
    strcpy(tmp, option);
297
 
  }
298
 
 
299
 
  return 0;
300
 
}
301
 
 
302
 
 
303
 
/*
304
 
  Gets options from the command line
305
 
 
306
 
  SYNOPSIS
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
312
 
 
313
 
  RETURN
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
317
 
*/
318
 
 
319
 
int get_defaults_options(int argc, char **argv,
320
 
                         char **defaults,
321
 
                         char **extra_defaults,
322
 
                         char **group_suffix)
323
 
{
324
 
  int org_argc= argc, prev_argc= 0;
325
 
  *defaults= *extra_defaults= *group_suffix= 0;
326
 
 
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=");
330
 
 
331
 
  while (argc >= 2 && argc != prev_argc)
332
 
  {
333
 
    /* Skip program name or previously handled argument */
334
 
    argv++;
335
 
    prev_argc= argc;                            /* To check if we found */
336
 
    if (!*defaults && (strncmp(*argv,
337
 
                               DEFAULTS_FILE.c_str(),
338
 
                               DEFAULTS_FILE.size()) == 0))
339
 
    {
340
 
      *defaults= *argv + DEFAULTS_FILE.size();
341
 
       argc--;
342
 
       continue;
343
 
    }
344
 
    if (!*extra_defaults && (strncmp(*argv, 
345
 
                                     DEFAULTS_EXTRA_FILE.c_str(),
346
 
                                     DEFAULTS_EXTRA_FILE.size()) == 0))
347
 
    {
348
 
      *extra_defaults= *argv + DEFAULTS_EXTRA_FILE.size();
349
 
      argc--;
350
 
      continue;
351
 
    }
352
 
    if (!*group_suffix && (strncmp(*argv, 
353
 
                                   DEFAULTS_GROUP_SUFFIX.c_str(),
354
 
                                   DEFAULTS_GROUP_SUFFIX.size()) == 0))
355
 
 
356
 
    {
357
 
      *group_suffix= *argv + DEFAULTS_GROUP_SUFFIX.size();
358
 
      argc--;
359
 
      continue;
360
 
    }
361
 
  }
362
 
  return org_argc - argc;
363
 
}
364
 
 
365
 
 
366
 
/*
367
 
  Read options from configurations files
368
 
 
369
 
  SYNOPSIS
370
 
    load_defaults()
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
377
 
 
378
 
  IMPLEMENTATION
379
 
 
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
383
 
 
384
 
   NOTES
385
 
    In case of fatal error, the function will print a warning and do
386
 
    exit(1)
387
 
 
388
 
    To free used memory one should call free_defaults() with the argument
389
 
    that was put in *argv
390
 
 
391
 
   RETURN
392
 
     0  ok
393
 
     1  The given conf_file didn't exists
394
 
*/
395
 
 
396
 
 
397
 
int load_defaults(const char *conf_file, const char **groups,
398
 
                  int *argc, char ***argv)
399
 
{
400
 
  DYNAMIC_ARRAY args;
401
 
  TYPELIB group;
402
 
  uint32_t args_used= 0;
403
 
  int error= 0;
404
 
  memory::Root alloc(512);
405
 
  char *ptr,**res;
406
 
  struct handle_option_ctx ctx;
407
 
 
408
 
  init_default_directories();
409
 
  /*
410
 
    Check if the user doesn't want any default option processing
411
 
    --no-defaults is always the first option
412
 
  */
413
 
  if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
414
 
  {
415
 
    /* remove the --no-defaults argument and return only the other arguments */
416
 
    uint32_t i;
417
 
    if (!(ptr=(char*) alloc.alloc_root(sizeof(alloc)+ (*argc + 1)*sizeof(char*))))
418
 
      goto err;
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++)
423
 
      res[i-1]=argv[0][i];
424
 
    res[i-1]=0;                                 /* End pointer */
425
 
    (*argc)--;
426
 
    *argv=res;
427
 
    *(memory::Root*) ptr= alloc;                        /* Save alloc root for free */
428
 
    return(0);
429
 
  }
430
 
 
431
 
  group.count=0;
432
 
  group.name= "defaults";
433
 
  group.type_names= groups;
434
 
 
435
 
  for (; *groups ; groups++)
436
 
    group.count++;
437
 
 
438
 
  if (my_init_dynamic_array(&args, sizeof(char*),*argc, 32))
439
 
    goto err;
440
 
 
441
 
  ctx.alloc= &alloc;
442
 
  ctx.args= &args;
443
 
  ctx.group= &group;
444
 
 
445
 
  error= my_search_option_files(conf_file, argc, argv, &args_used,
446
 
                                handle_default_option, (void *) &ctx);
447
 
  /*
448
 
    Here error contains <> 0 only if we have a fully specified conf_file
449
 
    or a forced default file
450
 
  */
451
 
  if (!(ptr=(char*) alloc.alloc_root(sizeof(alloc)+ (args.size() + *argc +1) *sizeof(char*))))
452
 
    goto err;
453
 
  res= (char**) (ptr+sizeof(alloc));
454
 
 
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 */
459
 
  (*argc)-= args_used;
460
 
  (*argv)+= args_used;
461
 
 
462
 
  /*
463
 
    Check if we wan't to see the new argument list
464
 
    This options must always be the last of the default options
465
 
  */
466
 
  if (*argc)
467
 
    memcpy(res+1+args.size(), *argv + 1, (*argc-1)*sizeof(char*));
468
 
  res[args.size()+ *argc]=0;                    /* last null */
469
 
 
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);
474
 
 
475
 
  return(error);
476
 
 
477
 
 err:
478
 
  fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
479
 
  exit(1);
480
 
}
481
 
 
482
 
 
483
 
void free_defaults(char **argv)
484
 
{
485
 
  memory::Root ptr;
486
 
  memcpy(&ptr, (char*) argv - sizeof(ptr), sizeof(ptr));
487
 
  ptr.free_root(MYF(0));
488
 
}
489
 
 
490
 
 
491
 
static int search_default_file(Process_option_func opt_handler,
492
 
                               void *handler_ctx,
493
 
                               const char *dir,
494
 
                               const char *config_file)
495
 
{
496
 
  char **ext;
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;
500
 
 
501
 
  for (ext= (char**) exts_to_use; *ext; ext++)
502
 
  {
503
 
    int error;
504
 
    if ((error= search_default_file_with_ext(opt_handler, handler_ctx,
505
 
                                             dir, *ext,
506
 
                                             config_file, 0)) < 0)
507
 
      return error;
508
 
  }
509
 
  return 0;
510
 
}
511
 
 
512
 
 
513
 
/*
514
 
  Skip over keyword and get argument after keyword
515
 
 
516
 
  SYNOPSIS
517
 
   get_argument()
518
 
   keyword              Include directive keyword
519
 
   kwlen                Length of keyword
520
 
   ptr                  Pointer to the keword in the line under process
521
 
   line                 line number
522
 
 
523
 
  RETURN
524
 
   0    error
525
 
   #    Returns pointer to the argument after the keyword.
526
 
*/
527
 
 
528
 
static char *get_argument(const char *keyword, size_t kwlen,
529
 
                          char *ptr, char *name, uint32_t line)
530
 
{
531
 
  char *end;
532
 
 
533
 
  /* Skip over "include / includedir keyword" and following whitespace */
534
 
 
535
 
  for (ptr+= kwlen - 1;
536
 
       my_isspace(&my_charset_utf8_general_ci, ptr[0]);
537
 
       ptr++)
538
 
  {}
539
 
 
540
 
  /*
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
544
 
  */
545
 
  for (end= ptr + strlen(ptr) - 1;
546
 
       my_isspace(&my_charset_utf8_general_ci, *(end - 1));
547
 
       end--)
548
 
  {}
549
 
  end[0]= 0;                                    /* Cut off end space */
550
 
 
551
 
  /* Print error msg if there is nothing after !include* directive */
552
 
  if (end <= ptr)
553
 
  {
554
 
    fprintf(stderr,
555
 
            "error: Wrong '!%s' directive in config file: %s at line %d\n",
556
 
            keyword, name, line);
557
 
    return 0;
558
 
  }
559
 
  return ptr;
560
 
}
561
 
 
562
 
 
563
 
/*
564
 
  Open a configuration file (if exists) and read given options from it
565
 
 
566
 
  SYNOPSIS
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
575
 
    group                       groups to read
576
 
    recursion_level             the level of recursion, got while processing
577
 
                                "!include" or "!includedir"
578
 
 
579
 
  RETURN
580
 
    0   Success
581
 
    -1  Fatal error, abort
582
 
     1  File not found (Warning)
583
 
*/
584
 
 
585
 
static int search_default_file_with_ext(Process_option_func opt_handler,
586
 
                                        void *handler_ctx,
587
 
                                        const char *dir,
588
 
                                        const char *ext,
589
 
                                        const char *config_file,
590
 
                                        int recursion_level)
591
 
{
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;
597
 
  FILE *fp;
598
 
  uint32_t line=0;
599
 
  bool found_group=0;
600
 
 
601
 
  if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
602
 
    return 0;                                   /* Ignore wrong paths */
603
 
  if (dir)
604
 
  {
605
 
    end=convert_dirname(name, dir, NULL);
606
 
    if (dir[0] == FN_HOMELIB)           /* Add . to filenames in home */
607
 
      *end++='.';
608
 
    sprintf(end,"%s%s",config_file,ext);
609
 
  }
610
 
  else
611
 
  {
612
 
    strcpy(name,config_file);
613
 
  }
614
 
  fn_format(name,name,"","",4);
615
 
  {
616
 
    struct stat stat_info;
617
 
    if (stat(name,&stat_info))
618
 
      return 1;
619
 
    /*
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.
623
 
    */
624
 
    if ((stat_info.st_mode & S_IWOTH) &&
625
 
        (stat_info.st_mode & S_IFMT) == S_IFREG)
626
 
    {
627
 
      fprintf(stderr, "Warning: World-writable config file '%s' is ignored\n",
628
 
              name);
629
 
      return 0;
630
 
    }
631
 
  }
632
 
  if (!(fp= fopen(name, "r")))
633
 
    return 1;                                   /* Ignore wrong files */
634
 
 
635
 
  memset(buff,0,sizeof(buff));
636
 
  while (fgets(buff, sizeof(buff) - 1, fp))
637
 
  {
638
 
    line++;
639
 
    /* Ignore comment and empty lines */
640
 
    for (ptr= buff; my_isspace(&my_charset_utf8_general_ci, *ptr); ptr++)
641
 
    {}
642
 
 
643
 
    if (*ptr == '#' || *ptr == ';' || !*ptr)
644
 
      continue;
645
 
 
646
 
    /* Configuration File Directives */
647
 
    if ((*ptr == '!'))
648
 
    {
649
 
      if (recursion_level >= max_recursion_level)
650
 
      {
651
 
        for (end= ptr + strlen(ptr) - 1;
652
 
             my_isspace(&my_charset_utf8_general_ci, *(end - 1));
653
 
             end--)
654
 
        {}
655
 
        end[0]= 0;
656
 
        fprintf(stderr,
657
 
                "Warning: skipping '%s' directive as maximum include"
658
 
                "recursion level was reached in file %s at line %d\n",
659
 
                ptr, name, line);
660
 
        continue;
661
 
      }
662
 
 
663
 
      /* skip over `!' and following whitespace */
664
 
      for (++ptr; my_isspace(&my_charset_utf8_general_ci, ptr[0]); ptr++)
665
 
      {}
666
 
 
667
 
      if ((!strncmp(ptr, includedir_keyword,
668
 
                    sizeof(includedir_keyword) - 1)) &&
669
 
          my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(includedir_keyword) - 1]))
670
 
      {
671
 
        if (!(ptr= get_argument(includedir_keyword,
672
 
                                sizeof(includedir_keyword),
673
 
                                ptr, name, line)))
674
 
          goto err;
675
 
 
676
 
        CachedDirectory dir_cache(ptr);
677
 
 
678
 
        if (dir_cache.fail())
679
 
        {
680
 
          /**
681
 
           * @todo
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.
686
 
           */
687
 
          fprintf(stderr, _("error: could not open directory: %s\n"), ptr);
688
 
          goto err;
689
 
        }
690
 
 
691
 
        CachedDirectory::Entries files= dir_cache.getEntries();
692
 
        CachedDirectory::Entries::iterator file_iter= files.begin();
693
 
 
694
 
        while (file_iter != files.end())
695
 
        {
696
 
          CachedDirectory::Entry *entry= *file_iter;
697
 
          ext= fn_ext(entry->filename.c_str());
698
 
 
699
 
          /* check extension */
700
 
          for (tmp_ext= (char**) f_extensions; *tmp_ext; tmp_ext++)
701
 
          {
702
 
            if (!strcmp(ext, *tmp_ext))
703
 
            {
704
 
              fn_format(tmp, entry->filename.c_str(), ptr, "",
705
 
                        MY_UNPACK_FILENAME | MY_SAFE_PATH);
706
 
 
707
 
              search_default_file_with_ext(opt_handler, handler_ctx, "", "",
708
 
                                           tmp, recursion_level + 1);
709
 
            }
710
 
          }
711
 
 
712
 
          ++file_iter;
713
 
        }
714
 
      }
715
 
      else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) &&
716
 
               my_isspace(&my_charset_utf8_general_ci, ptr[sizeof(include_keyword)-1]))
717
 
      {
718
 
        if (!(ptr= get_argument(include_keyword,
719
 
                                sizeof(include_keyword), ptr,
720
 
                                name, line)))
721
 
          goto err;
722
 
 
723
 
        search_default_file_with_ext(opt_handler, handler_ctx, "", "", ptr,
724
 
                                     recursion_level + 1);
725
 
      }
726
 
 
727
 
      continue;
728
 
    }
729
 
 
730
 
    if (*ptr == '[')                            /* Group name */
731
 
    {
732
 
      found_group=1;
733
 
      if (!(end=(char *) strchr(++ptr,']')))
734
 
      {
735
 
        fprintf(stderr,
736
 
                "error: Wrong group definition in config file: %s at line %d\n",
737
 
                name,line);
738
 
        goto err;
739
 
      }
740
 
      /* Remove end space */
741
 
      for ( ; my_isspace(&my_charset_utf8_general_ci,end[-1]) ; end--) ;
742
 
      end[0]=0;
743
 
 
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';
746
 
 
747
 
      /* signal that a new group is found */
748
 
      opt_handler(handler_ctx, curr_gr, NULL);
749
 
 
750
 
      continue;
751
 
    }
752
 
    if (!found_group)
753
 
    {
754
 
      fprintf(stderr,
755
 
              "error: Found option without preceding group in config file: %s at line: %d\n",
756
 
              name,line);
757
 
      goto err;
758
 
    }
759
 
 
760
 
 
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--) ;
765
 
    if (!value)
766
 
    {
767
 
      strncpy(strcpy(option,"--")+2,ptr,strlen(ptr)+1);
768
 
      if (opt_handler(handler_ctx, curr_gr, option))
769
 
        goto err;
770
 
    }
771
 
    else
772
 
    {
773
 
      /* Remove pre- and end space */
774
 
      char *value_end;
775
 
      for (value++ ; my_isspace(&my_charset_utf8_general_ci,*value); value++) ;
776
 
      value_end= strchr(value, '\0');
777
 
      /*
778
 
       We don't have to test for value_end >= value as we know there is
779
 
       an '=' before
780
 
      */
781
 
      for ( ; my_isspace(&my_charset_utf8_general_ci,value_end[-1]) ; value_end--) ;
782
 
      if (value_end < value)                    /* Empty string */
783
 
        value_end=value;
784
 
 
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 */
789
 
      {
790
 
        value++;
791
 
        value_end--;
792
 
      }
793
 
      
794
 
      memset(option,0,2+(size_t)(end-ptr)+1);
795
 
      ptr= strncpy(strcpy(option,"--")+2,ptr,(size_t) (end-ptr));
796
 
      ptr[end-ptr]= '\0';
797
 
      ptr+= strlen(ptr);
798
 
      *ptr++= '=';
799
 
 
800
 
      for ( ; value != value_end; value++)
801
 
      {
802
 
        if (*value == '\\' && value != value_end-1)
803
 
        {
804
 
          switch(*++value) {
805
 
          case 'n':
806
 
            *ptr++='\n';
807
 
            break;
808
 
          case 't':
809
 
            *ptr++= '\t';
810
 
            break;
811
 
          case 'r':
812
 
            *ptr++ = '\r';
813
 
            break;
814
 
          case 'b':
815
 
            *ptr++ = '\b';
816
 
            break;
817
 
          case 's':
818
 
            *ptr++= ' ';                        /* space */
819
 
            break;
820
 
          case '\"':
821
 
            *ptr++= '\"';
822
 
            break;
823
 
          case '\'':
824
 
            *ptr++= '\'';
825
 
            break;
826
 
          case '\\':
827
 
            *ptr++= '\\';
828
 
            break;
829
 
          default:                              /* Unknown; Keep '\' */
830
 
            *ptr++= '\\';
831
 
            *ptr++= *value;
832
 
            break;
833
 
          }
834
 
        }
835
 
        else
836
 
          *ptr++= *value;
837
 
      }
838
 
      *ptr=0;
839
 
      if (opt_handler(handler_ctx, curr_gr, option))
840
 
        goto err;
841
 
    }
842
 
  }
843
 
  fclose(fp);
844
 
  return(0);
845
 
 
846
 
 err:
847
 
  fclose(fp);
848
 
 
849
 
  return -1;                                    /* Fatal error */
850
 
}
851
 
 
852
 
 
853
 
static char *remove_end_comment(char *ptr)
854
 
{
855
 
  char quote= 0;        /* we are inside quote marks */
856
 
  char escape= 0;       /* symbol is protected by escape chagacter */
857
 
 
858
 
  for (; *ptr; ptr++)
859
 
  {
860
 
    if ((*ptr == '\'' || *ptr == '\"') && !escape)
861
 
    {
862
 
      if (!quote)
863
 
        quote= *ptr;
864
 
      else if (quote == *ptr)
865
 
        quote= 0;
866
 
    }
867
 
    /* We are not inside a string */
868
 
    if (!quote && *ptr == '#')
869
 
    {
870
 
      *ptr= 0;
871
 
      return ptr;
872
 
    }
873
 
    escape= (quote && *ptr == '\\' && !escape);
874
 
  }
875
 
  return ptr;
876
 
}
877
 
 
878
 
void my_print_default_files(const char *conf_file)
879
 
{
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;
884
 
  const char **dirs;
885
 
 
886
 
  init_default_directories();
887
 
  puts("\nDefault options are read from the following files in the given order:");
888
 
 
889
 
  if (dirname_length(conf_file))
890
 
    fputs(conf_file,stdout);
891
 
  else
892
 
  {
893
 
    for (dirs=default_directories ; *dirs; dirs++)
894
 
    {
895
 
      for (ext= (char**) exts_to_use; *ext; ext++)
896
 
      {
897
 
        const char *pos;
898
 
        char *end;
899
 
        if (**dirs)
900
 
          pos= *dirs;
901
 
        else if (my_defaults_extra_file)
902
 
          pos= my_defaults_extra_file;
903
 
        else
904
 
          continue;
905
 
        end= convert_dirname(name, pos, NULL);
906
 
        if (name[0] == FN_HOMELIB)      /* Add . to filenames in home */
907
 
          *end++='.';
908
 
  sprintf(end,"%s%s ",conf_file, *ext);
909
 
        fputs(name,stdout);
910
 
      }
911
 
    }
912
 
  }
913
 
  puts("");
914
 
}
915
 
 
916
 
void print_defaults(const char *conf_file, const char **groups)
917
 
{
918
 
  const char **groups_save= groups;
919
 
  my_print_default_files(conf_file);
920
 
 
921
 
  fputs("The following groups are read:",stdout);
922
 
  for ( ; *groups ; groups++)
923
 
  {
924
 
    fputc(' ',stdout);
925
 
    fputs(*groups,stdout);
926
 
  }
927
 
 
928
 
  if (my_defaults_group_suffix)
929
 
  {
930
 
    groups= groups_save;
931
 
    for ( ; *groups ; groups++)
932
 
    {
933
 
      fputc(' ',stdout);
934
 
      fputs(*groups,stdout);
935
 
      fputs(my_defaults_group_suffix,stdout);
936
 
    }
937
 
  }
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");
942
 
}
943
 
 
944
 
/*
945
 
  This extra complexity is to avoid declaring 'rc' if it won't be
946
 
  used.
947
 
*/
948
 
static void add_directory(const char* dir)
949
 
{
950
 
  array_append_string_unique(dir, default_directories, array_elements(default_directories));
951
 
}
952
 
 
953
 
static void add_common_directories()
954
 
{
955
 
  const char *env= getenv("DRIZZLE_HOME"); 
956
 
  if (env) 
957
 
    add_directory(env); 
958
 
  // Placeholder for --defaults-extra-file=<path>
959
 
  add_directory(""); 
960
 
}
961
 
 
962
 
/**
963
 
  Initialize default directories for Unix
964
 
 
965
 
  @details
966
 
    1. /etc/
967
 
    2. /etc/drizzle/
968
 
    3. --sysconfdir=<path> (compile-time option)
969
 
    4. getenv("DRIZZLE_HOME")
970
 
    5. --defaults-extra-file=<path> (run-time option)
971
 
    6. "~/"
972
 
*/
973
 
 
974
 
static void init_default_directories(void)
975
 
{
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();
981
 
  add_directory("~/");
982
 
}
983
 
 
984
 
} /* namespace internal */
985
 
} /* namespace drizzled */