2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
21 * \brief Configuration File Parser
23 * \author Mark Spencer <markster@digium.com>
25 * Includes the Asterisk Realtime API - ARA
26 * See doc/realtime.txt and doc/extconfig.txt
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33 #include "asterisk/paths.h" /* use ast_config_AST_CONFIG_DIR */
34 #include "asterisk/network.h" /* we do some sockaddr manipulation here */
38 #include <math.h> /* HUGE_VAL */
40 #define AST_INCLUDE_GLOB 1
42 #ifdef AST_INCLUDE_GLOB
43 /* glob compat stuff - eventually this should go in compat.h or some
44 * header in include/asterisk/
46 #if defined(__Darwin__) || defined(__CYGWIN__)
47 #define GLOB_ABORTED GLOB_ABEND
53 #define MY_GLOB_FLAGS GLOB_NOCHECK
55 #define MY_GLOB_FLAGS (GLOB_NOMAGIC|GLOB_BRACE)
60 #include "asterisk/config.h"
61 #include "asterisk/cli.h"
62 #include "asterisk/lock.h"
63 #include "asterisk/utils.h"
64 #include "asterisk/channel.h"
65 #include "asterisk/app.h"
66 #include "asterisk/astobj2.h"
67 #include "asterisk/strings.h" /* for the ast_str_*() API */
69 #define MAX_NESTED_COMMENTS 128
70 #define COMMENT_START ";--"
71 #define COMMENT_END "--;"
72 #define COMMENT_META ';'
73 #define COMMENT_TAG '-'
75 static char *extconfig_conf = "extconfig.conf";
78 /*! \brief Structure to keep comments for rewriting configuration files */
80 struct ast_comment *next;
84 /*! \brief Hold the mtime for config files, so if we don't need to reread our config, don't. */
85 struct cache_file_include {
86 AST_LIST_ENTRY(cache_file_include) list;
90 struct cache_file_mtime {
91 AST_LIST_ENTRY(cache_file_mtime) list;
92 AST_LIST_HEAD(includes, cache_file_include) includes;
93 unsigned int has_exec:1;
99 static AST_LIST_HEAD_STATIC(cfmtime_head, cache_file_mtime);
102 /* comment buffers are better implemented using the ast_str_*() API */
103 #define CB_SIZE 250 /* initial size of comment buffers */
105 static void CB_ADD(struct ast_str **cb, const char *str)
107 ast_str_append(cb, 0, "%s", str);
110 static void CB_ADD_LEN(struct ast_str **cb, const char *str, int len)
112 char *s = alloca(len + 1);
113 ast_copy_string(s, str, len);
114 ast_str_append(cb, 0, "%s", str);
117 static void CB_RESET(struct ast_str *cb, struct ast_str *llb)
125 static struct ast_comment *ALLOC_COMMENT(const struct ast_str *buffer)
127 struct ast_comment *x = NULL;
128 if (buffer && buffer->used)
129 x = ast_calloc(1, sizeof(*x) + buffer->used + 1);
131 strcpy(x->cmt, buffer->str);
135 /* I need to keep track of each config file, and all its inclusions,
136 so that we can track blank lines in each */
143 static int hash_string(const void *obj, const int flags)
145 char *str = ((struct inclfile*)obj)->fname;
148 for (total=0; *str; str++) {
149 unsigned int tmp = total;
150 total <<= 1; /* multiply by 2 */
151 total += tmp; /* multiply by 3 */
152 total <<= 2; /* multiply by 12 */
153 total += tmp; /* multiply by 13 */
155 total += ((unsigned int)(*str));
162 static int hashtab_compare_strings(void *a, void *b, int flags)
164 const struct inclfile *ae = a, *be = b;
165 return !strcmp(ae->fname, be->fname) ? CMP_MATCH : 0;
168 static struct ast_config_map {
169 struct ast_config_map *next;
175 } *config_maps = NULL;
177 AST_MUTEX_DEFINE_STATIC(config_lock);
178 static struct ast_config_engine *config_engine_list;
180 #define MAX_INCLUDE_LEVEL 10
182 struct ast_category_template_instance {
183 char name[80]; /* redundant? */
184 const struct ast_category *inst;
185 AST_LIST_ENTRY(ast_category_template_instance) next;
188 struct ast_category {
190 int ignored; /*!< do not let user of the config see this category -- set by (!) after the category decl; a template */
192 char *file; /*!< the file name from whence this declaration was read */
194 AST_LIST_HEAD_NOLOCK(template_instance_list, ast_category_template_instance) template_instances;
195 struct ast_comment *precomments;
196 struct ast_comment *sameline;
197 struct ast_comment *trailing; /*!< the last object in the list will get assigned any trailing comments when EOF is hit */
198 struct ast_variable *root;
199 struct ast_variable *last;
200 struct ast_category *next;
204 struct ast_category *root;
205 struct ast_category *last;
206 struct ast_category *current;
207 struct ast_category *last_browse; /*!< used to cache the last category supplied via category_browse */
209 int max_include_level;
210 struct ast_config_include *includes; /*!< a list of inclusions, which should describe the entire tree */
213 struct ast_config_include {
214 char *include_location_file; /*!< file name in which the include occurs */
215 int include_location_lineno; /*!< lineno where include occurred */
216 int exec; /*!< set to non-zero if itsa #exec statement */
217 char *exec_file; /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
218 char *included_file; /*!< file name included */
219 int inclusion_count; /*!< if the file is included more than once, a running count thereof -- but, worry not,
220 we explode the instances and will include those-- so all entries will be unique */
221 int output; /*!< a flag to indicate if the inclusion has been output */
222 struct ast_config_include *next; /*!< ptr to next inclusion in the list */
225 struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
227 struct ast_variable *variable;
228 int name_len = strlen(name) + 1;
229 int val_len = strlen(value) + 1;
230 int fn_len = strlen(filename) + 1;
232 if ((variable = ast_calloc(1, name_len + val_len + fn_len + sizeof(*variable)))) {
233 char *dst = variable->stuff; /* writable space starts here */
234 variable->name = strcpy(dst, name);
236 variable->value = strcpy(dst, value);
238 variable->file = strcpy(dst, filename);
243 struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
245 /* a file should be included ONCE. Otherwise, if one of the instances is changed,
246 * then all be changed. -- how do we know to include it? -- Handling modified
247 * instances is possible, I'd have
248 * to create a new master for each instance. */
249 struct ast_config_include *inc;
252 inc = ast_include_find(conf, included_file);
255 inc->inclusion_count++;
256 snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
257 } while (stat(real_included_file_name, &statbuf) == 0);
258 ast_log(LOG_WARNING,"'%s', line %d: Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
260 *real_included_file_name = 0;
262 inc = ast_calloc(1,sizeof(struct ast_config_include));
263 inc->include_location_file = ast_strdup(from_file);
264 inc->include_location_lineno = from_lineno;
265 if (!ast_strlen_zero(real_included_file_name))
266 inc->included_file = ast_strdup(real_included_file_name);
268 inc->included_file = ast_strdup(included_file);
272 inc->exec_file = ast_strdup(exec_file);
274 /* attach this new struct to the conf struct */
275 inc->next = conf->includes;
276 conf->includes = inc;
281 void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
283 struct ast_config_include *incl;
284 struct ast_category *cat;
285 struct ast_variable *v;
287 int from_len = strlen(from_file);
288 int to_len = strlen(to_file);
290 if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
293 /* the manager code allows you to read in one config file, then
294 * write it back out under a different name. But, the new arrangement
295 * ties output lines to the file name. So, before you try to write
296 * the config file to disk, better riffle thru the data and make sure
297 * the file names are changed.
299 /* file names are on categories, includes (of course), and on variables. So,
300 * traverse all this and swap names */
302 for (incl = conf->includes; incl; incl=incl->next) {
303 if (strcmp(incl->include_location_file,from_file) == 0) {
304 if (from_len >= to_len)
305 strcpy(incl->include_location_file, to_file);
307 free(incl->include_location_file);
308 incl->include_location_file = strdup(to_file);
312 for (cat = conf->root; cat; cat = cat->next) {
313 if (strcmp(cat->file,from_file) == 0) {
314 if (from_len >= to_len)
315 strcpy(cat->file, to_file);
318 cat->file = strdup(to_file);
321 for (v = cat->root; v; v = v->next) {
322 if (strcmp(v->file,from_file) == 0) {
323 if (from_len >= to_len)
324 strcpy(v->file, to_file);
327 v->file = strdup(to_file);
334 struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
336 struct ast_config_include *x;
337 for (x=conf->includes;x;x=x->next) {
338 if (strcmp(x->included_file,included_file) == 0)
345 void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
350 category->last->next = variable;
352 category->root = variable;
353 category->last = variable;
354 while (category->last->next)
355 category->last = category->last->next;
358 void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
360 struct ast_variable *cur = category->root;
364 if (!variable || sscanf(line, "%d", &insertline) != 1)
367 variable->next = category->root;
368 category->root = variable;
370 for (lineno = 1; lineno < insertline; lineno++) {
375 variable->next = cur->next;
376 cur->next = variable;
380 void ast_variables_destroy(struct ast_variable *v)
382 struct ast_variable *vn;
391 struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
393 struct ast_category *cat = NULL;
395 if (category && config->last_browse && (config->last_browse->name == category))
396 cat = config->last_browse;
398 cat = ast_category_get(config, category);
400 return (cat) ? cat->root : NULL;
403 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
406 tmp = ast_variable_retrieve(cfg, cat, var);
408 tmp = ast_variable_retrieve(cfg, "general", var);
413 const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
415 struct ast_variable *v;
418 for (v = ast_variable_browse(config, category); v; v = v->next) {
419 if (!strcasecmp(variable, v->name))
423 struct ast_category *cat;
425 for (cat = config->root; cat; cat = cat->next)
426 for (v = cat->root; v; v = v->next)
427 if (!strcasecmp(variable, v->name))
434 static struct ast_variable *variable_clone(const struct ast_variable *old)
436 struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
439 new->lineno = old->lineno;
440 new->object = old->object;
441 new->blanklines = old->blanklines;
442 /* TODO: clone comments? */
448 static void move_variables(struct ast_category *old, struct ast_category *new)
450 struct ast_variable *var = old->root;
453 /* we can just move the entire list in a single op */
454 ast_variable_append(new, var);
457 struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
459 struct ast_category *category;
461 if ((category = ast_calloc(1, sizeof(*category))))
462 ast_copy_string(category->name, name, sizeof(category->name));
463 category->file = strdup(in_file);
464 category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
468 static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
470 struct ast_category *cat;
472 /* try exact match first, then case-insensitive match */
473 for (cat = config->root; cat; cat = cat->next) {
474 if (cat->name == category_name && (ignored || !cat->ignored))
478 for (cat = config->root; cat; cat = cat->next) {
479 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
486 struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
488 return category_get(config, category_name, 0);
491 int ast_category_exist(const struct ast_config *config, const char *category_name)
493 return !!ast_category_get(config, category_name);
496 void ast_category_append(struct ast_config *config, struct ast_category *category)
499 config->last->next = category;
501 config->root = category;
502 category->include_level = config->include_level;
503 config->last = category;
504 config->current = category;
507 void ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
509 struct ast_category *cur_category;
513 if (!strcasecmp(config->root->name, match)) {
514 cat->next = config->root;
518 for (cur_category = config->root; cur_category; cur_category = cur_category->next) {
519 if (!strcasecmp(cur_category->next->name, match)) {
520 cat->next = cur_category->next;
521 cur_category->next = cat;
527 static void ast_destroy_comments(struct ast_category *cat)
529 struct ast_comment *n, *p;
531 for (p=cat->precomments; p; p=n) {
535 for (p=cat->sameline; p; p=n) {
539 for (p=cat->trailing; p; p=n) {
543 cat->precomments = NULL;
544 cat->sameline = NULL;
545 cat->trailing = NULL;
548 static void ast_destroy_template_list(struct ast_category *cat)
550 struct ast_category_template_instance *x;
552 while ((x = AST_LIST_REMOVE_HEAD(&cat->template_instances, next)))
556 void ast_category_destroy(struct ast_category *cat)
558 ast_variables_destroy(cat->root);
563 ast_destroy_comments(cat);
564 ast_destroy_template_list(cat);
568 static void ast_includes_destroy(struct ast_config_include *incls)
570 struct ast_config_include *incl,*inclnext;
572 for (incl=incls; incl; incl = inclnext) {
573 inclnext = incl->next;
574 if (incl->include_location_file)
575 free(incl->include_location_file);
577 free(incl->exec_file);
578 if (incl->included_file)
579 free(incl->included_file);
584 static struct ast_category *next_available_category(struct ast_category *cat)
586 for (; cat && cat->ignored; cat = cat->next);
591 /*! return the first var of a category */
592 struct ast_variable *ast_category_first(struct ast_category *cat)
594 return (cat) ? cat->root : NULL;
597 struct ast_variable *ast_category_root(struct ast_config *config, char *cat)
599 struct ast_category *category = ast_category_get(config, cat);
602 return category->root;
606 char *ast_category_browse(struct ast_config *config, const char *prev)
608 struct ast_category *cat = NULL;
610 if (prev && config->last_browse && (config->last_browse->name == prev))
611 cat = config->last_browse->next;
612 else if (!prev && config->root)
615 for (cat = config->root; cat; cat = cat->next) {
616 if (cat->name == prev) {
622 for (cat = config->root; cat; cat = cat->next) {
623 if (!strcasecmp(cat->name, prev)) {
632 cat = next_available_category(cat);
634 config->last_browse = cat;
635 return (cat) ? cat->name : NULL;
638 struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
640 struct ast_variable *v;
649 void ast_category_rename(struct ast_category *cat, const char *name)
651 ast_copy_string(cat->name, name, sizeof(cat->name));
654 static void inherit_category(struct ast_category *new, const struct ast_category *base)
656 struct ast_variable *var;
657 struct ast_category_template_instance *x = ast_calloc(1,sizeof(struct ast_category_template_instance));
659 strcpy(x->name, base->name);
661 AST_LIST_INSERT_TAIL(&new->template_instances, x, next);
662 for (var = base->root; var; var = var->next)
663 ast_variable_append(new, variable_clone(var));
666 struct ast_config *ast_config_new(void)
668 struct ast_config *config;
670 if ((config = ast_calloc(1, sizeof(*config))))
671 config->max_include_level = MAX_INCLUDE_LEVEL;
675 int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
677 struct ast_variable *cur, *prev=NULL, *curn;
681 cur = category->root;
683 if (cur->name == variable) {
685 prev->next = cur->next;
686 if (cur == category->last)
687 category->last = prev;
689 category->root = cur->next;
690 if (cur == category->last)
691 category->last = NULL;
694 ast_variables_destroy(cur);
702 cur = category->root;
705 if ((!ast_strlen_zero(line) && lineno == atoi(line)) || (ast_strlen_zero(line) && !strcasecmp(cur->name, variable) && (ast_strlen_zero(match) || !strcasecmp(cur->value, match)))) {
707 prev->next = cur->next;
708 if (cur == category->last)
709 category->last = prev;
711 category->root = cur->next;
712 if (cur == category->last)
713 category->last = NULL;
716 ast_variables_destroy(cur);
727 int ast_variable_update(struct ast_category *category, const char *variable,
728 const char *value, const char *match, unsigned int object)
730 struct ast_variable *cur, *prev=NULL, *newer=NULL;
732 for (cur = category->root; cur; prev = cur, cur = cur->next) {
733 if (strcasecmp(cur->name, variable) ||
734 (!ast_strlen_zero(match) && strcasecmp(cur->value, match)))
737 if (!(newer = ast_variable_new(variable, value, cur->file)))
740 newer->next = cur->next;
741 newer->object = cur->object || object;
745 category->root = newer;
746 if (category->last == cur)
747 category->last = newer;
750 ast_variables_destroy(cur);
758 category->root = newer;
763 int ast_category_delete(struct ast_config *cfg, const char *category)
765 struct ast_category *prev=NULL, *cat;
769 if (cat->name == category) {
771 prev->next = cat->next;
772 if (cat == cfg->last)
775 cfg->root = cat->next;
776 if (cat == cfg->last)
779 ast_category_destroy(cat);
789 if (!strcasecmp(cat->name, category)) {
791 prev->next = cat->next;
792 if (cat == cfg->last)
795 cfg->root = cat->next;
796 if (cat == cfg->last)
799 ast_category_destroy(cat);
808 int ast_category_empty(struct ast_config *cfg, const char *category)
810 struct ast_category *cat;
812 for (cat = cfg->root; cat; cat = cat->next) {
813 if (!strcasecmp(cat->name, category))
815 ast_variables_destroy(cat->root);
824 void ast_config_destroy(struct ast_config *cfg)
826 struct ast_category *cat, *catn;
831 ast_includes_destroy(cfg->includes);
837 ast_category_destroy(catn);
842 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
847 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
849 /* cast below is just to silence compiler warning about dropping "const" */
850 cfg->current = (struct ast_category *) cat;
853 enum config_cache_attribute_enum {
854 ATTRIBUTE_INCLUDE = 0,
858 static void config_cache_attribute(const char *configfile, enum config_cache_attribute_enum attrtype, const char *filename, const char *who_asked)
860 struct cache_file_mtime *cfmtime;
861 struct cache_file_include *cfinclude;
862 struct stat statbuf = { 0, };
864 /* Find our cached entry for this configuration file */
865 AST_LIST_LOCK(&cfmtime_head);
866 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
867 if (!strcmp(cfmtime->filename, configfile) && !strcmp(cfmtime->who_asked, who_asked))
871 cfmtime = ast_calloc(1, sizeof(*cfmtime) + strlen(configfile) + 1 + strlen(who_asked) + 1);
873 AST_LIST_UNLOCK(&cfmtime_head);
876 AST_LIST_HEAD_INIT(&cfmtime->includes);
877 strcpy(cfmtime->filename, configfile);
878 cfmtime->who_asked = cfmtime->filename + strlen(configfile) + 1;
879 strcpy(cfmtime->who_asked, who_asked);
880 /* Note that the file mtime is initialized to 0, i.e. 1970 */
881 AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
884 if (!stat(configfile, &statbuf))
887 cfmtime->mtime = statbuf.st_mtime;
890 case ATTRIBUTE_INCLUDE:
891 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
892 if (!strcmp(cfinclude->include, filename)) {
893 AST_LIST_UNLOCK(&cfmtime_head);
897 cfinclude = ast_calloc(1, sizeof(*cfinclude) + strlen(filename) + 1);
899 AST_LIST_UNLOCK(&cfmtime_head);
902 strcpy(cfinclude->include, filename);
903 AST_LIST_INSERT_TAIL(&cfmtime->includes, cfinclude, list);
906 cfmtime->has_exec = 1;
909 AST_LIST_UNLOCK(&cfmtime_head);
912 /*! \brief parse one line in the configuration.
914 * We can have a category header [foo](...)
915 * a directive #include / #exec
916 * or a regular line name = value
919 static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
920 char *buf, int lineno, const char *configfile, struct ast_flags flags,
921 struct ast_str *comment_buffer,
922 struct ast_str *lline_buffer,
923 const char *suggested_include_file,
924 struct ast_category **last_cat, struct ast_variable **last_var, const char *who_asked)
928 struct ast_variable *v;
929 char cmd[512], exec_file[512];
931 /* Actually parse the entry */
932 if (cur[0] == '[') { /* A category header */
933 /* format is one of the following:
934 * [foo] define a new category named 'foo'
935 * [foo](!) define a new template category named 'foo'
936 * [foo](+) append to category 'foo', error if foo does not exist.
937 * [foo](a) define a new category and inherit from template a.
938 * You can put a comma-separated list of templates and '!' and '+'
939 * between parentheses, with obvious meaning.
941 struct ast_category *newcat = NULL;
944 c = strchr(cur, ']');
946 ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
954 if (!(*cat = newcat = ast_category_new(catname, ast_strlen_zero(suggested_include_file)?configfile:suggested_include_file, lineno))) {
957 (*cat)->lineno = lineno;
962 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
963 newcat->precomments = ALLOC_COMMENT(comment_buffer);
964 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
965 newcat->sameline = ALLOC_COMMENT(lline_buffer);
966 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
967 CB_RESET(comment_buffer, lline_buffer);
969 /* If there are options or categories to inherit from, process them now */
971 if (!(cur = strchr(c, ')'))) {
972 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
976 while ((cur = strsep(&c, ","))) {
977 if (!strcasecmp(cur, "!")) {
979 } else if (!strcasecmp(cur, "+")) {
980 *cat = category_get(cfg, catname, 1);
983 ast_category_destroy(newcat);
984 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
988 move_variables(newcat, *cat);
989 ast_category_destroy(newcat);
993 struct ast_category *base;
995 base = category_get(cfg, cur, 1);
997 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
1000 inherit_category(*cat, base);
1005 ast_category_append(cfg, *cat);
1006 } else if (cur[0] == '#') { /* A directive - #include or #exec */
1008 char real_inclusion_name[256];
1009 struct ast_config_include *inclu;
1010 int do_include = 0; /* otherwise, it is exec */
1014 while (*c && (*c > 32)) c++;
1017 /* Find real argument */
1018 c = ast_skip_blanks(c + 1);
1023 if (!strcasecmp(cur, "include")) {
1025 } else if (!strcasecmp(cur, "exec")) {
1026 if (!ast_opt_exec_includes) {
1027 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
1028 return 0; /* XXX is this correct ? or we should return -1 ? */
1031 ast_log(LOG_WARNING, "Unknown directive '#%s' at line %d of %s\n", cur, lineno, configfile);
1032 return 0; /* XXX is this correct ? or we should return -1 ? */
1036 ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
1037 do_include ? "include" : "exec",
1038 do_include ? "filename" : "/path/to/executable",
1041 return 0; /* XXX is this correct ? or we should return -1 ? */
1044 /* Strip off leading and trailing "'s and <>'s */
1045 while ((*c == '<') || (*c == '>') || (*c == '\"')) c++;
1046 /* Get rid of leading mess */
1049 while (!ast_strlen_zero(cur)) {
1050 c = cur + strlen(cur) - 1;
1051 if ((*c == '>') || (*c == '<') || (*c == '\"'))
1056 /* #exec </path/to/executable>
1057 We create a tmp file, then we #include it, then we delete it. */
1059 struct timeval tv = ast_tvnow();
1060 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1061 config_cache_attribute(configfile, ATTRIBUTE_EXEC, NULL, who_asked);
1062 snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d%d.%ld", (int)tv.tv_sec, (int)tv.tv_usec, (long)pthread_self());
1063 snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
1064 ast_safe_system(cmd);
1067 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1068 config_cache_attribute(configfile, ATTRIBUTE_INCLUDE, cur, who_asked);
1069 exec_file[0] = '\0';
1072 /* record this inclusion */
1073 inclu = ast_include_new(cfg, configfile, cur, !do_include, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
1075 do_include = ast_config_internal_load(cur, cfg, flags, real_inclusion_name, who_asked) ? 1 : 0;
1076 if (!ast_strlen_zero(exec_file))
1079 ast_log(LOG_ERROR, "The file '%s' was listed as a #include but it does not exist.\n", cur);
1082 /* XXX otherwise what ? the default return is 0 anyways */
1085 /* Just a line (variable = value) */
1087 ast_log(LOG_WARNING,
1088 "parse error: No category context for line %d of %s\n", lineno, configfile);
1091 c = strchr(cur, '=');
1096 /* Ignore > in => */
1102 if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), *suggested_include_file ? suggested_include_file : configfile))) {
1107 /* Put and reset comments */
1109 ast_variable_append(*cat, v);
1111 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1112 v->precomments = ALLOC_COMMENT(comment_buffer);
1113 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1114 v->sameline = ALLOC_COMMENT(lline_buffer);
1115 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1116 CB_RESET(comment_buffer, lline_buffer);
1122 ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
1128 static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, struct ast_flags flags, const char *suggested_include_file, const char *who_asked)
1131 #if defined(LOW_MEMORY)
1136 char *new_buf, *comment_p, *process_buf;
1139 int comment = 0, nest[MAX_NESTED_COMMENTS];
1140 struct ast_category *cat = NULL;
1142 struct stat statbuf;
1143 struct cache_file_mtime *cfmtime = NULL;
1144 struct cache_file_include *cfinclude;
1145 struct ast_variable *last_var = 0;
1146 struct ast_category *last_cat = 0;
1147 /*! Growable string buffer */
1148 struct ast_str *comment_buffer = NULL; /*!< this will be a comment collector.*/
1149 struct ast_str *lline_buffer = NULL; /*!< A buffer for stuff behind the ; */
1152 cat = ast_config_get_current_category(cfg);
1154 if (filename[0] == '/') {
1155 ast_copy_string(fn, filename, sizeof(fn));
1157 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
1160 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1161 comment_buffer = ast_str_create(CB_SIZE);
1163 lline_buffer = ast_str_create(CB_SIZE);
1164 if (!lline_buffer) {
1166 ast_free(comment_buffer);
1167 ast_log(LOG_ERROR, "Failed to initialize the comment buffer!\n");
1171 #ifdef AST_INCLUDE_GLOB
1175 globbuf.gl_offs = 0; /* initialize it to silence gcc */
1176 glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
1177 if (glob_ret == GLOB_NOSPACE)
1178 ast_log(LOG_WARNING,
1179 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
1180 else if (glob_ret == GLOB_ABORTED)
1181 ast_log(LOG_WARNING,
1182 "Glob Expansion of pattern '%s' failed: Read error\n", fn);
1184 /* loop over expanded files */
1186 for (i=0; i<globbuf.gl_pathc; i++) {
1187 ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
1190 * The following is not a loop, but just a convenient way to define a block
1191 * (using do { } while(0) ), and be able to exit from it with 'continue'
1192 * or 'break' in case of errors. Nice trick.
1195 if (stat(fn, &statbuf))
1198 if (!S_ISREG(statbuf.st_mode)) {
1199 ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
1203 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
1204 /* Find our cached entry for this configuration file */
1205 AST_LIST_LOCK(&cfmtime_head);
1206 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
1207 if (!strcmp(cfmtime->filename, fn) && !strcmp(cfmtime->who_asked, who_asked))
1211 cfmtime = ast_calloc(1, sizeof(*cfmtime) + strlen(fn) + 1 + strlen(who_asked) + 1);
1214 AST_LIST_HEAD_INIT(&cfmtime->includes);
1215 strcpy(cfmtime->filename, fn);
1216 cfmtime->who_asked = cfmtime->filename + strlen(fn) + 1;
1217 strcpy(cfmtime->who_asked, who_asked);
1218 /* Note that the file mtime is initialized to 0, i.e. 1970 */
1219 AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
1223 if (cfmtime && (!cfmtime->has_exec) && (cfmtime->mtime == statbuf.st_mtime) && ast_test_flag(&flags, CONFIG_FLAG_FILEUNCHANGED)) {
1224 /* File is unchanged, what about the (cached) includes (if any)? */
1226 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
1227 /* We must glob here, because if we did not, then adding a file to globbed directory would
1228 * incorrectly cause no reload to be necessary. */
1230 #ifdef AST_INCLUDE_GLOB
1232 glob_t globbuf = { .gl_offs = 0 };
1233 glob_ret = glob(cfinclude->include, MY_GLOB_FLAGS, NULL, &globbuf);
1234 /* On error, we reparse */
1235 if (glob_ret == GLOB_NOSPACE || glob_ret == GLOB_ABORTED)
1238 /* loop over expanded files */
1240 for (j = 0; j < globbuf.gl_pathc; j++) {
1241 ast_copy_string(fn2, globbuf.gl_pathv[j], sizeof(fn2));
1243 ast_copy_string(fn2, cfinclude->include);
1245 if (config_text_file_load(NULL, NULL, fn2, NULL, flags, "", who_asked) == NULL) {
1246 /* that second-to-last field needs to be looked at in this case... TODO */
1248 /* One change is enough to short-circuit and reload the whole shebang */
1251 #ifdef AST_INCLUDE_GLOB
1258 AST_LIST_UNLOCK(&cfmtime_head);
1259 return CONFIG_STATUS_FILEUNCHANGED;
1262 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1263 AST_LIST_UNLOCK(&cfmtime_head);
1265 /* If cfg is NULL, then we just want an answer */
1270 cfmtime->mtime = statbuf.st_mtime;
1272 ast_verb(2, "Parsing '%s': ", fn);
1274 if (!(f = fopen(fn, "r"))) {
1275 ast_debug(1, "No file to parse: %s\n", fn);
1276 ast_verb(2, "Not found (%s)\n", strerror(errno));
1280 /* If we get to this point, then we're loading regardless */
1281 ast_clear_flag(&flags, CONFIG_FLAG_FILEUNCHANGED);
1282 ast_debug(1, "Parsing %s\n", fn);
1283 ast_verb(2, "Found\n");
1286 if (fgets(buf, sizeof(buf), f)) {
1287 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && lline_buffer->used) {
1288 CB_ADD(&comment_buffer, lline_buffer->str); /* add the current lline buffer to the comment buffer */
1289 lline_buffer->used = 0; /* erase the lline buffer */
1298 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
1299 /* blank line? really? Can we add it to an existing comment and maybe preserve inter- and post- comment spacing? */
1300 CB_ADD(&comment_buffer, "\n"); /* add a newline to the comment buffer */
1301 continue; /* go get a new line, then */
1304 while ((comment_p = strchr(new_buf, COMMENT_META))) {
1305 if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
1306 /* Escaped semicolons aren't comments. */
1307 new_buf = comment_p + 1;
1308 } else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
1309 /* Meta-Comment start detected ";--" */
1310 if (comment < MAX_NESTED_COMMENTS) {
1312 new_buf = comment_p + 3;
1314 nest[comment-1] = lineno;
1316 ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
1318 } else if ((comment_p >= new_buf + 2) &&
1319 (*(comment_p - 1) == COMMENT_TAG) &&
1320 (*(comment_p - 2) == COMMENT_TAG)) {
1321 /* Meta-Comment end detected */
1323 new_buf = comment_p + 1;
1325 /* Back to non-comment now */
1327 /* Actually have to move what's left over the top, then continue */
1329 oldptr = process_buf + strlen(process_buf);
1330 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1331 CB_ADD(&comment_buffer, ";");
1332 CB_ADD_LEN(&comment_buffer, oldptr+1, new_buf-oldptr-1);
1335 memmove(oldptr, new_buf, strlen(new_buf) + 1);
1338 process_buf = new_buf;
1342 /* If ; is found, and we are not nested in a comment,
1343 we immediately stop all comment processing */
1344 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1345 CB_ADD(&lline_buffer, comment_p);
1348 new_buf = comment_p;
1350 new_buf = comment_p + 1;
1353 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment && !process_buf ) {
1354 CB_ADD(&comment_buffer, buf); /* the whole line is a comment, store it */
1358 char *buf = ast_strip(process_buf);
1359 if (!ast_strlen_zero(buf)) {
1360 if (process_text_line(cfg, &cat, buf, lineno, fn, flags, comment_buffer, lline_buffer, suggested_include_file, &last_cat, &last_var, who_asked)) {
1368 /* end of file-- anything in a comment buffer? */
1370 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used ) {
1371 if (lline_buffer && lline_buffer->used) {
1372 CB_ADD(&comment_buffer, lline_buffer->str); /* add the current lline buffer to the comment buffer */
1373 lline_buffer->used = 0; /* erase the lline buffer */
1375 last_cat->trailing = ALLOC_COMMENT(comment_buffer);
1377 } else if (last_var) {
1378 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used ) {
1379 if (lline_buffer && lline_buffer->used) {
1380 CB_ADD(&comment_buffer, lline_buffer->str); /* add the current lline buffer to the comment buffer */
1381 lline_buffer->used = 0; /* erase the lline buffer */
1383 last_var->trailing = ALLOC_COMMENT(comment_buffer);
1386 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used) {
1387 ast_debug(1, "Nothing to attach comments to, discarded: %s\n", comment_buffer->str);
1390 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1391 CB_RESET(comment_buffer, lline_buffer);
1396 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
1398 #ifdef AST_INCLUDE_GLOB
1399 if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED)
1407 if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg->include_level == 1 && ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1409 ast_free(comment_buffer);
1411 ast_free(lline_buffer);
1412 comment_buffer = NULL;
1413 lline_buffer = NULL;
1423 /* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
1424 which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
1425 recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
1426 be shocked and mystified as to why things are not showing up in the files!
1428 Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
1429 and line number are stored for each include, plus the name of the file included, so that these statements may be
1430 included in the output files on a file_save operation.
1432 The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
1433 are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
1434 the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
1435 and a header gets added.
1437 vars and category heads are output in the order they are stored in the config file. So, if the software
1438 shuffles these at all, then the placement of #include directives might get a little mixed up, because the
1439 file/lineno data probably won't get changed.
1443 static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
1449 ast_copy_string(date, ctime(&t), sizeof(date));
1451 fprintf(f1, ";!\n");
1452 fprintf(f1, ";! Automatically generated configuration file\n");
1453 if (strcmp(configfile, fn))
1454 fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
1456 fprintf(f1, ";! Filename: %s\n", configfile);
1457 fprintf(f1, ";! Generator: %s\n", generator);
1458 fprintf(f1, ";! Creation Date: %s", date);
1459 fprintf(f1, ";!\n");
1462 static void inclfile_destroy(void *obj)
1464 const struct inclfile *o = obj;
1471 static void set_fn(char *fn, int fn_size, const char *file, const char *configfile, struct ao2_container *fileset, struct inclfile **fi)
1473 struct inclfile lookup;
1475 if (!file || file[0] == 0) {
1476 if (configfile[0] == '/')
1477 ast_copy_string(fn, configfile, fn_size);
1479 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
1480 } else if (file[0] == '/')
1481 ast_copy_string(fn, file, fn_size);
1483 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
1485 *fi = ao2_find(fileset, &lookup, OBJ_POINTER);
1487 /* set up a file scratch pad */
1488 struct inclfile *fx = ao2_alloc(sizeof(struct inclfile), inclfile_destroy);
1489 fx->fname = ast_strdup(fn);
1492 ao2_link(fileset, fx);
1496 static int count_linefeeds(char *str)
1508 static int count_linefeeds_in_comments(struct ast_comment *x)
1513 count += count_linefeeds(x->cmt);
1519 static void insert_leading_blank_lines(FILE *fp, struct inclfile *fi, struct ast_comment *precomments, int lineno)
1521 int precomment_lines = count_linefeeds_in_comments(precomments);
1524 /* I don't have to worry about those ;! comments, they are
1525 stored in the precomments, but not printed back out.
1526 I did have to make sure that comments following
1527 the ;! header comments were not also deleted in the process */
1528 for (i=fi->lineno;i<lineno - precomment_lines; i++) {
1531 fi->lineno = lineno+1; /* Advance the file lineno */
1534 int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
1538 struct ast_variable *var;
1539 struct ast_category *cat;
1540 struct ast_comment *cmt;
1541 struct ast_config_include *incl;
1543 struct ao2_container *fileset = ao2_container_alloc(180000, hash_string, hashtab_compare_strings);
1544 struct inclfile *fi = 0;
1546 /* reset all the output flags, in case this isn't our first time saving this data */
1548 for (incl=cfg->includes; incl; incl = incl->next)
1551 /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
1552 are all truncated to zero bytes and have that nice header*/
1554 for (incl=cfg->includes; incl; incl = incl->next)
1556 if (!incl->exec) { /* leave the execs alone -- we'll write out the #exec directives, but won't zero out the include files or exec files*/
1559 set_fn(fn, sizeof(fn), incl->included_file, configfile, fileset, &fi); /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
1562 gen_header(f1, configfile, fn, generator);
1563 fclose(f1); /* this should zero out the file */
1565 ast_debug(1, "Unable to open for writing: %s\n", fn);
1566 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1568 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1573 set_fn(fn, sizeof(fn), 0, configfile, fileset, &fi); /* just set fn to absolute ver of configfile */
1575 if ((f = fopen(fn, "w+"))) {
1577 if ((f = fopen(fn, "w"))) {
1579 ast_verb(2, "Saving '%s': ", fn);
1580 gen_header(f, configfile, fn, generator);
1583 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1585 /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
1586 /* since each var, cat, and associated comments can come from any file, we have to be
1587 mobile, and open each file, print, and close it on an entry-by-entry basis */
1590 set_fn(fn, sizeof(fn), cat->file, configfile, fileset, &fi);
1594 ast_debug(1, "Unable to open for writing: %s\n", fn);
1595 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1596 ao2_ref(fileset, -1);
1600 /* dump any includes that happen before this category header */
1601 for (incl=cfg->includes; incl; incl = incl->next) {
1602 if (strcmp(incl->include_location_file, cat->file) == 0){
1603 if (cat->lineno > incl->include_location_lineno && !incl->output) {
1605 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
1607 fprintf(f,"#include \"%s\"\n", incl->included_file);
1613 insert_leading_blank_lines(f, fi, cat->precomments, cat->lineno);
1614 /* Dump section with any appropriate comment */
1615 for (cmt = cat->precomments; cmt; cmt=cmt->next) {
1616 char *cmtp = cmt->cmt;
1617 while (*cmtp == ';' && *(cmtp+1) == '!') {
1618 char *cmtp2 = strchr(cmtp+1, '\n');
1624 fprintf(f,"%s", cmtp);
1626 if (!cat->precomments)
1628 fprintf(f, "[%s]", cat->name);
1629 if (cat->ignored || !AST_LIST_EMPTY(&cat->template_instances)) {
1634 if (cat->ignored && !AST_LIST_EMPTY(&cat->template_instances)) {
1637 if (!AST_LIST_EMPTY(&cat->template_instances)) {
1638 struct ast_category_template_instance *x;
1639 AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
1640 fprintf(f,"%s",x->name);
1641 if (x != AST_LIST_LAST(&cat->template_instances))
1647 for(cmt = cat->sameline; cmt; cmt=cmt->next)
1649 fprintf(f,"%s", cmt->cmt);
1653 for (cmt = cat->trailing; cmt; cmt=cmt->next) {
1654 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
1655 fprintf(f,"%s", cmt->cmt);
1658 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1663 struct ast_category_template_instance *x;
1665 AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
1666 struct ast_variable *v;
1667 for (v = x->inst->root; v; v = v->next) {
1668 if (!strcasecmp(var->name, v->name) && !strcmp(var->value, v->value)) {
1680 set_fn(fn, sizeof(fn), var->file, configfile, fileset, &fi);
1684 ast_debug(1, "Unable to open for writing: %s\n", fn);
1685 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1686 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1688 ao2_ref(fileset, -1);
1692 /* dump any includes that happen before this category header */
1693 for (incl=cfg->includes; incl; incl = incl->next) {
1694 if (strcmp(incl->include_location_file, var->file) == 0){
1695 if (var->lineno > incl->include_location_lineno && !incl->output) {
1697 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
1699 fprintf(f,"#include \"%s\"\n", incl->included_file);
1705 insert_leading_blank_lines(f, fi, var->precomments, var->lineno);
1706 for (cmt = var->precomments; cmt; cmt=cmt->next) {
1707 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
1708 fprintf(f,"%s", cmt->cmt);
1711 fprintf(f, "%s %s %s %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
1713 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
1714 for (cmt = var->trailing; cmt; cmt=cmt->next) {
1715 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
1716 fprintf(f,"%s", cmt->cmt);
1718 if (var->blanklines) {
1719 blanklines = var->blanklines;
1720 while (blanklines--)
1725 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1733 ast_verb(2, "Saved\n");
1735 ast_debug(1, "Unable to open for writing: %s\n", fn);
1736 ast_verb(2, "Unable to write (%s)", strerror(errno));
1737 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1738 ao2_ref(fileset, -1);
1742 /* Now, for files with trailing #include/#exec statements,
1743 we have to make sure every entry is output */
1745 for (incl=cfg->includes; incl; incl = incl->next) {
1746 if (!incl->output) {
1747 /* open the respective file */
1748 set_fn(fn, sizeof(fn), incl->include_location_file, configfile, fileset, &fi);
1752 ast_debug(1, "Unable to open for writing: %s\n", fn);
1753 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1754 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1756 ao2_ref(fileset, -1);
1760 /* output the respective include */
1762 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
1764 fprintf(f,"#include \"%s\"\n", incl->included_file);
1767 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1771 ao2_ref(fileset, -1); /* this should destroy the hash container */
1776 static void clear_config_maps(void)
1778 struct ast_config_map *map;
1780 ast_mutex_lock(&config_lock);
1782 while (config_maps) {
1784 config_maps = config_maps->next;
1788 ast_mutex_unlock(&config_lock);
1791 static int append_mapping(const char *name, const char *driver, const char *database, const char *table)
1793 struct ast_config_map *map;
1796 length = sizeof(*map);
1797 length += strlen(name) + 1;
1798 length += strlen(driver) + 1;
1799 length += strlen(database) + 1;
1801 length += strlen(table) + 1;
1803 if (!(map = ast_calloc(1, length)))
1806 map->name = map->stuff;
1807 strcpy(map->name, name);
1808 map->driver = map->name + strlen(map->name) + 1;
1809 strcpy(map->driver, driver);
1810 map->database = map->driver + strlen(map->driver) + 1;
1811 strcpy(map->database, database);
1813 map->table = map->database + strlen(map->database) + 1;
1814 strcpy(map->table, table);
1816 map->next = config_maps;
1818 ast_verb(2, "Binding %s to %s/%s/%s\n", map->name, map->driver, map->database, map->table ? map->table : map->name);
1824 int read_config_maps(void)
1826 struct ast_config *config, *configtmp;
1827 struct ast_variable *v;
1828 char *driver, *table, *database, *stringp, *tmp;
1829 struct ast_flags flags = { 0 };
1831 clear_config_maps();
1833 configtmp = ast_config_new();
1834 configtmp->max_include_level = 1;
1835 config = ast_config_internal_load(extconfig_conf, configtmp, flags, "", "extconfig");
1837 ast_config_destroy(configtmp);
1841 for (v = ast_variable_browse(config, "settings"); v; v = v->next) {
1843 ast_copy_string(buf, v->value, sizeof(buf));
1845 driver = strsep(&stringp, ",");
1847 if ((tmp = strchr(stringp, '\"')))
1850 /* check if the database text starts with a double quote */
1851 if (*stringp == '"') {
1853 database = strsep(&stringp, "\"");
1854 strsep(&stringp, ",");
1856 /* apparently this text has no quotes */
1857 database = strsep(&stringp, ",");
1860 table = strsep(&stringp, ",");
1862 if (!strcmp(v->name, extconfig_conf)) {
1863 ast_log(LOG_WARNING, "Cannot bind '%s'!\n", extconfig_conf);
1867 if (!strcmp(v->name, "asterisk.conf")) {
1868 ast_log(LOG_WARNING, "Cannot bind 'asterisk.conf'!\n");
1872 if (!strcmp(v->name, "logger.conf")) {
1873 ast_log(LOG_WARNING, "Cannot bind 'logger.conf'!\n");
1877 if (!driver || !database)
1879 if (!strcasecmp(v->name, "sipfriends")) {
1880 ast_log(LOG_WARNING, "The 'sipfriends' table is obsolete, update your config to use sipusers and sippeers, though they can point to the same table.\n");
1881 append_mapping("sipusers", driver, database, table ? table : "sipfriends");
1882 append_mapping("sippeers", driver, database, table ? table : "sipfriends");
1883 } else if (!strcasecmp(v->name, "iaxfriends")) {
1884 ast_log(LOG_WARNING, "The 'iaxfriends' table is obsolete, update your config to use iaxusers and iaxpeers, though they can point to the same table.\n");
1885 append_mapping("iaxusers", driver, database, table ? table : "iaxfriends");
1886 append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends");
1888 append_mapping(v->name, driver, database, table);
1891 ast_config_destroy(config);
1895 int ast_config_engine_register(struct ast_config_engine *new)
1897 struct ast_config_engine *ptr;
1899 ast_mutex_lock(&config_lock);
1901 if (!config_engine_list) {
1902 config_engine_list = new;
1904 for (ptr = config_engine_list; ptr->next; ptr=ptr->next);
1908 ast_mutex_unlock(&config_lock);
1909 ast_log(LOG_NOTICE,"Registered Config Engine %s\n", new->name);
1914 int ast_config_engine_deregister(struct ast_config_engine *del)
1916 struct ast_config_engine *ptr, *last=NULL;
1918 ast_mutex_lock(&config_lock);
1920 for (ptr = config_engine_list; ptr; ptr=ptr->next) {
1923 last->next = ptr->next;
1925 config_engine_list = ptr->next;
1931 ast_mutex_unlock(&config_lock);
1936 /*! \brief Find realtime engine for realtime family */
1937 static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
1939 struct ast_config_engine *eng, *ret = NULL;
1940 struct ast_config_map *map;
1942 ast_mutex_lock(&config_lock);
1944 for (map = config_maps; map; map = map->next) {
1945 if (!strcasecmp(family, map->name)) {
1947 ast_copy_string(database, map->database, dbsiz);
1949 ast_copy_string(table, map->table ? map->table : family, tabsiz);
1954 /* Check if the required driver (engine) exist */
1956 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
1957 if (!strcasecmp(eng->name, map->driver))
1962 ast_mutex_unlock(&config_lock);
1964 /* if we found a mapping, but the engine is not available, then issue a warning */
1966 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
1971 static struct ast_config_engine text_file_engine = {
1973 .load_func = config_text_file_load,
1976 struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, struct ast_flags flags, const char *suggested_include_file, const char *who_asked)
1980 struct ast_config_engine *loader = &text_file_engine;
1981 struct ast_config *result;
1983 /* The config file itself bumps include_level by 1 */
1984 if (cfg->max_include_level > 0 && cfg->include_level == cfg->max_include_level + 1) {
1985 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
1989 cfg->include_level++;
1991 if (strcmp(filename, extconfig_conf) && strcmp(filename, "asterisk.conf") && config_engine_list) {
1992 struct ast_config_engine *eng;
1994 eng = find_engine(filename, db, sizeof(db), table, sizeof(table));
1997 if (eng && eng->load_func) {
2000 eng = find_engine("global", db, sizeof(db), table, sizeof(table));
2001 if (eng && eng->load_func)
2006 result = loader->load_func(db, table, filename, cfg, flags, suggested_include_file, who_asked);
2008 if (result && result != CONFIG_STATUS_FILEUNCHANGED)
2009 result->include_level--;
2011 cfg->include_level--;
2016 struct ast_config *ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
2018 struct ast_config *cfg;
2019 struct ast_config *result;
2021 cfg = ast_config_new();
2025 result = ast_config_internal_load(filename, cfg, flags, "", who_asked);
2026 if (!result || result == CONFIG_STATUS_FILEUNCHANGED)
2027 ast_config_destroy(cfg);
2032 static struct ast_variable *ast_load_realtime_helper(const char *family, va_list ap)
2034 struct ast_config_engine *eng;
2037 struct ast_variable *res=NULL;
2039 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2040 if (eng && eng->realtime_func)
2041 res = eng->realtime_func(db, table, ap);
2046 struct ast_variable *ast_load_realtime_all(const char *family, ...)
2048 struct ast_variable *res;
2051 va_start(ap, family);
2052 res = ast_load_realtime_helper(family, ap);
2058 struct ast_variable *ast_load_realtime(const char *family, ...)
2060 struct ast_variable *res, *cur, *prev = NULL, *freeme = NULL;
2063 va_start(ap, family);
2064 res = ast_load_realtime_helper(family, ap);
2067 /* Eliminate blank entries */
2068 for (cur = res; cur; cur = cur->next) {
2074 if (ast_strlen_zero(cur->value)) {
2076 prev->next = cur->next;
2087 /*! \brief Check if realtime engine is configured for family */
2088 int ast_check_realtime(const char *family)
2090 struct ast_config_engine *eng;
2092 eng = find_engine(family, NULL, 0, NULL, 0);
2098 /*! \brief Check if there's any realtime engines loaded */
2099 int ast_realtime_enabled()
2101 return config_maps ? 1 : 0;
2104 int ast_realtime_require_field(const char *family, ...)
2106 struct ast_config_engine *eng;
2108 char table[256] = "";
2112 va_start(ap, family);
2113 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2114 if (eng && eng->require_func) {
2115 res = eng->require_func(db, table, ap);
2122 int ast_unload_realtime(const char *family)
2124 struct ast_config_engine *eng;
2126 char table[256] = "";
2129 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2130 if (eng && eng->unload_func) {
2131 res = eng->unload_func(db, table);
2136 struct ast_config *ast_load_realtime_multientry(const char *family, ...)
2138 struct ast_config_engine *eng;
2141 struct ast_config *res=NULL;
2144 va_start(ap, family);
2145 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2146 if (eng && eng->realtime_multi_func)
2147 res = eng->realtime_multi_func(db, table, ap);
2153 int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
2155 struct ast_config_engine *eng;
2161 va_start(ap, lookup);
2162 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2163 if (eng && eng->update_func)
2164 res = eng->update_func(db, table, keyfield, lookup, ap);
2170 int ast_store_realtime(const char *family, ...)
2172 struct ast_config_engine *eng;
2178 va_start(ap, family);
2179 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2180 if (eng && eng->store_func)
2181 res = eng->store_func(db, table, ap);
2187 int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...)
2189 struct ast_config_engine *eng;
2195 va_start(ap, lookup);
2196 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2197 if (eng && eng->destroy_func)
2198 res = eng->destroy_func(db, table, keyfield, lookup, ap);
2204 /*! \brief Helper function to parse arguments
2205 * See documentation in config.h
2207 int ast_parse_arg(const char *arg, enum ast_parse_flags flags,
2208 void *p_result, ...)
2213 va_start(ap, p_result);
2214 switch (flags & PARSE_TYPE) {
2217 int32_t *result = p_result;
2218 int32_t x, def = result ? *result : 0,
2219 high = (int32_t)0x7fffffff,
2220 low = (int32_t)0x80000000;
2221 /* optional argument: first default value, then range */
2222 if (flags & PARSE_DEFAULT)
2223 def = va_arg(ap, int32_t);
2224 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
2225 /* range requested, update bounds */
2226 low = va_arg(ap, int32_t);
2227 high = va_arg(ap, int32_t);
2229 x = strtol(arg, NULL, 0);
2230 error = (x < low) || (x > high);
2231 if (flags & PARSE_OUT_RANGE)
2234 *result = error ? def : x;
2236 "extract int from [%s] in [%d, %d] gives [%d](%d)\n",
2238 result ? *result : x, error);
2244 uint32_t *result = p_result;
2245 uint32_t x, def = result ? *result : 0,
2246 low = 0, high = (uint32_t)~0;
2247 /* optional argument: first default value, then range */
2248 if (flags & PARSE_DEFAULT)
2249 def = va_arg(ap, uint32_t);
2250 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
2251 /* range requested, update bounds */
2252 low = va_arg(ap, uint32_t);
2253 high = va_arg(ap, uint32_t);
2255 x = strtoul(arg, NULL, 0);
2256 error = (x < low) || (x > high);
2257 if (flags & PARSE_OUT_RANGE)
2260 *result = error ? def : x;
2262 "extract uint from [%s] in [%u, %u] gives [%u](%d)\n",
2264 result ? *result : x, error);
2270 double *result = p_result;
2271 double x, def = result ? *result : 0,
2272 low = -HUGE_VAL, high = HUGE_VAL;
2274 /* optional argument: first default value, then range */
2275 if (flags & PARSE_DEFAULT)
2276 def = va_arg(ap, double);
2277 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
2278 /* range requested, update bounds */
2279 low = va_arg(ap, double);
2280 high = va_arg(ap, double);
2282 x = strtod(arg, NULL);
2283 error = (x < low) || (x > high);
2284 if (flags & PARSE_OUT_RANGE)
2287 *result = error ? def : x;
2289 "extract double from [%s] in [%f, %f] gives [%f](%d)\n",
2291 result ? *result : x, error);
2297 struct sockaddr_in _sa_buf; /* buffer for the result */
2298 struct sockaddr_in *sa = p_result ?
2299 (struct sockaddr_in *)p_result : &_sa_buf;
2300 /* default is either the supplied value or the result itself */
2301 struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
2302 va_arg(ap, struct sockaddr_in *) : sa;
2304 struct ast_hostent ahp;
2306 bzero(&_sa_buf, sizeof(_sa_buf)); /* clear buffer */
2307 /* duplicate the string to strip away the :port */
2308 port = ast_strdupa(arg);
2309 buf = strsep(&port, ":");
2310 sa->sin_family = AF_INET; /* assign family */
2312 * honor the ports flag setting, assign default value
2313 * in case of errors or field unset.
2315 flags &= PARSE_PORT_MASK; /* the only flags left to process */
2317 if (flags == PARSE_PORT_FORBID) {
2318 error = 1; /* port was forbidden */
2319 sa->sin_port = def->sin_port;
2320 } else if (flags == PARSE_PORT_IGNORE)
2321 sa->sin_port = def->sin_port;
2322 else /* accept or require */
2323 sa->sin_port = htons(strtol(port, NULL, 0));
2325 sa->sin_port = def->sin_port;
2326 if (flags == PARSE_PORT_REQUIRE)
2329 /* Now deal with host part, even if we have errors before. */
2330 hp = ast_gethostbyname(buf, &ahp);
2331 if (hp) /* resolved successfully */
2332 memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
2335 sa->sin_addr = def->sin_addr;
2338 "extract inaddr from [%s] gives [%s:%d](%d)\n",
2339 arg, ast_inet_ntoa(sa->sin_addr),
2340 ntohs(sa->sin_port), error);
2348 static char *handle_cli_core_show_config_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2350 struct ast_config_engine *eng;
2351 struct ast_config_map *map;
2355 e->command = "core show config mappings";
2357 "Usage: core show config mappings\n"
2358 " Shows the filenames to config engines.\n";
2364 ast_mutex_lock(&config_lock);
2366 if (!config_engine_list) {
2367 ast_cli(a->fd, "No config mappings found.\n");
2369 ast_cli(a->fd, "\n\n");
2370 for (eng = config_engine_list; eng; eng = eng->next) {
2371 ast_cli(a->fd, "\nConfig Engine: %s\n", eng->name);
2372 for (map = config_maps; map; map = map->next) {
2373 if (!strcasecmp(map->driver, eng->name)) {
2374 ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
2375 map->table ? map->table : map->name);
2379 ast_cli(a->fd,"\n\n");
2382 ast_mutex_unlock(&config_lock);
2387 static char *handle_cli_config_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2389 struct cache_file_mtime *cfmtime;
2390 char *prev = "", *completion_value = NULL;
2391 int wordlen, which = 0;
2395 e->command = "config reload";
2397 "Usage: config reload <filename.conf>\n"
2398 " Reloads all modules that reference <filename.conf>\n";
2405 wordlen = strlen(a->word);
2407 AST_LIST_LOCK(&cfmtime_head);
2408 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
2409 /* Skip duplicates - this only works because the list is sorted by filename */
2410 if (strcmp(cfmtime->filename, prev) == 0) {
2414 /* Core configs cannot be reloaded */
2415 if (ast_strlen_zero(cfmtime->who_asked)) {
2419 if (++which > a->n && strncmp(cfmtime->filename, a->word, wordlen) == 0) {
2420 completion_value = ast_strdup(cfmtime->filename);
2424 /* Otherwise save that we've seen this filename */
2425 prev = cfmtime->filename;
2427 AST_LIST_UNLOCK(&cfmtime_head);
2429 return completion_value;
2433 return CLI_SHOWUSAGE;
2436 AST_LIST_LOCK(&cfmtime_head);
2437 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
2438 if (!strcmp(cfmtime->filename, a->argv[2])) {
2439 char *buf = alloca(strlen("module reload ") + strlen(cfmtime->who_asked) + 1);
2440 sprintf(buf, "module reload %s", cfmtime->who_asked);
2441 ast_cli_command(a->fd, buf);
2444 AST_LIST_UNLOCK(&cfmtime_head);
2449 static char *handle_cli_config_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2451 struct cache_file_mtime *cfmtime;
2455 e->command = "config list";
2457 "Usage: config list\n"
2458 " Show all modules that have loaded a configuration file\n";
2464 AST_LIST_LOCK(&cfmtime_head);
2465 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
2466 ast_cli(a->fd, "%-20.20s %-50s\n", S_OR(cfmtime->who_asked, "core"), cfmtime->filename);
2468 AST_LIST_UNLOCK(&cfmtime_head);
2473 static struct ast_cli_entry cli_config[] = {
2474 AST_CLI_DEFINE(handle_cli_core_show_config_mappings, "Display config mappings (file names to config engines)"),
2475 AST_CLI_DEFINE(handle_cli_config_reload, "Force a reload on modules using a particular configuration file"),
2476 AST_CLI_DEFINE(handle_cli_config_list, "Show all files that have loaded a configuration file"),
2479 int register_config_cli()
2481 ast_cli_register_multiple(cli_config, sizeof(cli_config) / sizeof(struct ast_cli_entry));