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 #include "asterisk/config.h"
43 #include "asterisk/cli.h"
44 #include "asterisk/lock.h"
45 #include "asterisk/utils.h"
46 #include "asterisk/channel.h"
47 #include "asterisk/app.h"
48 #include "asterisk/astobj2.h"
49 #include "asterisk/strings.h" /* for the ast_str_*() API */
51 #define MAX_NESTED_COMMENTS 128
52 #define COMMENT_START ";--"
53 #define COMMENT_END "--;"
54 #define COMMENT_META ';'
55 #define COMMENT_TAG '-'
57 static char *extconfig_conf = "extconfig.conf";
60 /*! \brief Structure to keep comments for rewriting configuration files */
62 struct ast_comment *next;
66 /*! \brief Hold the mtime for config files, so if we don't need to reread our config, don't. */
67 struct cache_file_include {
68 AST_LIST_ENTRY(cache_file_include) list;
72 struct cache_file_mtime {
73 AST_LIST_ENTRY(cache_file_mtime) list;
74 AST_LIST_HEAD(includes, cache_file_include) includes;
75 unsigned int has_exec:1;
81 static AST_LIST_HEAD_STATIC(cfmtime_head, cache_file_mtime);
83 static int init_appendbuf(void *data)
85 struct ast_str **str = data;
86 *str = ast_str_create(16);
90 AST_THREADSTORAGE_CUSTOM(appendbuf, init_appendbuf, ast_free_ptr);
92 /* comment buffers are better implemented using the ast_str_*() API */
93 #define CB_SIZE 250 /* initial size of comment buffers */
95 static void CB_ADD(struct ast_str **cb, const char *str)
97 ast_str_append(cb, 0, "%s", str);
100 static void CB_ADD_LEN(struct ast_str **cb, const char *str, int len)
102 char *s = alloca(len + 1);
103 ast_copy_string(s, str, len);
104 ast_str_append(cb, 0, "%s", str);
107 static void CB_RESET(struct ast_str *cb, struct ast_str *llb)
117 static struct ast_comment *ALLOC_COMMENT(struct ast_str *buffer)
119 struct ast_comment *x = NULL;
120 if (!buffer || !ast_str_strlen(buffer)) {
123 if ((x = ast_calloc(1, sizeof(*x) + ast_str_strlen(buffer) + 1))) {
124 strcpy(x->cmt, ast_str_buffer(buffer)); /* SAFE */
129 /* I need to keep track of each config file, and all its inclusions,
130 so that we can track blank lines in each */
137 static int hash_string(const void *obj, const int flags)
139 char *str = ((struct inclfile *) obj)->fname;
142 for (total = 0; *str; str++) {
143 unsigned int tmp = total;
144 total <<= 1; /* multiply by 2 */
145 total += tmp; /* multiply by 3 */
146 total <<= 2; /* multiply by 12 */
147 total += tmp; /* multiply by 13 */
149 total += ((unsigned int) (*str));
157 static int hashtab_compare_strings(void *a, void *b, int flags)
159 const struct inclfile *ae = a, *be = b;
160 return !strcmp(ae->fname, be->fname) ? CMP_MATCH | CMP_STOP : 0;
163 static struct ast_config_map {
164 struct ast_config_map *next;
170 } *config_maps = NULL;
172 AST_MUTEX_DEFINE_STATIC(config_lock);
173 static struct ast_config_engine *config_engine_list;
175 #define MAX_INCLUDE_LEVEL 10
177 struct ast_category_template_instance {
178 char name[80]; /* redundant? */
179 const struct ast_category *inst;
180 AST_LIST_ENTRY(ast_category_template_instance) next;
183 struct ast_category {
185 int ignored; /*!< do not let user of the config see this category -- set by (!) after the category decl; a template */
187 char *file; /*!< the file name from whence this declaration was read */
189 AST_LIST_HEAD_NOLOCK(template_instance_list, ast_category_template_instance) template_instances;
190 struct ast_comment *precomments;
191 struct ast_comment *sameline;
192 struct ast_comment *trailing; /*!< the last object in the list will get assigned any trailing comments when EOF is hit */
193 struct ast_variable *root;
194 struct ast_variable *last;
195 struct ast_category *next;
199 struct ast_category *root;
200 struct ast_category *last;
201 struct ast_category *current;
202 struct ast_category *last_browse; /*!< used to cache the last category supplied via category_browse */
204 int max_include_level;
205 struct ast_config_include *includes; /*!< a list of inclusions, which should describe the entire tree */
208 struct ast_config_include {
209 char *include_location_file; /*!< file name in which the include occurs */
210 int include_location_lineno; /*!< lineno where include occurred */
211 int exec; /*!< set to non-zero if itsa #exec statement */
212 char *exec_file; /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
213 char *included_file; /*!< file name included */
214 int inclusion_count; /*!< if the file is included more than once, a running count thereof -- but, worry not,
215 we explode the instances and will include those-- so all entries will be unique */
216 int output; /*!< a flag to indicate if the inclusion has been output */
217 struct ast_config_include *next; /*!< ptr to next inclusion in the list */
221 struct ast_variable *_ast_variable_new(const char *name, const char *value, const char *filename, const char *file, const char *func, int lineno)
223 struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
226 struct ast_variable *variable;
227 int name_len = strlen(name) + 1;
228 int val_len = strlen(value) + 1;
229 int fn_len = strlen(filename) + 1;
232 if ((variable = __ast_calloc(1, name_len + val_len + fn_len + sizeof(*variable), file, lineno, func))) {
234 if ((variable = ast_calloc(1, name_len + val_len + fn_len + sizeof(*variable)))) {
236 char *dst = variable->stuff; /* writable space starts here */
237 variable->name = strcpy(dst, name);
239 variable->value = strcpy(dst, value);
241 variable->file = strcpy(dst, filename);
246 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)
248 /* a file should be included ONCE. Otherwise, if one of the instances is changed,
249 * then all be changed. -- how do we know to include it? -- Handling modified
250 * instances is possible, I'd have
251 * to create a new master for each instance. */
252 struct ast_config_include *inc;
255 inc = ast_include_find(conf, included_file);
258 inc->inclusion_count++;
259 snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
260 } while (stat(real_included_file_name, &statbuf) == 0);
261 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);
263 *real_included_file_name = 0;
265 inc = ast_calloc(1,sizeof(struct ast_config_include));
266 inc->include_location_file = ast_strdup(from_file);
267 inc->include_location_lineno = from_lineno;
268 if (!ast_strlen_zero(real_included_file_name))
269 inc->included_file = ast_strdup(real_included_file_name);
271 inc->included_file = ast_strdup(included_file);
275 inc->exec_file = ast_strdup(exec_file);
277 /* attach this new struct to the conf struct */
278 inc->next = conf->includes;
279 conf->includes = inc;
284 void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
286 struct ast_config_include *incl;
287 struct ast_category *cat;
288 struct ast_variable *v;
290 int from_len = strlen(from_file);
291 int to_len = strlen(to_file);
293 if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
296 /* the manager code allows you to read in one config file, then
297 * write it back out under a different name. But, the new arrangement
298 * ties output lines to the file name. So, before you try to write
299 * the config file to disk, better riffle thru the data and make sure
300 * the file names are changed.
302 /* file names are on categories, includes (of course), and on variables. So,
303 * traverse all this and swap names */
305 for (incl = conf->includes; incl; incl=incl->next) {
306 if (strcmp(incl->include_location_file,from_file) == 0) {
307 if (from_len >= to_len)
308 strcpy(incl->include_location_file, to_file);
310 free(incl->include_location_file);
311 incl->include_location_file = strdup(to_file);
315 for (cat = conf->root; cat; cat = cat->next) {
316 if (strcmp(cat->file,from_file) == 0) {
317 if (from_len >= to_len)
318 strcpy(cat->file, to_file);
321 cat->file = strdup(to_file);
324 for (v = cat->root; v; v = v->next) {
325 if (strcmp(v->file,from_file) == 0) {
326 if (from_len >= to_len)
327 strcpy(v->file, to_file);
330 v->file = strdup(to_file);
337 struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
339 struct ast_config_include *x;
340 for (x=conf->includes;x;x=x->next) {
341 if (strcmp(x->included_file,included_file) == 0)
348 void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
353 category->last->next = variable;
355 category->root = variable;
356 category->last = variable;
357 while (category->last->next)
358 category->last = category->last->next;
361 void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
363 struct ast_variable *cur = category->root;
367 if (!variable || sscanf(line, "%30d", &insertline) != 1) {
371 variable->next = category->root;
372 category->root = variable;
374 for (lineno = 1; lineno < insertline; lineno++) {
380 variable->next = cur->next;
381 cur->next = variable;
385 static void ast_comment_destroy(struct ast_comment **comment)
387 struct ast_comment *n, *p;
389 for (p = *comment; p; p = n) {
397 void ast_variables_destroy(struct ast_variable *v)
399 struct ast_variable *vn;
404 ast_comment_destroy(&vn->precomments);
405 ast_comment_destroy(&vn->sameline);
406 ast_comment_destroy(&vn->trailing);
411 struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
413 struct ast_category *cat = NULL;
415 if (category && config->last_browse && (config->last_browse->name == category)) {
416 cat = config->last_browse;
418 cat = ast_category_get(config, category);
421 return (cat) ? cat->root : NULL;
424 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
427 tmp = ast_variable_retrieve(cfg, cat, var);
429 tmp = ast_variable_retrieve(cfg, "general", var);
435 const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
437 struct ast_variable *v;
440 for (v = ast_variable_browse(config, category); v; v = v->next) {
441 if (!strcasecmp(variable, v->name)) {
446 struct ast_category *cat;
448 for (cat = config->root; cat; cat = cat->next) {
449 for (v = cat->root; v; v = v->next) {
450 if (!strcasecmp(variable, v->name)) {
460 static struct ast_variable *variable_clone(const struct ast_variable *old)
462 struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
465 new->lineno = old->lineno;
466 new->object = old->object;
467 new->blanklines = old->blanklines;
468 /* TODO: clone comments? */
474 static void move_variables(struct ast_category *old, struct ast_category *new)
476 struct ast_variable *var = old->root;
479 /* we can just move the entire list in a single op */
480 ast_variable_append(new, var);
483 struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
485 struct ast_category *category;
487 if ((category = ast_calloc(1, sizeof(*category))))
488 ast_copy_string(category->name, name, sizeof(category->name));
489 category->file = strdup(in_file);
490 category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
494 static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
496 struct ast_category *cat;
498 /* try exact match first, then case-insensitive match */
499 for (cat = config->root; cat; cat = cat->next) {
500 if (cat->name == category_name && (ignored || !cat->ignored))
504 for (cat = config->root; cat; cat = cat->next) {
505 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
512 struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
514 return category_get(config, category_name, 0);
517 int ast_category_exist(const struct ast_config *config, const char *category_name)
519 return !!ast_category_get(config, category_name);
522 void ast_category_append(struct ast_config *config, struct ast_category *category)
525 config->last->next = category;
527 config->root = category;
528 category->include_level = config->include_level;
529 config->last = category;
530 config->current = category;
533 void ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
535 struct ast_category *cur_category;
539 if (!strcasecmp(config->root->name, match)) {
540 cat->next = config->root;
544 for (cur_category = config->root; cur_category; cur_category = cur_category->next) {
545 if (!strcasecmp(cur_category->next->name, match)) {
546 cat->next = cur_category->next;
547 cur_category->next = cat;
553 static void ast_destroy_template_list(struct ast_category *cat)
555 struct ast_category_template_instance *x;
557 while ((x = AST_LIST_REMOVE_HEAD(&cat->template_instances, next)))
561 void ast_category_destroy(struct ast_category *cat)
563 ast_variables_destroy(cat->root);
568 ast_comment_destroy(&cat->precomments);
569 ast_comment_destroy(&cat->sameline);
570 ast_comment_destroy(&cat->trailing);
571 ast_destroy_template_list(cat);
575 static void ast_includes_destroy(struct ast_config_include *incls)
577 struct ast_config_include *incl,*inclnext;
579 for (incl=incls; incl; incl = inclnext) {
580 inclnext = incl->next;
581 if (incl->include_location_file)
582 free(incl->include_location_file);
584 free(incl->exec_file);
585 if (incl->included_file)
586 free(incl->included_file);
591 static struct ast_category *next_available_category(struct ast_category *cat)
593 for (; cat && cat->ignored; cat = cat->next);
598 /*! return the first var of a category */
599 struct ast_variable *ast_category_first(struct ast_category *cat)
601 return (cat) ? cat->root : NULL;
604 struct ast_variable *ast_category_root(struct ast_config *config, char *cat)
606 struct ast_category *category = ast_category_get(config, cat);
609 return category->root;
613 char *ast_category_browse(struct ast_config *config, const char *prev)
615 struct ast_category *cat = NULL;
617 if (prev && config->last_browse && (config->last_browse->name == prev))
618 cat = config->last_browse->next;
619 else if (!prev && config->root)
622 for (cat = config->root; cat; cat = cat->next) {
623 if (cat->name == prev) {
629 for (cat = config->root; cat; cat = cat->next) {
630 if (!strcasecmp(cat->name, prev)) {
639 cat = next_available_category(cat);
641 config->last_browse = cat;
642 return (cat) ? cat->name : NULL;
645 struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
647 struct ast_variable *v;
656 void ast_category_rename(struct ast_category *cat, const char *name)
658 ast_copy_string(cat->name, name, sizeof(cat->name));
661 static void inherit_category(struct ast_category *new, const struct ast_category *base)
663 struct ast_variable *var;
664 struct ast_category_template_instance *x = ast_calloc(1,sizeof(struct ast_category_template_instance));
666 strcpy(x->name, base->name);
668 AST_LIST_INSERT_TAIL(&new->template_instances, x, next);
669 for (var = base->root; var; var = var->next)
670 ast_variable_append(new, variable_clone(var));
673 struct ast_config *ast_config_new(void)
675 struct ast_config *config;
677 if ((config = ast_calloc(1, sizeof(*config))))
678 config->max_include_level = MAX_INCLUDE_LEVEL;
682 int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
684 struct ast_variable *cur, *prev=NULL, *curn;
688 cur = category->root;
690 if (cur->name == variable) {
692 prev->next = cur->next;
693 if (cur == category->last)
694 category->last = prev;
696 category->root = cur->next;
697 if (cur == category->last)
698 category->last = NULL;
701 ast_variables_destroy(cur);
709 cur = category->root;
712 if ((!ast_strlen_zero(line) && lineno == atoi(line)) || (ast_strlen_zero(line) && !strcasecmp(cur->name, variable) && (ast_strlen_zero(match) || !strcasecmp(cur->value, match)))) {
714 prev->next = cur->next;
715 if (cur == category->last)
716 category->last = prev;
718 category->root = cur->next;
719 if (cur == category->last)
720 category->last = NULL;
723 ast_variables_destroy(cur);
734 int ast_variable_update(struct ast_category *category, const char *variable,
735 const char *value, const char *match, unsigned int object)
737 struct ast_variable *cur, *prev=NULL, *newer=NULL;
739 for (cur = category->root; cur; prev = cur, cur = cur->next) {
740 if (strcasecmp(cur->name, variable) ||
741 (!ast_strlen_zero(match) && strcasecmp(cur->value, match)))
744 if (!(newer = ast_variable_new(variable, value, cur->file)))
747 newer->next = cur->next;
748 newer->object = cur->object || object;
750 /* Preserve everything */
751 newer->lineno = cur->lineno;
752 newer->blanklines = cur->blanklines;
753 newer->precomments = cur->precomments; cur->precomments = NULL;
754 newer->sameline = cur->sameline; cur->sameline = NULL;
755 newer->trailing = cur->trailing; cur->trailing = NULL;
760 category->root = newer;
761 if (category->last == cur)
762 category->last = newer;
765 ast_variables_destroy(cur);
770 /* Could not find variable to update */
774 int ast_category_delete(struct ast_config *cfg, const char *category)
776 struct ast_category *prev=NULL, *cat;
780 if (cat->name == category) {
782 prev->next = cat->next;
783 if (cat == cfg->last)
786 cfg->root = cat->next;
787 if (cat == cfg->last)
790 ast_category_destroy(cat);
800 if (!strcasecmp(cat->name, category)) {
802 prev->next = cat->next;
803 if (cat == cfg->last)
806 cfg->root = cat->next;
807 if (cat == cfg->last)
810 ast_category_destroy(cat);
819 int ast_category_empty(struct ast_config *cfg, const char *category)
821 struct ast_category *cat;
823 for (cat = cfg->root; cat; cat = cat->next) {
824 if (!strcasecmp(cat->name, category))
826 ast_variables_destroy(cat->root);
835 void ast_config_destroy(struct ast_config *cfg)
837 struct ast_category *cat, *catn;
842 ast_includes_destroy(cfg->includes);
848 ast_category_destroy(catn);
853 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
858 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
860 /* cast below is just to silence compiler warning about dropping "const" */
861 cfg->current = (struct ast_category *) cat;
864 enum config_cache_attribute_enum {
865 ATTRIBUTE_INCLUDE = 0,
869 static void config_cache_attribute(const char *configfile, enum config_cache_attribute_enum attrtype, const char *filename, const char *who_asked)
871 struct cache_file_mtime *cfmtime;
872 struct cache_file_include *cfinclude;
873 struct stat statbuf = { 0, };
875 /* Find our cached entry for this configuration file */
876 AST_LIST_LOCK(&cfmtime_head);
877 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
878 if (!strcmp(cfmtime->filename, configfile) && !strcmp(cfmtime->who_asked, who_asked))
882 cfmtime = ast_calloc(1, sizeof(*cfmtime) + strlen(configfile) + 1 + strlen(who_asked) + 1);
884 AST_LIST_UNLOCK(&cfmtime_head);
887 AST_LIST_HEAD_INIT(&cfmtime->includes);
888 strcpy(cfmtime->filename, configfile);
889 cfmtime->who_asked = cfmtime->filename + strlen(configfile) + 1;
890 strcpy(cfmtime->who_asked, who_asked);
891 /* Note that the file mtime is initialized to 0, i.e. 1970 */
892 AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
895 if (!stat(configfile, &statbuf))
898 cfmtime->mtime = statbuf.st_mtime;
901 case ATTRIBUTE_INCLUDE:
902 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
903 if (!strcmp(cfinclude->include, filename)) {
904 AST_LIST_UNLOCK(&cfmtime_head);
908 cfinclude = ast_calloc(1, sizeof(*cfinclude) + strlen(filename) + 1);
910 AST_LIST_UNLOCK(&cfmtime_head);
913 strcpy(cfinclude->include, filename);
914 AST_LIST_INSERT_TAIL(&cfmtime->includes, cfinclude, list);
917 cfmtime->has_exec = 1;
920 AST_LIST_UNLOCK(&cfmtime_head);
923 /*! \brief parse one line in the configuration.
925 * We can have a category header [foo](...)
926 * a directive #include / #exec
927 * or a regular line name = value
930 static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
931 char *buf, int lineno, const char *configfile, struct ast_flags flags,
932 struct ast_str *comment_buffer,
933 struct ast_str *lline_buffer,
934 const char *suggested_include_file,
935 struct ast_category **last_cat, struct ast_variable **last_var, const char *who_asked)
939 struct ast_variable *v;
940 char cmd[512], exec_file[512];
942 /* Actually parse the entry */
943 if (cur[0] == '[') { /* A category header */
944 /* format is one of the following:
945 * [foo] define a new category named 'foo'
946 * [foo](!) define a new template category named 'foo'
947 * [foo](+) append to category 'foo', error if foo does not exist.
948 * [foo](a) define a new category and inherit from template a.
949 * You can put a comma-separated list of templates and '!' and '+'
950 * between parentheses, with obvious meaning.
952 struct ast_category *newcat = NULL;
955 c = strchr(cur, ']');
957 ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
965 if (!(*cat = newcat = ast_category_new(catname,
966 S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile),
970 (*cat)->lineno = lineno;
975 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
976 newcat->precomments = ALLOC_COMMENT(comment_buffer);
977 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
978 newcat->sameline = ALLOC_COMMENT(lline_buffer);
979 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
980 CB_RESET(comment_buffer, lline_buffer);
982 /* If there are options or categories to inherit from, process them now */
984 if (!(cur = strchr(c, ')'))) {
985 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
989 while ((cur = strsep(&c, ","))) {
990 if (!strcasecmp(cur, "!")) {
992 } else if (!strcasecmp(cur, "+")) {
993 *cat = category_get(cfg, catname, 1);
996 ast_category_destroy(newcat);
997 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
1001 move_variables(newcat, *cat);
1002 ast_category_destroy(newcat);
1006 struct ast_category *base;
1008 base = category_get(cfg, cur, 1);
1010 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
1013 inherit_category(*cat, base);
1018 ast_category_append(cfg, *cat);
1019 } else if (cur[0] == '#') { /* A directive - #include or #exec */
1021 char real_inclusion_name[256];
1022 struct ast_config_include *inclu;
1023 int do_include = 0; /* otherwise, it is exec */
1027 while (*c && (*c > 32)) {
1033 /* Find real argument */
1034 c = ast_strip(c + 1);
1041 if (!strcasecmp(cur, "include")) {
1043 } else if (!strcasecmp(cur, "exec")) {
1044 if (!ast_opt_exec_includes) {
1045 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
1046 return 0; /* XXX is this correct ? or we should return -1 ? */
1049 ast_log(LOG_WARNING, "Unknown directive '#%s' at line %d of %s\n", cur, lineno, configfile);
1050 return 0; /* XXX is this correct ? or we should return -1 ? */
1054 ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
1055 do_include ? "include" : "exec",
1056 do_include ? "filename" : "/path/to/executable",
1059 return 0; /* XXX is this correct ? or we should return -1 ? */
1063 /* Strip off leading and trailing "'s and <>'s */
1065 if ((*c == '"') || (*c == '<')) {
1066 char quote_char = *c;
1067 if (quote_char == '<') {
1071 if (*(c + strlen(c) - 1) == quote_char) {
1073 *(c + strlen(c) - 1) = '\0';
1078 /* #exec </path/to/executable>
1079 We create a tmp file, then we #include it, then we delete it. */
1081 struct timeval now = ast_tvnow();
1082 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1083 config_cache_attribute(configfile, ATTRIBUTE_EXEC, NULL, who_asked);
1084 snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d%d.%ld", (int)now.tv_sec, (int)now.tv_usec, (long)pthread_self());
1085 snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
1086 ast_safe_system(cmd);
1089 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1090 config_cache_attribute(configfile, ATTRIBUTE_INCLUDE, cur, who_asked);
1091 exec_file[0] = '\0';
1094 /* record this inclusion */
1095 inclu = ast_include_new(cfg, cfg->include_level == 1 ? "" : configfile, cur, !do_include, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
1097 do_include = ast_config_internal_load(cur, cfg, flags, real_inclusion_name, who_asked) ? 1 : 0;
1098 if (!ast_strlen_zero(exec_file))
1101 ast_log(LOG_ERROR, "The file '%s' was listed as a #include but it does not exist.\n", cur);
1104 /* XXX otherwise what ? the default return is 0 anyways */
1107 /* Just a line (variable = value) */
1110 ast_log(LOG_WARNING,
1111 "parse error: No category context for line %d of %s\n", lineno, configfile);
1114 c = strchr(cur, '=');
1116 if (c && c > cur && (*(c - 1) == '+')) {
1117 struct ast_variable *var, *replace = NULL;
1118 struct ast_str **str = ast_threadstorage_get(&appendbuf, sizeof(*str));
1120 if (!str || !*str) {
1126 cur = ast_strip(cur);
1128 /* Must iterate through category until we find last variable of same name (since there could be multiple) */
1129 for (var = ast_category_first(*cat); var; var = var->next) {
1130 if (!strcmp(var->name, cur)) {
1136 /* Nothing to replace; just set a variable normally. */
1137 goto set_new_variable;
1140 ast_str_set(str, 0, "%s", replace->value);
1141 ast_str_append(str, 0, "%s", c);
1142 ast_str_trim_blanks(*str);
1143 ast_variable_update(*cat, replace->name, ast_skip_blanks(ast_str_buffer(*str)), replace->value, object);
1147 /* Ignore > in => */
1153 if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile)))) {
1158 /* Put and reset comments */
1160 ast_variable_append(*cat, v);
1162 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1163 v->precomments = ALLOC_COMMENT(comment_buffer);
1164 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1165 v->sameline = ALLOC_COMMENT(lline_buffer);
1166 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1167 CB_RESET(comment_buffer, lline_buffer);
1173 ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
1179 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)
1182 #if defined(LOW_MEMORY)
1187 char *new_buf, *comment_p, *process_buf;
1190 int comment = 0, nest[MAX_NESTED_COMMENTS];
1191 struct ast_category *cat = NULL;
1193 struct stat statbuf;
1194 struct cache_file_mtime *cfmtime = NULL;
1195 struct cache_file_include *cfinclude;
1196 struct ast_variable *last_var = 0;
1197 struct ast_category *last_cat = 0;
1198 /*! Growable string buffer */
1199 struct ast_str *comment_buffer = NULL; /*!< this will be a comment collector.*/
1200 struct ast_str *lline_buffer = NULL; /*!< A buffer for stuff behind the ; */
1203 cat = ast_config_get_current_category(cfg);
1205 if (filename[0] == '/') {
1206 ast_copy_string(fn, filename, sizeof(fn));
1208 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
1211 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1212 comment_buffer = ast_str_create(CB_SIZE);
1214 lline_buffer = ast_str_create(CB_SIZE);
1215 if (!lline_buffer) {
1217 ast_free(comment_buffer);
1218 ast_log(LOG_ERROR, "Failed to initialize the comment buffer!\n");
1222 #ifdef AST_INCLUDE_GLOB
1226 globbuf.gl_offs = 0; /* initialize it to silence gcc */
1227 glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
1228 if (glob_ret == GLOB_NOSPACE)
1229 ast_log(LOG_WARNING,
1230 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
1231 else if (glob_ret == GLOB_ABORTED)
1232 ast_log(LOG_WARNING,
1233 "Glob Expansion of pattern '%s' failed: Read error\n", fn);
1235 /* loop over expanded files */
1237 for (i=0; i<globbuf.gl_pathc; i++) {
1238 ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
1241 * The following is not a loop, but just a convenient way to define a block
1242 * (using do { } while(0) ), and be able to exit from it with 'continue'
1243 * or 'break' in case of errors. Nice trick.
1246 if (stat(fn, &statbuf))
1249 if (!S_ISREG(statbuf.st_mode)) {
1250 ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
1254 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
1255 /* Find our cached entry for this configuration file */
1256 AST_LIST_LOCK(&cfmtime_head);
1257 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
1258 if (!strcmp(cfmtime->filename, fn) && !strcmp(cfmtime->who_asked, who_asked))
1262 cfmtime = ast_calloc(1, sizeof(*cfmtime) + strlen(fn) + 1 + strlen(who_asked) + 1);
1265 AST_LIST_HEAD_INIT(&cfmtime->includes);
1266 strcpy(cfmtime->filename, fn);
1267 cfmtime->who_asked = cfmtime->filename + strlen(fn) + 1;
1268 strcpy(cfmtime->who_asked, who_asked);
1269 /* Note that the file mtime is initialized to 0, i.e. 1970 */
1270 AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
1274 if (cfmtime && (!cfmtime->has_exec) && (cfmtime->mtime == statbuf.st_mtime) && ast_test_flag(&flags, CONFIG_FLAG_FILEUNCHANGED)) {
1275 /* File is unchanged, what about the (cached) includes (if any)? */
1277 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
1278 /* We must glob here, because if we did not, then adding a file to globbed directory would
1279 * incorrectly cause no reload to be necessary. */
1281 #ifdef AST_INCLUDE_GLOB
1283 glob_t glob_buf = { .gl_offs = 0 };
1284 glob_return = glob(cfinclude->include, MY_GLOB_FLAGS, NULL, &glob_buf);
1285 /* On error, we reparse */
1286 if (glob_return == GLOB_NOSPACE || glob_return == GLOB_ABORTED)
1289 /* loop over expanded files */
1291 for (j = 0; j < glob_buf.gl_pathc; j++) {
1292 ast_copy_string(fn2, glob_buf.gl_pathv[j], sizeof(fn2));
1294 ast_copy_string(fn2, cfinclude->include);
1296 if (config_text_file_load(NULL, NULL, fn2, NULL, flags, "", who_asked) == NULL) {
1297 /* that second-to-last field needs to be looked at in this case... TODO */
1299 /* One change is enough to short-circuit and reload the whole shebang */
1302 #ifdef AST_INCLUDE_GLOB
1309 AST_LIST_UNLOCK(&cfmtime_head);
1310 return CONFIG_STATUS_FILEUNCHANGED;
1313 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1314 AST_LIST_UNLOCK(&cfmtime_head);
1316 /* If cfg is NULL, then we just want an answer */
1321 cfmtime->mtime = statbuf.st_mtime;
1323 ast_verb(2, "Parsing '%s': ", fn);
1325 if (!(f = fopen(fn, "r"))) {
1326 ast_debug(1, "No file to parse: %s\n", fn);
1327 ast_verb(2, "Not found (%s)\n", strerror(errno));
1331 /* If we get to this point, then we're loading regardless */
1332 ast_clear_flag(&flags, CONFIG_FLAG_FILEUNCHANGED);
1333 ast_debug(1, "Parsing %s\n", fn);
1334 ast_verb(2, "Found\n");
1337 if (fgets(buf, sizeof(buf), f)) {
1338 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && ast_str_strlen(lline_buffer)) {
1339 CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
1340 ast_str_reset(lline_buffer); /* erase the lline buffer */
1349 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer) && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
1350 /* blank line? really? Can we add it to an existing comment and maybe preserve inter- and post- comment spacing? */
1351 CB_ADD(&comment_buffer, "\n"); /* add a newline to the comment buffer */
1352 continue; /* go get a new line, then */
1355 while ((comment_p = strchr(new_buf, COMMENT_META))) {
1356 if ((comment_p > new_buf) && (*(comment_p - 1) == '\\')) {
1357 /* Escaped semicolons aren't comments. */
1358 new_buf = comment_p + 1;
1359 } else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
1360 /* Meta-Comment start detected ";--" */
1361 if (comment < MAX_NESTED_COMMENTS) {
1363 new_buf = comment_p + 3;
1365 nest[comment-1] = lineno;
1367 ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
1369 } else if ((comment_p >= new_buf + 2) &&
1370 (*(comment_p - 1) == COMMENT_TAG) &&
1371 (*(comment_p - 2) == COMMENT_TAG)) {
1372 /* Meta-Comment end detected */
1374 new_buf = comment_p + 1;
1376 /* Back to non-comment now */
1378 /* Actually have to move what's left over the top, then continue */
1380 oldptr = process_buf + strlen(process_buf);
1381 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1382 CB_ADD(&comment_buffer, ";");
1383 CB_ADD_LEN(&comment_buffer, oldptr+1, new_buf-oldptr-1);
1386 memmove(oldptr, new_buf, strlen(new_buf) + 1);
1389 process_buf = new_buf;
1393 /* If ; is found, and we are not nested in a comment,
1394 we immediately stop all comment processing */
1395 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1396 CB_ADD(&lline_buffer, comment_p);
1399 new_buf = comment_p;
1401 new_buf = comment_p + 1;
1404 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment && !process_buf ) {
1405 CB_ADD(&comment_buffer, buf); /* the whole line is a comment, store it */
1409 char *buffer = ast_strip(process_buf);
1410 if (!ast_strlen_zero(buffer)) {
1411 if (process_text_line(cfg, &cat, buffer, lineno, fn, flags, comment_buffer, lline_buffer, suggested_include_file, &last_cat, &last_var, who_asked)) {
1412 cfg = CONFIG_STATUS_FILEINVALID;
1419 /* end of file-- anything in a comment buffer? */
1421 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
1422 if (lline_buffer && ast_str_strlen(lline_buffer)) {
1423 CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
1424 ast_str_reset(lline_buffer); /* erase the lline buffer */
1426 last_cat->trailing = ALLOC_COMMENT(comment_buffer);
1428 } else if (last_var) {
1429 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
1430 if (lline_buffer && ast_str_strlen(lline_buffer)) {
1431 CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
1432 ast_str_reset(lline_buffer); /* erase the lline buffer */
1434 last_var->trailing = ALLOC_COMMENT(comment_buffer);
1437 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
1438 ast_debug(1, "Nothing to attach comments to, discarded: %s\n", ast_str_buffer(comment_buffer));
1441 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1442 CB_RESET(comment_buffer, lline_buffer);
1447 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
1449 #ifdef AST_INCLUDE_GLOB
1450 if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
1459 if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID && cfg->include_level == 1 && ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1461 ast_free(comment_buffer);
1463 ast_free(lline_buffer);
1464 comment_buffer = NULL;
1465 lline_buffer = NULL;
1475 /* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
1476 which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
1477 recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
1478 be shocked and mystified as to why things are not showing up in the files!
1480 Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
1481 and line number are stored for each include, plus the name of the file included, so that these statements may be
1482 included in the output files on a file_save operation.
1484 The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
1485 are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
1486 the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
1487 and a header gets added.
1489 vars and category heads are output in the order they are stored in the config file. So, if the software
1490 shuffles these at all, then the placement of #include directives might get a little mixed up, because the
1491 file/lineno data probably won't get changed.
1495 static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
1501 ast_copy_string(date, ctime(&t), sizeof(date));
1503 fprintf(f1, ";!\n");
1504 fprintf(f1, ";! Automatically generated configuration file\n");
1505 if (strcmp(configfile, fn))
1506 fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
1508 fprintf(f1, ";! Filename: %s\n", configfile);
1509 fprintf(f1, ";! Generator: %s\n", generator);
1510 fprintf(f1, ";! Creation Date: %s", date);
1511 fprintf(f1, ";!\n");
1514 static void inclfile_destroy(void *obj)
1516 const struct inclfile *o = obj;
1523 static void set_fn(char *fn, int fn_size, const char *file, const char *configfile, struct ao2_container *fileset, struct inclfile **fi)
1525 struct inclfile lookup;
1527 if (!file || file[0] == 0) {
1528 if (configfile[0] == '/')
1529 ast_copy_string(fn, configfile, fn_size);
1531 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
1532 } else if (file[0] == '/')
1533 ast_copy_string(fn, file, fn_size);
1535 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
1537 *fi = ao2_find(fileset, &lookup, OBJ_POINTER);
1539 /* set up a file scratch pad */
1540 struct inclfile *fx = ao2_alloc(sizeof(struct inclfile), inclfile_destroy);
1541 fx->fname = ast_strdup(fn);
1544 ao2_link(fileset, fx);
1548 static int count_linefeeds(char *str)
1560 static int count_linefeeds_in_comments(struct ast_comment *x)
1565 count += count_linefeeds(x->cmt);
1571 static void insert_leading_blank_lines(FILE *fp, struct inclfile *fi, struct ast_comment *precomments, int lineno)
1573 int precomment_lines = count_linefeeds_in_comments(precomments);
1576 /* I don't have to worry about those ;! comments, they are
1577 stored in the precomments, but not printed back out.
1578 I did have to make sure that comments following
1579 the ;! header comments were not also deleted in the process */
1580 if (lineno - precomment_lines - fi->lineno < 0) { /* insertions can mess up the line numbering and produce negative numbers that mess things up */
1582 } else if (lineno == 0) {
1583 /* Line replacements also mess things up */
1585 } else if (lineno - precomment_lines - fi->lineno < 5) {
1586 /* Only insert less than 5 blank lines; if anything more occurs,
1587 * it's probably due to context deletion. */
1588 for (i = fi->lineno; i < lineno - precomment_lines; i++) {
1592 /* Deletion occurred - insert a single blank line, for separation of
1597 fi->lineno = lineno + 1; /* Advance the file lineno */
1600 int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
1602 return ast_config_text_file_save(configfile, cfg, generator);
1605 int ast_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
1609 struct ast_variable *var;
1610 struct ast_category *cat;
1611 struct ast_comment *cmt;
1612 struct ast_config_include *incl;
1614 struct ao2_container *fileset = ao2_container_alloc(180000, hash_string, hashtab_compare_strings);
1615 struct inclfile *fi = 0;
1617 /* reset all the output flags, in case this isn't our first time saving this data */
1619 for (incl=cfg->includes; incl; incl = incl->next)
1622 /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
1623 are all truncated to zero bytes and have that nice header*/
1625 for (incl=cfg->includes; incl; incl = incl->next)
1627 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*/
1630 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 */
1633 gen_header(f1, configfile, fn, generator);
1634 fclose(f1); /* this should zero out the file */
1636 ast_debug(1, "Unable to open for writing: %s\n", fn);
1637 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1639 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1644 set_fn(fn, sizeof(fn), 0, configfile, fileset, &fi); /* just set fn to absolute ver of configfile */
1646 if ((f = fopen(fn, "w+"))) {
1648 if ((f = fopen(fn, "w"))) {
1650 ast_verb(2, "Saving '%s': ", fn);
1651 gen_header(f, configfile, fn, generator);
1654 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1656 /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
1657 /* since each var, cat, and associated comments can come from any file, we have to be
1658 mobile, and open each file, print, and close it on an entry-by-entry basis */
1661 set_fn(fn, sizeof(fn), cat->file, configfile, fileset, &fi);
1665 ast_debug(1, "Unable to open for writing: %s\n", fn);
1666 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1667 ao2_ref(fileset, -1);
1671 /* dump any includes that happen before this category header */
1672 for (incl=cfg->includes; incl; incl = incl->next) {
1673 if (strcmp(incl->include_location_file, cat->file) == 0){
1674 if (cat->lineno > incl->include_location_lineno && !incl->output) {
1676 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
1678 fprintf(f,"#include \"%s\"\n", incl->included_file);
1684 insert_leading_blank_lines(f, fi, cat->precomments, cat->lineno);
1685 /* Dump section with any appropriate comment */
1686 for (cmt = cat->precomments; cmt; cmt=cmt->next) {
1687 char *cmtp = cmt->cmt;
1688 while (*cmtp == ';' && *(cmtp+1) == '!') {
1689 char *cmtp2 = strchr(cmtp+1, '\n');
1695 fprintf(f,"%s", cmtp);
1697 fprintf(f, "[%s]", cat->name);
1698 if (cat->ignored || !AST_LIST_EMPTY(&cat->template_instances)) {
1703 if (cat->ignored && !AST_LIST_EMPTY(&cat->template_instances)) {
1706 if (!AST_LIST_EMPTY(&cat->template_instances)) {
1707 struct ast_category_template_instance *x;
1708 AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
1709 fprintf(f,"%s",x->name);
1710 if (x != AST_LIST_LAST(&cat->template_instances))
1716 for(cmt = cat->sameline; cmt; cmt=cmt->next)
1718 fprintf(f,"%s", cmt->cmt);
1722 for (cmt = cat->trailing; cmt; cmt=cmt->next) {
1723 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
1724 fprintf(f,"%s", cmt->cmt);
1727 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1732 struct ast_category_template_instance *x;
1734 AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
1735 struct ast_variable *v;
1736 for (v = x->inst->root; v; v = v->next) {
1737 if (!strcasecmp(var->name, v->name) && !strcmp(var->value, v->value)) {
1749 set_fn(fn, sizeof(fn), var->file, configfile, fileset, &fi);
1753 ast_debug(1, "Unable to open for writing: %s\n", fn);
1754 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1755 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1757 ao2_ref(fileset, -1);
1761 /* dump any includes that happen before this category header */
1762 for (incl=cfg->includes; incl; incl = incl->next) {
1763 if (strcmp(incl->include_location_file, var->file) == 0){
1764 if (var->lineno > incl->include_location_lineno && !incl->output) {
1766 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
1768 fprintf(f,"#include \"%s\"\n", incl->included_file);
1774 insert_leading_blank_lines(f, fi, var->precomments, var->lineno);
1775 for (cmt = var->precomments; cmt; cmt=cmt->next) {
1776 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
1777 fprintf(f,"%s", cmt->cmt);
1780 fprintf(f, "%s %s %s %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
1782 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
1783 for (cmt = var->trailing; cmt; cmt=cmt->next) {
1784 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
1785 fprintf(f,"%s", cmt->cmt);
1787 if (var->blanklines) {
1788 blanklines = var->blanklines;
1789 while (blanklines--)
1794 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1802 ast_verb(2, "Saved\n");
1804 ast_debug(1, "Unable to open for writing: %s\n", fn);
1805 ast_verb(2, "Unable to write (%s)", strerror(errno));
1806 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1807 ao2_ref(fileset, -1);
1811 /* Now, for files with trailing #include/#exec statements,
1812 we have to make sure every entry is output */
1814 for (incl=cfg->includes; incl; incl = incl->next) {
1815 if (!incl->output) {
1816 /* open the respective file */
1817 set_fn(fn, sizeof(fn), incl->include_location_file, configfile, fileset, &fi);
1821 ast_debug(1, "Unable to open for writing: %s\n", fn);
1822 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1823 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1825 ao2_ref(fileset, -1);
1829 /* output the respective include */
1831 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
1833 fprintf(f,"#include \"%s\"\n", incl->included_file);
1836 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1840 ao2_ref(fileset, -1); /* this should destroy the hash container */
1845 static void clear_config_maps(void)
1847 struct ast_config_map *map;
1849 ast_mutex_lock(&config_lock);
1851 while (config_maps) {
1853 config_maps = config_maps->next;
1857 ast_mutex_unlock(&config_lock);
1860 static int append_mapping(const char *name, const char *driver, const char *database, const char *table)
1862 struct ast_config_map *map;
1865 length = sizeof(*map);
1866 length += strlen(name) + 1;
1867 length += strlen(driver) + 1;
1868 length += strlen(database) + 1;
1870 length += strlen(table) + 1;
1872 if (!(map = ast_calloc(1, length)))
1875 map->name = map->stuff;
1876 strcpy(map->name, name);
1877 map->driver = map->name + strlen(map->name) + 1;
1878 strcpy(map->driver, driver);
1879 map->database = map->driver + strlen(map->driver) + 1;
1880 strcpy(map->database, database);
1882 map->table = map->database + strlen(map->database) + 1;
1883 strcpy(map->table, table);
1885 map->next = config_maps;
1887 ast_verb(2, "Binding %s to %s/%s/%s\n", map->name, map->driver, map->database, map->table ? map->table : map->name);
1893 int read_config_maps(void)
1895 struct ast_config *config, *configtmp;
1896 struct ast_variable *v;
1897 char *driver, *table, *database, *stringp, *tmp;
1898 struct ast_flags flags = { 0 };
1900 clear_config_maps();
1902 configtmp = ast_config_new();
1903 configtmp->max_include_level = 1;
1904 config = ast_config_internal_load(extconfig_conf, configtmp, flags, "", "extconfig");
1905 if (config == CONFIG_STATUS_FILEINVALID) {
1907 } else if (!config) {
1908 ast_config_destroy(configtmp);
1912 for (v = ast_variable_browse(config, "settings"); v; v = v->next) {
1914 ast_copy_string(buf, v->value, sizeof(buf));
1916 driver = strsep(&stringp, ",");
1918 if ((tmp = strchr(stringp, '\"')))
1921 /* check if the database text starts with a double quote */
1922 if (*stringp == '"') {
1924 database = strsep(&stringp, "\"");
1925 strsep(&stringp, ",");
1927 /* apparently this text has no quotes */
1928 database = strsep(&stringp, ",");
1931 table = strsep(&stringp, ",");
1933 if (!strcmp(v->name, extconfig_conf)) {
1934 ast_log(LOG_WARNING, "Cannot bind '%s'!\n", extconfig_conf);
1938 if (!strcmp(v->name, "asterisk.conf")) {
1939 ast_log(LOG_WARNING, "Cannot bind 'asterisk.conf'!\n");
1943 if (!strcmp(v->name, "logger.conf")) {
1944 ast_log(LOG_WARNING, "Cannot bind 'logger.conf'!\n");
1948 if (!driver || !database)
1950 if (!strcasecmp(v->name, "sipfriends")) {
1951 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");
1952 append_mapping("sipusers", driver, database, table ? table : "sipfriends");
1953 append_mapping("sippeers", driver, database, table ? table : "sipfriends");
1954 } else if (!strcasecmp(v->name, "iaxfriends")) {
1955 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");
1956 append_mapping("iaxusers", driver, database, table ? table : "iaxfriends");
1957 append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends");
1959 append_mapping(v->name, driver, database, table);
1962 ast_config_destroy(config);
1966 int ast_config_engine_register(struct ast_config_engine *new)
1968 struct ast_config_engine *ptr;
1970 ast_mutex_lock(&config_lock);
1972 if (!config_engine_list) {
1973 config_engine_list = new;
1975 for (ptr = config_engine_list; ptr->next; ptr=ptr->next);
1979 ast_mutex_unlock(&config_lock);
1980 ast_log(LOG_NOTICE,"Registered Config Engine %s\n", new->name);
1985 int ast_config_engine_deregister(struct ast_config_engine *del)
1987 struct ast_config_engine *ptr, *last=NULL;
1989 ast_mutex_lock(&config_lock);
1991 for (ptr = config_engine_list; ptr; ptr=ptr->next) {
1994 last->next = ptr->next;
1996 config_engine_list = ptr->next;
2002 ast_mutex_unlock(&config_lock);
2007 /*! \brief Find realtime engine for realtime family */
2008 static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
2010 struct ast_config_engine *eng, *ret = NULL;
2011 struct ast_config_map *map;
2013 ast_mutex_lock(&config_lock);
2015 for (map = config_maps; map; map = map->next) {
2016 if (!strcasecmp(family, map->name)) {
2018 ast_copy_string(database, map->database, dbsiz);
2020 ast_copy_string(table, map->table ? map->table : family, tabsiz);
2025 /* Check if the required driver (engine) exist */
2027 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
2028 if (!strcasecmp(eng->name, map->driver))
2033 ast_mutex_unlock(&config_lock);
2035 /* if we found a mapping, but the engine is not available, then issue a warning */
2037 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
2042 static struct ast_config_engine text_file_engine = {
2044 .load_func = config_text_file_load,
2047 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)
2051 struct ast_config_engine *loader = &text_file_engine;
2052 struct ast_config *result;
2054 /* The config file itself bumps include_level by 1 */
2055 if (cfg->max_include_level > 0 && cfg->include_level == cfg->max_include_level + 1) {
2056 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
2060 cfg->include_level++;
2062 if (strcmp(filename, extconfig_conf) && strcmp(filename, "asterisk.conf") && config_engine_list) {
2063 struct ast_config_engine *eng;
2065 eng = find_engine(filename, db, sizeof(db), table, sizeof(table));
2068 if (eng && eng->load_func) {
2071 eng = find_engine("global", db, sizeof(db), table, sizeof(table));
2072 if (eng && eng->load_func)
2077 result = loader->load_func(db, table, filename, cfg, flags, suggested_include_file, who_asked);
2079 if (result && result != CONFIG_STATUS_FILEINVALID && result != CONFIG_STATUS_FILEUNCHANGED)
2080 result->include_level--;
2081 else if (result != CONFIG_STATUS_FILEINVALID)
2082 cfg->include_level--;
2087 struct ast_config *ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
2089 struct ast_config *cfg;
2090 struct ast_config *result;
2092 cfg = ast_config_new();
2096 result = ast_config_internal_load(filename, cfg, flags, "", who_asked);
2097 if (!result || result == CONFIG_STATUS_FILEUNCHANGED || result == CONFIG_STATUS_FILEINVALID)
2098 ast_config_destroy(cfg);
2103 static struct ast_variable *ast_load_realtime_helper(const char *family, va_list ap)
2105 struct ast_config_engine *eng;
2108 struct ast_variable *res=NULL;
2110 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2111 if (eng && eng->realtime_func)
2112 res = eng->realtime_func(db, table, ap);
2117 struct ast_variable *ast_load_realtime_all(const char *family, ...)
2119 struct ast_variable *res;
2122 va_start(ap, family);
2123 res = ast_load_realtime_helper(family, ap);
2129 struct ast_variable *ast_load_realtime(const char *family, ...)
2131 struct ast_variable *res, *cur, *prev = NULL, *freeme = NULL;
2134 va_start(ap, family);
2135 res = ast_load_realtime_helper(family, ap);
2138 /* Eliminate blank entries */
2139 for (cur = res; cur; cur = cur->next) {
2145 if (ast_strlen_zero(cur->value)) {
2147 prev->next = cur->next;
2151 } else if (cur->value[0] == ' ' && cur->value[1] == '\0') {
2152 char *vptr = (char *) cur->value;
2162 /*! \brief Check if realtime engine is configured for family */
2163 int ast_check_realtime(const char *family)
2165 struct ast_config_engine *eng;
2166 if (!ast_realtime_enabled()) {
2167 return 0; /* There are no engines at all so fail early */
2170 eng = find_engine(family, NULL, 0, NULL, 0);
2176 /*! \brief Check if there's any realtime engines loaded */
2177 int ast_realtime_enabled()
2179 return config_maps ? 1 : 0;
2182 int ast_realtime_require_field(const char *family, ...)
2184 struct ast_config_engine *eng;
2190 va_start(ap, family);
2191 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2192 if (eng && eng->require_func) {
2193 res = eng->require_func(db, table, ap);
2200 int ast_unload_realtime(const char *family)
2202 struct ast_config_engine *eng;
2207 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2208 if (eng && eng->unload_func) {
2209 res = eng->unload_func(db, table);
2214 struct ast_config *ast_load_realtime_multientry(const char *family, ...)
2216 struct ast_config_engine *eng;
2219 struct ast_config *res = NULL;
2222 va_start(ap, family);
2223 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2224 if (eng && eng->realtime_multi_func)
2225 res = eng->realtime_multi_func(db, table, ap);
2231 int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
2233 struct ast_config_engine *eng;
2239 va_start(ap, lookup);
2240 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2241 if (eng && eng->update_func)
2242 res = eng->update_func(db, table, keyfield, lookup, ap);
2248 int ast_update2_realtime(const char *family, ...)
2250 struct ast_config_engine *eng;
2256 va_start(ap, family);
2257 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2258 if (eng && eng->update2_func)
2259 res = eng->update2_func(db, table, ap);
2265 int ast_store_realtime(const char *family, ...)
2267 struct ast_config_engine *eng;
2273 va_start(ap, family);
2274 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2275 if (eng && eng->store_func)
2276 res = eng->store_func(db, table, ap);
2282 int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...)
2284 struct ast_config_engine *eng;
2290 va_start(ap, lookup);
2291 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2292 if (eng && eng->destroy_func)
2293 res = eng->destroy_func(db, table, keyfield, lookup, ap);
2299 /*! \brief Helper function to parse arguments
2300 * See documentation in config.h
2302 int ast_parse_arg(const char *arg, enum ast_parse_flags flags,
2303 void *p_result, ...)
2308 va_start(ap, p_result);
2309 switch (flags & PARSE_TYPE) {
2312 int32_t *result = p_result;
2313 int32_t x, def = result ? *result : 0,
2314 high = (int32_t)0x7fffffff,
2315 low = (int32_t)0x80000000;
2316 /* optional argument: first default value, then range */
2317 if (flags & PARSE_DEFAULT)
2318 def = va_arg(ap, int32_t);
2319 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
2320 /* range requested, update bounds */
2321 low = va_arg(ap, int32_t);
2322 high = va_arg(ap, int32_t);
2324 x = strtol(arg, NULL, 0);
2325 error = (x < low) || (x > high);
2326 if (flags & PARSE_OUT_RANGE)
2329 *result = error ? def : x;
2331 "extract int from [%s] in [%d, %d] gives [%d](%d)\n",
2333 result ? *result : x, error);
2339 uint32_t *result = p_result;
2340 uint32_t x, def = result ? *result : 0,
2341 low = 0, high = (uint32_t)~0;
2342 /* optional argument: first default value, then range */
2343 if (flags & PARSE_DEFAULT)
2344 def = va_arg(ap, uint32_t);
2345 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
2346 /* range requested, update bounds */
2347 low = va_arg(ap, uint32_t);
2348 high = va_arg(ap, uint32_t);
2350 x = strtoul(arg, NULL, 0);
2351 error = (x < low) || (x > high);
2352 if (flags & PARSE_OUT_RANGE)
2355 *result = error ? def : x;
2357 "extract uint from [%s] in [%u, %u] gives [%u](%d)\n",
2359 result ? *result : x, error);
2365 double *result = p_result;
2366 double x, def = result ? *result : 0,
2367 low = -HUGE_VAL, high = HUGE_VAL;
2369 /* optional argument: first default value, then range */
2370 if (flags & PARSE_DEFAULT)
2371 def = va_arg(ap, double);
2372 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
2373 /* range requested, update bounds */
2374 low = va_arg(ap, double);
2375 high = va_arg(ap, double);
2377 x = strtod(arg, NULL);
2378 error = (x < low) || (x > high);
2379 if (flags & PARSE_OUT_RANGE)
2382 *result = error ? def : x;
2384 "extract double from [%s] in [%f, %f] gives [%f](%d)\n",
2386 result ? *result : x, error);
2392 struct sockaddr_in _sa_buf; /* buffer for the result */
2393 struct sockaddr_in *sa = p_result ?
2394 (struct sockaddr_in *)p_result : &_sa_buf;
2395 /* default is either the supplied value or the result itself */
2396 struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
2397 va_arg(ap, struct sockaddr_in *) : sa;
2399 struct ast_hostent ahp;
2401 memset(&_sa_buf, '\0', sizeof(_sa_buf)); /* clear buffer */
2402 /* duplicate the string to strip away the :port */
2403 port = ast_strdupa(arg);
2404 buf = strsep(&port, ":");
2405 sa->sin_family = AF_INET; /* assign family */
2407 * honor the ports flag setting, assign default value
2408 * in case of errors or field unset.
2410 flags &= PARSE_PORT_MASK; /* the only flags left to process */
2412 if (flags == PARSE_PORT_FORBID) {
2413 error = 1; /* port was forbidden */
2414 sa->sin_port = def->sin_port;
2415 } else if (flags == PARSE_PORT_IGNORE)
2416 sa->sin_port = def->sin_port;
2417 else /* accept or require */
2418 sa->sin_port = htons(strtol(port, NULL, 0));
2420 sa->sin_port = def->sin_port;
2421 if (flags == PARSE_PORT_REQUIRE)
2424 /* Now deal with host part, even if we have errors before. */
2425 hp = ast_gethostbyname(buf, &ahp);
2426 if (hp) /* resolved successfully */
2427 memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
2430 sa->sin_addr = def->sin_addr;
2433 "extract inaddr from [%s] gives [%s:%d](%d)\n",
2434 arg, ast_inet_ntoa(sa->sin_addr),
2435 ntohs(sa->sin_port), error);
2443 static char *handle_cli_core_show_config_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2445 struct ast_config_engine *eng;
2446 struct ast_config_map *map;
2450 e->command = "core show config mappings";
2452 "Usage: core show config mappings\n"
2453 " Shows the filenames to config engines.\n";
2459 ast_mutex_lock(&config_lock);
2461 if (!config_engine_list) {
2462 ast_cli(a->fd, "No config mappings found.\n");
2464 ast_cli(a->fd, "\n\n");
2465 for (eng = config_engine_list; eng; eng = eng->next) {
2466 ast_cli(a->fd, "\nConfig Engine: %s\n", eng->name);
2467 for (map = config_maps; map; map = map->next) {
2468 if (!strcasecmp(map->driver, eng->name)) {
2469 ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
2470 map->table ? map->table : map->name);
2474 ast_cli(a->fd,"\n\n");
2477 ast_mutex_unlock(&config_lock);
2482 static char *handle_cli_config_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2484 struct cache_file_mtime *cfmtime;
2485 char *prev = "", *completion_value = NULL;
2486 int wordlen, which = 0;
2490 e->command = "config reload";
2492 "Usage: config reload <filename.conf>\n"
2493 " Reloads all modules that reference <filename.conf>\n";
2500 wordlen = strlen(a->word);
2502 AST_LIST_LOCK(&cfmtime_head);
2503 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
2504 /* Skip duplicates - this only works because the list is sorted by filename */
2505 if (strcmp(cfmtime->filename, prev) == 0) {
2509 /* Core configs cannot be reloaded */
2510 if (ast_strlen_zero(cfmtime->who_asked)) {
2514 if (++which > a->n && strncmp(cfmtime->filename, a->word, wordlen) == 0) {
2515 completion_value = ast_strdup(cfmtime->filename);
2519 /* Otherwise save that we've seen this filename */
2520 prev = cfmtime->filename;
2522 AST_LIST_UNLOCK(&cfmtime_head);
2524 return completion_value;
2528 return CLI_SHOWUSAGE;
2531 AST_LIST_LOCK(&cfmtime_head);
2532 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
2533 if (!strcmp(cfmtime->filename, a->argv[2])) {
2534 char *buf = alloca(strlen("module reload ") + strlen(cfmtime->who_asked) + 1);
2535 sprintf(buf, "module reload %s", cfmtime->who_asked);
2536 ast_cli_command(a->fd, buf);
2539 AST_LIST_UNLOCK(&cfmtime_head);
2544 static char *handle_cli_config_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2546 struct cache_file_mtime *cfmtime;
2550 e->command = "config list";
2552 "Usage: config list\n"
2553 " Show all modules that have loaded a configuration file\n";
2559 AST_LIST_LOCK(&cfmtime_head);
2560 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
2561 ast_cli(a->fd, "%-20.20s %-50s\n", S_OR(cfmtime->who_asked, "core"), cfmtime->filename);
2563 AST_LIST_UNLOCK(&cfmtime_head);
2568 static struct ast_cli_entry cli_config[] = {
2569 AST_CLI_DEFINE(handle_cli_core_show_config_mappings, "Display config mappings (file names to config engines)"),
2570 AST_CLI_DEFINE(handle_cli_config_reload, "Force a reload on modules using a particular configuration file"),
2571 AST_CLI_DEFINE(handle_cli_config_list, "Show all files that have loaded a configuration file"),
2574 int register_config_cli()
2576 ast_cli_register_multiple(cli_config, ARRAY_LEN(cli_config));