Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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;
67  regex_t *name_regex;
68  struct aco_type **obj;
69  enum aco_option_type type;
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 
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 */
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 {
591  ao2_global_obj_replace_unref(*info->global_obj, info->internal->pending);
592 
593  return 0;
594 }
595 
596 static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
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 
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 {
738  }
739  } else {
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))) {
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())) {
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:
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 /*! \internal
1041  * \brief Generate a category match string suitable for display in 'config show help'
1042  */
1043 static struct ast_str *derive_category_text(enum aco_category_op category_match, const char *category)
1044 {
1045  struct ast_str *s = ast_str_create(128);
1046 
1047  if (!s) {
1048  return NULL;
1049  }
1050 
1051  switch (category_match) {
1052  case ACO_WHITELIST_ARRAY:
1053  case ACO_BLACKLIST_ARRAY: {
1054  size_t i;
1055  const char **matches = (const char **) category;
1056  ast_str_append(&s, 0, "^(");
1057  for (i = 0; matches[i]; i++) {
1058  ast_str_append(&s, 0, "%s%s",
1059  i ? "|" : "",
1060  matches[i]);
1061  }
1062  ast_str_append(&s, 0, ")$");
1063  break;
1064  }
1065  case ACO_WHITELIST_EXACT:
1066  case ACO_BLACKLIST_EXACT:
1067  ast_str_set(&s, 0, "^%s$", category);
1068  break;
1069  case ACO_WHITELIST:
1070  case ACO_BLACKLIST:
1071  default:
1072  ast_str_set(&s, 0, "%s", category);
1073  break;
1074  }
1075 
1076  return s;
1077 }
1078 
1079 /* Define as 0 if we want to allow configurations to be registered without
1080  * documentation
1081  */
1082 #define XMLDOC_STRICT 1
1083 
1084 /*! \internal
1085  * \brief Update the XML documentation for a config type based on its registration
1086  */
1087 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)
1088 {
1089  RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
1090  RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
1091  struct ast_xml_doc_item *config_type;
1092  struct ast_xml_node *type, *syntax, *matchinfo, *tmp;
1093  struct ast_str *derived_category = NULL;
1094 
1095  /* If we already have a syntax element, bail. This isn't an error, since we may unload a module which
1096  * has updated the docs and then load it again. */
1097  if ((results = ast_xmldoc_query("/docs/configInfo[@name='%s']/configFile/configObject[@name='%s']/syntax", module, name))) {
1098  return 0;
1099  }
1100 
1101  if (!(results = ast_xmldoc_query("/docs/configInfo[@name='%s']/configFile/configObject[@name='%s']", module, name))) {
1102  ast_log(LOG_WARNING, "Cannot update type '%s' in module '%s' because it has no existing documentation!\n", name, module);
1103  return XMLDOC_STRICT ? -1 : 0;
1104  }
1105 
1106  if (!(type = ast_xml_xpath_get_first_result(results))) {
1107  ast_log(LOG_WARNING, "Could not retrieve documentation for type '%s' in module '%s'\n", name, module);
1108  return XMLDOC_STRICT ? -1 : 0;
1109  }
1110 
1111  if (!(syntax = ast_xml_new_child(type, "syntax"))) {
1112  ast_log(LOG_WARNING, "Could not create syntax node for type '%s' in module '%s'\n", name, module);
1113  return XMLDOC_STRICT ? -1 : 0;
1114  }
1115 
1116  if (!(matchinfo = ast_xml_new_child(syntax, "matchInfo"))) {
1117  ast_log(LOG_WARNING, "Could not create matchInfo node for type '%s' in module '%s'\n", name, module);
1118  return XMLDOC_STRICT ? -1 : 0;
1119  }
1120 
1121  if (!(tmp = ast_xml_new_child(matchinfo, "category"))) {
1122  ast_log(LOG_WARNING, "Could not create category node for type '%s' in module '%s'\n", name, module);
1123  return XMLDOC_STRICT ? -1 : 0;
1124  }
1125 
1126  derived_category = derive_category_text(category_match, category);
1127  if (derived_category) {
1128  ast_xml_set_text(tmp, ast_str_buffer(derived_category));
1129  ast_free(derived_category);
1130  }
1131 
1132  switch (category_match) {
1133  case ACO_WHITELIST:
1134  case ACO_WHITELIST_EXACT:
1135  case ACO_WHITELIST_ARRAY:
1136  ast_xml_set_attribute(tmp, "match", "true");
1137  break;
1138  case ACO_BLACKLIST:
1139  case ACO_BLACKLIST_EXACT:
1140  case ACO_BLACKLIST_ARRAY:
1141  ast_xml_set_attribute(tmp, "match", "false");
1142  break;
1143  }
1144 
1145  if (!ast_strlen_zero(matchfield)) {
1146  if (!(tmp = ast_xml_new_child(matchinfo, "field"))) {
1147  ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
1148  return XMLDOC_STRICT ? -1 : 0;
1149  }
1150  ast_xml_set_attribute(tmp, "name", matchfield);
1151  ast_xml_set_text(tmp, matchvalue);
1152  }
1153 
1154  if (!config_info || !(config_type = find_xmldoc_type(config_info, name))) {
1155  ast_log(LOG_WARNING, "Could not obtain XML documentation item for config type %s\n", name);
1156  return XMLDOC_STRICT ? -1 : 0;
1157  }
1158 
1159  if (ast_xmldoc_regenerate_doc_item(config_type)) {
1160  ast_log(LOG_WARNING, "Could not update type '%s' with values from config type registration\n", name);
1161  return XMLDOC_STRICT ? -1 : 0;
1162  }
1163 
1164  return 0;
1165 }
1166 
1167 /*! \internal
1168  * \brief Update the XML documentation for a config option based on its registration
1169  */
1170 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)
1171 {
1172  RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
1173  RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
1174  struct ast_xml_doc_item * config_option;
1175  struct ast_xml_node *option;
1176 
1178 
1179  if (!config_info || !(config_option = find_xmldoc_option(config_info, types, name))) {
1180  ast_log(LOG_ERROR, "XML Documentation for option '%s' in modules '%s' not found!\n", name, module);
1181  return XMLDOC_STRICT ? -1 : 0;
1182  }
1183 
1184  if (!(results = ast_xmldoc_query("/docs/configInfo[@name='%s']/configFile/configObject[@name='%s']/configOption[@name='%s']", module, object_name, name))) {
1185  ast_log(LOG_WARNING, "Could not find option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1186  return XMLDOC_STRICT ? -1 : 0;
1187  }
1188 
1189  if (!(option = ast_xml_xpath_get_first_result(results))) {
1190  ast_log(LOG_WARNING, "Could not obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1191  return XMLDOC_STRICT ? -1 : 0;
1192  }
1193  ast_xml_set_attribute(option, "regex", regex ? "true" : "false");
1194  ast_xml_set_attribute(option, "default", default_value);
1196 
1197  if (ast_xmldoc_regenerate_doc_item(config_option)) {
1198  ast_log(LOG_WARNING, "Could not update option '%s' with values from config option registration\n", name);
1199  return XMLDOC_STRICT ? -1 : 0;
1200  }
1201 
1202  return 0;
1203 }
1204 
1205 /*! \internal
1206  * \brief Show the modules with configuration information
1207  */
1208 static void cli_show_modules(struct ast_cli_args *a)
1209 {
1210  struct ast_xml_doc_item *item;
1211  struct ao2_iterator it_items;
1212 
1213  ast_assert(a->argc == 3);
1214 
1215  if (ao2_container_count(xmldocs) == 0) {
1216  ast_cli(a->fd, "No modules found.\n");
1217  return;
1218  }
1219 
1220  it_items = ao2_iterator_init(xmldocs, 0);
1221  ast_cli(a->fd, "The following modules have configuration information:\n");
1222  while ((item = ao2_iterator_next(&it_items))) {
1223  ast_cli(a->fd, "\t%s\n", item->name);
1224  ao2_ref(item, -1);
1225  }
1226  ao2_iterator_destroy(&it_items);
1227 }
1228 
1229 /*! \internal
1230  * \brief Show the configuration types for a module
1231  */
1233 {
1235  struct ast_xml_doc_item *tmp;
1236 
1237  ast_assert(a->argc == 4);
1238 
1239  if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1240  ast_cli(a->fd, "Module %s not found.\n", a->argv[3]);
1241  return;
1242  }
1243 
1244  if (ast_str_strlen(item->synopsis)) {
1245  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->synopsis), 1));
1246  }
1247  if (ast_str_strlen(item->description)) {
1248  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->description), 1));
1249  }
1250 
1251  tmp = item;
1252  ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
1253  while ((tmp = AST_LIST_NEXT(tmp, next))) {
1254  if (!strcasecmp(tmp->type, "configObject")) {
1255  ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1256  ast_str_buffer(tmp->synopsis));
1257  }
1258  }
1259 }
1260 
1261 /*! \internal
1262  * \brief Show the information for a configuration type
1263  */
1265 {
1267  struct ast_xml_doc_item *tmp;
1268  char option_type[64];
1269  int match = 0;
1270 
1271  ast_assert(a->argc == 5);
1272 
1273  if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1274  ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1275  return;
1276  }
1277 
1278  tmp = item;
1279  while ((tmp = AST_LIST_NEXT(tmp, next))) {
1280  if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
1281  match = 1;
1282  term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
1283  ast_cli(a->fd, "%s", option_type);
1284  if (ast_str_strlen(tmp->syntax)) {
1285  ast_cli(a->fd, ": [%s]\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1286  } else {
1287  ast_cli(a->fd, "\n\n");
1288  }
1289  if (ast_str_strlen(tmp->synopsis)) {
1290  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->synopsis), 1));
1291  }
1292  if (ast_str_strlen(tmp->description)) {
1293  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1294  }
1295  }
1296  }
1297 
1298  if (!match) {
1299  ast_cli(a->fd, "Unknown configuration type %s\n", a->argv[4]);
1300  return;
1301  }
1302 
1303  /* Now iterate over the options for the type */
1304  tmp = item;
1305  while ((tmp = AST_LIST_NEXT(tmp, next))) {
1306  if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
1307  ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1308  ast_str_buffer(tmp->synopsis));
1309  }
1310  }
1311 }
1312 
1313 /*! \internal
1314  * \brief Show detailed information for an option
1315  */
1317 {
1319  struct ast_xml_doc_item *tmp;
1320  char option_name[64];
1321  int match = 0;
1322 
1323  ast_assert(a->argc == 6);
1324 
1325  if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1326  ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1327  return;
1328  }
1329  tmp = item;
1330  while ((tmp = AST_LIST_NEXT(tmp, next))) {
1331  if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
1332  if (match) {
1333  ast_cli(a->fd, "\n");
1334  }
1335  term_color(option_name, tmp->ref, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_name));
1336  ast_cli(a->fd, "[%s%s]\n", option_name, ast_term_reset());
1337  if (ast_str_strlen(tmp->syntax)) {
1338  ast_cli(a->fd, "%s\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1339  }
1340  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(AS_OR(tmp->synopsis, "No information available"), 1));
1341  if (ast_str_strlen(tmp->description)) {
1342  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1343  }
1344 
1345  if (ast_str_strlen(tmp->seealso)) {
1346  ast_cli(a->fd, "See Also:\n");
1347  ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->seealso), 1));
1348  }
1349 
1350  match = 1;
1351  }
1352  }
1353 
1354  if (!match) {
1355  ast_cli(a->fd, "No option %s found for %s:%s\n", a->argv[5], a->argv[3], a->argv[4]);
1356  }
1357 }
1358 
1359 static char *cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1360 {
1361  switch (cmd) {
1362  case CLI_INIT:
1363  e->command = "config show help";
1364  e->usage =
1365  "Usage: config show help [<module> [<type> [<option>]]]\n"
1366  " Display detailed information about module configuration.\n"
1367  " * If nothing is specified, the modules that have\n"
1368  " configuration information are listed.\n"
1369  " * If <module> is specified, the configuration types\n"
1370  " for that module will be listed, along with brief\n"
1371  " information about that type.\n"
1372  " * If <module> and <type> are specified, detailed\n"
1373  " information about the type is displayed, as well\n"
1374  " as the available options.\n"
1375  " * If <module>, <type>, and <option> are specified,\n"
1376  " detailed information will be displayed about that\n"
1377  " option.\n"
1378  " NOTE: the help documentation is partially generated at run\n"
1379  " time when a module is loaded. If a module is not loaded,\n"
1380  " configuration help for that module may be incomplete.\n";
1381  return NULL;
1382  case CLI_GENERATE:
1383  switch(a->pos) {
1384  case 3:
1385  return complete_config_module(a->word);
1386  case 4:
1387  return complete_config_type(a->argv[3], a->word);
1388  case 5:
1389  return complete_config_option(a->argv[3], a->argv[4], a->word);
1390  default:
1391  return NULL;
1392  }
1393  }
1394 
1395  switch (a->argc) {
1396  case 3:
1398  break;
1399  case 4:
1401  break;
1402  case 5:
1404  break;
1405  case 6:
1407  break;
1408  default:
1409  return CLI_SHOWUSAGE;
1410  }
1411 
1412  return CLI_SUCCESS;
1413 }
1414 
1415 static struct ast_cli_entry cli_aco[] = {
1416  AST_CLI_DEFINE(cli_show_help, "Show configuration help for a module"),
1417 };
1418 
1419 static void aco_deinit(void)
1420 {
1423 }
1424 #endif /* AST_XML_DOCS */
1425 
1426 int aco_init(void)
1427 {
1428 #ifdef AST_XML_DOCS
1430  if (!(xmldocs = ast_xmldoc_build_documentation("configInfo"))) {
1431  ast_log(LOG_ERROR, "Couldn't build config documentation\n");
1432  return -1;
1433  }
1435 #endif /* AST_XML_DOCS */
1436  return 0;
1437 }
1438 
1439 /* Default config option handlers */
1440 
1441 /*! \brief Default option handler for signed integers
1442  * \note For a description of the opt->flags and opt->args values, see the documentation for
1443  * enum aco_option_type in config_options.h
1444  */
1445 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1446  int *field = (int *)(obj + opt->args[0]);
1447  unsigned int flags = PARSE_INT32 | opt->flags;
1448  int res = 0;
1449  if (opt->flags & PARSE_IN_RANGE) {
1450  res = opt->flags & PARSE_DEFAULT ?
1451  ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
1452  ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
1453  if (res) {
1454  if (opt->flags & PARSE_RANGE_DEFAULTS) {
1455  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]);
1456  res = 0;
1457  } else if (opt->flags & PARSE_DEFAULT) {
1458  ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1459  res = 0;
1460  }
1461  }
1462  } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
1463  ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
1464  } else {
1465  res = ast_parse_arg(var->value, flags, field);
1466  }
1467 
1468  return res;
1469 }
1470 
1471 /*! \brief Default option handler for unsigned integers
1472  * \note For a description of the opt->flags and opt->args values, see the documentation for
1473  * enum aco_option_type in config_options.h
1474  */
1475 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1476  unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1477  unsigned int flags = PARSE_UINT32 | opt->flags;
1478  int res = 0;
1479  if (opt->flags & PARSE_IN_RANGE) {
1480  res = opt->flags & PARSE_DEFAULT ?
1481  ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
1482  ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
1483  if (res) {
1484  if (opt->flags & PARSE_RANGE_DEFAULTS) {
1485  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]);
1486  res = 0;
1487  } else if (opt->flags & PARSE_DEFAULT) {
1488  ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %u instead.\n", var->name, var->value, *field);
1489  res = 0;
1490  }
1491  }
1492  } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
1493  ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
1494  } else {
1495  res = ast_parse_arg(var->value, flags, field);
1496  }
1497 
1498  return res;
1499 }
1500 
1501 /*! \brief Default option handler for timelen signed integers
1502  * \note For a description of the opt->flags and opt->args values, see the documentation for
1503  * enum aco_option_type in config_options.h
1504  */
1505 static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1506 {
1507  int *field = (int *)(obj + opt->args[0]);
1508  unsigned int flags = PARSE_TIMELEN | opt->flags;
1509  int res = 0;
1510  if (opt->flags & PARSE_IN_RANGE) {
1511  if (opt->flags & PARSE_DEFAULT) {
1512  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]);
1513  } else {
1514  res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2], (int) opt->args[3]);
1515  }
1516  if (res) {
1517  if (opt->flags & PARSE_RANGE_DEFAULTS) {
1518  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]);
1519  res = 0;
1520  } else if (opt->flags & PARSE_DEFAULT) {
1521  ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1522  res = 0;
1523  }
1524  }
1525  } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1], (int) opt->args[2])) {
1526  ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
1527  } else {
1528  res = ast_parse_arg(var->value, flags, field, (enum ast_timelen) opt->args[1]);
1529  }
1530 
1531  return res;
1532 }
1533 
1534 /*! \brief Default option handler for doubles
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 double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1539  double *field = (double *)(obj + opt->args[0]);
1540  return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
1541 }
1542 
1543 /*! \brief Default handler for ACLs
1544  * \note For a description of the opt->flags and opt->args values, see the documentation for
1545  * enum aco_option_type in config_options.h
1546  */
1547 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1548  struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
1549  int error = 0;
1550  *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
1551  return error;
1552 }
1553 
1554 /*! \brief Default option handler for codec preferences/capabilities
1555  * \note For a description of the opt->flags and opt->args values, see the documentation for
1556  * enum aco_option_type in config_options.h
1557  */
1558 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1559  struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[0]);
1560  return ast_format_cap_update_by_allow_disallow(*cap, var->value, opt->flags);
1561 }
1562 
1563 /*! \brief Default option handler for stringfields
1564  * \note For a description of the opt->flags and opt->args values, see the documentation for
1565  * enum aco_option_type in config_options.h
1566  */
1567 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1568 {
1569  ast_string_field *field = (const char **)(obj + opt->args[0]);
1570  struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
1571  struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
1572 
1573  if (opt->flags && ast_strlen_zero(var->value)) {
1574  return -1;
1575  }
1576  ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
1577  return 0;
1578 }
1579 
1580 /*! \brief Default option handler for bools (ast_true/ast_false)
1581  * \note For a description of the opt->flags and opt->args values, see the documentation for
1582  * enum aco_option_type in config_options.h
1583  */
1584 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1585 {
1586  unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1587  *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
1588  return 0;
1589 }
1590 
1591 /*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
1592  * \note For a description of the opt->flags and opt->args values, see the documentation for
1593  * enum aco_option_type in config_options.h
1594  */
1595 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1596 {
1597  unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
1598  unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
1599  unsigned int flag = opt->args[1];
1600  if (val) {
1601  *flags_field |= flag;
1602  } else {
1603  *flags_field &= ~flag;
1604  }
1605  return 0;
1606 }
1607 
1608 /*! \brief Default handler for ast_sockaddrs
1609  * \note For a description of the opt->flags and opt->args values, see the documentation for
1610  * enum aco_option_type in config_options.h
1611  */
1612 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1613 {
1614  struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
1615  return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
1616 }
1617 
1618 /*! \brief Default handler for doing nothing
1619  */
1620 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1621 {
1622  return 0;
1623 }
1624 
1625 /*! \brief Default handler for character arrays
1626  * \note For a description of the opt->flags and opt->args values, see the documentation for
1627  * enum aco_option_type in config_options.h
1628  */
1629 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1630 {
1631  char *field = (char *)(obj + opt->args[0]);
1632  size_t len = opt->args[1];
1633 
1634  if (opt->flags && ast_strlen_zero(var->value)) {
1635  return -1;
1636  }
1637  ast_copy_string(field, var->value, len);
1638  return 0;
1639 }
Prototypes for public functions only of internal interest,.
Access Control of various sorts.
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
char * text
Definition: app_queue.c:1641
#define var
Definition: ast_expr2f.c:614
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_KEY
Definition: astobj2.h:1151
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
static int tmp()
Definition: bt_open.c:389
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:2312
static const char type[]
Definition: chan_ooh323.c:109
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
int ast_cli_unregister(struct ast_cli_entry *e)
Unregisters a command or an array of commands.
Definition: main/cli.c:2431
#define CLI_SUCCESS
Definition: cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2760
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
short word
#define CONFIG_OPT_BUCKETS
static struct ao2_container * xmldocs
static char * aco_option_type_string[]
Value of the aco_option_type enum as strings.
static void internal_type_destroy(struct aco_type *type)
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
static struct ast_cli_entry cli_aco[]
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.
static int find_option_cb(void *obj, void *arg, int flags)
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for character arrays.
int aco_init(void)
static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for ast_sockaddrs.
static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for stringfields.
static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload)
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)
static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for codec preferences/capabilities.
static int config_opt_hash(const void *obj, const int flags)
static int internal_type_init(struct aco_type *type)
static struct ast_xml_doc_item * find_xmldoc_option(struct ast_xml_doc_item *config_info, struct aco_type **types, const char *name)
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
static int config_opt_cmp(void *obj, void *arg, int flags)
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.
static int timelen_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for timelen signed integers.
static void aco_deinit(void)
static void config_option_destroy(void *obj)
static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for unsigned integers.
static int apply_config(struct aco_info *info)
static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for doubles.
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)
static int link_option_to_types(struct aco_info *info, struct aco_type **types, struct aco_option *opt)
static char * complete_config_option(const char *module, const char *option, const char *word)
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.
static struct aco_type * internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
struct ao2_container * aco_option_container_alloc(void)
Allocate a container to hold config options.
static char * complete_config_module(const char *word)
static void cli_show_modules(struct ast_cli_args *a)
static void internal_file_types_destroy(struct aco_file *file)
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 internal_aco_type_category_check(struct aco_type *match, const char *category)
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
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 int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for ACLs.
static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default handler for doing nothing.
static char * complete_config_type(const char *module, const char *word)
static struct ast_xml_doc_item * find_xmldoc_type(struct ast_xml_doc_item *config_info, const char *name)
static void cli_show_module_types(struct ast_cli_args *a)
static char * cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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.
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)
static struct aco_option * aco_option_find(struct aco_type *type, const char *name)
static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
static struct ast_str * derive_category_text(enum aco_category_op category_match, const char *category)
static void cli_show_module_options(struct ast_cli_args *a)
static int is_preload(struct aco_file *file, const char *cat)
#define XMLDOC_STRICT
static regex_t * build_regex(const char *text)
static void cli_show_module_type(struct ast_cli_args *a)
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.
static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
Default option handler for signed integers.
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.
Configuration option-handling.
int(* aco_option_handler)(const struct aco_option *opt, struct ast_variable *var, void *obj)
A callback function for handling a particular option.
aco_matchtype
What kind of matching should be done on an option name.
@ ACO_PREFIX
@ ACO_EXACT
@ ACO_REGEX
aco_process_status
Return values for the aco_process functions.
@ ACO_PROCESS_UNCHANGED
The config had not been edited and no changes applied.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
@ ACO_PROCESS_OK
The config was processed and applied.
aco_option_type
The option types.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_CODEC_T
Type for default option handler for format capabilities.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_BOOLFLAG_T
Type for default option handler for bools (ast_true/ast_false) that are stored in a flag.
@ OPT_CUSTOM_T
Type for a custom (user-defined) option handler.
@ OPT_CHAR_ARRAY_T
Type for default option handler for character array strings.
@ OPT_ACL_T
Type for default option handler for ACLs.
@ OPT_SOCKADDR_T
Type for default handler for ast_sockaddrs.
@ OPT_YESNO_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_INT_T
Type for default option handler for signed integers.
@ OPT_TIMELEN_T
Type for default option handler for time length signed integers.
@ OPT_DOUBLE_T
Type for default option handler for doubles.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
@ ACO_ITEM
@ ACO_GLOBAL
@ ACO_IGNORE
aco_category_op
@ ACO_WHITELIST_ARRAY
@ ACO_BLACKLIST
@ ACO_WHITELIST_EXACT
@ ACO_WHITELIST
@ ACO_BLACKLIST_ARRAY
@ ACO_BLACKLIST_EXACT
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
long int flag
Definition: f2c.h:83
Format Capabilities API.
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 const char name[]
Definition: format_mp3.c:68
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3327
#define CONFIG_STATUS_FILEMISSING
#define ast_variable_new(name, value, filename)
@ CONFIG_FLAG_FILEUNCHANGED
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
Definition: main/config.c:3726
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:768
@ PARSE_RANGE_DEFAULTS
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
Asterisk internal frame definitions.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
def info(msg)
static int reload(void)
#define NULL
Definition: resample.c:96
const char * ast_string_field
Definition: stringfields.h:190
#define ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data)
Definition: stringfields.h:510
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1117
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: main/utils.c:2097
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
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:2114
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:640
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1091
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:711
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:1281
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:406
#define AS_OR(a, b)
Definition: strings.h:49
The representation of a single configuration file to be processed.
const char * filename
Bits of aco_info that shouldn't be assigned outside this file.
regex_t * name_regex
unsigned int no_doc
const char * name
unsigned char deprecated
const char * aliased_to
const char * default_val
unsigned int flags
intptr_t args[0]
struct aco_type ** obj
enum aco_matchtype match_type
aco_option_handler handler
enum aco_option_type type
struct ao2_container * opts
Type information about a category-level configurable object.
const char * category
const char * name
struct aco_type_internal * internal
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure used to handle boolean flags.
Definition: utils.h:199
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
internal representation of ACL entries In principle user applications would have no need for this,...
Definition: acl.h:51
Socket address structure.
Definition: netsock2.h:97
Support for dynamic strings.
Definition: strings.h:604
Structure for variables, used for configurations and for channel variables.
Struct that contains the XML documentation for a particular item. Note that this is an ao2 ref counte...
Definition: xmldoc.h:56
const ast_string_field ref
Definition: xmldoc.h:74
struct ast_xml_doc_item * next
Definition: xmldoc.h:80
const ast_string_field type
Definition: xmldoc.h:74
const ast_string_field name
Definition: xmldoc.h:74
Definition: ast_expr2.c:325
Handy terminal functions for vt* terms.
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:357
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:235
#define COLOR_MAGENTA
Definition: term.h:60
#define COLOR_BLACK
Definition: term.h:50
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
struct association categories[]
static struct aco_type item
Definition: test_config.c:1463
static struct test_val a
int error(const char *format,...)
Definition: utils/frame.c:999
#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:936
#define ast_assert(a)
Definition: utils.h:734
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ARRAY_LEN(a)
Definition: utils.h:661
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:389
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:135
void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
Free the XPath results.
Definition: xml.c:399
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:263
void ast_xml_set_text(struct ast_xml_node *node, const char *content)
Set an element content string.
Definition: xml.c:341
Asterisk XML Documentation API.
struct ao2_container * ast_xmldoc_build_documentation(const char *type)
Build the documentation for a particular source type.
Definition: xmldoc.c:2655
struct ast_xml_xpath_results * ast_xmldoc_query(const char *fmt,...)
Execute an XPath query on the loaded XML documentation.
Definition: xmldoc.c:2547
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:2606