Asterisk - The Open Source Telephony Project  GIT-master-932eae6
config_options.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
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.
13  *
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.
17  */
18 
19 /*! \file
20  * \brief Configuration Option-handling
21  * \author Terry Wilson <twilson@digium.com>
22  */
23 
24 /*** MODULEINFO
25  <support_level>core</support_level>
26  ***/
27 
28 #include "asterisk.h"
29 
30 #include <regex.h>
31 
32 #include "asterisk/_private.h"
33 #include "asterisk/config.h"
35 #include "asterisk/stringfields.h"
36 #include "asterisk/acl.h"
37 #include "asterisk/app.h"
38 #include "asterisk/frame.h"
39 #include "asterisk/xmldoc.h"
40 #include "asterisk/cli.h"
41 #include "asterisk/term.h"
42 #include "asterisk/format_cap.h"
43 
44 #ifdef LOW_MEMORY
45 #define CONFIG_OPT_BUCKETS 5
46 #else
47 #define CONFIG_OPT_BUCKETS 53
48 #endif /* LOW_MEMORY */
49 
50 /*! \brief Bits of aco_info that shouldn't be assigned outside this file
51  * \internal
52  */
54  void *pending; /*!< The user-defined config object awaiting application */
55 };
56 
58  regex_t *regex;
59  struct ao2_container *opts; /*!< The container of options registered to the aco_info */
60 };
61 
62 struct aco_option {
63  const char *name;
64  const char *aliased_to;
65  const char *default_val;
66  enum aco_matchtype match_type;
67  regex_t *name_regex;
68  struct aco_type **obj;
71  unsigned int flags;
72  unsigned int no_doc:1;
73 #ifdef AST_DEVMODE
74  unsigned int doc_unavailable:1;
75 #endif
76  unsigned char deprecated:1;
77  size_t argc;
78  intptr_t args[0];
79 };
80 
81 #ifdef AST_XML_DOCS
82 static struct ao2_container *xmldocs;
83 
84 /*! \brief Value of the aco_option_type enum as strings */
85 static char *aco_option_type_string[] = {
86  "ACL", /* OPT_ACL_T, */
87  "Boolean", /* OPT_BOOL_T, */
88  "Boolean", /* OPT_BOOLFLAG_T, */
89  "String", /* OPT_CHAR_ARRAY_T, */
90  "Codec", /* OPT_CODEC_T, */
91  "Custom", /* OPT_CUSTOM_T, */
92  "Double", /* OPT_DOUBLE_T, */
93  "Integer", /* OPT_INT_T, */
94  "None", /* OPT_NOOP_T, */
95  "IP Address", /* OPT_SOCKADDR_T, */
96  "String", /* OPT_STRINGFIELD_T, */
97  "Unsigned Integer", /* OPT_UINT_T, */
98  "Boolean", /* OPT_YESNO_T, */
99  "Time Length", /* OPT_TIMELEN_T, */
100 };
101 #endif /* AST_XML_DOCS */
102 
104 {
105  if (!(info && info->internal)) {
106  ast_log(LOG_ERROR, "This may not be called without an initialized aco_info!\n");
107  return NULL;
108  }
109  return info->internal->pending;
110 }
111 
112 static void config_option_destroy(void *obj)
113 {
114  struct aco_option *opt = obj;
115  if (opt->match_type == ACO_REGEX && opt->name_regex) {
116  regfree(opt->name_regex);
117  ast_free(opt->name_regex);
118  }
119 }
120 
121 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
122 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
123 static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
124 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
125 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
126 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
127 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
128 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
129 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
130 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
131 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
132 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
133 
134 #ifdef AST_XML_DOCS
135 static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, enum aco_category_op category_match);
136 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);
137 #endif
138 
140 {
141  switch(type) {
142  case OPT_ACL_T: return acl_handler_fn;
143  case OPT_BOOL_T: return bool_handler_fn;
144  /* Reading from config files, BOOL and YESNO are handled exactly the
145  * same. Their difference is in how they are rendered to users
146  */
147  case OPT_YESNO_T: return bool_handler_fn;
148  case OPT_BOOLFLAG_T: return boolflag_handler_fn;
150  case OPT_CODEC_T: return codec_handler_fn;
151  case OPT_DOUBLE_T: return double_handler_fn;
152  case OPT_INT_T: return int_handler_fn;
153  case OPT_NOOP_T: return noop_handler_fn;
154  case OPT_SOCKADDR_T: return sockaddr_handler_fn;
156  case OPT_UINT_T: return uint_handler_fn;
157  case OPT_TIMELEN_T: return timelen_handler_fn;
158 
159  case OPT_CUSTOM_T: return NULL;
160  }
161 
162  return NULL;
163 }
164 
165 static regex_t *build_regex(const char *text)
166 {
167  int res;
168  regex_t *regex;
169 
170  if (!(regex = ast_malloc(sizeof(*regex)))) {
171  return NULL;
172  }
173 
174  if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
175  size_t len = regerror(res, regex, NULL, 0);
176  char buf[len];
177  regerror(res, regex, buf, len);
178  ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
179  ast_free(regex);
180  return NULL;
181  }
182 
183  return regex;
184 }
185 
186 static int link_option_to_types(struct aco_info *info, struct aco_type **types, struct aco_option *opt)
187 {
188  size_t idx = 0;
189  struct aco_type *type;
190 
191  while ((type = types[idx++])) {
192  if (!type->internal) {
193  ast_log(LOG_ERROR, "Attempting to register option using uninitialized type\n");
194  return -1;
195  }
196  if (!ao2_link(type->internal->opts, opt)) {
197  do {
198  ao2_unlink(types[idx - 1]->internal->opts, opt);
199  } while (--idx);
200  return -1;
201  }
202 #ifdef AST_XML_DOCS
203  if (!info->hidden && !opt->no_doc &&
204  xmldoc_update_config_option(types, info->module, opt->name, type->name, opt->default_val, opt->match_type == ACO_REGEX, opt->type)) {
205 #ifdef AST_DEVMODE
206  opt->doc_unavailable = 1;
207 #endif
208  }
209 #endif
210  }
211  /* The container(s) should hold the only ref to opt */
212  ao2_ref(opt, -1);
213 
214  return 0;
215 }
216 
217 int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
218 {
219  struct aco_option *opt;
220 
221  if (!info || ast_strlen_zero(name) || ast_strlen_zero(aliased_to)) {
222  return -1;
223  }
224 
226  if (!opt) {
227  return -1;
228  }
229 
230  opt->name = name;
231  opt->aliased_to = aliased_to;
232  opt->deprecated = 1;
233  opt->match_type = ACO_EXACT;
234 
235  if (link_option_to_types(info, types, opt)) {
236  ao2_ref(opt, -1);
237  return -1;
238  }
239 
240  return 0;
241 }
242 
243 unsigned int aco_option_get_flags(const struct aco_option *option)
244 {
245  return option->flags;
246 }
247 
248 intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
249 {
250  return option->args[position];
251 }
252 
253 #ifdef AST_XML_DOCS
254 /*! \internal
255  * \brief Find a particular ast_xml_doc_item from it's parent config_info, types, and name
256  */
257 static struct ast_xml_doc_item *find_xmldoc_option(struct ast_xml_doc_item *config_info, struct aco_type **types, const char *name)
258 {
259  struct ast_xml_doc_item *iter = config_info;
260 
261  if (!iter) {
262  return NULL;
263  }
264  /* First is just the configInfo, we can skip it */
265  while ((iter = AST_LIST_NEXT(iter, next))) {
266  size_t x;
267  if (strcasecmp(iter->name, name)) {
268  continue;
269  }
270  for (x = 0; types[x]; x++) {
271  /* All we care about is that at least one type has the option */
272  if (!strcasecmp(types[x]->name, iter->ref)) {
273  return iter;
274  }
275  }
276  }
277  return NULL;
278 }
279 
280 /*! \internal
281  * \brief Find a particular ast_xml_doc_item from it's parent config_info and name
282  */
283 static struct ast_xml_doc_item *find_xmldoc_type(struct ast_xml_doc_item *config_info, const char *name)
284 {
285  struct ast_xml_doc_item *iter = config_info;
286  if (!iter) {
287  return NULL;
288  }
289  /* First is just the config Info, skip it */
290  while ((iter = AST_LIST_NEXT(iter, next))) {
291  if (!strcasecmp(iter->type, "configObject") && !strcasecmp(iter->name, name)) {
292  break;
293  }
294  }
295  return iter;
296 }
297 
298 #endif /* AST_XML_DOCS */
299 
300 int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types,
301  const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags,
302  unsigned int no_doc, size_t argc, ...)
303 {
304  struct aco_option *opt;
305  va_list ap;
306  int tmp;
307 
308  /* Custom option types require a handler */
309  if (!handler && kind == OPT_CUSTOM_T) {
310  return -1;
311  }
312 
313  if (!(types && types[0])) {
314  return -1;
315  }
316 
317  opt = ao2_alloc_options(sizeof(*opt) + argc * sizeof(opt->args[0]),
319  if (!opt) {
320  return -1;
321  }
322 
323  if (matchtype == ACO_REGEX && !(opt->name_regex = build_regex(name))) {
324  ao2_ref(opt, -1);
325  return -1;
326  }
327 
328  va_start(ap, argc);
329  for (tmp = 0; tmp < argc; tmp++) {
330  opt->args[tmp] = va_arg(ap, size_t);
331  }
332  va_end(ap);
333 
334  opt->name = name;
335  opt->match_type = matchtype;
336  opt->default_val = default_val;
337  opt->type = kind;
338  opt->handler = handler;
339  opt->flags = flags;
340  opt->argc = argc;
341  opt->no_doc = no_doc;
342 
343  if (!opt->handler && !(opt->handler = ast_config_option_default_handler(opt->type))) {
344  /* This should never happen */
345  ast_log(LOG_ERROR, "No handler provided, and no default handler exists for type %u\n", opt->type);
346  ao2_ref(opt, -1);
347  return -1;
348  };
349 
350  if (link_option_to_types(info, types, opt)) {
351  ao2_ref(opt, -1);
352  return -1;
353  }
354 
355  return 0;
356 }
357 
358 static int config_opt_hash(const void *obj, const int flags)
359 {
360  const struct aco_option *opt = obj;
361  const char *name = (flags & OBJ_KEY) ? obj : opt->name;
362  return ast_str_case_hash(name);
363 }
364 
365 static int config_opt_cmp(void *obj, void *arg, int flags)
366 {
367  struct aco_option *opt1 = obj, *opt2 = arg;
368  const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
369  return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
370 }
371 
372 static int find_option_cb(void *obj, void *arg, int flags)
373 {
374  struct aco_option *match = obj;
375  const char *name = arg;
376 
377  switch (match->match_type) {
378  case ACO_EXACT:
379  return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
380  case ACO_PREFIX:
381  return strncasecmp(name, match->name, strlen(match->name)) ? 0 : CMP_MATCH | CMP_STOP;
382  case ACO_REGEX:
383  return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
384  }
385  ast_log(LOG_ERROR, "Unknown match type. This should not be possible.\n");
386  return CMP_STOP;
387 }
388 
389 static struct aco_option *aco_option_find(struct aco_type *type, const char *name)
390 {
391  struct aco_option *opt;
392 
393  if (!type || !type->internal || !type->internal->opts) {
394  ast_log(LOG_NOTICE, "Attempting to use NULL or unitialized config type\n");
395  return NULL;
396  }
397 
398  /* Try an exact match with OBJ_KEY for the common/fast case, then iterate through
399  * all options for the regex cases */
400  if (!(opt = ao2_callback(type->internal->opts, OBJ_KEY, find_option_cb, (void *) name))) {
401  opt = ao2_callback(type->internal->opts, 0, find_option_cb, (void *) name);
402  }
403  return opt;
404 }
405 
407 {
410 }
411 
412 static int internal_aco_type_category_check(struct aco_type *match, const char *category)
413 {
414  const char **categories = (const char **)match->category;
415 
416  switch (match->category_match) {
417  case ACO_WHITELIST:
418  return regexec(match->internal->regex, category, 0, NULL, 0);
419 
420  case ACO_BLACKLIST:
421  return !regexec(match->internal->regex, category, 0, NULL, 0);
422 
423  case ACO_WHITELIST_EXACT:
424  return strcasecmp(match->category, category);
425 
426  case ACO_BLACKLIST_EXACT:
427  return !strcasecmp(match->category, category);
428 
429  case ACO_WHITELIST_ARRAY:
430  while (*categories) {
431  if (!strcasecmp(*categories, category)) {
432  return 0;
433  }
434  categories++;
435  }
436  return -1;
437 
438  case ACO_BLACKLIST_ARRAY:
439  while (*categories) {
440  if (!strcasecmp(*categories, category)) {
441  return -1;
442  }
443  categories++;
444  }
445  return 0;
446  }
447 
448  return -1;
449 }
450 
451 static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
452 {
453  size_t x;
454  struct aco_type *match;
455  const char *val;
456 
457  for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
458  /* First make sure we are an object that can service this category */
459  if (internal_aco_type_category_check(match, category)) {
460  continue;
461  }
462 
463  /* Then, see if we need to match a particular field */
464  if (!ast_strlen_zero(match->matchfield) && (!ast_strlen_zero(match->matchvalue) || match->matchfunc)) {
465  if (!(val = ast_variable_retrieve(cfg, category, match->matchfield))) {
466  ast_log(LOG_ERROR, "Required match field '%s' not found\n", match->matchfield);
467  return NULL;
468  }
469  if (match->matchfunc) {
470  if (!match->matchfunc(val)) {
471  continue;
472  }
473  } else if (strcasecmp(val, match->matchvalue)) {
474  continue;
475  }
476  }
477  /* If we get this far, we're a match */
478  break;
479  }
480 
481  return match;
482 }
483 
484 static int is_preload(struct aco_file *file, const char *cat)
485 {
486  int i;
487 
488  if (!file->preload) {
489  return 0;
490  }
491 
492  for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
493  if (!strcasecmp(cat, file->preload[i])) {
494  return 1;
495  }
496  }
497  return 0;
498 }
499 
500 static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload) {
501  RAII_VAR(void *, new_item, NULL, ao2_cleanup);
502  struct aco_type *type;
503  /* For global types, field is the global option struct. For non-global, it is the container for items.
504  * We do not grab a reference to these objects, as the info already holds references to them. This
505  * pointer is just a convenience. Do not actually store it somewhere. */
506  void **field;
507  regex_t *regex_skip;
508 
509  /* Skip preloaded categories if we aren't preloading */
510  if (!preload && is_preload(file, cat)) {
511  return 0;
512  }
513 
514  /* Skip the category if we've been told to ignore it */
515  if (!ast_strlen_zero(file->skip_category)) {
516  regex_skip = build_regex(file->skip_category);
517  if (!regexec(regex_skip, cat, 0, NULL, 0)) {
518  regfree(regex_skip);
519  ast_free(regex_skip);
520  return 0;
521  }
522  regfree(regex_skip);
523  ast_free(regex_skip);
524  }
525 
526  /* Find aco_type by category, if not found it is an error */
527  if (!(type = internal_aco_type_find(file, cfg, cat))) {
528  ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
529  return -1;
530  }
531 
532  if (type->type == ACO_IGNORE) {
533  return 0;
534  }
535 
536  field = info->internal->pending + type->item_offset;
537  if (!*field) {
538  ast_log(LOG_ERROR, "In %s: %s - No object to update!\n", file->filename, cat);
539  return -1;
540  }
541 
542  if (type->type == ACO_GLOBAL && *field) {
543  if (aco_process_category_options(type, cfg, cat, *field)) {
544  ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
545  return -1;
546  }
547  } else if (type->type == ACO_ITEM) {
548  int new = 0;
549  /* If we have multiple definitions of a category in a file, or can set the values from multiple
550  * files, look up the entry if we've already added it so we can merge the values together.
551  * Otherwise, alloc a new item. */
552  if (*field) {
553  if (!(new_item = type->item_find(*field, cat))) {
554  if (!(new_item = type->item_alloc(cat))) {
555  ast_log(LOG_ERROR, "In %s: Could not create item for %s\n", file->filename, cat);
556  return -1;
557  }
558  if (aco_set_defaults(type, cat, new_item)) {
559  ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
560  return -1;
561  }
562  new = 1;
563  }
564  }
565 
566  if (type->item_pre_process && type->item_pre_process(new_item)) {
567  ast_log(LOG_ERROR, "In %s: Preprocess callback for %s failed\n", file->filename, cat);
568  return -1;
569  }
570 
571  if (aco_process_category_options(type, cfg, cat, new_item)) {
572  ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
573  return -1;
574  }
575 
576  if (type->item_prelink && type->item_prelink(new_item)) {
577  ast_log(LOG_ERROR, "In %s: Pre-link callback for %s failed\n", file->filename, cat);
578  return -1;
579  }
580 
581  if (new && !ao2_link(*field, new_item)) {
582  ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", file->filename, cat);
583  return -1;
584  }
585  }
586  return 0;
587 }
588 
589 static int apply_config(struct aco_info *info)
590 {
592 
593  return 0;
594 }
595 
597 {
598  const char *cat = NULL;
599 
600  if (file->preload) {
601  int i;
602  for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
603  if (process_category(cfg, info, file, file->preload[i], 1)) {
604  return ACO_PROCESS_ERROR;
605  }
606  }
607  }
608 
609  while ((cat = ast_category_browse(cfg, cat))) {
610  if (process_category(cfg, info, file, cat, 0)) {
611  return ACO_PROCESS_ERROR;
612  }
613  }
614  return ACO_PROCESS_OK;
615 }
616 
618 {
619  if (!info->internal) {
620  ast_log(LOG_ERROR, "Attempt to process %s with uninitialized aco_info\n", file->filename);
621  return ACO_PROCESS_ERROR;
622  }
623 
624  if (!(info->internal->pending = info->snapshot_alloc())) {
625  ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", file->filename);
626  goto error;
627  }
628 
629  if (internal_process_ast_config(info, file, cfg)) {
630  goto error;
631  }
632 
633  if (info->pre_apply_config && info->pre_apply_config()) {
634  goto error;
635  }
636 
637  if (apply_config(info)) {
638  goto error;
639  };
640 
641  ao2_cleanup(info->internal->pending);
642  info->internal->pending = NULL;
643  return ACO_PROCESS_OK;
644 
645 error:
646  ao2_cleanup(info->internal->pending);
647  info->internal->pending = NULL;
648 
649  return ACO_PROCESS_ERROR;
650 }
651 
653 {
654  struct ast_config *cfg;
655  struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
656  int res = ACO_PROCESS_OK;
657  int file_count = 0;
658  struct aco_file *file;
659 
660  if (!info->internal) {
661  ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
662  return ACO_PROCESS_ERROR;
663  }
664 
665  if (!(info->files[0])) {
666  ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
667  return ACO_PROCESS_ERROR;
668  }
669 
670  if (!(info->internal->pending = info->snapshot_alloc())) {
671  ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->module);
672  return ACO_PROCESS_ERROR;
673  }
674 
675  while (res != ACO_PROCESS_ERROR && (file = info->files[file_count++])) {
676  const char *filename = file->filename;
677  struct aco_type *match;
678  int i;
679 
680  /* set defaults for global objects */
681  for (i = 0, match = file->types[i]; match; match = file->types[++i]) {
682  void **field = info->internal->pending + match->item_offset;
683 
684  if (match->type == ACO_IGNORE) {
685  continue;
686  }
687 
688  if (match->type != ACO_GLOBAL || !*field) {
689  continue;
690  }
691 
692  if (aco_set_defaults(match, match->category, *field)) {
693  ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, match->category);
694  res = ACO_PROCESS_ERROR;
695  break;
696  }
697  }
698 
699  if (res == ACO_PROCESS_ERROR) {
700  break;
701  }
702 
703 try_alias:
704  cfg = ast_config_load(filename, cfg_flags);
705  if (!cfg || cfg == CONFIG_STATUS_FILEMISSING) {
706  if (file->alias && strcmp(file->alias, filename)) {
707  filename = file->alias;
708  goto try_alias;
709  }
710  ast_log(LOG_ERROR, "Unable to load config file '%s'\n", file->filename);
711  res = ACO_PROCESS_ERROR;
712  break;
713  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
714  ast_debug(1, "%s was unchanged\n", file->filename);
715  res = ACO_PROCESS_UNCHANGED;
716  continue;
717  } else if (cfg == CONFIG_STATUS_FILEINVALID) {
718  ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n",
719  file->filename);
720  res = ACO_PROCESS_ERROR;
721  break;
722  }
723 
724  /* A file got loaded. */
725  if (reload) {
726  /* Must do any subsequent file loads unconditionally. */
727  reload = 0;
729 
730  if (file_count != 1) {
731  /*
732  * Must restart loading to load all config files since a file
733  * after the first one changed.
734  */
735  file_count = 0;
736  } else {
737  res = internal_process_ast_config(info, file, cfg);
738  }
739  } else {
740  res = internal_process_ast_config(info, file, cfg);
741  }
742  ast_config_destroy(cfg);
743  }
744 
745  if (res != ACO_PROCESS_OK) {
746  goto end;
747  }
748 
749  if (info->pre_apply_config && info->pre_apply_config()) {
750  res = ACO_PROCESS_ERROR;
751  goto end;
752  }
753 
754  if (apply_config(info)) {
755  res = ACO_PROCESS_ERROR;
756  goto end;
757  }
758 
759  if (info->post_apply_config) {
760  info->post_apply_config();
761  }
762 
763 end:
764  ao2_cleanup(info->internal->pending);
765  info->internal->pending = NULL;
766 
767  return res;
768 }
769 int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
770 {
771  RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup);
772  if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) {
773  const char *alias = ast_strdupa(opt->aliased_to);
774  ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias);
775  ao2_ref(opt, -1);
776  opt = aco_option_find(type, alias);
777  }
778 
779  if (!opt) {
780  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);
781  return -1;
782  }
783 
784  if (!opt->handler) {
785  /* It should be impossible for an option to not have a handler */
786  ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name);
787  return -1;
788  }
789 
790 #ifdef AST_DEVMODE
791  if (opt->doc_unavailable) {
792  ast_log(LOG_ERROR, "Config option '%s' of type '%s' is not completely documented and can not be set\n", var->name, type->name);
793  return -1;
794  }
795 #endif
796 
797  if (opt->handler(opt, var, obj)) {
798  ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file);
799  return -1;
800  }
801 
802  return 0;
803 }
804 
805 int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
806 {
807  struct ast_variable *var;
808 
809  for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
810  if (aco_process_var(type, cat, var, obj)) {
811  return -1;
812  }
813  }
814 
815  return 0;
816 }
817 
818 static void internal_type_destroy(struct aco_type *type)
819 {
820  /* If we've already had all our internal data cleared out,
821  * then there's no need to proceed further
822  */
823  if (!type->internal) {
824  return;
825  }
826 
827  if (type->internal->regex) {
828  regfree(type->internal->regex);
829  ast_free(type->internal->regex);
830  }
831  ao2_cleanup(type->internal->opts);
832  type->internal->opts = NULL;
833  ast_free(type->internal);
834  type->internal = NULL;
835 }
836 
838 {
839  size_t x;
840  struct aco_type *t;
841 
842  for (x = 0, t = file->types[x]; t; t = file->types[++x]) {
844  t = NULL;
845  }
846 }
847 
848 static int internal_type_init(struct aco_type *type)
849 {
850  if (!(type->internal = ast_calloc(1, sizeof(*type->internal)))) {
851  return -1;
852  }
853 
854  switch (type->category_match) {
855  case ACO_BLACKLIST:
856  case ACO_WHITELIST:
857  if (!(type->internal->regex = build_regex(type->category))) {
858  internal_type_destroy(type);
859  return -1;
860  }
861  break;
862  case ACO_BLACKLIST_EXACT:
863  case ACO_WHITELIST_EXACT:
864  case ACO_BLACKLIST_ARRAY:
865  case ACO_WHITELIST_ARRAY:
866  break;
867  }
868 
869  if (!(type->internal->opts = aco_option_container_alloc())) {
870  internal_type_destroy(type);
871  return -1;
872  }
873 
874  return 0;
875 }
876 
878 {
879  size_t x = 0, y = 0;
880  struct aco_file *file;
881  struct aco_type *type;
882 
883  if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
884  return -1;
885  }
886 
887  while ((file = info->files[x++])) {
888  while ((type = file->types[y++])) {
889  if (internal_type_init(type)) {
890  goto error;
891  }
892 #ifdef AST_XML_DOCS
893  if (!info->hidden &&
894  !type->hidden &&
895  type->type != ACO_IGNORE &&
896  xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match)) {
897  goto error;
898  }
899 #endif /* AST_XML_DOCS */
900  }
901  y = 0;
902  }
903 
904  return 0;
905 error:
906  aco_info_destroy(info);
907  return -1;
908 }
909 
911 {
912  int x;
913  /* It shouldn't be possible for internal->pending to be in use when this is called because
914  * of the locks in loader.c around reloads and unloads and the fact that internal->pending
915  * only exists while those locks are held */
916  ast_free(info->internal);
917  info->internal = NULL;
918 
919  for (x = 0; info->files[x]; x++) {
921  }
922 }
923 
924 int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
925 {
926  struct aco_option *opt;
927  struct ao2_iterator iter;
928 
929  if (!type->internal) {
930  return -1;
931  }
932 
933  iter = ao2_iterator_init(type->internal->opts, 0);
934 
935  while ((opt = ao2_iterator_next(&iter))) {
937 
938  if (ast_strlen_zero(opt->default_val)) {
939  ao2_ref(opt, -1);
940  continue;
941  }
942  if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
943  ao2_ref(opt, -1);
944  ao2_iterator_destroy(&iter);
945  return -1;
946  }
947  if (opt->handler(opt, var, obj)) {
948  ast_log(LOG_ERROR, "Unable to set default for %s, %s=%s\n", category, var->name, var->value);
949  ao2_ref(opt, -1);
950  ao2_iterator_destroy(&iter);
951  return -1;
952  }
953  ao2_ref(opt, -1);
954  }
955  ao2_iterator_destroy(&iter);
956 
957  return 0;
958 }
959 
960 #ifdef AST_XML_DOCS
961 
962 /*! \internal
963  * \brief Complete the name of the module the user is looking for
964  */
965 static char *complete_config_module(const char *word)
966 {
967  size_t wordlen = strlen(word);
968  struct ao2_iterator i;
969  struct ast_xml_doc_item *cur;
970 
971  i = ao2_iterator_init(xmldocs, 0);
972  while ((cur = ao2_iterator_next(&i))) {
973  if (!strncasecmp(word, cur->name, wordlen)) {
975  ao2_ref(cur, -1);
976  break;
977  }
978  }
979  ao2_ref(cur, -1);
980  }
982 
983  return NULL;
984 }
985 
986 /*! \internal
987  * \brief Complete the name of the configuration type the user is looking for
988  */
989 static char *complete_config_type(const char *module, const char *word)
990 {
991  size_t wordlen = strlen(word);
992  struct ast_xml_doc_item *info;
993  struct ast_xml_doc_item *cur;
994 
995  info = ao2_find(xmldocs, module, OBJ_KEY);
996  if (!info) {
997  return NULL;
998  }
999 
1000  cur = info;
1001  while ((cur = AST_LIST_NEXT(cur, next))) {
1002  if (!strcasecmp(cur->type, "configObject") && !strncasecmp(word, cur->name, wordlen)) {
1003  if (ast_cli_completion_add(ast_strdup(cur->name))) {
1004  break;
1005  }
1006  }
1007  }
1008  ao2_ref(info, -1);
1009 
1010  return NULL;
1011 }
1012 
1013 /*! \internal
1014  * \brief Complete the name of the configuration option the user is looking for
1015  */
1016 static char *complete_config_option(const char *module, const char *option, const char *word)
1017 {
1018  size_t wordlen = strlen(word);
1019  struct ast_xml_doc_item *info;
1020  struct ast_xml_doc_item *cur;
1021 
1022  info = ao2_find(xmldocs, module, OBJ_KEY);
1023  if (!info) {
1024  return NULL;
1025  }
1026 
1027  cur = info;
1028  while ((cur = AST_LIST_NEXT(cur, next))) {
1029  if (!strcasecmp(cur->type, "configOption") && !strcasecmp(cur->ref, option) && !strncasecmp(word, cur->name, wordlen)) {
1030  if (ast_cli_completion_add(ast_strdup(cur->name))) {
1031  break;
1032  }
1033  }
1034  }
1035  ao2_ref(info, -1);
1036 
1037  return NULL;
1038 }
1039 
1040 /* Define as 0 if we want to allow configurations to be registered without
1041  * documentation
1042  */
1043 #define XMLDOC_STRICT 1
1044 
1045 /*! \internal
1046  * \brief Update the XML documentation for a config type based on its registration
1047  */
1048 static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, enum aco_category_op category_match)
1049 {
1050  RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
1051  RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
1052  struct ast_xml_doc_item *config_type;
1053  struct ast_xml_node *type, *syntax, *matchinfo, *tmp;
1054 
1055  /* If we already have a syntax element, bail. This isn't an error, since we may unload a module which
1056  * has updated the docs and then load it again. */
1057  if ((results = ast_xmldoc_query("/docs/configInfo[@name='%s']/configFile/configObject[@name='%s']/syntax", module, name))) {
1058  return 0;
1059  }
1060 
1061  if (!(results = ast_xmldoc_query("/docs/configInfo[@name='%s']/configFile/configObject[@name='%s']", module, name))) {
1062  ast_log(LOG_WARNING, "Cannot update type '%s' in module '%s' because it has no existing documentation!\n", name, module);
1063  return XMLDOC_STRICT ? -1 : 0;
1064  }
1065 
1066  if (!(type = ast_xml_xpath_get_first_result(results))) {
1067  ast_log(LOG_WARNING, "Could not retrieve documentation for type '%s' in module '%s'\n", name, module);
1068  return XMLDOC_STRICT ? -1 : 0;
1069  }
1070 
1071  if (!(syntax = ast_xml_new_child(type, "syntax"))) {
1072  ast_log(LOG_WARNING, "Could not create syntax node for type '%s' in module '%s'\n", name, module);
1073  return XMLDOC_STRICT ? -1 : 0;
1074  }
1075 
1076  if (!(matchinfo = ast_xml_new_child(syntax, "matchInfo"))) {
1077  ast_log(LOG_WARNING, "Could not create matchInfo node for type '%s' in module '%s'\n", name, module);
1078  return XMLDOC_STRICT ? -1 : 0;
1079  }
1080 
1081  if (!(tmp = ast_xml_new_child(matchinfo, "category"))) {
1082  ast_log(LOG_WARNING, "Could not create category node for type '%s' in module '%s'\n", name, module);
1083  return XMLDOC_STRICT ? -1 : 0;
1084  }
1085 
1086  ast_xml_set_text(tmp, category);
1087  switch (category_match) {
1088  case ACO_WHITELIST:
1089  case ACO_WHITELIST_EXACT:
1090  case ACO_WHITELIST_ARRAY:
1091  ast_xml_set_attribute(tmp, "match", "true");
1092  break;
1093  case ACO_BLACKLIST:
1094  case ACO_BLACKLIST_EXACT:
1095  case ACO_BLACKLIST_ARRAY:
1096  ast_xml_set_attribute(tmp, "match", "false");
1097  break;
1098  }
1099 
1100  if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) {
1101  ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
1102  return XMLDOC_STRICT ? -1 : 0;
1103  }
1104 
1105  ast_xml_set_attribute(tmp, "name", matchfield);
1106  ast_xml_set_text(tmp, matchvalue);
1107 
1108  if (!config_info || !(config_type = find_xmldoc_type(config_info, name))) {
1109  ast_log(LOG_WARNING, "Could not obtain XML documentation item for config type %s\n", name);
1110  return XMLDOC_STRICT ? -1 : 0;
1111  }
1112 
1113  if (ast_xmldoc_regenerate_doc_item(config_type)) {
1114  ast_log(LOG_WARNING, "Could not update type '%s' with values from config type registration\n", name);
1115  return XMLDOC_STRICT ? -1 : 0;
1116  }
1117 
1118  return 0;
1119 }
1120 
1121 /*! \internal
1122  * \brief Update the XML documentation for a config option based on its registration
1123  */
1124 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)
1125 {
1126  RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
1127  RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
1128  struct ast_xml_doc_item * config_option;
1129  struct ast_xml_node *option;
1130 
1132 
1133  if (!config_info || !(config_option = find_xmldoc_option(config_info, types, name))) {
1134  ast_log(LOG_ERROR, "XML Documentation for option '%s' in modules '%s' not found!\n", name, module);
1135  return XMLDOC_STRICT ? -1 : 0;
1136  }
1137 
1138  if (!(results = ast_xmldoc_query("/docs/configInfo[@name='%s']/configFile/configObject[@name='%s']/configOption[@name='%s']", module, object_name, name))) {
1139  ast_log(LOG_WARNING, "Could not find option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1140  return XMLDOC_STRICT ? -1 : 0;
1141  }
1142 
1143  if (!(option = ast_xml_xpath_get_first_result(results))) {
1144  ast_log(LOG_WARNING, "Could not obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1145  return XMLDOC_STRICT ? -1 : 0;
1146  }
1147  ast_xml_set_attribute(option, "regex", regex ? "true" : "false");
1148  ast_xml_set_attribute(option, "default", default_value);
1149  ast_xml_set_attribute(option, "type", aco_option_type_string[type]);
1150 
1151  if (ast_xmldoc_regenerate_doc_item(config_option)) {
1152  ast_log(LOG_WARNING, "Could not update option '%s' with values from config option registration\n", name);
1153  return XMLDOC_STRICT ? -1 : 0;
1154  }
1155 
1156  return 0;
1157 }
1158 
1159 /*! \internal
1160  * \brief Show the modules with configuration information
1161  */
1162 static void cli_show_modules(struct ast_cli_args *a)
1163 {
1164  struct ast_xml_doc_item *item;
1165  struct ao2_iterator it_items;
1166 
1167  ast_assert(a->argc == 3);
1168 
1169  if (ao2_container_count(xmldocs) == 0) {
1170  ast_cli(a->fd, "No modules found.\n");
1171  return;
1172  }
1173 
1174  it_items = ao2_iterator_init(xmldocs, 0);
1175  ast_cli(a->fd, "The following modules have configuration information:\n");
1176  while ((item = ao2_iterator_next(&it_items))) {
1177  ast_cli(a->fd, "\t%s\n", item->name);
1178  ao2_ref(item, -1);
1179  }
1180  ao2_iterator_destroy(&it_items);
1181 }
1182 
1183 /*! \internal
1184  * \brief Show the configuration types for a module
1185  */
1187 {
1189  struct ast_xml_doc_item *tmp;
1190 
1191  ast_assert(a->argc == 4);
1192 
1193  if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1194  ast_cli(a->fd, "Module %s not found.\n", a->argv[3]);
1195  return;
1196  }
1197 
1198  if (ast_str_strlen(item->synopsis)) {
1199  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->synopsis), 1));
1200  }
1201  if (ast_str_strlen(item->description)) {
1202  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->description), 1));
1203  }
1204 
1205  tmp = item;
1206  ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
1207  while ((tmp = AST_LIST_NEXT(tmp, next))) {
1208  if (!strcasecmp(tmp->type, "configObject")) {
1209  ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1210  ast_str_buffer(tmp->synopsis));
1211  }
1212  }
1213 }
1214 
1215 /*! \internal
1216  * \brief Show the information for a configuration type
1217  */
1219 {
1221  struct ast_xml_doc_item *tmp;
1222  char option_type[64];
1223  int match = 0;
1224 
1225  ast_assert(a->argc == 5);
1226 
1227  if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1228  ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1229  return;
1230  }
1231 
1232  tmp = item;
1233  while ((tmp = AST_LIST_NEXT(tmp, next))) {
1234  if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
1235  match = 1;
1236  term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
1237  ast_cli(a->fd, "%s", option_type);
1238  if (ast_str_strlen(tmp->syntax)) {
1239  ast_cli(a->fd, ": [%s]\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1240  } else {
1241  ast_cli(a->fd, "\n\n");
1242  }
1243  if (ast_str_strlen(tmp->synopsis)) {
1244  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->synopsis), 1));
1245  }
1246  if (ast_str_strlen(tmp->description)) {
1247  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1248  }
1249  }
1250  }
1251 
1252  if (!match) {
1253  ast_cli(a->fd, "Unknown configuration type %s\n", a->argv[4]);
1254  return;
1255  }
1256 
1257  /* Now iterate over the options for the type */
1258  tmp = item;
1259  while ((tmp = AST_LIST_NEXT(tmp, next))) {
1260  if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
1261  ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1262  ast_str_buffer(tmp->synopsis));
1263  }
1264  }
1265 }
1266 
1267 /*! \internal
1268  * \brief Show detailed information for an option
1269  */
1271 {
1273  struct ast_xml_doc_item *tmp;
1274  char option_name[64];
1275  int match = 0;
1276 
1277  ast_assert(a->argc == 6);
1278 
1279  if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1280  ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1281  return;
1282  }
1283  tmp = item;
1284  while ((tmp = AST_LIST_NEXT(tmp, next))) {
1285  if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
1286  if (match) {
1287  ast_cli(a->fd, "\n");
1288  }
1289  term_color(option_name, tmp->ref, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_name));
1290  ast_cli(a->fd, "[%s%s]\n", option_name, ast_term_reset());
1291  if (ast_str_strlen(tmp->syntax)) {
1292  ast_cli(a->fd, "%s\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1293  }
1294  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(AS_OR(tmp->synopsis, "No information available"), 1));
1295  if (ast_str_strlen(tmp->description)) {
1296  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1297  }
1298 
1299  if (ast_str_strlen(tmp->seealso)) {
1300  ast_cli(a->fd, "See Also:\n");
1301  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->seealso), 1));
1302  }
1303 
1304  match = 1;
1305  }
1306  }
1307 
1308  if (!match) {
1309  ast_cli(a->fd, "No option %s found for %s:%s\n", a->argv[5], a->argv[3], a->argv[4]);
1310  }
1311 }
1312 
1313 static char *cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1314 {
1315  switch (cmd) {
1316  case CLI_INIT:
1317  e->command = "config show help";
1318  e->usage =
1319  "Usage: config show help [<module> [<type> [<option>]]]\n"
1320  " Display detailed information about module configuration.\n"
1321  " * If nothing is specified, the modules that have\n"
1322  " configuration information are listed.\n"
1323  " * If <module> is specified, the configuration types\n"
1324  " for that module will be listed, along with brief\n"
1325  " information about that type.\n"
1326  " * If <module> and <type> are specified, detailed\n"
1327  " information about the type is displayed, as well\n"
1328  " as the available options.\n"
1329  " * If <module>, <type>, and <option> are specified,\n"
1330  " detailed information will be displayed about that\n"
1331  " option.\n"
1332  " NOTE: the help documentation is partially generated at run\n"
1333  " time when a module is loaded. If a module is not loaded,\n"
1334  " configuration help for that module may be incomplete.\n";
1335  return NULL;
1336  case CLI_GENERATE:
1337  switch(a->pos) {
1338  case 3:
1339  return complete_config_module(a->word);
1340  case 4:
1341  return complete_config_type(a->argv[3], a->word);
1342  case 5:
1343  return complete_config_option(a->argv[3], a->argv[4], a->word);
1344  default:
1345  return NULL;
1346  }
1347  }
1348 
1349  switch (a->argc) {
1350  case 3:
1351  cli_show_modules(a);
1352  break;
1353  case 4:
1355  break;
1356  case 5:
1358  break;
1359  case 6:
1361  break;
1362  default:
1363  return CLI_SHOWUSAGE;
1364  }
1365 
1366  return CLI_SUCCESS;
1367 }
1368 
1369 static struct ast_cli_entry cli_aco[] = {
1370  AST_CLI_DEFINE(cli_show_help, "Show configuration help for a module"),
1371 };
1372 
1373 static void aco_deinit(void)
1374 {
1375  ast_cli_unregister(cli_aco);
1376  ao2_cleanup(xmldocs);
1377 }
1378 #endif /* AST_XML_DOCS */
1379 
1380 int aco_init(void)
1381 {
1382 #ifdef AST_XML_DOCS
1384  if (!(xmldocs = ast_xmldoc_build_documentation("configInfo"))) {
1385  ast_log(LOG_ERROR, "Couldn't build config documentation\n");
1386  return -1;
1387  }
1388  ast_cli_register_multiple(cli_aco, ARRAY_LEN(cli_aco));
1389 #endif /* AST_XML_DOCS */
1390  return 0;
1391 }
1392 
1393 /* Default config option handlers */
1394 
1395 /*! \brief Default option handler for signed integers
1396  * \note For a description of the opt->flags and opt->args values, see the documentation for
1397  * enum aco_option_type in config_options.h
1398  */
1399 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1400  int *field = (int *)(obj + opt->args[0]);
1401  unsigned int flags = PARSE_INT32 | opt->flags;
1402  int res = 0;
1403  if (opt->flags & PARSE_IN_RANGE) {
1404  res = opt->flags & PARSE_DEFAULT ?
1405  ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
1406  ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
1407  if (res) {
1408  if (opt->flags & PARSE_RANGE_DEFAULTS) {
1409  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]);
1410  res = 0;
1411  } else if (opt->flags & PARSE_DEFAULT) {
1412  ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1413  res = 0;
1414  }
1415  }
1416  } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
1417  ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
1418  } else {
1419  res = ast_parse_arg(var->value, flags, field);
1420  }
1421 
1422  return res;
1423 }
1424 
1425 /*! \brief Default option handler for unsigned integers
1426  * \note For a description of the opt->flags and opt->args values, see the documentation for
1427  * enum aco_option_type in config_options.h
1428  */
1429 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1430  unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1431  unsigned int flags = PARSE_UINT32 | opt->flags;
1432  int res = 0;
1433  if (opt->flags & PARSE_IN_RANGE) {
1434  res = opt->flags & PARSE_DEFAULT ?
1435  ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
1436  ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
1437  if (res) {
1438  if (opt->flags & PARSE_RANGE_DEFAULTS) {
1439  ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %u instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
1440  res = 0;
1441  } else if (opt->flags & PARSE_DEFAULT) {
1442  ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %u instead.\n", var->name, var->value, *field);
1443  res = 0;
1444  }
1445  }
1446  } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
1447  ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
1448  } else {
1449  res = ast_parse_arg(var->value, flags, field);
1450  }
1451 
1452  return res;
1453 }
1454 
1455 /*! \brief Default option handler for timelen signed integers
1456  * \note For a description of the opt->flags and opt->args values, see the documentation for
1457  * enum aco_option_type in config_options.h
1458  */
1459 static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1460 {
1461  int *field = (int *)(obj + opt->args[0]);
1462  unsigned int flags = PARSE_TIMELEN | opt->flags;
1463  int res = 0;
1464  if (opt->flags & PARSE_IN_RANGE) {
1465  if (opt->flags & PARSE_DEFAULT) {
1466  res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2], (int) opt->args[3], opt->args[4]);
1467  } else {
1468  res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2], (int) opt->args[3]);
1469  }
1470  if (res) {
1471  if (opt->flags & PARSE_RANGE_DEFAULTS) {
1472  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[2], (int) opt->args[3]);
1473  res = 0;
1474  } else if (opt->flags & PARSE_DEFAULT) {
1475  ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1476  res = 0;
1477  }
1478  }
1479  } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2])) {
1480  ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
1481  } else {
1482  res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1]);
1483  }
1484 
1485  return res;
1486 }
1487 
1488 /*! \brief Default option handler for doubles
1489  * \note For a description of the opt->flags and opt->args values, see the documentation for
1490  * enum aco_option_type in config_options.h
1491  */
1492 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1493  double *field = (double *)(obj + opt->args[0]);
1494  return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
1495 }
1496 
1497 /*! \brief Default handler for ACLs
1498  * \note For a description of the opt->flags and opt->args values, see the documentation for
1499  * enum aco_option_type in config_options.h
1500  */
1501 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1502  struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
1503  int error = 0;
1504  *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
1505  return error;
1506 }
1507 
1508 /*! \brief Default option handler for codec preferences/capabilities
1509  * \note For a description of the opt->flags and opt->args values, see the documentation for
1510  * enum aco_option_type in config_options.h
1511  */
1512 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1513  struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[0]);
1514  return ast_format_cap_update_by_allow_disallow(*cap, var->value, opt->flags);
1515 }
1516 
1517 /*! \brief Default option handler for stringfields
1518  * \note For a description of the opt->flags and opt->args values, see the documentation for
1519  * enum aco_option_type in config_options.h
1520  */
1521 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1522 {
1523  ast_string_field *field = (const char **)(obj + opt->args[0]);
1524  struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
1525  struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
1526 
1527  if (opt->flags && ast_strlen_zero(var->value)) {
1528  return -1;
1529  }
1530  ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
1531  return 0;
1532 }
1533 
1534 /*! \brief Default option handler for bools (ast_true/ast_false)
1535  * \note For a description of the opt->flags and opt->args values, see the documentation for
1536  * enum aco_option_type in config_options.h
1537  */
1538 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1539 {
1540  unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1541  *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
1542  return 0;
1543 }
1544 
1545 /*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
1546  * \note For a description of the opt->flags and opt->args values, see the documentation for
1547  * enum aco_option_type in config_options.h
1548  */
1549 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1550 {
1551  unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
1552  unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
1553  unsigned int flag = opt->args[1];
1554  if (val) {
1555  *flags_field |= flag;
1556  } else {
1557  *flags_field &= ~flag;
1558  }
1559  return 0;
1560 }
1561 
1562 /*! \brief Default handler for ast_sockaddrs
1563  * \note For a description of the opt->flags and opt->args values, see the documentation for
1564  * enum aco_option_type in config_options.h
1565  */
1566 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1567 {
1568  struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
1569  return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
1570 }
1571 
1572 /*! \brief Default handler for doing nothing
1573  */
1574 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1575 {
1576  return 0;
1577 }
1578 
1579 /*! \brief Default handler for character arrays
1580  * \note For a description of the opt->flags and opt->args values, see the documentation for
1581  * enum aco_option_type in config_options.h
1582  */
1583 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1584 {
1585  char *field = (char *)(obj + opt->args[0]);
1586  size_t len = opt->args[1];
1587 
1588  if (opt->flags && ast_strlen_zero(var->value)) {
1589  return -1;
1590  }
1591  ast_copy_string(field, var->value, len);
1592  return 0;
1593 }
aco_type_item_pre_process item_pre_process
static struct aco_option * aco_option_find(struct aco_type *type, const char *name)
Type for default handler for ast_sockaddrs.
struct ast_variable * next
Type for default option handler for format capabilities.
int(* aco_option_handler)(const struct aco_option *opt, struct ast_variable *var, void *obj)
A callback function for handling a particular option.
const char * matchfield
aco_pre_apply_config pre_apply_config
static const char type[]
Definition: chan_ooh323.c:109
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for ast_sockaddrs.
aco_type_item_find item_find
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
struct ao2_global_obj * global_obj
unsigned int no_doc
aco_option_handler handler
Asterisk main include file. File version handling, generic pbx functions.
static void cli_show_module_types(struct ast_cli_args *a)
static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for character arrays.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
struct aco_info_internal * internal
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
Definition: ast_expr2.c:325
static void cli_show_module_type(struct ast_cli_args *a)
struct ast_xml_doc_item * next
Definition: xmldoc.h:80
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
static void aco_deinit(void)
#define OBJ_KEY
Definition: astobj2.h:1155
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
const ast_string_field ref
Definition: xmldoc.h:74
static int config_opt_cmp(void *obj, void *arg, int flags)
unsigned int aco_option_get_flags(const struct aco_option *option)
Read the flags of a config option - useful when using a custom callback for a config option...
int ast_cli_unregister(struct ast_cli_entry *e)
Unregisters a command or an array of commands.
Definition: main/cli.c:2397
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define LOG_WARNING
Definition: logger.h:274
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
struct aco_type_internal * internal
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
#define CONFIG_STATUS_FILEINVALID
static struct ast_cli_entry cli_aco[]
static int tmp()
Definition: bt_open.c:389
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
aco_type_prelink item_prelink
static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for bools (ast_true/ast_false) that are stored as flags.
struct ao2_container * ast_xmldoc_build_documentation(const char *type)
Build the documentation for a particular source type.
Definition: xmldoc.c:2653
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for unsigned integers.
Definition: cli.h:152
Type for a default handler that should do nothing.
static regex_t * build_regex(const char *text)
intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
Get the offset position for an argument within a config option.
static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
struct ast_xml_xpath_results * ast_xmldoc_query(const char *fmt,...)
Execute an XPath query on the loaded XML documentation.
Definition: xmldoc.c:2545
static struct aco_type item
Definition: test_config.c:1463
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
const char * default_val
static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for codec preferences/capabilities.
const char * ast_string_field
Definition: stringfields.h:190
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_assert(a)
Definition: utils.h:650
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2316
Type for default option handler for bools (ast_true/ast_false) that are stored in a flag...
char * text
Definition: app_queue.c:1511
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
static char * complete_config_module(const char *word)
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
const char * args
#define NULL
Definition: resample.c:96
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
char * end
Definition: eagi_proxy.c:73
The representation of a single configuration file to be processed.
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
Bits of aco_info that shouldn&#39;t be assigned outside this file.
enum aco_type_t type
static void cli_show_modules(struct ast_cli_args *a)
aco_matchtype
What kind of matching should be done on an option name.
Socket address structure.
Definition: netsock2.h:97
static char * cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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)
struct ast_xml_node * ast_xml_new_child(struct ast_xml_node *parent, const char *child_name)
Add a child node inside a passed parent node.
Definition: xml.c:125
struct aco_type ** obj
Type for a custom (user-defined) option handler.
int ast_format_cap_update_by_allow_disallow(struct ast_format_cap *cap, const char *list, int allowing)
Parse an "allow" or "deny" list and modify a format capabilities structure accordingly.
Definition: format_cap.c:320
static int is_preload(struct aco_file *file, const char *cat)
const char * alias
static char * complete_config_type(const char *module, const char *word)
Type for default option handler for character array strings.
internal representation of ACL entries In principle user applications would have no need for this...
Definition: acl.h:51
Type for default option handler for bools (ast_true/ast_false)
Configuration File Parser.
#define XMLDOC_STRICT
struct ao2_container * opts
static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for bools (ast_true/ast_false)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
const char * matchvalue
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
unsigned int flags
static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for doing nothing.
const ast_string_field type
Definition: xmldoc.h:74
enum aco_matchtype match_type
static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for signed integers.
static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for stringfields.
int aco_init(void)
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
static struct ao2_container * xmldocs
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:851
Type for default option handler for unsigned integers.
int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
Parse each option defined in a config category.
static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, enum aco_category_op category_match)
const int fd
Definition: cli.h:159
static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
static void internal_type_destroy(struct aco_type *type)
Access Control of various sorts.
unsigned int hidden
const char * category
int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
Register a deprecated (and aliased) config option.
Asterisk internal frame definitions.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
aco_process_status
Return values for the aco_process functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static char * complete_config_option(const char *module, const char *option, const char *word)
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
aco_type_item_alloc item_alloc
#define ast_variable_new(name, value, filename)
enum aco_category_op category_match
aco_option_type
The option types.
intptr_t args[0]
#define CONFIG_STATUS_FILEUNCHANGED
Format Capabilities API.
The config had not been edited and no changes applied.
Their was an error and no changes were applied.
struct ast_str * description
Definition: xmldoc.h:66
static int link_option_to_types(struct aco_info *info, struct aco_type **types, struct aco_option *opt)
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
Definition: term.c:184
const char *const * argv
Definition: cli.h:161
#define COLOR_BLACK
Definition: term.h:47
static char * aco_option_type_string[]
Value of the aco_option_type enum as strings.
Configuration option-handling.
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1822
struct aco_file * files[]
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
struct association categories[]
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
#define CLI_SHOWUSAGE
Definition: cli.h:45
aco_post_apply_config post_apply_config
#define CONFIG_OPT_BUCKETS
Type for default option handler for bools (ast_true/ast_false)
def info(msg)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
regex_t * name_regex
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
enum aco_option_type type
#define LOG_NOTICE
Definition: logger.h:263
unsigned char deprecated
static int find_option_cb(void *obj, void *arg, int flags)
void ast_xml_set_text(struct ast_xml_node *node, const char *content)
Set an element content string.
Definition: xml.c:326
static int internal_aco_type_category_check(struct aco_type *match, const char *category)
const ast_string_field name
Definition: xmldoc.h:74
long int flag
Definition: f2c.h:83
#define ast_strlen_zero(a)
Definition: muted.c:73
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:948
Type for default option handler for ACLs.
static int reload(void)
Definition: cdr_mysql.c:741
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:306
Type for default option handler for doubles.
const char ** preload
static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for timelen signed integers.
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *result,...)
The argument parsing routine.
Definition: main/config.c:3657
The config was processed and applied.
Asterisk XML Documentation API.
#define ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data)
Definition: stringfields.h:503
const char * word
Definition: cli.h:163
Prototypes for public functions only of internal interest,.
void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
Free the XPath results.
Definition: xml.c:370
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
char * ast_xmldoc_printable(const char *bwinput, int withcolors)
Colorize and put delimiters (instead of tags) to the xmldoc output.
Definition: xmldoc.c:242
int ast_xmldoc_regenerate_doc_item(struct ast_xml_doc_item *item)
Regenerate the documentation for a particular item.
Definition: xmldoc.c:2604
Structure used to handle boolean flags.
Definition: utils.h:199
static struct ast_xml_doc_item * find_xmldoc_option(struct ast_xml_doc_item *config_info, struct aco_type **types, const char *name)
#define ast_clear_flag(p, flag)
Definition: utils.h:77
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
const char * skip_category
const char * usage
Definition: cli.h:177
#define CONFIG_STATUS_FILEMISSING
#define CLI_SUCCESS
Definition: cli.h:44
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:694
static void cli_show_module_options(struct ast_cli_args *a)
#define ao2_global_obj_replace_unref(holder, obj)
Definition: astobj2.h:908
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
const char * name
#define AS_OR(a, b)
Definition: strings.h:49
int ast_xml_set_attribute(struct ast_xml_node *node, const char *name, const char *value)
Set an attribute to a node.
Definition: xml.c:253
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Type for default option handler for time length signed integers.
Standard Command Line Interface.
Type information about a category-level configurable object.
aco_snapshot_alloc snapshot_alloc
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
size_t item_offset
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: main/utils.c:1839
const int pos
Definition: cli.h:164
const char * filename
enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
Process config info from an ast_config via options registered with an aco_info.
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition: test_ari.c:59
static int internal_type_init(struct aco_type *type)
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
Type for default option handler for stringfields.
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
struct ast_ha * ast_append_ha(const char *sense, const char *stuff, struct ast_ha *path, int *error)
Add a new rule to a list of HAs.
Definition: acl.c:713
Handy terminal functions for vt* terms.
int error(const char *format,...)
Definition: utils/frame.c:999
Struct that contains the XML documentation for a particular item. Note that this is an ao2 ref counte...
Definition: xmldoc.h:56
int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
Parse a single ast_variable and apply it to an object.
Generic container type.
static int apply_config(struct aco_info *info)
static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload)
static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for ACLs.
const char * module
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2726
struct ast_str * syntax
Definition: xmldoc.h:58
struct aco_type * types[]
Type for default option handler for signed integers.
const char * aliased_to
const char * name
struct ao2_container * aco_option_container_alloc(void)
Allocate a container to hold config options.
static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for doubles.
aco_category_op
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ast_xml_node * ast_xml_xpath_get_first_result(struct ast_xml_xpath_results *results)
Return the first result node of an XPath query.
Definition: xml.c:365
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static int config_opt_hash(const void *obj, const int flags)
static struct ast_xml_doc_item * find_xmldoc_type(struct ast_xml_doc_item *config_info, const char *name)
int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types, const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags, unsigned int no_doc, size_t argc,...)
register a config option
struct ast_str * seealso
Definition: xmldoc.h:60
aco_matchvalue_func matchfunc
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1250
static struct aco_type * internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
#define COLOR_MAGENTA
Definition: term.h:57
struct ast_str * synopsis
Definition: xmldoc.h:64
short word
static void internal_file_types_destroy(struct aco_file *file)
static struct test_val a
#define ao2_link(container, obj)
Definition: astobj2.h:1549
unsigned int hidden
static void config_option_destroy(void *obj)