Asterisk - The Open Source Telephony Project GIT-master-ff80666
main/config.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2010, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
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.
13 *
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.
17 */
18
19/*! \file
20 *
21 * \brief Configuration File Parser
22 *
23 * \author Mark Spencer <markster@digium.com>
24 *
25 * Includes the Asterisk Realtime API - ARA
26 * See https://docs.asterisk.org
27 */
28
29/*** MODULEINFO
30 <support_level>core</support_level>
31 ***/
32
33/* This maintains the original "module reload extconfig" CLI command instead
34 * of replacing it with "module reload config". */
35#undef AST_MODULE
36#define AST_MODULE "extconfig"
37
38#include "asterisk.h"
39
40#include "asterisk/paths.h" /* use ast_config_AST_CONFIG_DIR */
41#include "asterisk/network.h" /* we do some sockaddr manipulation here */
42
43#include <string.h>
44#include <libgen.h>
45#include <time.h>
46#include <sys/stat.h>
47#include <sys/wait.h>
48
49#include <math.h> /* HUGE_VAL */
50#include <regex.h>
51
52#include "asterisk/config.h"
53#include "asterisk/cli.h"
54#include "asterisk/lock.h"
55#include "asterisk/utils.h"
56#include "asterisk/channel.h"
57#include "asterisk/app.h"
58#include "asterisk/astobj2.h"
59#include "asterisk/strings.h" /* for the ast_str_*() API */
60#include "asterisk/netsock2.h"
61#include "asterisk/module.h"
62
63#define MAX_NESTED_COMMENTS 128
64#define COMMENT_START ";--"
65#define COMMENT_END "--;"
66#define COMMENT_META ';'
67#define COMMENT_TAG '-'
68
69/*!
70 * Define the minimum filename space to reserve for each
71 * ast_variable in case the filename is renamed later by
72 * ast_include_rename().
73 */
74#define MIN_VARIABLE_FNAME_SPACE 40
75
76static char *extconfig_conf = "extconfig.conf";
77
78static struct ao2_container *cfg_hooks;
79static void config_hook_exec(const char *filename, const char *module, const struct ast_config *cfg);
80static inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2);
81static int does_category_match(struct ast_category *cat, const char *category_name,
82 const char *match, char sep);
83
84/*! \brief Structure to keep comments for rewriting configuration files */
87 /*! Comment body allocated after struct. */
88 char cmt[0];
89};
90
91/*! \brief Hold the mtime for config files, so if we don't need to reread our config, don't. */
94 /*! Filename or wildcard pattern as specified by the including file. */
95 char include[0];
96};
97
101 unsigned int has_exec:1;
102 /*! stat() file size */
103 unsigned long stat_size;
104 /*! stat() file modtime nanoseconds */
105 unsigned long stat_mtime_nsec;
106 /*! stat() file modtime seconds since epoc */
108
109 /*! String stuffed in filename[] after the filename string. */
110 const char *who_asked;
111 /*! Filename and who_asked stuffed after it. */
112 char filename[0];
113};
114
115/*! Cached file mtime list. */
117
118static int init_appendbuf(void *data)
119{
120 struct ast_str **str = data;
121 *str = ast_str_create(16);
122 return *str ? 0 : -1;
123}
124
126
127/* comment buffers are better implemented using the ast_str_*() API */
128#define CB_SIZE 250 /* initial size of comment buffers */
129
130static void CB_ADD(struct ast_str **cb, const char *str)
131{
132 ast_str_append(cb, 0, "%s", str);
133}
134
135static void CB_ADD_LEN(struct ast_str **cb, const char *str, int len)
136{
137 char *s = ast_alloca(len + 1);
138
139 memcpy(s, str, len);
140 s[len] = '\0';
141 ast_str_append(cb, 0, "%s", s);
142}
143
144static void CB_RESET(struct ast_str *cb, struct ast_str *llb)
145{
146 if (cb) {
147 ast_str_reset(cb);
148 }
149 if (llb) {
150 ast_str_reset(llb);
151 }
152}
153
154static struct ast_comment *ALLOC_COMMENT(struct ast_str *buffer)
155{
156 struct ast_comment *x = NULL;
157 if (!buffer || !ast_str_strlen(buffer)) {
158 return NULL;
159 }
160 if ((x = ast_calloc(1, sizeof(*x) + ast_str_strlen(buffer) + 1))) {
161 strcpy(x->cmt, ast_str_buffer(buffer)); /* SAFE */
162 }
163 return x;
164}
165
166/* I need to keep track of each config file, and all its inclusions,
167 so that we can track blank lines in each */
168
169struct inclfile {
170 char *fname;
172};
173
174static int hash_string(const void *obj, const int flags)
175{
176 char *str = ((struct inclfile *) obj)->fname;
177 int total;
178
179 for (total = 0; *str; str++) {
180 unsigned int tmp = total;
181 total <<= 1; /* multiply by 2 */
182 total += tmp; /* multiply by 3 */
183 total <<= 2; /* multiply by 12 */
184 total += tmp; /* multiply by 13 */
185
186 total += ((unsigned int) (*str));
187 }
188 if (total < 0) {
189 total = -total;
190 }
191 return total;
192}
193
194static int hashtab_compare_strings(void *a, void *b, int flags)
195{
196 const struct inclfile *ae = a, *be = b;
197 return !strcmp(ae->fname, be->fname) ? CMP_MATCH | CMP_STOP : 0;
198}
199
200static struct ast_config_map {
203 /*! Stored in stuff[] at struct end. */
204 const char *name;
205 /*! Stored in stuff[] at struct end. */
206 const char *driver;
207 /*! Stored in stuff[] at struct end. */
208 const char *database;
209 /*! Stored in stuff[] at struct end. */
210 const char *table;
211 /*! Contents of name, driver, database, and table in that order stuffed here. */
212 char stuff[0];
214
217
218#define MAX_INCLUDE_LEVEL 10
219
221 char name[80]; /* redundant? */
222 const struct ast_category *inst;
224};
225
227 char name[80];
228 int ignored:1; /*!< do not let user of the config see this category -- set by (!) after the category decl; a template */
229 int loaded:1; /*!< 0 = created in memory, 1 = loaded from disk */
231 /*!
232 * \brief The file name from whence this declaration was read
233 * \note Will never be NULL
234 */
235 char *file;
240 struct ast_comment *trailing; /*!< the last object in the list will get assigned any trailing comments when EOF is hit */
241 /*! First category variable in the list. */
243 /*! Last category variable in the list. */
245 /*! Previous node in the list. */
247 /*! Next node in the list. */
249};
250
252 /*! First config category in the list. */
254 /*! Last config category in the list. */
257 struct ast_category *last_browse; /*!< used to cache the last category supplied via category_browse */
260 /*! First inclusion in the list. */
262 /*! Last inclusion in the list. */
264};
265
268 /*! #include path or matching #tryinclude paths */
269 char path[];
270};
271
272/*!
273 * \brief Types used for ast_include_new() include_type
274 */
276 /*! #include statements */
278 /*! #exec statements */
280 /*! #tryinclude statements */
282};
283
285 /*!
286 * \brief file name in which the include occurs
287 * \note Will never be NULL
288 */
290 int include_location_lineno; /*!< lineno where include occurred */
291 enum include_statement_type include_type; /*!< #include, #exec, #tryinclude */
292 /*!
293 * \brief if it's an exec, you'll have both the /var/tmp to read, and the original script
294 * \note Will never be NULL if exec is non-zero
295 */
297 /*!
298 * \brief file name included
299 * \note Will never be NULL
300 */
303 int inclusion_count; /*!< if the file is included more than once, a running count thereof -- but, worry not,
304 we explode the instances and will include those-- so all entries will be unique */
305 int output; /*!< a flag to indicate if the inclusion has been output */
308 struct ast_comment *trailing; /*!< the last object in the list will get assigned any trailing comments when EOF is hit */
309 struct ast_config_include *next; /*!< ptr to next inclusion in the list */
310};
311
312static void ast_variable_destroy(struct ast_variable *doomed);
313static void ast_includes_destroy(struct ast_config_include *incls);
314
315struct ast_variable *_ast_variable_new(const char *name, const char *value, const char *filename, const char *file, const char *func, int lineno)
316{
317 struct ast_variable *variable;
318 int name_len = strlen(name) + 1;
319 int val_len = strlen(value) + 1;
320 int fn_len = strlen(filename) + 1;
321
322 /* Ensure a minimum length in case the filename is changed later. */
323 if (fn_len < MIN_VARIABLE_FNAME_SPACE) {
325 }
326
327 variable = __ast_calloc(1, fn_len + name_len + val_len + sizeof(*variable),
328 file, lineno, func);
329 if (variable) {
330 char *dst = variable->stuff; /* writable space starts here */
331
332 /* Put file first so ast_include_rename() can calculate space available. */
333 variable->file = strcpy(dst, filename);
334 dst += fn_len;
335 variable->name = strcpy(dst, name);
336 dst += name_len;
337 variable->value = strcpy(dst, value);
338 }
339 return variable;
340}
341
342/*!
343 * \internal
344 * \brief Move the contents from the source to the destination variable.
345 *
346 * \param dst_var Destination variable node
347 * \param src_var Source variable node
348 */
349static void ast_variable_move(struct ast_variable *dst_var, struct ast_variable *src_var)
350{
351 dst_var->lineno = src_var->lineno;
352 dst_var->object = src_var->object;
353 dst_var->blanklines = src_var->blanklines;
354 dst_var->precomments = src_var->precomments;
355 src_var->precomments = NULL;
356 dst_var->sameline = src_var->sameline;
357 src_var->sameline = NULL;
358 dst_var->trailing = src_var->trailing;
359 src_var->trailing = NULL;
360}
361
362static void make_fn(char *fn, size_t fn_size, const char *file, const char *configfile);
363
364struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int include_type, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
365{
366 /* a file should be included ONCE. Otherwise, if one of the instances is changed,
367 * then all be changed. -- how do we know to include it? -- Handling modified
368 * instances is possible, I'd have
369 * to create a new master for each instance. */
370 struct ast_config_include *inc;
371 struct config_included_file *inc_file;
372 struct stat statbuf;
373 char fn[PATH_MAX];
374
375 inc = ast_include_find(conf, included_file);
376 if (inc) {
377 do {
378 inc->inclusion_count++;
379 snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
380 } while (stat(real_included_file_name, &statbuf) == 0);
381 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);
382 } else
383 *real_included_file_name = 0;
384
385 inc = ast_calloc(1,sizeof(struct ast_config_include));
386 if (!inc) {
387 return NULL;
388 }
389 inc->include_location_file = ast_strdup(from_file);
390 if (!inc->include_location_file) {
392 return NULL;
393 }
394 inc->include_location_lineno = from_lineno;
395 if (!ast_strlen_zero(real_included_file_name)) {
396 inc->included_file = ast_strdup(real_included_file_name);
397 } else {
398 inc->included_file = ast_strdup(included_file);
399 }
400 if (!inc->included_file) {
402 return NULL;
403 }
404
405 inc->include_type = include_type;
406
407 make_fn(fn, sizeof(fn), inc->included_file, from_file);
408 switch (inc->include_type) {
410 inc_file = ast_calloc(1, sizeof(*inc_file) + strlen(fn) + 1);
411 if (!inc_file) {
413 return NULL;
414 }
415 strcpy(inc_file->path, fn); /* safe */
416 AST_LIST_INSERT_TAIL(&inc->included_files, inc_file, next);
417 break;
419 {
420 int glob_ret;
421 glob_t globbuf;
422
423 /* add files that match the pattern */
424 globbuf.gl_offs = 0;
425 glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
426 if (glob_ret == 0) {
427 int i;
428
429 for (i = 0; i < globbuf.gl_pathc; i++) {
430 char *matched_path = globbuf.gl_pathv[i];
431
432 if (access(matched_path, F_OK) != 0) {
433 /* skip #tryinclude paths that do not already exist. */
434 continue;
435 }
436
437 inc_file = ast_calloc(1, sizeof(*inc_file) + strlen(matched_path) + 1);
438 if (!inc_file) {
440 globfree(&globbuf);
441 return NULL;
442 }
443 strcpy(inc_file->path, matched_path); /* safe */
444 AST_LIST_INSERT_TAIL(&inc->included_files, inc_file, next);
445 }
446 }
447 globfree(&globbuf);
448 break;
449 }
451 inc->exec_file = ast_strdup(exec_file);
452 if (!inc->exec_file) {
454 return NULL;
455 }
456 break;
457 }
458
459 /* attach this new struct to the conf struct */
460 if (conf->includes_root && conf->includes_last) {
461 conf->includes_last->next = inc;
462 } else {
463 conf->includes_root = inc;
464 }
465 conf->includes_last = inc;
466
467 return inc;
468}
469
470void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
471{
472 struct ast_config_include *incl;
473 struct ast_category *cat;
474 char *str;
475
476 int from_len = strlen(from_file);
477 int to_len = strlen(to_file);
478
479 if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
480 return;
481
482 /* the manager code allows you to read in one config file, then
483 * write it back out under a different name. But, the new arrangement
484 * ties output lines to the file name. So, before you try to write
485 * the config file to disk, better riffle thru the data and make sure
486 * the file names are changed.
487 */
488 /* file names are on categories, includes (of course), and on variables. So,
489 * traverse all this and swap names */
490
491 for (incl = conf->includes_root; incl; incl = incl->next) {
492 if (strcmp(incl->include_location_file, from_file) == 0) {
493 if (from_len >= to_len)
494 strcpy(incl->include_location_file, to_file);
495 else {
496 /* Keep the old filename if the allocation fails. */
497 str = ast_strdup(to_file);
498 if (str) {
501 }
502 }
503 }
504 }
505 for (cat = conf->root; cat; cat = cat->next) {
506 struct ast_variable **prev;
507 struct ast_variable *v;
508 struct ast_variable *new_var;
509
510 if (strcmp(cat->file, from_file) == 0) {
511 if (from_len >= to_len)
512 strcpy(cat->file, to_file);
513 else {
514 /* Keep the old filename if the allocation fails. */
515 str = ast_strdup(to_file);
516 if (str) {
517 ast_free(cat->file);
518 cat->file = str;
519 }
520 }
521 }
522 for (prev = &cat->root, v = cat->root; v; prev = &v->next, v = v->next) {
523 if (strcmp(v->file, from_file)) {
524 continue;
525 }
526
527 /*
528 * Calculate actual space available. The file string is
529 * intentionally stuffed before the name string just so we can
530 * do this.
531 */
532 if (to_len < v->name - v->file) {
533 /* The new name will fit in the available space. */
534 str = (char *) v->file;/* Stupid compiler complains about discarding qualifiers even though I used a cast. */
535 strcpy(str, to_file);/* SAFE */
536 continue;
537 }
538
539 /* Keep the old filename if the allocation fails. */
540 new_var = ast_variable_new(v->name, v->value, to_file);
541 if (!new_var) {
542 continue;
543 }
544
545 /* Move items from the old list node to the replacement node. */
546 ast_variable_move(new_var, v);
547
548 /* Replace the old node in the list with the new node. */
549 new_var->next = v->next;
550 if (cat->last == v) {
551 cat->last = new_var;
552 }
553 *prev = new_var;
554
556
557 v = new_var;
558 }
559 }
560}
561
563{
564 struct ast_config_include *x;
565 for (x = conf->includes_root; x; x = x->next) {
566 if (strcmp(x->included_file, included_file) == 0)
567 return x;
568 }
569 return 0;
570}
571
572
573void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
574{
575 if (!variable)
576 return;
577 if (category->last)
578 category->last->next = variable;
579 else
580 category->root = variable;
581 category->last = variable;
582 while (category->last->next)
583 category->last = category->last->next;
584}
585
586void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
587{
588 struct ast_variable *cur = category->root;
589 int lineno;
590 int insertline;
591
592 if (!variable || sscanf(line, "%30d", &insertline) != 1) {
593 return;
594 }
595 if (!insertline) {
596 variable->next = category->root;
597 category->root = variable;
598 } else {
599 for (lineno = 1; lineno < insertline; lineno++) {
600 cur = cur->next;
601 if (!cur->next) {
602 break;
603 }
604 }
605 variable->next = cur->next;
606 cur->next = variable;
607 }
608}
609
611{
612 struct ast_comment *n, *p;
613
614 for (p = *comment; p; p = n) {
615 n = p->next;
616 ast_free(p);
617 }
618
619 *comment = NULL;
620}
621
622static void ast_variable_destroy(struct ast_variable *doomed)
623{
627 ast_free(doomed);
628}
629
631{
632 struct ast_variable *cloned;
633 struct ast_variable *tmp;
634
635 if (!(cloned = ast_variable_new(var->name, var->value, var->file))) {
636 return NULL;
637 }
638
639 tmp = cloned;
640
641 while ((var = var->next)) {
642 if (!(tmp->next = ast_variable_new(var->name, var->value, var->file))) {
643 ast_variables_destroy(cloned);
644 return NULL;
645 }
646 tmp = tmp->next;
647 }
648
649 return cloned;
650}
651
653{
654 struct ast_variable *var1, *var2;
655
656 var1 = var;
657
658 if (!var1 || !var1->next) {
659 return var1;
660 }
661
662 var2 = var1->next;
663 var1->next = NULL;
664
665 while (var2) {
666 struct ast_variable *next = var2->next;
667
668 var2->next = var1;
669 var1 = var2;
670 var2 = next;
671 }
672
673 return var1;
674}
675
677{
678 struct ast_variable *vn;
679
680 while (var) {
681 vn = var;
682 var = var->next;
684 }
685}
686
687struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
688{
689 struct ast_category *cat;
690
691 if (config->last_browse && (config->last_browse->name == category)) {
692 cat = config->last_browse;
693 } else {
694 cat = ast_category_get(config, category, NULL);
695 }
696
697 return (cat) ? cat->root : NULL;
698}
699
700static inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2)
701{
702 l1->next = l2->next;
703 l2->next = l1;
704 return l2;
705}
706
708{
709 struct ast_variable *p, *q;
710 struct ast_variable top;
711 int changed = 1;
712 memset(&top, 0, sizeof(top));
713 top.next = start;
714 if (start != NULL && start->next != NULL) {
715 while (changed) {
716 changed = 0;
717 q = &top;
718 p = top.next;
719 while (p->next != NULL) {
720 if (p->next != NULL && strcmp(p->name, p->next->name) > 0) {
721 q->next = variable_list_switch(p, p->next);
722 changed = 1;
723 }
724 q = p;
725 if (p->next != NULL)
726 p = p->next;
727 }
728 }
729 }
730 return top.next;
731}
732
733struct ast_variable *ast_variable_list_append_hint(struct ast_variable **head, struct ast_variable *search_hint, struct ast_variable *newvar)
734{
735 struct ast_variable *curr;
736 struct ast_variable *sh = search_hint;
737 ast_assert(head != NULL);
738
739 if (!*head) {
740 *head = newvar;
741 } else {
742 if (sh == NULL) {
743 sh = *head;
744 }
745 for (curr = sh; curr->next; curr = curr->next);
746 curr->next = newvar;
747 }
748
749 for (curr = newvar; curr->next; curr = curr->next);
750
751 return curr;
752}
753
754int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *replacement)
755{
756 struct ast_variable *v, **prev = head;
757
758 for (v = *head; v; prev = &v->next, v = v->next) {
759 if (!strcmp(v->name, replacement->name)) {
760 replacement->next = v->next;
761 *prev = replacement;
762 ast_free(v);
763 return 0;
764 }
765 }
766
767 return -1;
768}
769
771 struct ast_variable *new)
772{
773 struct ast_variable *v, **prev = head;
774
775 for (v = *head; v; prev = &v->next, v = v->next) {
776 if (v == old) {
777 new->next = v->next;
778 *prev = new;
779 ast_free(v);
780 return 0;
781 }
782 }
783
784 return -1;
785}
786
787struct ast_str *ast_variable_list_join(const struct ast_variable *head, const char *item_separator,
788 const char *name_value_separator, const char *quote_char, struct ast_str **str)
789{
790 struct ast_variable *var = (struct ast_variable *)head;
791 struct ast_str *local_str = NULL;
792
793 if (str == NULL || *str == NULL) {
795 if (!local_str) {
796 return NULL;
797 }
798 } else {
799 local_str = *str;
800 }
801
802 for (; var; var = var->next) {
803 ast_str_append(&local_str, 0, "%s%s%s%s%s%s", var->name, name_value_separator, S_OR(quote_char, ""),
804 var->value, S_OR(quote_char, ""), var->next ? item_separator : "");
805 }
806
807 if (str != NULL) {
808 *str = local_str;
809 }
810 return local_str;
811}
812
813struct ast_variable *ast_variable_list_from_quoted_string(const char *input, const char *item_separator,
814 const char *name_value_separator, const char *quote_str)
815{
816 char item_sep;
817 char nv_sep;
818 char quote;
819 struct ast_variable *new_list = NULL;
820 struct ast_variable *new_var = NULL;
821 char *item_string;
822 char *item;
823 char *item_name;
824 char *item_value;
825
826 if (ast_strlen_zero(input)) {
827 return NULL;
828 }
829
830 item_sep = ast_strlen_zero(item_separator) ? ',' : item_separator[0];
831 nv_sep = ast_strlen_zero(name_value_separator) ? '=' : name_value_separator[0];
832 quote = ast_strlen_zero(quote_str) ? '"' : quote_str[0];
833 item_string = ast_strip(ast_strdupa(input));
834
835 while ((item = ast_strsep_quoted(&item_string, item_sep, quote, AST_STRSEP_ALL))) {
836 item_name = ast_strsep_quoted(&item, nv_sep, quote, AST_STRSEP_ALL);
837 if (!item_name) {
838 ast_variables_destroy(new_list);
839 return NULL;
840 }
841
842 item_value = ast_strsep_quoted(&item, nv_sep, quote, AST_STRSEP_ALL);
843
844 new_var = ast_variable_new(item_name, item_value ?: "", "");
845 if (!new_var) {
846 ast_variables_destroy(new_list);
847 return NULL;
848 }
849 ast_variable_list_append(&new_list, new_var);
850 }
851 return new_list;
852}
853
854struct ast_variable *ast_variable_list_from_string(const char *input, const char *item_separator,
855 const char *name_value_separator)
856{
857 return ast_variable_list_from_quoted_string(input, item_separator, name_value_separator, NULL);
858}
859
860const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
861{
862 const char *tmp;
863 tmp = ast_variable_retrieve(cfg, cat, var);
864 if (!tmp) {
865 tmp = ast_variable_retrieve(cfg, "general", var);
866 }
867 return tmp;
868}
869
870const char *ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
871{
872 struct ast_variable *v;
873 const char *match = NULL;
874
875 /* We can't return as soon as we find a match, because if a config section overrides
876 * something specified in a template, then the actual effective value is the last
877 * one encountered, not the first one.
878 * (This is like using the -1 index for the AST_CONFIG function.)
879 * Also see ast_variable_find_last_in_list
880 */
881
882 if (category) {
883 for (v = ast_variable_browse(config, category); v; v = v->next) {
884 if (!strcasecmp(variable, v->name)) {
885 match = v->value;
886 }
887 }
888 } else {
889 struct ast_category *cat;
890
891 for (cat = config->root; cat; cat = cat->next) {
892 for (v = cat->root; v; v = v->next) {
893 if (!strcasecmp(variable, v->name)) {
894 match = v->value;
895 }
896 }
897 }
898 }
899
900 return match;
901}
902
904 const char *category, const char *variable, const char *filter)
905{
906 struct ast_category *cat = NULL;
907 const char *value;
908
909 while ((cat = ast_category_browse_filtered(config, category, cat, filter))) {
910 value = ast_variable_find(cat, variable);
911 if (value) {
912 return value;
913 }
914 }
915
916 return NULL;
917}
918
919const char *ast_variable_find(const struct ast_category *category, const char *variable)
920{
921 return ast_variable_find_in_list(category->root, variable);
922}
923
924const struct ast_variable *ast_variable_find_variable_in_list(const struct ast_variable *list, const char *variable_name)
925{
926 const struct ast_variable *v;
927
928 for (v = list; v; v = v->next) {
929 if (!strcasecmp(variable_name, v->name)) {
930 return v;
931 }
932 }
933 return NULL;
934}
935
936int ast_variables_match(const struct ast_variable *left, const struct ast_variable *right)
937{
938 char *op;
939
940 if (left == right) {
941 return 1;
942 }
943
944 if (!(left && right)) {
945 return 0;
946 }
947
948 op = strrchr(right->name, ' ');
949 if (op) {
950 op++;
951 }
952
953 return ast_strings_match(left->value, op ? ast_strdupa(op) : NULL, right->value);
954}
955
956int ast_variable_lists_match(const struct ast_variable *left, const struct ast_variable *right, int exact_match)
957{
958 const struct ast_variable *field;
959 int right_count = 0;
960 int left_count = 0;
961
962 if (left == right) {
963 return 1;
964 }
965
966 if (!(left && right)) {
967 return 0;
968 }
969
970 for (field = right; field; field = field->next) {
971 char *space = strrchr(field->name, ' ');
972 const struct ast_variable *old;
973 char * name = (char *)field->name;
974
975 if (space) {
976 name = ast_strdup(field->name);
977 if (!name) {
978 return 0;
979 }
980 name[space - field->name] = '\0';
981 }
982
984 if (name != field->name) {
985 ast_free(name);
986 }
987
988 if (exact_match) {
989 if (!old || strcmp(old->value, field->value)) {
990 return 0;
991 }
992 } else {
993 if (!ast_variables_match(old, field)) {
994 return 0;
995 }
996 }
997
998 right_count++;
999 }
1000
1001 if (exact_match) {
1002 for (field = left; field; field = field->next) {
1003 left_count++;
1004 }
1005
1006 if (right_count != left_count) {
1007 return 0;
1008 }
1009 }
1010
1011 return 1;
1012}
1013
1014const char *ast_variable_find_in_list(const struct ast_variable *list, const char *variable)
1015{
1016 const struct ast_variable *v;
1017
1018 for (v = list; v; v = v->next) {
1019 if (!strcasecmp(variable, v->name)) {
1020 return v->value;
1021 }
1022 }
1023 return NULL;
1024}
1025
1026const char *ast_variable_find_last_in_list(const struct ast_variable *list, const char *variable)
1027{
1028 const struct ast_variable *v;
1029 const char *found = NULL;
1030
1031 for (v = list; v; v = v->next) {
1032 if (!strcasecmp(variable, v->name)) {
1033 found = v->value;
1034 }
1035 }
1036 return found;
1037}
1038
1039static struct ast_variable *variable_clone(const struct ast_variable *old)
1040{
1041 struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
1042
1043 if (new) {
1044 new->lineno = old->lineno;
1045 new->object = old->object;
1046 new->blanklines = old->blanklines;
1047 /* TODO: clone comments? */
1048 }
1049
1050 return new;
1051}
1052
1053static void move_variables(struct ast_category *old, struct ast_category *new)
1054{
1055 struct ast_variable *var = old->root;
1056
1057 old->root = NULL;
1058 /* we can just move the entire list in a single op */
1060}
1061
1062/*! \brief Returns true if ALL of the regex expressions and category name match.
1063 * Both can be NULL (I.E. no predicate) which results in a true return;
1064 */
1065static int does_category_match(struct ast_category *cat, const char *category_name,
1066 const char *match, char sep)
1067{
1068 char *dupmatch;
1069 char *nvp = NULL;
1070 int match_found = 0, match_expressions = 0;
1071 int template_ok = 0;
1072
1073 /* Only match on category name if it's not a NULL or empty string */
1074 if (!ast_strlen_zero(category_name) && strcasecmp(cat->name, category_name)) {
1075 return 0;
1076 }
1077
1078 /* If match is NULL or empty, automatically match if not a template */
1079 if (ast_strlen_zero(match)) {
1080 return !cat->ignored;
1081 }
1082
1083 dupmatch = ast_strdupa(match);
1084
1085 while ((nvp = ast_strsep(&dupmatch, sep, AST_STRSEP_STRIP))) {
1086 struct ast_variable *v;
1087 char *match_name;
1088 char *match_value = NULL;
1089 char *regerr;
1090 int rc;
1091 regex_t r_name, r_value;
1092
1093 match_expressions++;
1094
1095 match_name = ast_strsep(&nvp, '=', AST_STRSEP_STRIP);
1096 match_value = ast_strsep(&nvp, '=', AST_STRSEP_STRIP);
1097
1098 /* an empty match value is OK. A NULL match value (no =) is NOT. */
1099 if (match_value == NULL) {
1100 break;
1101 }
1102
1103 if (!strcmp("TEMPLATES", match_name)) {
1104 if (!strcasecmp("include", match_value)) {
1105 if (cat->ignored) {
1106 template_ok = 1;
1107 }
1108 match_found++;
1109 } else if (!strcasecmp("restrict", match_value)) {
1110 if (cat->ignored) {
1111 match_found++;
1112 template_ok = 1;
1113 } else {
1114 break;
1115 }
1116 }
1117 continue;
1118 }
1119
1120 if ((rc = regcomp(&r_name, match_name, REG_EXTENDED | REG_NOSUB))) {
1121 regerr = ast_alloca(128);
1122 regerror(rc, &r_name, regerr, 128);
1123 ast_log(LOG_ERROR, "Regular expression '%s' failed to compile: %s\n",
1124 match_name, regerr);
1125 regfree(&r_name);
1126 return 0;
1127 }
1128 if ((rc = regcomp(&r_value, match_value, REG_EXTENDED | REG_NOSUB))) {
1129 regerr = ast_alloca(128);
1130 regerror(rc, &r_value, regerr, 128);
1131 ast_log(LOG_ERROR, "Regular expression '%s' failed to compile: %s\n",
1132 match_value, regerr);
1133 regfree(&r_name);
1134 regfree(&r_value);
1135 return 0;
1136 }
1137
1138 for (v = cat->root; v; v = v->next) {
1139 if (!regexec(&r_name, v->name, 0, NULL, 0)
1140 && !regexec(&r_value, v->value, 0, NULL, 0)) {
1141 match_found++;
1142 break;
1143 }
1144 }
1145 regfree(&r_name);
1146 regfree(&r_value);
1147 }
1148 if (match_found == match_expressions && (!cat->ignored || template_ok)) {
1149 return 1;
1150 }
1151 return 0;
1152}
1153
1154
1155static struct ast_category *new_category(const char *name, const char *in_file, int lineno, int template)
1156{
1157 struct ast_category *category;
1158
1159 category = ast_calloc(1, sizeof(*category));
1160 if (!category) {
1161 return NULL;
1162 }
1163 category->file = ast_strdup(in_file);
1164 if (!category->file) {
1165 ast_category_destroy(category);
1166 return NULL;
1167 }
1168 ast_copy_string(category->name, name, sizeof(category->name));
1169 category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
1170 category->ignored = template;
1171 return category;
1172}
1173
1174struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
1175{
1176 return new_category(name, in_file, lineno, 0);
1177}
1178
1179struct ast_category *ast_category_new_template(const char *name, const char *in_file, int lineno)
1180{
1181 return new_category(name, in_file, lineno, 1);
1182}
1183
1184static struct ast_category *category_get_sep(const struct ast_config *config,
1185 const char *category_name, const char *filter, char sep, char pointer_match_possible)
1186{
1187 struct ast_category *cat;
1188
1189 if (pointer_match_possible) {
1190 for (cat = config->root; cat; cat = cat->next) {
1191 if (cat->name == category_name && does_category_match(cat, category_name, filter, sep)) {
1192 return cat;
1193 }
1194 }
1195 }
1196
1197 for (cat = config->root; cat; cat = cat->next) {
1198 if (does_category_match(cat, category_name, filter, sep)) {
1199 return cat;
1200 }
1201 }
1202
1203 return NULL;
1204}
1205
1207 const char *category_name, const char *filter)
1208{
1209 return category_get_sep(config, category_name, filter, ',', 1);
1210}
1211
1212const char *ast_category_get_name(const struct ast_category *category)
1213{
1214 return category->name;
1215}
1216
1217int ast_category_is_template(const struct ast_category *category)
1218{
1219 return category->ignored;
1220}
1221
1222struct ast_str *ast_category_get_templates(const struct ast_category *category)
1223{
1224 struct ast_category_template_instance *template;
1225 struct ast_str *str;
1226 int first = 1;
1227
1228 if (AST_LIST_EMPTY(&category->template_instances)) {
1229 return NULL;
1230 }
1231
1232 str = ast_str_create(128);
1233 if (!str) {
1234 return NULL;
1235 }
1236
1237 AST_LIST_TRAVERSE(&category->template_instances, template, next) {
1238 ast_str_append(&str, 0, "%s%s", first ? "" : ",", template->name);
1239 first = 0;
1240 }
1241
1242 return str;
1243}
1244
1245int ast_category_exist(const struct ast_config *config, const char *category_name,
1246 const char *filter)
1247{
1248 return !!ast_category_get(config, category_name, filter);
1249}
1250
1251void ast_category_append(struct ast_config *config, struct ast_category *category)
1252{
1253 if (config->last) {
1254 config->last->next = category;
1255 category->prev = config->last;
1256 } else {
1257 config->root = category;
1258 category->prev = NULL;
1259 }
1260 category->next = NULL;
1261 category->include_level = config->include_level;
1262
1263 config->last = category;
1264 config->current = category;
1265}
1266
1267int ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
1268{
1269 struct ast_category *cur_category;
1270
1271 if (!config || !config->root || !cat || !match) {
1272 return -1;
1273 }
1274
1275 if (!strcasecmp(config->root->name, match)) {
1276 cat->next = config->root;
1277 cat->prev = NULL;
1278 config->root->prev = cat;
1279 config->root = cat;
1280 return 0;
1281 }
1282
1283 for (cur_category = config->root->next; cur_category; cur_category = cur_category->next) {
1284 if (!strcasecmp(cur_category->name, match)) {
1285 cat->prev = cur_category->prev;
1286 cat->prev->next = cat;
1287
1288 cat->next = cur_category;
1289 cur_category->prev = cat;
1290
1291 return 0;
1292 }
1293 }
1294
1295 return -1;
1296}
1297
1299{
1301
1302 while ((x = AST_LIST_REMOVE_HEAD(&cat->template_instances, next)))
1303 ast_free(x);
1304}
1305
1307{
1309 cat->root = NULL;
1310 cat->last = NULL;
1315 ast_free(cat->file);
1316 ast_free(cat);
1317}
1318
1320{
1321 struct config_included_file *x;
1322
1323 while ((x = AST_LIST_REMOVE_HEAD(&incl->included_files, next))) {
1324 ast_free(x);
1325 }
1326}
1327
1329{
1331 ast_free(incl->exec_file);
1332 ast_free(incl->included_file);
1337 ast_free(incl);
1338}
1339
1341{
1342 struct ast_config_include *incl, *inclnext;
1343
1344 for (incl = incls; incl; incl = inclnext) {
1345 inclnext = incl->next;
1346 ast_include_destroy(incl);
1347 }
1348}
1349
1351 const char *name, const char *filter)
1352{
1353 for (; cat && !does_category_match(cat, name, filter, ','); cat = cat->next);
1354
1355 return cat;
1356}
1357
1358/*! return the first var of a category */
1360{
1361 return (cat) ? cat->root : NULL;
1362}
1363
1365{
1366 struct ast_category *category = ast_category_get(config, cat, NULL);
1367
1368 if (category)
1369 return category->root;
1370 return NULL;
1371}
1372
1373void ast_config_sort_categories(struct ast_config *config, int descending,
1374 int (*comparator)(struct ast_category *p, struct ast_category *q))
1375{
1376 /*
1377 * The contents of this function are adapted from
1378 * an example of linked list merge sorting
1379 * copyright 2001 Simon Tatham.
1380 *
1381 * Permission is hereby granted, free of charge, to any person
1382 * obtaining a copy of this software and associated documentation
1383 * files (the "Software"), to deal in the Software without
1384 * restriction, including without limitation the rights to use,
1385 * copy, modify, merge, publish, distribute, sublicense, and/or
1386 * sell copies of the Software, and to permit persons to whom the
1387 * Software is furnished to do so, subject to the following
1388 * conditions:
1389 *
1390 * The above copyright notice and this permission notice shall be
1391 * included in all copies or substantial portions of the Software.
1392 *
1393 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1394 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
1395 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1396 * NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
1397 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
1398 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1399 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1400 * SOFTWARE.
1401 */
1402
1403 int insize = 1;
1404 struct ast_category *p, *q, *e, *tail;
1405 int nmerges, psize, qsize, i;
1406
1407 /* If the descending flag was sent, we'll apply inversion to the comparison function's return. */
1408 if (descending) {
1409 descending = -1;
1410 } else {
1411 descending = 1;
1412 }
1413
1414 if (!config->root) {
1415 return;
1416 }
1417
1418 while (1) {
1419 p = config->root;
1420 config->root = NULL;
1421 tail = NULL;
1422
1423 nmerges = 0; /* count number of merges we do in this pass */
1424
1425 while (p) {
1426 nmerges++; /* there exists a merge to be done */
1427
1428 /* step `insize' places along from p */
1429 q = p;
1430 psize = 0;
1431 for (i = 0; i < insize; i++) {
1432 psize++;
1433 q = q->next;
1434 if (!q) {
1435 break;
1436 }
1437 }
1438
1439 /* if q hasn't fallen off end, we have two lists to merge */
1440 qsize = insize;
1441
1442 /* now we have two lists; merge them */
1443 while (psize > 0 || (qsize > 0 && q)) {
1444 /* decide whether next element of merge comes from p or q */
1445 if (psize == 0) {
1446 /* p is empty; e must come from q. */
1447 e = q;
1448 q = q->next;
1449 qsize--;
1450 } else if (qsize == 0 || !q) {
1451 /* q is empty; e must come from p. */
1452 e = p; p = p->next; psize--;
1453 } else if ((comparator(p, q) * descending) <= 0) {
1454 /* First element of p is lower (or same) e must come from p. */
1455 e = p;
1456 p = p->next;
1457 psize--;
1458 } else {
1459 /* First element of q is lower; e must come from q. */
1460 e = q;
1461 q = q->next;
1462 qsize--;
1463 }
1464
1465 /* add the next element to the merged list */
1466 if (tail) {
1467 tail->next = e;
1468 } else {
1469 config->root = e;
1470 }
1471 tail = e;
1472 }
1473
1474 /* now p has stepped `insize' places along, and q has too */
1475 p = q;
1476 }
1477
1478 tail->next = NULL;
1479
1480 /* If we have done only one merge, we're finished. */
1481 if (nmerges <= 1) { /* allow for nmerges==0, the empty list case */
1482 return;
1483 }
1484
1485 /* Otherwise repeat, merging lists twice the size */
1486 insize *= 2;
1487 }
1488
1489}
1490
1491char *ast_category_browse(struct ast_config *config, const char *prev_name)
1492{
1493 struct ast_category *cat;
1494
1495 if (!prev_name) {
1496 /* First time browse. */
1497 cat = config->root;
1498 } else if (config->last_browse && (config->last_browse->name == prev_name)) {
1499 /* Simple last browse found. */
1500 cat = config->last_browse->next;
1501 } else {
1502 /*
1503 * Config changed since last browse.
1504 *
1505 * First try cheap last browse search. (Rebrowsing a different
1506 * previous category?)
1507 */
1508 for (cat = config->root; cat; cat = cat->next) {
1509 if (cat->name == prev_name) {
1510 /* Found it. */
1511 cat = cat->next;
1512 break;
1513 }
1514 }
1515 if (!cat) {
1516 /*
1517 * Have to do it the hard way. (Last category was deleted and
1518 * re-added?)
1519 */
1520 for (cat = config->root; cat; cat = cat->next) {
1521 if (!strcasecmp(cat->name, prev_name)) {
1522 /* Found it. */
1523 cat = cat->next;
1524 break;
1525 }
1526 }
1527 }
1528 }
1529
1530 if (cat)
1531 cat = next_available_category(cat, NULL, NULL);
1532
1533 config->last_browse = cat;
1534 return (cat) ? cat->name : NULL;
1535}
1536
1538 const char *category_name, struct ast_category *prev, const char *filter)
1539{
1540 struct ast_category *cat;
1541
1542 if (!prev) {
1543 prev = config->root;
1544 } else {
1545 prev = prev->next;
1546 }
1547
1548 cat = next_available_category(prev, category_name, filter);
1549
1550 return cat;
1551}
1552
1554{
1555 struct ast_variable *v;
1556
1557 v = cat->root;
1558 cat->root = NULL;
1559 cat->last = NULL;
1560
1561 return v;
1562}
1563
1564void ast_category_rename(struct ast_category *cat, const char *name)
1565{
1566 ast_copy_string(cat->name, name, sizeof(cat->name));
1567}
1568
1569int ast_category_inherit(struct ast_category *new, const struct ast_category *base)
1570{
1571 struct ast_variable *var;
1573
1574 x = ast_calloc(1, sizeof(*x));
1575 if (!x) {
1576 return -1;
1577 }
1578 strcpy(x->name, base->name);
1579 x->inst = base;
1580 AST_LIST_INSERT_TAIL(&new->template_instances, x, next);
1581 for (var = base->root; var; var = var->next) {
1582 struct ast_variable *cloned = variable_clone(var);
1583 if (!cloned) {
1584 return -1;
1585 }
1586 cloned->inherited = 1;
1587 ast_variable_append(new, cloned);
1588 }
1589 return 0;
1590}
1591
1593{
1594 struct ast_config *config;
1595
1596 if ((config = ast_calloc(1, sizeof(*config))))
1597 config->max_include_level = MAX_INCLUDE_LEVEL;
1598 return config;
1599}
1600
1601int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
1602{
1603 struct ast_variable *cur, *prev=NULL, *curn;
1604 int res = -1;
1605 int num_item = 0;
1606 int req_item;
1607
1608 req_item = -1;
1609 if (!ast_strlen_zero(line)) {
1610 /* Requesting to delete by item number. */
1611 if (sscanf(line, "%30d", &req_item) != 1
1612 || req_item < 0) {
1613 /* Invalid item number to delete. */
1614 return -1;
1615 }
1616 }
1617
1618 prev = NULL;
1619 cur = category->root;
1620 while (cur) {
1621 curn = cur->next;
1622 /* Delete by item number or by variable name with optional value. */
1623 if ((0 <= req_item && num_item == req_item)
1624 || (req_item < 0 && !strcasecmp(cur->name, variable)
1625 && (ast_strlen_zero(match) || !strcasecmp(cur->value, match)))) {
1626 if (prev) {
1627 prev->next = cur->next;
1628 if (cur == category->last)
1629 category->last = prev;
1630 } else {
1631 category->root = cur->next;
1632 if (cur == category->last)
1633 category->last = NULL;
1634 }
1636 res = 0;
1637 } else
1638 prev = cur;
1639
1640 cur = curn;
1641 ++num_item;
1642 }
1643 return res;
1644}
1645
1646int ast_variable_update(struct ast_category *category, const char *variable,
1647 const char *value, const char *match, unsigned int object)
1648{
1649 struct ast_variable *cur, *prev = NULL, *newer = NULL;
1650 struct ast_variable *matchcur = NULL, *matchprev = NULL;
1651
1652 /* Find the last match. See comments in ast_variable_retrieve,
1653 * but this ensures updating config sections that inherit from
1654 * templates works properly. */
1655 for (cur = category->root; cur; prev = cur, cur = cur->next) {
1656 if (strcasecmp(cur->name, variable) || (!ast_strlen_zero(match) && strcasecmp(cur->value, match))) {
1657 /* Not the same variable,
1658 * or its value doesn't match. */
1659 continue;
1660 }
1661 matchprev = prev;
1662 matchcur = cur;
1663 }
1664
1665 if (!matchcur) {
1666 /* Could not find variable to update */
1667 return -1;
1668 }
1669
1670 /* Restore pointers from the matching var */
1671 prev = matchprev;
1672 cur = matchcur;
1673
1674 if (!(newer = ast_variable_new(variable, value, cur->file))) {
1675 return -1;
1676 }
1677
1678 ast_variable_move(newer, cur);
1679 newer->object = newer->object || object;
1680
1681 /* Replace the old node in the list with the new node. */
1682 newer->next = cur->next;
1683 if (prev) {
1684 prev->next = newer;
1685 } else {
1686 category->root = newer;
1687 }
1688 if (category->last == cur) {
1689 category->last = newer;
1690 }
1691
1693 return 0;
1694}
1695
1697 struct ast_category *category)
1698{
1699 struct ast_category *prev;
1700
1701 if (!config || !category) {
1702 return NULL;
1703 }
1704
1705 if (category->prev) {
1706 category->prev->next = category->next;
1707 } else {
1708 config->root = category->next;
1709 }
1710
1711 if (category->next) {
1712 category->next->prev = category->prev;
1713 } else {
1714 config->last = category->prev;
1715 }
1716
1717 prev = category->prev;
1718
1719 if (config->last_browse == category) {
1720 config->last_browse = prev;
1721 }
1722
1723 ast_category_destroy(category);
1724
1725 return prev;
1726}
1727
1729{
1730 if (!category) {
1731 return -1;
1732 }
1733
1734 ast_variables_destroy(category->root);
1735 category->root = NULL;
1736 category->last = NULL;
1737
1738 return 0;
1739}
1740
1742{
1743 struct ast_category *cat, *catn;
1744
1745 if (!cfg)
1746 return;
1747
1749
1750 cat = cfg->root;
1751 while (cat) {
1752 catn = cat;
1753 cat = cat->next;
1755 }
1756 ast_free(cfg);
1757}
1758
1760{
1761 return cfg->current;
1762}
1763
1764void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
1765{
1766 /* cast below is just to silence compiler warning about dropping "const" */
1767 cfg->current = (struct ast_category *) cat;
1768}
1769
1770/*!
1771 * \internal
1772 * \brief Create a new cfmtime list node.
1773 *
1774 * \param filename Config filename caching.
1775 * \param who_asked Who wanted to know.
1776 *
1777 * \retval cfmtime New node on success.
1778 * \retval NULL on error.
1779 */
1780static struct cache_file_mtime *cfmtime_new(const char *filename, const char *who_asked)
1781{
1782 struct cache_file_mtime *cfmtime;
1783 char *dst;
1784
1785 cfmtime = ast_calloc(1,
1786 sizeof(*cfmtime) + strlen(filename) + 1 + strlen(who_asked) + 1);
1787 if (!cfmtime) {
1788 return NULL;
1789 }
1790 dst = cfmtime->filename; /* writable space starts here */
1791 strcpy(dst, filename); /* Safe */
1792 dst += strlen(dst) + 1;
1793 cfmtime->who_asked = strcpy(dst, who_asked); /* Safe */
1794
1795 return cfmtime;
1796}
1797
1801};
1802
1803/*!
1804 * \internal
1805 * \brief Save the stat() data to the cached file modtime struct.
1806 *
1807 * \param cfmtime Cached file modtime.
1808 * \param statbuf Buffer filled in by stat().
1809 */
1810static void cfmstat_save(struct cache_file_mtime *cfmtime, struct stat *statbuf)
1811{
1812 cfmtime->stat_size = statbuf->st_size;
1813#if defined(HAVE_STRUCT_STAT_ST_MTIM)
1814 cfmtime->stat_mtime_nsec = statbuf->st_mtim.tv_nsec;
1815#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
1816 cfmtime->stat_mtime_nsec = statbuf->st_mtimensec;
1817#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
1818 cfmtime->stat_mtime_nsec = statbuf->st_mtimespec.tv_nsec;
1819#else
1820 cfmtime->stat_mtime_nsec = 0;
1821#endif
1822 cfmtime->stat_mtime = statbuf->st_mtime;
1823}
1824
1825/*!
1826 * \internal
1827 * \brief Compare the stat() data with the cached file modtime struct.
1828 *
1829 * \param cfmtime Cached file modtime.
1830 * \param statbuf Buffer filled in by stat().
1831 *
1832 * \retval non-zero if different.
1833 */
1834static int cfmstat_cmp(struct cache_file_mtime *cfmtime, struct stat *statbuf)
1835{
1836 struct cache_file_mtime cfm_buf;
1837
1838 cfmstat_save(&cfm_buf, statbuf);
1839
1840 return cfmtime->stat_size != cfm_buf.stat_size
1841 || cfmtime->stat_mtime != cfm_buf.stat_mtime
1842 || cfmtime->stat_mtime_nsec != cfm_buf.stat_mtime_nsec;
1843}
1844
1845/*!
1846 * \internal
1847 * \brief Clear the cached file modtime include list.
1848 *
1849 * \param cfmtime Cached file modtime.
1850 *
1851 * \note cfmtime_head is assumed already locked.
1852 */
1854{
1855 struct cache_file_include *cfinclude;
1856
1857 while ((cfinclude = AST_LIST_REMOVE_HEAD(&cfmtime->includes, list))) {
1858 ast_free(cfinclude);
1859 }
1860}
1861
1862/*!
1863 * \internal
1864 * \brief Destroy the given cached file modtime entry.
1865 *
1866 * \param cfmtime Cached file modtime.
1867 *
1868 * \note cfmtime_head is assumed already locked.
1869 */
1871{
1873 ast_free(cfmtime);
1874}
1875
1876/*!
1877 * \internal
1878 * \brief Remove and destroy the config cache entry for the filename and who_asked.
1879 *
1880 * \param filename Config filename.
1881 * \param who_asked Which module asked.
1882 */
1883static void config_cache_remove(const char *filename, const char *who_asked)
1884{
1885 struct cache_file_mtime *cfmtime;
1886
1889 if (!strcmp(cfmtime->filename, filename)
1890 && !strcmp(cfmtime->who_asked, who_asked)) {
1893 break;
1894 }
1895 }
1898}
1899
1900static void config_cache_attribute(const char *configfile, enum config_cache_attribute_enum attrtype, const char *filename, const char *who_asked)
1901{
1902 struct cache_file_mtime *cfmtime;
1903 struct cache_file_include *cfinclude;
1904
1905 /* Find our cached entry for this configuration file */
1907 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
1908 if (!strcmp(cfmtime->filename, configfile) && !strcmp(cfmtime->who_asked, who_asked))
1909 break;
1910 }
1911 if (!cfmtime) {
1912 cfmtime = cfmtime_new(configfile, who_asked);
1913 if (!cfmtime) {
1915 return;
1916 }
1917 /* Note that the file mtime is initialized to 0, i.e. 1970 */
1918 AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
1919 }
1920
1921 switch (attrtype) {
1922 case ATTRIBUTE_INCLUDE:
1923 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
1924 if (!strcmp(cfinclude->include, filename)) {
1926 return;
1927 }
1928 }
1929 cfinclude = ast_calloc(1, sizeof(*cfinclude) + strlen(filename) + 1);
1930 if (!cfinclude) {
1932 return;
1933 }
1934 strcpy(cfinclude->include, filename); /* Safe */
1935 AST_LIST_INSERT_TAIL(&cfmtime->includes, cfinclude, list);
1936 break;
1937 case ATTRIBUTE_EXEC:
1938 cfmtime->has_exec = 1;
1939 break;
1940 }
1942}
1943
1944/*!
1945 * \internal
1946 * \brief Process an #exec include, reporting errors.
1947 *
1948 * For backwards compatibility we return success in most cases because we
1949 * do not want to prevent the rest of the configuration (or the module
1950 * loading that configuration) from loading.
1951 *
1952 * \param command The command to execute
1953 * \param output_file The filename to write to
1954 *
1955 * \retval 0 on success
1956 * \retval -1 on failure
1957 */
1958static int handle_include_exec(const char *command, const char *output_file)
1959{
1960 char buf[1024];
1961 FILE *fp;
1962 int status;
1963 struct stat output_file_info;
1964
1965 /* stderr to stdout, stdout to file */
1966 if (snprintf(buf, sizeof(buf), "%s 2>&1 > %s", command, output_file) >= sizeof(buf)) {
1967 ast_log(LOG_ERROR, "Failed to construct command string to execute %s.\n", command);
1968 return -1;
1969 }
1970
1972
1973 errno = 0;
1974
1975 fp = popen(buf, "r");
1976 if (!fp) {
1977 ast_log(LOG_ERROR, "#exec <%s>: Failed to execute: %s\n",
1978 command,
1979 strerror(errno));
1981 return 0;
1982 }
1983
1984 while (fgets(buf, sizeof(buf), fp)) {
1985 /* Ensure we have a \n at the end */
1986 if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 2] != '\n') {
1987 ast_log(LOG_ERROR, "#exec <%s>: %s... <truncated>\n",
1988 command,
1989 buf);
1990
1991 /* Consume the rest of the line */
1992 while (fgets(buf, sizeof(buf), fp)) {
1993 if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 2] == '\n') {
1994 break;
1995 }
1996 }
1997
1998 continue;
1999 }
2000
2001 /* `buf` has the newline, so we don't need to print it ourselves */
2002 ast_log(LOG_ERROR, "#exec <%s>: %s",
2003 command,
2004 buf);
2005 }
2006
2007 status = pclose(fp);
2008 if (status == -1) {
2009 ast_log(LOG_ERROR, "#exec <%s>: Failed to retrieve exit status: %s\n",
2010 command,
2011 strerror(errno));
2012 } else {
2014 if (status) {
2015 ast_log(LOG_ERROR, "#exec <%s>: Exited with return value %d\n",
2016 command,
2017 status);
2018 }
2019 }
2020
2022
2023 /* Check that the output file contains something */
2024 if (stat(output_file, &output_file_info) == -1) {
2025 ast_log(LOG_ERROR, "#exec <%s>: Unable to stat() temporary file `%s': %s\n",
2026 command,
2027 output_file,
2028 strerror(errno));
2029 } else if (output_file_info.st_size == 0) {
2030 ast_log(LOG_WARNING, "#exec <%s>: The program generated no usable output.\n",
2031 command);
2032 }
2033
2034 return 0;
2035}
2036
2037/*! \brief parse one line in the configuration.
2038 * \verbatim
2039 * We can have a category header [foo](...)
2040 * a directive #include, #tryinclude, #exec
2041 * or a regular line name = value
2042 * \endverbatim
2043 */
2044static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
2045 char *buf, int lineno, const char *configfile, struct ast_flags flags,
2046 struct ast_str *comment_buffer,
2047 struct ast_str *lline_buffer,
2048 const char *suggested_include_file,
2049 struct ast_category **last_cat,
2050 struct ast_variable **last_var,
2051 struct ast_config_include **last_inc,
2052 const char *who_asked)
2053{
2054 char *c;
2055 char *cur = buf;
2056 struct ast_variable *v;
2057 char exec_file[512];
2058
2059 /* Actually parse the entry */
2060 if (cur[0] == '[') { /* A category header */
2061 /* format is one of the following:
2062 * [foo] define a new category named 'foo'
2063 * [foo](!) define a new template category named 'foo'
2064 * [foo](+) append to category 'foo', error if foo does not exist.
2065 * [foo](a) define a new category and inherit from category or template a.
2066 * You can put a comma-separated list of categories and templates
2067 * and '!' and '+' between parentheses, with obvious meaning.
2068 */
2069 struct ast_category *newcat;
2070 char *catname;
2071
2072 c = strchr(cur, ']');
2073 if (!c) {
2074 ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
2075 return -1;
2076 }
2077 *c++ = '\0';
2078 cur++;
2079 if (*c++ != '(')
2080 c = NULL;
2081 catname = cur;
2082 *cat = newcat = ast_category_new(catname,
2083 S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile),
2084 lineno);
2085 if (!newcat) {
2086 return -1;
2087 }
2088 (*cat)->loaded = 1;
2089 (*cat)->lineno = lineno;
2090
2091 /* add comments */
2096 }
2097
2098 /* If there are options or categories to inherit from, process them now */
2099 if (c) {
2100 if (!(cur = strchr(c, ')'))) {
2101 ast_category_destroy(newcat);
2102 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
2103 return -1;
2104 }
2105 *cur = '\0';
2106 while ((cur = strsep(&c, ","))) {
2107 if (!strcasecmp(cur, "!")) {
2108 (*cat)->ignored = 1;
2109 } else if (cur[0] == '+') {
2110 char *filter = NULL;
2111
2112 if (cur[1] != ',') {
2113 filter = &cur[1];
2114 }
2115 *cat = category_get_sep(cfg, catname, filter, '&', 0);
2116 if (!(*cat)) {
2117 if (newcat) {
2118 ast_category_destroy(newcat);
2119 }
2120 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
2121 return -1;
2122 }
2123 if (newcat) {
2125 (*cat)->ignored |= newcat->ignored;
2126 move_variables(newcat, *cat);
2127 ast_category_destroy(newcat);
2128 newcat = NULL;
2129 }
2130 } else {
2131 struct ast_category *base;
2132
2133 base = category_get_sep(cfg, cur, "TEMPLATES=include", ',', 0);
2134 if (!base) {
2135 if (newcat) {
2136 ast_category_destroy(newcat);
2137 }
2138 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
2139 return -1;
2140 }
2141 if (ast_category_inherit(*cat, base)) {
2142 if (newcat) {
2143 ast_category_destroy(newcat);
2144 }
2145 ast_log(LOG_ERROR, "Inheritance requested, but allocation failed\n");
2146 return -1;
2147 }
2148 }
2149 }
2150 }
2151
2152 /*
2153 * We need to set *last_cat to newcat here regardless. If the
2154 * category is being appended to we have no place for trailing
2155 * comments on the appended category. The appended category
2156 * may be in another file or it already has trailing comments
2157 * that we would then leak.
2158 */
2159 *last_cat = newcat;
2160 *last_var = NULL;
2161 *last_inc = NULL;
2162 if (newcat) {
2163 ast_category_append(cfg, newcat);
2164 }
2165 } else if (cur[0] == '#') { /* A directive - #include, #tryinclude, or #exec */
2166 char *cur2;
2167 char real_inclusion_name[256];
2168 int include_type;
2169 struct ast_config_include *newinclude;
2170 struct ast_config *result;
2171
2172 cur++;
2173 c = cur;
2174 while (*c && (*c > 32)) {
2175 c++;
2176 }
2177
2178 if (*c) {
2179 *c = '\0';
2180 /* Find real argument */
2181 c = ast_strip(c + 1);
2182 if (!(*c)) {
2183 c = NULL;
2184 }
2185 } else {
2186 c = NULL;
2187 }
2188 if (!strcasecmp(cur, "include")) {
2189 include_type = CONFIG_STATEMENT_INCLUDE;
2190 } else if (!strcasecmp(cur, "tryinclude")) {
2191 include_type = CONFIG_STATEMENT_TRYINCLUDE;
2192 } else if (!strcasecmp(cur, "exec")) {
2193 if (!ast_opt_exec_includes) {
2194 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
2195 return 0; /* XXX is this correct ? or we should return -1 ? */
2196 }
2197 include_type = CONFIG_STATEMENT_EXEC;
2198 } else {
2199 ast_log(LOG_WARNING, "Unknown directive '#%s' at line %d of %s\n", cur, lineno, configfile);
2200 return 0; /* XXX is this correct ? or we should return -1 ? */
2201 }
2202
2203 if (c == NULL) {
2204 ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
2205 cur,
2206 (include_type != CONFIG_STATEMENT_EXEC) ? "filename" : "/path/to/executable",
2207 lineno,
2208 configfile);
2209 return 0; /* XXX is this correct ? or we should return -1 ? */
2210 }
2211
2212 cur = c;
2213 /* Strip off leading and trailing "'s and <>'s */
2214 /* Dequote */
2215 if ((*c == '"') || (*c == '<')) {
2216 char quote_char = *c;
2217 if (quote_char == '<') {
2218 quote_char = '>';
2219 }
2220
2221 if (*(c + strlen(c) - 1) == quote_char) {
2222 cur++;
2223 *(c + strlen(c) - 1) = '\0';
2224 }
2225 }
2226 cur2 = cur;
2227
2228 if (include_type == CONFIG_STATEMENT_EXEC) {
2229 /* #exec </path/to/executable>
2230 We create a tmp file, then we #include it, then we delete it. */
2231 struct timeval now = ast_tvnow();
2232
2233 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
2234 config_cache_attribute(configfile, ATTRIBUTE_EXEC, NULL, who_asked);
2235 snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d%d.%ld", (int)now.tv_sec, (int)now.tv_usec, (long)pthread_self());
2236 if (handle_include_exec(cur, exec_file)) {
2237 return -1;
2238 }
2239 cur = exec_file;
2240 } else {
2241 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
2242 config_cache_attribute(configfile, ATTRIBUTE_INCLUDE, cur, who_asked);
2243 exec_file[0] = '\0';
2244 }
2245 /* A #include */
2246 /* record this inclusion */
2247 newinclude = ast_include_new(cfg, cfg->include_level == 1 ? "" : configfile, cur, include_type, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
2248 if (!newinclude) {
2249 if (!ast_strlen_zero(exec_file)) {
2250 unlink(exec_file);
2251 }
2252 return -1;
2253 }
2254
2255 result = ast_config_internal_load(cur, cfg, flags, real_inclusion_name, who_asked);
2256 if (!ast_strlen_zero(exec_file)) {
2257 unlink(exec_file);
2258 }
2259 if (!result && (include_type != CONFIG_STATEMENT_TRYINCLUDE)) {
2260 ast_log(LOG_ERROR, "The file '%s' was listed as a #include but it does not exist.\n", cur);
2261 return -1;
2262 }
2263
2264 /* add comments */
2267 newinclude->sameline = ALLOC_COMMENT(lline_buffer);
2269 }
2270
2271 /* for now, any end-of-file (trailing) comments are after this #include */
2272 *last_cat = NULL;
2273 *last_var = NULL;
2274 *last_inc = newinclude;
2275 } else {
2276 /* Just a line (variable = value) */
2277 int object = 0;
2278 int is_escaped;
2279
2280 if (!(*cat)) {
2282 "parse error: No category context for line %d of %s\n", lineno, configfile);
2283 return -1;
2284 }
2285
2286 is_escaped = cur[0] == '\\';
2287 if (is_escaped) {
2288 /* First character is escaped. */
2289 ++cur;
2290 if (cur[0] < 33) {
2291 ast_log(LOG_ERROR, "Invalid escape in line %d of %s\n", lineno, configfile);
2292 return -1;
2293 }
2294 }
2295 c = strchr(cur + is_escaped, '=');
2296
2297 if (c && c > cur + is_escaped && (*(c - 1) == '+')) {
2298 struct ast_variable *var, *replace = NULL;
2299 struct ast_str **str = ast_threadstorage_get(&appendbuf, sizeof(*str));
2300
2301 if (!str || !*str) {
2302 return -1;
2303 }
2304
2305 *(c - 1) = '\0';
2306 c++;
2307 cur = ast_strip(cur);
2308
2309 /* Must iterate through category until we find last variable of same name (since there could be multiple) */
2310 for (var = ast_category_first(*cat); var; var = var->next) {
2311 if (!strcmp(var->name, cur)) {
2312 replace = var;
2313 }
2314 }
2315
2316 if (!replace) {
2317 /* Nothing to replace; just set a variable normally. */
2318 goto set_new_variable;
2319 }
2320
2321 ast_str_set(str, 0, "%s", replace->value);
2322 ast_str_append(str, 0, "%s", c);
2324 ast_variable_update(*cat, replace->name, ast_skip_blanks(ast_str_buffer(*str)), replace->value, object);
2325 } else if (c) {
2326 *c = 0;
2327 c++;
2328 /* Ignore > in => */
2329 if (*c== '>') {
2330 object = 1;
2331 c++;
2332 }
2333 cur = ast_strip(cur);
2334set_new_variable:
2335 if (ast_strlen_zero(cur)) {
2336 ast_log(LOG_WARNING, "No variable name in line %d of %s\n", lineno, configfile);
2337 } else if ((v = ast_variable_new(cur, ast_strip(c), S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile)))) {
2338 v->lineno = lineno;
2339 v->object = object;
2340 *last_cat = NULL;
2341 *last_var = v;
2342 *last_inc = NULL;
2343 /* Put and reset comments */
2344 v->blanklines = 0;
2345 ast_variable_append(*cat, v);
2346 /* add comments */
2351 }
2352 } else {
2353 return -1;
2354 }
2355 } else {
2356 ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
2357 }
2358 }
2359 return 0;
2360}
2361
2362static 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)
2363{
2364 char fn[256];
2365#if defined(LOW_MEMORY)
2366 char buf[512];
2367#else
2368 char buf[8192];
2369#endif
2370 char *new_buf, *comment_p, *process_buf;
2371 FILE *f;
2372 int lineno=0;
2373 int comment = 0, nest[MAX_NESTED_COMMENTS];
2374 struct ast_category *cat = NULL;
2375 int count = 0;
2376 struct stat statbuf;
2377 struct cache_file_mtime *cfmtime = NULL;
2378 struct cache_file_include *cfinclude;
2379 struct ast_category *last_cat = NULL;
2380 struct ast_variable *last_var = NULL;
2381 struct ast_config_include *last_inc = NULL;
2382 /*! Growable string buffer */
2383 struct ast_str *comment_buffer = NULL; /*!< this will be a comment collector.*/
2384 struct ast_str *lline_buffer = NULL; /*!< A buffer for stuff behind the ; */
2385 int glob_ret;
2386 glob_t globbuf;
2387
2388 if (cfg) {
2390 }
2391
2392 if (filename[0] == '/') {
2393 ast_copy_string(fn, filename, sizeof(fn));
2394 } else {
2395 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
2396 }
2397
2400 if (comment_buffer) {
2402 }
2403 if (!lline_buffer) {
2405 ast_log(LOG_ERROR, "Failed to initialize the comment buffer!\n");
2406 return NULL;
2407 }
2408 }
2409
2410 globbuf.gl_offs = 0; /* initialize it to silence gcc */
2411 glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
2412 if (glob_ret == GLOB_NOSPACE) {
2414 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
2415 } else if (glob_ret == GLOB_ABORTED) {
2417 "Glob Expansion of pattern '%s' failed: Read error\n", fn);
2418 } else {
2419 /* loop over expanded files */
2420 int i;
2421
2422 if (!cfg && (globbuf.gl_pathc != 1 || strcmp(fn, globbuf.gl_pathv[0]))) {
2423 /*
2424 * We just want a file changed answer and since we cannot
2425 * tell if a file was deleted with wildcard matching we will
2426 * assume that something has always changed. Also without
2427 * a lot of refactoring we couldn't check more than one file
2428 * for changes in the glob loop anyway.
2429 */
2430 globfree(&globbuf);
2433 return NULL;
2434 }
2435 for (i = 0; i < globbuf.gl_pathc; i++) {
2436 ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
2437
2438 /*
2439 * The following is not a loop, but just a convenient way to define a block
2440 * (using do { } while(0) ), and be able to exit from it with 'continue'
2441 * or 'break' in case of errors. Nice trick.
2442 */
2443 do {
2444 if (stat(fn, &statbuf)) {
2445 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
2446 config_cache_remove(fn, who_asked);
2447 }
2448 continue;
2449 }
2450
2451 if (!S_ISREG(statbuf.st_mode)) {
2452 ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
2453 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
2454 config_cache_remove(fn, who_asked);
2455 }
2456 continue;
2457 }
2458
2459 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
2460 /* Find our cached entry for this configuration file */
2462 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
2463 if (!strcmp(cfmtime->filename, fn) && !strcmp(cfmtime->who_asked, who_asked)) {
2464 break;
2465 }
2466 }
2467 if (!cfmtime) {
2468 cfmtime = cfmtime_new(fn, who_asked);
2469 if (!cfmtime) {
2471 continue;
2472 }
2473 /* Note that the file mtime is initialized to 0, i.e. 1970 */
2474 AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
2475 }
2476 }
2477
2478 if (cfmtime
2479 && !cfmtime->has_exec
2480 && !cfmstat_cmp(cfmtime, &statbuf)
2482 int unchanged = 1;
2483
2484 /* File is unchanged, what about the (cached) includes (if any)? */
2485 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
2486 if (!config_text_file_load(NULL, NULL, cfinclude->include,
2487 NULL, flags, "", who_asked)) {
2488 /* One change is enough to short-circuit and reload the whole shebang */
2489 unchanged = 0;
2490 break;
2491 }
2492 }
2493
2494 if (unchanged) {
2496 globfree(&globbuf);
2500 }
2501 }
2502
2503 /* If cfg is NULL, then we just want a file changed answer. */
2504 if (cfg == NULL) {
2505 if (cfmtime) {
2507 }
2508 continue;
2509 }
2510
2511 if (cfmtime) {
2512 /* Forget about what we thought we knew about this file's includes. */
2513 cfmtime->has_exec = 0;
2515
2516 cfmstat_save(cfmtime, &statbuf);
2518 }
2519
2520 if (!(f = fopen(fn, "r"))) {
2521 ast_debug(1, "No file to parse: %s\n", fn);
2522 ast_verb(2, "Parsing '%s': Not found (%s)\n", fn, strerror(errno));
2523 continue;
2524 }
2525 count++;
2526 /* If we get to this point, then we're loading regardless */
2528 ast_debug(1, "Parsing %s\n", fn);
2529 while (!feof(f)) {
2530 lineno++;
2531 if (fgets(buf, sizeof(buf), f)) {
2532 /* Skip lines that are too long */
2533 if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 2] != '\n') {
2534 ast_log(LOG_WARNING, "Line %d too long, skipping. It begins with: %.32s...\n", lineno, buf);
2535 while (fgets(buf, sizeof(buf), f)) {
2536 if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 2] == '\n') {
2537 break;
2538 }
2539 }
2540 continue;
2541 }
2542
2543 /* If there is a UTF-8 BOM, skip over it */
2544 if (lineno == 1) {
2545#define UTF8_BOM "\xEF\xBB\xBF"
2546 size_t line_bytes = strlen(buf);
2547 size_t bom_bytes = sizeof(UTF8_BOM) - 1;
2548 if (line_bytes >= bom_bytes
2549 && !memcmp(buf, UTF8_BOM, bom_bytes)) {
2550 memmove(buf, &buf[bom_bytes], line_bytes - bom_bytes + 1);
2551 }
2552#undef UTF8_BOM
2553 }
2554
2556 && lline_buffer
2558 CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
2559 ast_str_reset(lline_buffer); /* erase the lline buffer */
2560 }
2561
2562 new_buf = buf;
2563 if (comment) {
2564 process_buf = NULL;
2565 } else {
2566 process_buf = buf;
2567 }
2568
2570 && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf, " \t\n\r"))) {
2571 /* keep blank lines as comments */
2572 CB_ADD(&comment_buffer, "\n"); /* add newline to the comment buffer */
2573 continue; /* go get a new line, then */
2574 }
2575
2576 while ((comment_p = strchr(new_buf, COMMENT_META))) {
2577 if ((comment_p > new_buf) && (*(comment_p - 1) == '\\')) {
2578 /* Escaped semicolons aren't comments. */
2579 new_buf = comment_p;
2580 /* write over the \ and bring the null terminator with us */
2581 memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
2582 } else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
2583 /* Meta-Comment start detected ";--" */
2585 *comment_p = '\0';
2586 new_buf = comment_p + 3;
2587 comment++;
2588 nest[comment-1] = lineno;
2589 } else {
2590 ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
2591 }
2592 } else if ((comment_p >= new_buf + 2) &&
2593 (*(comment_p - 1) == COMMENT_TAG) &&
2594 (*(comment_p - 2) == COMMENT_TAG)) {
2595 /* Meta-Comment end detected "--;" */
2596 comment--;
2597 new_buf = comment_p + 1;
2598 if (!comment) {
2599 /* Back to non-comment now */
2600 if (process_buf) {
2601 /* Actually have to move what's left over the top, then continue */
2602 char *oldptr;
2603
2604 oldptr = process_buf + strlen(process_buf);
2606 CB_ADD(&comment_buffer, ";");
2607 CB_ADD_LEN(&comment_buffer, oldptr+1, new_buf-oldptr-1);
2608 }
2609
2610 memmove(oldptr, new_buf, strlen(new_buf) + 1);
2611 new_buf = oldptr;
2612 } else {
2613 process_buf = new_buf;
2614 }
2615 }
2616 } else {
2617 if (!comment) {
2618 /* If ; is found, and we are not nested in a comment,
2619 we immediately stop all comment processing */
2620 while ((comment_p > new_buf) && isspace(*(comment_p - 1))) {
2621 /* To preserve comment formatting we want to include any
2622 whitespace before the ";" */
2623 comment_p--;
2624 }
2625 if ((comment_p != new_buf) && (*comment_p == ' ') && (*(comment_p + 1) == ' ')) {
2626 /* If the comment (w/whitespace) does not start in column 1
2627 then, when written out, the preceeding variable/value will
2628 be separated from the comment by two spaces. To preserve
2629 comment formatting we should also take this into account. */
2630 comment_p += 2;
2631 }
2633 CB_ADD(&lline_buffer, comment_p);
2634 }
2635 *comment_p = '\0';
2636 new_buf = comment_p;
2637 } else {
2638 new_buf = comment_p + 1;
2639 }
2640 }
2641 }
2642 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment && !process_buf ) {
2643 CB_ADD(&comment_buffer, buf); /* the whole line is a comment, store it */
2644 }
2645
2646 if (process_buf) {
2647 char *buffer = ast_strip(process_buf);
2648
2649 if (!ast_strlen_zero(buffer)) {
2650 if (process_text_line(cfg, &cat, buffer, lineno, fn,
2652 suggested_include_file, &last_cat, &last_var, &last_inc,
2653 who_asked)) {
2655 break;
2656 }
2657 }
2658 }
2659 }
2660 }
2661 /* end of file-- anything in a comment buffer? */
2662 if (last_cat) {
2665 CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
2666 ast_str_reset(lline_buffer); /* erase the lline buffer */
2667 }
2669 }
2670 } else if (last_var) {
2673 CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
2674 ast_str_reset(lline_buffer); /* erase the lline buffer */
2675 }
2677 }
2678 } else if (last_inc) {
2681 CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer)); /* add the current lline buffer to the comment buffer */
2682 ast_str_reset(lline_buffer); /* erase the lline buffer */
2683 }
2685 }
2686 } else {
2688 ast_debug(1, "Nothing to attach comments to, discarded: %s\n", ast_str_buffer(comment_buffer));
2689 }
2690 }
2693 }
2694
2695 fclose(f);
2696 } while (0);
2697 if (comment) {
2698 ast_log(LOG_WARNING, "Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
2699 }
2700 if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
2701 break;
2702 }
2703 }
2704 globfree(&globbuf);
2705 }
2706
2709
2710 if (count == 0) {
2711 return NULL;
2712 }
2713
2714 return cfg;
2715}
2716
2717
2718/* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
2719 which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
2720 recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
2721 be shocked and mystified as to why things are not showing up in the files!
2722
2723 Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
2724 and line number are stored for each include, plus the name of the file included, so that these statements may be
2725 included in the output files on a file_save operation.
2726
2727 The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
2728 are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
2729 the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
2730 and a header gets added.
2731
2732 vars and category heads are output in the order they are stored in the config file. So, if the software
2733 shuffles these at all, then the placement of #include directives might get a little mixed up, because the
2734 file/lineno data probably won't get changed.
2735
2736*/
2737
2738static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
2739{
2740 char date[256]="";
2741 time_t t;
2742
2743 time(&t);
2744 ast_copy_string(date, ctime(&t), sizeof(date));
2745
2746 fprintf(f1, ";!\n");
2747 fprintf(f1, ";! Automatically generated configuration file\n");
2748 if (strcmp(configfile, fn))
2749 fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
2750 else
2751 fprintf(f1, ";! Filename: %s\n", configfile);
2752 fprintf(f1, ";! Generator: %s\n", generator);
2753 fprintf(f1, ";! Creation Date: %s", date);
2754 fprintf(f1, ";!\n");
2755}
2756
2757static void inclfile_destroy(void *obj)
2758{
2759 const struct inclfile *o = obj;
2760
2761 ast_free(o->fname);
2762}
2763
2764static void make_fn(char *fn, size_t fn_size, const char *file, const char *configfile)
2765{
2766 if (ast_strlen_zero(file)) {
2767 if (configfile[0] == '/') {
2768 ast_copy_string(fn, configfile, fn_size);
2769 } else {
2770 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
2771 }
2772 } else if (file[0] == '/') {
2773 ast_copy_string(fn, file, fn_size);
2774 } else {
2775 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
2776 }
2777}
2778
2779static struct inclfile *set_fn(char *fn, size_t fn_size, const char *file, const char *configfile, struct ao2_container *fileset)
2780{
2781 struct inclfile lookup;
2782 struct inclfile *fi;
2783
2784 make_fn(fn, fn_size, file, configfile);
2785 lookup.fname = fn;
2786 fi = ao2_find(fileset, &lookup, OBJ_POINTER);
2787 if (fi) {
2788 /* Found existing include file scratch pad. */
2789 return fi;
2790 }
2791
2792 /* set up a file scratch pad */
2793 fi = ao2_alloc(sizeof(struct inclfile), inclfile_destroy);
2794 if (!fi) {
2795 /* Scratch pad creation failed. */
2796 return NULL;
2797 }
2798 fi->fname = ast_strdup(fn);
2799 if (!fi->fname) {
2800 /* Scratch pad creation failed. */
2801 ao2_ref(fi, -1);
2802 return NULL;
2803 }
2804 fi->lineno = 1;
2805
2806 ao2_link(fileset, fi);
2807
2808 return fi;
2809}
2810
2811static int count_linefeeds(char *str)
2812{
2813 int count = 0;
2814
2815 while (*str) {
2816 if (*str =='\n')
2817 count++;
2818 str++;
2819 }
2820 return count;
2821}
2822
2824{
2825 int count = 0;
2826
2827 while (x) {
2828 count += count_linefeeds(x->cmt);
2829 x = x->next;
2830 }
2831 return count;
2832}
2833
2834static void insert_leading_blank_lines(FILE *fp, struct inclfile *fi, struct ast_comment *precomments, int lineno)
2835{
2836 int precomment_lines;
2837 int i;
2838
2839 if (!fi) {
2840 /* No file scratch pad object so insert no blank lines. */
2841 return;
2842 }
2843
2844 precomment_lines = count_linefeeds_in_comments(precomments);
2845
2846 /* I don't have to worry about those ;! comments, they are
2847 stored in the precomments, but not printed back out.
2848 I did have to make sure that comments following
2849 the ;! header comments were not also deleted in the process */
2850 if (lineno - precomment_lines - fi->lineno < 0) { /* insertions can mess up the line numbering and produce negative numbers that mess things up */
2851 return;
2852 } else if (lineno == 0) {
2853 /* Line replacements also mess things up */
2854 return;
2855 } else if (lineno - precomment_lines - fi->lineno < 5) {
2856 /* Only insert less than 5 blank lines; if anything more occurs,
2857 * it's probably due to context deletion. */
2858 for (i = fi->lineno; i < lineno - precomment_lines; i++) {
2859 fprintf(fp, "\n");
2860 }
2861 } else {
2862 /* Deletion occurred - insert a single blank line, for separation of
2863 * contexts. */
2864 fprintf(fp, "\n");
2865 }
2866
2867 fi->lineno = lineno + 1; /* Advance the file lineno */
2868}
2869
2870int ast_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
2871{
2873}
2874
2875static int is_writable(const char *fn)
2876{
2877 if (access(fn, F_OK)) {
2878 char *dn = dirname(ast_strdupa(fn));
2879
2880 if (access(dn, R_OK | W_OK)) {
2881 ast_log(LOG_ERROR, "Unable to write to directory %s (%s)\n", dn, strerror(errno));
2882 return 0;
2883 }
2884 } else {
2885 if (access(fn, R_OK | W_OK)) {
2886 ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno));
2887 return 0;
2888 }
2889 }
2890
2891 return 1;
2892}
2893
2894static void print_comment(FILE *f, struct ast_comment *comment)
2895{
2896 struct ast_comment *cmt;
2897
2898 for (cmt = comment; cmt; cmt = cmt->next) {
2899 const char *line = cmt->cmt;
2900 char *nl;
2901
2902 while ((nl = strchr(line, '\n')) != NULL) {
2903 *nl = '\0';
2904 if (line[0] != ';' || line[1] != '!') {
2905 /* if not one of our generated header comments */
2906 fprintf(f, "%s\n", line);
2907 }
2908
2909 line = nl + 1;
2910 }
2911 }
2912}
2913
2914static void print_include(FILE *f, struct ast_config_include *incl)
2915{
2916 switch (incl->include_type) {
2918 fprintf(f, "#include \"%s\"\n", incl->included_file);
2919 break;
2921 fprintf(f, "#tryinclude \"%s\"\n", incl->included_file);
2922 break;
2924 fprintf(f, "#exec \"%s\"\n", incl->exec_file);
2925 break;
2926 }
2927}
2928
2929int ast_config_text_file_save2(const char *configfile, const struct ast_config *cfg, const char *generator, uint32_t flags)
2930{
2931 FILE *f;
2932 char fn[PATH_MAX];
2933 struct ast_variable *var;
2934 struct ast_category *cat;
2935 struct ast_comment *cmt;
2936 struct ast_config_include *incl;
2937 int blanklines = 0;
2938 struct ao2_container *fileset;
2939 struct inclfile *fi;
2940
2941 /* Check all the files for write access before attempting to modify any of them */
2942 for (incl = cfg->includes_root; incl; incl = incl->next) {
2943 /* reset all the output flags in case this isn't our first time saving this data */
2944 incl->output = 0;
2945
2946 if (incl->include_type != CONFIG_STATEMENT_EXEC) {
2947 struct config_included_file *included_file;
2948 int ok = 1;
2949
2950 /* Not a #exec. */
2951 /* For #include, make sure we have write access to the include file
2952 file or its parent directory. If the file itself doesn't exist,
2953 make sure we have write access to the directory. */
2954 /* For #tryinclude, we check the file(s) that match the pattern. */
2955
2956 AST_LIST_TRAVERSE(&incl->included_files, included_file, next) {
2957 if (!is_writable(included_file->path)) {
2958 /* the #tryinclude path exists but is not writable */
2959 ok = 0;
2960 break;
2961 }
2962 }
2963
2964 if (!ok) {
2965 /* at least one include file is not writable */
2966 return -1;
2967 }
2968 }
2969 }
2970
2971 /* now make sure we have write access to the main config file or its parent directory */
2972 make_fn(fn, sizeof(fn), 0, configfile);
2973 if (!is_writable(fn)) {
2974 return -1;
2975 }
2976
2979 if (!fileset) {
2980 /* Container creation failed. */
2981 return -1;
2982 }
2983
2984 /* Now that we know we have write access to all files, it's safe to start truncating them */
2985
2986 /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
2987 are all truncated to zero bytes and have that nice header*/
2988 /* Note: for #exec, we write out the directives but don't zero out the exec files */
2989 for (incl = cfg->includes_root; incl; incl = incl->next) {
2990 if (incl->include_type != CONFIG_STATEMENT_EXEC) {
2991 struct config_included_file *included_file;
2992
2993 AST_LIST_TRAVERSE(&incl->included_files, included_file, next) {
2994 fi = set_fn(fn, sizeof(fn), included_file->path, configfile, fileset);
2995 f = fopen(fn, "w");
2996 if (f) {
2997 ast_verb(2, "Saving tryinclude '%s'\n", fn);
2998 gen_header(f, configfile, fn, generator);
2999 fclose(f);
3000 } else {
3001 ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno));
3002 }
3003 if (fi) {
3004 ao2_ref(fi, -1);
3005 }
3006 }
3007 }
3008 }
3009
3010 /* just set fn to absolute ver of configfile */
3011 fi = set_fn(fn, sizeof(fn), 0, configfile, fileset);
3012 if (
3013#ifdef __CYGWIN__
3014 (f = fopen(fn, "w+"))
3015#else
3016 (f = fopen(fn, "w"))
3017#endif
3018 ) {
3019 ast_verb(2, "Saving '%s'\n", fn);
3020 gen_header(f, configfile, fn, generator);
3021 cat = cfg->root;
3022 fclose(f);
3023 if (fi) {
3024 ao2_ref(fi, -1);
3025 }
3026
3027 /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
3028 /* since each var, cat, and associated comments can come from any file, we have to be
3029 mobile, and open each file, print, and close it on an entry-by-entry basis */
3030
3031 while (cat) {
3032 fi = set_fn(fn, sizeof(fn), cat->file, configfile, fileset);
3033 f = fopen(fn, "a");
3034 if (!f) {
3035 ast_log(LOG_ERROR, "Unable to write %s (%s)\n", fn, strerror(errno));
3036 if (fi) {
3037 ao2_ref(fi, -1);
3038 }
3039 ao2_ref(fileset, -1);
3040 return -1;
3041 }
3042
3043 /* dump any includes that happen before this category header */
3044 for (incl = cfg->includes_root; incl; incl = incl->next) {
3045 if (strcmp(incl->include_location_file, cat->file) == 0) {
3046 if (cat->lineno > incl->include_location_lineno && !incl->output) {
3047 /* add the precomments */
3049 print_comment(f, incl->precomments);
3050 /* and the include */
3051 print_include(f, incl);
3052 incl->output = 1;
3053 }
3054 }
3055 }
3056
3057 /* dump any comments that happen before this category header */
3059 print_comment(f, cat->precomments);
3060
3061 /* dump the category header */
3062 fprintf(f, "[%s]", cat->name);
3063 if (cat->ignored || !AST_LIST_EMPTY(&cat->template_instances)) {
3064 fprintf(f, "(");
3065 if (cat->ignored) {
3066 fprintf(f, "!");
3067 }
3068 if (cat->ignored && !AST_LIST_EMPTY(&cat->template_instances)) {
3069 fprintf(f, ",");
3070 }
3071 if (!AST_LIST_EMPTY(&cat->template_instances)) {
3074 fprintf(f, "%s",x->name);
3075 if (x != AST_LIST_LAST(&cat->template_instances))
3076 fprintf(f, ",");
3077 }
3078 }
3079 fprintf(f, ")");
3080 }
3081 for(cmt = cat->sameline; cmt; cmt = cmt->next)
3082 {
3083 fprintf(f, "%s", cmt->cmt);
3084 }
3085 if (!cat->sameline)
3086 fprintf(f, "\n");
3087
3088 /* dump any trailing comments */
3089 print_comment(f, cat->trailing);
3090
3091 /* and we're all done */
3092 fclose(f);
3093 if (fi) {
3094 ao2_ref(fi, -1);
3095 }
3096
3097 var = cat->root;
3098 while (var) {
3100 struct ast_variable *parent = NULL; /* last occurrence matching variable name */
3101
3102 /*
3103 * When saving the configuration we have the option to preserve
3104 * the effective category contents. If enabled, the template
3105 * variables are materialized into the leaf categories. Here,
3106 * we check to see if a variable is also present in the leaf
3107 * and, if so, we do not keep just the leaf value (no point in
3108 * duplicate "var = value" lines in the .conf.
3109 */
3111 if (var->inherited) {
3112 struct ast_variable *v;
3113 int skip = 0;
3114
3115 for (v = var->next; v; v = v->next) {
3116 if (!strcasecmp(var->name, v->name)) {
3117 /* skip earlier inherited duplicate */
3118 skip = 1;
3119 break;
3120 }
3121 }
3122 if (skip) {
3123 var = var->next;
3124 continue;
3125 }
3126 }
3127 }
3128
3129 /*
3130 * Walk every template instance in the order Asterisk applies
3131 * them, letting later templates override earlier ones.
3132 */
3134 struct ast_variable *v;
3135 struct ast_variable *last = NULL;
3136
3137 /* Within a template, capture the last occurrence of the key. */
3138 for (v = x->inst->root; v; v = v->next) {
3139 if (!strcasecmp(var->name, v->name)) {
3140 last = v;
3141 }
3142 }
3143
3144 if (last) {
3145 parent = last;
3146 }
3147 }
3148
3149 /* decide whether to write the variable */
3151 /* materialize inherited vars; suppress only explicit exact dups */
3152 if (!var->inherited && parent && !strcmp(var->value, parent->value)) {
3153 var = var->next;
3154 continue;
3155 }
3156 } else {
3157 /* skip inherited, explicit exact dups */
3158 if (var->inherited || (parent && !strcmp(var->value, parent->value))) {
3159 var = var->next;
3160 continue;
3161 }
3162 }
3163
3164 fi = set_fn(fn, sizeof(fn), var->file, configfile, fileset);
3165 f = fopen(fn, "a");
3166 if (!f) {
3167 ast_debug(1, "Unable to open for writing: %s\n", fn);
3168 ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
3169 if (fi) {
3170 ao2_ref(fi, -1);
3171 }
3172 ao2_ref(fileset, -1);
3173 return -1;
3174 }
3175
3176 /* dump any includes that happen before this variable */
3177 for (incl = cfg->includes_root; incl; incl = incl->next) {
3178 if (strcmp(incl->include_location_file, var->file) == 0) {
3179 if (var->lineno > incl->include_location_lineno && !incl->output) {
3180 /* add the precomments */
3182 print_comment(f, incl->precomments);
3183 /* and the include */
3184 print_include(f, incl);
3185 incl->output = 1;
3186 }
3187 }
3188 }
3189
3190 /* dump any comments that happen before this variable */
3191 insert_leading_blank_lines(f, fi, var->precomments, var->lineno);
3192 print_comment(f, var->precomments);
3193
3194 { /* Block for 'escaped' scope */
3195 int escaped_len = 2 * strlen(var->value) + 1;
3196 char escaped[escaped_len];
3197
3198 ast_escape_semicolons(var->value, escaped, escaped_len);
3199
3200 if (var->sameline) {
3201 fprintf(f, "%s %s %s %s", var->name, (var->object ? "=>" : "="),
3202 escaped, var->sameline->cmt);
3203 } else {
3204 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="),
3205 escaped);
3206 }
3207 }
3208
3209 /* dump any trailing comments */
3210 print_comment(f, var->trailing);
3211 if (var->blanklines) {
3212 blanklines = var->blanklines;
3213 while (blanklines--)
3214 fprintf(f, "\n");
3215 }
3216
3217 fclose(f);
3218 if (fi) {
3219 ao2_ref(fi, -1);
3220 }
3221
3222 var = var->next;
3223 }
3224 cat = cat->next;
3225 }
3226
3227
3228 /* Now, for files with trailing #include/#exec statements,
3229 we have to make sure every entry is output */
3230 for (incl = cfg->includes_root; incl; incl = incl->next) {
3231 if (!incl->output) {
3232 /* open the respective file */
3233 fi = set_fn(fn, sizeof(fn), incl->include_location_file, configfile, fileset);
3234 f = fopen(fn, "a");
3235 if (!f) {
3236 ast_debug(1, "Unable to open for writing: %s\n", fn);
3237 ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
3238 if (fi) {
3239 ao2_ref(fi, -1);
3240 }
3241 ao2_ref(fileset, -1);
3242 return -1;
3243 }
3244
3245 /* add the precomments */
3247 print_comment(f, incl->precomments);
3248 /* and the include */
3249 print_include(f, incl);
3250 /* and any trailing comments */
3251 print_comment(f, incl->trailing);
3252
3253 incl->output = 1;
3254 fclose(f);
3255 if (fi) {
3256 ao2_ref(fi, -1);
3257 }
3258 }
3259 }
3260
3261
3262 ast_verb(2, "Saving '%s': saved\n", fn);
3263 } else {
3264 ast_debug(1, "Unable to open for writing: %s\n", fn);
3265 ast_verb(2, "Unable to write '%s' (%s)\n", fn, strerror(errno));
3266 if (fi) {
3267 ao2_ref(fi, -1);
3268 }
3269 ao2_ref(fileset, -1);
3270 return -1;
3271 }
3272
3273 ao2_ref(fileset, -1); /* this should destroy the hash container */
3274
3275 /* pass new configuration to any config hooks */
3276 config_hook_exec(configfile, generator, cfg);
3277
3278 return 0;
3279}
3280
3281static void clear_config_maps(void)
3282{
3283 struct ast_config_map *map;
3284
3285 while (config_maps) {
3286 map = config_maps;
3288 ast_free(map);
3289 }
3290}
3291
3292#ifdef TEST_FRAMEWORK
3293int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
3294#else
3295static int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
3296#endif
3297{
3298 struct ast_config_map *map;
3299 char *dst;
3300 int length;
3301
3302 length = sizeof(*map);
3303 length += strlen(name) + 1;
3304 length += strlen(driver) + 1;
3305 length += strlen(database) + 1;
3306 if (table)
3307 length += strlen(table) + 1;
3308
3309 if (!(map = ast_calloc(1, length)))
3310 return -1;
3311
3312 dst = map->stuff; /* writable space starts here */
3313 map->name = strcpy(dst, name);
3314 dst += strlen(dst) + 1;
3315 map->driver = strcpy(dst, driver);
3316 dst += strlen(dst) + 1;
3317 map->database = strcpy(dst, database);
3318 if (table) {
3319 dst += strlen(dst) + 1;
3320 map->table = strcpy(dst, table);
3321 }
3322 map->priority = priority;
3323 map->next = config_maps;
3324 config_maps = map;
3325
3326 ast_verb(5, "Binding %s to %s/%s/%s\n", map->name, map->driver, map->database, map->table ? map->table : map->name);
3327
3328 return 0;
3329}
3330
3331static int reload_module(void)
3332{
3333 struct ast_config *config, *configtmp;
3334 struct ast_variable *v;
3335 char *driver, *table, *database, *textpri, *stringp, *tmp;
3336 struct ast_flags flags = { CONFIG_FLAG_NOREALTIME };
3337 int pri;
3339
3341
3342 configtmp = ast_config_new();
3343 if (!configtmp) {
3344 ast_log(LOG_ERROR, "Unable to allocate memory for new config\n");
3345 return -1;
3346 }
3347 config = ast_config_internal_load(extconfig_conf, configtmp, flags, "", "extconfig");
3349 return -1;
3350 } else if (!config) {
3351 ast_config_destroy(configtmp);
3352 return 0;
3353 }
3354
3355 for (v = ast_variable_browse(config, "settings"); v; v = v->next) {
3356 char buf[512];
3357 ast_copy_string(buf, v->value, sizeof(buf));
3358 stringp = buf;
3359 driver = strsep(&stringp, ",");
3360 if (!stringp) {
3361 ast_log(LOG_WARNING, "extconfig.conf: value '%s' ignored due to wrong format\n", v->value);
3362 continue;
3363 }
3364 if ((tmp = strchr(stringp, '\"')))
3365 stringp = tmp;
3366
3367 /* check if the database text starts with a double quote */
3368 if (*stringp == '"') {
3369 stringp++;
3370 database = strsep(&stringp, "\"");
3371 strsep(&stringp, ",");
3372 } else {
3373 /* apparently this text has no quotes */
3374 database = strsep(&stringp, ",");
3375 }
3376
3377 table = strsep(&stringp, ",");
3378 textpri = strsep(&stringp, ",");
3379 if (!textpri || !(pri = atoi(textpri))) {
3380 pri = 1;
3381 }
3382
3383 if (!strcmp(v->name, extconfig_conf)) {
3384 ast_log(LOG_WARNING, "Cannot bind '%s'!\n", extconfig_conf);
3385 continue;
3386 }
3387
3388 if (!strcmp(v->name, "asterisk.conf")) {
3389 ast_log(LOG_WARNING, "Cannot bind 'asterisk.conf'!\n");
3390 continue;
3391 }
3392
3393 if (!strcmp(v->name, "logger.conf")) {
3394 ast_log(LOG_WARNING, "Cannot bind 'logger.conf'!\n");
3395 continue;
3396 }
3397
3398 if (!driver || !database)
3399 continue;
3400 if (!strcasecmp(v->name, "iaxfriends")) {
3401 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");
3402 ast_realtime_append_mapping("iaxusers", driver, database, table ? table : "iaxfriends", pri);
3403 ast_realtime_append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends", pri);
3404 } else
3405 ast_realtime_append_mapping(v->name, driver, database, table, pri);
3406 }
3407
3409 return 0;
3410}
3411
3413{
3414 struct ast_config_engine *ptr;
3415
3417
3418 if (!config_engine_list) {
3419 config_engine_list = new;
3420 } else {
3421 for (ptr = config_engine_list; ptr->next; ptr=ptr->next);
3422 ptr->next = new;
3423 }
3424
3425 return 1;
3426}
3427
3429{
3430 struct ast_config_engine *ptr, *last=NULL;
3431
3433
3434 for (ptr = config_engine_list; ptr; ptr=ptr->next) {
3435 if (ptr == del) {
3436 if (last)
3437 last->next = ptr->next;
3438 else
3439 config_engine_list = ptr->next;
3440 break;
3441 }
3442 last = ptr;
3443 }
3444
3445 return 0;
3446}
3447
3448int ast_realtime_is_mapping_defined(const char *family)
3449{
3450 struct ast_config_map *map;
3452
3453 for (map = config_maps; map; map = map->next) {
3454 if (!strcasecmp(family, map->name)) {
3455 return 1;
3456 }
3457 }
3458 ast_debug(5, "Failed to find a realtime mapping for %s\n", family);
3459
3460 return 0;
3461}
3462
3463/*! \brief Find realtime engine for realtime family */
3464static struct ast_config_engine *find_engine(const char *family, int priority, char *database, int dbsiz, char *table, int tabsiz)
3465{
3466 struct ast_config_engine *eng, *ret = NULL;
3467 struct ast_config_map *map;
3468
3470
3471 for (map = config_maps; map; map = map->next) {
3472 if (!strcasecmp(family, map->name) && (priority == map->priority)) {
3473 if (database)
3474 ast_copy_string(database, map->database, dbsiz);
3475 if (table)
3476 ast_copy_string(table, map->table ? map->table : family, tabsiz);
3477 break;
3478 }
3479 }
3480
3481 /* Check if the required driver (engine) exist */
3482 if (map) {
3483 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
3484 if (!strcasecmp(eng->name, map->driver))
3485 ret = eng;
3486 }
3487 }
3488
3489 /* if we found a mapping, but the engine is not available, then issue a warning */
3490 if (map && !ret)
3491 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
3492
3493 return ret;
3494}
3495
3497 .name = "text",
3498 .load_func = config_text_file_load,
3499};
3500
3501struct ast_config *ast_config_copy(const struct ast_config *old)
3502{
3503 struct ast_config *new_config = ast_config_new();
3504 struct ast_category *cat_iter;
3505
3506 if (!new_config) {
3507 return NULL;
3508 }
3509
3510 for (cat_iter = old->root; cat_iter; cat_iter = cat_iter->next) {
3511 struct ast_category *new_cat =
3512 ast_category_new(cat_iter->name, cat_iter->file, cat_iter->lineno);
3513 if (!new_cat) {
3514 goto fail;
3515 }
3516 ast_category_append(new_config, new_cat);
3517 if (cat_iter->root) {
3518 new_cat->root = ast_variables_dup(cat_iter->root);
3519 if (!new_cat->root) {
3520 goto fail;
3521 }
3522 new_cat->last = cat_iter->last;
3523 }
3524 }
3525
3526 return new_config;
3527
3528fail:
3529 ast_config_destroy(new_config);
3530 return NULL;
3531}
3532
3533
3534struct 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)
3535{
3536 char db[256];
3537 char table[256];
3538 struct ast_config_engine *loader = &text_file_engine;
3539 struct ast_config *result;
3540
3541 /* The config file itself bumps include_level by 1 */
3542 if (cfg->max_include_level > 0 && cfg->include_level == cfg->max_include_level + 1) {
3543 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
3544 return NULL;
3545 }
3546
3547 cfg->include_level++;
3548
3550 struct ast_config_engine *eng;
3551
3552 eng = find_engine(filename, 1, db, sizeof(db), table, sizeof(table));
3553
3554
3555 if (eng && eng->load_func) {
3556 loader = eng;
3557 } else {
3558 eng = find_engine("global", 1, db, sizeof(db), table, sizeof(table));
3559 if (eng && eng->load_func)
3560 loader = eng;
3561 }
3562 }
3563
3564 result = loader->load_func(db, table, filename, cfg, flags, suggested_include_file, who_asked);
3565
3567 result->include_level--;
3568 config_hook_exec(filename, who_asked, result);
3569 } else if (result != CONFIG_STATUS_FILEINVALID) {
3570 cfg->include_level--;
3571 }
3572
3573 return result;
3574}
3575
3576struct ast_config *ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
3577{
3578 struct ast_config *cfg;
3579 struct ast_config *result;
3580
3581 cfg = ast_config_new();
3582 if (!cfg)
3583 return NULL;
3584
3585 result = ast_config_internal_load(filename, cfg, flags, "", who_asked);
3587 ast_config_destroy(cfg);
3588
3589 return result;
3590}
3591
3592#define realtime_arguments_to_fields(ap, result) realtime_arguments_to_fields2(ap, 0, result)
3593
3594/*!
3595 * \internal
3596 * \brief
3597 *
3598 * \param ap list of variable arguments
3599 * \param skip Skip argument pairs for this number of variables
3600 * \param result Address of a variables pointer to store the results
3601 * May be NULL if no arguments are parsed
3602 * Will be NULL on failure.
3603 *
3604 * \retval 0 on success or empty ap list
3605 * \retval -1 on failure
3606 */
3607static int realtime_arguments_to_fields2(va_list ap, int skip, struct ast_variable **result)
3608{
3609 struct ast_variable *first, *fields = NULL;
3610 const char *newparam;
3611 const char *newval;
3612
3613 /*
3614 * Previously we would do:
3615 *
3616 * va_start(ap, last);
3617 * x = realtime_arguments_to_fields(ap);
3618 * y = realtime_arguments_to_fields(ap);
3619 * va_end(ap);
3620 *
3621 * While this works on generic amd64 machines (2014), it doesn't on the
3622 * raspberry PI. The va_arg() manpage says:
3623 *
3624 * If ap is passed to a function that uses va_arg(ap, type) then
3625 * the value of ap is undefined after the return of that function.
3626 *
3627 * On the raspberry, ap seems to get reset after the call: the contents
3628 * of y would be equal to the contents of x.
3629 *
3630 * So, instead we allow the caller to skip past earlier argument sets
3631 * using the skip parameter:
3632 *
3633 * va_start(ap, last);
3634 * if (realtime_arguments_to_fields(ap, &x)) {
3635 * // FAILURE CONDITIONS
3636 * }
3637 * va_end(ap);
3638 * va_start(ap, last);
3639 * if (realtime_arguments_to_fields2(ap, 1, &y)) {
3640 * // FAILURE CONDITIONS
3641 * }
3642 * va_end(ap);
3643 */
3644 while (skip--) {
3645 /* There must be at least one argument. */
3646 newparam = va_arg(ap, const char *);
3647 newval = va_arg(ap, const char *);
3648 while ((newparam = va_arg(ap, const char *))) {
3649 newval = va_arg(ap, const char *);
3650 }
3651 }
3652
3653 /* Load up the first vars. */
3654 newparam = va_arg(ap, const char *);
3655 if (!newparam) {
3656 *result = NULL;
3657 return 0;
3658 }
3659 newval = va_arg(ap, const char *);
3660
3661 if (!(first = ast_variable_new(newparam, newval, ""))) {
3662 *result = NULL;
3663 return -1;
3664 }
3665
3666 while ((newparam = va_arg(ap, const char *))) {
3667 struct ast_variable *field;
3668
3669 newval = va_arg(ap, const char *);
3670 if (!(field = ast_variable_new(newparam, newval, ""))) {
3671 ast_variables_destroy(fields);
3673 *result = NULL;
3674 return -1;
3675 }
3676
3677 field->next = fields;
3678 fields = field;
3679 }
3680
3681 first->next = fields;
3682 fields = first;
3683
3684 *result = fields;
3685 return 0;
3686}
3687
3688struct ast_variable *ast_load_realtime_all_fields(const char *family, const struct ast_variable *fields)
3689{
3690 struct ast_config_engine *eng;
3691 char db[256];
3692 char table[256];
3693 struct ast_variable *res=NULL;
3694 int i;
3695
3696 for (i = 1; ; i++) {
3697 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
3698 if (eng->realtime_func) {
3699 res = eng->realtime_func(db, table, fields);
3700
3701 /* If a backend returns CONFIG_RT_NOT_FOUND, stop iteration and return NULL,
3702 * indicating that the requested record does not exist and no failover should occur.
3703 * Only continue iteration if the result is NULL and not CONFIG_RT_NOT_FOUND,
3704 * which signals a backend failure.
3705 */
3706 if (res == CONFIG_RT_NOT_FOUND) {
3707 return NULL;
3708 }
3709 if (res) {
3710 return res;
3711 }
3712 }
3713 } else {
3714 return NULL;
3715 }
3716 }
3717
3718 return res;
3719}
3720
3721struct ast_variable *ast_load_realtime_all(const char *family, ...)
3722{
3723 RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
3724 struct ast_variable *res = NULL;
3725 va_list ap;
3726
3727 va_start(ap, family);
3728 realtime_arguments_to_fields(ap, &fields);
3729 va_end(ap);
3730
3731 if (fields) {
3732 res = ast_load_realtime_all_fields(family, fields);
3733 }
3734
3735 return res;
3736}
3737
3738struct ast_variable *ast_load_realtime_fields(const char *family, const struct ast_variable *fields)
3739{
3740 struct ast_variable *res;
3741 struct ast_variable *cur;
3742 struct ast_variable **prev;
3743
3744 res = ast_load_realtime_all_fields(family, fields);
3745
3746 /* Filter the list. */
3747 prev = &res;
3748 cur = res;
3749 while (cur) {
3750 if (ast_strlen_zero(cur->value)) {
3751 /* Eliminate empty entries */
3752 struct ast_variable *next;
3753
3754 next = cur->next;
3755 *prev = next;
3757 cur = next;
3758 } else {
3759 /* Make blank entries empty and keep them. */
3760 if (cur->value[0] == ' ' && cur->value[1] == '\0') {
3761 char *vptr = (char *) cur->value;
3762
3763 vptr[0] = '\0';
3764 }
3765
3766 prev = &cur->next;
3767 cur = cur->next;
3768 }
3769 }
3770 return res;
3771}
3772
3773struct ast_variable *ast_load_realtime(const char *family, ...)
3774{
3775 RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
3776 int field_res = 0;
3777 va_list ap;
3778
3779 va_start(ap, family);
3780 if (realtime_arguments_to_fields(ap, &fields)) {
3781 field_res = -1;
3782 }
3783 va_end(ap);
3784
3785 if (field_res) {
3786 return NULL;
3787 }
3788
3789 if (!fields) {
3790 return NULL;
3791 }
3792
3793 return ast_load_realtime_fields(family, fields);
3794}
3795
3796/*! \brief Check if realtime engine is configured for family */
3797int ast_check_realtime(const char *family)
3798{
3799 struct ast_config_engine *eng;
3800 if (!ast_realtime_enabled()) {
3801 return 0; /* There are no engines at all so fail early */
3802 }
3803
3804 eng = find_engine(family, 1, NULL, 0, NULL, 0);
3805 if (eng)
3806 return 1;
3807 return 0;
3808}
3809
3810/*! \brief Check if there's any realtime engines loaded */
3812{
3813 return config_maps ? 1 : 0;
3814}
3815
3816int ast_realtime_require_field(const char *family, ...)
3817{
3818 struct ast_config_engine *eng;
3819 char db[256];
3820 char table[256];
3821 va_list ap, aq;
3822 int res = -1, i;
3823
3824 va_start(ap, family);
3825 for (i = 1; ; i++) {
3826 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
3827 va_copy(aq, ap);
3828 /* If the require succeeds, it returns 0. */
3829 if (eng->require_func && !(res = eng->require_func(db, table, aq))) {
3830 va_end(aq);
3831 break;
3832 }
3833 va_end(aq);
3834 } else {
3835 break;
3836 }
3837 }
3838 va_end(ap);
3839
3840 return res;
3841}
3842
3843int ast_unload_realtime(const char *family)
3844{
3845 struct ast_config_engine *eng;
3846 char db[256];
3847 char table[256];
3848 int res = -1, i;
3849
3850 for (i = 1; ; i++) {
3851 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
3852 if (eng->unload_func) {
3853 /* Do this for ALL engines */
3854 res = eng->unload_func(db, table);
3855 }
3856 } else {
3857 break;
3858 }
3859 }
3860 return res;
3861}
3862
3863struct ast_config *ast_load_realtime_multientry_fields(const char *family, const struct ast_variable *fields)
3864{
3865 struct ast_config_engine *eng;
3866 char db[256];
3867 char table[256];
3868 struct ast_config *res = NULL;
3869 int i;
3870
3871 for (i = 1; ; i++) {
3872 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
3873 if (eng->realtime_multi_func && (res = eng->realtime_multi_func(db, table, fields))) {
3874 /* If we were returned an empty cfg, destroy it and return NULL */
3875 if (!res->root) {
3876 ast_config_destroy(res);
3877 res = NULL;
3878 }
3879 break;
3880 }
3881 } else {
3882 break;
3883 }
3884 }
3885
3886 return res;
3887}
3888
3889struct ast_config *ast_load_realtime_multientry(const char *family, ...)
3890{
3891 RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
3892 va_list ap;
3893
3894 va_start(ap, family);
3895 realtime_arguments_to_fields(ap, &fields);
3896 va_end(ap);
3897
3898 if (!fields) {
3899 return NULL;
3900 }
3901
3902 return ast_load_realtime_multientry_fields(family, fields);
3903}
3904
3905int ast_update_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
3906{
3907 struct ast_config_engine *eng;
3908 int res = -1, i;
3909 char db[256];
3910 char table[256];
3911
3912 for (i = 1; ; i++) {
3913 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
3914 /* If the update succeeds, it returns >= 0. */
3915 if (eng->update_func && ((res = eng->update_func(db, table, keyfield, lookup, fields)) >= 0)) {
3916 break;
3917 }
3918 } else {
3919 break;
3920 }
3921 }
3922
3923 return res;
3924}
3925
3926int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
3927{
3928 RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
3929 va_list ap;
3930
3931 va_start(ap, lookup);
3932 realtime_arguments_to_fields(ap, &fields);
3933 va_end(ap);
3934
3935 if (!fields) {
3936 return -1;
3937 }
3938
3939 return ast_update_realtime_fields(family, keyfield, lookup, fields);
3940}
3941
3942int ast_update2_realtime_fields(const char *family, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
3943{
3944 struct ast_config_engine *eng;
3945 int res = -1, i;
3946 char db[256];
3947 char table[256];
3948
3949 for (i = 1; ; i++) {
3950 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
3951 if (eng->update2_func && !(res = eng->update2_func(db, table, lookup_fields, update_fields))) {
3952 break;
3953 }
3954 } else {
3955 break;
3956 }
3957 }
3958
3959 return res;
3960}
3961
3962int ast_update2_realtime(const char *family, ...)
3963{
3964 RAII_VAR(struct ast_variable *, lookup_fields, NULL, ast_variables_destroy);
3965 RAII_VAR(struct ast_variable *, update_fields, NULL, ast_variables_destroy);
3966 va_list ap;
3967
3968 va_start(ap, family);
3969 /* XXX: If we wanted to pass no lookup fields (select all), we'd be
3970 * out of luck. realtime_arguments_to_fields expects at least one key
3971 * value pair. */
3972 realtime_arguments_to_fields(ap, &lookup_fields);
3973 va_end(ap);
3974
3975 va_start(ap, family);
3976 realtime_arguments_to_fields2(ap, 1, &update_fields);
3977 va_end(ap);
3978
3979 if (!lookup_fields || !update_fields) {
3980 return -1;
3981 }
3982
3983 return ast_update2_realtime_fields(family, lookup_fields, update_fields);
3984}
3985
3986int ast_store_realtime_fields(const char *family, const struct ast_variable *fields)
3987{
3988 struct ast_config_engine *eng;
3989 int res = -1, i;
3990 char db[256];
3991 char table[256];
3992
3993 for (i = 1; ; i++) {
3994 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
3995 /* If the store succeeds, it returns >= 0*/
3996 if (eng->store_func && ((res = eng->store_func(db, table, fields)) >= 0)) {
3997 break;
3998 }
3999 } else {
4000 break;
4001 }
4002 }
4003
4004 return res;
4005}
4006
4007int ast_store_realtime(const char *family, ...)
4008{
4009 RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
4010 va_list ap;
4011
4012 va_start(ap, family);
4013 realtime_arguments_to_fields(ap, &fields);
4014 va_end(ap);
4015
4016 if (!fields) {
4017 return -1;
4018 }
4019
4020 return ast_store_realtime_fields(family, fields);
4021}
4022
4023int ast_destroy_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
4024{
4025 struct ast_config_engine *eng;
4026 int res = -1, i;
4027 char db[256];
4028 char table[256];
4029
4030 for (i = 1; ; i++) {
4031 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
4032 if (eng->destroy_func && ((res = eng->destroy_func(db, table, keyfield, lookup, fields)) >= 0)) {
4033 break;
4034 }
4035 } else {
4036 break;
4037 }
4038 }
4039
4040 return res;
4041}
4042
4043int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...)
4044{
4045 RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
4046 int res = 0;
4047 va_list ap;
4048
4049 va_start(ap, lookup);
4050 if (realtime_arguments_to_fields(ap, &fields)) {
4051 res = -1;
4052 }
4053 va_end(ap);
4054
4055 if (res) {
4056 return -1;
4057 }
4058
4059 return ast_destroy_realtime_fields(family, keyfield, lookup, fields);
4060}
4061
4063{
4064 char *orig = chunk;
4065 for (; *chunk; chunk++) {
4066 if (*chunk == '^' && strchr("0123456789ABCDEFabcdef", chunk[1]) && strchr("0123456789ABCDEFabcdef", chunk[2])) {
4067 sscanf(chunk + 1, "%02hhX", (unsigned char *)chunk);
4068 memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
4069 }
4070 }
4071 return orig;
4072}
4073
4074char *ast_realtime_encode_chunk(struct ast_str **dest, ssize_t maxlen, const char *chunk)
4075{
4076 if (!strchr(chunk, ';') && !strchr(chunk, '^')) {
4077 ast_str_set(dest, maxlen, "%s", chunk);
4078 } else {
4079 ast_str_reset(*dest);
4080 for (; *chunk; chunk++) {
4081 if (strchr(";^", *chunk)) {
4082 ast_str_append(dest, maxlen, "^%02hhX", *chunk);
4083 } else {
4084 ast_str_append(dest, maxlen, "%c", *chunk);
4085 }
4086 }
4087 }
4088 return ast_str_buffer(*dest);
4089}
4090
4091/*! \brief Helper function to parse arguments
4092 * See documentation in config.h
4093 */
4094int ast_parse_arg(const char *arg, enum ast_parse_flags flags,
4095 void *p_result, ...)
4096{
4097 va_list ap;
4098 int error = 0;
4099
4100 va_start(ap, p_result);
4101 switch (flags & PARSE_TYPE) {
4102 case PARSE_INT32:
4103 {
4104 long int x = 0;
4105 int32_t *result = p_result;
4106 int32_t def = result ? *result : 0, high = INT32_MAX, low = INT32_MIN;
4107 char *endptr = NULL;
4108
4109 /* optional arguments: default value and/or (low, high) */
4110 if (flags & PARSE_DEFAULT) {
4111 def = va_arg(ap, int32_t);
4112 }
4113 if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
4114 low = va_arg(ap, int32_t);
4115 high = va_arg(ap, int32_t);
4116 }
4117 if (ast_strlen_zero(arg)) {
4118 error = 1;
4119 goto int32_done;
4120 }
4121 errno = 0;
4122 x = strtol(arg, &endptr, 0);
4123 if (*endptr || errno || x < INT32_MIN || x > INT32_MAX) {
4124 /* Parse error, or type out of int32_t bounds */
4125 error = 1;
4126 goto int32_done;
4127 }
4128 error = (x < low) || (x > high);
4129 if (flags & PARSE_RANGE_DEFAULTS) {
4130 if (x < low) {
4131 def = low;
4132 } else if (x > high) {
4133 def = high;
4134 }
4135 }
4136 if (flags & PARSE_OUT_RANGE) {
4137 error = !error;
4138 }
4139int32_done:
4140 if (result) {
4141 *result = error ? def : x;
4142 }
4143
4144 ast_debug(3, "extract int from [%s] in [%d, %d] gives [%ld](%d)\n",
4145 arg, low, high, result ? *result : x, error);
4146 break;
4147 }
4148
4149 case PARSE_UINT32:
4150 {
4151 unsigned long int x = 0;
4152 uint32_t *result = p_result;
4153 uint32_t def = result ? *result : 0, low = 0, high = UINT32_MAX;
4154 char *endptr = NULL;
4155
4156 /* optional argument: first default value, then range */
4157 if (flags & PARSE_DEFAULT) {
4158 def = va_arg(ap, uint32_t);
4159 }
4160 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
4161 /* range requested, update bounds */
4162 low = va_arg(ap, uint32_t);
4163 high = va_arg(ap, uint32_t);
4164 }
4165
4166 if (ast_strlen_zero(arg)) {
4167 error = 1;
4168 goto uint32_done;
4169 }
4170 /* strtoul will happily and silently negate negative numbers */
4171 arg = ast_skip_blanks(arg);
4172 if (*arg == '-') {
4173 error = 1;
4174 goto uint32_done;
4175 }
4176 errno = 0;
4177 x = strtoul(arg, &endptr, 0);
4178 if (*endptr || errno || x > UINT32_MAX) {
4179 error = 1;
4180 goto uint32_done;
4181 }
4182 error = (x < low) || (x > high);
4183 if (flags & PARSE_RANGE_DEFAULTS) {
4184 if (x < low) {
4185 def = low;
4186 } else if (x > high) {
4187 def = high;
4188 }
4189 }
4190 if (flags & PARSE_OUT_RANGE) {
4191 error = !error;
4192 }
4193uint32_done:
4194 if (result) {
4195 *result = error ? def : x;
4196 }
4197 ast_debug(3, "extract uint from [%s] in [%u, %u] gives [%lu](%d)\n",
4198 arg, low, high, result ? *result : x, error);
4199 break;
4200 }
4201
4202 case PARSE_TIMELEN:
4203 {
4204 int x = 0;
4205 int *result = p_result;
4206 int def = result ? *result : 0;
4207 int high = INT_MAX;
4208 int low = INT_MIN;
4209 enum ast_timelen defunit;
4210
4211 defunit = va_arg(ap, enum ast_timelen);
4212 /* optional arguments: default value and/or (low, high) */
4213 if (flags & PARSE_DEFAULT) {
4214 def = va_arg(ap, int);
4215 }
4216 if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
4217 low = va_arg(ap, int);
4218 high = va_arg(ap, int);
4219 }
4220 if (ast_strlen_zero(arg)) {
4221 error = 1;
4222 goto timelen_done;
4223 }
4224 error = ast_app_parse_timelen(arg, &x, defunit);
4225 if (error || x < INT_MIN || x > INT_MAX) {
4226 /* Parse error, or type out of int bounds */
4227 error = 1;
4228 goto timelen_done;
4229 }
4230 error = (x < low) || (x > high);
4231 if (flags & PARSE_RANGE_DEFAULTS) {
4232 if (x < low) {
4233 def = low;
4234 } else if (x > high) {
4235 def = high;
4236 }
4237 }
4238 if (flags & PARSE_OUT_RANGE) {
4239 error = !error;
4240 }
4241timelen_done:
4242 if (result) {
4243 *result = error ? def : x;
4244 }
4245
4246 ast_debug(3, "extract timelen from [%s] in [%d, %d] gives [%d](%d)\n",
4247 arg, low, high, result ? *result : x, error);
4248 break;
4249 }
4250
4251 case PARSE_DOUBLE:
4252 {
4253 double *result = p_result;
4254 double x = 0, def = result ? *result : 0, low = -HUGE_VAL, high = HUGE_VAL;
4255 char *endptr = NULL;
4256
4257 /* optional argument: first default value, then range */
4258 if (flags & PARSE_DEFAULT) {
4259 def = va_arg(ap, double);
4260 }
4261 if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
4262 /* range requested, update bounds */
4263 low = va_arg(ap, double);
4264 high = va_arg(ap, double);
4265 }
4266 if (ast_strlen_zero(arg)) {
4267 error = 1;
4268 goto double_done;
4269 }
4270 errno = 0;
4271 x = strtod(arg, &endptr);
4272 if (*endptr || errno == ERANGE) {
4273 error = 1;
4274 goto double_done;
4275 }
4276 error = (x < low) || (x > high);
4277 if (flags & PARSE_OUT_RANGE) {
4278 error = !error;
4279 }
4280double_done:
4281 if (result) {
4282 *result = error ? def : x;
4283 }
4284 ast_debug(3, "extract double from [%s] in [%f, %f] gives [%f](%d)\n",
4285 arg, low, high, result ? *result : x, error);
4286 break;
4287 }
4288 case PARSE_ADDR:
4289 {
4290 struct ast_sockaddr *addr = (struct ast_sockaddr *)p_result;
4291
4292 if (!ast_sockaddr_parse(addr, arg, flags & PARSE_PORT_MASK)) {
4293 error = 1;
4294 }
4295
4296 ast_debug(3, "extract addr from %s gives %s(%d)\n",
4297 arg, ast_sockaddr_stringify(addr), error);
4298
4299 break;
4300 }
4301 case PARSE_INADDR: /* TODO Remove this (use PARSE_ADDR instead). */
4302 {
4303 char *port, *buf;
4304 struct sockaddr_in _sa_buf; /* buffer for the result */
4305 struct sockaddr_in *sa = p_result ?
4306 (struct sockaddr_in *)p_result : &_sa_buf;
4307 /* default is either the supplied value or the result itself */
4308 struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
4309 va_arg(ap, struct sockaddr_in *) : sa;
4310 struct ast_sockaddr addr = { {0,} };
4311
4312 memset(&_sa_buf, '\0', sizeof(_sa_buf)); /* clear buffer */
4313 /* duplicate the string to strip away the :port */
4314 port = ast_strdupa(arg);
4315 buf = strsep(&port, ":");
4316 sa->sin_family = AF_INET; /* assign family */
4317 /*
4318 * honor the ports flag setting, assign default value
4319 * in case of errors or field unset.
4320 */
4321 flags &= PARSE_PORT_MASK; /* the only flags left to process */
4322 if (port) {
4323 if (flags == PARSE_PORT_FORBID) {
4324 error = 1; /* port was forbidden */
4325 sa->sin_port = def->sin_port;
4326 } else if (flags == PARSE_PORT_IGNORE)
4327 sa->sin_port = def->sin_port;
4328 else /* accept or require */
4329 sa->sin_port = htons(strtol(port, NULL, 0));
4330 } else {
4331 sa->sin_port = def->sin_port;
4332 if (flags == PARSE_PORT_REQUIRE)
4333 error = 1;
4334 }
4335 /* Now deal with host part, even if we have errors before. */
4336 if (ast_sockaddr_resolve_first_af(&addr, buf, PARSE_PORT_FORBID, AF_INET)) {
4337 error = 1;
4338 sa->sin_addr = def->sin_addr;
4339 } else {
4340 struct sockaddr_in tmp;
4341 ast_sockaddr_to_sin(&addr, &tmp);
4342 sa->sin_addr = tmp.sin_addr;
4343 }
4344 ast_debug(3,
4345 "extract inaddr from [%s] gives [%s:%d](%d)\n",
4346 arg, ast_inet_ntoa(sa->sin_addr),
4347 ntohs(sa->sin_port), error);
4348 break;
4349 }
4350 }
4351 va_end(ap);
4352 return error;
4353}
4354
4355static char *handle_cli_core_show_config_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4356{
4357 struct ast_config_engine *eng;
4358 struct ast_config_map *map;
4359
4360 switch (cmd) {
4361 case CLI_INIT:
4362 e->command = "core show config mappings";
4363 e->usage =
4364 "Usage: core show config mappings\n"
4365 " Shows the filenames to config engines.\n";
4366 return NULL;
4367 case CLI_GENERATE:
4368 return NULL;
4369 }
4370
4371 {
4373
4374 if (!config_engine_list) {
4375 ast_cli(a->fd, "No config mappings found.\n");
4376 } else {
4377 for (eng = config_engine_list; eng; eng = eng->next) {
4378 ast_cli(a->fd, "Config Engine: %s\n", eng->name);
4379 for (map = config_maps; map; map = map->next) {
4380 if (!strcasecmp(map->driver, eng->name)) {
4381 ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
4382 map->table ? map->table : map->name);
4383 }
4384 }
4385 }
4386 }
4387 }
4388
4389 return CLI_SUCCESS;
4390}
4391
4392static char *handle_cli_config_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4393{
4394 struct cache_file_mtime *cfmtime;
4395 char *prev = "";
4396 int wordlen;
4397
4398 switch (cmd) {
4399 case CLI_INIT:
4400 e->command = "config reload";
4401 e->usage =
4402 "Usage: config reload <filename.conf>\n"
4403 " Reloads all modules that reference <filename.conf>\n";
4404 return NULL;
4405 case CLI_GENERATE:
4406 if (a->pos > 2) {
4407 return NULL;
4408 }
4409
4410 wordlen = strlen(a->word);
4411
4413 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
4414 /* Core configs cannot be reloaded */
4415 if (ast_strlen_zero(cfmtime->who_asked)) {
4416 continue;
4417 }
4418
4419 /* Skip duplicates - this only works because the list is sorted by filename */
4420 if (!strcmp(cfmtime->filename, prev)) {
4421 continue;
4422 }
4423
4424 if (!strncmp(cfmtime->filename, a->word, wordlen)) {
4426 break;
4427 }
4428 }
4429
4430 /* Otherwise save that we've seen this filename */
4431 prev = cfmtime->filename;
4432 }
4434
4435 return NULL;
4436 }
4437
4438 if (a->argc != 3) {
4439 return CLI_SHOWUSAGE;
4440 }
4441
4443 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
4444 if (!strcmp(cfmtime->filename, a->argv[2])) {
4445 char *buf = ast_alloca(strlen("module reload ") + strlen(cfmtime->who_asked) + 1);
4446 sprintf(buf, "module reload %s", cfmtime->who_asked);
4447 ast_cli_command(a->fd, buf);
4448 }
4449 }
4451
4452 return CLI_SUCCESS;
4453}
4454
4455static char *handle_cli_config_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4456{
4457 struct cache_file_mtime *cfmtime;
4458
4459 switch (cmd) {
4460 case CLI_INIT:
4461 e->command = "config list";
4462 e->usage =
4463 "Usage: config list\n"
4464 " Show all modules that have loaded a configuration file\n";
4465 return NULL;
4466 case CLI_GENERATE:
4467 return NULL;
4468 }
4469
4471 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
4472 ast_cli(a->fd, "%-20.20s %-50s\n", S_OR(cfmtime->who_asked, "core"), cfmtime->filename);
4473 }
4475
4476 return CLI_SUCCESS;
4477}
4478
4479static struct ast_cli_entry cli_config[] = {
4480 AST_CLI_DEFINE(handle_cli_core_show_config_mappings, "Display config mappings (file names to config engines)"),
4481 AST_CLI_DEFINE(handle_cli_config_reload, "Force a reload on modules using a particular configuration file"),
4482 AST_CLI_DEFINE(handle_cli_config_list, "Show all files that have loaded a configuration file"),
4483};
4484
4485static void config_shutdown(void)
4486{
4487 struct cache_file_mtime *cfmtime;
4488
4490 while ((cfmtime = AST_LIST_REMOVE_HEAD(&cfmtime_head, list))) {
4492 }
4494
4496
4498
4500 cfg_hooks = NULL;
4501}
4502
4504{
4506 /* This is separate from the module load so cleanup can happen very late. */
4508 return 0;
4509}
4510
4511struct cfg_hook {
4512 const char *name;
4513 const char *filename;
4514 const char *module;
4516};
4517
4518static void hook_destroy(void *obj)
4519{
4520 struct cfg_hook *hook = obj;
4521 ast_free((void *) hook->name);
4522 ast_free((void *) hook->filename);
4523 ast_free((void *) hook->module);
4524}
4525
4526static int hook_cmp(void *obj, void *arg, int flags)
4527{
4528 struct cfg_hook *hook1 = obj;
4529 struct cfg_hook *hook2 = arg;
4530
4531 return !(strcasecmp(hook1->name, hook2->name)) ? CMP_MATCH | CMP_STOP : 0;
4532}
4533
4534static int hook_hash(const void *obj, const int flags)
4535{
4536 const struct cfg_hook *hook = obj;
4537
4538 return ast_str_hash(hook->name);
4539}
4540
4542{
4543 struct cfg_hook tmp;
4544
4545 tmp.name = ast_strdupa(name);
4546
4548}
4549
4550static void config_hook_exec(const char *filename, const char *module, const struct ast_config *cfg)
4551{
4552 struct ao2_iterator it;
4553 struct cfg_hook *hook;
4554 if (!(cfg_hooks)) {
4555 return;
4556 }
4558 while ((hook = ao2_iterator_next(&it))) {
4559 if (!strcasecmp(hook->filename, filename) &&
4560 !strcasecmp(hook->module, module)) {
4561 struct ast_config *copy = ast_config_copy(cfg);
4562 hook->hook_cb(copy);
4563 }
4564 ao2_ref(hook, -1);
4565 }
4567}
4568
4570 const char *filename,
4571 const char *module,
4572 enum config_hook_flags flags,
4574{
4575 struct cfg_hook *hook;
4576 if (!cfg_hooks) {
4579 if (!cfg_hooks) {
4580 return -1;
4581 }
4582 }
4583
4584 if (!(hook = ao2_alloc(sizeof(*hook), hook_destroy))) {
4585 return -1;
4586 }
4587
4588 hook->hook_cb = hook_cb;
4589 hook->filename = ast_strdup(filename);
4590 hook->name = ast_strdup(name);
4591 hook->module = ast_strdup(module);
4592
4593 ao2_link(cfg_hooks, hook);
4594 ao2_ref(hook, -1);
4595 return 0;
4596}
4597
4598static int unload_module(void)
4599{
4600 return 0;
4601}
4602
4603static int load_module(void)
4604{
4605 if (ast_opt_console) {
4606 ast_verb(0, "[ Initializing Custom Configuration Options ]\n");
4607 }
4608
4610}
4611
4612/* This module explicitly loads before realtime drivers. */
4614 .support_level = AST_MODULE_SUPPORT_CORE,
4615 .load = load_module,
4616 .unload = unload_module,
4618 .load_pri = 0,
#define comment
Definition: ael_lex.c:965
#define GLOB_ABORTED
Definition: ael_lex.c:828
jack_status_t status
Definition: app_jack.c:149
const char * str
Definition: app_jack.c:150
struct sla_ringing_trunk * first
Definition: app_sla.c:338
ast_mutex_t lock
Definition: app_sla.c:337
struct sla_ringing_trunk * last
Definition: app_sla.c:338
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define INT32_MAX
Definition: ast_expr2f.c:79
#define var
Definition: ast_expr2f.c:605
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1570
#define INT32_MIN
Definition: ast_expr2f.c:70
#define UINT32_MAX
Definition: ast_expr2f.c:88
char * strsep(char **str, const char *delims)
#define MY_GLOB_FLAGS
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define PATH_MAX
Definition: asterisk.h:40
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
void * __ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) attribute_malloc
Definition: astmm.c:1603
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_POINTER
Definition: astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#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.
Definition: astobj2.h:1303
static int priority
static char * table
Definition: cdr_odbc.c:55
static sqlite3 * db
static PGresult * result
Definition: cel_pgsql.c:84
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2388
static const char config[]
Definition: chan_ooh323.c:111
General Asterisk PBX channel definitions.
#define AST_MAX_USER_FIELD
Definition: channel.h:176
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2737
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
ast_cli_command
calling arguments for new-style handlers.
Definition: cli.h:151
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
char * be
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static char * lline_buffer
Definition: extconf.c:706
static char * comment_buffer
Definition: extconf.c:703
static const char name[]
Definition: format_mp3.c:68
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:980
static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:899
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
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.
Definition: main/app.c:3273
void ast_replace_sigchld(void)
Replace the SIGCHLD handler.
Definition: extconf.c:799
void ast_unreplace_sigchld(void)
Restore the SIGCHLD handler.
Definition: extconf.c:813
Configuration File Parser.
#define ast_variable_new(name, value, filename)
#define ast_variable_list_append(head, new_var)
#define CONFIG_STATUS_FILEUNCHANGED
@ CONFIG_SAVE_FLAG_PRESERVE_EFFECTIVE_CONTEXT
#define CONFIG_STATUS_FILEINVALID
ast_parse_flags
Support code to parse config file arguments.
@ PARSE_RANGE_DEFAULTS
@ PARSE_PORT_REQUIRE
@ CONFIG_FLAG_NOCACHE
@ CONFIG_FLAG_NOREALTIME
@ CONFIG_FLAG_WITHCOMMENTS
@ CONFIG_FLAG_FILEUNCHANGED
#define CONFIG_RT_NOT_FOUND
int(* config_hook_cb)(struct ast_config *cfg)
Callback when configuration is updated.
config_hook_flags
Flags that affect the behaviour of config hooks.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:291
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_INSERT_SORTALPHA(head, elm, field, sortfield)
Inserts a list entry into a alphabetically sorted list.
Definition: linkedlists.h:751
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:429
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
Asterisk locking-related definitions:
#define SCOPED_MUTEX(varname, lock)
scoped lock specialization for mutexes
Definition: lock.h:596
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:527
void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
Definition: main/config.c:470
static void config_cache_flush_includes(struct cache_file_mtime *cfmtime)
Definition: main/config.c:1853
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.
Definition: main/config.c:813
static struct ast_cli_entry cli_config[]
Definition: main/config.c:4479
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: main/config.c:1491
#define MAX_NESTED_COMMENTS
Definition: main/config.c:63
const char * ast_category_get_name(const struct ast_category *category)
Return the name of the category.
Definition: main/config.c:1212
#define UTF8_BOM
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
Definition: main/config.c:573
struct ast_category * ast_category_new_template(const char *name, const char *in_file, int lineno)
Create a category making it a template.
Definition: main/config.c:1179
struct ast_variable * ast_category_detach_variables(struct ast_category *cat)
Definition: main/config.c:1553
static void config_shutdown(void)
Definition: main/config.c:4485
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: main/config.c:3576
static void ast_includes_destroy(struct ast_config_include *incls)
Definition: main/config.c:1340
int ast_store_realtime(const char *family,...)
Create realtime configuration.
Definition: main/config.c:4007
static int cfmstat_cmp(struct cache_file_mtime *cfmtime, struct stat *statbuf)
Definition: main/config.c:1834
int ast_variables_match(const struct ast_variable *left, const struct ast_variable *right)
Tests 2 variable values to see if they match.
Definition: main/config.c:936
int ast_store_realtime_fields(const char *family, const struct ast_variable *fields)
Create realtime configuration.
Definition: main/config.c:3986
#define MIN_VARIABLE_FNAME_SPACE
Definition: main/config.c:74
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.
Definition: main/config.c:4569
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.
Definition: main/config.c:2870
void ast_category_rename(struct ast_category *cat, const char *name)
Definition: main/config.c:1564
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.
Definition: main/config.c:1373
static void config_cache_attribute(const char *configfile, enum config_cache_attribute_enum attrtype, const char *filename, const char *who_asked)
Definition: main/config.c:1900
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...)
Update realtime configuration.
Definition: main/config.c:3926
int ast_destroy_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Destroy realtime configuration.
Definition: main/config.c:4023
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.
Definition: main/config.c:1026
int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
Definition: main/config.c:1601
int ast_realtime_require_field(const char *family,...)
Inform realtime what fields that may be stored.
Definition: main/config.c:3816
struct ast_config * ast_config_copy(const struct ast_config *old)
Copies the contents of one ast_config into another.
Definition: main/config.c:3501
void ast_config_hook_unregister(const char *name)
Unregister a config hook.
Definition: main/config.c:4541
int ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
Inserts new category.
Definition: main/config.c:1267
static void config_included_files_destroy(struct ast_config_include *incl)
Definition: main/config.c:1319
struct ast_category * ast_category_delete(struct ast_config *config, struct ast_category *category)
Delete a category.
Definition: main/config.c:1696
char * ast_realtime_encode_chunk(struct ast_str **dest, ssize_t maxlen, const char *chunk)
Encodes a chunk of data for realtime.
Definition: main/config.c:4074
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: main/config.c:1741
static void config_cache_remove(const char *filename, const char *who_asked)
Definition: main/config.c:1883
#define CB_SIZE
Definition: main/config.c:128
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.
Definition: main/config.c:854
static int count_linefeeds_in_comments(struct ast_comment *x)
Definition: main/config.c:2823
include_statement_type
Types used for ast_include_new() include_type.
Definition: main/config.c:275
@ CONFIG_STATEMENT_TRYINCLUDE
Definition: main/config.c:281
@ CONFIG_STATEMENT_INCLUDE
Definition: main/config.c:277
@ CONFIG_STATEMENT_EXEC
Definition: main/config.c:279
static ast_mutex_t config_lock
Definition: main/config.c:215
#define COMMENT_TAG
Definition: main/config.c:67
static int hook_hash(const void *obj, const int flags)
Definition: main/config.c:4534
static char * handle_cli_config_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/config.c:4392
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: main/config.c:1592
static struct ast_category * category_get_sep(const struct ast_config *config, const char *category_name, const char *filter, char sep, char pointer_match_possible)
Definition: main/config.c:1184
static void ast_variable_destroy(struct ast_variable *doomed)
Definition: main/config.c:622
#define realtime_arguments_to_fields(ap, result)
Definition: main/config.c:3592
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.
Definition: main/config.c:1646
struct ast_variable * ast_variables_reverse(struct ast_variable *var)
Reverse a variable list.
Definition: main/config.c:652
int ast_realtime_enabled(void)
Check if there's any realtime engines loaded.
Definition: main/config.c:3811
static int init_appendbuf(void *data)
Definition: main/config.c:118
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.
Definition: main/config.c:1014
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3843
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)
Definition: main/config.c:2362
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, struct ast_config_include **last_inc, const char *who_asked)
parse one line in the configuration.
Definition: main/config.c:2044
static void insert_leading_blank_lines(FILE *fp, struct inclfile *fi, struct ast_comment *precomments, int lineno)
Definition: main/config.c:2834
static int hashtab_compare_strings(void *a, void *b, int flags)
Definition: main/config.c:194
static struct ast_category * next_available_category(struct ast_category *cat, const char *name, const char *filter)
Definition: main/config.c:1350
config_cache_attribute_enum
Definition: main/config.c:1798
@ ATTRIBUTE_EXEC
Definition: main/config.c:1800
@ ATTRIBUTE_INCLUDE
Definition: main/config.c:1799
struct ast_str * ast_category_get_templates(const struct ast_category *category)
Return the template names this category inherits from.
Definition: main/config.c:1222
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
Definition: main/config.c:3428
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)
Definition: main/config.c:3534
static int realtime_arguments_to_fields2(va_list ap, int skip, struct ast_variable **result)
Definition: main/config.c:3607
struct ast_variable * ast_load_realtime_all(const char *family,...)
Definition: main/config.c:3721
struct ast_config_include * ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int include_type, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
Definition: main/config.c:364
void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
Set the category within the configuration as being current.
Definition: main/config.c:1764
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category.
Definition: main/config.c:1174
struct ast_variable * ast_load_realtime(const char *family,...)
Definition: main/config.c:3773
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.
Definition: main/config.c:3464
static int reload_module(void)
Definition: main/config.c:3331
int ast_update2_realtime(const char *family,...)
Update realtime configuration.
Definition: main/config.c:3962
int ast_realtime_is_mapping_defined(const char *family)
Determine if a mapping exists for a given family.
Definition: main/config.c:3448
int ast_config_engine_register(struct ast_config_engine *new)
Register config engine.
Definition: main/config.c:3412
struct ast_category * ast_config_get_current_category(const struct ast_config *cfg)
Retrieve the current category name being built.
Definition: main/config.c:1759
static void move_variables(struct ast_category *old, struct ast_category *new)
Definition: main/config.c:1053
struct ast_config * ast_load_realtime_multientry(const char *family,...)
Retrieve realtime configuration.
Definition: main/config.c:3889
static int count_linefeeds(char *str)
Definition: main/config.c:2811
char * ast_realtime_decode_chunk(char *chunk)
Remove standard encoding from realtime values, which ensures that a semicolon embedded within a singl...
Definition: main/config.c:4062
static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
Definition: main/config.c:2738
static void ast_destroy_template_list(struct ast_category *cat)
Definition: main/config.c:1298
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
Definition: main/config.c:1251
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.
Definition: main/config.c:4094
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3797
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.
Definition: main/config.c:733
struct ast_variable * ast_load_realtime_all_fields(const char *family, const struct ast_variable *fields)
Definition: main/config.c:3688
static char * handle_cli_core_show_config_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/config.c:4355
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
Definition: main/config.c:630
struct ast_variable * ast_category_root(struct ast_config *config, char *cat)
returns the root ast_variable of a config
Definition: main/config.c:1364
static void clear_config_maps(void)
Definition: main/config.c:3281
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Definition: main/config.c:687
static void print_include(FILE *f, struct ast_config_include *incl)
Definition: main/config.c:2914
static struct ast_threadstorage appendbuf
Definition: main/config.c:125
static void ast_variable_move(struct ast_variable *dst_var, struct ast_variable *src_var)
Definition: main/config.c:349
static void CB_RESET(struct ast_str *cb, struct ast_str *llb)
Definition: main/config.c:144
static void ast_comment_destroy(struct ast_comment **comment)
Definition: main/config.c:610
int ast_category_empty(struct ast_category *category)
Removes and destroys all variables in a category.
Definition: main/config.c:1728
static struct ast_variable * variable_clone(const struct ast_variable *old)
Definition: main/config.c:1039
int ast_category_is_template(const struct ast_category *category)
Check if category is a template.
Definition: main/config.c:1217
static void config_cache_destroy_entry(struct cache_file_mtime *cfmtime)
Definition: main/config.c:1870
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.
Definition: main/config.c:787
static struct ast_config_map * config_maps
static int hash_string(const void *obj, const int flags)
Definition: main/config.c:174
static struct ao2_container * cfg_hooks
Definition: main/config.c:78
#define COMMENT_META
Definition: main/config.c:66
#define MAX_INCLUDE_LEVEL
Definition: main/config.c:218
struct ast_variable * ast_load_realtime_fields(const char *family, const struct ast_variable *fields)
Retrieve realtime configuration.
Definition: main/config.c:3738
int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *replacement)
Replace a variable in the given list with a new value.
Definition: main/config.c:754
static int handle_include_exec(const char *command, const char *output_file)
Definition: main/config.c:1958
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:870
int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup,...)
Destroy realtime configuration.
Definition: main/config.c:4043
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.
Definition: main/config.c:903
int ast_update_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Update realtime configuration.
Definition: main/config.c:3905
static void hook_destroy(void *obj)
Definition: main/config.c:4518
static int hook_cmp(void *obj, void *arg, int flags)
Definition: main/config.c:4526
static void ast_include_destroy(struct ast_config_include *incl)
Definition: main/config.c:1328
void ast_category_destroy(struct ast_category *cat)
Definition: main/config.c:1306
struct ast_variable * ast_category_first(struct ast_category *cat)
given a pointer to a category, return the root variable.
Definition: main/config.c:1359
static struct inclfile * set_fn(char *fn, size_t fn_size, const char *file, const char *configfile, struct ao2_container *fileset)
Definition: main/config.c:2779
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.
Definition: main/config.c:2929
const char * ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
Retrieve a configuration variable within the configuration set.
Definition: main/config.c:860
static void cfmstat_save(struct cache_file_mtime *cfmtime, struct stat *statbuf)
Definition: main/config.c:1810
static int load_module(void)
Definition: main/config.c:4603
int ast_category_exist(const struct ast_config *config, const char *category_name, const char *filter)
Check for category duplicates.
Definition: main/config.c:1245
struct ast_variable * ast_variable_list_sort(struct ast_variable *start)
Performs an in-place sort on the variable list by ascending name.
Definition: main/config.c:707
static void CB_ADD_LEN(struct ast_str **cb, const char *str, int len)
Definition: main/config.c:135
static void print_comment(FILE *f, struct ast_comment *comment)
Definition: main/config.c:2894
static int is_writable(const char *fn)
Definition: main/config.c:2875
static int unload_module(void)
Definition: main/config.c:4598
static void make_fn(char *fn, size_t fn_size, const char *file, const char *configfile)
Definition: main/config.c:2764
void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
Definition: main/config.c:586
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.
Definition: main/config.c:770
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.
Definition: main/config.c:956
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: main/config.c:676
static char * extconfig_conf
Definition: main/config.c:76
struct ast_config_include * ast_include_find(struct ast_config *conf, const char *included_file)
Definition: main/config.c:562
struct ast_variable * _ast_variable_new(const char *name, const char *value, const char *filename, const char *file, const char *func, int lineno)
Definition: main/config.c:315
static char * handle_cli_config_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/config.c:4455
static struct cache_file_mtime * cfmtime_new(const char *filename, const char *who_asked)
Definition: main/config.c:1780
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....
Definition: main/config.c:1065
struct ast_config * ast_load_realtime_multientry_fields(const char *family, const struct ast_variable *fields)
Retrieve realtime configuration.
Definition: main/config.c:3863
static struct ast_category * new_category(const char *name, const char *in_file, int lineno, int template)
Definition: main/config.c:1155
static struct ast_config_engine * config_engine_list
Definition: main/config.c:216
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.
Definition: main/config.c:924
static int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
Definition: main/config.c:3295
int ast_update2_realtime_fields(const char *family, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
Update realtime configuration.
Definition: main/config.c:3942
static void inclfile_destroy(void *obj)
Definition: main/config.c:2757
int ast_category_inherit(struct ast_category *new, const struct ast_category *base)
Applies base (template) to category.
Definition: main/config.c:1569
const char * ast_variable_find(const struct ast_category *category, const char *variable)
Gets a variable value from a specific category structure by name.
Definition: main/config.c:919
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
Definition: main/config.c:1206
static struct ast_comment * ALLOC_COMMENT(struct ast_str *buffer)
Definition: main/config.c:154
static void config_hook_exec(const char *filename, const char *module, const struct ast_config *cfg)
Definition: main/config.c:4550
static struct ast_config_engine text_file_engine
Definition: main/config.c:3496
static void CB_ADD(struct ast_str **cb, const char *str)
Definition: main/config.c:130
static struct ast_variable * variable_list_switch(struct ast_variable *l1, struct ast_variable *l2)
Definition: main/config.c:700
int register_config_cli(void)
Exposed initialization method for core process.
Definition: main/config.c:4503
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.
Definition: main/config.c:1537
#define WEXITSTATUS(status)
#define WIFEXITED(status)
int errno
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:330
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_FAILURE
Module could not be loaded properly.
Definition: module.h:102
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
Network socket handling.
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.
Definition: netsock2.c:337
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:256
#define ast_sockaddr_to_sin(addr, sin)
Converts a struct ast_sockaddr to a struct sockaddr_in.
Definition: netsock2.h:765
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
Wrapper for network related headers, masking differences between various operating systems....
const char * ast_inet_ntoa(struct in_addr ia)
thread-safe replacement for inet_ntoa().
Definition: utils.c:964
#define ast_opt_console
Definition: options.h:121
#define ast_opt_exec_includes
Definition: options.h:118
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:152
static int total
Definition: res_adsi.c:970
static int reload(void)
#define NULL
Definition: resample.c:96
String manipulation functions.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
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.
Definition: utils.c:1935
void ast_str_trim_blanks(struct ast_str *buf)
Trims trailing whitespace characters from an ast_str string.
Definition: strings.h:719
@ AST_STRSEP_ALL
Definition: strings.h:258
@ AST_STRSEP_STRIP
Definition: strings.h:255
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
int ast_strings_match(const char *left, const char *op, const char *right)
Compares 2 strings using realtime-style operators.
Definition: strings.c:260
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition: utils.c:1871
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
struct ast_category_template_instance * next
Definition: main/config.c:223
const struct ast_category * inst
Definition: main/config.c:222
struct ast_comment * precomments
Definition: main/config.c:238
char name[80]
Definition: main/config.c:227
struct ast_category::template_instance_list template_instances
struct ast_category * next
Definition: main/config.c:248
struct ast_variable * last
Definition: main/config.c:244
struct ast_comment * trailing
Definition: main/config.c:240
struct ast_variable * root
Definition: main/config.c:242
struct ast_comment * sameline
Definition: main/config.c:239
struct ast_category * prev
Definition: main/config.c:246
char * file
The file name from whence this declaration was read.
Definition: main/config.c:235
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure to keep comments for rewriting configuration files.
Definition: main/config.c:85
char cmt[0]
Definition: main/config.c:88
struct ast_comment * next
Definition: main/config.c:86
Configuration engine structure, used to define realtime drivers.
realtime_var_get * realtime_func
struct ast_config_engine * next
realtime_destroy * destroy_func
realtime_unload * unload_func
realtime_store * store_func
realtime_multi_get * realtime_multi_func
config_load_func * load_func
realtime_update * update_func
realtime_update2 * update2_func
realtime_require * require_func
char * include_location_file
file name in which the include occurs
Definition: main/config.c:289
char * exec_file
if it's an exec, you'll have both the /var/tmp to read, and the original script
Definition: main/config.c:296
char * included_file
file name included
Definition: main/config.c:301
struct ast_config_include::included_files_list included_files
struct ast_comment * sameline
Definition: main/config.c:307
struct ast_config_include * next
Definition: main/config.c:309
struct ast_comment * precomments
Definition: main/config.c:306
enum include_statement_type include_type
Definition: main/config.c:291
struct ast_comment * trailing
Definition: main/config.c:308
const char * driver
Definition: main/config.c:206
struct ast_config_map * next
Definition: main/config.c:201
const char * table
Definition: main/config.c:210
const char * database
Definition: main/config.c:208
const char * name
Definition: main/config.c:204
struct ast_config_include * includes_root
Definition: main/config.c:261
struct ast_config_include * includes_last
Definition: main/config.c:263
struct ast_category * current
Definition: main/config.c:256
int include_level
Definition: main/config.c:258
int max_include_level
Definition: main/config.c:259
struct ast_category * last
Definition: main/config.c:255
struct ast_category * root
Definition: main/config.c:253
struct ast_category * last_browse
Definition: main/config.c:257
Structure used to handle boolean flags.
Definition: utils.h:217
Socket address structure.
Definition: netsock2.h:97
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
char stuff[0]
Contents of file, name, and value in that order stuffed here.
struct ast_comment * precomments
struct ast_comment * trailing
struct ast_comment * sameline
struct ast_variable * next
Hold the mtime for config files, so if we don't need to reread our config, don't.
Definition: main/config.c:92
struct cache_file_include::@340 list
struct cache_file_mtime::@341 list
unsigned long stat_size
Definition: main/config.c:103
struct cache_file_mtime::includes includes
unsigned int has_exec
Definition: main/config.c:101
const char * who_asked
Definition: main/config.c:110
unsigned long stat_mtime_nsec
Definition: main/config.c:105
config_hook_cb hook_cb
Definition: main/config.c:4515
const char * filename
Definition: main/config.c:4513
const char * module
Definition: main/config.c:4514
const char * name
Definition: main/config.c:4512
All configuration options for http media cache.
struct config_included_file * next
Definition: main/config.c:267
int lineno
Definition: main/config.c:171
char * fname
Definition: main/config.c:170
struct sla_ringing_trunk * next
Definition: app_sla.c:314
int value
Definition: syslog.c:37
static int hook_cb(struct ast_config *cfg)
Definition: test_config.c:875
static struct aco_type item
Definition: test_config.c:1463
static struct test_val b
static struct test_val a
static struct test_val c
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
Time-related functions and macros.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
int error(const char *format,...)
Definition: utils/frame.c:999
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:978
#define ast_assert(a)
Definition: utils.h:776
#define ast_clear_flag(p, flag)
Definition: utils.h:77
char * ast_escape_semicolons(const char *string, char *outbuf, int buflen)
Escape semicolons found in a string.
Definition: utils.c:847
#define ARRAY_LEN(a)
Definition: utils.h:703