func_config.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2008, Digium, Inc.
  5. *
  6. * Russell Bryant <russell@digium.com>
  7. * Tilghman Lesher <func_config__200803@the-tilghman.com>
  8. *
  9. * See http://www.asterisk.org for more information about
  10. * the Asterisk project. Please do not directly contact
  11. * any of the maintainers of this project for assistance;
  12. * the project provides a web site, mailing lists and IRC
  13. * channels for your use.
  14. *
  15. * This program is free software, distributed under the terms of
  16. * the GNU General Public License Version 2. See the LICENSE file
  17. * at the top of the source tree.
  18. */
  19. /*! \file
  20. *
  21. * \brief A function to retrieve variables from an Asterisk configuration file
  22. *
  23. * \author Russell Bryant <russell@digium.com>
  24. * \author Tilghman Lesher <func_config__200803@the-tilghman.com>
  25. *
  26. * \ingroup functions
  27. */
  28. /*** MODULEINFO
  29. <support_level>core</support_level>
  30. ***/
  31. #include "asterisk.h"
  32. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  33. #include "asterisk/module.h"
  34. #include "asterisk/channel.h"
  35. #include "asterisk/pbx.h"
  36. #include "asterisk/app.h"
  37. /*** DOCUMENTATION
  38. <function name="AST_CONFIG" language="en_US">
  39. <synopsis>
  40. Retrieve a variable from a configuration file.
  41. </synopsis>
  42. <syntax>
  43. <parameter name="config_file" required="true" />
  44. <parameter name="category" required="true" />
  45. <parameter name="variable_name" required="true" />
  46. </syntax>
  47. <description>
  48. <para>This function reads a variable from an Asterisk configuration file.</para>
  49. </description>
  50. </function>
  51. ***/
  52. struct config_item {
  53. AST_RWLIST_ENTRY(config_item) entry;
  54. struct ast_config *cfg;
  55. char filename[0];
  56. };
  57. static AST_RWLIST_HEAD_STATIC(configs, config_item);
  58. static int config_function_read(struct ast_channel *chan, const char *cmd, char *data,
  59. char *buf, size_t len)
  60. {
  61. struct ast_config *cfg;
  62. struct ast_flags cfg_flags = { CONFIG_FLAG_FILEUNCHANGED };
  63. const char *val;
  64. char *parse;
  65. struct config_item *cur;
  66. AST_DECLARE_APP_ARGS(args,
  67. AST_APP_ARG(filename);
  68. AST_APP_ARG(category);
  69. AST_APP_ARG(variable);
  70. AST_APP_ARG(index);
  71. );
  72. if (ast_strlen_zero(data)) {
  73. ast_log(LOG_ERROR, "AST_CONFIG() requires an argument\n");
  74. return -1;
  75. }
  76. parse = ast_strdupa(data);
  77. AST_STANDARD_APP_ARGS(args, parse);
  78. if (ast_strlen_zero(args.filename)) {
  79. ast_log(LOG_ERROR, "AST_CONFIG() requires a filename\n");
  80. return -1;
  81. }
  82. if (ast_strlen_zero(args.category)) {
  83. ast_log(LOG_ERROR, "AST_CONFIG() requires a category\n");
  84. return -1;
  85. }
  86. if (ast_strlen_zero(args.variable)) {
  87. ast_log(LOG_ERROR, "AST_CONFIG() requires a variable\n");
  88. return -1;
  89. }
  90. if (!(cfg = ast_config_load(args.filename, cfg_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
  91. return -1;
  92. }
  93. if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
  94. /* Retrieve cfg from list */
  95. AST_RWLIST_RDLOCK(&configs);
  96. AST_RWLIST_TRAVERSE(&configs, cur, entry) {
  97. if (!strcmp(cur->filename, args.filename)) {
  98. break;
  99. }
  100. }
  101. if (!cur) {
  102. /* At worst, we might leak an entry while upgrading locks */
  103. AST_RWLIST_UNLOCK(&configs);
  104. AST_RWLIST_WRLOCK(&configs);
  105. if (!(cur = ast_calloc(1, sizeof(*cur) + strlen(args.filename) + 1))) {
  106. AST_RWLIST_UNLOCK(&configs);
  107. return -1;
  108. }
  109. strcpy(cur->filename, args.filename);
  110. ast_clear_flag(&cfg_flags, CONFIG_FLAG_FILEUNCHANGED);
  111. if (!(cfg = ast_config_load(args.filename, cfg_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
  112. ast_free(cur);
  113. AST_RWLIST_UNLOCK(&configs);
  114. return -1;
  115. }
  116. cur->cfg = cfg;
  117. AST_RWLIST_INSERT_TAIL(&configs, cur, entry);
  118. }
  119. cfg = cur->cfg;
  120. } else {
  121. /* Replace cfg in list */
  122. AST_RWLIST_WRLOCK(&configs);
  123. AST_RWLIST_TRAVERSE(&configs, cur, entry) {
  124. if (!strcmp(cur->filename, args.filename)) {
  125. break;
  126. }
  127. }
  128. if (!cur) {
  129. if (!(cur = ast_calloc(1, sizeof(*cur) + strlen(args.filename) + 1))) {
  130. AST_RWLIST_UNLOCK(&configs);
  131. return -1;
  132. }
  133. strcpy(cur->filename, args.filename);
  134. cur->cfg = cfg;
  135. AST_RWLIST_INSERT_TAIL(&configs, cur, entry);
  136. } else {
  137. ast_config_destroy(cur->cfg);
  138. cur->cfg = cfg;
  139. }
  140. }
  141. if (!(val = ast_variable_retrieve(cfg, args.category, args.variable))) {
  142. ast_debug(1, "'%s' not found in [%s] of '%s'\n", args.variable,
  143. args.category, args.filename);
  144. AST_RWLIST_UNLOCK(&configs);
  145. return -1;
  146. }
  147. ast_copy_string(buf, val, len);
  148. /* Unlock down here, so there's no chance the struct goes away while we're using it. */
  149. AST_RWLIST_UNLOCK(&configs);
  150. return 0;
  151. }
  152. static struct ast_custom_function config_function = {
  153. .name = "AST_CONFIG",
  154. .read = config_function_read,
  155. };
  156. static int unload_module(void)
  157. {
  158. struct config_item *current;
  159. int res = ast_custom_function_unregister(&config_function);
  160. AST_RWLIST_WRLOCK(&configs);
  161. while ((current = AST_RWLIST_REMOVE_HEAD(&configs, entry))) {
  162. ast_config_destroy(current->cfg);
  163. ast_free(current);
  164. }
  165. AST_RWLIST_UNLOCK(&configs);
  166. return res;
  167. }
  168. static int load_module(void)
  169. {
  170. return ast_custom_function_register(&config_function);
  171. }
  172. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Asterisk configuration file variable access");