2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2012, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 * \brief Configuration Option-handling
21 * \author Terry Wilson <twilson@digium.com>
25 <support_level>core</support_level>
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34 #include "asterisk/_private.h"
35 #include "asterisk/config.h"
36 #include "asterisk/config_options.h"
37 #include "asterisk/stringfields.h"
38 #include "asterisk/acl.h"
39 #include "asterisk/frame.h"
40 #include "asterisk/xmldoc.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/term.h"
45 #define CONFIG_OPT_BUCKETS 5
47 #define CONFIG_OPT_BUCKETS 53
48 #endif /* LOW_MEMORY */
50 /*! \brief Bits of aco_info that shouldn't be assigned outside this file
53 struct aco_info_internal {
54 void *pending; /*!< The user-defined config object awaiting application */
57 struct aco_type_internal {
59 struct ao2_container *opts; /*!< The container of options registered to the aco_info */
64 const char *aliased_to;
65 const char *default_val;
66 enum aco_matchtype match_type;
68 struct aco_type **obj;
69 enum aco_option_type type;
70 aco_option_handler handler;
72 unsigned int no_doc:1;
73 unsigned char deprecated:1;
79 static struct ao2_container *xmldocs;
80 #endif /* AST_XML_DOCS */
82 /*! \brief Value of the aco_option_type enum as strings */
83 static char *aco_option_type_string[] = {
84 "ACL", /* OPT_ACL_T, */
85 "Boolean", /* OPT_BOOL_T, */
86 "Boolean", /* OPT_BOOLFLAG_T, */
87 "String", /* OPT_CHAR_ARRAY_T, */
88 "Codec", /* OPT_CODEC_T, */
89 "Custom", /* OPT_CUSTOM_T, */
90 "Double", /* OPT_DOUBLE_T, */
91 "Integer", /* OPT_INT_T, */
92 "None", /* OPT_NOOP_T, */
93 "IP Address", /* OPT_SOCKADDR_T, */
94 "String", /* OPT_STRINGFIELD_T, */
95 "Unsigned Integer", /* OPT_UINT_T, */
98 void *aco_pending_config(struct aco_info *info)
100 if (!(info && info->internal)) {
101 ast_log(LOG_ERROR, "This may not be called without an initialized aco_info!\n");
104 return info->internal->pending;
107 static void config_option_destroy(void *obj)
109 struct aco_option *opt = obj;
110 if (opt->match_type == ACO_REGEX && opt->name_regex) {
111 regfree(opt->name_regex);
112 ast_free(opt->name_regex);
116 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
117 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
118 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
119 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
120 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
121 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
122 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
123 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
124 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
125 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
126 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
129 static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches);
130 static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type);
133 static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
136 case OPT_ACL_T: return acl_handler_fn;
137 case OPT_BOOL_T: return bool_handler_fn;
138 case OPT_BOOLFLAG_T: return boolflag_handler_fn;
139 case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
140 case OPT_CODEC_T: return codec_handler_fn;
141 case OPT_DOUBLE_T: return double_handler_fn;
142 case OPT_INT_T: return int_handler_fn;
143 case OPT_NOOP_T: return noop_handler_fn;
144 case OPT_SOCKADDR_T: return sockaddr_handler_fn;
145 case OPT_STRINGFIELD_T: return stringfield_handler_fn;
146 case OPT_UINT_T: return uint_handler_fn;
148 case OPT_CUSTOM_T: return NULL;
154 static regex_t *build_regex(const char *text)
159 if (!(regex = ast_malloc(sizeof(*regex)))) {
163 if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
164 size_t len = regerror(res, regex, NULL, 0);
166 regerror(res, regex, buf, len);
167 ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
175 static int link_option_to_types(struct aco_info *info, struct aco_type **types, struct aco_option *opt)
178 struct aco_type *type;
180 while ((type = types[idx++])) {
181 if (!type->internal) {
182 ast_log(LOG_ERROR, "Attempting to register option using uninitialized type\n");
185 if (!ao2_link(type->internal->opts, opt)
189 xmldoc_update_config_option(types, info->module, opt->name, type->name, opt->default_val, opt->match_type == ACO_REGEX, opt->type))
190 #endif /* AST_XML_DOCS */
193 ao2_unlink(types[idx - 1]->internal->opts, opt);
198 /* The container(s) should hold the only ref to opt */
204 int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
206 struct aco_option *opt;
208 if (!info || ast_strlen_zero(name) || ast_strlen_zero(aliased_to)) {
212 if (!(opt = ao2_alloc(sizeof(*opt), config_option_destroy))) {
217 opt->aliased_to = aliased_to;
219 opt->match_type = ACO_EXACT;
221 if (link_option_to_types(info, types, opt)) {
229 unsigned int aco_option_get_flags(const struct aco_option *option)
231 return option->flags;
234 intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
236 return option->args[position];
241 * \brief Find a particular ast_xml_doc_item from it's parent config_info, types, and name
243 static struct ast_xml_doc_item *find_xmldoc_option(struct ast_xml_doc_item *config_info, struct aco_type **types, const char *name)
245 struct ast_xml_doc_item *iter = config_info;
250 /* First is just the configInfo, we can skip it */
251 while ((iter = iter->next)) {
253 if (strcasecmp(iter->name, name)) {
256 for (x = 0; types[x]; x++) {
257 /* All we care about is that at least one type has the option */
258 if (!strcasecmp(types[x]->name, iter->ref)) {
267 * \brief Find a particular ast_xml_doc_item from it's parent config_info and name
269 static struct ast_xml_doc_item *find_xmldoc_type(struct ast_xml_doc_item *config_info, const char *name)
271 struct ast_xml_doc_item *iter = config_info;
275 /* First is just the config Info, skip it */
276 while ((iter = iter->next)) {
277 if (!strcasecmp(iter->type, "configObject") && !strcasecmp(iter->name, name)) {
284 #endif /* AST_XML_DOCS */
286 int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types,
287 const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags,
288 unsigned int no_doc, size_t argc, ...)
290 struct aco_option *opt;
294 /* Custom option types require a handler */
295 if (!handler && kind == OPT_CUSTOM_T) {
299 if (!(types && types[0])) {
303 if (!(opt = ao2_alloc(sizeof(*opt) + argc * sizeof(opt->args[0]), config_option_destroy))) {
307 if (matchtype == ACO_REGEX && !(opt->name_regex = build_regex(name))) {
313 for (tmp = 0; tmp < argc; tmp++) {
314 opt->args[tmp] = va_arg(ap, size_t);
319 opt->match_type = matchtype;
320 opt->default_val = default_val;
322 opt->handler = handler;
325 opt->no_doc = no_doc;
327 if (!opt->handler && !(opt->handler = ast_config_option_default_handler(opt->type))) {
328 /* This should never happen */
329 ast_log(LOG_ERROR, "No handler provided, and no default handler exists for type %d\n", opt->type);
334 if (link_option_to_types(info, types, opt)) {
342 static int config_opt_hash(const void *obj, const int flags)
344 const struct aco_option *opt = obj;
345 const char *name = (flags & OBJ_KEY) ? obj : opt->name;
346 return ast_str_case_hash(name);
349 static int config_opt_cmp(void *obj, void *arg, int flags)
351 struct aco_option *opt1 = obj, *opt2 = arg;
352 const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
353 return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
356 static int find_option_cb(void *obj, void *arg, int flags)
358 struct aco_option *match = obj;
359 const char *name = arg;
361 switch (match->match_type) {
363 return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
365 return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
367 ast_log(LOG_ERROR, "Unknown match type. This should not be possible.\n");
371 static struct aco_option *aco_option_find(struct aco_type *type, const char *name)
373 struct aco_option *opt;
375 if (!type || !type->internal || !type->internal->opts) {
376 ast_log(LOG_NOTICE, "Attempting to use NULL or unitialized config type\n");
380 /* Try an exact match with OBJ_KEY for the common/fast case, then iterate through
381 * all options for the regex cases */
382 if (!(opt = ao2_callback(type->internal->opts, OBJ_KEY, find_option_cb, (void *) name))) {
383 opt = ao2_callback(type->internal->opts, 0, find_option_cb, (void *) name);
388 struct ao2_container *aco_option_container_alloc(void)
390 return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
393 static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
396 struct aco_type *match;
399 for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
400 /* First make sure we are an object that can service this category */
401 if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) {
405 /* Then, see if we need to match a particular field */
406 if (!ast_strlen_zero(match->matchfield) && (!ast_strlen_zero(match->matchvalue) || match->matchfunc)) {
407 if (!(val = ast_variable_retrieve(cfg, category, match->matchfield))) {
408 ast_log(LOG_ERROR, "Required match field '%s' not found\n", match->matchfield);
411 if (match->matchfunc) {
412 if (!match->matchfunc(val)) {
415 } else if (strcasecmp(val, match->matchvalue)) {
419 /* If we get this far, we're a match */
426 static int is_preload(struct aco_file *file, const char *cat)
430 if (!file->preload) {
434 for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
435 if (!strcasecmp(cat, file->preload[i])) {
442 static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload) {
443 RAII_VAR(void *, new_item, NULL, ao2_cleanup);
444 struct aco_type *type;
445 /* For global types, field is the global option struct. For non-global, it is the container for items.
446 * We do not grab a reference to these objects, as the info already holds references to them. This
447 * pointer is just a convenience. Do not actually store it somewhere. */
451 /* Skip preloaded categories if we aren't preloading */
452 if (!preload && is_preload(file, cat)) {
456 /* Skip the category if we've been told to ignore it */
457 if (!ast_strlen_zero(file->skip_category)) {
458 regex_skip = build_regex(file->skip_category);
459 if (!regexec(regex_skip, cat, 0, NULL, 0)) {
460 ast_free(regex_skip);
463 ast_free(regex_skip);
466 /* Find aco_type by category, if not found it is an error */
467 if (!(type = internal_aco_type_find(file, cfg, cat))) {
468 ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
472 field = info->internal->pending + type->item_offset;
474 ast_log(LOG_ERROR, "No object to update!\n");
478 if (type->type == ACO_GLOBAL && *field) {
479 if (aco_set_defaults(type, cat, *field)) {
480 ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
483 if (aco_process_category_options(type, cfg, cat, *field)) {
484 ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
487 } else if (type->type == ACO_ITEM) {
489 /* If we have multiple definitions of a category in a file, or can set the values from multiple
490 * files, look up the entry if we've already added it so we can merge the values together.
491 * Otherwise, alloc a new item. */
493 if (!(new_item = type->item_find(*field, cat))) {
494 if (!(new_item = type->item_alloc(cat))) {
495 ast_log(LOG_ERROR, "In %s: Could not create item for %s\n", file->filename, cat);
498 if (aco_set_defaults(type, cat, new_item)) {
499 ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
506 if (type->item_pre_process && type->item_pre_process(new_item)) {
507 ast_log(LOG_ERROR, "In %s: Preprocess callback for %s failed\n", file->filename, cat);
511 if (aco_process_category_options(type, cfg, cat, new_item)) {
512 ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
516 if (type->item_prelink && type->item_prelink(new_item)) {
517 ast_log(LOG_ERROR, "In %s: Pre-link callback for %s failed\n", file->filename, cat);
521 if (new && !ao2_link(*field, new_item)) {
522 ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", file->filename, cat);
529 static int apply_config(struct aco_info *info)
531 ao2_global_obj_replace_unref(*info->global_obj, info->internal->pending);
536 static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
538 const char *cat = NULL;
542 for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
543 if (process_category(cfg, info, file, file->preload[i], 1)) {
544 return ACO_PROCESS_ERROR;
549 while ((cat = ast_category_browse(cfg, cat))) {
550 if (process_category(cfg, info, file, cat, 0)) {
551 return ACO_PROCESS_ERROR;
554 return ACO_PROCESS_OK;
557 enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
559 if (!info->internal) {
560 ast_log(LOG_ERROR, "Attempt to process %s with uninitialized aco_info\n", file->filename);
564 if (!(info->internal->pending = info->snapshot_alloc())) {
565 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", file->filename);
569 if (internal_process_ast_config(info, file, cfg)) {
573 if (info->pre_apply_config && info->pre_apply_config()) {
577 if (apply_config(info)) {
581 ao2_cleanup(info->internal->pending);
582 return ACO_PROCESS_OK;
585 ao2_cleanup(info->internal->pending);
586 return ACO_PROCESS_ERROR;
589 enum aco_process_status aco_process_config(struct aco_info *info, int reload)
591 struct ast_config *cfg;
592 struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
593 int res = ACO_PROCESS_OK, x = 0;
594 struct aco_file *file;
596 if (!(info->files[0])) {
597 ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
598 return ACO_PROCESS_ERROR;
601 if (!info->internal) {
602 ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
603 return ACO_PROCESS_ERROR;
606 if (!(info->internal->pending = info->snapshot_alloc())) {
607 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->module);
608 return ACO_PROCESS_ERROR;
612 * XXX ASTERISK-22009 must fix config framework loading of multiple files.
614 * A reload with multiple files must reload all files if any
615 * file has been touched.
617 while (res != ACO_PROCESS_ERROR && (file = info->files[x++])) {
618 const char *filename = file->filename;
620 if (!(cfg = ast_config_load(filename, cfg_flags))) {
621 if (file->alias && strcmp(file->alias, filename)) {
622 filename = file->alias;
625 ast_log(LOG_ERROR, "Unable to load config file '%s'\n", file->filename);
626 res = ACO_PROCESS_ERROR;
628 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
629 ast_debug(1, "%s was unchanged\n", file->filename);
630 res = ACO_PROCESS_UNCHANGED;
632 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
633 ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", file->filename);
634 res = ACO_PROCESS_ERROR;
636 } else if (cfg == CONFIG_STATUS_FILEMISSING) {
637 if (file->alias && strcmp(file->alias, filename)) {
638 filename = file->alias;
641 ast_log(LOG_ERROR, "%s is missing! Cannot load %s\n", file->filename, info->module);
642 res = ACO_PROCESS_ERROR;
646 res = internal_process_ast_config(info, file, cfg);
647 ast_config_destroy(cfg);
650 if (res != ACO_PROCESS_OK) {
654 if (info->pre_apply_config && (info->pre_apply_config())) {
655 res = ACO_PROCESS_ERROR;
659 if (apply_config(info)) {
660 res = ACO_PROCESS_ERROR;
664 if (info->post_apply_config) {
665 info->post_apply_config();
669 ao2_cleanup(info->internal->pending);
672 int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
674 RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup);
675 if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) {
676 const char *alias = ast_strdupa(opt->aliased_to);
677 ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias);
679 opt = aco_option_find(type, alias);
683 ast_log(LOG_ERROR, "Could not find option suitable for category '%s' named '%s' at line %d of %s\n", cat, var->name, var->lineno, var->file);
688 /* It should be impossible for an option to not have a handler */
689 ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name);
692 if (opt->handler(opt, var, obj)) {
693 ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file);
700 int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
702 struct ast_variable *var;
704 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
705 if (aco_process_var(type, cat, var, obj)) {
713 static void internal_type_destroy(struct aco_type *type)
715 /* If we've already had all our internal data cleared out,
716 * then there's no need to proceed further
718 if (!type->internal) {
722 if (type->internal->regex) {
723 regfree(type->internal->regex);
724 ast_free(type->internal->regex);
726 ao2_cleanup(type->internal->opts);
727 type->internal->opts = NULL;
728 ast_free(type->internal);
729 type->internal = NULL;
732 static void internal_file_types_destroy(struct aco_file *file)
737 for (x = 0, t = file->types[x]; t; t = file->types[++x]) {
738 internal_type_destroy(t);
743 static int internal_type_init(struct aco_type *type)
745 if (!(type->internal = ast_calloc(1, sizeof(*type->internal)))) {
749 if (!(type->internal->regex = build_regex(type->category))) {
750 internal_type_destroy(type);
754 if (!(type->internal->opts = aco_option_container_alloc())) {
755 internal_type_destroy(type);
762 int aco_info_init(struct aco_info *info)
765 struct aco_file *file;
766 struct aco_type *type;
768 if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
772 while ((file = info->files[x++])) {
773 while ((type = file->types[y++])) {
774 if (internal_type_init(type)) {
780 xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match == ACO_WHITELIST)) {
783 #endif /* AST_XML_DOCS */
790 aco_info_destroy(info);
794 void aco_info_destroy(struct aco_info *info)
797 /* It shouldn't be possible for internal->pending to be in use when this is called because
798 * of the locks in loader.c around reloads and unloads and the fact that internal->pending
799 * only exists while those locks are held */
800 ast_free(info->internal);
801 info->internal = NULL;
803 for (x = 0; info->files[x]; x++) {
804 internal_file_types_destroy(info->files[x]);
808 int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
810 struct aco_option *opt;
811 struct ao2_iterator iter;
813 iter = ao2_iterator_init(type->internal->opts, 0);
815 while ((opt = ao2_iterator_next(&iter))) {
816 RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy);
818 if (ast_strlen_zero(opt->default_val)) {
822 if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
824 ao2_iterator_destroy(&iter);
827 if (opt->handler(opt, var, obj)) {
828 ast_log(LOG_ERROR, "Unable to set default for %s, %s=%s\n", category, var->name, var->value);
830 ao2_iterator_destroy(&iter);
835 ao2_iterator_destroy(&iter);
843 * \brief Complete the name of the module the user is looking for
845 static char *complete_config_module(const char *word, int pos, int state)
848 size_t wordlen = strlen(word);
850 struct ao2_iterator i;
851 struct ast_xml_doc_item *cur;
857 i = ao2_iterator_init(xmldocs, 0);
858 while ((cur = ao2_iterator_next(&i))) {
859 if (!strncasecmp(word, cur->name, wordlen) && ++which > state) {
860 c = ast_strdup(cur->name);
866 ao2_iterator_destroy(&i);
872 * \brief Complete the name of the configuration type the user is looking for
874 static char *complete_config_type(const char *module, const char *word, int pos, int state)
877 size_t wordlen = strlen(word);
879 RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
880 struct ast_xml_doc_item *cur;
886 if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
891 while ((cur = cur->next)) {
892 if (!strcasecmp(cur->type, "configObject") && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
893 c = ast_strdup(cur->name);
901 * \brief Complete the name of the configuration option the user is looking for
903 static char *complete_config_option(const char *module, const char *option, const char *word, int pos, int state)
906 size_t wordlen = strlen(word);
908 RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
909 struct ast_xml_doc_item *cur;
915 if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
920 while ((cur = cur->next)) {
921 if (!strcasecmp(cur->type, "configOption") && !strcasecmp(cur->ref, option) && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
922 c = ast_strdup(cur->name);
929 /* Define as 0 if we want to allow configurations to be registered without
932 #define XMLDOC_STRICT 1
935 * \brief Update the XML documentation for a config type based on its registration
937 static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches)
939 RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
940 RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
941 struct ast_xml_doc_item *config_type;
942 struct ast_xml_node *type, *syntax, *matchinfo, *tmp;
944 /* If we already have a syntax element, bail. This isn't an error, since we may unload a module which
945 * has updated the docs and then load it again. */
946 if ((results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/syntax", module, name))) {
950 if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']", module, name))) {
951 ast_log(LOG_WARNING, "Cannot update type '%s' in module '%s' because it has no existing documentation!\n", name, module);
952 return XMLDOC_STRICT ? -1 : 0;
955 if (!(type = ast_xml_xpath_get_first_result(results))) {
956 ast_log(LOG_WARNING, "Could not retrieve documentation for type '%s' in module '%s'\n", name, module);
957 return XMLDOC_STRICT ? -1 : 0;
960 if (!(syntax = ast_xml_new_child(type, "syntax"))) {
961 ast_log(LOG_WARNING, "Could not create syntax node for type '%s' in module '%s'\n", name, module);
962 return XMLDOC_STRICT ? -1 : 0;
965 if (!(matchinfo = ast_xml_new_child(syntax, "matchInfo"))) {
966 ast_log(LOG_WARNING, "Could not create matchInfo node for type '%s' in module '%s'\n", name, module);
967 return XMLDOC_STRICT ? -1 : 0;
970 if (!(tmp = ast_xml_new_child(matchinfo, "category"))) {
971 ast_log(LOG_WARNING, "Could not create category node for type '%s' in module '%s'\n", name, module);
972 return XMLDOC_STRICT ? -1 : 0;
975 ast_xml_set_text(tmp, category);
976 ast_xml_set_attribute(tmp, "match", matches ? "true" : "false");
978 if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) {
979 ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
980 return XMLDOC_STRICT ? -1 : 0;
983 ast_xml_set_attribute(tmp, "name", matchfield);
984 ast_xml_set_text(tmp, matchvalue);
986 if (!config_info || !(config_type = find_xmldoc_type(config_info, name))) {
987 ast_log(LOG_WARNING, "Could not obtain XML documentation item for config type %s\n", name);
988 return XMLDOC_STRICT ? -1 : 0;
991 if (ast_xmldoc_regenerate_doc_item(config_type)) {
992 ast_log(LOG_WARNING, "Could not update type '%s' with values from config type registration\n", name);
993 return XMLDOC_STRICT ? -1 : 0;
1000 * \brief Update the XML documentation for a config option based on its registration
1002 static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type)
1004 RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
1005 RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
1006 struct ast_xml_doc_item * config_option;
1007 struct ast_xml_node *option;
1009 ast_assert(ARRAY_LEN(aco_option_type_string) > type);
1011 if (!config_info || !(config_option = find_xmldoc_option(config_info, types, name))) {
1012 ast_log(LOG_ERROR, "XML Documentation for option '%s' in modules '%s' not found!\n", name, module);
1013 return XMLDOC_STRICT ? -1 : 0;
1016 if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/configOption[@name='%s']", module, object_name, name))) {
1017 ast_log(LOG_WARNING, "Could not find option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1018 return XMLDOC_STRICT ? -1 : 0;
1021 if (!(option = ast_xml_xpath_get_first_result(results))) {
1022 ast_log(LOG_WARNING, "Could obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1023 return XMLDOC_STRICT ? -1 : 0;
1025 ast_xml_set_attribute(option, "regex", regex ? "true" : "false");
1026 ast_xml_set_attribute(option, "default", default_value);
1027 ast_xml_set_attribute(option, "type", aco_option_type_string[type]);
1029 if (ast_xmldoc_regenerate_doc_item(config_option)) {
1030 ast_log(LOG_WARNING, "Could not update option '%s' with values from config option registration\n", name);
1031 return XMLDOC_STRICT ? -1 : 0;
1038 * \brief Show the modules with configuration information
1040 static void cli_show_modules(struct ast_cli_args *a)
1042 struct ast_xml_doc_item *item;
1043 struct ao2_iterator it_items;
1045 ast_assert(a->argc == 3);
1047 if (ao2_container_count(xmldocs) == 0) {
1048 ast_cli(a->fd, "No modules found.\n");
1052 it_items = ao2_iterator_init(xmldocs, 0);
1053 ast_cli(a->fd, "The following modules have configuration information:\n");
1054 while ((item = ao2_iterator_next(&it_items))) {
1055 ast_cli(a->fd, "\t%s\n", item->name);
1058 ao2_iterator_destroy(&it_items);
1062 * \brief Show the configuration types for a module
1064 static void cli_show_module_types(struct ast_cli_args *a)
1066 RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
1067 struct ast_xml_doc_item *tmp;
1069 ast_assert(a->argc == 4);
1071 if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1072 ast_cli(a->fd, "Module %s not found.\n", a->argv[3]);
1076 if (ast_str_strlen(item->synopsis)) {
1077 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->synopsis), 1));
1079 if (ast_str_strlen(item->description)) {
1080 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->description), 1));
1084 ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
1085 while ((tmp = tmp->next)) {
1086 if (!strcasecmp(tmp->type, "configObject")) {
1087 ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1088 ast_str_buffer(tmp->synopsis));
1094 * \brief Show the information for a configuration type
1096 static void cli_show_module_type(struct ast_cli_args *a)
1098 RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
1099 struct ast_xml_doc_item *tmp;
1100 char option_type[64];
1103 ast_assert(a->argc == 5);
1105 if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1106 ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1111 while ((tmp = tmp->next)) {
1112 if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
1114 term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
1115 ast_cli(a->fd, "%s", option_type);
1116 if (ast_str_strlen(tmp->syntax)) {
1117 ast_cli(a->fd, ": [%s]\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1119 ast_cli(a->fd, "\n\n");
1121 if (ast_str_strlen(tmp->synopsis)) {
1122 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->synopsis), 1));
1124 if (ast_str_strlen(tmp->description)) {
1125 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1131 ast_cli(a->fd, "Unknown configuration type %s\n", a->argv[4]);
1135 /* Now iterate over the options for the type */
1137 while ((tmp = tmp->next)) {
1138 if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
1139 ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1140 ast_str_buffer(tmp->synopsis));
1146 * \brief Show detailed information for an option
1148 static void cli_show_module_options(struct ast_cli_args *a)
1150 RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
1151 struct ast_xml_doc_item *tmp;
1152 char option_name[64];
1155 ast_assert(a->argc == 6);
1157 if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1158 ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1162 while ((tmp = tmp->next)) {
1163 if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
1165 ast_cli(a->fd, "\n");
1167 term_color(option_name, tmp->ref, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_name));
1168 ast_cli(a->fd, "[%s%s]\n", option_name, term_end());
1169 if (ast_str_strlen(tmp->syntax)) {
1170 ast_cli(a->fd, "%s\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1172 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(AS_OR(tmp->synopsis, "No information available"), 1));
1173 if (ast_str_strlen(tmp->description)) {
1174 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1182 ast_cli(a->fd, "No option %s found for %s:%s\n", a->argv[5], a->argv[3], a->argv[4]);
1186 static char *cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1190 e->command = "config show help";
1192 "Usage: config show help [<module> [<type> [<option>]]]\n"
1193 " Display detailed information about module configuration.\n"
1194 " * If nothing is specified, the modules that have\n"
1195 " configuration information are listed.\n"
1196 " * If <module> is specified, the configuration types\n"
1197 " for that module will be listed, along with brief\n"
1198 " information about that type.\n"
1199 " * If <module> and <type> are specified, detailed\n"
1200 " information about the type is displayed, as well\n"
1201 " as the available options.\n"
1202 " * If <module>, <type>, and <option> are specified,\n"
1203 " detailed information will be displayed about that\n"
1205 " NOTE: the help documentation is partially generated at run\n"
1206 " time when a module is loaded. If a module is not loaded,\n"
1207 " configuration help for that module may be incomplete.\n";
1211 case 3: return complete_config_module(a->word, a->pos, a->n);
1212 case 4: return complete_config_type(a->argv[3], a->word, a->pos, a->n);
1213 case 5: return complete_config_option(a->argv[3], a->argv[4], a->word, a->pos, a->n);
1214 default: return NULL;
1220 cli_show_modules(a);
1223 cli_show_module_types(a);
1226 cli_show_module_type(a);
1229 cli_show_module_options(a);
1232 return CLI_SHOWUSAGE;
1238 static struct ast_cli_entry cli_aco[] = {
1239 AST_CLI_DEFINE(cli_show_help, "Show configuration help for a module"),
1242 static void aco_deinit(void)
1244 ast_cli_unregister(cli_aco);
1245 ao2_cleanup(xmldocs);
1247 #endif /* AST_XML_DOCS */
1252 ast_register_atexit(aco_deinit);
1253 if (!(xmldocs = ast_xmldoc_build_documentation("configInfo"))) {
1254 ast_log(LOG_ERROR, "Couldn't build config documentation\n");
1257 ast_cli_register_multiple(cli_aco, ARRAY_LEN(cli_aco));
1258 #endif /* AST_XML_DOCS */
1262 /* Default config option handlers */
1264 /*! \brief Default option handler for signed integers
1265 * \note For a description of the opt->flags and opt->args values, see the documentation for
1266 * enum aco_option_type in config_options.h
1268 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1269 int *field = (int *)(obj + opt->args[0]);
1270 unsigned int flags = PARSE_INT32 | opt->flags;
1272 if (opt->flags & PARSE_IN_RANGE) {
1273 res = opt->flags & PARSE_DEFAULT ?
1274 ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
1275 ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
1277 if (opt->flags & PARSE_RANGE_DEFAULTS) {
1278 ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
1280 } else if (opt->flags & PARSE_DEFAULT) {
1281 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1285 } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
1286 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
1288 res = ast_parse_arg(var->value, flags, field);
1294 /*! \brief Default option handler for unsigned integers
1295 * \note For a description of the opt->flags and opt->args values, see the documentation for
1296 * enum aco_option_type in config_options.h
1298 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1299 unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1300 unsigned int flags = PARSE_INT32 | opt->flags;
1302 if (opt->flags & PARSE_IN_RANGE) {
1303 res = opt->flags & PARSE_DEFAULT ?
1304 ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
1305 ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
1307 if (opt->flags & PARSE_RANGE_DEFAULTS) {
1308 ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
1310 } else if (opt->flags & PARSE_DEFAULT) {
1311 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1315 } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
1316 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
1318 res = ast_parse_arg(var->value, flags, field);
1324 /*! \brief Default option handler for doubles
1325 * \note For a description of the opt->flags and opt->args values, see the documentation for
1326 * enum aco_option_type in config_options.h
1328 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1329 double *field = (double *)(obj + opt->args[0]);
1330 return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
1333 /*! \brief Default handler for ACLs
1334 * \note For a description of the opt->flags and opt->args values, see the documentation for
1335 * enum aco_option_type in config_options.h
1337 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1338 struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
1340 *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
1344 /*! \brief Default option handler for codec preferences/capabilities
1345 * \note For a description of the opt->flags and opt->args values, see the documentation for
1346 * enum aco_option_type in config_options.h
1348 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1349 struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + opt->args[0]);
1350 struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[1]);
1351 return ast_parse_allow_disallow(pref, *cap, var->value, opt->flags);
1354 /*! \brief Default option handler for stringfields
1355 * \note For a description of the opt->flags and opt->args values, see the documentation for
1356 * enum aco_option_type in config_options.h
1358 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1360 ast_string_field *field = (const char **)(obj + opt->args[0]);
1361 struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
1362 struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
1364 if (opt->flags && ast_strlen_zero(var->value)) {
1367 ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
1371 /*! \brief Default option handler for bools (ast_true/ast_false)
1372 * \note For a description of the opt->flags and opt->args values, see the documentation for
1373 * enum aco_option_type in config_options.h
1375 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1377 unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1378 *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
1382 /*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
1383 * \note For a description of the opt->flags and opt->args values, see the documentation for
1384 * enum aco_option_type in config_options.h
1386 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1388 unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
1389 unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
1390 unsigned int flag = opt->args[1];
1392 *flags_field |= flag;
1394 *flags_field &= ~flag;
1399 /*! \brief Default handler for ast_sockaddrs
1400 * \note For a description of the opt->flags and opt->args values, see the documentation for
1401 * enum aco_option_type in config_options.h
1403 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1405 struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
1406 return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
1409 /*! \brief Default handler for doing nothing
1411 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1416 /*! \brief Default handler for character arrays
1417 * \note For a description of the opt->flags and opt->args values, see the documentation for
1418 * enum aco_option_type in config_options.h
1420 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1422 char *field = (char *)(obj + opt->args[0]);
1423 size_t len = opt->args[1];
1425 if (opt->flags && ast_strlen_zero(var->value)) {
1428 ast_copy_string(field, var->value, len);