2
* config.c : reading configuration information
4
* ====================================================================
5
* Copyright (c) 2000-2004 CollabNet. All rights reserved.
7
* This software is licensed as described in the file COPYING, which
8
* you should have received as part of this distribution. The terms
9
* are also available at http://subversion.tigris.org/license-1.html.
10
* If newer versions of this license are posted there, you may use a
11
* newer version instead, at your option.
13
* This software consists of voluntary contributions made by many
14
* individuals. For exact contribution history, see the revision
15
* history and logs, available at http://subversion.tigris.org/.
16
* ====================================================================
21
#define APR_WANT_STRFUNC
22
#define APR_WANT_MEMFUNC
25
#include <apr_general.h>
27
#include "svn_error.h"
28
#include "svn_pools.h"
29
#include "config_impl.h"
31
#include "svn_private_config.h"
36
/* Section table entries. */
37
typedef struct cfg_section_t cfg_section_t;
40
/* The section name. */
43
/* The section name, converted into a hash key. */
46
/* Table of cfg_option_t's. */
51
/* Option table entries. */
52
typedef struct cfg_option_t cfg_option_t;
55
/* The option name. */
58
/* The option name, converted into a hash key. */
61
/* The unexpanded option value. */
64
/* The expanded option value. */
67
/* Expansion flag. If this is TRUE, this value has already been expanded.
68
In this case, if x_value is NULL, no expansions were necessary,
69
and value should be used directly. */
70
svn_boolean_t expanded;
76
svn_config_read (svn_config_t **cfgp, const char *file,
77
svn_boolean_t must_exist, apr_pool_t *pool)
79
svn_config_t *cfg = apr_palloc (pool, sizeof (*cfg));
82
cfg->sections = apr_hash_make (pool);
84
cfg->x_pool = svn_pool_create (pool);
85
cfg->x_values = FALSE;
86
cfg->tmp_key = svn_stringbuf_create ("", pool);
87
cfg->tmp_value = svn_stringbuf_create ("", pool);
89
/* Yes, this is platform-specific code in Subversion, but there's no
90
practical way to migrate it into APR, as it's simultaneously
91
Subversion-specific and Windows-specific. Even if we eventually
92
want to have APR offer a generic config-reading interface, it
93
makes sense to test it here first and migrate it later. */
95
if (0 == strncmp (file, SVN_REGISTRY_PREFIX, SVN_REGISTRY_PREFIX_LEN))
96
err = svn_config__parse_registry (cfg, file + SVN_REGISTRY_PREFIX_LEN,
100
err = svn_config__parse_file (cfg, file, must_exist);
102
if (err != SVN_NO_ERROR)
112
/* Read various configuration sources into *CFGP, in this order, with
113
* later reads overriding the results of earlier ones:
115
* 1. SYS_REGISTRY_PATH (only on Win32, but ignored if NULL)
117
* 2. SYS_FILE_PATH (everywhere, but ignored if NULL)
119
* 3. USR_REGISTRY_PATH (only on Win32, but ignored if NULL)
121
* 4. USR_FILE_PATH (everywhere, but ignored if NULL)
123
* Allocate *CFGP in POOL. Even if no configurations are read,
124
* allocate an empty *CFGP.
127
read_all (svn_config_t **cfgp,
128
const char *sys_registry_path,
129
const char *usr_registry_path,
130
const char *sys_file_path,
131
const char *usr_file_path,
134
svn_boolean_t red_config = FALSE; /* "red" is the past tense of "read" */
136
/*** Read system-wide configurations first... ***/
139
if (sys_registry_path)
141
SVN_ERR (svn_config_read (cfgp, sys_registry_path, FALSE, pool));
149
SVN_ERR (svn_config_merge (*cfgp, sys_file_path, FALSE));
152
SVN_ERR (svn_config_read (cfgp, sys_file_path, FALSE, pool));
157
/*** ...followed by per-user configurations. ***/
160
if (usr_registry_path)
163
SVN_ERR (svn_config_merge (*cfgp, usr_registry_path, FALSE));
166
SVN_ERR (svn_config_read (cfgp, usr_registry_path, FALSE, pool));
175
SVN_ERR (svn_config_merge (*cfgp, usr_file_path, FALSE));
178
SVN_ERR (svn_config_read (cfgp, usr_file_path, FALSE, pool));
191
get_category_config (svn_config_t **cfg,
192
const char *config_dir,
193
const char *category,
196
const char *usr_reg_path = NULL, *sys_reg_path = NULL;
197
const char *usr_cfg_path, *sys_cfg_path;
204
sys_reg_path = apr_pstrcat (pool, SVN_REGISTRY_SYS_CONFIG_PATH,
206
usr_reg_path = apr_pstrcat (pool, SVN_REGISTRY_USR_CONFIG_PATH,
210
SVN_ERR (svn_config__sys_config_path (&sys_cfg_path, category, pool));
215
SVN_ERR (svn_config__user_config_path (config_dir, &usr_cfg_path, category,
217
SVN_ERR (read_all (cfg,
218
sys_reg_path, usr_reg_path,
219
sys_cfg_path, usr_cfg_path,
227
svn_config_get_config (apr_hash_t **cfg_hash,
228
const char *config_dir,
232
*cfg_hash = apr_hash_make (pool);
234
#define CATLEN (sizeof (SVN_CONFIG_CATEGORY_SERVERS) - 1)
235
SVN_ERR (get_category_config (&cfg, config_dir, SVN_CONFIG_CATEGORY_SERVERS,
238
apr_hash_set (*cfg_hash, SVN_CONFIG_CATEGORY_SERVERS, CATLEN, cfg);
241
#define CATLEN (sizeof (SVN_CONFIG_CATEGORY_CONFIG) - 1)
242
SVN_ERR (get_category_config (&cfg, config_dir, SVN_CONFIG_CATEGORY_CONFIG,
245
apr_hash_set (*cfg_hash, SVN_CONFIG_CATEGORY_CONFIG, CATLEN, cfg);
253
/* Iterate through CFG, passing BATON to CALLBACK for every (SECTION, OPTION)
254
pair. Stop if CALLBACK returns TRUE. Allocate from POOL. */
256
for_each_option (svn_config_t *cfg, void *baton, apr_pool_t *pool,
257
svn_boolean_t callback (void *same_baton,
258
cfg_section_t *section,
259
cfg_option_t *option))
261
apr_hash_index_t *sec_ndx;
262
for (sec_ndx = apr_hash_first (pool, cfg->sections);
264
sec_ndx = apr_hash_next (sec_ndx))
268
apr_hash_index_t *opt_ndx;
270
apr_hash_this (sec_ndx, NULL, NULL, &sec_ptr);
273
for (opt_ndx = apr_hash_first (pool, sec->options);
275
opt_ndx = apr_hash_next (opt_ndx))
280
apr_hash_this (opt_ndx, NULL, NULL, &opt_ptr);
283
if (callback (baton, sec, opt))
292
merge_callback (void *baton, cfg_section_t *section, cfg_option_t *option)
294
svn_config_set (baton, section->name, option->name, option->value);
299
svn_config_merge (svn_config_t *cfg, const char *file,
300
svn_boolean_t must_exist)
302
/* The original config hash shouldn't change if there's an error
303
while reading the confguration, so read into a temporary table.
304
### We could use a tmp subpool for this, since merge_cfg is going
305
to be tossed afterwards. Premature optimization, though? */
306
svn_config_t *merge_cfg;
307
SVN_ERR (svn_config_read (&merge_cfg, file, must_exist, cfg->pool));
309
/* Now copy the new options into the original table. */
310
for_each_option (merge_cfg, cfg, merge_cfg->pool, merge_callback);
316
/* Remove variable expansions from CFG. Walk through the options tree,
317
killing all expanded values, then clear the expanded value pool. */
319
rmex_callback (void *baton, cfg_section_t *section, cfg_option_t *option)
321
/* Only clear the `expanded' flag if the value actually contains
322
variable expansions. */
323
if (option->expanded && option->x_value != NULL)
325
option->x_value = NULL;
326
option->expanded = FALSE;
329
(void)(baton); /* Unused parameter. */
330
(void)(section); /* Unused parameter. */
335
remove_expansions (svn_config_t *cfg)
340
for_each_option (cfg, NULL, cfg->x_pool, rmex_callback);
341
apr_pool_clear (cfg->x_pool);
342
cfg->x_values = FALSE;
347
/* Canonicalize a string for hashing. Modifies KEY in place. */
348
static APR_INLINE char *
349
make_hash_key (char *key)
352
for (p = key; *p != 0; ++p)
353
*p = apr_tolower (*p);
358
/* Return a pointer to an option in CFG, or NULL if it doesn't exist.
359
if SECTIONP is non-null, return a pointer to the option's section.
360
OPTION may be NULL. */
361
static cfg_option_t *
362
find_option (svn_config_t *cfg, const char *section, const char *option,
363
cfg_section_t **sectionp)
367
/* Canonicalize the hash key */
368
svn_stringbuf_set (cfg->tmp_key, section);
369
make_hash_key (cfg->tmp_key->data);
371
sec_ptr = apr_hash_get (cfg->sections, cfg->tmp_key->data,
373
if (sectionp != NULL)
376
if (sec_ptr != NULL && option != NULL)
378
cfg_section_t *sec = sec_ptr;
381
/* Canonicalize the option key */
382
svn_stringbuf_set (cfg->tmp_key, option);
383
make_hash_key (cfg->tmp_key->data);
385
opt = apr_hash_get (sec->options, cfg->tmp_key->data,
387
/* NOTE: ConfigParser's sections are case sensitive. */
389
&& apr_strnatcasecmp(section, SVN_CONFIG__DEFAULT_SECTION) != 0)
390
/* Options which aren't found in the requested section are
391
also sought after in the default section. */
392
opt = find_option (cfg, SVN_CONFIG__DEFAULT_SECTION, option, &sec);
400
/* Has a bi-directional dependency with make_string_from_option(). */
402
expand_option_value (svn_config_t *cfg, cfg_section_t *section,
403
const char *opt_value, const char **opt_x_valuep,
407
/* Set *VALUEP according to the OPT's value. A value for X_POOL must
408
only ever be passed into this function by expand_option_value(). */
410
make_string_from_option (const char **valuep, svn_config_t *cfg,
411
cfg_section_t *section, cfg_option_t *opt,
414
/* Expand the option value if necessary. */
417
apr_pool_t *tmp_pool = (x_pool ? x_pool : svn_pool_create (cfg->x_pool));
419
expand_option_value (cfg, section, opt->value, &opt->x_value, tmp_pool);
420
opt->expanded = TRUE;
424
/* Grab the fully expanded value from tmp_pool before its
427
opt->x_value = apr_pstrmemdup (cfg->x_pool, opt->x_value,
428
strlen (opt->x_value));
429
svn_pool_destroy (tmp_pool);
434
*valuep = opt->x_value;
436
*valuep = opt->value;
440
/* Start of variable-replacement placeholder */
441
#define FMT_START "%("
442
#define FMT_START_LEN (sizeof (FMT_START) - 1)
444
/* End of variable-replacement placeholder */
446
#define FMT_END_LEN (sizeof (FMT_END) - 1)
449
/* Expand OPT_VALUE in SECTION to *OPT_X_VALUE. If no variable
450
replacements are done, set OPT_X_VALUE to NULL. Allocate from
453
expand_option_value (svn_config_t *cfg, cfg_section_t *section,
454
const char *opt_value, const char **opt_x_valuep,
457
svn_stringbuf_t *buf = NULL;
458
const char *parse_from = opt_value;
459
const char *copy_from = parse_from;
460
const char *name_start, *name_end;
462
while (parse_from != NULL
463
&& *parse_from != '\0'
464
&& (name_start = strstr (parse_from, FMT_START)) != NULL)
466
name_start += FMT_START_LEN;
467
if (*name_start == '\0')
468
/* FMT_START at end of opt_value. */
471
name_end = strstr (name_start, FMT_END);
472
if (name_end != NULL)
475
apr_size_t len = name_end - name_start;
476
char *name = apr_pstrmemdup (x_pool, name_start, len);
478
x_opt = find_option (cfg, section->name, name, NULL);
484
/* Pass back the sub-pool originally provided by
485
make_string_from_option() as an indication of when it
487
make_string_from_option (&cstring, cfg, section, x_opt, x_pool);
489
/* Append the plain text preceding the expansion. */
490
len = name_start - FMT_START_LEN - copy_from;
493
buf = svn_stringbuf_ncreate (copy_from, len, x_pool);
494
cfg->x_values = TRUE;
497
svn_stringbuf_appendbytes(buf, copy_from, len);
499
/* Append the expansion and adjust parse pointers. */
500
svn_stringbuf_appendcstr (buf, cstring);
501
parse_from = name_end + FMT_END_LEN;
502
copy_from = parse_from;
505
/* Though ConfigParser considers the failure to resolve
506
the requested expansion an exception condition, we
507
consider it to be plain text, and look for the start of
509
parse_from = name_end + FMT_END_LEN;
512
/* Though ConfigParser treats unterminated format specifiers
513
as an exception condition, we consider them to be plain
514
text. The fact that there are no more format specifier
515
endings means we're done parsing. */
521
/* Copy the remainder of the plain text. */
522
svn_stringbuf_appendcstr (buf, copy_from);
523
*opt_x_valuep = buf->data;
526
*opt_x_valuep = NULL;
532
svn_config_get (svn_config_t *cfg, const char **valuep,
533
const char *section, const char *option,
534
const char *default_value)
539
cfg_option_t *opt = find_option (cfg, section, option, &sec);
542
make_string_from_option (valuep, cfg, sec, opt, NULL);
546
apr_pool_t *tmp_pool = svn_pool_create (cfg->x_pool);
547
const char *x_default;
548
expand_option_value (cfg, sec, default_value, &x_default, tmp_pool);
551
svn_stringbuf_set (cfg->tmp_value, x_default);
552
*valuep = cfg->tmp_value->data;
555
*valuep = default_value;
556
svn_pool_destroy (tmp_pool);
561
*valuep = default_value;
568
svn_config_set (svn_config_t *cfg,
569
const char *section, const char *option,
575
remove_expansions (cfg);
577
opt = find_option (cfg, section, option, &sec);
580
/* Replace the option's value. */
581
opt->value = apr_pstrdup (cfg->pool, value);
582
opt->expanded = FALSE;
586
/* Create a new option */
587
opt = apr_palloc (cfg->pool, sizeof (*opt));
588
opt->name = apr_pstrdup (cfg->pool, option);
589
opt->hash_key = make_hash_key (apr_pstrdup (cfg->pool, option));
591
opt->value = apr_pstrdup (cfg->pool, value);
593
opt->expanded = FALSE;
597
/* Even the section doesn't exist. Create it. */
598
sec = apr_palloc (cfg->pool, sizeof (*sec));
599
sec->name = apr_pstrdup (cfg->pool, section);
600
sec->hash_key = make_hash_key (apr_pstrdup (cfg->pool, section));
601
sec->options = apr_hash_make (cfg->pool);
602
apr_hash_set (cfg->sections, sec->hash_key, APR_HASH_KEY_STRING, sec);
605
apr_hash_set (sec->options, opt->hash_key, APR_HASH_KEY_STRING, opt);
611
svn_config_get_bool (svn_config_t *cfg, svn_boolean_t *valuep,
612
const char *section, const char *option,
613
svn_boolean_t default_value)
615
const char *tmp_value;
617
svn_config_get (cfg, &tmp_value, section, option, NULL);
618
if (tmp_value == NULL)
619
*valuep = default_value;
620
else if (0 == strcasecmp (tmp_value, SVN_CONFIG_TRUE)
621
|| 0 == strcasecmp (tmp_value, "yes")
622
|| 0 == strcasecmp (tmp_value, "on")
623
|| 0 == strcmp (tmp_value, "1"))
625
else if (0 == strcasecmp (tmp_value, SVN_CONFIG_FALSE)
626
|| 0 == strcasecmp (tmp_value, "no")
627
|| 0 == strcasecmp (tmp_value, "off")
628
|| 0 == strcmp (tmp_value, "0"))
631
return svn_error_createf (SVN_ERR_RA_DAV_INVALID_CONFIG_VALUE, NULL,
632
_("Config error: invalid boolean value '%s'"),
641
svn_config_set_bool (svn_config_t *cfg,
642
const char *section, const char *option,
645
svn_config_set (cfg, section, option,
646
(value ? SVN_CONFIG_TRUE : SVN_CONFIG_FALSE));
652
svn_config__enumerate_sections (svn_config_t *cfg,
653
svn_config__section_enumerator_t callback,
656
return svn_config_enumerate_sections (cfg,
657
(svn_config_section_enumerator_t) callback, baton);
661
svn_config_enumerate_sections (svn_config_t *cfg,
662
svn_config_section_enumerator_t callback,
665
apr_hash_index_t *sec_ndx;
668
for (sec_ndx = apr_hash_first (cfg->x_pool, cfg->sections);
670
sec_ndx = apr_hash_next (sec_ndx))
675
apr_hash_this (sec_ndx, NULL, NULL, &sec_ptr);
678
if (!callback (sec->name, baton))
688
svn_config_enumerate (svn_config_t *cfg, const char *section,
689
svn_config_enumerator_t callback, void *baton)
692
apr_hash_index_t *opt_ndx;
695
find_option (cfg, section, NULL, &sec);
700
for (opt_ndx = apr_hash_first (cfg->x_pool, sec->options);
702
opt_ndx = apr_hash_next (opt_ndx))
706
const char *temp_value;
708
apr_hash_this (opt_ndx, NULL, NULL, &opt_ptr);
712
make_string_from_option (&temp_value, cfg, sec, opt, NULL);
713
if (!callback (opt->name, temp_value, baton))
722
/* Baton for search_groups() */
723
struct search_groups_baton
725
const char *key; /* Provided by caller of svn_config_find_group */
726
const char *match; /* Filled in by search_groups */
731
/* This is an `svn_config_enumerator_t' function, and BATON is a
732
* `struct search_groups_baton *'.
734
static svn_boolean_t search_groups (const char *name,
738
struct search_groups_baton *b = baton;
739
apr_array_header_t *list;
741
list = svn_cstring_split (value, ",", TRUE, b->pool);
742
if (svn_cstring_match_glob_list (b->key, list))
744
/* Fill in the match and return false, to stop enumerating. */
745
b->match = apr_pstrdup (b->pool, name);
753
const char *svn_config_find_group (svn_config_t *cfg, const char *key,
754
const char *master_section,
757
struct search_groups_baton gb;
762
svn_config_enumerate (cfg, master_section, search_groups, &gb);
768
svn_config_get_server_setting (svn_config_t *cfg,
769
const char* server_group,
770
const char* option_name,
771
const char* default_value)
774
svn_config_get (cfg, &retval, SVN_CONFIG_SECTION_GLOBAL,
775
option_name, default_value);
778
svn_config_get (cfg, &retval, server_group, option_name, retval);
784
svn_config_get_server_setting_int (svn_config_t *cfg,
785
const char *server_group,
786
const char *option_name,
787
apr_int64_t default_value,
788
apr_int64_t *result_value,
791
const char* tmp_value;
794
tmp_value = svn_config_get_server_setting (cfg, server_group,
796
if (tmp_value == NULL)
797
*result_value = default_value;
800
/* read tmp_value as an int now */
801
*result_value = apr_strtoi64 (tmp_value, &end_pos, 0);
805
return svn_error_createf
806
(SVN_ERR_RA_DAV_INVALID_CONFIG_VALUE, NULL,
807
_("Config error: invalid integer value '%s'"),