config_options.c 47 KB

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