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;
98 static AST_LIST_HEAD_STATIC(cfmtime_head, cache_file_mtime);
101 /* comment buffers are better implemented using the ast_str_*() API */
102 #define CB_SIZE 250 /* initial size of comment buffers */
104 static void CB_ADD(struct ast_str **cb, const char *str)
106 ast_str_append(cb, 0, "%s", str);
109 static void CB_ADD_LEN(struct ast_str **cb, const char *str, int len)
111 char *s = alloca(len + 1);
112 ast_copy_string(s, str, len);
113 ast_str_append(cb, 0, "%s", str);
116 static void CB_RESET(struct ast_str *cb, struct ast_str *llb)
124 static struct ast_comment *ALLOC_COMMENT(const struct ast_str *buffer)
126 struct ast_comment *x = NULL;
127 if (buffer && buffer->used)
128 x = ast_calloc(1, sizeof(*x) + buffer->used + 1);
130 strcpy(x->cmt, buffer->str);
134 /* I need to keep track of each config file, and all its inclusions,
135 so that we can track blank lines in each */
142 static int hash_string(const void *obj, const int flags)
144 char *str = ((struct inclfile*)obj)->fname;
147 for (total=0; *str; str++) {
148 unsigned int tmp = total;
149 total <<= 1; /* multiply by 2 */
150 total += tmp; /* multiply by 3 */
151 total <<= 2; /* multiply by 12 */
152 total += tmp; /* multiply by 13 */
154 total += ((unsigned int)(*str));
161 static int hashtab_compare_strings(void *a, void *b, int flags)
163 const struct inclfile *ae = a, *be = b;
164 return !strcmp(ae->fname, be->fname) ? CMP_MATCH : 0;
167 static struct ast_config_map {
168 struct ast_config_map *next;
174 } *config_maps = NULL;
176 AST_MUTEX_DEFINE_STATIC(config_lock);
177 static struct ast_config_engine *config_engine_list;
179 #define MAX_INCLUDE_LEVEL 10
181 struct ast_category_template_instance {
182 char name[80]; /* redundant? */
183 const struct ast_category *inst;
184 AST_LIST_ENTRY(ast_category_template_instance) next;
187 struct ast_category {
189 int ignored; /*!< do not let user of the config see this category -- set by (!) after the category decl; a template */
191 char *file; /*!< the file name from whence this declaration was read */
193 AST_LIST_HEAD_NOLOCK(template_instance_list, ast_category_template_instance) template_instances;
194 struct ast_comment *precomments;
195 struct ast_comment *sameline;
196 struct ast_comment *trailing; /*!< the last object in the list will get assigned any trailing comments when EOF is hit */
197 struct ast_variable *root;
198 struct ast_variable *last;
199 struct ast_category *next;
203 struct ast_category *root;
204 struct ast_category *last;
205 struct ast_category *current;
206 struct ast_category *last_browse; /*!< used to cache the last category supplied via category_browse */
208 int max_include_level;
209 struct ast_config_include *includes; /*!< a list of inclusions, which should describe the entire tree */
212 struct ast_config_include {
213 char *include_location_file; /*!< file name in which the include occurs */
214 int include_location_lineno; /*!< lineno where include occurred */
215 int exec; /*!< set to non-zero if itsa #exec statement */
216 char *exec_file; /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
217 char *included_file; /*!< file name included */
218 int inclusion_count; /*!< if the file is included more than once, a running count thereof -- but, worry not,
219 we explode the instances and will include those-- so all entries will be unique */
220 int output; /*!< a flag to indicate if the inclusion has been output */
221 struct ast_config_include *next; /*!< ptr to next inclusion in the list */
224 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;
231 if ((variable = ast_calloc(1, name_len + val_len + fn_len + sizeof(*variable)))) {
232 char *dst = variable->stuff; /* writable space starts here */
233 variable->name = strcpy(dst, name);
235 variable->value = strcpy(dst, value);
237 variable->file = strcpy(dst, filename);
242 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)
244 /* a file should be included ONCE. Otherwise, if one of the instances is changed,
245 then all be changed. -- how do we know to include it? -- Handling modified
246 instances is possible, I'd have
247 to create a new master for each instance. */
248 struct ast_config_include *inc;
251 inc = ast_include_find(conf, included_file);
254 inc->inclusion_count++;
255 snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
256 } while (stat(real_included_file_name, &statbuf) == 0);
257 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);
259 *real_included_file_name = 0;
261 inc = ast_calloc(1,sizeof(struct ast_config_include));
262 inc->include_location_file = ast_strdup(from_file);
263 inc->include_location_lineno = from_lineno;
264 if (!ast_strlen_zero(real_included_file_name))
265 inc->included_file = ast_strdup(real_included_file_name);
267 inc->included_file = ast_strdup(included_file);
271 inc->exec_file = ast_strdup(exec_file);
273 /* attach this new struct to the conf struct */
274 inc->next = conf->includes;
275 conf->includes = inc;
280 void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
282 struct ast_config_include *incl;
283 struct ast_category *cat;
284 struct ast_variable *v;
286 int from_len = strlen(from_file);
287 int to_len = strlen(to_file);
289 if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
292 /* the manager code allows you to read in one config file, then
293 write it back out under a different name. But, the new arrangement
294 ties output lines to the file name. So, before you try to write
295 the config file to disk, better riffle thru the data and make sure
296 the file names are changed.
298 /* file names are on categories, includes (of course), and on variables. So,
299 traverse all this and swap names */
301 for (incl = conf->includes; incl; incl=incl->next) {
302 if (strcmp(incl->include_location_file,from_file) == 0) {
303 if (from_len >= to_len)
304 strcpy(incl->include_location_file, to_file);
306 free(incl->include_location_file);
307 incl->include_location_file = strdup(to_file);
311 for (cat = conf->root; cat; cat = cat->next) {
312 if (strcmp(cat->file,from_file) == 0) {
313 if (from_len >= to_len)
314 strcpy(cat->file, to_file);
317 cat->file = strdup(to_file);
320 for (v = cat->root; v; v = v->next) {
321 if (strcmp(v->file,from_file) == 0) {
322 if (from_len >= to_len)
323 strcpy(v->file, to_file);
326 v->file = strdup(to_file);
333 struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
335 struct ast_config_include *x;
336 for (x=conf->includes;x;x=x->next) {
337 if (strcmp(x->included_file,included_file) == 0)
344 void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
349 category->last->next = variable;
351 category->root = variable;
352 category->last = variable;
353 while (category->last->next)
354 category->last = category->last->next;
357 void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
359 struct ast_variable *cur = category->root;
363 if (!variable || sscanf(line, "%d", &insertline) != 1)
366 variable->next = category->root;
367 category->root = variable;
369 for (lineno = 1; lineno < insertline; lineno++) {
374 variable->next = cur->next;
375 cur->next = variable;
379 void ast_variables_destroy(struct ast_variable *v)
381 struct ast_variable *vn;
390 struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
392 struct ast_category *cat = NULL;
394 if (category && config->last_browse && (config->last_browse->name == category))
395 cat = config->last_browse;
397 cat = ast_category_get(config, category);
399 return (cat) ? cat->root : NULL;
402 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
405 tmp = ast_variable_retrieve(cfg, cat, var);
407 tmp = ast_variable_retrieve(cfg, "general", var);
412 const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
414 struct ast_variable *v;
417 for (v = ast_variable_browse(config, category); v; v = v->next) {
418 if (!strcasecmp(variable, v->name))
422 struct ast_category *cat;
424 for (cat = config->root; cat; cat = cat->next)
425 for (v = cat->root; v; v = v->next)
426 if (!strcasecmp(variable, v->name))
433 static struct ast_variable *variable_clone(const struct ast_variable *old)
435 struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
438 new->lineno = old->lineno;
439 new->object = old->object;
440 new->blanklines = old->blanklines;
441 /* TODO: clone comments? */
447 static void move_variables(struct ast_category *old, struct ast_category *new)
449 struct ast_variable *var = old->root;
452 /* we can just move the entire list in a single op */
453 ast_variable_append(new, var);
456 struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
458 struct ast_category *category;
460 if ((category = ast_calloc(1, sizeof(*category))))
461 ast_copy_string(category->name, name, sizeof(category->name));
462 category->file = strdup(in_file);
463 category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
467 static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
469 struct ast_category *cat;
471 /* try exact match first, then case-insensitive match */
472 for (cat = config->root; cat; cat = cat->next) {
473 if (cat->name == category_name && (ignored || !cat->ignored))
477 for (cat = config->root; cat; cat = cat->next) {
478 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
485 struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
487 return category_get(config, category_name, 0);
490 int ast_category_exist(const struct ast_config *config, const char *category_name)
492 return !!ast_category_get(config, category_name);
495 void ast_category_append(struct ast_config *config, struct ast_category *category)
498 config->last->next = category;
500 config->root = category;
501 category->include_level = config->include_level;
502 config->last = category;
503 config->current = category;
506 void ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
508 struct ast_category *cur_category;
512 if (!strcasecmp(config->root->name, match)) {
513 cat->next = config->root;
517 for (cur_category = config->root; cur_category; cur_category = cur_category->next) {
518 if (!strcasecmp(cur_category->next->name, match)) {
519 cat->next = cur_category->next;
520 cur_category->next = cat;
526 static void ast_destroy_comments(struct ast_category *cat)
528 struct ast_comment *n, *p;
530 for (p=cat->precomments; p; p=n) {
534 for (p=cat->sameline; p; p=n) {
538 for (p=cat->trailing; p; p=n) {
542 cat->precomments = NULL;
543 cat->sameline = NULL;
544 cat->trailing = NULL;
547 static void ast_destroy_template_list(struct ast_category *cat)
549 struct ast_category_template_instance *x;
551 while ((x = AST_LIST_REMOVE_HEAD(&cat->template_instances, next)))
555 void ast_category_destroy(struct ast_category *cat)
557 ast_variables_destroy(cat->root);
562 ast_destroy_comments(cat);
563 ast_destroy_template_list(cat);
567 static void ast_includes_destroy(struct ast_config_include *incls)
569 struct ast_config_include *incl,*inclnext;
571 for (incl=incls; incl; incl = inclnext) {
572 inclnext = incl->next;
573 if (incl->include_location_file)
574 free(incl->include_location_file);
576 free(incl->exec_file);
577 if (incl->included_file)
578 free(incl->included_file);
583 static struct ast_category *next_available_category(struct ast_category *cat)
585 for (; cat && cat->ignored; cat = cat->next);
590 /*! return the first var of a category */
591 struct ast_variable *ast_category_first(struct ast_category *cat)
593 return (cat) ? cat->root : NULL;
596 struct ast_variable *ast_category_root(struct ast_config *config, char *cat)
598 struct ast_category *category = ast_category_get(config, cat);
601 return category->root;
605 char *ast_category_browse(struct ast_config *config, const char *prev)
607 struct ast_category *cat = NULL;
609 if (prev && config->last_browse && (config->last_browse->name == prev))
610 cat = config->last_browse->next;
611 else if (!prev && config->root)
614 for (cat = config->root; cat; cat = cat->next) {
615 if (cat->name == prev) {
621 for (cat = config->root; cat; cat = cat->next) {
622 if (!strcasecmp(cat->name, prev)) {
631 cat = next_available_category(cat);
633 config->last_browse = cat;
634 return (cat) ? cat->name : NULL;
637 struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
639 struct ast_variable *v;
648 void ast_category_rename(struct ast_category *cat, const char *name)
650 ast_copy_string(cat->name, name, sizeof(cat->name));
653 static void inherit_category(struct ast_category *new, const struct ast_category *base)
655 struct ast_variable *var;
656 struct ast_category_template_instance *x = ast_calloc(1,sizeof(struct ast_category_template_instance));
658 strcpy(x->name, base->name);
660 AST_LIST_INSERT_TAIL(&new->template_instances, x, next);
661 for (var = base->root; var; var = var->next)
662 ast_variable_append(new, variable_clone(var));
665 struct ast_config *ast_config_new(void)
667 struct ast_config *config;
669 if ((config = ast_calloc(1, sizeof(*config))))
670 config->max_include_level = MAX_INCLUDE_LEVEL;
674 int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
676 struct ast_variable *cur, *prev=NULL, *curn;
680 cur = category->root;
682 if (cur->name == variable) {
684 prev->next = cur->next;
685 if (cur == category->last)
686 category->last = prev;
688 category->root = cur->next;
689 if (cur == category->last)
690 category->last = NULL;
693 ast_variables_destroy(cur);
701 cur = category->root;
704 if ((!ast_strlen_zero(line) && lineno == atoi(line)) || (ast_strlen_zero(line) && !strcasecmp(cur->name, variable) && (ast_strlen_zero(match) || !strcasecmp(cur->value, match)))) {
706 prev->next = cur->next;
707 if (cur == category->last)
708 category->last = prev;
710 category->root = cur->next;
711 if (cur == category->last)
712 category->last = NULL;
715 ast_variables_destroy(cur);
726 int ast_variable_update(struct ast_category *category, const char *variable,
727 const char *value, const char *match, unsigned int object)
729 struct ast_variable *cur, *prev=NULL, *newer=NULL;
731 for (cur = category->root; cur; prev = cur, cur = cur->next) {
732 if (strcasecmp(cur->name, variable) ||
733 (!ast_strlen_zero(match) && strcasecmp(cur->value, match)))
736 if (!(newer = ast_variable_new(variable, value, cur->file)))
739 newer->next = cur->next;
740 newer->object = cur->object || object;
744 category->root = newer;
745 if (category->last == cur)
746 category->last = newer;
749 ast_variables_destroy(cur);
757 category->root = newer;
762 int ast_category_delete(struct ast_config *cfg, const char *category)
764 struct ast_category *prev=NULL, *cat;
768 if (cat->name == category) {
770 prev->next = cat->next;
771 if (cat == cfg->last)
774 cfg->root = cat->next;
775 if (cat == cfg->last)
778 ast_category_destroy(cat);
788 if (!strcasecmp(cat->name, category)) {
790 prev->next = cat->next;
791 if (cat == cfg->last)
794 cfg->root = cat->next;
795 if (cat == cfg->last)
798 ast_category_destroy(cat);
807 int ast_category_empty(struct ast_config *cfg, const char *category)
809 struct ast_category *cat;
811 for (cat = cfg->root; cat; cat = cat->next) {
812 if (!strcasecmp(cat->name, category))
814 ast_variables_destroy(cat->root);
823 void ast_config_destroy(struct ast_config *cfg)
825 struct ast_category *cat, *catn;
830 ast_includes_destroy(cfg->includes);
836 ast_category_destroy(catn);
841 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
846 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
848 /* cast below is just to silence compiler warning about dropping "const" */
849 cfg->current = (struct ast_category *) cat;
852 enum config_cache_attribute_enum {
853 ATTRIBUTE_INCLUDE = 0,
857 static void config_cache_attribute(const char *configfile, enum config_cache_attribute_enum attrtype, const char *filename)
859 struct cache_file_mtime *cfmtime;
860 struct cache_file_include *cfinclude;
861 struct stat statbuf = { 0, };
863 /* Find our cached entry for this configuration file */
864 AST_LIST_LOCK(&cfmtime_head);
865 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
866 if (!strcmp(cfmtime->filename, configfile))
870 cfmtime = ast_calloc(1, sizeof(*cfmtime) + strlen(configfile) + 1);
872 AST_LIST_UNLOCK(&cfmtime_head);
875 AST_LIST_HEAD_INIT(&cfmtime->includes);
876 strcpy(cfmtime->filename, configfile);
877 /* Note that the file mtime is initialized to 0, i.e. 1970 */
878 AST_LIST_INSERT_TAIL(&cfmtime_head, cfmtime, list);
881 if (!stat(configfile, &statbuf))
884 cfmtime->mtime = statbuf.st_mtime;
887 case ATTRIBUTE_INCLUDE:
888 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
889 if (!strcmp(cfinclude->include, filename)) {
890 AST_LIST_UNLOCK(&cfmtime_head);
894 cfinclude = ast_calloc(1, sizeof(*cfinclude) + strlen(filename) + 1);
896 AST_LIST_UNLOCK(&cfmtime_head);
899 strcpy(cfinclude->include, filename);
900 AST_LIST_INSERT_TAIL(&cfmtime->includes, cfinclude, list);
903 cfmtime->has_exec = 1;
906 AST_LIST_UNLOCK(&cfmtime_head);
909 /*! \brief parse one line in the configuration.
911 * We can have a category header [foo](...)
912 * a directive #include / #exec
913 * or a regular line name = value
916 static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
917 char *buf, int lineno, const char *configfile, struct ast_flags flags,
918 struct ast_str *comment_buffer,
919 struct ast_str *lline_buffer,
920 const char *suggested_include_file,
921 struct ast_category **last_cat, struct ast_variable **last_var)
925 struct ast_variable *v;
926 char cmd[512], exec_file[512];
928 /* Actually parse the entry */
929 if (cur[0] == '[') { /* A category header */
930 /* format is one of the following:
931 * [foo] define a new category named 'foo'
932 * [foo](!) define a new template category named 'foo'
933 * [foo](+) append to category 'foo', error if foo does not exist.
934 * [foo](a) define a new category and inherit from template a.
935 * You can put a comma-separated list of templates and '!' and '+'
936 * between parentheses, with obvious meaning.
938 struct ast_category *newcat = NULL;
941 c = strchr(cur, ']');
943 ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
951 if (!(*cat = newcat = ast_category_new(catname, ast_strlen_zero(suggested_include_file)?configfile:suggested_include_file, lineno))) {
954 (*cat)->lineno = lineno;
959 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
960 newcat->precomments = ALLOC_COMMENT(comment_buffer);
961 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
962 newcat->sameline = ALLOC_COMMENT(lline_buffer);
963 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
964 CB_RESET(comment_buffer, lline_buffer);
966 /* If there are options or categories to inherit from, process them now */
968 if (!(cur = strchr(c, ')'))) {
969 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
973 while ((cur = strsep(&c, ","))) {
974 if (!strcasecmp(cur, "!")) {
976 } else if (!strcasecmp(cur, "+")) {
977 *cat = category_get(cfg, catname, 1);
980 ast_category_destroy(newcat);
981 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
985 move_variables(newcat, *cat);
986 ast_category_destroy(newcat);
990 struct ast_category *base;
992 base = category_get(cfg, cur, 1);
994 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
997 inherit_category(*cat, base);
1002 ast_category_append(cfg, *cat);
1003 } else if (cur[0] == '#') { /* A directive - #include or #exec */
1005 char real_inclusion_name[256];
1006 struct ast_config_include *inclu;
1007 int do_include = 0; /* otherwise, it is exec */
1011 while (*c && (*c > 32)) c++;
1014 /* Find real argument */
1015 c = ast_skip_blanks(c + 1);
1020 if (!strcasecmp(cur, "include")) {
1022 } else if (!strcasecmp(cur, "exec")) {
1023 if (!ast_opt_exec_includes) {
1024 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
1025 return 0; /* XXX is this correct ? or we should return -1 ? */
1028 ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
1029 return 0; /* XXX is this correct ? or we should return -1 ? */
1033 ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
1034 do_include ? "include" : "exec",
1035 do_include ? "filename" : "/path/to/executable",
1038 return 0; /* XXX is this correct ? or we should return -1 ? */
1041 /* Strip off leading and trailing "'s and <>'s */
1042 while ((*c == '<') || (*c == '>') || (*c == '\"')) c++;
1043 /* Get rid of leading mess */
1046 while (!ast_strlen_zero(cur)) {
1047 c = cur + strlen(cur) - 1;
1048 if ((*c == '>') || (*c == '<') || (*c == '\"'))
1053 /* #exec </path/to/executable>
1054 We create a tmp file, then we #include it, then we delete it. */
1056 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1057 config_cache_attribute(configfile, ATTRIBUTE_EXEC, NULL);
1058 snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d.%ld", (int)time(NULL), (long)pthread_self());
1059 snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
1060 ast_safe_system(cmd);
1063 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1064 config_cache_attribute(configfile, ATTRIBUTE_INCLUDE, cur);
1065 exec_file[0] = '\0';
1068 /* record this inclusion */
1069 inclu = ast_include_new(cfg, configfile, cur, !do_include, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
1071 do_include = ast_config_internal_load(cur, cfg, flags, real_inclusion_name) ? 1 : 0;
1072 if (!ast_strlen_zero(exec_file))
1075 ast_log(LOG_ERROR, "The file '%s' was listed as a #include but it does not exist.\n", cur);
1078 /* XXX otherwise what ? the default return is 0 anyways */
1081 /* Just a line (variable = value) */
1083 ast_log(LOG_WARNING,
1084 "parse error: No category context for line %d of %s\n", lineno, configfile);
1087 c = strchr(cur, '=');
1092 /* Ignore > in => */
1098 if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), *suggested_include_file ? suggested_include_file : configfile))) {
1103 /* Put and reset comments */
1105 ast_variable_append(*cat, v);
1107 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1108 v->precomments = ALLOC_COMMENT(comment_buffer);
1109 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1110 v->sameline = ALLOC_COMMENT(lline_buffer);
1111 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1112 CB_RESET(comment_buffer, lline_buffer);
1118 ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
1124 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)
1128 char *new_buf, *comment_p, *process_buf;
1131 int comment = 0, nest[MAX_NESTED_COMMENTS];
1132 struct ast_category *cat = NULL;
1134 struct stat statbuf;
1135 struct cache_file_mtime *cfmtime = NULL;
1136 struct cache_file_include *cfinclude;
1137 struct ast_variable *last_var = 0;
1138 struct ast_category *last_cat = 0;
1139 /*! Growable string buffer */
1140 struct ast_str *comment_buffer = NULL; /*!< this will be a comment collector.*/
1141 struct ast_str *lline_buffer = NULL; /*!< A buffer for stuff behind the ; */
1144 cat = ast_config_get_current_category(cfg);
1146 if (filename[0] == '/') {
1147 ast_copy_string(fn, filename, sizeof(fn));
1149 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
1152 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1153 comment_buffer = ast_str_create(CB_SIZE);
1155 lline_buffer = ast_str_create(CB_SIZE);
1156 if (!lline_buffer) {
1158 ast_free(comment_buffer);
1159 ast_log(LOG_ERROR, "Failed to initialize the comment buffer!\n");
1163 #ifdef AST_INCLUDE_GLOB
1167 globbuf.gl_offs = 0; /* initialize it to silence gcc */
1168 glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
1169 if (glob_ret == GLOB_NOSPACE)
1170 ast_log(LOG_WARNING,
1171 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
1172 else if (glob_ret == GLOB_ABORTED)
1173 ast_log(LOG_WARNING,
1174 "Glob Expansion of pattern '%s' failed: Read error\n", fn);
1176 /* loop over expanded files */
1178 for (i=0; i<globbuf.gl_pathc; i++) {
1179 ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
1182 * The following is not a loop, but just a convenient way to define a block
1183 * (using do { } while(0) ), and be able to exit from it with 'continue'
1184 * or 'break' in case of errors. Nice trick.
1187 if (stat(fn, &statbuf))
1190 if (!S_ISREG(statbuf.st_mode)) {
1191 ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
1195 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
1196 /* Find our cached entry for this configuration file */
1197 AST_LIST_LOCK(&cfmtime_head);
1198 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
1199 if (!strcmp(cfmtime->filename, fn))
1203 cfmtime = ast_calloc(1, sizeof(*cfmtime) + strlen(fn) + 1);
1206 AST_LIST_HEAD_INIT(&cfmtime->includes);
1207 strcpy(cfmtime->filename, fn);
1208 /* Note that the file mtime is initialized to 0, i.e. 1970 */
1209 AST_LIST_INSERT_TAIL(&cfmtime_head, cfmtime, list);
1213 if (cfmtime && (!cfmtime->has_exec) && (cfmtime->mtime == statbuf.st_mtime) && ast_test_flag(&flags, CONFIG_FLAG_FILEUNCHANGED)) {
1214 /* File is unchanged, what about the (cached) includes (if any)? */
1216 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
1217 /* We must glob here, because if we did not, then adding a file to globbed directory would
1218 * incorrectly cause no reload to be necessary. */
1220 #ifdef AST_INCLUDE_GLOB
1222 glob_t globbuf = { .gl_offs = 0 };
1223 glob_ret = glob(cfinclude->include, MY_GLOB_FLAGS, NULL, &globbuf);
1224 /* On error, we reparse */
1225 if (glob_ret == GLOB_NOSPACE || glob_ret == GLOB_ABORTED)
1228 /* loop over expanded files */
1230 for (j = 0; j < globbuf.gl_pathc; j++) {
1231 ast_copy_string(fn2, globbuf.gl_pathv[j], sizeof(fn2));
1233 ast_copy_string(fn2, cfinclude->include);
1235 if (config_text_file_load(NULL, NULL, fn2, NULL, flags, "") == NULL) { /* that last field needs to be looked at in this case... TODO */
1237 /* One change is enough to short-circuit and reload the whole shebang */
1240 #ifdef AST_INCLUDE_GLOB
1247 AST_LIST_UNLOCK(&cfmtime_head);
1248 return CONFIG_STATUS_FILEUNCHANGED;
1251 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1252 AST_LIST_UNLOCK(&cfmtime_head);
1254 /* If cfg is NULL, then we just want an answer */
1259 cfmtime->mtime = statbuf.st_mtime;
1261 ast_verb(2, "Parsing '%s': ", fn);
1263 if (!(f = fopen(fn, "r"))) {
1264 ast_debug(1, "No file to parse: %s\n", fn);
1265 ast_verb(2, "Not found (%s)\n", strerror(errno));
1269 /* If we get to this point, then we're loading regardless */
1270 ast_clear_flag(&flags, CONFIG_FLAG_FILEUNCHANGED);
1271 ast_debug(1, "Parsing %s\n", fn);
1272 ast_verb(2, "Found\n");
1275 if (fgets(buf, sizeof(buf), f)) {
1276 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && lline_buffer->used) {
1277 CB_ADD(&comment_buffer, lline_buffer->str); /* add the current lline buffer to the comment buffer */
1278 lline_buffer->used = 0; /* erase the lline buffer */
1287 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
1288 /* blank line? really? Can we add it to an existing comment and maybe preserve inter- and post- comment spacing? */
1289 CB_ADD(&comment_buffer, "\n"); /* add a newline to the comment buffer */
1290 continue; /* go get a new line, then */
1293 while ((comment_p = strchr(new_buf, COMMENT_META))) {
1294 if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
1295 /* Escaped semicolons aren't comments. */
1296 new_buf = comment_p + 1;
1297 } else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
1298 /* Meta-Comment start detected ";--" */
1299 if (comment < MAX_NESTED_COMMENTS) {
1301 new_buf = comment_p + 3;
1303 nest[comment-1] = lineno;
1305 ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
1307 } else if ((comment_p >= new_buf + 2) &&
1308 (*(comment_p - 1) == COMMENT_TAG) &&
1309 (*(comment_p - 2) == COMMENT_TAG)) {
1310 /* Meta-Comment end detected */
1312 new_buf = comment_p + 1;
1314 /* Back to non-comment now */
1316 /* Actually have to move what's left over the top, then continue */
1318 oldptr = process_buf + strlen(process_buf);
1319 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1320 CB_ADD(&comment_buffer, ";");
1321 CB_ADD_LEN(&comment_buffer, oldptr+1, new_buf-oldptr-1);
1324 memmove(oldptr, new_buf, strlen(new_buf) + 1);
1327 process_buf = new_buf;
1331 /* If ; is found, and we are not nested in a comment,
1332 we immediately stop all comment processing */
1333 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1334 CB_ADD(&lline_buffer, comment_p);
1337 new_buf = comment_p;
1339 new_buf = comment_p + 1;
1342 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment && !process_buf ) {
1343 CB_ADD(&comment_buffer, buf); /* the whole line is a comment, store it */
1347 char *buf = ast_strip(process_buf);
1348 if (!ast_strlen_zero(buf)) {
1349 if (process_text_line(cfg, &cat, buf, lineno, fn, flags, comment_buffer, lline_buffer, suggested_include_file, &last_cat, &last_var)) {
1357 /* end of file-- anything in a comment buffer? */
1359 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used ) {
1360 if (lline_buffer && lline_buffer->used) {
1361 CB_ADD(&comment_buffer, lline_buffer->str); /* add the current lline buffer to the comment buffer */
1362 lline_buffer->used = 0; /* erase the lline buffer */
1364 last_cat->trailing = ALLOC_COMMENT(comment_buffer);
1366 } else if (last_var) {
1367 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used ) {
1368 if (lline_buffer && lline_buffer->used) {
1369 CB_ADD(&comment_buffer, lline_buffer->str); /* add the current lline buffer to the comment buffer */
1370 lline_buffer->used = 0; /* erase the lline buffer */
1372 last_var->trailing = ALLOC_COMMENT(comment_buffer);
1375 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used) {
1376 ast_debug(1, "Nothing to attach comments to, discarded: %s\n", comment_buffer->str);
1379 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1380 CB_RESET(comment_buffer, lline_buffer);
1385 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
1387 #ifdef AST_INCLUDE_GLOB
1388 if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED)
1396 if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg->include_level == 1 && ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1398 ast_free(comment_buffer);
1400 ast_free(lline_buffer);
1401 comment_buffer = NULL;
1402 lline_buffer = NULL;
1412 /* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
1413 which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
1414 recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
1415 be shocked and mystified as to why things are not showing up in the files!
1417 Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
1418 and line number are stored for each include, plus the name of the file included, so that these statements may be
1419 included in the output files on a file_save operation.
1421 The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
1422 are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
1423 the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
1424 and a header gets added.
1426 vars and category heads are output in the order they are stored in the config file. So, if the software
1427 shuffles these at all, then the placement of #include directives might get a little mixed up, because the
1428 file/lineno data probably won't get changed.
1432 static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
1438 ast_copy_string(date, ctime(&t), sizeof(date));
1440 fprintf(f1, ";!\n");
1441 fprintf(f1, ";! Automatically generated configuration file\n");
1442 if (strcmp(configfile, fn))
1443 fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
1445 fprintf(f1, ";! Filename: %s\n", configfile);
1446 fprintf(f1, ";! Generator: %s\n", generator);
1447 fprintf(f1, ";! Creation Date: %s", date);
1448 fprintf(f1, ";!\n");
1451 static void inclfile_destroy(void *obj)
1453 const struct inclfile *o = obj;
1460 static void set_fn(char *fn, int fn_size, const char *file, const char *configfile, struct ao2_container *fileset, struct inclfile **fi)
1462 struct inclfile lookup;
1464 if (!file || file[0] == 0) {
1465 if (configfile[0] == '/')
1466 ast_copy_string(fn, configfile, fn_size);
1468 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
1469 } else if (file[0] == '/')
1470 ast_copy_string(fn, file, fn_size);
1472 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
1474 *fi = ao2_find(fileset, &lookup, OBJ_POINTER);
1476 /* set up a file scratch pad */
1477 struct inclfile *fx = ao2_alloc(sizeof(struct inclfile), inclfile_destroy);
1478 fx->fname = ast_strdup(fn);
1481 ao2_link(fileset, fx);
1485 static int count_linefeeds(char *str)
1497 static int count_linefeeds_in_comments(struct ast_comment *x)
1502 count += count_linefeeds(x->cmt);
1508 static void insert_leading_blank_lines(FILE *fp, struct inclfile *fi, struct ast_comment *precomments, int lineno)
1510 int precomment_lines = count_linefeeds_in_comments(precomments);
1513 /* I don't have to worry about those ;! comments, they are
1514 stored in the precomments, but not printed back out.
1515 I did have to make sure that comments following
1516 the ;! header comments were not also deleted in the process */
1517 for (i=fi->lineno;i<lineno - precomment_lines; i++) {
1520 fi->lineno = lineno+1; /* Advance the file lineno */
1523 int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
1527 struct ast_variable *var;
1528 struct ast_category *cat;
1529 struct ast_comment *cmt;
1530 struct ast_config_include *incl;
1532 struct ao2_container *fileset = ao2_container_alloc(180000, hash_string, hashtab_compare_strings);
1533 struct inclfile *fi = 0;
1535 /* reset all the output flags, in case this isn't our first time saving this data */
1537 for (incl=cfg->includes; incl; incl = incl->next)
1540 /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
1541 are all truncated to zero bytes and have that nice header*/
1543 for (incl=cfg->includes; incl; incl = incl->next)
1545 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*/
1548 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 */
1551 gen_header(f1, configfile, fn, generator);
1552 fclose(f1); /* this should zero out the file */
1554 ast_debug(1, "Unable to open for writing: %s\n", fn);
1555 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1557 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1562 set_fn(fn, sizeof(fn), 0, configfile, fileset, &fi); /* just set fn to absolute ver of configfile */
1564 if ((f = fopen(fn, "w+"))) {
1566 if ((f = fopen(fn, "w"))) {
1568 ast_verb(2, "Saving '%s': ", fn);
1569 gen_header(f, configfile, fn, generator);
1572 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1574 /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
1575 /* since each var, cat, and associated comments can come from any file, we have to be
1576 mobile, and open each file, print, and close it on an entry-by-entry basis */
1579 set_fn(fn, sizeof(fn), cat->file, configfile, fileset, &fi);
1583 ast_debug(1, "Unable to open for writing: %s\n", fn);
1584 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1585 ao2_ref(fileset, -1);
1589 /* dump any includes that happen before this category header */
1590 for (incl=cfg->includes; incl; incl = incl->next) {
1591 if (strcmp(incl->include_location_file, cat->file) == 0){
1592 if (cat->lineno > incl->include_location_lineno && !incl->output) {
1594 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
1596 fprintf(f,"#include \"%s\"\n", incl->included_file);
1602 insert_leading_blank_lines(f, fi, cat->precomments, cat->lineno);
1603 /* Dump section with any appropriate comment */
1604 for (cmt = cat->precomments; cmt; cmt=cmt->next) {
1605 char *cmtp = cmt->cmt;
1606 while (*cmtp == ';' && *(cmtp+1) == '!') {
1607 char *cmtp2 = strchr(cmtp+1, '\n');
1613 fprintf(f,"%s", cmtp);
1615 if (!cat->precomments)
1617 fprintf(f, "[%s]", cat->name);
1620 if (!AST_LIST_EMPTY(&cat->template_instances)) {
1621 struct ast_category_template_instance *x;
1623 AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
1624 fprintf(f,"%s",x->name);
1625 if (x != AST_LIST_LAST(&cat->template_instances))
1630 for(cmt = cat->sameline; cmt; cmt=cmt->next)
1632 fprintf(f,"%s", cmt->cmt);
1636 for (cmt = cat->trailing; cmt; cmt=cmt->next) {
1637 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
1638 fprintf(f,"%s", cmt->cmt);
1641 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1646 struct ast_category_template_instance *x;
1648 AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
1649 struct ast_variable *v;
1650 for (v = x->inst->root; v; v = v->next) {
1651 if (!strcasecmp(var->name, v->name) && !strcmp(var->value, v->value)) {
1663 set_fn(fn, sizeof(fn), var->file, configfile, fileset, &fi);
1667 ast_debug(1, "Unable to open for writing: %s\n", fn);
1668 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1669 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1671 ao2_ref(fileset, -1);
1675 /* dump any includes that happen before this category header */
1676 for (incl=cfg->includes; incl; incl = incl->next) {
1677 if (strcmp(incl->include_location_file, var->file) == 0){
1678 if (var->lineno > incl->include_location_lineno && !incl->output) {
1680 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
1682 fprintf(f,"#include \"%s\"\n", incl->included_file);
1688 insert_leading_blank_lines(f, fi, var->precomments, var->lineno);
1689 for (cmt = var->precomments; cmt; cmt=cmt->next) {
1690 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
1691 fprintf(f,"%s", cmt->cmt);
1694 fprintf(f, "%s %s %s %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
1696 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
1697 for (cmt = var->trailing; cmt; cmt=cmt->next) {
1698 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
1699 fprintf(f,"%s", cmt->cmt);
1701 if (var->blanklines) {
1702 blanklines = var->blanklines;
1703 while (blanklines--)
1708 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1716 ast_verb(2, "Saved\n");
1718 ast_debug(1, "Unable to open for writing: %s\n", fn);
1719 ast_verb(2, "Unable to write (%s)", strerror(errno));
1720 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1721 ao2_ref(fileset, -1);
1725 /* Now, for files with trailing #include/#exec statements,
1726 we have to make sure every entry is output */
1728 for (incl=cfg->includes; incl; incl = incl->next) {
1729 if (!incl->output) {
1730 /* open the respective file */
1731 set_fn(fn, sizeof(fn), incl->include_location_file, configfile, fileset, &fi);
1735 ast_debug(1, "Unable to open for writing: %s\n", fn);
1736 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
1737 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1739 ao2_ref(fileset, -1);
1743 /* output the respective include */
1745 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
1747 fprintf(f,"#include \"%s\"\n", incl->included_file);
1750 ao2_ref(fi,-1); /* we are giving up this reference to the object ptd to by fi */
1754 ao2_ref(fileset, -1); /* this should destroy the hash container */
1759 static void clear_config_maps(void)
1761 struct ast_config_map *map;
1763 ast_mutex_lock(&config_lock);
1765 while (config_maps) {
1767 config_maps = config_maps->next;
1771 ast_mutex_unlock(&config_lock);
1774 static int append_mapping(const char *name, const char *driver, const char *database, const char *table)
1776 struct ast_config_map *map;
1779 length = sizeof(*map);
1780 length += strlen(name) + 1;
1781 length += strlen(driver) + 1;
1782 length += strlen(database) + 1;
1784 length += strlen(table) + 1;
1786 if (!(map = ast_calloc(1, length)))
1789 map->name = map->stuff;
1790 strcpy(map->name, name);
1791 map->driver = map->name + strlen(map->name) + 1;
1792 strcpy(map->driver, driver);
1793 map->database = map->driver + strlen(map->driver) + 1;
1794 strcpy(map->database, database);
1796 map->table = map->database + strlen(map->database) + 1;
1797 strcpy(map->table, table);
1799 map->next = config_maps;
1801 ast_verb(2, "Binding %s to %s/%s/%s\n", map->name, map->driver, map->database, map->table ? map->table : map->name);
1807 int read_config_maps(void)
1809 struct ast_config *config, *configtmp;
1810 struct ast_variable *v;
1811 char *driver, *table, *database, *stringp, *tmp;
1812 struct ast_flags flags = { 0 };
1814 clear_config_maps();
1816 configtmp = ast_config_new();
1817 configtmp->max_include_level = 1;
1818 config = ast_config_internal_load(extconfig_conf, configtmp, flags, "");
1820 ast_config_destroy(configtmp);
1824 for (v = ast_variable_browse(config, "settings"); v; v = v->next) {
1826 ast_copy_string(buf, v->value, sizeof(buf));
1828 driver = strsep(&stringp, ",");
1830 if ((tmp = strchr(stringp, '\"')))
1833 /* check if the database text starts with a double quote */
1834 if (*stringp == '"') {
1836 database = strsep(&stringp, "\"");
1837 strsep(&stringp, ",");
1839 /* apparently this text has no quotes */
1840 database = strsep(&stringp, ",");
1843 table = strsep(&stringp, ",");
1845 if (!strcmp(v->name, extconfig_conf)) {
1846 ast_log(LOG_WARNING, "Cannot bind '%s'!\n", extconfig_conf);
1850 if (!strcmp(v->name, "asterisk.conf")) {
1851 ast_log(LOG_WARNING, "Cannot bind 'asterisk.conf'!\n");
1855 if (!strcmp(v->name, "logger.conf")) {
1856 ast_log(LOG_WARNING, "Cannot bind 'logger.conf'!\n");
1860 if (!driver || !database)
1862 if (!strcasecmp(v->name, "sipfriends")) {
1863 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");
1864 append_mapping("sipusers", driver, database, table ? table : "sipfriends");
1865 append_mapping("sippeers", driver, database, table ? table : "sipfriends");
1866 } else if (!strcasecmp(v->name, "iaxfriends")) {
1867 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");
1868 append_mapping("iaxusers", driver, database, table ? table : "iaxfriends");
1869 append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends");
1871 append_mapping(v->name, driver, database, table);
1874 ast_config_destroy(config);
1878 int ast_config_engine_register(struct ast_config_engine *new)
1880 struct ast_config_engine *ptr;
1882 ast_mutex_lock(&config_lock);
1884 if (!config_engine_list) {
1885 config_engine_list = new;
1887 for (ptr = config_engine_list; ptr->next; ptr=ptr->next);
1891 ast_mutex_unlock(&config_lock);
1892 ast_log(LOG_NOTICE,"Registered Config Engine %s\n", new->name);
1897 int ast_config_engine_deregister(struct ast_config_engine *del)
1899 struct ast_config_engine *ptr, *last=NULL;
1901 ast_mutex_lock(&config_lock);
1903 for (ptr = config_engine_list; ptr; ptr=ptr->next) {
1906 last->next = ptr->next;
1908 config_engine_list = ptr->next;
1914 ast_mutex_unlock(&config_lock);
1919 /*! \brief Find realtime engine for realtime family */
1920 static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
1922 struct ast_config_engine *eng, *ret = NULL;
1923 struct ast_config_map *map;
1925 ast_mutex_lock(&config_lock);
1927 for (map = config_maps; map; map = map->next) {
1928 if (!strcasecmp(family, map->name)) {
1930 ast_copy_string(database, map->database, dbsiz);
1932 ast_copy_string(table, map->table ? map->table : family, tabsiz);
1937 /* Check if the required driver (engine) exist */
1939 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
1940 if (!strcasecmp(eng->name, map->driver))
1945 ast_mutex_unlock(&config_lock);
1947 /* if we found a mapping, but the engine is not available, then issue a warning */
1949 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
1954 static struct ast_config_engine text_file_engine = {
1956 .load_func = config_text_file_load,
1959 struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, struct ast_flags flags, const char *suggested_include_file)
1963 struct ast_config_engine *loader = &text_file_engine;
1964 struct ast_config *result;
1966 /* The config file itself bumps include_level by 1 */
1967 if (cfg->max_include_level > 0 && cfg->include_level == cfg->max_include_level + 1) {
1968 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
1972 cfg->include_level++;
1974 if (strcmp(filename, extconfig_conf) && strcmp(filename, "asterisk.conf") && config_engine_list) {
1975 struct ast_config_engine *eng;
1977 eng = find_engine(filename, db, sizeof(db), table, sizeof(table));
1980 if (eng && eng->load_func) {
1983 eng = find_engine("global", db, sizeof(db), table, sizeof(table));
1984 if (eng && eng->load_func)
1989 result = loader->load_func(db, table, filename, cfg, flags, suggested_include_file);
1991 if (result && result != CONFIG_STATUS_FILEUNCHANGED)
1992 result->include_level--;
1994 cfg->include_level--;
1999 struct ast_config *ast_config_load(const char *filename, struct ast_flags flags)
2001 struct ast_config *cfg;
2002 struct ast_config *result;
2004 cfg = ast_config_new();
2008 result = ast_config_internal_load(filename, cfg, flags, "");
2009 if (!result || result == CONFIG_STATUS_FILEUNCHANGED)
2010 ast_config_destroy(cfg);
2015 static struct ast_variable *ast_load_realtime_helper(const char *family, va_list ap)
2017 struct ast_config_engine *eng;
2020 struct ast_variable *res=NULL;
2022 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2023 if (eng && eng->realtime_func)
2024 res = eng->realtime_func(db, table, ap);
2029 struct ast_variable *ast_load_realtime_all(const char *family, ...)
2031 struct ast_variable *res;
2034 va_start(ap, family);
2035 res = ast_load_realtime_helper(family, ap);
2041 struct ast_variable *ast_load_realtime(const char *family, ...)
2043 struct ast_variable *res, *cur, *prev = NULL, *freeme = NULL;
2046 va_start(ap, family);
2047 res = ast_load_realtime_helper(family, ap);
2050 /* Eliminate blank entries */
2051 for (cur = res; cur; cur = cur->next) {
2057 if (ast_strlen_zero(cur->value)) {
2059 prev->next = cur->next;
2070 /*! \brief Check if realtime engine is configured for family */
2071 int ast_check_realtime(const char *family)
2073 struct ast_config_engine *eng;
2075 eng = find_engine(family, NULL, 0, NULL, 0);
2081 /*! \brief Check if there's any realtime engines loaded */
2082 int ast_realtime_enabled()
2084 return config_maps ? 1 : 0;
2087 struct ast_config *ast_load_realtime_multientry(const char *family, ...)
2089 struct ast_config_engine *eng;
2092 struct ast_config *res=NULL;
2095 va_start(ap, family);
2096 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2097 if (eng && eng->realtime_multi_func)
2098 res = eng->realtime_multi_func(db, table, ap);
2104 int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
2106 struct ast_config_engine *eng;
2112 va_start(ap, lookup);
2113 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2114 if (eng && eng->update_func)
2115 res = eng->update_func(db, table, keyfield, lookup, ap);
2121 int ast_store_realtime(const char *family, ...) {
2122 struct ast_config_engine *eng;
2128 va_start(ap, family);
2129 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2130 if (eng && eng->store_func)
2131 res = eng->store_func(db, table, ap);
2137 int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...) {
2138 struct ast_config_engine *eng;
2144 va_start(ap, lookup);
2145 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
2146 if (eng && eng->destroy_func)
2147 res = eng->destroy_func(db, table, keyfield, lookup, ap);
2153 /*! \brief Helper function to parse arguments
2154 * See documentation in config.h
2156 int ast_parse_arg(const char *arg, enum ast_parse_flags flags,
2157 void *p_result, ...)
2162 va_start(ap, p_result);
2163 switch (flags & PARSE_TYPE) {
2166 int32_t *result = p_result;
2167 int32_t x, def = result ? *result : 0,
2168 high = (int32_t)0x7fffffff,
2169 low = (int32_t)0x80000000;
2170 /* optional argument: first default value, then range */
2171 if (flags & PARSE_DEFAULT)
2172 def = va_arg(ap, int32_t);
2173 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
2174 /* range requested, update bounds */
2175 low = va_arg(ap, int32_t);
2176 high = va_arg(ap, int32_t);
2178 x = strtol(arg, NULL, 0);
2179 error = (x < low) || (x > high);
2180 if (flags & PARSE_OUT_RANGE)
2183 *result = error ? def : x;
2185 "extract int from [%s] in [%d, %d] gives [%d](%d)\n",
2187 result ? *result : x, error);
2193 uint32_t *result = p_result;
2194 uint32_t x, def = result ? *result : 0,
2195 low = 0, high = (uint32_t)~0;
2196 /* optional argument: first default value, then range */
2197 if (flags & PARSE_DEFAULT)
2198 def = va_arg(ap, uint32_t);
2199 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
2200 /* range requested, update bounds */
2201 low = va_arg(ap, uint32_t);
2202 high = va_arg(ap, uint32_t);
2204 x = strtoul(arg, NULL, 0);
2205 error = (x < low) || (x > high);
2206 if (flags & PARSE_OUT_RANGE)
2209 *result = error ? def : x;
2211 "extract uint from [%s] in [%u, %u] gives [%u](%d)\n",
2213 result ? *result : x, error);
2219 double *result = p_result;
2220 double x, def = result ? *result : 0,
2221 low = -HUGE_VAL, high = HUGE_VAL;
2223 /* optional argument: first default value, then range */
2224 if (flags & PARSE_DEFAULT)
2225 def = va_arg(ap, double);
2226 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
2227 /* range requested, update bounds */
2228 low = va_arg(ap, double);
2229 high = va_arg(ap, double);
2231 x = strtod(arg, NULL);
2232 error = (x < low) || (x > high);
2233 if (flags & PARSE_OUT_RANGE)
2236 *result = error ? def : x;
2238 "extract double from [%s] in [%f, %f] gives [%f](%d)\n",
2240 result ? *result : x, error);
2246 struct sockaddr_in _sa_buf; /* buffer for the result */
2247 struct sockaddr_in *sa = p_result ?
2248 (struct sockaddr_in *)p_result : &_sa_buf;
2249 /* default is either the supplied value or the result itself */
2250 struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
2251 va_arg(ap, struct sockaddr_in *) : sa;
2253 struct ast_hostent ahp;
2255 bzero(&_sa_buf, sizeof(_sa_buf)); /* clear buffer */
2256 /* duplicate the string to strip away the :port */
2257 port = ast_strdupa(arg);
2258 buf = strsep(&port, ":");
2259 sa->sin_family = AF_INET; /* assign family */
2261 * honor the ports flag setting, assign default value
2262 * in case of errors or field unset.
2264 flags &= PARSE_PORT_MASK; /* the only flags left to process */
2266 if (flags == PARSE_PORT_FORBID) {
2267 error = 1; /* port was forbidden */
2268 sa->sin_port = def->sin_port;
2269 } else if (flags == PARSE_PORT_IGNORE)
2270 sa->sin_port = def->sin_port;
2271 else /* accept or require */
2272 sa->sin_port = htons(strtol(port, NULL, 0));
2274 sa->sin_port = def->sin_port;
2275 if (flags == PARSE_PORT_REQUIRE)
2278 /* Now deal with host part, even if we have errors before. */
2279 hp = ast_gethostbyname(buf, &ahp);
2280 if (hp) /* resolved successfully */
2281 memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
2284 sa->sin_addr = def->sin_addr;
2287 "extract inaddr from [%s] gives [%s:%d](%d)\n",
2288 arg, ast_inet_ntoa(sa->sin_addr),
2289 ntohs(sa->sin_port), error);
2297 static char *handle_cli_core_show_config_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2299 struct ast_config_engine *eng;
2300 struct ast_config_map *map;
2304 e->command = "core show config mappings";
2306 "Usage: core show config mappings\n"
2307 " Shows the filenames to config engines.\n";
2313 ast_mutex_lock(&config_lock);
2315 if (!config_engine_list) {
2316 ast_cli(a->fd, "No config mappings found.\n");
2318 ast_cli(a->fd, "\n\n");
2319 for (eng = config_engine_list; eng; eng = eng->next) {
2320 ast_cli(a->fd, "\nConfig Engine: %s\n", eng->name);
2321 for (map = config_maps; map; map = map->next) {
2322 if (!strcasecmp(map->driver, eng->name)) {
2323 ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
2324 map->table ? map->table : map->name);
2328 ast_cli(a->fd,"\n\n");
2331 ast_mutex_unlock(&config_lock);
2336 static struct ast_cli_entry cli_config[] = {
2337 AST_CLI_DEFINE(handle_cli_core_show_config_mappings, "Display config mappings (file names to config engines)"),
2340 int register_config_cli()
2342 ast_cli_register_multiple(cli_config, sizeof(cli_config) / sizeof(struct ast_cli_entry));