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
, pool
);
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
));
190 /* CONFIG_DIR provides an override for the default behavior of reading
191 the default set of overlay files described by read_all()'s doc
194 get_category_config(svn_config_t
**cfg
,
195 const char *config_dir
,
196 const char *category
,
199 const char *usr_reg_path
= NULL
, *sys_reg_path
= NULL
;
200 const char *usr_cfg_path
, *sys_cfg_path
;
207 sys_reg_path
= apr_pstrcat(pool
, SVN_REGISTRY_SYS_CONFIG_PATH
,
209 usr_reg_path
= apr_pstrcat(pool
, SVN_REGISTRY_USR_CONFIG_PATH
,
213 SVN_ERR(svn_config__sys_config_path(&sys_cfg_path
, category
, pool
));
218 SVN_ERR(svn_config__user_config_path(config_dir
, &usr_cfg_path
, category
,
220 SVN_ERR(read_all(cfg
,
221 sys_reg_path
, usr_reg_path
,
222 sys_cfg_path
, usr_cfg_path
,
230 svn_config_get_config(apr_hash_t
**cfg_hash
,
231 const char *config_dir
,
235 *cfg_hash
= apr_hash_make(pool
);
237 #define CATLEN (sizeof(SVN_CONFIG_CATEGORY_SERVERS) - 1)
238 SVN_ERR(get_category_config(&cfg
, config_dir
, SVN_CONFIG_CATEGORY_SERVERS
,
241 apr_hash_set(*cfg_hash
, SVN_CONFIG_CATEGORY_SERVERS
, CATLEN
, cfg
);
244 #define CATLEN (sizeof(SVN_CONFIG_CATEGORY_CONFIG) - 1)
245 SVN_ERR(get_category_config(&cfg
, config_dir
, SVN_CONFIG_CATEGORY_CONFIG
,
248 apr_hash_set(*cfg_hash
, SVN_CONFIG_CATEGORY_CONFIG
, CATLEN
, cfg
);
256 /* Iterate through CFG, passing BATON to CALLBACK for every (SECTION, OPTION)
257 pair. Stop if CALLBACK returns TRUE. Allocate from POOL. */
259 for_each_option(svn_config_t
*cfg
, void *baton
, apr_pool_t
*pool
,
260 svn_boolean_t
callback(void *same_baton
,
261 cfg_section_t
*section
,
262 cfg_option_t
*option
))
264 apr_hash_index_t
*sec_ndx
;
265 for (sec_ndx
= apr_hash_first(pool
, cfg
->sections
);
267 sec_ndx
= apr_hash_next(sec_ndx
))
271 apr_hash_index_t
*opt_ndx
;
273 apr_hash_this(sec_ndx
, NULL
, NULL
, &sec_ptr
);
276 for (opt_ndx
= apr_hash_first(pool
, sec
->options
);
278 opt_ndx
= apr_hash_next(opt_ndx
))
283 apr_hash_this(opt_ndx
, NULL
, NULL
, &opt_ptr
);
286 if (callback(baton
, sec
, opt
))
295 merge_callback(void *baton
, cfg_section_t
*section
, cfg_option_t
*option
)
297 svn_config_set(baton
, section
->name
, option
->name
, option
->value
);
302 svn_config_merge(svn_config_t
*cfg
, const char *file
,
303 svn_boolean_t must_exist
)
305 /* The original config hash shouldn't change if there's an error
306 while reading the confguration, so read into a temporary table.
307 ### We could use a tmp subpool for this, since merge_cfg is going
308 to be tossed afterwards. Premature optimization, though? */
309 svn_config_t
*merge_cfg
;
310 SVN_ERR(svn_config_read(&merge_cfg
, file
, must_exist
, cfg
->pool
));
312 /* Now copy the new options into the original table. */
313 for_each_option(merge_cfg
, cfg
, merge_cfg
->pool
, merge_callback
);
319 /* Remove variable expansions from CFG. Walk through the options tree,
320 killing all expanded values, then clear the expanded value pool. */
322 rmex_callback(void *baton
, cfg_section_t
*section
, cfg_option_t
*option
)
324 /* Only clear the `expanded' flag if the value actually contains
325 variable expansions. */
326 if (option
->expanded
&& option
->x_value
!= NULL
)
328 option
->x_value
= NULL
;
329 option
->expanded
= FALSE
;
336 remove_expansions(svn_config_t
*cfg
)
341 for_each_option(cfg
, NULL
, cfg
->x_pool
, rmex_callback
);
342 svn_pool_clear(cfg
->x_pool
);
343 cfg
->x_values
= FALSE
;
348 /* Canonicalize a string for hashing. Modifies KEY in place. */
349 static APR_INLINE
char *
350 make_hash_key(char *key
)
353 for (p
= key
; *p
!= 0; ++p
)
354 *p
= apr_tolower(*p
);
359 /* Return a pointer to an option in CFG, or NULL if it doesn't exist.
360 if SECTIONP is non-null, return a pointer to the option's section.
361 OPTION may be NULL. */
362 static cfg_option_t
*
363 find_option(svn_config_t
*cfg
, const char *section
, const char *option
,
364 cfg_section_t
**sectionp
)
368 /* Canonicalize the hash key */
369 svn_stringbuf_set(cfg
->tmp_key
, section
);
370 make_hash_key(cfg
->tmp_key
->data
);
372 sec_ptr
= apr_hash_get(cfg
->sections
, cfg
->tmp_key
->data
,
374 if (sectionp
!= NULL
)
377 if (sec_ptr
!= NULL
&& option
!= NULL
)
379 cfg_section_t
*sec
= sec_ptr
;
382 /* Canonicalize the option key */
383 svn_stringbuf_set(cfg
->tmp_key
, option
);
384 make_hash_key(cfg
->tmp_key
->data
);
386 opt
= apr_hash_get(sec
->options
, cfg
->tmp_key
->data
,
388 /* NOTE: ConfigParser's sections are case sensitive. */
390 && apr_strnatcasecmp(section
, SVN_CONFIG__DEFAULT_SECTION
) != 0)
391 /* Options which aren't found in the requested section are
392 also sought after in the default section. */
393 opt
= find_option(cfg
, SVN_CONFIG__DEFAULT_SECTION
, option
, &sec
);
401 /* Has a bi-directional dependency with make_string_from_option(). */
403 expand_option_value(svn_config_t
*cfg
, cfg_section_t
*section
,
404 const char *opt_value
, const char **opt_x_valuep
,
408 /* Set *VALUEP according to the OPT's value. A value for X_POOL must
409 only ever be passed into this function by expand_option_value(). */
411 make_string_from_option(const char **valuep
, svn_config_t
*cfg
,
412 cfg_section_t
*section
, cfg_option_t
*opt
,
415 /* Expand the option value if necessary. */
418 apr_pool_t
*tmp_pool
= (x_pool
? x_pool
: svn_pool_create(cfg
->x_pool
));
420 expand_option_value(cfg
, section
, opt
->value
, &opt
->x_value
, tmp_pool
);
421 opt
->expanded
= TRUE
;
425 /* Grab the fully expanded value from tmp_pool before its
428 opt
->x_value
= apr_pstrmemdup(cfg
->x_pool
, opt
->x_value
,
429 strlen(opt
->x_value
));
430 svn_pool_destroy(tmp_pool
);
435 *valuep
= opt
->x_value
;
437 *valuep
= opt
->value
;
441 /* Start of variable-replacement placeholder */
442 #define FMT_START "%("
443 #define FMT_START_LEN (sizeof(FMT_START) - 1)
445 /* End of variable-replacement placeholder */
447 #define FMT_END_LEN (sizeof(FMT_END) - 1)
450 /* Expand OPT_VALUE (which may be NULL) in SECTION into *OPT_X_VALUEP.
451 If no variable replacements are done, set *OPT_X_VALUEP to
452 NULL. Allocate from X_POOL. */
454 expand_option_value(svn_config_t
*cfg
, cfg_section_t
*section
,
455 const char *opt_value
, const char **opt_x_valuep
,
458 svn_stringbuf_t
*buf
= NULL
;
459 const char *parse_from
= opt_value
;
460 const char *copy_from
= parse_from
;
461 const char *name_start
, *name_end
;
463 while (parse_from
!= NULL
464 && *parse_from
!= '\0'
465 && (name_start
= strstr(parse_from
, FMT_START
)) != NULL
)
467 name_start
+= FMT_START_LEN
;
468 if (*name_start
== '\0')
469 /* FMT_START at end of opt_value. */
472 name_end
= strstr(name_start
, FMT_END
);
473 if (name_end
!= NULL
)
476 apr_size_t len
= name_end
- name_start
;
477 char *name
= apr_pstrmemdup(x_pool
, name_start
, len
);
479 x_opt
= find_option(cfg
, section
->name
, name
, NULL
);
485 /* Pass back the sub-pool originally provided by
486 make_string_from_option() as an indication of when it
488 make_string_from_option(&cstring
, cfg
, section
, x_opt
, x_pool
);
490 /* Append the plain text preceding the expansion. */
491 len
= name_start
- FMT_START_LEN
- copy_from
;
494 buf
= svn_stringbuf_ncreate(copy_from
, len
, x_pool
);
495 cfg
->x_values
= TRUE
;
498 svn_stringbuf_appendbytes(buf
, copy_from
, len
);
500 /* Append the expansion and adjust parse pointers. */
501 svn_stringbuf_appendcstr(buf
, cstring
);
502 parse_from
= name_end
+ FMT_END_LEN
;
503 copy_from
= parse_from
;
506 /* Though ConfigParser considers the failure to resolve
507 the requested expansion an exception condition, we
508 consider it to be plain text, and look for the start of
510 parse_from
= name_end
+ FMT_END_LEN
;
513 /* Though ConfigParser treats unterminated format specifiers
514 as an exception condition, we consider them to be plain
515 text. The fact that there are no more format specifier
516 endings means we're done parsing. */
522 /* Copy the remainder of the plain text. */
523 svn_stringbuf_appendcstr(buf
, copy_from
);
524 *opt_x_valuep
= buf
->data
;
527 *opt_x_valuep
= NULL
;
533 svn_config_get(svn_config_t
*cfg
, const char **valuep
,
534 const char *section
, const char *option
,
535 const char *default_value
)
540 cfg_option_t
*opt
= find_option(cfg
, section
, option
, &sec
);
543 make_string_from_option(valuep
, cfg
, sec
, opt
, NULL
);
547 apr_pool_t
*tmp_pool
= svn_pool_create(cfg
->x_pool
);
548 const char *x_default
;
549 expand_option_value(cfg
, sec
, default_value
, &x_default
, tmp_pool
);
552 svn_stringbuf_set(cfg
->tmp_value
, x_default
);
553 *valuep
= cfg
->tmp_value
->data
;
556 *valuep
= default_value
;
557 svn_pool_destroy(tmp_pool
);
562 *valuep
= default_value
;
569 svn_config_set(svn_config_t
*cfg
,
570 const char *section
, const char *option
,
576 remove_expansions(cfg
);
578 opt
= find_option(cfg
, section
, option
, &sec
);
581 /* Replace the option's value. */
582 opt
->value
= apr_pstrdup(cfg
->pool
, value
);
583 opt
->expanded
= FALSE
;
587 /* Create a new option */
588 opt
= apr_palloc(cfg
->pool
, sizeof(*opt
));
589 opt
->name
= apr_pstrdup(cfg
->pool
, option
);
590 opt
->hash_key
= make_hash_key(apr_pstrdup(cfg
->pool
, option
));
592 opt
->value
= apr_pstrdup(cfg
->pool
, value
);
594 opt
->expanded
= FALSE
;
598 /* Even the section doesn't exist. Create it. */
599 sec
= apr_palloc(cfg
->pool
, sizeof(*sec
));
600 sec
->name
= apr_pstrdup(cfg
->pool
, section
);
601 sec
->hash_key
= make_hash_key(apr_pstrdup(cfg
->pool
, section
));
602 sec
->options
= apr_hash_make(cfg
->pool
);
603 apr_hash_set(cfg
->sections
, sec
->hash_key
, APR_HASH_KEY_STRING
, sec
);
606 apr_hash_set(sec
->options
, opt
->hash_key
, APR_HASH_KEY_STRING
, opt
);
612 svn_config_get_bool(svn_config_t
*cfg
, svn_boolean_t
*valuep
,
613 const char *section
, const char *option
,
614 svn_boolean_t default_value
)
616 const char *tmp_value
;
618 svn_config_get(cfg
, &tmp_value
, section
, option
, NULL
);
619 if (tmp_value
== NULL
)
620 *valuep
= default_value
;
621 else if (0 == svn_cstring_casecmp(tmp_value
, SVN_CONFIG_TRUE
)
622 || 0 == svn_cstring_casecmp(tmp_value
, "yes")
623 || 0 == svn_cstring_casecmp(tmp_value
, "on")
624 || 0 == strcmp(tmp_value
, "1"))
626 else if (0 == svn_cstring_casecmp(tmp_value
, SVN_CONFIG_FALSE
)
627 || 0 == svn_cstring_casecmp(tmp_value
, "no")
628 || 0 == svn_cstring_casecmp(tmp_value
, "off")
629 || 0 == strcmp(tmp_value
, "0"))
632 return svn_error_createf(SVN_ERR_RA_DAV_INVALID_CONFIG_VALUE
, NULL
,
633 _("Config error: invalid boolean value '%s'"),
642 svn_config_set_bool(svn_config_t
*cfg
,
643 const char *section
, const char *option
,
646 svn_config_set(cfg
, section
, option
,
647 (value
? SVN_CONFIG_TRUE
: SVN_CONFIG_FALSE
));
653 svn_config__enumerate_sections(svn_config_t
*cfg
,
654 svn_config__section_enumerator_t callback
,
657 return svn_config_enumerate_sections(cfg
,
658 (svn_config_section_enumerator_t
) callback
, baton
);
662 svn_config_enumerate_sections(svn_config_t
*cfg
,
663 svn_config_section_enumerator_t callback
,
666 apr_hash_index_t
*sec_ndx
;
668 apr_pool_t
*subpool
= svn_pool_create(cfg
->x_pool
);
670 for (sec_ndx
= apr_hash_first(subpool
, cfg
->sections
);
672 sec_ndx
= apr_hash_next(sec_ndx
))
677 apr_hash_this(sec_ndx
, NULL
, NULL
, &sec_ptr
);
680 if (!callback(sec
->name
, baton
))
684 svn_pool_destroy(subpool
);
690 svn_config_enumerate_sections2(svn_config_t
*cfg
,
691 svn_config_section_enumerator2_t callback
,
692 void *baton
, apr_pool_t
*pool
)
694 apr_hash_index_t
*sec_ndx
;
695 apr_pool_t
*iteration_pool
;
698 iteration_pool
= svn_pool_create(pool
);
699 for (sec_ndx
= apr_hash_first(pool
, cfg
->sections
);
701 sec_ndx
= apr_hash_next(sec_ndx
))
706 apr_hash_this(sec_ndx
, NULL
, NULL
, &sec_ptr
);
709 svn_pool_clear(iteration_pool
);
710 if (!callback(sec
->name
, baton
, iteration_pool
))
713 svn_pool_destroy(iteration_pool
);
721 svn_config_enumerate(svn_config_t
*cfg
, const char *section
,
722 svn_config_enumerator_t callback
, void *baton
)
725 apr_hash_index_t
*opt_ndx
;
729 find_option(cfg
, section
, NULL
, &sec
);
733 subpool
= svn_pool_create(cfg
->x_pool
);
735 for (opt_ndx
= apr_hash_first(subpool
, sec
->options
);
737 opt_ndx
= apr_hash_next(opt_ndx
))
741 const char *temp_value
;
743 apr_hash_this(opt_ndx
, NULL
, NULL
, &opt_ptr
);
747 make_string_from_option(&temp_value
, cfg
, sec
, opt
, NULL
);
748 if (!callback(opt
->name
, temp_value
, baton
))
752 svn_pool_destroy(subpool
);
758 svn_config_enumerate2(svn_config_t
*cfg
, const char *section
,
759 svn_config_enumerator2_t callback
, void *baton
,
763 apr_hash_index_t
*opt_ndx
;
764 apr_pool_t
*iteration_pool
;
767 find_option(cfg
, section
, NULL
, &sec
);
771 iteration_pool
= svn_pool_create(pool
);
773 for (opt_ndx
= apr_hash_first(pool
, sec
->options
);
775 opt_ndx
= apr_hash_next(opt_ndx
))
779 const char *temp_value
;
781 apr_hash_this(opt_ndx
, NULL
, NULL
, &opt_ptr
);
785 make_string_from_option(&temp_value
, cfg
, sec
, opt
, NULL
);
786 svn_pool_clear(iteration_pool
);
787 if (!callback(opt
->name
, temp_value
, baton
, iteration_pool
))
790 svn_pool_destroy(iteration_pool
);
797 /* Baton for search_groups() */
798 struct search_groups_baton
800 const char *key
; /* Provided by caller of svn_config_find_group */
801 const char *match
; /* Filled in by search_groups */
806 /* This is an `svn_config_enumerator_t' function, and BATON is a
807 * `struct search_groups_baton *'.
809 static svn_boolean_t
search_groups(const char *name
,
814 struct search_groups_baton
*b
= baton
;
815 apr_array_header_t
*list
;
817 list
= svn_cstring_split(value
, ",", TRUE
, pool
);
818 if (svn_cstring_match_glob_list(b
->key
, list
))
820 /* Fill in the match and return false, to stop enumerating. */
821 b
->match
= apr_pstrdup(b
->pool
, name
);
829 const char *svn_config_find_group(svn_config_t
*cfg
, const char *key
,
830 const char *master_section
,
833 struct search_groups_baton gb
;
838 svn_config_enumerate2(cfg
, master_section
, search_groups
, &gb
, pool
);
844 svn_config_get_server_setting(svn_config_t
*cfg
,
845 const char* server_group
,
846 const char* option_name
,
847 const char* default_value
)
850 svn_config_get(cfg
, &retval
, SVN_CONFIG_SECTION_GLOBAL
,
851 option_name
, default_value
);
854 svn_config_get(cfg
, &retval
, server_group
, option_name
, retval
);
860 svn_config_get_server_setting_int(svn_config_t
*cfg
,
861 const char *server_group
,
862 const char *option_name
,
863 apr_int64_t default_value
,
864 apr_int64_t
*result_value
,
867 const char* tmp_value
;
870 tmp_value
= svn_config_get_server_setting(cfg
, server_group
,
872 if (tmp_value
== NULL
)
873 *result_value
= default_value
;
876 /* read tmp_value as an int now */
877 *result_value
= apr_strtoi64(tmp_value
, &end_pos
, 0);
881 return svn_error_createf
882 (SVN_ERR_RA_DAV_INVALID_CONFIG_VALUE
, NULL
,
883 _("Config error: invalid integer value '%s'"),
892 svn_config_has_section(svn_config_t
*cfg
, const char *section
)
894 return apr_hash_get(cfg
->sections
, section
, APR_HASH_KEY_STRING
) != NULL
;