config_options.c 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462
  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. /*! \file
  19. * \brief Configuration Option-handling
  20. * \author Terry Wilson <twilson@digium.com>
  21. */
  22. /*** MODULEINFO
  23. <support_level>core</support_level>
  24. ***/
  25. #include "asterisk.h"
  26. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  27. #include <regex.h>
  28. #include "asterisk/_private.h"
  29. #include "asterisk/config.h"
  30. #include "asterisk/config_options.h"
  31. #include "asterisk/stringfields.h"
  32. #include "asterisk/acl.h"
  33. #include "asterisk/frame.h"
  34. #include "asterisk/xmldoc.h"
  35. #include "asterisk/cli.h"
  36. #include "asterisk/term.h"
  37. #include "asterisk/format_cap.h"
  38. #ifdef LOW_MEMORY
  39. #define CONFIG_OPT_BUCKETS 5
  40. #else
  41. #define CONFIG_OPT_BUCKETS 53
  42. #endif /* LOW_MEMORY */
  43. /*! \brief Bits of aco_info that shouldn't be assigned outside this file
  44. * \internal
  45. */
  46. struct aco_info_internal {
  47. void *pending; /*!< The user-defined config object awaiting application */
  48. };
  49. struct aco_type_internal {
  50. regex_t *regex;
  51. struct ao2_container *opts; /*!< The container of options registered to the aco_info */
  52. };
  53. struct aco_option {
  54. const char *name;
  55. const char *aliased_to;
  56. const char *default_val;
  57. enum aco_matchtype match_type;
  58. regex_t *name_regex;
  59. struct aco_type **obj;
  60. enum aco_option_type type;
  61. aco_option_handler handler;
  62. unsigned int flags;
  63. unsigned int no_doc:1;
  64. unsigned char deprecated:1;
  65. size_t argc;
  66. intptr_t args[0];
  67. };
  68. #ifdef AST_XML_DOCS
  69. static struct ao2_container *xmldocs;
  70. #endif /* AST_XML_DOCS */
  71. /*! \brief Value of the aco_option_type enum as strings */
  72. static char *aco_option_type_string[] = {
  73. "ACL", /* OPT_ACL_T, */
  74. "Boolean", /* OPT_BOOL_T, */
  75. "Boolean", /* OPT_BOOLFLAG_T, */
  76. "String", /* OPT_CHAR_ARRAY_T, */
  77. "Codec", /* OPT_CODEC_T, */
  78. "Custom", /* OPT_CUSTOM_T, */
  79. "Double", /* OPT_DOUBLE_T, */
  80. "Integer", /* OPT_INT_T, */
  81. "None", /* OPT_NOOP_T, */
  82. "IP Address", /* OPT_SOCKADDR_T, */
  83. "String", /* OPT_STRINGFIELD_T, */
  84. "Unsigned Integer", /* OPT_UINT_T, */
  85. };
  86. void *aco_pending_config(struct aco_info *info)
  87. {
  88. if (!(info && info->internal)) {
  89. ast_log(LOG_ERROR, "This may not be called without an initialized aco_info!\n");
  90. return NULL;
  91. }
  92. return info->internal->pending;
  93. }
  94. static void config_option_destroy(void *obj)
  95. {
  96. struct aco_option *opt = obj;
  97. if (opt->match_type == ACO_REGEX && opt->name_regex) {
  98. regfree(opt->name_regex);
  99. ast_free(opt->name_regex);
  100. }
  101. }
  102. static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  103. static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  104. static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  105. static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  106. static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  107. static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  108. static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  109. static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  110. static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  111. static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  112. static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
  113. #ifdef AST_XML_DOCS
  114. static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches);
  115. 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);
  116. #endif
  117. static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
  118. {
  119. switch(type) {
  120. case OPT_ACL_T: return acl_handler_fn;
  121. case OPT_BOOL_T: return bool_handler_fn;
  122. case OPT_BOOLFLAG_T: return boolflag_handler_fn;
  123. case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
  124. case OPT_CODEC_T: return codec_handler_fn;
  125. case OPT_DOUBLE_T: return double_handler_fn;
  126. case OPT_INT_T: return int_handler_fn;
  127. case OPT_NOOP_T: return noop_handler_fn;
  128. case OPT_SOCKADDR_T: return sockaddr_handler_fn;
  129. case OPT_STRINGFIELD_T: return stringfield_handler_fn;
  130. case OPT_UINT_T: return uint_handler_fn;
  131. case OPT_CUSTOM_T: return NULL;
  132. }
  133. return NULL;
  134. }
  135. static regex_t *build_regex(const char *text)
  136. {
  137. int res;
  138. regex_t *regex;
  139. if (!(regex = ast_malloc(sizeof(*regex)))) {
  140. return NULL;
  141. }
  142. if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
  143. size_t len = regerror(res, regex, NULL, 0);
  144. char buf[len];
  145. regerror(res, regex, buf, len);
  146. ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
  147. ast_free(regex);
  148. return NULL;
  149. }
  150. return regex;
  151. }
  152. static int link_option_to_types(struct aco_info *info, struct aco_type **types, struct aco_option *opt)
  153. {
  154. size_t idx = 0;
  155. struct aco_type *type;
  156. while ((type = types[idx++])) {
  157. if (!type->internal) {
  158. ast_log(LOG_ERROR, "Attempting to register option using uninitialized type\n");
  159. return -1;
  160. }
  161. if (!ao2_link(type->internal->opts, opt)
  162. #ifdef AST_XML_DOCS
  163. || (!info->hidden &&
  164. !opt->no_doc &&
  165. xmldoc_update_config_option(types, info->module, opt->name, type->name, opt->default_val, opt->match_type == ACO_REGEX, opt->type))
  166. #endif /* AST_XML_DOCS */
  167. ) {
  168. do {
  169. ao2_unlink(types[idx - 1]->internal->opts, opt);
  170. } while (--idx);
  171. return -1;
  172. }
  173. }
  174. /* The container(s) should hold the only ref to opt */
  175. ao2_ref(opt, -1);
  176. return 0;
  177. }
  178. int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
  179. {
  180. struct aco_option *opt;
  181. if (!info || ast_strlen_zero(name) || ast_strlen_zero(aliased_to)) {
  182. return -1;
  183. }
  184. if (!(opt = ao2_alloc(sizeof(*opt), config_option_destroy))) {
  185. return -1;
  186. }
  187. opt->name = name;
  188. opt->aliased_to = aliased_to;
  189. opt->deprecated = 1;
  190. opt->match_type = ACO_EXACT;
  191. if (link_option_to_types(info, types, opt)) {
  192. ao2_ref(opt, -1);
  193. return -1;
  194. }
  195. return 0;
  196. }
  197. unsigned int aco_option_get_flags(const struct aco_option *option)
  198. {
  199. return option->flags;
  200. }
  201. intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
  202. {
  203. return option->args[position];
  204. }
  205. #ifdef AST_XML_DOCS
  206. /*! \internal
  207. * \brief Find a particular ast_xml_doc_item from it's parent config_info, types, and name
  208. */
  209. static struct ast_xml_doc_item *find_xmldoc_option(struct ast_xml_doc_item *config_info, struct aco_type **types, const char *name)
  210. {
  211. struct ast_xml_doc_item *iter = config_info;
  212. if (!iter) {
  213. return NULL;
  214. }
  215. /* First is just the configInfo, we can skip it */
  216. while ((iter = AST_LIST_NEXT(iter, next))) {
  217. size_t x;
  218. if (strcasecmp(iter->name, name)) {
  219. continue;
  220. }
  221. for (x = 0; types[x]; x++) {
  222. /* All we care about is that at least one type has the option */
  223. if (!strcasecmp(types[x]->name, iter->ref)) {
  224. return iter;
  225. }
  226. }
  227. }
  228. return NULL;
  229. }
  230. /*! \internal
  231. * \brief Find a particular ast_xml_doc_item from it's parent config_info and name
  232. */
  233. static struct ast_xml_doc_item *find_xmldoc_type(struct ast_xml_doc_item *config_info, const char *name)
  234. {
  235. struct ast_xml_doc_item *iter = config_info;
  236. if (!iter) {
  237. return NULL;
  238. }
  239. /* First is just the config Info, skip it */
  240. while ((iter = AST_LIST_NEXT(iter, next))) {
  241. if (!strcasecmp(iter->type, "configObject") && !strcasecmp(iter->name, name)) {
  242. break;
  243. }
  244. }
  245. return iter;
  246. }
  247. #endif /* AST_XML_DOCS */
  248. int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types,
  249. const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags,
  250. unsigned int no_doc, size_t argc, ...)
  251. {
  252. struct aco_option *opt;
  253. va_list ap;
  254. int tmp;
  255. /* Custom option types require a handler */
  256. if (!handler && kind == OPT_CUSTOM_T) {
  257. return -1;
  258. }
  259. if (!(types && types[0])) {
  260. return -1;
  261. }
  262. if (!(opt = ao2_alloc(sizeof(*opt) + argc * sizeof(opt->args[0]), config_option_destroy))) {
  263. return -1;
  264. }
  265. if (matchtype == ACO_REGEX && !(opt->name_regex = build_regex(name))) {
  266. ao2_ref(opt, -1);
  267. return -1;
  268. }
  269. va_start(ap, argc);
  270. for (tmp = 0; tmp < argc; tmp++) {
  271. opt->args[tmp] = va_arg(ap, size_t);
  272. }
  273. va_end(ap);
  274. opt->name = name;
  275. opt->match_type = matchtype;
  276. opt->default_val = default_val;
  277. opt->type = kind;
  278. opt->handler = handler;
  279. opt->flags = flags;
  280. opt->argc = argc;
  281. opt->no_doc = no_doc;
  282. if (!opt->handler && !(opt->handler = ast_config_option_default_handler(opt->type))) {
  283. /* This should never happen */
  284. ast_log(LOG_ERROR, "No handler provided, and no default handler exists for type %u\n", opt->type);
  285. ao2_ref(opt, -1);
  286. return -1;
  287. };
  288. if (link_option_to_types(info, types, opt)) {
  289. ao2_ref(opt, -1);
  290. return -1;
  291. }
  292. return 0;
  293. }
  294. static int config_opt_hash(const void *obj, const int flags)
  295. {
  296. const struct aco_option *opt = obj;
  297. const char *name = (flags & OBJ_KEY) ? obj : opt->name;
  298. return ast_str_case_hash(name);
  299. }
  300. static int config_opt_cmp(void *obj, void *arg, int flags)
  301. {
  302. struct aco_option *opt1 = obj, *opt2 = arg;
  303. const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
  304. return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
  305. }
  306. static int find_option_cb(void *obj, void *arg, int flags)
  307. {
  308. struct aco_option *match = obj;
  309. const char *name = arg;
  310. switch (match->match_type) {
  311. case ACO_EXACT:
  312. return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
  313. case ACO_REGEX:
  314. return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
  315. }
  316. ast_log(LOG_ERROR, "Unknown match type. This should not be possible.\n");
  317. return CMP_STOP;
  318. }
  319. static struct aco_option *aco_option_find(struct aco_type *type, const char *name)
  320. {
  321. struct aco_option *opt;
  322. if (!type || !type->internal || !type->internal->opts) {
  323. ast_log(LOG_NOTICE, "Attempting to use NULL or unitialized config type\n");
  324. return NULL;
  325. }
  326. /* Try an exact match with OBJ_KEY for the common/fast case, then iterate through
  327. * all options for the regex cases */
  328. if (!(opt = ao2_callback(type->internal->opts, OBJ_KEY, find_option_cb, (void *) name))) {
  329. opt = ao2_callback(type->internal->opts, 0, find_option_cb, (void *) name);
  330. }
  331. return opt;
  332. }
  333. struct ao2_container *aco_option_container_alloc(void)
  334. {
  335. return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
  336. }
  337. static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
  338. {
  339. size_t x;
  340. struct aco_type *match;
  341. const char *val;
  342. for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
  343. /* First make sure we are an object that can service this category */
  344. if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) {
  345. continue;
  346. }
  347. /* Then, see if we need to match a particular field */
  348. if (!ast_strlen_zero(match->matchfield) && (!ast_strlen_zero(match->matchvalue) || match->matchfunc)) {
  349. if (!(val = ast_variable_retrieve(cfg, category, match->matchfield))) {
  350. ast_log(LOG_ERROR, "Required match field '%s' not found\n", match->matchfield);
  351. return NULL;
  352. }
  353. if (match->matchfunc) {
  354. if (!match->matchfunc(val)) {
  355. continue;
  356. }
  357. } else if (strcasecmp(val, match->matchvalue)) {
  358. continue;
  359. }
  360. }
  361. /* If we get this far, we're a match */
  362. break;
  363. }
  364. return match;
  365. }
  366. static int is_preload(struct aco_file *file, const char *cat)
  367. {
  368. int i;
  369. if (!file->preload) {
  370. return 0;
  371. }
  372. for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
  373. if (!strcasecmp(cat, file->preload[i])) {
  374. return 1;
  375. }
  376. }
  377. return 0;
  378. }
  379. static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload) {
  380. RAII_VAR(void *, new_item, NULL, ao2_cleanup);
  381. struct aco_type *type;
  382. /* For global types, field is the global option struct. For non-global, it is the container for items.
  383. * We do not grab a reference to these objects, as the info already holds references to them. This
  384. * pointer is just a convenience. Do not actually store it somewhere. */
  385. void **field;
  386. regex_t *regex_skip;
  387. /* Skip preloaded categories if we aren't preloading */
  388. if (!preload && is_preload(file, cat)) {
  389. return 0;
  390. }
  391. /* Skip the category if we've been told to ignore it */
  392. if (!ast_strlen_zero(file->skip_category)) {
  393. regex_skip = build_regex(file->skip_category);
  394. if (!regexec(regex_skip, cat, 0, NULL, 0)) {
  395. regfree(regex_skip);
  396. ast_free(regex_skip);
  397. return 0;
  398. }
  399. regfree(regex_skip);
  400. ast_free(regex_skip);
  401. }
  402. /* Find aco_type by category, if not found it is an error */
  403. if (!(type = internal_aco_type_find(file, cfg, cat))) {
  404. ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
  405. return -1;
  406. }
  407. field = info->internal->pending + type->item_offset;
  408. if (!*field) {
  409. ast_log(LOG_ERROR, "In %s: %s - No object to update!\n", file->filename, cat);
  410. return -1;
  411. }
  412. if (type->type == ACO_GLOBAL && *field) {
  413. if (aco_process_category_options(type, cfg, cat, *field)) {
  414. ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
  415. return -1;
  416. }
  417. } else if (type->type == ACO_ITEM) {
  418. int new = 0;
  419. /* If we have multiple definitions of a category in a file, or can set the values from multiple
  420. * files, look up the entry if we've already added it so we can merge the values together.
  421. * Otherwise, alloc a new item. */
  422. if (*field) {
  423. if (!(new_item = type->item_find(*field, cat))) {
  424. if (!(new_item = type->item_alloc(cat))) {
  425. ast_log(LOG_ERROR, "In %s: Could not create item for %s\n", file->filename, cat);
  426. return -1;
  427. }
  428. if (aco_set_defaults(type, cat, new_item)) {
  429. ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
  430. return -1;
  431. }
  432. new = 1;
  433. }
  434. }
  435. if (type->item_pre_process && type->item_pre_process(new_item)) {
  436. ast_log(LOG_ERROR, "In %s: Preprocess callback for %s failed\n", file->filename, cat);
  437. return -1;
  438. }
  439. if (aco_process_category_options(type, cfg, cat, new_item)) {
  440. ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
  441. return -1;
  442. }
  443. if (type->item_prelink && type->item_prelink(new_item)) {
  444. ast_log(LOG_ERROR, "In %s: Pre-link callback for %s failed\n", file->filename, cat);
  445. return -1;
  446. }
  447. if (new && !ao2_link(*field, new_item)) {
  448. ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", file->filename, cat);
  449. return -1;
  450. }
  451. }
  452. return 0;
  453. }
  454. static int apply_config(struct aco_info *info)
  455. {
  456. ao2_global_obj_replace_unref(*info->global_obj, info->internal->pending);
  457. return 0;
  458. }
  459. static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
  460. {
  461. const char *cat = NULL;
  462. if (file->preload) {
  463. int i;
  464. for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
  465. if (process_category(cfg, info, file, file->preload[i], 1)) {
  466. return ACO_PROCESS_ERROR;
  467. }
  468. }
  469. }
  470. while ((cat = ast_category_browse(cfg, cat))) {
  471. if (process_category(cfg, info, file, cat, 0)) {
  472. return ACO_PROCESS_ERROR;
  473. }
  474. }
  475. return ACO_PROCESS_OK;
  476. }
  477. enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
  478. {
  479. if (!info->internal) {
  480. ast_log(LOG_ERROR, "Attempt to process %s with uninitialized aco_info\n", file->filename);
  481. goto error;
  482. }
  483. if (!(info->internal->pending = info->snapshot_alloc())) {
  484. ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", file->filename);
  485. goto error;
  486. }
  487. if (internal_process_ast_config(info, file, cfg)) {
  488. goto error;
  489. }
  490. if (info->pre_apply_config && info->pre_apply_config()) {
  491. goto error;
  492. }
  493. if (apply_config(info)) {
  494. goto error;
  495. };
  496. ao2_cleanup(info->internal->pending);
  497. return ACO_PROCESS_OK;
  498. error:
  499. ao2_cleanup(info->internal->pending);
  500. return ACO_PROCESS_ERROR;
  501. }
  502. enum aco_process_status aco_process_config(struct aco_info *info, int reload)
  503. {
  504. struct ast_config *cfg;
  505. struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
  506. int res = ACO_PROCESS_OK;
  507. int file_count = 0;
  508. struct aco_file *file;
  509. if (!info->internal) {
  510. ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
  511. return ACO_PROCESS_ERROR;
  512. }
  513. if (!(info->files[0])) {
  514. ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
  515. return ACO_PROCESS_ERROR;
  516. }
  517. if (!(info->internal->pending = info->snapshot_alloc())) {
  518. ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->module);
  519. return ACO_PROCESS_ERROR;
  520. }
  521. while (res != ACO_PROCESS_ERROR && (file = info->files[file_count++])) {
  522. const char *filename = file->filename;
  523. struct aco_type *match;
  524. int i;
  525. /* set defaults for global objects */
  526. for (i = 0, match = file->types[i]; match; match = file->types[++i]) {
  527. void **field = info->internal->pending + match->item_offset;
  528. if (match->type != ACO_GLOBAL || !*field) {
  529. continue;
  530. }
  531. if (aco_set_defaults(match, match->category, *field)) {
  532. ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, match->category);
  533. res = ACO_PROCESS_ERROR;
  534. break;
  535. }
  536. }
  537. if (res == ACO_PROCESS_ERROR) {
  538. break;
  539. }
  540. try_alias:
  541. cfg = ast_config_load(filename, cfg_flags);
  542. if (!cfg || cfg == CONFIG_STATUS_FILEMISSING) {
  543. if (file->alias && strcmp(file->alias, filename)) {
  544. filename = file->alias;
  545. goto try_alias;
  546. }
  547. ast_log(LOG_ERROR, "Unable to load config file '%s'\n", file->filename);
  548. res = ACO_PROCESS_ERROR;
  549. break;
  550. } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
  551. ast_debug(1, "%s was unchanged\n", file->filename);
  552. res = ACO_PROCESS_UNCHANGED;
  553. continue;
  554. } else if (cfg == CONFIG_STATUS_FILEINVALID) {
  555. ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n",
  556. file->filename);
  557. res = ACO_PROCESS_ERROR;
  558. break;
  559. }
  560. /* A file got loaded. */
  561. if (reload) {
  562. /* Must do any subsequent file loads unconditionally. */
  563. reload = 0;
  564. ast_clear_flag(&cfg_flags, CONFIG_FLAG_FILEUNCHANGED);
  565. if (file_count != 1) {
  566. /*
  567. * Must restart loading to load all config files since a file
  568. * after the first one changed.
  569. */
  570. file_count = 0;
  571. } else {
  572. res = internal_process_ast_config(info, file, cfg);
  573. }
  574. } else {
  575. res = internal_process_ast_config(info, file, cfg);
  576. }
  577. ast_config_destroy(cfg);
  578. }
  579. if (res != ACO_PROCESS_OK) {
  580. goto end;
  581. }
  582. if (info->pre_apply_config && info->pre_apply_config()) {
  583. res = ACO_PROCESS_ERROR;
  584. goto end;
  585. }
  586. if (apply_config(info)) {
  587. res = ACO_PROCESS_ERROR;
  588. goto end;
  589. }
  590. if (info->post_apply_config) {
  591. info->post_apply_config();
  592. }
  593. end:
  594. ao2_cleanup(info->internal->pending);
  595. return res;
  596. }
  597. int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
  598. {
  599. RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup);
  600. if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) {
  601. const char *alias = ast_strdupa(opt->aliased_to);
  602. ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias);
  603. ao2_ref(opt, -1);
  604. opt = aco_option_find(type, alias);
  605. }
  606. if (!opt) {
  607. 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);
  608. return -1;
  609. }
  610. if (!opt->handler) {
  611. /* It should be impossible for an option to not have a handler */
  612. ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name);
  613. return -1;
  614. }
  615. if (opt->handler(opt, var, obj)) {
  616. ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file);
  617. return -1;
  618. }
  619. return 0;
  620. }
  621. int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
  622. {
  623. struct ast_variable *var;
  624. for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
  625. if (aco_process_var(type, cat, var, obj)) {
  626. return -1;
  627. }
  628. }
  629. return 0;
  630. }
  631. static void internal_type_destroy(struct aco_type *type)
  632. {
  633. /* If we've already had all our internal data cleared out,
  634. * then there's no need to proceed further
  635. */
  636. if (!type->internal) {
  637. return;
  638. }
  639. if (type->internal->regex) {
  640. regfree(type->internal->regex);
  641. ast_free(type->internal->regex);
  642. }
  643. ao2_cleanup(type->internal->opts);
  644. type->internal->opts = NULL;
  645. ast_free(type->internal);
  646. type->internal = NULL;
  647. }
  648. static void internal_file_types_destroy(struct aco_file *file)
  649. {
  650. size_t x;
  651. struct aco_type *t;
  652. for (x = 0, t = file->types[x]; t; t = file->types[++x]) {
  653. internal_type_destroy(t);
  654. t = NULL;
  655. }
  656. }
  657. static int internal_type_init(struct aco_type *type)
  658. {
  659. if (!(type->internal = ast_calloc(1, sizeof(*type->internal)))) {
  660. return -1;
  661. }
  662. if (!(type->internal->regex = build_regex(type->category))) {
  663. internal_type_destroy(type);
  664. return -1;
  665. }
  666. if (!(type->internal->opts = aco_option_container_alloc())) {
  667. internal_type_destroy(type);
  668. return -1;
  669. }
  670. return 0;
  671. }
  672. int aco_info_init(struct aco_info *info)
  673. {
  674. size_t x = 0, y = 0;
  675. struct aco_file *file;
  676. struct aco_type *type;
  677. if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
  678. return -1;
  679. }
  680. while ((file = info->files[x++])) {
  681. while ((type = file->types[y++])) {
  682. if (internal_type_init(type)) {
  683. goto error;
  684. }
  685. #ifdef AST_XML_DOCS
  686. if (!info->hidden &&
  687. !type->hidden &&
  688. xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match == ACO_WHITELIST)) {
  689. goto error;
  690. }
  691. #endif /* AST_XML_DOCS */
  692. }
  693. y = 0;
  694. }
  695. return 0;
  696. error:
  697. aco_info_destroy(info);
  698. return -1;
  699. }
  700. void aco_info_destroy(struct aco_info *info)
  701. {
  702. int x;
  703. /* It shouldn't be possible for internal->pending to be in use when this is called because
  704. * of the locks in loader.c around reloads and unloads and the fact that internal->pending
  705. * only exists while those locks are held */
  706. ast_free(info->internal);
  707. info->internal = NULL;
  708. for (x = 0; info->files[x]; x++) {
  709. internal_file_types_destroy(info->files[x]);
  710. }
  711. }
  712. int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
  713. {
  714. struct aco_option *opt;
  715. struct ao2_iterator iter;
  716. iter = ao2_iterator_init(type->internal->opts, 0);
  717. while ((opt = ao2_iterator_next(&iter))) {
  718. RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy);
  719. if (ast_strlen_zero(opt->default_val)) {
  720. ao2_ref(opt, -1);
  721. continue;
  722. }
  723. if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
  724. ao2_ref(opt, -1);
  725. ao2_iterator_destroy(&iter);
  726. return -1;
  727. }
  728. if (opt->handler(opt, var, obj)) {
  729. ast_log(LOG_ERROR, "Unable to set default for %s, %s=%s\n", category, var->name, var->value);
  730. ao2_ref(opt, -1);
  731. ao2_iterator_destroy(&iter);
  732. return -1;
  733. }
  734. ao2_ref(opt, -1);
  735. }
  736. ao2_iterator_destroy(&iter);
  737. return 0;
  738. }
  739. #ifdef AST_XML_DOCS
  740. /*! \internal
  741. * \brief Complete the name of the module the user is looking for
  742. */
  743. static char *complete_config_module(const char *word, int pos, int state)
  744. {
  745. char *c = NULL;
  746. size_t wordlen = strlen(word);
  747. int which = 0;
  748. struct ao2_iterator i;
  749. struct ast_xml_doc_item *cur;
  750. if (pos != 3) {
  751. return NULL;
  752. }
  753. i = ao2_iterator_init(xmldocs, 0);
  754. while ((cur = ao2_iterator_next(&i))) {
  755. if (!strncasecmp(word, cur->name, wordlen) && ++which > state) {
  756. c = ast_strdup(cur->name);
  757. ao2_ref(cur, -1);
  758. break;
  759. }
  760. ao2_ref(cur, -1);
  761. }
  762. ao2_iterator_destroy(&i);
  763. return c;
  764. }
  765. /*! \internal
  766. * \brief Complete the name of the configuration type the user is looking for
  767. */
  768. static char *complete_config_type(const char *module, const char *word, int pos, int state)
  769. {
  770. char *c = NULL;
  771. size_t wordlen = strlen(word);
  772. int which = 0;
  773. RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
  774. struct ast_xml_doc_item *cur;
  775. if (pos != 4) {
  776. return NULL;
  777. }
  778. if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
  779. return NULL;
  780. }
  781. cur = info;
  782. while ((cur = AST_LIST_NEXT(cur, next))) {
  783. if (!strcasecmp(cur->type, "configObject") && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
  784. c = ast_strdup(cur->name);
  785. break;
  786. }
  787. }
  788. return c;
  789. }
  790. /*! \internal
  791. * \brief Complete the name of the configuration option the user is looking for
  792. */
  793. static char *complete_config_option(const char *module, const char *option, const char *word, int pos, int state)
  794. {
  795. char *c = NULL;
  796. size_t wordlen = strlen(word);
  797. int which = 0;
  798. RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
  799. struct ast_xml_doc_item *cur;
  800. if (pos != 5) {
  801. return NULL;
  802. }
  803. if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
  804. return NULL;
  805. }
  806. cur = info;
  807. while ((cur = AST_LIST_NEXT(cur, next))) {
  808. if (!strcasecmp(cur->type, "configOption") && !strcasecmp(cur->ref, option) && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
  809. c = ast_strdup(cur->name);
  810. break;
  811. }
  812. }
  813. return c;
  814. }
  815. /* Define as 0 if we want to allow configurations to be registered without
  816. * documentation
  817. */
  818. #define XMLDOC_STRICT 1
  819. /*! \internal
  820. * \brief Update the XML documentation for a config type based on its registration
  821. */
  822. static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches)
  823. {
  824. RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
  825. RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
  826. struct ast_xml_doc_item *config_type;
  827. struct ast_xml_node *type, *syntax, *matchinfo, *tmp;
  828. /* If we already have a syntax element, bail. This isn't an error, since we may unload a module which
  829. * has updated the docs and then load it again. */
  830. if ((results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/syntax", module, name))) {
  831. return 0;
  832. }
  833. if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']", module, name))) {
  834. ast_log(LOG_WARNING, "Cannot update type '%s' in module '%s' because it has no existing documentation!\n", name, module);
  835. return XMLDOC_STRICT ? -1 : 0;
  836. }
  837. if (!(type = ast_xml_xpath_get_first_result(results))) {
  838. ast_log(LOG_WARNING, "Could not retrieve documentation for type '%s' in module '%s'\n", name, module);
  839. return XMLDOC_STRICT ? -1 : 0;
  840. }
  841. if (!(syntax = ast_xml_new_child(type, "syntax"))) {
  842. ast_log(LOG_WARNING, "Could not create syntax node for type '%s' in module '%s'\n", name, module);
  843. return XMLDOC_STRICT ? -1 : 0;
  844. }
  845. if (!(matchinfo = ast_xml_new_child(syntax, "matchInfo"))) {
  846. ast_log(LOG_WARNING, "Could not create matchInfo node for type '%s' in module '%s'\n", name, module);
  847. return XMLDOC_STRICT ? -1 : 0;
  848. }
  849. if (!(tmp = ast_xml_new_child(matchinfo, "category"))) {
  850. ast_log(LOG_WARNING, "Could not create category node for type '%s' in module '%s'\n", name, module);
  851. return XMLDOC_STRICT ? -1 : 0;
  852. }
  853. ast_xml_set_text(tmp, category);
  854. ast_xml_set_attribute(tmp, "match", matches ? "true" : "false");
  855. if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) {
  856. ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
  857. return XMLDOC_STRICT ? -1 : 0;
  858. }
  859. ast_xml_set_attribute(tmp, "name", matchfield);
  860. ast_xml_set_text(tmp, matchvalue);
  861. if (!config_info || !(config_type = find_xmldoc_type(config_info, name))) {
  862. ast_log(LOG_WARNING, "Could not obtain XML documentation item for config type %s\n", name);
  863. return XMLDOC_STRICT ? -1 : 0;
  864. }
  865. if (ast_xmldoc_regenerate_doc_item(config_type)) {
  866. ast_log(LOG_WARNING, "Could not update type '%s' with values from config type registration\n", name);
  867. return XMLDOC_STRICT ? -1 : 0;
  868. }
  869. return 0;
  870. }
  871. /*! \internal
  872. * \brief Update the XML documentation for a config option based on its registration
  873. */
  874. 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)
  875. {
  876. RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
  877. RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
  878. struct ast_xml_doc_item * config_option;
  879. struct ast_xml_node *option;
  880. ast_assert(ARRAY_LEN(aco_option_type_string) > type);
  881. if (!config_info || !(config_option = find_xmldoc_option(config_info, types, name))) {
  882. ast_log(LOG_ERROR, "XML Documentation for option '%s' in modules '%s' not found!\n", name, module);
  883. return XMLDOC_STRICT ? -1 : 0;
  884. }
  885. if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/configOption[@name='%s']", module, object_name, name))) {
  886. ast_log(LOG_WARNING, "Could not find option '%s' with type '%s' in module '%s'\n", name, object_name, module);
  887. return XMLDOC_STRICT ? -1 : 0;
  888. }
  889. if (!(option = ast_xml_xpath_get_first_result(results))) {
  890. ast_log(LOG_WARNING, "Could obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module);
  891. return XMLDOC_STRICT ? -1 : 0;
  892. }
  893. ast_xml_set_attribute(option, "regex", regex ? "true" : "false");
  894. ast_xml_set_attribute(option, "default", default_value);
  895. ast_xml_set_attribute(option, "type", aco_option_type_string[type]);
  896. if (ast_xmldoc_regenerate_doc_item(config_option)) {
  897. ast_log(LOG_WARNING, "Could not update option '%s' with values from config option registration\n", name);
  898. return XMLDOC_STRICT ? -1 : 0;
  899. }
  900. return 0;
  901. }
  902. /*! \internal
  903. * \brief Show the modules with configuration information
  904. */
  905. static void cli_show_modules(struct ast_cli_args *a)
  906. {
  907. struct ast_xml_doc_item *item;
  908. struct ao2_iterator it_items;
  909. ast_assert(a->argc == 3);
  910. if (ao2_container_count(xmldocs) == 0) {
  911. ast_cli(a->fd, "No modules found.\n");
  912. return;
  913. }
  914. it_items = ao2_iterator_init(xmldocs, 0);
  915. ast_cli(a->fd, "The following modules have configuration information:\n");
  916. while ((item = ao2_iterator_next(&it_items))) {
  917. ast_cli(a->fd, "\t%s\n", item->name);
  918. ao2_ref(item, -1);
  919. }
  920. ao2_iterator_destroy(&it_items);
  921. }
  922. /*! \internal
  923. * \brief Show the configuration types for a module
  924. */
  925. static void cli_show_module_types(struct ast_cli_args *a)
  926. {
  927. RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
  928. struct ast_xml_doc_item *tmp;
  929. ast_assert(a->argc == 4);
  930. if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
  931. ast_cli(a->fd, "Module %s not found.\n", a->argv[3]);
  932. return;
  933. }
  934. if (ast_str_strlen(item->synopsis)) {
  935. ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->synopsis), 1));
  936. }
  937. if (ast_str_strlen(item->description)) {
  938. ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->description), 1));
  939. }
  940. tmp = item;
  941. ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
  942. while ((tmp = AST_LIST_NEXT(tmp, next))) {
  943. if (!strcasecmp(tmp->type, "configObject")) {
  944. ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
  945. ast_str_buffer(tmp->synopsis));
  946. }
  947. }
  948. }
  949. /*! \internal
  950. * \brief Show the information for a configuration type
  951. */
  952. static void cli_show_module_type(struct ast_cli_args *a)
  953. {
  954. RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
  955. struct ast_xml_doc_item *tmp;
  956. char option_type[64];
  957. int match = 0;
  958. ast_assert(a->argc == 5);
  959. if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
  960. ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
  961. return;
  962. }
  963. tmp = item;
  964. while ((tmp = AST_LIST_NEXT(tmp, next))) {
  965. if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
  966. match = 1;
  967. term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
  968. ast_cli(a->fd, "%s", option_type);
  969. if (ast_str_strlen(tmp->syntax)) {
  970. ast_cli(a->fd, ": [%s]\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
  971. } else {
  972. ast_cli(a->fd, "\n\n");
  973. }
  974. if (ast_str_strlen(tmp->synopsis)) {
  975. ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->synopsis), 1));
  976. }
  977. if (ast_str_strlen(tmp->description)) {
  978. ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
  979. }
  980. }
  981. }
  982. if (!match) {
  983. ast_cli(a->fd, "Unknown configuration type %s\n", a->argv[4]);
  984. return;
  985. }
  986. /* Now iterate over the options for the type */
  987. tmp = item;
  988. while ((tmp = AST_LIST_NEXT(tmp, next))) {
  989. if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
  990. ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
  991. ast_str_buffer(tmp->synopsis));
  992. }
  993. }
  994. }
  995. /*! \internal
  996. * \brief Show detailed information for an option
  997. */
  998. static void cli_show_module_options(struct ast_cli_args *a)
  999. {
  1000. RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
  1001. struct ast_xml_doc_item *tmp;
  1002. char option_name[64];
  1003. int match = 0;
  1004. ast_assert(a->argc == 6);
  1005. if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
  1006. ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
  1007. return;
  1008. }
  1009. tmp = item;
  1010. while ((tmp = AST_LIST_NEXT(tmp, next))) {
  1011. if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
  1012. if (match) {
  1013. ast_cli(a->fd, "\n");
  1014. }
  1015. term_color(option_name, tmp->ref, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_name));
  1016. ast_cli(a->fd, "[%s%s]\n", option_name, ast_term_reset());
  1017. if (ast_str_strlen(tmp->syntax)) {
  1018. ast_cli(a->fd, "%s\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
  1019. }
  1020. ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(AS_OR(tmp->synopsis, "No information available"), 1));
  1021. if (ast_str_strlen(tmp->description)) {
  1022. ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
  1023. }
  1024. if (ast_str_strlen(tmp->seealso)) {
  1025. ast_cli(a->fd, "See Also:\n");
  1026. ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->seealso), 1));
  1027. }
  1028. match = 1;
  1029. }
  1030. }
  1031. if (!match) {
  1032. ast_cli(a->fd, "No option %s found for %s:%s\n", a->argv[5], a->argv[3], a->argv[4]);
  1033. }
  1034. }
  1035. static char *cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  1036. {
  1037. switch (cmd) {
  1038. case CLI_INIT:
  1039. e->command = "config show help";
  1040. e->usage =
  1041. "Usage: config show help [<module> [<type> [<option>]]]\n"
  1042. " Display detailed information about module configuration.\n"
  1043. " * If nothing is specified, the modules that have\n"
  1044. " configuration information are listed.\n"
  1045. " * If <module> is specified, the configuration types\n"
  1046. " for that module will be listed, along with brief\n"
  1047. " information about that type.\n"
  1048. " * If <module> and <type> are specified, detailed\n"
  1049. " information about the type is displayed, as well\n"
  1050. " as the available options.\n"
  1051. " * If <module>, <type>, and <option> are specified,\n"
  1052. " detailed information will be displayed about that\n"
  1053. " option.\n"
  1054. " NOTE: the help documentation is partially generated at run\n"
  1055. " time when a module is loaded. If a module is not loaded,\n"
  1056. " configuration help for that module may be incomplete.\n";
  1057. return NULL;
  1058. case CLI_GENERATE:
  1059. switch(a->pos) {
  1060. case 3: return complete_config_module(a->word, a->pos, a->n);
  1061. case 4: return complete_config_type(a->argv[3], a->word, a->pos, a->n);
  1062. case 5: return complete_config_option(a->argv[3], a->argv[4], a->word, a->pos, a->n);
  1063. default: return NULL;
  1064. }
  1065. }
  1066. switch (a->argc) {
  1067. case 3:
  1068. cli_show_modules(a);
  1069. break;
  1070. case 4:
  1071. cli_show_module_types(a);
  1072. break;
  1073. case 5:
  1074. cli_show_module_type(a);
  1075. break;
  1076. case 6:
  1077. cli_show_module_options(a);
  1078. break;
  1079. default:
  1080. return CLI_SHOWUSAGE;
  1081. }
  1082. return CLI_SUCCESS;
  1083. }
  1084. static struct ast_cli_entry cli_aco[] = {
  1085. AST_CLI_DEFINE(cli_show_help, "Show configuration help for a module"),
  1086. };
  1087. static void aco_deinit(void)
  1088. {
  1089. ast_cli_unregister(cli_aco);
  1090. ao2_cleanup(xmldocs);
  1091. }
  1092. #endif /* AST_XML_DOCS */
  1093. int aco_init(void)
  1094. {
  1095. #ifdef AST_XML_DOCS
  1096. ast_register_cleanup(aco_deinit);
  1097. if (!(xmldocs = ast_xmldoc_build_documentation("configInfo"))) {
  1098. ast_log(LOG_ERROR, "Couldn't build config documentation\n");
  1099. return -1;
  1100. }
  1101. ast_cli_register_multiple(cli_aco, ARRAY_LEN(cli_aco));
  1102. #endif /* AST_XML_DOCS */
  1103. return 0;
  1104. }
  1105. /* Default config option handlers */
  1106. /*! \brief Default option handler for signed integers
  1107. * \note For a description of the opt->flags and opt->args values, see the documentation for
  1108. * enum aco_option_type in config_options.h
  1109. */
  1110. static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
  1111. int *field = (int *)(obj + opt->args[0]);
  1112. unsigned int flags = PARSE_INT32 | opt->flags;
  1113. int res = 0;
  1114. if (opt->flags & PARSE_IN_RANGE) {
  1115. res = opt->flags & PARSE_DEFAULT ?
  1116. ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
  1117. ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
  1118. if (res) {
  1119. if (opt->flags & PARSE_RANGE_DEFAULTS) {
  1120. 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]);
  1121. res = 0;
  1122. } else if (opt->flags & PARSE_DEFAULT) {
  1123. ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
  1124. res = 0;
  1125. }
  1126. }
  1127. } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
  1128. ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
  1129. } else {
  1130. res = ast_parse_arg(var->value, flags, field);
  1131. }
  1132. return res;
  1133. }
  1134. /*! \brief Default option handler for unsigned integers
  1135. * \note For a description of the opt->flags and opt->args values, see the documentation for
  1136. * enum aco_option_type in config_options.h
  1137. */
  1138. static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
  1139. unsigned int *field = (unsigned int *)(obj + opt->args[0]);
  1140. unsigned int flags = PARSE_INT32 | opt->flags;
  1141. int res = 0;
  1142. if (opt->flags & PARSE_IN_RANGE) {
  1143. res = opt->flags & PARSE_DEFAULT ?
  1144. ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
  1145. ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
  1146. if (res) {
  1147. if (opt->flags & PARSE_RANGE_DEFAULTS) {
  1148. 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]);
  1149. res = 0;
  1150. } else if (opt->flags & PARSE_DEFAULT) {
  1151. ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %u instead.\n", var->name, var->value, *field);
  1152. res = 0;
  1153. }
  1154. }
  1155. } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
  1156. ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
  1157. } else {
  1158. res = ast_parse_arg(var->value, flags, field);
  1159. }
  1160. return res;
  1161. }
  1162. /*! \brief Default option handler for doubles
  1163. * \note For a description of the opt->flags and opt->args values, see the documentation for
  1164. * enum aco_option_type in config_options.h
  1165. */
  1166. static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
  1167. double *field = (double *)(obj + opt->args[0]);
  1168. return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
  1169. }
  1170. /*! \brief Default handler for ACLs
  1171. * \note For a description of the opt->flags and opt->args values, see the documentation for
  1172. * enum aco_option_type in config_options.h
  1173. */
  1174. static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
  1175. struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
  1176. int error = 0;
  1177. *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
  1178. return error;
  1179. }
  1180. /*! \brief Default option handler for codec preferences/capabilities
  1181. * \note For a description of the opt->flags and opt->args values, see the documentation for
  1182. * enum aco_option_type in config_options.h
  1183. */
  1184. static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
  1185. struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[0]);
  1186. return ast_format_cap_update_by_allow_disallow(*cap, var->value, opt->flags);
  1187. }
  1188. /*! \brief Default option handler for stringfields
  1189. * \note For a description of the opt->flags and opt->args values, see the documentation for
  1190. * enum aco_option_type in config_options.h
  1191. */
  1192. static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
  1193. {
  1194. ast_string_field *field = (const char **)(obj + opt->args[0]);
  1195. struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
  1196. struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
  1197. if (opt->flags && ast_strlen_zero(var->value)) {
  1198. return -1;
  1199. }
  1200. ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
  1201. return 0;
  1202. }
  1203. /*! \brief Default option handler for bools (ast_true/ast_false)
  1204. * \note For a description of the opt->flags and opt->args values, see the documentation for
  1205. * enum aco_option_type in config_options.h
  1206. */
  1207. static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
  1208. {
  1209. unsigned int *field = (unsigned int *)(obj + opt->args[0]);
  1210. *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
  1211. return 0;
  1212. }
  1213. /*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
  1214. * \note For a description of the opt->flags and opt->args values, see the documentation for
  1215. * enum aco_option_type in config_options.h
  1216. */
  1217. static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
  1218. {
  1219. unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
  1220. unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
  1221. unsigned int flag = opt->args[1];
  1222. if (val) {
  1223. *flags_field |= flag;
  1224. } else {
  1225. *flags_field &= ~flag;
  1226. }
  1227. return 0;
  1228. }
  1229. /*! \brief Default handler for ast_sockaddrs
  1230. * \note For a description of the opt->flags and opt->args values, see the documentation for
  1231. * enum aco_option_type in config_options.h
  1232. */
  1233. static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
  1234. {
  1235. struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
  1236. return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
  1237. }
  1238. /*! \brief Default handler for doing nothing
  1239. */
  1240. static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
  1241. {
  1242. return 0;
  1243. }
  1244. /*! \brief Default handler for character arrays
  1245. * \note For a description of the opt->flags and opt->args values, see the documentation for
  1246. * enum aco_option_type in config_options.h
  1247. */
  1248. static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
  1249. {
  1250. char *field = (char *)(obj + opt->args[0]);
  1251. size_t len = opt->args[1];
  1252. if (opt->flags && ast_strlen_zero(var->value)) {
  1253. return -1;
  1254. }
  1255. ast_copy_string(field, var->value, len);
  1256. return 0;
  1257. }