36 #define AST_MODULE "extconfig"
62 #define MAX_NESTED_COMMENTS 128
63 #define COMMENT_START ";--"
64 #define COMMENT_END "--;"
65 #define COMMENT_META ';'
66 #define COMMENT_TAG '-'
73 #define MIN_VARIABLE_FNAME_SPACE 40
75 static char *extconfig_conf =
"extconfig.conf";
78 static void config_hook_exec(
const char *filename,
const char *module,
const struct ast_config *cfg);
81 const char *match,
char sep);
100 unsigned int has_exec:1;
117 static
int init_appendbuf(
void *data)
121 return *str ? 0 : -1;
129 static void CB_ADD(
struct ast_str **cb,
const char *str)
134 static void CB_ADD_LEN(
struct ast_str **cb,
const char *str,
int len)
173 static int hash_string(
const void *obj,
const int flags)
175 char *str = ((
struct inclfile *) obj)->fname;
178 for (total = 0; *str; str++) {
179 unsigned int tmp = total;
185 total += ((
unsigned int) (*str));
193 static int hashtab_compare_strings(
void *a,
void *b,
int flags)
195 const struct inclfile *ae = a, *be = b;
212 } *config_maps = NULL;
214 AST_MUTEX_DEFINE_STATIC(config_lock);
217 #define MAX_INCLUDE_LEVEL 10
257 int max_include_level;
285 static void ast_variable_destroy(
struct ast_variable *doomed);
288 struct ast_variable *_ast_variable_new(
const char *name,
const char *
value,
const char *
filename,
const char *file,
const char *func,
int lineno)
291 int name_len = strlen(name) + 1;
292 int val_len = strlen(value) + 1;
293 int fn_len = strlen(filename) + 1;
300 variable = __ast_calloc(1, fn_len + name_len + val_len +
sizeof(*variable),
303 char *dst = variable->
stuff;
306 variable->
file = strcpy(dst, filename);
308 variable->
name = strcpy(dst, name);
310 variable->
value = strcpy(dst, value);
324 dst_var->lineno = src_var->lineno;
327 dst_var->precomments = src_var->precomments;
328 src_var->precomments = NULL;
329 dst_var->sameline = src_var->sameline;
330 src_var->sameline = NULL;
344 inc = ast_include_find(conf, included_file);
347 inc->inclusion_count++;
348 snprintf(real_included_file_name, real_included_file_name_size,
"%s~~%d", included_file, inc->inclusion_count);
349 }
while (stat(real_included_file_name, &statbuf) == 0);
350 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);
352 *real_included_file_name = 0;
358 inc->include_location_file =
ast_strdup(from_file);
359 inc->include_location_lineno = from_lineno;
360 if (!ast_strlen_zero(real_included_file_name))
361 inc->included_file =
ast_strdup(real_included_file_name);
363 inc->included_file =
ast_strdup(included_file);
369 if (!inc->include_location_file
370 || !inc->included_file
371 || (is_exec && !inc->exec_file)) {
372 ast_includes_destroy(inc);
383 void ast_include_rename(
struct ast_config *conf,
const char *from_file,
const char *to_file)
389 int from_len = strlen(from_file);
390 int to_len = strlen(to_file);
392 if (strcmp(from_file, to_file) == 0)
406 if (from_len >= to_len)
418 for (cat = conf->
root; cat; cat = cat->
next) {
423 if (strcmp(cat->
file,from_file) == 0) {
424 if (from_len >= to_len)
425 strcpy(cat->
file, to_file);
436 if (strcmp(v->
file, from_file)) {
445 if (to_len < v->name - v->
file) {
447 str = (
char *) v->
file;
448 strcpy(str, to_file);
453 new_var = ast_variable_new(v->
name, v->
value, to_file);
459 ast_variable_move(new_var, v);
463 if (cat->
last == v) {
468 ast_variable_destroy(v);
493 category->
root = variable;
494 category->
last = variable;
505 if (!variable || sscanf(line,
"%30d", &insertline) != 1) {
510 category->
root = variable;
512 for (lineno = 1; lineno < insertline; lineno++) {
519 cur->
next = variable;
523 static void ast_comment_destroy(
struct ast_comment **comment)
527 for (p = *comment; p; p = n) {
535 static void ast_variable_destroy(
struct ast_variable *doomed)
537 ast_comment_destroy(&doomed->precomments);
538 ast_comment_destroy(&doomed->sameline);
539 ast_comment_destroy(&doomed->
trailing);
548 if (!(cloned = ast_variable_new(var->
name, var->
value, var->
file))) {
554 while ((var = var->
next)) {
571 if (!var1 || !var1->
next) {
596 ast_variable_destroy(vn);
610 return (cat) ? cat->
root : NULL;
625 memset(&top, 0,
sizeof(top));
627 if (start != NULL && start->
next != NULL) {
632 while (p->
next != NULL) {
634 q->
next = variable_list_switch(p, p->
next);
650 ast_assert(head != NULL);
658 for (curr = sh; curr->
next; curr = curr->
next);
662 for (curr = newvar; curr->
next; curr = curr->
next);
671 for (v = *head; v; prev = &v->
next, v = v->
next) {
672 if (!strcmp(v->
name, replacement->
name)) {
688 for (v = *head; v; prev = &v->
next, v = v->
next) {
701 const char *name_value_separator,
const char *quote_char,
struct ast_str **str)
704 struct ast_str *local_str = NULL;
706 if (str == NULL || *str == NULL) {
715 for (; var; var = var->
next) {
717 var->
value,
S_OR(quote_char,
""), var->
next ? item_separator :
"");
727 const char *name_value_separator,
const char *quote_str)
739 if (ast_strlen_zero(input)) {
743 item_sep = ast_strlen_zero(item_separator) ?
',' : item_separator[0];
744 nv_sep = ast_strlen_zero(name_value_separator) ?
'=' : name_value_separator[0];
745 quote = ast_strlen_zero(quote_str) ?
'"' : quote_str[0];
757 new_var = ast_variable_new(item_name, item_value ?:
"",
"");
762 ast_variable_list_append(&new_list, new_var);
768 const char *name_value_separator)
776 tmp = ast_variable_retrieve(cfg, cat, var);
778 tmp = ast_variable_retrieve(cfg,
"general", var);
783 const char *ast_variable_retrieve(
struct ast_config *config,
const char *category,
const char *variable)
788 for (v = ast_variable_browse(config, category); v; v = v->
next) {
789 if (!strcasecmp(variable, v->
name)) {
796 for (cat = config->
root; cat; cat = cat->
next) {
797 for (v = cat->
root; v; v = v->
next) {
798 if (!strcasecmp(variable, v->
name)) {
809 const char *category,
const char *variable,
const char *
filter)
833 for (v = list; v; v = v->
next) {
834 if (!strcasecmp(variable_name, v->
name)) {
849 if (!(left && right)) {
853 op = strrchr(right->
name,
' ');
871 if (!(left && right)) {
875 for (field = right; field; field = field->
next) {
876 char *space = strrchr(field->
name,
' ');
878 char * name = (
char *)field->
name;
885 name[space - field->
name] =
'\0';
889 if (name != field->
name) {
894 if (!old || strcmp(old->
value, field->
value)) {
907 for (field = left; field; field = field->
next) {
911 if (right_count != left_count) {
923 for (v = list; v; v = v->
next) {
924 if (!strcasecmp(variable, v->
name)) {
934 const char *found = NULL;
936 for (v = list; v; v = v->
next) {
937 if (!strcasecmp(variable, v->
name)) {
949 new->lineno = old->lineno;
950 new->object = old->
object;
964 ast_variable_append(
new, var);
971 const char *match,
char sep)
975 int match_found = 0, match_expressions = 0;
979 if (!ast_strlen_zero(category_name) && strcasecmp(cat->name, category_name)) {
984 if (ast_strlen_zero(match)) {
993 char *match_value = NULL;
996 regex_t r_name, r_value;
1004 if (match_value == NULL) {
1008 if (!strcmp(
"TEMPLATES", match_name)) {
1009 if (!strcasecmp(
"include", match_value)) {
1014 }
else if (!strcasecmp(
"restrict", match_value)) {
1025 if ((rc = regcomp(&r_name, match_name, REG_EXTENDED | REG_NOSUB))) {
1027 regerror(rc, &r_name, regerr, 128);
1028 ast_log(LOG_ERROR,
"Regular expression '%s' failed to compile: %s\n",
1029 match_name, regerr);
1033 if ((rc = regcomp(&r_value, match_value, REG_EXTENDED | REG_NOSUB))) {
1035 regerror(rc, &r_value, regerr, 128);
1036 ast_log(LOG_ERROR,
"Regular expression '%s' failed to compile: %s\n",
1037 match_value, regerr);
1043 for (v = cat->
root; v; v = v->
next) {
1044 if (!regexec(&r_name, v->
name, 0, NULL, 0)
1045 && !regexec(&r_value, v->
value, 0, NULL, 0)) {
1053 if (match_found == match_expressions && (!cat->
ignored || template_ok)) {
1060 static struct ast_category *new_category(
const char *name,
const char *in_file,
int lineno,
int template)
1069 if (!category->
file) {
1070 ast_category_destroy(category);
1074 category->lineno = lineno;
1081 return new_category(name, in_file, lineno, 0);
1086 return new_category(name, in_file, lineno, 1);
1090 const char *category_name,
const char *
filter,
char sep,
char pointer_match_possible)
1094 if (pointer_match_possible) {
1095 for (cat = config->
root; cat; cat = cat->
next) {
1102 for (cat = config->
root; cat; cat = cat->
next) {
1112 const char *category_name,
const char *filter)
1114 return category_get_sep(config, category_name, filter,
',', 1);
1119 return category->name;
1143 ast_str_append(&str, 0,
"%s%s", first ?
"" :
",", template->name);
1162 config->
root = category;
1163 category->
prev = NULL;
1165 category->
next = NULL;
1166 category->include_level = config->include_level;
1168 config->
last = category;
1169 config->current = category;
1176 if (!config || !config->
root || !cat || !match) {
1180 if (!strcasecmp(config->
root->name, match)) {
1188 for (cur_category = config->
root->
next; cur_category; cur_category = cur_category->
next) {
1189 if (!strcasecmp(cur_category->name, match)) {
1193 cat->
next = cur_category;
1194 cur_category->
prev = cat;
1203 static void ast_destroy_template_list(
struct ast_category *cat)
1216 ast_comment_destroy(&cat->precomments);
1217 ast_comment_destroy(&cat->sameline);
1218 ast_comment_destroy(&cat->
trailing);
1219 ast_destroy_template_list(cat);
1220 ast_free(cat->
file);
1228 for (incl=incls; incl; incl = inclnext) {
1229 inclnext = incl->
next;
1238 const char *name,
const char *filter)
1248 return (cat) ? cat->
root : NULL;
1256 return category->
root;
1292 int nmerges, psize, qsize, i;
1301 if (!config->
root) {
1307 config->
root = NULL;
1318 for (i = 0; i < insize; i++) {
1330 while (psize > 0 || (qsize > 0 && q)) {
1337 }
else if (qsize == 0 || !q) {
1339 e = p; p = p->
next; psize--;
1340 }
else if ((comparator(p,q) * descending) <= 0) {
1395 for (cat = config->
root; cat; cat = cat->
next) {
1396 if (cat->name == prev_name) {
1407 for (cat = config->
root; cat; cat = cat->
next) {
1408 if (!strcasecmp(cat->name, prev_name)) {
1418 cat = next_available_category(cat, NULL, NULL);
1421 return (cat) ? cat->name : NULL;
1425 const char *category_name,
struct ast_category *prev,
const char *filter)
1430 prev = config->
root;
1435 cat = next_available_category(prev, category_name, filter);
1451 void ast_category_rename(
struct ast_category *cat,
const char *name)
1465 strcpy(x->name, base->name);
1468 for (var = base->
root; var; var = var->
next) {
1474 ast_variable_append(
new, cloned);
1483 if ((config =
ast_calloc(1,
sizeof(*config))))
1484 config->max_include_level = MAX_INCLUDE_LEVEL;
1488 int ast_variable_delete(
struct ast_category *category,
const char *variable,
const char *match,
const char *line)
1496 if (!ast_strlen_zero(line)) {
1498 if (sscanf(line,
"%30d", &req_item) != 1
1506 cur = category->
root;
1510 if ((0 <= req_item && num_item == req_item)
1511 || (req_item < 0 && !strcasecmp(cur->
name, variable)
1512 && (ast_strlen_zero(match) || !strcasecmp(cur->
value, match)))) {
1515 if (cur == category->
last)
1519 if (cur == category->
last)
1520 category->
last = NULL;
1522 ast_variable_destroy(cur);
1534 const char *value,
const char *match,
unsigned int object)
1538 for (cur = category->
root; cur; prev = cur, cur = cur->
next) {
1539 if (strcasecmp(cur->
name, variable) ||
1540 (!ast_strlen_zero(match) && strcasecmp(cur->
value, match)))
1543 if (!(newer = ast_variable_new(variable, value, cur->
file)))
1546 ast_variable_move(newer, cur);
1547 newer->object = newer->object || object;
1550 newer->next = cur->
next;
1554 category->
root = newer;
1555 if (category->
last == cur)
1556 category->
last = newer;
1558 ast_variable_destroy(cur);
1572 if (!config || !category) {
1576 if (category->
prev) {
1582 if (category->
next) {
1588 prev = category->
prev;
1594 ast_category_destroy(category);
1606 category->
root = NULL;
1607 category->
last = NULL;
1619 ast_includes_destroy(cfg->
includes);
1625 ast_category_destroy(catn);
1632 return cfg->current;
1657 sizeof(*cfmtime) + strlen(filename) + 1 + strlen(who_asked) + 1);
1662 strcpy(dst, filename);
1663 dst += strlen(dst) + 1;
1664 cfmtime->
who_asked = strcpy(dst, who_asked);
1669 enum config_cache_attribute_enum {
1670 ATTRIBUTE_INCLUDE = 0,
1681 static void cfmstat_save(
struct cache_file_mtime *cfmtime,
struct stat *statbuf)
1684 #if defined(HAVE_STRUCT_STAT_ST_MTIM)
1686 #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
1688 #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
1705 static int cfmstat_cmp(
struct cache_file_mtime *cfmtime,
struct stat *statbuf)
1709 cfmstat_save(&cfm_buf, statbuf);
1729 ast_free(cfinclude);
1743 config_cache_flush_includes(cfmtime);
1754 static void config_cache_remove(
const char *filename,
const char *who_asked)
1760 if (!strcmp(cfmtime->
filename, filename)
1761 && !strcmp(cfmtime->
who_asked, who_asked)) {
1763 config_cache_destroy_entry(cfmtime);
1771 static void config_cache_attribute(
const char *configfile,
enum config_cache_attribute_enum attrtype,
const char *filename,
const char *who_asked)
1779 if (!strcmp(cfmtime->
filename, configfile) && !strcmp(cfmtime->
who_asked, who_asked))
1783 cfmtime = cfmtime_new(configfile, who_asked);
1793 case ATTRIBUTE_INCLUDE:
1795 if (!strcmp(cfinclude->
include, filename)) {
1800 cfinclude =
ast_calloc(1,
sizeof(*cfinclude) + strlen(filename) + 1);
1805 strcpy(cfinclude->
include, filename);
1808 case ATTRIBUTE_EXEC:
1809 cfmtime->has_exec = 1;
1829 static int handle_include_exec(
const char *command,
const char *output_file)
1834 struct stat output_file_info;
1837 if (snprintf(buf,
sizeof(buf),
"%s 2>&1 > %s", command, output_file) >=
sizeof(buf)) {
1838 ast_log(LOG_ERROR,
"Failed to construct command string to execute %s.\n", command);
1846 fp = popen(buf,
"r");
1848 ast_log(LOG_ERROR,
"#exec <%s>: Failed to execute: %s\n",
1855 while (fgets(buf,
sizeof(buf), fp)) {
1857 if (strlen(buf) ==
sizeof(buf) - 1 && buf[
sizeof(buf) - 2] !=
'\n') {
1858 ast_log(LOG_ERROR,
"#exec <%s>: %s... <truncated>\n",
1863 while (fgets(buf,
sizeof(buf), fp)) {
1864 if (strlen(buf) !=
sizeof(buf) - 1 || buf[
sizeof(buf) - 2] ==
'\n') {
1873 ast_log(LOG_ERROR,
"#exec <%s>: %s",
1878 status = pclose(fp);
1880 ast_log(LOG_ERROR,
"#exec <%s>: Failed to retrieve exit status: %s\n",
1884 status = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1886 ast_log(LOG_ERROR,
"#exec <%s>: Exited with return value %d\n",
1895 if (stat(output_file, &output_file_info) == -1) {
1896 ast_log(LOG_ERROR,
"#exec <%s>: Unable to stat() temporary file `%s': %s\n",
1900 }
else if (output_file_info.st_size == 0) {
1901 ast_log(LOG_WARNING,
"#exec <%s>: The program generated no usable output.\n",
1916 char *buf,
int lineno,
const char *configfile,
struct ast_flags flags,
1919 const char *suggested_include_file,
1925 char exec_file[512];
1928 if (cur[0] ==
'[') {
1940 c = strchr(cur,
']');
1942 ast_log(LOG_WARNING,
"parse error: no closing ']', line %d of %s\n", lineno, configfile);
1951 S_OR(suggested_include_file, cfg->include_level == 1 ?
"" : configfile),
1956 (*cat)->lineno = lineno;
1960 newcat->precomments = ALLOC_COMMENT(comment_buffer);
1962 newcat->sameline = ALLOC_COMMENT(lline_buffer);
1964 CB_RESET(comment_buffer, lline_buffer);
1968 if (!(cur = strchr(c,
')'))) {
1969 ast_category_destroy(newcat);
1970 ast_log(LOG_WARNING,
"parse error: no closing ')', line %d of %s\n", lineno, configfile);
1974 while ((cur = strsep(&c,
","))) {
1975 if (!strcasecmp(cur,
"!")) {
1976 (*cat)->ignored = 1;
1977 }
else if (cur[0] ==
'+') {
1978 char *filter = NULL;
1980 if (cur[1] !=
',') {
1983 *cat = category_get_sep(cfg, catname, filter,
'&', 0);
1986 ast_category_destroy(newcat);
1988 ast_log(LOG_WARNING,
"Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
1993 (*cat)->ignored |= newcat->
ignored;
1994 move_variables(newcat, *cat);
1995 ast_category_destroy(newcat);
2001 base = category_get_sep(cfg, cur,
"TEMPLATES=include",
',', 0);
2004 ast_category_destroy(newcat);
2006 ast_log(LOG_WARNING,
"Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
2011 ast_category_destroy(newcat);
2013 ast_log(LOG_ERROR,
"Inheritance requested, but allocation failed\n");
2032 }
else if (cur[0] ==
'#') {
2034 char real_inclusion_name[256];
2036 int try_include = 0;
2040 while (*c && (*c > 32)) {
2054 if (!strcasecmp(cur,
"include")) {
2056 }
else if (!strcasecmp(cur,
"tryinclude")) {
2059 }
else if (!strcasecmp(cur,
"exec")) {
2060 if (!ast_opt_exec_includes) {
2061 ast_log(LOG_WARNING,
"Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
2065 ast_log(LOG_WARNING,
"Unknown directive '#%s' at line %d of %s\n", cur, lineno, configfile);
2070 ast_log(LOG_WARNING,
"Directive '#%s' needs an argument (%s) at line %d of %s\n",
2071 do_include ?
"include / tryinclude" :
"exec",
2072 do_include ?
"filename" :
"/path/to/executable",
2081 if ((*c ==
'"') || (*c ==
'<')) {
2082 char quote_char = *c;
2083 if (quote_char ==
'<') {
2087 if (*(c + strlen(c) - 1) == quote_char) {
2089 *(c + strlen(c) - 1) =
'\0';
2100 config_cache_attribute(configfile, ATTRIBUTE_EXEC, NULL, who_asked);
2101 snprintf(exec_file,
sizeof(exec_file),
"/var/tmp/exec.%d%d.%ld", (
int)now.tv_sec, (
int)now.tv_usec, (
long)pthread_self());
2102 if (handle_include_exec(cur, exec_file)) {
2108 config_cache_attribute(configfile, ATTRIBUTE_INCLUDE, cur, who_asked);
2109 exec_file[0] =
'\0';
2113 ast_include_new(cfg, cfg->include_level == 1 ?
"" : configfile, cur, !do_include, cur2, lineno, real_inclusion_name,
sizeof(real_inclusion_name));
2115 do_include = ast_config_internal_load(cur, cfg, flags, real_inclusion_name, who_asked) ? 1 : 0;
2116 if (!ast_strlen_zero(exec_file))
2118 if (!do_include && !try_include) {
2119 ast_log(LOG_ERROR,
"The file '%s' was listed as a #include but it does not exist.\n", cur);
2130 ast_log(LOG_WARNING,
2131 "parse error: No category context for line %d of %s\n", lineno, configfile);
2135 is_escaped = cur[0] ==
'\\';
2140 ast_log(LOG_ERROR,
"Invalid escape in line %d of %s\n", lineno, configfile);
2144 c = strchr(cur + is_escaped,
'=');
2146 if (c && c > cur + is_escaped && (*(c - 1) ==
'+')) {
2150 if (!str || !*str) {
2160 if (!strcmp(var->
name, cur)) {
2167 goto set_new_variable;
2184 if (ast_strlen_zero(cur)) {
2185 ast_log(LOG_WARNING,
"No variable name in line %d of %s\n", lineno, configfile);
2186 }
else if ((v = ast_variable_new(cur,
ast_strip(c),
S_OR(suggested_include_file, cfg->include_level == 1 ?
"" : configfile)))) {
2193 ast_variable_append(*cat, v);
2196 v->precomments = ALLOC_COMMENT(comment_buffer);
2198 v->sameline = ALLOC_COMMENT(lline_buffer);
2200 CB_RESET(comment_buffer, lline_buffer);
2206 ast_log(LOG_WARNING,
"No '=' (equal sign) in line %d of %s\n", lineno, configfile);
2215 #if defined(LOW_MEMORY)
2220 char *new_buf, *comment_p, *process_buf;
2223 int comment = 0, nest[MAX_NESTED_COMMENTS];
2226 struct stat statbuf;
2241 if (filename[0] ==
'/') {
2244 snprintf(fn,
sizeof(fn),
"%s/%s", ast_config_AST_CONFIG_DIR, filename);
2249 if (comment_buffer) {
2252 if (!lline_buffer) {
2253 ast_free(comment_buffer);
2254 ast_log(LOG_ERROR,
"Failed to initialize the comment buffer!\n");
2259 globbuf.gl_offs = 0;
2260 glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
2261 if (glob_ret == GLOB_NOSPACE) {
2262 ast_log(LOG_WARNING,
2263 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
2264 }
else if (glob_ret == GLOB_ABORTED) {
2265 ast_log(LOG_WARNING,
2266 "Glob Expansion of pattern '%s' failed: Read error\n", fn);
2271 if (!cfg && (globbuf.gl_pathc != 1 || strcmp(fn, globbuf.gl_pathv[0]))) {
2280 ast_free(comment_buffer);
2281 ast_free(lline_buffer);
2284 for (i=0; i<globbuf.gl_pathc; i++) {
2293 if (stat(fn, &statbuf)) {
2295 config_cache_remove(fn, who_asked);
2300 if (!S_ISREG(statbuf.st_mode)) {
2301 ast_log(LOG_WARNING,
"'%s' is not a regular file, ignoring\n", fn);
2303 config_cache_remove(fn, who_asked);
2317 cfmtime = cfmtime_new(fn, who_asked);
2328 && !cfmtime->has_exec
2329 && !cfmstat_cmp(cfmtime, &statbuf)
2336 NULL, flags,
"", who_asked)) {
2346 ast_free(comment_buffer);
2347 ast_free(lline_buffer);
2348 return CONFIG_STATUS_FILEUNCHANGED;
2362 cfmtime->has_exec = 0;
2363 config_cache_flush_includes(cfmtime);
2365 cfmstat_save(cfmtime, &statbuf);
2369 if (!(f = fopen(fn,
"r"))) {
2370 ast_debug(1,
"No file to parse: %s\n", fn);
2371 ast_verb(2,
"Parsing '%s': Not found (%s)\n", fn, strerror(errno));
2380 if (fgets(buf,
sizeof(buf), f)) {
2382 if (strlen(buf) ==
sizeof(buf) - 1 && buf[
sizeof(buf) - 2] !=
'\n') {
2383 ast_log(LOG_WARNING,
"Line %d too long, skipping. It begins with: %.32s...\n", lineno, buf);
2384 while (fgets(buf,
sizeof(buf), f)) {
2385 if (strlen(buf) !=
sizeof(buf) - 1 || buf[
sizeof(buf) - 2] ==
'\n') {
2394 #define UTF8_BOM "\xEF\xBB\xBF"
2395 size_t line_bytes = strlen(buf);
2396 size_t bom_bytes =
sizeof(UTF8_BOM) - 1;
2397 if (line_bytes >= bom_bytes
2398 && !memcmp(buf, UTF8_BOM, bom_bytes)) {
2399 memmove(buf, &buf[bom_bytes], line_bytes - bom_bytes + 1);
2421 && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf,
" \t\n\r"))) {
2423 CB_ADD(&comment_buffer,
"\n");
2427 while ((comment_p = strchr(new_buf, COMMENT_META))) {
2428 if ((comment_p > new_buf) && (*(comment_p - 1) ==
'\\')) {
2430 new_buf = comment_p;
2432 memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
2433 }
else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] !=
'-')) {
2435 if (comment < MAX_NESTED_COMMENTS) {
2437 new_buf = comment_p + 3;
2439 nest[comment-1] = lineno;
2441 ast_log(LOG_ERROR,
"Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
2443 }
else if ((comment_p >= new_buf + 2) &&
2444 (*(comment_p - 1) == COMMENT_TAG) &&
2445 (*(comment_p - 2) == COMMENT_TAG)) {
2448 new_buf = comment_p + 1;
2455 oldptr = process_buf + strlen(process_buf);
2457 CB_ADD(&comment_buffer,
";");
2458 CB_ADD_LEN(&comment_buffer, oldptr+1, new_buf-oldptr-1);
2461 memmove(oldptr, new_buf, strlen(new_buf) + 1);
2464 process_buf = new_buf;
2472 CB_ADD(&lline_buffer, comment_p);
2475 new_buf = comment_p;
2477 new_buf = comment_p + 1;
2482 CB_ADD(&comment_buffer, buf);
2488 if (!ast_strlen_zero(buffer)) {
2490 flags, comment_buffer, lline_buffer,
2491 suggested_include_file, &last_cat, &last_var,
2493 cfg = CONFIG_STATUS_FILEINVALID;
2507 last_cat->
trailing = ALLOC_COMMENT(comment_buffer);
2509 }
else if (last_var) {
2515 last_var->
trailing = ALLOC_COMMENT(comment_buffer);
2523 CB_RESET(comment_buffer, lline_buffer);
2529 ast_log(LOG_WARNING,
"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
2531 if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
2538 ast_free(comment_buffer);
2539 ast_free(lline_buffer);
2569 static void gen_header(FILE *f1,
const char *configfile,
const char *fn,
const char *generator)
2577 fprintf(f1,
";!\n");
2578 fprintf(f1,
";! Automatically generated configuration file\n");
2579 if (strcmp(configfile, fn))
2580 fprintf(f1,
";! Filename: %s (%s)\n", configfile, fn);
2582 fprintf(f1,
";! Filename: %s\n", configfile);
2583 fprintf(f1,
";! Generator: %s\n", generator);
2584 fprintf(f1,
";! Creation Date: %s", date);
2585 fprintf(f1,
";!\n");
2588 static void inclfile_destroy(
void *obj)
2595 static void make_fn(
char *fn,
size_t fn_size,
const char *file,
const char *configfile)
2597 if (ast_strlen_zero(file)) {
2598 if (configfile[0] ==
'/') {
2601 snprintf(fn, fn_size,
"%s/%s", ast_config_AST_CONFIG_DIR, configfile);
2603 }
else if (file[0] ==
'/') {
2606 snprintf(fn, fn_size,
"%s/%s", ast_config_AST_CONFIG_DIR, file);
2610 static struct inclfile *set_fn(
char *fn,
size_t fn_size,
const char *file,
const char *configfile,
struct ao2_container *fileset)
2615 make_fn(fn, fn_size, file, configfile);
2624 fi = ao2_alloc(
sizeof(
struct inclfile), inclfile_destroy);
2642 static int count_linefeeds(
char *str)
2654 static int count_linefeeds_in_comments(
struct ast_comment *x)
2659 count += count_linefeeds(x->
cmt);
2665 static void insert_leading_blank_lines(FILE *fp,
struct inclfile *fi,
struct ast_comment *precomments,
int lineno)
2667 int precomment_lines;
2675 precomment_lines = count_linefeeds_in_comments(precomments);
2681 if (lineno - precomment_lines - fi->lineno < 0) {
2683 }
else if (lineno == 0) {
2686 }
else if (lineno - precomment_lines - fi->lineno < 5) {
2689 for (i = fi->lineno; i < lineno - precomment_lines; i++) {
2698 fi->lineno = lineno + 1;
2706 static int is_writable(
const char *fn)
2708 if (access(fn, F_OK)) {
2711 if (access(dn, R_OK | W_OK)) {
2712 ast_log(LOG_ERROR,
"Unable to write to directory %s (%s)\n", dn, strerror(errno));
2716 if (access(fn, R_OK | W_OK)) {
2717 ast_log(LOG_ERROR,
"Unable to write %s (%s)\n", fn, strerror(errno));
2738 hash_string, NULL, hashtab_compare_strings);
2753 if (!is_writable(fn)) {
2760 make_fn(fn,
sizeof(fn), 0, configfile);
2761 if (!is_writable(fn)) {
2772 fi = set_fn(fn,
sizeof(fn), incl->
included_file, configfile, fileset);
2775 gen_header(f, configfile, fn, generator);
2778 ast_log(LOG_ERROR,
"Unable to write %s (%s)\n", fn, strerror(errno));
2787 fi = set_fn(fn,
sizeof(fn), 0, configfile, fileset);
2790 (f = fopen(fn,
"w+"))
2792 (f = fopen(fn,
"w"))
2795 ast_verb(2,
"Saving '%s'\n", fn);
2796 gen_header(f, configfile, fn, generator);
2808 fi = set_fn(fn,
sizeof(fn), cat->
file, configfile, fileset);
2811 ast_log(LOG_ERROR,
"Unable to write %s (%s)\n", fn, strerror(errno));
2824 fprintf(f,
"#exec \"%s\"\n", incl->
exec_file);
2832 insert_leading_blank_lines(f, fi, cat->precomments, cat->lineno);
2834 for (cmt = cat->precomments; cmt; cmt=cmt->next) {
2835 char *cmtp = cmt->
cmt;
2836 while (cmtp && *cmtp ==
';' && *(cmtp+1) ==
'!') {
2837 char *cmtp2 = strchr(cmtp+1,
'\n');
2843 fprintf(f,
"%s", cmtp);
2845 fprintf(f,
"[%s]", cat->name);
2857 fprintf(f,
"%s",x->name);
2864 for(cmt = cat->sameline; cmt; cmt=cmt->next)
2866 fprintf(f,
"%s", cmt->
cmt);
2870 for (cmt = cat->
trailing; cmt; cmt=cmt->next) {
2871 if (cmt->
cmt[0] !=
';' || cmt->
cmt[1] !=
'!')
2872 fprintf(f,
"%s", cmt->
cmt);
2886 for (v = x->inst->
root; v; v = v->
next) {
2913 fi = set_fn(fn,
sizeof(fn), var->
file, configfile, fileset);
2916 ast_debug(1,
"Unable to open for writing: %s\n", fn);
2917 ast_verb(2,
"Unable to write %s (%s)\n", fn, strerror(errno));
2930 fprintf(f,
"#exec \"%s\"\n", incl->
exec_file);
2938 insert_leading_blank_lines(f, fi, var->precomments, var->lineno);
2939 for (cmt = var->precomments; cmt; cmt=cmt->next) {
2940 if (cmt->
cmt[0] !=
';' || cmt->
cmt[1] !=
'!')
2941 fprintf(f,
"%s", cmt->
cmt);
2945 int escaped_len = 2 * strlen(var->
value) + 1;
2946 char escaped[escaped_len];
2950 if (var->sameline) {
2951 fprintf(f,
"%s %s %s %s", var->
name, (var->
object ?
"=>" :
"="),
2952 escaped, var->sameline->
cmt);
2954 fprintf(f,
"%s %s %s\n", var->
name, (var->
object ?
"=>" :
"="),
2959 for (cmt = var->
trailing; cmt; cmt=cmt->next) {
2960 if (cmt->
cmt[0] !=
';' || cmt->
cmt[1] !=
'!')
2961 fprintf(f,
"%s", cmt->
cmt);
2965 while (blanklines--)
2978 ast_verb(2,
"Saving '%s': saved\n", fn);
2980 ast_debug(1,
"Unable to open for writing: %s\n", fn);
2981 ast_verb(2,
"Unable to write '%s' (%s)\n", fn, strerror(errno));
2997 ast_debug(1,
"Unable to open for writing: %s\n", fn);
2998 ast_verb(2,
"Unable to write %s (%s)\n", fn, strerror(errno));
3008 fprintf(f,
"#exec \"%s\"\n", incl->
exec_file);
3021 config_hook_exec(configfile, generator, cfg);
3026 static void clear_config_maps(
void)
3030 while (config_maps) {
3032 config_maps = config_maps->next;
3037 #ifdef TEST_FRAMEWORK
3038 int ast_realtime_append_mapping(
const char *name,
const char *driver,
const char *database,
const char *table,
int priority)
3040 static int ast_realtime_append_mapping(
const char *name,
const char *driver,
const char *database,
const char *table,
int priority)
3047 length =
sizeof(*map);
3048 length += strlen(name) + 1;
3049 length += strlen(driver) + 1;
3050 length += strlen(database) + 1;
3052 length += strlen(table) + 1;
3058 map->
name = strcpy(dst, name);
3059 dst += strlen(dst) + 1;
3060 map->
driver = strcpy(dst, driver);
3061 dst += strlen(dst) + 1;
3062 map->
database = strcpy(dst, database);
3064 dst += strlen(dst) + 1;
3065 map->
table = strcpy(dst, table);
3067 map->priority = priority;
3068 map->next = config_maps;
3076 static int reload_module(
void)
3080 char *driver, *table, *database, *textpri, *stringp, *tmp;
3085 clear_config_maps();
3089 ast_log(LOG_ERROR,
"Unable to allocate memory for new config\n");
3092 config = ast_config_internal_load(extconfig_conf, configtmp, flags,
"",
"extconfig");
3093 if (config == CONFIG_STATUS_FILEINVALID) {
3095 }
else if (!config) {
3100 for (v = ast_variable_browse(config,
"settings"); v; v = v->
next) {
3104 driver = strsep(&stringp,
",");
3106 ast_log(LOG_WARNING,
"extconfig.conf: value '%s' ignored due to wrong format\n", v->
value);
3109 if ((tmp = strchr(stringp,
'\"')))
3113 if (*stringp ==
'"') {
3115 database = strsep(&stringp,
"\"");
3116 strsep(&stringp,
",");
3119 database = strsep(&stringp,
",");
3122 table = strsep(&stringp,
",");
3123 textpri = strsep(&stringp,
",");
3124 if (!textpri || !(pri = atoi(textpri))) {
3128 if (!strcmp(v->
name, extconfig_conf)) {
3129 ast_log(LOG_WARNING,
"Cannot bind '%s'!\n", extconfig_conf);
3133 if (!strcmp(v->
name,
"asterisk.conf")) {
3134 ast_log(LOG_WARNING,
"Cannot bind 'asterisk.conf'!\n");
3138 if (!strcmp(v->
name,
"logger.conf")) {
3139 ast_log(LOG_WARNING,
"Cannot bind 'logger.conf'!\n");
3143 if (!driver || !database)
3145 if (!strcasecmp(v->
name,
"iaxfriends")) {
3146 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");
3147 ast_realtime_append_mapping(
"iaxusers", driver, database, table ? table :
"iaxfriends", pri);
3148 ast_realtime_append_mapping(
"iaxpeers", driver, database, table ? table :
"iaxfriends", pri);
3150 ast_realtime_append_mapping(v->
name, driver, database, table, pri);
3163 if (!config_engine_list) {
3164 config_engine_list =
new;
3166 for (ptr = config_engine_list; ptr->next; ptr=ptr->next);
3179 for (ptr = config_engine_list; ptr; ptr=ptr->next) {
3182 last->next = ptr->next;
3184 config_engine_list = ptr->next;
3198 for (map = config_maps; map; map = map->next) {
3199 if (!strcasecmp(family, map->
name)) {
3203 ast_debug(5,
"Failed to find a realtime mapping for %s\n", family);
3216 for (map = config_maps; map; map = map->next) {
3217 if (!strcasecmp(family, map->
name) && (priority == map->priority)) {
3228 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
3229 if (!strcasecmp(eng->name, map->
driver))
3236 ast_log(LOG_WARNING,
"Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->
name, map->
driver);
3255 for (cat_iter = old->
root; cat_iter; cat_iter = cat_iter->
next) {
3262 if (cat_iter->
root) {
3264 if (!new_cat->
root) {
3279 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)
3287 if (cfg->max_include_level > 0 && cfg->include_level == cfg->max_include_level + 1) {
3288 ast_log(LOG_WARNING,
"Maximum Include level (%d) exceeded\n", cfg->max_include_level);
3292 cfg->include_level++;
3297 eng =
find_engine(filename, 1, db,
sizeof(db), table,
sizeof(table));
3300 if (eng && eng->load_func) {
3303 eng =
find_engine(
"global", 1, db,
sizeof(db), table,
sizeof(table));
3304 if (eng && eng->load_func)
3309 result = loader->load_func(db, table, filename, cfg, flags, suggested_include_file, who_asked);
3311 if (result && result != CONFIG_STATUS_FILEINVALID && result != CONFIG_STATUS_FILEUNCHANGED) {
3312 result->include_level--;
3313 config_hook_exec(filename, who_asked, result);
3314 }
else if (result != CONFIG_STATUS_FILEINVALID) {
3315 cfg->include_level--;
3330 result = ast_config_internal_load(filename, cfg, flags,
"", who_asked);
3331 if (!result || result == CONFIG_STATUS_FILEUNCHANGED || result == CONFIG_STATUS_FILEINVALID)
3337 #define realtime_arguments_to_fields(ap, result) realtime_arguments_to_fields2(ap, 0, result)
3352 static int realtime_arguments_to_fields2(va_list ap,
int skip,
struct ast_variable **result)
3355 const char *newparam;
3391 newparam = va_arg(ap,
const char *);
3392 newval = va_arg(ap,
const char *);
3393 while ((newparam = va_arg(ap,
const char *))) {
3394 newval = va_arg(ap,
const char *);
3399 newparam = va_arg(ap,
const char *);
3404 newval = va_arg(ap,
const char *);
3406 if (!(first = ast_variable_new(newparam, newval,
""))) {
3411 while ((newparam = va_arg(ap,
const char *))) {
3414 newval = va_arg(ap,
const char *);
3415 if (!(field = ast_variable_new(newparam, newval,
""))) {
3422 field->
next = fields;
3426 first->
next = fields;
3441 for (i = 1; ; i++) {
3442 if ((eng =
find_engine(family, i, db,
sizeof(db), table,
sizeof(table)))) {
3443 if (eng->realtime_func && (res = eng->realtime_func(db, table, fields))) {
3454 struct ast_variable *ast_load_realtime_all(
const char *family, ...)
3460 va_start(ap, family);
3461 realtime_arguments_to_fields(ap, &fields);
3465 res = ast_load_realtime_all_fields(family, fields);
3477 res = ast_load_realtime_all_fields(family, fields);
3483 if (ast_strlen_zero(cur->
value)) {
3489 ast_variable_destroy(cur);
3493 if (cur->
value[0] ==
' ' && cur->
value[1] ==
'\0') {
3494 char *vptr = (
char *) cur->
value;
3506 struct ast_variable *ast_load_realtime(
const char *family, ...)
3512 va_start(ap, family);
3513 if (realtime_arguments_to_fields(ap, &fields)) {
3546 return config_maps ? 1 : 0;
3557 va_start(ap, family);
3558 for (i = 1; ; i++) {
3559 if ((eng =
find_engine(family, i, db,
sizeof(db), table,
sizeof(table)))) {
3562 if (eng->require_func && !(res = eng->require_func(db, table, aq))) {
3583 for (i = 1; ; i++) {
3584 if ((eng =
find_engine(family, i, db,
sizeof(db), table,
sizeof(table)))) {
3585 if (eng->unload_func) {
3587 res = eng->unload_func(db, table);
3604 for (i = 1; ; i++) {
3605 if ((eng =
find_engine(family, i, db,
sizeof(db), table,
sizeof(table)))) {
3606 if (eng->realtime_multi_func && (res = eng->realtime_multi_func(db, table, fields))) {
3627 va_start(ap, family);
3628 realtime_arguments_to_fields(ap, &fields);
3645 for (i = 1; ; i++) {
3646 if ((eng =
find_engine(family, i, db,
sizeof(db), table,
sizeof(table)))) {
3648 if (eng->update_func && ((res = eng->update_func(db, table, keyfield, lookup, fields)) >= 0)) {
3664 va_start(ap, lookup);
3665 realtime_arguments_to_fields(ap, &fields);
3682 for (i = 1; ; i++) {
3683 if ((eng =
find_engine(family, i, db,
sizeof(db), table,
sizeof(table)))) {
3684 if (eng->update2_func && !(res = eng->update2_func(db, table, lookup_fields, update_fields))) {
3701 va_start(ap, family);
3705 realtime_arguments_to_fields(ap, &lookup_fields);
3708 va_start(ap, family);
3709 realtime_arguments_to_fields2(ap, 1, &update_fields);
3712 if (!lookup_fields || !update_fields) {
3726 for (i = 1; ; i++) {
3727 if ((eng =
find_engine(family, i, db,
sizeof(db), table,
sizeof(table)))) {
3729 if (eng->store_func && ((res = eng->store_func(db, table, fields)) >= 0)) {
3745 va_start(ap, family);
3746 realtime_arguments_to_fields(ap, &fields);
3763 for (i = 1; ; i++) {
3764 if ((eng =
find_engine(family, i, db,
sizeof(db), table,
sizeof(table)))) {
3765 if (eng->destroy_func && ((res = eng->destroy_func(db, table, keyfield, lookup, fields)) >= 0)) {
3782 va_start(ap, lookup);
3783 if (realtime_arguments_to_fields(ap, &fields)) {
3798 for (; *chunk; chunk++) {
3799 if (*chunk ==
'^' && strchr(
"0123456789ABCDEFabcdef", chunk[1]) && strchr(
"0123456789ABCDEFabcdef", chunk[2])) {
3800 sscanf(chunk + 1,
"%02hhX", (
unsigned char *)chunk);
3801 memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
3809 if (!strchr(chunk,
';') && !strchr(chunk,
'^')) {
3813 for (; *chunk; chunk++) {
3814 if (strchr(
";^", *chunk)) {
3828 void *p_result, ...)
3833 va_start(ap, p_result);
3834 switch (flags & PARSE_TYPE) {
3838 int32_t *result = p_result;
3839 int32_t def = result ? *result : 0, high = INT32_MAX, low = INT32_MIN;
3840 char *endptr = NULL;
3843 if (flags & PARSE_DEFAULT) {
3844 def = va_arg(ap, int32_t);
3846 if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
3847 low = va_arg(ap, int32_t);
3848 high = va_arg(ap, int32_t);
3850 if (ast_strlen_zero(arg)) {
3855 x = strtol(arg, &endptr, 0);
3856 if (*endptr || errno || x < INT32_MIN || x > INT32_MAX) {
3861 error = (x < low) || (x > high);
3862 if (flags & PARSE_RANGE_DEFAULTS) {
3865 }
else if (x > high) {
3869 if (flags & PARSE_OUT_RANGE) {
3874 *result = error ? def : x;
3877 ast_debug(3,
"extract int from [%s] in [%d, %d] gives [%ld](%d)\n",
3878 arg, low, high, result ? *result : x, error);
3884 unsigned long int x = 0;
3885 uint32_t *result = p_result;
3886 uint32_t def = result ? *result : 0, low = 0, high = UINT32_MAX;
3887 char *endptr = NULL;
3890 if (flags & PARSE_DEFAULT) {
3891 def = va_arg(ap, uint32_t);
3893 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
3895 low = va_arg(ap, uint32_t);
3896 high = va_arg(ap, uint32_t);
3899 if (ast_strlen_zero(arg)) {
3910 x = strtoul(arg, &endptr, 0);
3911 if (*endptr || errno || x > UINT32_MAX) {
3915 error = (x < low) || (x > high);
3916 if (flags & PARSE_RANGE_DEFAULTS) {
3919 }
else if (x > high) {
3923 if (flags & PARSE_OUT_RANGE) {
3928 *result = error ? def : x;
3930 ast_debug(3,
"extract uint from [%s] in [%u, %u] gives [%lu](%d)\n",
3931 arg, low, high, result ? *result : x, error);
3938 int *result = p_result;
3939 int def = result ? *result : 0;
3942 enum ast_timelen defunit;
3944 defunit = va_arg(ap,
enum ast_timelen);
3946 if (flags & PARSE_DEFAULT) {
3947 def = va_arg(ap,
int);
3949 if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
3950 low = va_arg(ap,
int);
3951 high = va_arg(ap,
int);
3953 if (ast_strlen_zero(arg)) {
3958 if (error || x < INT_MIN || x > INT_MAX) {
3963 error = (x < low) || (x > high);
3964 if (flags & PARSE_RANGE_DEFAULTS) {
3967 }
else if (x > high) {
3971 if (flags & PARSE_OUT_RANGE) {
3976 *result = error ? def : x;
3979 ast_debug(3,
"extract timelen from [%s] in [%d, %d] gives [%d](%d)\n",
3980 arg, low, high, result ? *result : x, error);
3986 double *result = p_result;
3987 double x = 0, def = result ? *result : 0, low = -HUGE_VAL, high = HUGE_VAL;
3988 char *endptr = NULL;
3991 if (flags & PARSE_DEFAULT) {
3992 def = va_arg(ap,
double);
3994 if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
3996 low = va_arg(ap,
double);
3997 high = va_arg(ap,
double);
3999 if (ast_strlen_zero(arg)) {
4004 x = strtod(arg, &endptr);
4005 if (*endptr || errno == ERANGE) {
4009 error = (x < low) || (x > high);
4010 if (flags & PARSE_OUT_RANGE) {
4015 *result = error ? def : x;
4017 ast_debug(3,
"extract double from [%s] in [%f, %f] gives [%f](%d)\n",
4018 arg, low, high, result ? *result : x, error);
4029 ast_debug(3,
"extract addr from %s gives %s(%d)\n",
4037 struct sockaddr_in _sa_buf;
4038 struct sockaddr_in *sa = p_result ?
4039 (
struct sockaddr_in *)p_result : &_sa_buf;
4041 struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
4042 va_arg(ap,
struct sockaddr_in *) : sa;
4045 memset(&_sa_buf,
'\0',
sizeof(_sa_buf));
4048 buf = strsep(&port,
":");
4049 sa->sin_family = AF_INET;
4054 flags &= PARSE_PORT_MASK;
4056 if (flags == PARSE_PORT_FORBID) {
4058 sa->sin_port = def->sin_port;
4059 }
else if (flags == PARSE_PORT_IGNORE)
4060 sa->sin_port = def->sin_port;
4062 sa->sin_port = htons(strtol(port, NULL, 0));
4064 sa->sin_port = def->sin_port;
4065 if (flags == PARSE_PORT_REQUIRE)
4071 sa->sin_addr = def->sin_addr;
4073 struct sockaddr_in tmp;
4075 sa->sin_addr = tmp.sin_addr;
4078 "extract inaddr from [%s] gives [%s:%d](%d)\n",
4080 ntohs(sa->sin_port), error);
4095 e->
command =
"core show config mappings";
4097 "Usage: core show config mappings\n"
4098 " Shows the filenames to config engines.\n";
4107 if (!config_engine_list) {
4108 ast_cli(a->fd,
"No config mappings found.\n");
4110 for (eng = config_engine_list; eng; eng = eng->next) {
4111 ast_cli(a->fd,
"Config Engine: %s\n", eng->name);
4112 for (map = config_maps; map; map = map->next) {
4113 if (!strcasecmp(map->
driver, eng->name)) {
4114 ast_cli(a->fd,
"===> %s (db=%s, table=%s)\n", map->
name, map->
database,
4135 "Usage: config reload <filename.conf>\n"
4136 " Reloads all modules that reference <filename.conf>\n";
4143 wordlen = strlen(a->word);
4148 if (ast_strlen_zero(cfmtime->
who_asked)) {
4153 if (!strcmp(cfmtime->
filename, prev)) {
4157 if (!strncmp(cfmtime->
filename, a->word, wordlen)) {
4172 return CLI_SHOWUSAGE;
4177 if (!strcmp(cfmtime->
filename, a->argv[2])) {
4179 sprintf(buf,
"module reload %s", cfmtime->
who_asked);
4196 "Usage: config list\n"
4197 " Show all modules that have loaded a configuration file\n";
4213 AST_CLI_DEFINE(handle_cli_core_show_config_mappings,
"Display config mappings (file names to config engines)"),
4214 AST_CLI_DEFINE(handle_cli_config_reload,
"Force a reload on modules using a particular configuration file"),
4215 AST_CLI_DEFINE(handle_cli_config_list,
"Show all files that have loaded a configuration file"),
4218 static void config_shutdown(
void)
4224 config_cache_destroy_entry(cfmtime);
4230 clear_config_maps();
4232 ao2_cleanup(cfg_hooks);
4251 static void hook_destroy(
void *obj)
4254 ast_free((
void *) hook->name);
4255 ast_free((
void *) hook->filename);
4256 ast_free((
void *) hook->module);
4259 static int hook_cmp(
void *obj,
void *arg,
int flags)
4267 static int hook_hash(
const void *obj,
const int flags)
4283 static void config_hook_exec(
const char *filename,
const char *module,
const struct ast_config *cfg)
4291 while ((hook = ao2_iterator_next(&it))) {
4292 if (!strcasecmp(hook->filename, filename) &&
4293 !strcasecmp(hook->module, module)) {
4295 hook->hook_cb(copy);
4303 const char *filename,
4311 hook_hash, NULL, hook_cmp);
4317 if (!(hook = ao2_alloc(
sizeof(*hook), hook_destroy))) {
4321 hook->hook_cb = hook_cb;
4331 static int unload_module(
void)
4336 static int load_module(
void)
4338 if (ast_opt_console) {
4339 ast_verb(0,
"[ Initializing Custom Configuration Options ]\n");
4346 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"Configuration",
4347 .support_level = AST_MODULE_SUPPORT_CORE,
4348 .load = load_module,
4349 .unload = unload_module,
4350 .reload = reload_module,
struct ast_variable * next
struct ast_category * next
#define AST_LIST_LOCK(head)
Locks a list.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int ast_variable_list_replace_variable(struct ast_variable **head, struct ast_variable *old, struct ast_variable *new)
Replace a variable in the given list with a new variable.
char * ast_realtime_decode_chunk(char *chunk)
Remove standard encoding from realtime values, which ensures that a semicolon embedded within a singl...
struct ast_variable * ast_variables_reverse(struct ast_variable *var)
Reverse a variable list.
char * file
The file name from whence this declaration was read.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
void ast_unreplace_sigchld(void)
Restore the SIGCHLD handler.
String manipulation functions.
int ast_config_engine_register(struct ast_config_engine *new)
Register config engine.
int register_config_cli(void)
Exposed initialization method for core process.
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
struct ast_variable * ast_category_root(struct ast_config *config, char *cat)
returns the root ast_variable of a config
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
char * include_location_file
file name in which the include occurs
Time-related functions and macros.
void ast_config_hook_unregister(const char *name)
Unregister a config hook.
int ast_category_inherit(struct ast_category *new, const struct ast_category *base)
Applies base (template) to category.
char * ast_realtime_encode_chunk(struct ast_str **dest, ssize_t maxlen, const char *chunk)
Encodes a chunk of data for realtime.
int ast_destroy_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Destroy realtime configuration.
int ast_update2_realtime_fields(const char *family, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
Update realtime configuration.
struct ast_config_include * includes
descriptor for a cli entry.
int ast_realtime_enabled(void)
Check if there's any realtime engines loaded.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
int ast_category_exist(const struct ast_config *config, const char *category_name, const char *filter)
Check for category duplicates.
struct ast_variable * ast_variable_list_append_hint(struct ast_variable **head, struct ast_variable *search_hint, struct ast_variable *newvar)
Appends a variable list to the end of another list.
struct ast_variable * ast_variable_list_sort(struct ast_variable *start)
Performs an in-place sort on the variable list by ascending name.
Structure for variables, used for configurations and for channel variables.
int ast_config_hook_register(const char *name, const char *filename, const char *module, enum config_hook_flags flags, config_hook_cb hook_cb)
Register a config hook for a particular file and module.
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
int ast_update_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Update realtime configuration.
struct ast_category * prev
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
int(* config_hook_cb)(struct ast_config *cfg)
Callback when configuration is updated.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static int copy(char *infile, char *outfile)
Utility function to copy a file.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
char * ast_escape_semicolons(const char *string, char *outbuf, int buflen)
Escape semicolons found in a string.
struct ast_category * ast_category_delete(struct ast_config *config, struct ast_category *category)
Delete a category.
#define ast_strdup(str)
A wrapper for strdup()
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
Helper function to parse arguments See documentation in config.h.
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...)
Update realtime configuration.
struct ast_category * ast_config_get_current_category(const struct ast_config *cfg)
Retrieve the current category name being built.
char * exec_file
if it's an exec, you'll have both the /var/tmp to read, and the original script
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
void ast_free_ptr(void *ptr)
free() wrapper
Socket address structure.
Hold the mtime for config files, so if we don't need to reread our config, don't. ...
Configuration engine structure, used to define realtime drivers.
All configuration options for http media cache.
struct ast_category * last
struct ast_config * ast_load_realtime_multientry(const char *family,...)
Retrieve realtime configuration.
#define AST_LIST_INSERT_SORTALPHA(head, elm, field, sortfield)
Inserts a list entry into a alphabetically sorted list.
static char * lline_buffer
struct ast_comment * trailing
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Configuration File Parser.
static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile, struct ast_flags flags, struct ast_str *comment_buffer, struct ast_str *lline_buffer, const char *suggested_include_file, struct ast_category **last_cat, struct ast_variable **last_var, const char *who_asked)
parse one line in the configuration.
struct ast_comment * trailing
General Asterisk PBX channel definitions.
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
Asterisk file paths, configured in asterisk.conf.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
char * included_file
file name included
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
int ast_sockaddr_resolve_first_af(struct ast_sockaddr *addr, const char *name, int flag, int family)
Return the first entry from ast_sockaddr_resolve filtered by address family.
ast_cli_command
calling arguments for new-style handlers.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
struct ast_variable * root
char stuff[0]
Contents of file, name, and value in that order stuffed here.
int ast_variable_lists_match(const struct ast_variable *left, const struct ast_variable *right, int exact_match)
Tests 2 variable lists to see if they match.
void ast_replace_sigchld(void)
Replace the SIGCHLD handler.
struct ast_variable * ast_load_realtime_fields(const char *family, const struct ast_variable *fields)
Retrieve realtime configuration.
const char * ast_variable_retrieve_filtered(struct ast_config *config, const char *category, const char *variable, const char *filter)
Gets a variable by context and variable names.
Wrapper for network related headers, masking differences between various operating systems...
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
static char * comment_buffer
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
struct ast_category * last_browse
int ast_realtime_require_field(const char *family,...)
Inform realtime what fields that may be stored.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Support for dynamic strings.
int ast_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
Save a config text file preserving the pre 13.2 behavior.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
const char * ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
Retrieve a configuration variable within the configuration set.
int ast_category_is_template(const struct ast_category *category)
Check if category is a template.
int ast_variables_match(const struct ast_variable *left, const struct ast_variable *right)
Tests 2 variable values to see if they match.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
const char * ast_variable_find_in_list(const struct ast_variable *list, const char *variable)
Gets the value of a variable from a variable list by name.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
const char * ast_variable_find_last_in_list(const struct ast_variable *list, const char *variable)
Gets the value of the LAST occurrence of a variable from a variable list.
int ast_realtime_is_mapping_defined(const char *family)
Determine if a mapping exists for a given family.
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
struct ast_variable * ast_variable_list_from_string(const char *input, const char *item_separator, const char *name_value_separator)
Parse a string into an ast_variable list. The reverse of ast_variable_list_join.
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
int ast_update2_realtime(const char *family,...)
Update realtime configuration.
int include_location_lineno
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *replacement)
Replace a variable in the given list with a new value.
char * ast_strsep_quoted(char **s, const char sep, const char quote, uint32_t flags)
Like ast_strsep() except you can specify a specific quote character.
int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup,...)
Destroy realtime configuration.
#define ast_calloc(num, len)
A wrapper for calloc()
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Module could not be loaded properly.
int ast_store_realtime(const char *family,...)
Create realtime configuration.
void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
Set the category within the configuration as being current.
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)
Structure used to handle boolean flags.
struct ast_variable * ast_variable_list_from_quoted_string(const char *input, const char *item_separator, const char *name_value_separator, const char *quote_str)
Parse a string into an ast_variable list. The reverse of ast_variable_list_join.
config_hook_flags
Flags that affect the behaviour of config hooks.
void ast_config_sort_categories(struct ast_config *config, int descending, int(*comparator)(struct ast_category *p, struct ast_category *q))
Sorts categories in a config in the order of a numerical value contained within them.
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
const char * ast_variable_find(const struct ast_category *category, const char *variable)
Gets a variable value from a specific category structure by name.
struct ast_str * ast_category_get_templates(const struct ast_category *category)
Return the template names this category inherits from.
int ast_store_realtime_fields(const char *family, const struct ast_variable *fields)
Create realtime configuration.
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
const char * ast_category_get_name(const struct ast_category *category)
Return the name of the category.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
int ast_category_empty(struct ast_category *category)
Removes and destroys all variables in a category.
struct ast_variable * last
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category.
#define MIN_VARIABLE_FNAME_SPACE
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Standard Command Line Interface.
struct ast_config_include * next
struct ast_config * ast_config_copy(const struct ast_config *old)
Copies the contents of one ast_config into another.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
unsigned long stat_mtime_nsec
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
static struct ast_config_engine * find_engine(const char *family, int priority, char *database, int dbsiz, char *table, int tabsiz)
Find realtime engine for realtime family.
struct ast_config * ast_load_realtime_multientry_fields(const char *family, const struct ast_variable *fields)
Retrieve realtime configuration.
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
struct ast_variable * ast_category_first(struct ast_category *cat)
given a pointer to a category, return the root variable.
#define ast_sockaddr_to_sin(addr, sin)
Converts a struct ast_sockaddr to a struct sockaddr_in.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
struct ast_category * root
void ast_str_trim_blanks(struct ast_str *buf)
Trims trailing whitespace characters from an ast_str string.
ast_parse_flags
Support code to parse config file arguments.
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen defunit)
Common routine to parse time lengths, with optional time unit specifier.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
int ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
Inserts new category.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
const struct ast_variable * ast_variable_find_variable_in_list(const struct ast_variable *list, const char *variable_name)
Gets a variable from a variable list by name.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
struct ast_category * ast_category_browse_filtered(struct ast_config *config, const char *category_name, struct ast_category *prev, const char *filter)
Browse categories with filters.
int ast_config_text_file_save2(const char *configfile, const struct ast_config *cfg, const char *generator, uint32_t flags)
Save a config text file.
int ast_variable_update(struct ast_category *category, const char *variable, const char *value, const char *match, unsigned int object)
Update variable value within a config.
int ast_strings_match(const char *left, const char *op, const char *right)
Compares 2 strings using realtime-style operators.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
static int does_category_match(struct ast_category *cat, const char *category_name, const char *match, char sep)
Returns true if ALL of the regex expressions and category name match. Both can be NULL (I...
struct ast_category * ast_category_new_template(const char *name, const char *in_file, int lineno)
Create a category making it a template.
struct ast_str * ast_variable_list_join(const struct ast_variable *head, const char *item_separator, const char *name_value_separator, const char *quote_char, struct ast_str **str)
Join an ast_variable list with specified separators and quoted values.
#define AST_MAX_USER_FIELD
#define ao2_link(container, obj)
Add an object to a container.