446bac2dfbd1530ed65ebd1f263c5bf1c26af058
[asterisk/asterisk.git] / main / config.c
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 http://wiki.asterisk.org
27  */
28
29 /*** MODULEINFO
30         <support_level>core</support_level>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include "asterisk/paths.h"     /* use ast_config_AST_CONFIG_DIR */
38 #include "asterisk/network.h"   /* we do some sockaddr manipulation here */
39 #include <time.h>
40 #include <sys/stat.h>
41
42 #include <math.h>       /* HUGE_VAL */
43
44 #define AST_INCLUDE_GLOB 1
45
46 #include "asterisk/config.h"
47 #include "asterisk/cli.h"
48 #include "asterisk/lock.h"
49 #include "asterisk/utils.h"
50 #include "asterisk/channel.h"
51 #include "asterisk/app.h"
52 #include "asterisk/astobj2.h"
53 #include "asterisk/strings.h"   /* for the ast_str_*() API */
54 #include "asterisk/netsock2.h"
55
56 #define MAX_NESTED_COMMENTS 128
57 #define COMMENT_START ";--"
58 #define COMMENT_END "--;"
59 #define COMMENT_META ';'
60 #define COMMENT_TAG '-'
61
62 /*!
63  * Define the minimum filename space to reserve for each
64  * ast_variable in case the filename is renamed later by
65  * ast_include_rename().
66  */
67 #define MIN_VARIABLE_FNAME_SPACE        40
68
69 static char *extconfig_conf = "extconfig.conf";
70
71 static struct ao2_container *cfg_hooks;
72 static void config_hook_exec(const char *filename, const char *module, struct ast_config *cfg);
73 inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2);
74
75 /*! \brief Structure to keep comments for rewriting configuration files */
76 struct ast_comment {
77         struct ast_comment *next;
78         /*! Comment body allocated after struct. */
79         char cmt[0];
80 };
81
82 /*! \brief Hold the mtime for config files, so if we don't need to reread our config, don't. */
83 struct cache_file_include {
84         AST_LIST_ENTRY(cache_file_include) list;
85         char include[0];
86 };
87
88 struct cache_file_mtime {
89         AST_LIST_ENTRY(cache_file_mtime) list;
90         AST_LIST_HEAD_NOLOCK(includes, cache_file_include) includes;
91         unsigned int has_exec:1;
92         time_t mtime;
93
94         /*! String stuffed in filename[] after the filename string. */
95         const char *who_asked;
96         /*! Filename and who_asked stuffed after it. */
97         char filename[0];
98 };
99
100 /*! Cached file mtime list. */
101 static AST_LIST_HEAD_STATIC(cfmtime_head, cache_file_mtime);
102
103 static int init_appendbuf(void *data)
104 {
105         struct ast_str **str = data;
106         *str = ast_str_create(16);
107         return *str ? 0 : -1;
108 }
109
110 AST_THREADSTORAGE_CUSTOM(appendbuf, init_appendbuf, ast_free_ptr);
111
112 /* comment buffers are better implemented using the ast_str_*() API */
113 #define CB_SIZE 250     /* initial size of comment buffers */
114
115 static void  CB_ADD(struct ast_str **cb, const char *str)
116 {
117         ast_str_append(cb, 0, "%s", str);
118 }
119
120 static void  CB_ADD_LEN(struct ast_str **cb, const char *str, int len)
121 {
122         char *s = ast_alloca(len + 1);
123         ast_copy_string(s, str, len);
124         ast_str_append(cb, 0, "%s", str);
125 }
126
127 static void CB_RESET(struct ast_str *cb, struct ast_str *llb)
128 {
129         if (cb) {
130                 ast_str_reset(cb);
131         }
132         if (llb) {
133                 ast_str_reset(llb);
134         }
135 }
136
137 static struct ast_comment *ALLOC_COMMENT(struct ast_str *buffer)
138 {
139         struct ast_comment *x = NULL;
140         if (!buffer || !ast_str_strlen(buffer)) {
141                 return NULL;
142         }
143         if ((x = ast_calloc(1, sizeof(*x) + ast_str_strlen(buffer) + 1))) {
144                 strcpy(x->cmt, ast_str_buffer(buffer)); /* SAFE */
145         }
146         return x;
147 }
148
149 /* I need to keep track of each config file, and all its inclusions,
150    so that we can track blank lines in each */
151
152 struct inclfile {
153         char *fname;
154         int lineno;
155 };
156
157 static int hash_string(const void *obj, const int flags)
158 {
159         char *str = ((struct inclfile *) obj)->fname;
160         int total;
161
162         for (total = 0; *str; str++) {
163                 unsigned int tmp = total;
164                 total <<= 1; /* multiply by 2 */
165                 total += tmp; /* multiply by 3 */
166                 total <<= 2; /* multiply by 12 */
167                 total += tmp; /* multiply by 13 */
168
169                 total += ((unsigned int) (*str));
170         }
171         if (total < 0) {
172                 total = -total;
173         }
174         return total;
175 }
176
177 static int hashtab_compare_strings(void *a, void *b, int flags)
178 {
179         const struct inclfile *ae = a, *be = b;
180         return !strcmp(ae->fname, be->fname) ? CMP_MATCH | CMP_STOP : 0;
181 }
182
183 static struct ast_config_map {
184         struct ast_config_map *next;
185         int priority;
186         /*! Stored in stuff[] at struct end. */
187         const char *name;
188         /*! Stored in stuff[] at struct end. */
189         const char *driver;
190         /*! Stored in stuff[] at struct end. */
191         const char *database;
192         /*! Stored in stuff[] at struct end. */
193         const char *table;
194         /*! Contents of name, driver, database, and table in that order stuffed here. */
195         char stuff[0];
196 } *config_maps = NULL;
197
198 AST_MUTEX_DEFINE_STATIC(config_lock);
199 static struct ast_config_engine *config_engine_list;
200
201 #define MAX_INCLUDE_LEVEL 10
202
203 struct ast_category_template_instance {
204         char name[80]; /* redundant? */
205         const struct ast_category *inst;
206         AST_LIST_ENTRY(ast_category_template_instance) next;
207 };
208
209 struct ast_category {
210         char name[80];
211         int ignored;                    /*!< do not let user of the config see this category -- set by (!) after the category decl; a template */
212         int include_level;
213         /*!
214          * \brief The file name from whence this declaration was read
215          * \note Will never be NULL
216          */
217         char *file;
218         int lineno;
219         AST_LIST_HEAD_NOLOCK(template_instance_list, ast_category_template_instance) template_instances;
220         struct ast_comment *precomments;
221         struct ast_comment *sameline;
222         struct ast_comment *trailing; /*!< the last object in the list will get assigned any trailing comments when EOF is hit */
223         /*! First category variable in the list. */
224         struct ast_variable *root;
225         /*! Last category variable in the list. */
226         struct ast_variable *last;
227         /*! Next node in the list. */
228         struct ast_category *next;
229 };
230
231 struct ast_config {
232         /*! First config category in the list. */
233         struct ast_category *root;
234         /*! Last config category in the list. */
235         struct ast_category *last;
236         struct ast_category *current;
237         struct ast_category *last_browse;     /*!< used to cache the last category supplied via category_browse */
238         int include_level;
239         int max_include_level;
240         struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */
241 };
242
243 struct ast_config_include {
244         /*!
245          * \brief file name in which the include occurs
246          * \note Will never be NULL
247          */
248         char *include_location_file;
249         int  include_location_lineno;    /*!< lineno where include occurred */
250         int  exec;                       /*!< set to non-zero if its a #exec statement */
251         /*!
252          * \brief if it's an exec, you'll have both the /var/tmp to read, and the original script
253          * \note Will never be NULL if exec is non-zero
254          */
255         char *exec_file;
256         /*!
257          * \brief file name included
258          * \note Will never be NULL
259          */
260         char *included_file;
261         int inclusion_count;             /*!< if the file is included more than once, a running count thereof -- but, worry not,
262                                               we explode the instances and will include those-- so all entries will be unique */
263         int output;                      /*!< a flag to indicate if the inclusion has been output */
264         struct ast_config_include *next; /*!< ptr to next inclusion in the list */
265 };
266
267 static void ast_variable_destroy(struct ast_variable *doomed);
268 static void ast_includes_destroy(struct ast_config_include *incls);
269
270 #ifdef MALLOC_DEBUG
271 struct ast_variable *_ast_variable_new(const char *name, const char *value, const char *filename, const char *file, const char *func, int lineno)
272 #else
273 struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
274 #endif
275 {
276         struct ast_variable *variable;
277         int name_len = strlen(name) + 1;
278         int val_len = strlen(value) + 1;
279         int fn_len = strlen(filename) + 1;
280
281         /* Ensure a minimum length in case the filename is changed later. */
282         if (fn_len < MIN_VARIABLE_FNAME_SPACE) {
283                 fn_len = MIN_VARIABLE_FNAME_SPACE;
284         }
285
286         if (
287 #ifdef MALLOC_DEBUG
288                 (variable = __ast_calloc(1, fn_len + name_len + val_len + sizeof(*variable), file, lineno, func))
289 #else
290                 (variable = ast_calloc(1, fn_len + name_len + val_len + sizeof(*variable)))
291 #endif
292                 ) {
293                 char *dst = variable->stuff;    /* writable space starts here */
294
295                 /* Put file first so ast_include_rename() can calculate space available. */
296                 variable->file = strcpy(dst, filename);
297                 dst += fn_len;
298                 variable->name = strcpy(dst, name);
299                 dst += name_len;
300                 variable->value = strcpy(dst, value);
301         }
302         return variable;
303 }
304
305 /*!
306  * \internal
307  * \brief Move the contents from the source to the destination variable.
308  *
309  * \param dst_var Destination variable node
310  * \param src_var Source variable node
311  *
312  * \return Nothing
313  */
314 static void ast_variable_move(struct ast_variable *dst_var, struct ast_variable *src_var)
315 {
316         dst_var->lineno = src_var->lineno;
317         dst_var->object = src_var->object;
318         dst_var->blanklines = src_var->blanklines;
319         dst_var->precomments = src_var->precomments;
320         src_var->precomments = NULL;
321         dst_var->sameline = src_var->sameline;
322         src_var->sameline = NULL;
323         dst_var->trailing = src_var->trailing;
324         src_var->trailing = NULL;
325 }
326
327 struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
328 {
329         /* a file should be included ONCE. Otherwise, if one of the instances is changed,
330          * then all be changed. -- how do we know to include it? -- Handling modified
331          * instances is possible, I'd have
332          * to create a new master for each instance. */
333         struct ast_config_include *inc;
334         struct stat statbuf;
335
336         inc = ast_include_find(conf, included_file);
337         if (inc) {
338                 do {
339                         inc->inclusion_count++;
340                         snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
341                 } while (stat(real_included_file_name, &statbuf) == 0);
342                 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);
343         } else
344                 *real_included_file_name = 0;
345
346         inc = ast_calloc(1,sizeof(struct ast_config_include));
347         if (!inc) {
348                 return NULL;
349         }
350         inc->include_location_file = ast_strdup(from_file);
351         inc->include_location_lineno = from_lineno;
352         if (!ast_strlen_zero(real_included_file_name))
353                 inc->included_file = ast_strdup(real_included_file_name);
354         else
355                 inc->included_file = ast_strdup(included_file);
356
357         inc->exec = is_exec;
358         if (is_exec)
359                 inc->exec_file = ast_strdup(exec_file);
360
361         if (!inc->include_location_file
362                 || !inc->included_file
363                 || (is_exec && !inc->exec_file)) {
364                 ast_includes_destroy(inc);
365                 return NULL;
366         }
367
368         /* attach this new struct to the conf struct */
369         inc->next = conf->includes;
370         conf->includes = inc;
371
372         return inc;
373 }
374
375 void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
376 {
377         struct ast_config_include *incl;
378         struct ast_category *cat;
379         char *str;
380
381         int from_len = strlen(from_file);
382         int to_len = strlen(to_file);
383
384         if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
385                 return;
386
387         /* the manager code allows you to read in one config file, then
388          * write it back out under a different name. But, the new arrangement
389          * ties output lines to the file name. So, before you try to write
390          * the config file to disk, better riffle thru the data and make sure
391          * the file names are changed.
392          */
393         /* file names are on categories, includes (of course), and on variables. So,
394          * traverse all this and swap names */
395
396         for (incl = conf->includes; incl; incl=incl->next) {
397                 if (strcmp(incl->include_location_file,from_file) == 0) {
398                         if (from_len >= to_len)
399                                 strcpy(incl->include_location_file, to_file);
400                         else {
401                                 /* Keep the old filename if the allocation fails. */
402                                 str = ast_strdup(to_file);
403                                 if (str) {
404                                         ast_free(incl->include_location_file);
405                                         incl->include_location_file = str;
406                                 }
407                         }
408                 }
409         }
410         for (cat = conf->root; cat; cat = cat->next) {
411                 struct ast_variable **prev;
412                 struct ast_variable *v;
413                 struct ast_variable *new_var;
414
415                 if (strcmp(cat->file,from_file) == 0) {
416                         if (from_len >= to_len)
417                                 strcpy(cat->file, to_file);
418                         else {
419                                 /* Keep the old filename if the allocation fails. */
420                                 str = ast_strdup(to_file);
421                                 if (str) {
422                                         ast_free(cat->file);
423                                         cat->file = str;
424                                 }
425                         }
426                 }
427                 for (prev = &cat->root, v = cat->root; v; prev = &v->next, v = v->next) {
428                         if (strcmp(v->file, from_file)) {
429                                 continue;
430                         }
431
432                         /*
433                          * Calculate actual space available.  The file string is
434                          * intentionally stuffed before the name string just so we can
435                          * do this.
436                          */
437                         if (to_len < v->name - v->file) {
438                                 /* The new name will fit in the available space. */
439                                 str = (char *) v->file;/* Stupid compiler complains about discarding qualifiers even though I used a cast. */
440                                 strcpy(str, to_file);/* SAFE */
441                                 continue;
442                         }
443
444                         /* Keep the old filename if the allocation fails. */
445                         new_var = ast_variable_new(v->name, v->value, to_file);
446                         if (!new_var) {
447                                 continue;
448                         }
449
450                         /* Move items from the old list node to the replacement node. */
451                         ast_variable_move(new_var, v);
452
453                         /* Replace the old node in the list with the new node. */
454                         new_var->next = v->next;
455                         if (cat->last == v) {
456                                 cat->last = new_var;
457                         }
458                         *prev = new_var;
459
460                         ast_variable_destroy(v);
461
462                         v = new_var;
463                 }
464         }
465 }
466
467 struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
468 {
469         struct ast_config_include *x;
470         for (x=conf->includes;x;x=x->next) {
471                 if (strcmp(x->included_file,included_file) == 0)
472                         return x;
473         }
474         return 0;
475 }
476
477
478 void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
479 {
480         if (!variable)
481                 return;
482         if (category->last)
483                 category->last->next = variable;
484         else
485                 category->root = variable;
486         category->last = variable;
487         while (category->last->next)
488                 category->last = category->last->next;
489 }
490
491 void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
492 {
493         struct ast_variable *cur = category->root;
494         int lineno;
495         int insertline;
496
497         if (!variable || sscanf(line, "%30d", &insertline) != 1) {
498                 return;
499         }
500         if (!insertline) {
501                 variable->next = category->root;
502                 category->root = variable;
503         } else {
504                 for (lineno = 1; lineno < insertline; lineno++) {
505                         cur = cur->next;
506                         if (!cur->next) {
507                                 break;
508                         }
509                 }
510                 variable->next = cur->next;
511                 cur->next = variable;
512         }
513 }
514
515 static void ast_comment_destroy(struct ast_comment **comment)
516 {
517         struct ast_comment *n, *p;
518
519         for (p = *comment; p; p = n) {
520                 n = p->next;
521                 ast_free(p);
522         }
523
524         *comment = NULL;
525 }
526
527 static void ast_variable_destroy(struct ast_variable *doomed)
528 {
529         ast_comment_destroy(&doomed->precomments);
530         ast_comment_destroy(&doomed->sameline);
531         ast_comment_destroy(&doomed->trailing);
532         ast_free(doomed);
533 }
534
535 struct ast_variable *ast_variables_dup(struct ast_variable *var)
536 {
537         struct ast_variable *cloned;
538         struct ast_variable *tmp;
539
540         if (!(cloned = ast_variable_new(var->name, var->value, var->file))) {
541                 return NULL;
542         }
543
544         tmp = cloned;
545
546         while ((var = var->next)) {
547                 if (!(tmp->next = ast_variable_new(var->name, var->value, var->file))) {
548                         ast_variables_destroy(cloned);
549                         return NULL;
550                 }
551                 tmp = tmp->next;
552         }
553
554         return cloned;
555 }
556
557 void ast_variables_destroy(struct ast_variable *v)
558 {
559         struct ast_variable *vn;
560
561         while (v) {
562                 vn = v;
563                 v = v->next;
564                 ast_variable_destroy(vn);
565         }
566 }
567
568 struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
569 {
570         struct ast_category *cat = NULL;
571
572         if (!category) {
573                 return NULL;
574         }
575
576         if (config->last_browse && (config->last_browse->name == category)) {
577                 cat = config->last_browse;
578         } else {
579                 cat = ast_category_get(config, category);
580         }
581
582         return (cat) ? cat->root : NULL;
583 }
584
585 inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2)
586 {
587     l1->next = l2->next;
588     l2->next = l1;
589     return l2;
590 }
591
592 struct ast_variable *ast_variable_list_sort(struct ast_variable *start)
593 {
594         struct ast_variable *p, *q, *top;
595         int changed = 1;
596         top = ast_calloc(1, sizeof(struct ast_variable));
597         top->next = start;
598         if (start != NULL && start->next != NULL) {
599                 while (changed) {
600                         changed = 0;
601                         q = top;
602                         p = top->next;
603                         while (p->next != NULL) {
604                                 if (p->next != NULL && strcmp(p->name, p->next->name) > 0) {
605                                         q->next = variable_list_switch(p, p->next);
606
607                                         changed = 1;
608                                 }
609                                 q = p;
610                                 if (p->next != NULL)
611                                         p = p->next;
612                         }
613                 }
614         }
615         return top->next;
616 }
617
618 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
619 {
620         const char *tmp;
621         tmp = ast_variable_retrieve(cfg, cat, var);
622         if (!tmp) {
623                 tmp = ast_variable_retrieve(cfg, "general", var);
624         }
625         return tmp;
626 }
627
628
629 const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
630 {
631         struct ast_variable *v;
632
633         if (category) {
634                 for (v = ast_variable_browse(config, category); v; v = v->next) {
635                         if (!strcasecmp(variable, v->name)) {
636                                 return v->value;
637                         }
638                 }
639         } else {
640                 struct ast_category *cat;
641
642                 for (cat = config->root; cat; cat = cat->next) {
643                         for (v = cat->root; v; v = v->next) {
644                                 if (!strcasecmp(variable, v->name)) {
645                                         return v->value;
646                                 }
647                         }
648                 }
649         }
650
651         return NULL;
652 }
653
654 static struct ast_variable *variable_clone(const struct ast_variable *old)
655 {
656         struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
657
658         if (new) {
659                 new->lineno = old->lineno;
660                 new->object = old->object;
661                 new->blanklines = old->blanklines;
662                 /* TODO: clone comments? */
663         }
664
665         return new;
666 }
667
668 static void move_variables(struct ast_category *old, struct ast_category *new)
669 {
670         struct ast_variable *var = old->root;
671
672         old->root = NULL;
673         /* we can just move the entire list in a single op */
674         ast_variable_append(new, var);
675 }
676
677 struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
678 {
679         struct ast_category *category;
680
681         category = ast_calloc(1, sizeof(*category));
682         if (!category) {
683                 return NULL;
684         }
685         category->file = ast_strdup(in_file);
686         if (!category->file) {
687                 ast_category_destroy(category);
688                 return NULL;
689         }
690         ast_copy_string(category->name, name, sizeof(category->name));
691         category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
692         return category;
693 }
694
695 static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
696 {
697         struct ast_category *cat;
698
699         /* try exact match first, then case-insensitive match */
700         for (cat = config->root; cat; cat = cat->next) {
701                 if (cat->name == category_name && (ignored || !cat->ignored))
702                         return cat;
703         }
704
705         for (cat = config->root; cat; cat = cat->next) {
706                 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
707                         return cat;
708         }
709
710         return NULL;
711 }
712
713 struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
714 {
715         return category_get(config, category_name, 0);
716 }
717
718 int ast_category_exist(const struct ast_config *config, const char *category_name)
719 {
720         return !!ast_category_get(config, category_name);
721 }
722
723 void ast_category_append(struct ast_config *config, struct ast_category *category)
724 {
725         if (config->last)
726                 config->last->next = category;
727         else
728                 config->root = category;
729         category->include_level = config->include_level;
730         config->last = category;
731         config->current = category;
732 }
733
734 void ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
735 {
736         struct ast_category *cur_category;
737
738         if (!cat || !match)
739                 return;
740         if (!strcasecmp(config->root->name, match)) {
741                 cat->next = config->root;
742                 config->root = cat;
743                 return;
744         }
745         for (cur_category = config->root; cur_category; cur_category = cur_category->next) {
746                 if (!strcasecmp(cur_category->next->name, match)) {
747                         cat->next = cur_category->next;
748                         cur_category->next = cat;
749                         break;
750                 }
751         }
752 }
753
754 static void ast_destroy_template_list(struct ast_category *cat)
755 {
756         struct ast_category_template_instance *x;
757
758         while ((x = AST_LIST_REMOVE_HEAD(&cat->template_instances, next)))
759                 ast_free(x);
760 }
761
762 void ast_category_destroy(struct ast_category *cat)
763 {
764         ast_variables_destroy(cat->root);
765         cat->root = NULL;
766         cat->last = NULL;
767         ast_comment_destroy(&cat->precomments);
768         ast_comment_destroy(&cat->sameline);
769         ast_comment_destroy(&cat->trailing);
770         ast_destroy_template_list(cat);
771         ast_free(cat->file);
772         ast_free(cat);
773 }
774
775 static void ast_includes_destroy(struct ast_config_include *incls)
776 {
777         struct ast_config_include *incl,*inclnext;
778
779         for (incl=incls; incl; incl = inclnext) {
780                 inclnext = incl->next;
781                 ast_free(incl->include_location_file);
782                 ast_free(incl->exec_file);
783                 ast_free(incl->included_file);
784                 ast_free(incl);
785         }
786 }
787
788 static struct ast_category *next_available_category(struct ast_category *cat)
789 {
790         for (; cat && cat->ignored; cat = cat->next);
791
792         return cat;
793 }
794
795 /*! return the first var of a category */
796 struct ast_variable *ast_category_first(struct ast_category *cat)
797 {
798         return (cat) ? cat->root : NULL;
799 }
800
801 struct ast_variable *ast_category_root(struct ast_config *config, char *cat)
802 {
803         struct ast_category *category = ast_category_get(config, cat);
804
805         if (category)
806                 return category->root;
807         return NULL;
808 }
809
810 void ast_config_sort_categories(struct ast_config *config, int descending,
811                                                                 int (*comparator)(struct ast_category *p, struct ast_category *q))
812 {
813         /*
814          * The contents of this function are adapted from
815          * an example of linked list merge sorting
816          * copyright 2001 Simon Tatham.
817          *
818          * Permission is hereby granted, free of charge, to any person
819          * obtaining a copy of this software and associated documentation
820          * files (the "Software"), to deal in the Software without
821          * restriction, including without limitation the rights to use,
822          * copy, modify, merge, publish, distribute, sublicense, and/or
823          * sell copies of the Software, and to permit persons to whom the
824          * Software is furnished to do so, subject to the following
825          * conditions:
826          *
827          * The above copyright notice and this permission notice shall be
828          * included in all copies or substantial portions of the Software.
829          *
830          * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
831          * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
832          * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
833          * NONINFRINGEMENT.  IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
834          * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
835          * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
836          * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
837          * SOFTWARE.
838          */
839
840         int insize = 1;
841         struct ast_category *p, *q, *e, *tail;
842         int nmerges, psize, qsize, i;
843
844         /* If the descending flag was sent, we'll apply inversion to the comparison function's return. */
845         if (descending) {
846                 descending = -1;
847         } else {
848                 descending = 1;
849         }
850
851         if (!config->root) {
852                 return;
853         }
854
855         while (1) {
856                 p = config->root;
857                 config->root = NULL;
858                 tail = NULL;
859
860                 nmerges = 0; /* count number of merges we do in this pass */
861
862                 while (p) {
863                         nmerges++; /* there exists a merge to be done */
864
865                         /* step `insize' places along from p */
866                         q = p;
867                         psize = 0;
868                         for (i = 0; i < insize; i++) {
869                                 psize++;
870                                 q = q->next;
871                                 if (!q) {
872                                         break;
873                                 }
874                         }
875
876                         /* if q hasn't fallen off end, we have two lists to merge */
877                         qsize = insize;
878
879                         /* now we have two lists; merge them */
880                         while (psize > 0 || (qsize > 0 && q)) {
881                                 /* decide whether next element of merge comes from p or q */
882                                 if (psize == 0) {
883                                         /* p is empty; e must come from q. */
884                                         e = q;
885                                         q = q->next;
886                                         qsize--;
887                                 } else if (qsize == 0 || !q) {
888                                         /* q is empty; e must come from p. */
889                                         e = p; p = p->next; psize--;
890                                 } else if ((comparator(p,q) * descending) <= 0) {
891                                         /* First element of p is lower (or same) e must come from p. */
892                                         e = p;
893                                         p = p->next;
894                                         psize--;
895                                 } else {
896                                         /* First element of q is lower; e must come from q. */
897                                         e = q;
898                                         q = q->next;
899                                         qsize--;
900                                 }
901
902                                 /* add the next element to the merged list */
903                                 if (tail) {
904                                         tail->next = e;
905                                 } else {
906                                         config->root = e;
907                                 }
908                                 tail = e;
909                         }
910
911                         /* now p has stepped `insize' places along, and q has too */
912                         p = q;
913                 }
914
915                 tail->next = NULL;
916
917                 /* If we have done only one merge, we're finished. */
918                 if (nmerges <= 1) { /* allow for nmerges==0, the empty list case */
919                         return;
920                 }
921
922                 /* Otherwise repeat, merging lists twice the size */
923                 insize *= 2;
924         }
925
926 }
927
928 char *ast_category_browse(struct ast_config *config, const char *prev)
929 {
930         struct ast_category *cat;
931
932         if (!prev) {
933                 /* First time browse. */
934                 cat = config->root;
935         } else if (config->last_browse && (config->last_browse->name == prev)) {
936                 /* Simple last browse found. */
937                 cat = config->last_browse->next;
938         } else {
939                 /*
940                  * Config changed since last browse.
941                  *
942                  * First try cheap last browse search. (Rebrowsing a different
943                  * previous category?)
944                  */
945                 for (cat = config->root; cat; cat = cat->next) {
946                         if (cat->name == prev) {
947                                 /* Found it. */
948                                 cat = cat->next;
949                                 break;
950                         }
951                 }
952                 if (!cat) {
953                         /*
954                          * Have to do it the hard way. (Last category was deleted and
955                          * re-added?)
956                          */
957                         for (cat = config->root; cat; cat = cat->next) {
958                                 if (!strcasecmp(cat->name, prev)) {
959                                         /* Found it. */
960                                         cat = cat->next;
961                                         break;
962                                 }
963                         }
964                 }
965         }
966
967         if (cat)
968                 cat = next_available_category(cat);
969
970         config->last_browse = cat;
971         return (cat) ? cat->name : NULL;
972 }
973
974 struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
975 {
976         struct ast_variable *v;
977
978         v = cat->root;
979         cat->root = NULL;
980         cat->last = NULL;
981
982         return v;
983 }
984
985 void ast_category_rename(struct ast_category *cat, const char *name)
986 {
987         ast_copy_string(cat->name, name, sizeof(cat->name));
988 }
989
990 static void inherit_category(struct ast_category *new, const struct ast_category *base)
991 {
992         struct ast_variable *var;
993         struct ast_category_template_instance *x;
994
995         x = ast_calloc(1, sizeof(*x));
996         if (!x) {
997                 return;
998         }
999         strcpy(x->name, base->name);
1000         x->inst = base;
1001         AST_LIST_INSERT_TAIL(&new->template_instances, x, next);
1002         for (var = base->root; var; var = var->next)
1003                 ast_variable_append(new, variable_clone(var));
1004 }
1005
1006 struct ast_config *ast_config_new(void)
1007 {
1008         struct ast_config *config;
1009
1010         if ((config = ast_calloc(1, sizeof(*config))))
1011                 config->max_include_level = MAX_INCLUDE_LEVEL;
1012         return config;
1013 }
1014
1015 int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
1016 {
1017         struct ast_variable *cur, *prev=NULL, *curn;
1018         int res = -1;
1019         int num_item = 0;
1020         int req_item;
1021
1022         req_item = -1;
1023         if (!ast_strlen_zero(line)) {
1024                 /* Requesting to delete by item number. */
1025                 if (sscanf(line, "%30d", &req_item) != 1
1026                         || req_item < 0) {
1027                         /* Invalid item number to delete. */
1028                         return -1;
1029                 }
1030         }
1031
1032         prev = NULL;
1033         cur = category->root;
1034         while (cur) {
1035                 curn = cur->next;
1036                 /* Delete by item number or by variable name with optional value. */
1037                 if ((0 <= req_item && num_item == req_item)
1038                         || (req_item < 0 && !strcasecmp(cur->name, variable)
1039                                 && (ast_strlen_zero(match) || !strcasecmp(cur->value, match)))) {
1040                         if (prev) {
1041                                 prev->next = cur->next;
1042                                 if (cur == category->last)
1043                                         category->last = prev;
1044                         } else {
1045                                 category->root = cur->next;
1046                                 if (cur == category->last)
1047                                         category->last = NULL;
1048                         }
1049                         ast_variable_destroy(cur);
1050                         res = 0;
1051                 } else
1052                         prev = cur;
1053
1054                 cur = curn;
1055                 ++num_item;
1056         }
1057         return res;
1058 }
1059
1060 int ast_variable_update(struct ast_category *category, const char *variable,
1061                                                 const char *value, const char *match, unsigned int object)
1062 {
1063         struct ast_variable *cur, *prev=NULL, *newer=NULL;
1064
1065         for (cur = category->root; cur; prev = cur, cur = cur->next) {
1066                 if (strcasecmp(cur->name, variable) ||
1067                         (!ast_strlen_zero(match) && strcasecmp(cur->value, match)))
1068                         continue;
1069
1070                 if (!(newer = ast_variable_new(variable, value, cur->file)))
1071                         return -1;
1072
1073                 ast_variable_move(newer, cur);
1074                 newer->object = newer->object || object;
1075
1076                 /* Replace the old node in the list with the new node. */
1077                 newer->next = cur->next;
1078                 if (prev)
1079                         prev->next = newer;
1080                 else
1081                         category->root = newer;
1082                 if (category->last == cur)
1083                         category->last = newer;
1084
1085                 ast_variable_destroy(cur);
1086
1087                 return 0;
1088         }
1089
1090         /* Could not find variable to update */
1091         return -1;
1092 }
1093
1094 int ast_category_delete(struct ast_config *cfg, const char *category)
1095 {
1096         struct ast_category *prev=NULL, *cat;
1097
1098         cat = cfg->root;
1099         while (cat) {
1100                 if (cat->name == category) {
1101                         if (prev) {
1102                                 prev->next = cat->next;
1103                                 if (cat == cfg->last)
1104                                         cfg->last = prev;
1105                         } else {
1106                                 cfg->root = cat->next;
1107                                 if (cat == cfg->last)
1108                                         cfg->last = NULL;
1109                         }
1110                         ast_category_destroy(cat);
1111                         return 0;
1112                 }
1113                 prev = cat;
1114                 cat = cat->next;
1115         }
1116
1117         prev = NULL;
1118         cat = cfg->root;
1119         while (cat) {
1120                 if (!strcasecmp(cat->name, category)) {
1121                         if (prev) {
1122                                 prev->next = cat->next;
1123                                 if (cat == cfg->last)
1124                                         cfg->last = prev;
1125                         } else {
1126                                 cfg->root = cat->next;
1127                                 if (cat == cfg->last)
1128                                         cfg->last = NULL;
1129                         }
1130                         ast_category_destroy(cat);
1131                         return 0;
1132                 }
1133                 prev = cat;
1134                 cat = cat->next;
1135         }
1136         return -1;
1137 }
1138
1139 int ast_category_empty(struct ast_config *cfg, const char *category)
1140 {
1141         struct ast_category *cat;
1142
1143         for (cat = cfg->root; cat; cat = cat->next) {
1144                 if (!strcasecmp(cat->name, category))
1145                         continue;
1146                 ast_variables_destroy(cat->root);
1147                 cat->root = NULL;
1148                 cat->last = NULL;
1149                 return 0;
1150         }
1151
1152         return -1;
1153 }
1154
1155 void ast_config_destroy(struct ast_config *cfg)
1156 {
1157         struct ast_category *cat, *catn;
1158
1159         if (!cfg)
1160                 return;
1161
1162         ast_includes_destroy(cfg->includes);
1163
1164         cat = cfg->root;
1165         while (cat) {
1166                 catn = cat;
1167                 cat = cat->next;
1168                 ast_category_destroy(catn);
1169         }
1170         ast_free(cfg);
1171 }
1172
1173 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
1174 {
1175         return cfg->current;
1176 }
1177
1178 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
1179 {
1180         /* cast below is just to silence compiler warning about dropping "const" */
1181         cfg->current = (struct ast_category *) cat;
1182 }
1183
1184 /*!
1185  * \internal
1186  * \brief Create a new cfmtime list node.
1187  *
1188  * \param filename Config filename caching.
1189  * \param who_asked Who wanted to know.
1190  *
1191  * \retval cfmtime New node on success.
1192  * \retval NULL on error.
1193  */
1194 static struct cache_file_mtime *cfmtime_new(const char *filename, const char *who_asked)
1195 {
1196         struct cache_file_mtime *cfmtime;
1197         char *dst;
1198
1199         cfmtime = ast_calloc(1,
1200                 sizeof(*cfmtime) + strlen(filename) + 1 + strlen(who_asked) + 1);
1201         if (!cfmtime) {
1202                 return NULL;
1203         }
1204         dst = cfmtime->filename;        /* writable space starts here */
1205         strcpy(dst, filename);
1206         dst += strlen(dst) + 1;
1207         cfmtime->who_asked = strcpy(dst, who_asked);
1208
1209         return cfmtime;
1210 }
1211
1212 enum config_cache_attribute_enum {
1213         ATTRIBUTE_INCLUDE = 0,
1214         ATTRIBUTE_EXEC = 1,
1215 };
1216
1217 static void config_cache_attribute(const char *configfile, enum config_cache_attribute_enum attrtype, const char *filename, const char *who_asked)
1218 {
1219         struct cache_file_mtime *cfmtime;
1220         struct cache_file_include *cfinclude;
1221         struct stat statbuf = { 0, };
1222
1223         /* Find our cached entry for this configuration file */
1224         AST_LIST_LOCK(&cfmtime_head);
1225         AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
1226                 if (!strcmp(cfmtime->filename, configfile) && !strcmp(cfmtime->who_asked, who_asked))
1227                         break;
1228         }
1229         if (!cfmtime) {
1230                 cfmtime = cfmtime_new(configfile, who_asked);
1231                 if (!cfmtime) {
1232                         AST_LIST_UNLOCK(&cfmtime_head);
1233                         return;
1234                 }
1235                 /* Note that the file mtime is initialized to 0, i.e. 1970 */
1236                 AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
1237         }
1238
1239         if (!stat(configfile, &statbuf))
1240                 cfmtime->mtime = 0;
1241         else
1242                 cfmtime->mtime = statbuf.st_mtime;
1243
1244         switch (attrtype) {
1245         case ATTRIBUTE_INCLUDE:
1246                 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
1247                         if (!strcmp(cfinclude->include, filename)) {
1248                                 AST_LIST_UNLOCK(&cfmtime_head);
1249                                 return;
1250                         }
1251                 }
1252                 cfinclude = ast_calloc(1, sizeof(*cfinclude) + strlen(filename) + 1);
1253                 if (!cfinclude) {
1254                         AST_LIST_UNLOCK(&cfmtime_head);
1255                         return;
1256                 }
1257                 strcpy(cfinclude->include, filename);
1258                 AST_LIST_INSERT_TAIL(&cfmtime->includes, cfinclude, list);
1259                 break;
1260         case ATTRIBUTE_EXEC:
1261                 cfmtime->has_exec = 1;
1262                 break;
1263         }
1264         AST_LIST_UNLOCK(&cfmtime_head);
1265 }
1266
1267 /*! \brief parse one line in the configuration.
1268  * \verbatim
1269  * We can have a category header        [foo](...)
1270  * a directive                          #include / #exec
1271  * or a regular line                    name = value
1272  * \endverbatim
1273  */
1274 static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
1275         char *buf, int lineno, const char *configfile, struct ast_flags flags,
1276         struct ast_str *comment_buffer,
1277         struct ast_str *lline_buffer,
1278         const char *suggested_include_file,
1279         struct ast_category **last_cat, struct ast_variable **last_var, const char *who_asked)
1280 {
1281         char *c;
1282         char *cur = buf;
1283         struct ast_variable *v;
1284         char cmd[512], exec_file[512];
1285
1286         /* Actually parse the entry */
1287         if (cur[0] == '[') { /* A category header */
1288                 /* format is one of the following:
1289                  * [foo]        define a new category named 'foo'
1290                  * [foo](!)     define a new template category named 'foo'
1291                  * [foo](+)     append to category 'foo', error if foo does not exist.
1292                  * [foo](a)     define a new category and inherit from category or template a.
1293                  *              You can put a comma-separated list of categories and templates
1294                  *              and '!' and '+' between parentheses, with obvious meaning.
1295                  */
1296                 struct ast_category *newcat = NULL;
1297                 char *catname;
1298
1299                 c = strchr(cur, ']');
1300                 if (!c) {
1301                         ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
1302                         return -1;
1303                 }
1304                 *c++ = '\0';
1305                 cur++;
1306                 if (*c++ != '(')
1307                         c = NULL;
1308                 catname = cur;
1309                 if (!(*cat = newcat = ast_category_new(catname,
1310                                 S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile),
1311                                 lineno))) {
1312                         return -1;
1313                 }
1314                 (*cat)->lineno = lineno;
1315                 *last_var = 0;
1316                 *last_cat = newcat;
1317
1318                 /* add comments */
1319                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1320                         newcat->precomments = ALLOC_COMMENT(comment_buffer);
1321                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1322                         newcat->sameline = ALLOC_COMMENT(lline_buffer);
1323                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1324                         CB_RESET(comment_buffer, lline_buffer);
1325
1326                 /* If there are options or categories to inherit from, process them now */
1327                 if (c) {
1328                         if (!(cur = strchr(c, ')'))) {
1329                                 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
1330                                 return -1;
1331                         }
1332                         *cur = '\0';
1333                         while ((cur = strsep(&c, ","))) {
1334                                 if (!strcasecmp(cur, "!")) {
1335                                         (*cat)->ignored = 1;
1336                                 } else if (!strcasecmp(cur, "+")) {
1337                                         *cat = category_get(cfg, catname, 1);
1338                                         if (!(*cat)) {
1339                                                 if (newcat)
1340                                                         ast_category_destroy(newcat);
1341                                                 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
1342                                                 return -1;
1343                                         }
1344                                         if (newcat) {
1345                                                 move_variables(newcat, *cat);
1346                                                 ast_category_destroy(newcat);
1347                                                 newcat = NULL;
1348                                         }
1349                                 } else {
1350                                         struct ast_category *base;
1351
1352                                         base = category_get(cfg, cur, 1);
1353                                         if (!base) {
1354                                                 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
1355                                                 return -1;
1356                                         }
1357                                         inherit_category(*cat, base);
1358                                 }
1359                         }
1360                 }
1361                 if (newcat)
1362                         ast_category_append(cfg, *cat);
1363         } else if (cur[0] == '#') { /* A directive - #include or #exec */
1364                 char *cur2;
1365                 char real_inclusion_name[256];
1366                 int do_include = 0;     /* otherwise, it is exec */
1367                 int try_include = 0;
1368
1369                 cur++;
1370                 c = cur;
1371                 while (*c && (*c > 32)) {
1372                         c++;
1373                 }
1374
1375                 if (*c) {
1376                         *c = '\0';
1377                         /* Find real argument */
1378                         c = ast_strip(c + 1);
1379                         if (!(*c)) {
1380                                 c = NULL;
1381                         }
1382                 } else {
1383                         c = NULL;
1384                 }
1385                 if (!strcasecmp(cur, "include")) {
1386                         do_include = 1;
1387                 } else if (!strcasecmp(cur, "tryinclude")) {
1388                         do_include = 1;
1389                         try_include = 1;
1390                 } else if (!strcasecmp(cur, "exec")) {
1391                         if (!ast_opt_exec_includes) {
1392                                 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
1393                                 return 0;       /* XXX is this correct ? or we should return -1 ? */
1394                         }
1395                 } else {
1396                         ast_log(LOG_WARNING, "Unknown directive '#%s' at line %d of %s\n", cur, lineno, configfile);
1397                         return 0;       /* XXX is this correct ? or we should return -1 ? */
1398                 }
1399
1400                 if (c == NULL) {
1401                         ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
1402                                         do_include ? "include / tryinclude" : "exec",
1403                                         do_include ? "filename" : "/path/to/executable",
1404                                         lineno,
1405                                         configfile);
1406                         return 0;       /* XXX is this correct ? or we should return -1 ? */
1407                 }
1408
1409                 cur = c;
1410                 /* Strip off leading and trailing "'s and <>'s */
1411                 /* Dequote */
1412                 if ((*c == '"') || (*c == '<')) {
1413                         char quote_char = *c;
1414                         if (quote_char == '<') {
1415                                 quote_char = '>';
1416                         }
1417
1418                         if (*(c + strlen(c) - 1) == quote_char) {
1419                                 cur++;
1420                                 *(c + strlen(c) - 1) = '\0';
1421                         }
1422                 }
1423                 cur2 = cur;
1424
1425                 /* #exec </path/to/executable>
1426                    We create a tmp file, then we #include it, then we delete it. */
1427                 if (!do_include) {
1428                         struct timeval now = ast_tvnow();
1429                         if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1430                                 config_cache_attribute(configfile, ATTRIBUTE_EXEC, NULL, who_asked);
1431                         snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d%d.%ld", (int)now.tv_sec, (int)now.tv_usec, (long)pthread_self());
1432                         snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
1433                         ast_safe_system(cmd);
1434                         cur = exec_file;
1435                 } else {
1436                         if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1437                                 config_cache_attribute(configfile, ATTRIBUTE_INCLUDE, cur, who_asked);
1438                         exec_file[0] = '\0';
1439                 }
1440                 /* A #include */
1441                 /* record this inclusion */
1442                 ast_include_new(cfg, cfg->include_level == 1 ? "" : configfile, cur, !do_include, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
1443
1444                 do_include = ast_config_internal_load(cur, cfg, flags, real_inclusion_name, who_asked) ? 1 : 0;
1445                 if (!ast_strlen_zero(exec_file))
1446                         unlink(exec_file);
1447                 if (!do_include && !try_include) {
1448                         ast_log(LOG_ERROR, "The file '%s' was listed as a #include but it does not exist.\n", cur);
1449                         return -1;
1450                 }
1451                 /* XXX otherwise what ? the default return is 0 anyways */
1452
1453         } else {
1454                 /* Just a line (variable = value) */
1455                 int object = 0;
1456                 int is_escaped;
1457
1458                 if (!(*cat)) {
1459                         ast_log(LOG_WARNING,
1460                                 "parse error: No category context for line %d of %s\n", lineno, configfile);
1461                         return -1;
1462                 }
1463
1464                 is_escaped = cur[0] == '\\';
1465                 if (is_escaped) {
1466                         /* First character is escaped. */
1467                         ++cur;
1468                         if (cur[0] < 33) {
1469                                 ast_log(LOG_ERROR, "Invalid escape in line %d of %s\n", lineno, configfile);
1470                                 return -1;
1471                         }
1472                 }
1473                 c = strchr(cur + is_escaped, '=');
1474
1475                 if (c && c > cur + is_escaped && (*(c - 1) == '+')) {
1476                         struct ast_variable *var, *replace = NULL;
1477                         struct ast_str **str = ast_threadstorage_get(&appendbuf, sizeof(*str));
1478
1479                         if (!str || !*str) {
1480                                 return -1;
1481                         }
1482
1483                         *(c - 1) = '\0';
1484                         c++;
1485                         cur = ast_strip(cur);
1486
1487                         /* Must iterate through category until we find last variable of same name (since there could be multiple) */
1488                         for (var = ast_category_first(*cat); var; var = var->next) {
1489                                 if (!strcmp(var->name, cur)) {
1490                                         replace = var;
1491                                 }
1492                         }
1493
1494                         if (!replace) {
1495                                 /* Nothing to replace; just set a variable normally. */
1496                                 goto set_new_variable;
1497                         }
1498
1499                         ast_str_set(str, 0, "%s", replace->value);
1500                         ast_str_append(str, 0, "%s", c);
1501                         ast_str_trim_blanks(*str);
1502                         ast_variable_update(*cat, replace->name, ast_skip_blanks(ast_str_buffer(*str)), replace->value, object);
1503                 } else if (c) {
1504                         *c = 0;
1505                         c++;
1506                         /* Ignore > in => */
1507                         if (*c== '>') {
1508                                 object = 1;
1509                                 c++;
1510                         }
1511                         cur = ast_strip(cur);
1512 set_new_variable:
1513                         if (ast_strlen_zero(cur)) {
1514                                 ast_log(LOG_WARNING, "No variable name in line %d of %s\n", lineno, configfile);
1515                         } else if ((v = ast_variable_new(cur, ast_strip(c), S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile)))) {
1516                                 v->lineno = lineno;
1517                                 v->object = object;
1518                                 *last_cat = 0;
1519                                 *last_var = v;
1520                                 /* Put and reset comments */
1521                                 v->blanklines = 0;
1522                                 ast_variable_append(*cat, v);
1523                                 /* add comments */
1524                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1525                                         v->precomments = ALLOC_COMMENT(comment_buffer);
1526                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1527                                         v->sameline = ALLOC_COMMENT(lline_buffer);
1528                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1529                                         CB_RESET(comment_buffer, lline_buffer);
1530
1531                         } else {
1532                                 return -1;
1533                         }
1534                 } else {
1535                         ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
1536                 }
1537         }
1538         return 0;
1539 }
1540
1541 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)
1542 {
1543         char fn[256];
1544 #if defined(LOW_MEMORY)
1545         char buf[512];
1546 #else
1547         char buf[8192];
1548 #endif
1549         char *new_buf, *comment_p, *process_buf;
1550         FILE *f;
1551         int lineno=0;
1552         int comment = 0, nest[MAX_NESTED_COMMENTS];
1553         struct ast_category *cat = NULL;
1554         int count = 0;
1555         struct stat statbuf;
1556         struct cache_file_mtime *cfmtime = NULL;
1557         struct cache_file_include *cfinclude;
1558         struct ast_variable *last_var = 0;
1559         struct ast_category *last_cat = 0;
1560         /*! Growable string buffer */
1561         struct ast_str *comment_buffer = NULL;  /*!< this will be a comment collector.*/
1562         struct ast_str *lline_buffer = NULL;    /*!< A buffer for stuff behind the ; */
1563
1564         if (cfg)
1565                 cat = ast_config_get_current_category(cfg);
1566
1567         if (filename[0] == '/') {
1568                 ast_copy_string(fn, filename, sizeof(fn));
1569         } else {
1570                 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
1571         }
1572
1573         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1574                 comment_buffer = ast_str_create(CB_SIZE);
1575                 if (comment_buffer)
1576                         lline_buffer = ast_str_create(CB_SIZE);
1577                 if (!lline_buffer) {
1578                         ast_free(comment_buffer);
1579                         ast_log(LOG_ERROR, "Failed to initialize the comment buffer!\n");
1580                         return NULL;
1581                 }
1582         }
1583 #ifdef AST_INCLUDE_GLOB
1584         {
1585                 int glob_ret;
1586                 glob_t globbuf;
1587                 globbuf.gl_offs = 0;    /* initialize it to silence gcc */
1588                 glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
1589                 if (glob_ret == GLOB_NOSPACE)
1590                         ast_log(LOG_WARNING,
1591                                 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
1592                 else if (glob_ret  == GLOB_ABORTED)
1593                         ast_log(LOG_WARNING,
1594                                 "Glob Expansion of pattern '%s' failed: Read error\n", fn);
1595                 else  {
1596                         /* loop over expanded files */
1597                         int i;
1598                         for (i=0; i<globbuf.gl_pathc; i++) {
1599                                 ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
1600 #endif
1601         /*
1602          * The following is not a loop, but just a convenient way to define a block
1603          * (using do { } while(0) ), and be able to exit from it with 'continue'
1604          * or 'break' in case of errors. Nice trick.
1605          */
1606         do {
1607                 if (stat(fn, &statbuf))
1608                         continue;
1609
1610                 if (!S_ISREG(statbuf.st_mode)) {
1611                         ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
1612                         continue;
1613                 }
1614
1615                 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
1616                         /* Find our cached entry for this configuration file */
1617                         AST_LIST_LOCK(&cfmtime_head);
1618                         AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
1619                                 if (!strcmp(cfmtime->filename, fn) && !strcmp(cfmtime->who_asked, who_asked))
1620                                         break;
1621                         }
1622                         if (!cfmtime) {
1623                                 cfmtime = cfmtime_new(fn, who_asked);
1624                                 if (!cfmtime)
1625                                         continue;
1626                                 /* Note that the file mtime is initialized to 0, i.e. 1970 */
1627                                 AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
1628                         }
1629                 }
1630
1631                 if (cfmtime && (!cfmtime->has_exec) && (cfmtime->mtime == statbuf.st_mtime) && ast_test_flag(&flags, CONFIG_FLAG_FILEUNCHANGED)) {
1632                         /* File is unchanged, what about the (cached) includes (if any)? */
1633                         int unchanged = 1;
1634                         AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
1635                                 /* We must glob here, because if we did not, then adding a file to globbed directory would
1636                                  * incorrectly cause no reload to be necessary. */
1637                                 char fn2[256];
1638 #ifdef AST_INCLUDE_GLOB
1639                                 int glob_return;
1640                                 glob_t glob_buf = { .gl_offs = 0 };
1641                                 glob_return = glob(cfinclude->include, MY_GLOB_FLAGS, NULL, &glob_buf);
1642                                 /* On error, we reparse */
1643                                 if (glob_return == GLOB_NOSPACE || glob_return  == GLOB_ABORTED)
1644                                         unchanged = 0;
1645                                 else  {
1646                                         /* loop over expanded files */
1647                                         int j;
1648                                         for (j = 0; j < glob_buf.gl_pathc; j++) {
1649                                                 ast_copy_string(fn2, glob_buf.gl_pathv[j], sizeof(fn2));
1650 #else
1651                                                 ast_copy_string(fn2, cfinclude->include);
1652 #endif
1653                                                 if (config_text_file_load(NULL, NULL, fn2, NULL, flags, "", who_asked) == NULL) {
1654                                                         /* that second-to-last field needs to be looked at in this case... TODO */
1655                                                         unchanged = 0;
1656                                                         /* One change is enough to short-circuit and reload the whole shebang */
1657                                                         break;
1658                                                 }
1659 #ifdef AST_INCLUDE_GLOB
1660                                         }
1661                                 }
1662 #endif
1663                         }
1664
1665                         if (unchanged) {
1666                                 AST_LIST_UNLOCK(&cfmtime_head);
1667                                 ast_free(comment_buffer);
1668                                 ast_free(lline_buffer);
1669 #ifdef AST_INCLUDE_GLOB
1670                                 globfree(&globbuf);
1671 #endif
1672                                 return CONFIG_STATUS_FILEUNCHANGED;
1673                         }
1674                 }
1675                 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
1676                         AST_LIST_UNLOCK(&cfmtime_head);
1677
1678                 /* If cfg is NULL, then we just want an answer */
1679                 if (cfg == NULL) {
1680                         ast_free(comment_buffer);
1681                         ast_free(lline_buffer);
1682 #ifdef AST_INCLUDE_GLOB
1683                                 globfree(&globbuf);
1684 #endif
1685                         return NULL;
1686                 }
1687
1688                 if (cfmtime)
1689                         cfmtime->mtime = statbuf.st_mtime;
1690
1691                 if (!(f = fopen(fn, "r"))) {
1692                         ast_debug(1, "No file to parse: %s\n", fn);
1693                         ast_verb(2, "Parsing '%s': Not found (%s)\n", fn, strerror(errno));
1694                         continue;
1695                 }
1696                 count++;
1697                 /* If we get to this point, then we're loading regardless */
1698                 ast_clear_flag(&flags, CONFIG_FLAG_FILEUNCHANGED);
1699                 ast_debug(1, "Parsing %s\n", fn);
1700                 ast_verb(2, "Parsing '%s': Found\n", fn);
1701                 while (!feof(f)) {
1702                         lineno++;
1703                         if (fgets(buf, sizeof(buf), f)) {
1704                                 /* Skip lines that are too long */
1705                                 if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 1] != '\n') {
1706                                         ast_log(LOG_WARNING, "Line %d too long, skipping. It begins with: %.32s...\n", lineno, buf);
1707                                         while (fgets(buf, sizeof(buf), f)) {
1708                                                 if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 1] == '\n') {
1709                                                         break;
1710                                                 }
1711                                         }
1712                                         continue;
1713                                 }
1714
1715                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && ast_str_strlen(lline_buffer)) {
1716                                         CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
1717                                         ast_str_reset(lline_buffer);        /* erase the lline buffer */
1718                                 }
1719
1720                                 new_buf = buf;
1721                                 if (comment)
1722                                         process_buf = NULL;
1723                                 else
1724                                         process_buf = buf;
1725
1726                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer) && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
1727                                         /* blank line? really? Can we add it to an existing comment and maybe preserve inter- and post- comment spacing? */
1728                                         CB_ADD(&comment_buffer, "\n");       /* add a newline to the comment buffer */
1729                                         continue; /* go get a new line, then */
1730                                 }
1731
1732                                 while ((comment_p = strchr(new_buf, COMMENT_META))) {
1733                                         if ((comment_p > new_buf) && (*(comment_p - 1) == '\\')) {
1734                                                 /* Escaped semicolons aren't comments. */
1735                                                 new_buf = comment_p;
1736                                                 /* write over the \ and bring the null terminator with us */
1737                                                 memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
1738                                         } else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
1739                                                 /* Meta-Comment start detected ";--" */
1740                                                 if (comment < MAX_NESTED_COMMENTS) {
1741                                                         *comment_p = '\0';
1742                                                         new_buf = comment_p + 3;
1743                                                         comment++;
1744                                                         nest[comment-1] = lineno;
1745                                                 } else {
1746                                                         ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
1747                                                 }
1748                                         } else if ((comment_p >= new_buf + 2) &&
1749                                                    (*(comment_p - 1) == COMMENT_TAG) &&
1750                                                    (*(comment_p - 2) == COMMENT_TAG)) {
1751                                                 /* Meta-Comment end detected */
1752                                                 comment--;
1753                                                 new_buf = comment_p + 1;
1754                                                 if (!comment) {
1755                                                         /* Back to non-comment now */
1756                                                         if (process_buf) {
1757                                                                 /* Actually have to move what's left over the top, then continue */
1758                                                                 char *oldptr;
1759                                                                 oldptr = process_buf + strlen(process_buf);
1760                                                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1761                                                                         CB_ADD(&comment_buffer, ";");
1762                                                                         CB_ADD_LEN(&comment_buffer, oldptr+1, new_buf-oldptr-1);
1763                                                                 }
1764
1765                                                                 memmove(oldptr, new_buf, strlen(new_buf) + 1);
1766                                                                 new_buf = oldptr;
1767                                                         } else
1768                                                                 process_buf = new_buf;
1769                                                 }
1770                                         } else {
1771                                                 if (!comment) {
1772                                                         /* If ; is found, and we are not nested in a comment,
1773                                                            we immediately stop all comment processing */
1774                                                         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1775                                                                 CB_ADD(&lline_buffer, comment_p);
1776                                                         }
1777                                                         *comment_p = '\0';
1778                                                         new_buf = comment_p;
1779                                                 } else
1780                                                         new_buf = comment_p + 1;
1781                                         }
1782                                 }
1783                                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment && !process_buf ) {
1784                                         CB_ADD(&comment_buffer, buf);  /* the whole line is a comment, store it */
1785                                 }
1786
1787                                 if (process_buf) {
1788                                         char *buffer = ast_strip(process_buf);
1789                                         if (!ast_strlen_zero(buffer)) {
1790                                                 if (process_text_line(cfg, &cat, buffer, lineno, fn, flags, comment_buffer, lline_buffer, suggested_include_file, &last_cat, &last_var, who_asked)) {
1791                                                         cfg = CONFIG_STATUS_FILEINVALID;
1792                                                         break;
1793                                                 }
1794                                         }
1795                                 }
1796                         }
1797                 }
1798                 /* end of file-- anything in a comment buffer? */
1799                 if (last_cat) {
1800                         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
1801                                 if (lline_buffer && ast_str_strlen(lline_buffer)) {
1802                                         CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
1803                                         ast_str_reset(lline_buffer);        /* erase the lline buffer */
1804                                 }
1805                                 last_cat->trailing = ALLOC_COMMENT(comment_buffer);
1806                         }
1807                 } else if (last_var) {
1808                         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
1809                                 if (lline_buffer && ast_str_strlen(lline_buffer)) {
1810                                         CB_ADD(&comment_buffer, ast_str_buffer(lline_buffer));       /* add the current lline buffer to the comment buffer */
1811                                         ast_str_reset(lline_buffer);        /* erase the lline buffer */
1812                                 }
1813                                 last_var->trailing = ALLOC_COMMENT(comment_buffer);
1814                         }
1815                 } else {
1816                         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && ast_str_strlen(comment_buffer)) {
1817                                 ast_debug(1, "Nothing to attach comments to, discarded: %s\n", ast_str_buffer(comment_buffer));
1818                         }
1819                 }
1820                 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
1821                         CB_RESET(comment_buffer, lline_buffer);
1822
1823                 fclose(f);
1824         } while (0);
1825         if (comment) {
1826                 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
1827         }
1828 #ifdef AST_INCLUDE_GLOB
1829                                         if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
1830                                                 break;
1831                                         }
1832                                 }
1833                                 globfree(&globbuf);
1834                         }
1835                 }
1836 #endif
1837
1838         if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
1839                 ast_free(comment_buffer);
1840                 ast_free(lline_buffer);
1841                 comment_buffer = NULL;
1842                 lline_buffer = NULL;
1843         }
1844
1845         if (count == 0)
1846                 return NULL;
1847
1848         return cfg;
1849 }
1850
1851
1852 /* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
1853    which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
1854    recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
1855    be shocked and mystified as to why things are not showing up in the files!
1856
1857    Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
1858    and line number are stored for each include, plus the name of the file included, so that these statements may be
1859    included in the output files on a file_save operation.
1860
1861    The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
1862    are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
1863    the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
1864    and a header gets added.
1865
1866    vars and category heads are output in the order they are stored in the config file. So, if the software
1867    shuffles these at all, then the placement of #include directives might get a little mixed up, because the
1868    file/lineno data probably won't get changed.
1869
1870 */
1871
1872 static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
1873 {
1874         char date[256]="";
1875         time_t t;
1876
1877         time(&t);
1878         ast_copy_string(date, ctime(&t), sizeof(date));
1879
1880         fprintf(f1, ";!\n");
1881         fprintf(f1, ";! Automatically generated configuration file\n");
1882         if (strcmp(configfile, fn))
1883                 fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
1884         else
1885                 fprintf(f1, ";! Filename: %s\n", configfile);
1886         fprintf(f1, ";! Generator: %s\n", generator);
1887         fprintf(f1, ";! Creation Date: %s", date);
1888         fprintf(f1, ";!\n");
1889 }
1890
1891 static void inclfile_destroy(void *obj)
1892 {
1893         const struct inclfile *o = obj;
1894
1895         ast_free(o->fname);
1896 }
1897
1898
1899 static struct inclfile *set_fn(char *fn, int fn_size, const char *file, const char *configfile, struct ao2_container *fileset)
1900 {
1901         struct inclfile lookup;
1902         struct inclfile *fi;
1903
1904         if (ast_strlen_zero(file)) {
1905                 if (configfile[0] == '/')
1906                         ast_copy_string(fn, configfile, fn_size);
1907                 else
1908                         snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
1909         } else if (file[0] == '/')
1910                 ast_copy_string(fn, file, fn_size);
1911         else
1912                 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
1913         lookup.fname = fn;
1914         fi = ao2_find(fileset, &lookup, OBJ_POINTER);
1915         if (fi) {
1916                 /* Found existing include file scratch pad. */
1917                 return fi;
1918         }
1919
1920         /* set up a file scratch pad */
1921         fi = ao2_alloc(sizeof(struct inclfile), inclfile_destroy);
1922         if (!fi) {
1923                 /* Scratch pad creation failed. */
1924                 return NULL;
1925         }
1926         fi->fname = ast_strdup(fn);
1927         if (!fi->fname) {
1928                 /* Scratch pad creation failed. */
1929                 ao2_ref(fi, -1);
1930                 return NULL;
1931         }
1932         fi->lineno = 1;
1933
1934         ao2_link(fileset, fi);
1935
1936         return fi;
1937 }
1938
1939 static int count_linefeeds(char *str)
1940 {
1941         int count = 0;
1942
1943         while (*str) {
1944                 if (*str =='\n')
1945                         count++;
1946                 str++;
1947         }
1948         return count;
1949 }
1950
1951 static int count_linefeeds_in_comments(struct ast_comment *x)
1952 {
1953         int count = 0;
1954
1955         while (x) {
1956                 count += count_linefeeds(x->cmt);
1957                 x = x->next;
1958         }
1959         return count;
1960 }
1961
1962 static void insert_leading_blank_lines(FILE *fp, struct inclfile *fi, struct ast_comment *precomments, int lineno)
1963 {
1964         int precomment_lines;
1965         int i;
1966
1967         if (!fi) {
1968                 /* No file scratch pad object so insert no blank lines. */
1969                 return;
1970         }
1971
1972         precomment_lines = count_linefeeds_in_comments(precomments);
1973
1974         /* I don't have to worry about those ;! comments, they are
1975            stored in the precomments, but not printed back out.
1976            I did have to make sure that comments following
1977            the ;! header comments were not also deleted in the process */
1978         if (lineno - precomment_lines - fi->lineno < 0) { /* insertions can mess up the line numbering and produce negative numbers that mess things up */
1979                 return;
1980         } else if (lineno == 0) {
1981                 /* Line replacements also mess things up */
1982                 return;
1983         } else if (lineno - precomment_lines - fi->lineno < 5) {
1984                 /* Only insert less than 5 blank lines; if anything more occurs,
1985                  * it's probably due to context deletion. */
1986                 for (i = fi->lineno; i < lineno - precomment_lines; i++) {
1987                         fprintf(fp, "\n");
1988                 }
1989         } else {
1990                 /* Deletion occurred - insert a single blank line, for separation of
1991                  * contexts. */
1992                 fprintf(fp, "\n");
1993         }
1994
1995         fi->lineno = lineno + 1; /* Advance the file lineno */
1996 }
1997
1998 int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
1999 {
2000         return ast_config_text_file_save(configfile, cfg, generator);
2001 }
2002
2003 int ast_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
2004 {
2005         FILE *f;
2006         char fn[PATH_MAX];
2007         struct ast_variable *var;
2008         struct ast_category *cat;
2009         struct ast_comment *cmt;
2010         struct ast_config_include *incl;
2011         int blanklines = 0;
2012         struct ao2_container *fileset;
2013         struct inclfile *fi;
2014
2015         fileset = ao2_container_alloc(1023, hash_string, hashtab_compare_strings);
2016         if (!fileset) {
2017                 /* Container creation failed. */
2018                 return -1;
2019         }
2020
2021         /* reset all the output flags, in case this isn't our first time saving this data */
2022         for (incl = cfg->includes; incl; incl = incl->next) {
2023                 incl->output = 0;
2024         }
2025
2026         /* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
2027            are all truncated to zero bytes and have that nice header*/
2028         for (incl = cfg->includes; incl; incl = incl->next) {
2029                 if (!incl->exec) { /* leave the execs alone -- we'll write out the #exec directives, but won't zero out the include files or exec files*/
2030                         /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
2031                         fi = set_fn(fn, sizeof(fn), incl->included_file, configfile, fileset);
2032                         f = fopen(fn, "w");
2033                         if (f) {
2034                                 gen_header(f, configfile, fn, generator);
2035                                 fclose(f); /* this should zero out the file */
2036                         } else {
2037                                 ast_debug(1, "Unable to open for writing: %s\n", fn);
2038                                 ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
2039                         }
2040                         if (fi) {
2041                                 ao2_ref(fi, -1);
2042                         }
2043                 }
2044         }
2045
2046         /* just set fn to absolute ver of configfile */
2047         fi = set_fn(fn, sizeof(fn), 0, configfile, fileset);
2048         if (
2049 #ifdef __CYGWIN__
2050                 (f = fopen(fn, "w+"))
2051 #else
2052                 (f = fopen(fn, "w"))
2053 #endif
2054                 ) {
2055                 ast_verb(2, "Saving '%s'\n", fn);
2056                 gen_header(f, configfile, fn, generator);
2057                 cat = cfg->root;
2058                 fclose(f);
2059                 if (fi) {
2060                         ao2_ref(fi, -1);
2061                 }
2062
2063                 /* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
2064                 /* since each var, cat, and associated comments can come from any file, we have to be
2065                    mobile, and open each file, print, and close it on an entry-by-entry basis */
2066
2067                 while (cat) {
2068                         fi = set_fn(fn, sizeof(fn), cat->file, configfile, fileset);
2069                         f = fopen(fn, "a");
2070                         if (!f) {
2071                                 ast_debug(1, "Unable to open for writing: %s\n", fn);
2072                                 ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
2073                                 if (fi) {
2074                                         ao2_ref(fi, -1);
2075                                 }
2076                                 ao2_ref(fileset, -1);
2077                                 return -1;
2078                         }
2079
2080                         /* dump any includes that happen before this category header */
2081                         for (incl=cfg->includes; incl; incl = incl->next) {
2082                                 if (strcmp(incl->include_location_file, cat->file) == 0){
2083                                         if (cat->lineno > incl->include_location_lineno && !incl->output) {
2084                                                 if (incl->exec)
2085                                                         fprintf(f,"#exec \"%s\"\n", incl->exec_file);
2086                                                 else
2087                                                         fprintf(f,"#include \"%s\"\n", incl->included_file);
2088                                                 incl->output = 1;
2089                                         }
2090                                 }
2091                         }
2092
2093                         insert_leading_blank_lines(f, fi, cat->precomments, cat->lineno);
2094                         /* Dump section with any appropriate comment */
2095                         for (cmt = cat->precomments; cmt; cmt=cmt->next) {
2096                                 char *cmtp = cmt->cmt;
2097                                 while (cmtp && *cmtp == ';' && *(cmtp+1) == '!') {
2098                                         char *cmtp2 = strchr(cmtp+1, '\n');
2099                                         if (cmtp2)
2100                                                 cmtp = cmtp2+1;
2101                                         else cmtp = 0;
2102                                 }
2103                                 if (cmtp)
2104                                         fprintf(f,"%s", cmtp);
2105                         }
2106                         fprintf(f, "[%s]", cat->name);
2107                         if (cat->ignored || !AST_LIST_EMPTY(&cat->template_instances)) {
2108                                 fprintf(f, "(");
2109                                 if (cat->ignored) {
2110                                         fprintf(f, "!");
2111                                 }
2112                                 if (cat->ignored && !AST_LIST_EMPTY(&cat->template_instances)) {
2113                                         fprintf(f, ",");
2114                                 }
2115                                 if (!AST_LIST_EMPTY(&cat->template_instances)) {
2116                                         struct ast_category_template_instance *x;
2117                                         AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
2118                                                 fprintf(f,"%s",x->name);
2119                                                 if (x != AST_LIST_LAST(&cat->template_instances))
2120                                                         fprintf(f,",");
2121                                         }
2122                                 }
2123                                 fprintf(f, ")");
2124                         }
2125                         for(cmt = cat->sameline; cmt; cmt=cmt->next)
2126                         {
2127                                 fprintf(f,"%s", cmt->cmt);
2128                         }
2129                         if (!cat->sameline)
2130                                 fprintf(f,"\n");
2131                         for (cmt = cat->trailing; cmt; cmt=cmt->next) {
2132                                 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
2133                                         fprintf(f,"%s", cmt->cmt);
2134                         }
2135                         fclose(f);
2136                         if (fi) {
2137                                 ao2_ref(fi, -1);
2138                         }
2139
2140                         var = cat->root;
2141                         while (var) {
2142                                 struct ast_category_template_instance *x;
2143                                 int found = 0;
2144                                 AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
2145                                         struct ast_variable *v;
2146                                         for (v = x->inst->root; v; v = v->next) {
2147                                                 if (!strcasecmp(var->name, v->name) && !strcmp(var->value, v->value)) {
2148                                                         found = 1;
2149                                                         break;
2150                                                 }
2151                                         }
2152                                         if (found)
2153                                                 break;
2154                                 }
2155                                 if (found) {
2156                                         var = var->next;
2157                                         continue;
2158                                 }
2159                                 fi = set_fn(fn, sizeof(fn), var->file, configfile, fileset);
2160                                 f = fopen(fn, "a");
2161                                 if (!f) {
2162                                         ast_debug(1, "Unable to open for writing: %s\n", fn);
2163                                         ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
2164                                         if (fi) {
2165                                                 ao2_ref(fi, -1);
2166                                         }
2167                                         ao2_ref(fileset, -1);
2168                                         return -1;
2169                                 }
2170
2171                                 /* dump any includes that happen before this category header */
2172                                 for (incl=cfg->includes; incl; incl = incl->next) {
2173                                         if (strcmp(incl->include_location_file, var->file) == 0){
2174                                                 if (var->lineno > incl->include_location_lineno && !incl->output) {
2175                                                         if (incl->exec)
2176                                                                 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
2177                                                         else
2178                                                                 fprintf(f,"#include \"%s\"\n", incl->included_file);
2179                                                         incl->output = 1;
2180                                                 }
2181                                         }
2182                                 }
2183
2184                                 insert_leading_blank_lines(f, fi, var->precomments, var->lineno);
2185                                 for (cmt = var->precomments; cmt; cmt=cmt->next) {
2186                                         if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
2187                                                 fprintf(f,"%s", cmt->cmt);
2188                                 }
2189                                 if (var->sameline)
2190                                         fprintf(f, "%s %s %s  %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
2191                                 else
2192                                         fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
2193                                 for (cmt = var->trailing; cmt; cmt=cmt->next) {
2194                                         if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
2195                                                 fprintf(f,"%s", cmt->cmt);
2196                                 }
2197                                 if (var->blanklines) {
2198                                         blanklines = var->blanklines;
2199                                         while (blanklines--)
2200                                                 fprintf(f, "\n");
2201                                 }
2202
2203                                 fclose(f);
2204                                 if (fi) {
2205                                         ao2_ref(fi, -1);
2206                                 }
2207
2208                                 var = var->next;
2209                         }
2210                         cat = cat->next;
2211                 }
2212                 if (!option_debug) {
2213                         ast_verb(2, "Saving '%s': saved\n", fn);
2214                 }
2215         } else {
2216                 ast_debug(1, "Unable to open for writing: %s\n", fn);
2217                 ast_verb(2, "Unable to write '%s' (%s)\n", fn, strerror(errno));
2218                 if (fi) {
2219                         ao2_ref(fi, -1);
2220                 }
2221                 ao2_ref(fileset, -1);
2222                 return -1;
2223         }
2224
2225         /* Now, for files with trailing #include/#exec statements,
2226            we have to make sure every entry is output */
2227         for (incl=cfg->includes; incl; incl = incl->next) {
2228                 if (!incl->output) {
2229                         /* open the respective file */
2230                         fi = set_fn(fn, sizeof(fn), incl->include_location_file, configfile, fileset);
2231                         f = fopen(fn, "a");
2232                         if (!f) {
2233                                 ast_debug(1, "Unable to open for writing: %s\n", fn);
2234                                 ast_verb(2, "Unable to write %s (%s)\n", fn, strerror(errno));
2235                                 if (fi) {
2236                                         ao2_ref(fi, -1);
2237                                 }
2238                                 ao2_ref(fileset, -1);
2239                                 return -1;
2240                         }
2241
2242                         /* output the respective include */
2243                         if (incl->exec)
2244                                 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
2245                         else
2246                                 fprintf(f,"#include \"%s\"\n", incl->included_file);
2247                         fclose(f);
2248                         incl->output = 1;
2249                         if (fi) {
2250                                 ao2_ref(fi, -1);
2251                         }
2252                 }
2253         }
2254         ao2_ref(fileset, -1); /* this should destroy the hash container */
2255
2256         return 0;
2257 }
2258
2259 static void clear_config_maps(void)
2260 {
2261         struct ast_config_map *map;
2262
2263         SCOPED_MUTEX(lock, &config_lock);
2264
2265         while (config_maps) {
2266                 map = config_maps;
2267                 config_maps = config_maps->next;
2268                 ast_free(map);
2269         }
2270 }
2271
2272 #ifdef TEST_FRAMEWORK
2273 int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
2274 #else
2275 static int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
2276 #endif
2277 {
2278         struct ast_config_map *map;
2279         char *dst;
2280         int length;
2281
2282         length = sizeof(*map);
2283         length += strlen(name) + 1;
2284         length += strlen(driver) + 1;
2285         length += strlen(database) + 1;
2286         if (table)
2287                 length += strlen(table) + 1;
2288
2289         if (!(map = ast_calloc(1, length)))
2290                 return -1;
2291
2292         dst = map->stuff;       /* writable space starts here */
2293         map->name = strcpy(dst, name);
2294         dst += strlen(dst) + 1;
2295         map->driver = strcpy(dst, driver);
2296         dst += strlen(dst) + 1;
2297         map->database = strcpy(dst, database);
2298         if (table) {
2299                 dst += strlen(dst) + 1;
2300                 map->table = strcpy(dst, table);
2301         }
2302         map->priority = priority;
2303         map->next = config_maps;
2304         config_maps = map;
2305
2306         ast_verb(2, "Binding %s to %s/%s/%s\n", map->name, map->driver, map->database, map->table ? map->table : map->name);
2307
2308         return 0;
2309 }
2310
2311 int read_config_maps(void)
2312 {
2313         struct ast_config *config, *configtmp;
2314         struct ast_variable *v;
2315         char *driver, *table, *database, *textpri, *stringp, *tmp;
2316         struct ast_flags flags = { CONFIG_FLAG_NOREALTIME };
2317         int pri;
2318
2319         clear_config_maps();
2320
2321         configtmp = ast_config_new();
2322         if (!configtmp) {
2323                 ast_log(LOG_ERROR, "Unable to allocate memory for new config\n");
2324                 return -1;
2325         }
2326         config = ast_config_internal_load(extconfig_conf, configtmp, flags, "", "extconfig");
2327         if (config == CONFIG_STATUS_FILEINVALID) {
2328                 return -1;
2329         } else if (!config) {
2330                 ast_config_destroy(configtmp);
2331                 return 0;
2332         }
2333
2334         for (v = ast_variable_browse(config, "settings"); v; v = v->next) {
2335                 char buf[512];
2336                 ast_copy_string(buf, v->value, sizeof(buf));
2337                 stringp = buf;
2338                 driver = strsep(&stringp, ",");
2339
2340                 if ((tmp = strchr(stringp, '\"')))
2341                         stringp = tmp;
2342
2343                 /* check if the database text starts with a double quote */
2344                 if (*stringp == '"') {
2345                         stringp++;
2346                         database = strsep(&stringp, "\"");
2347                         strsep(&stringp, ",");
2348                 } else {
2349                         /* apparently this text has no quotes */
2350                         database = strsep(&stringp, ",");
2351                 }
2352
2353                 table = strsep(&stringp, ",");
2354                 textpri = strsep(&stringp, ",");
2355                 if (!textpri || !(pri = atoi(textpri))) {
2356                         pri = 1;
2357                 }
2358
2359                 if (!strcmp(v->name, extconfig_conf)) {
2360                         ast_log(LOG_WARNING, "Cannot bind '%s'!\n", extconfig_conf);
2361                         continue;
2362                 }
2363
2364                 if (!strcmp(v->name, "asterisk.conf")) {
2365                         ast_log(LOG_WARNING, "Cannot bind 'asterisk.conf'!\n");
2366                         continue;
2367                 }
2368
2369                 if (!strcmp(v->name, "logger.conf")) {
2370                         ast_log(LOG_WARNING, "Cannot bind 'logger.conf'!\n");
2371                         continue;
2372                 }
2373
2374                 if (!driver || !database)
2375                         continue;
2376                 if (!strcasecmp(v->name, "sipfriends")) {
2377                         ast_log(LOG_WARNING, "The 'sipfriends' table is obsolete, update your config to use sippeers instead.\n");
2378                         ast_realtime_append_mapping("sippeers", driver, database, table ? table : "sipfriends", pri);
2379                 } else if (!strcasecmp(v->name, "iaxfriends")) {
2380                         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");
2381                         ast_realtime_append_mapping("iaxusers", driver, database, table ? table : "iaxfriends", pri);
2382                         ast_realtime_append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends", pri);
2383                 } else
2384                         ast_realtime_append_mapping(v->name, driver, database, table, pri);
2385         }
2386
2387         ast_config_destroy(config);
2388         return 0;
2389 }
2390
2391 int ast_config_engine_register(struct ast_config_engine *new)
2392 {
2393         struct ast_config_engine *ptr;
2394
2395         SCOPED_MUTEX(lock, &config_lock);
2396
2397         if (!config_engine_list) {
2398                 config_engine_list = new;
2399         } else {
2400                 for (ptr = config_engine_list; ptr->next; ptr=ptr->next);
2401                 ptr->next = new;
2402         }
2403
2404         ast_log(LOG_NOTICE,"Registered Config Engine %s\n", new->name);
2405
2406         return 1;
2407 }
2408
2409 int ast_config_engine_deregister(struct ast_config_engine *del)
2410 {
2411         struct ast_config_engine *ptr, *last=NULL;
2412
2413         SCOPED_MUTEX(lock, &config_lock);
2414
2415         for (ptr = config_engine_list; ptr; ptr=ptr->next) {
2416                 if (ptr == del) {
2417                         if (last)
2418                                 last->next = ptr->next;
2419                         else
2420                                 config_engine_list = ptr->next;
2421                         break;
2422                 }
2423                 last = ptr;
2424         }
2425
2426         return 0;
2427 }
2428
2429 int ast_realtime_is_mapping_defined(const char *family)
2430 {
2431         struct ast_config_map *map;
2432         SCOPED_MUTEX(lock, &config_lock);
2433
2434         for (map = config_maps; map; map = map->next) {
2435                 if (!strcasecmp(family, map->name)) {
2436                         return 1;
2437                 }
2438         }
2439
2440         return 0;
2441 }
2442
2443 /*! \brief Find realtime engine for realtime family */
2444 static struct ast_config_engine *find_engine(const char *family, int priority, char *database, int dbsiz, char *table, int tabsiz)
2445 {
2446         struct ast_config_engine *eng, *ret = NULL;
2447         struct ast_config_map *map;
2448
2449         SCOPED_MUTEX(lock, &config_lock);
2450
2451         for (map = config_maps; map; map = map->next) {
2452                 if (!strcasecmp(family, map->name) && (priority == map->priority)) {
2453                         if (database)
2454                                 ast_copy_string(database, map->database, dbsiz);
2455                         if (table)
2456                                 ast_copy_string(table, map->table ? map->table : family, tabsiz);
2457                         break;
2458                 }
2459         }
2460
2461         /* Check if the required driver (engine) exist */
2462         if (map) {
2463                 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
2464                         if (!strcasecmp(eng->name, map->driver))
2465                                 ret = eng;
2466                 }
2467         }
2468
2469         /* if we found a mapping, but the engine is not available, then issue a warning */
2470         if (map && !ret)
2471                 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
2472
2473         return ret;
2474 }
2475
2476 static struct ast_config_engine text_file_engine = {
2477         .name = "text",
2478         .load_func = config_text_file_load,
2479 };
2480
2481 struct ast_config *ast_config_copy(const struct ast_config *old)
2482 {
2483         struct ast_config *new_config = ast_config_new();
2484         struct ast_category *cat_iter;
2485
2486         if (!new_config) {
2487                 return NULL;
2488         }
2489
2490         for (cat_iter = old->root; cat_iter; cat_iter = cat_iter->next) {
2491                 struct ast_category *new_cat =
2492                         ast_category_new(cat_iter->name, cat_iter->file, cat_iter->lineno);
2493                 if (!new_cat) {
2494                         goto fail;
2495                 }
2496                 ast_category_append(new_config, new_cat);
2497                 if (cat_iter->root) {
2498                         new_cat->root = ast_variables_dup(cat_iter->root);
2499                         if (!new_cat->root) {
2500                                 goto fail;
2501                         }
2502                         new_cat->last = cat_iter->last;
2503                 }
2504         }
2505
2506         return new_config;
2507
2508 fail:
2509         ast_config_destroy(new_config);
2510         return NULL;
2511 }
2512
2513
2514 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)
2515 {
2516         char db[256];
2517         char table[256];
2518         struct ast_config_engine *loader = &text_file_engine;
2519         struct ast_config *result;
2520
2521         /* The config file itself bumps include_level by 1 */
2522         if (cfg->max_include_level > 0 && cfg->include_level == cfg->max_include_level + 1) {
2523                 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
2524                 return NULL;
2525         }
2526
2527         cfg->include_level++;
2528
2529         if (!ast_test_flag(&flags, CONFIG_FLAG_NOREALTIME) && config_engine_list) {
2530                 struct ast_config_engine *eng;
2531
2532                 eng = find_engine(filename, 1, db, sizeof(db), table, sizeof(table));
2533
2534
2535                 if (eng && eng->load_func) {
2536                         loader = eng;
2537                 } else {
2538                         eng = find_engine("global", 1, db, sizeof(db), table, sizeof(table));
2539                         if (eng && eng->load_func)
2540                                 loader = eng;
2541                 }
2542         }
2543
2544         result = loader->load_func(db, table, filename, cfg, flags, suggested_include_file, who_asked);
2545
2546         if (result && result != CONFIG_STATUS_FILEINVALID && result != CONFIG_STATUS_FILEUNCHANGED) {
2547                 result->include_level--;
2548                 config_hook_exec(filename, who_asked, result);
2549         } else if (result != CONFIG_STATUS_FILEINVALID) {
2550                 cfg->include_level--;
2551         }
2552
2553         return result;
2554 }
2555
2556 struct ast_config *ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
2557 {
2558         struct ast_config *cfg;
2559         struct ast_config *result;
2560
2561         cfg = ast_config_new();
2562         if (!cfg)
2563                 return NULL;
2564
2565         result = ast_config_internal_load(filename, cfg, flags, "", who_asked);
2566         if (!result || result == CONFIG_STATUS_FILEUNCHANGED || result == CONFIG_STATUS_FILEINVALID)
2567                 ast_config_destroy(cfg);
2568
2569         return result;
2570 }
2571
2572 #define realtime_arguments_to_fields(ap) realtime_arguments_to_fields2(ap, 0)
2573
2574 static struct ast_variable *realtime_arguments_to_fields2(va_list ap, int skip)
2575 {
2576         struct ast_variable *first, *fields = NULL;
2577         const char *newparam;
2578         const char *newval;
2579
2580         /*
2581          * Previously we would do:
2582          *
2583          *     va_start(ap, last);
2584          *     x = realtime_arguments_to_fields(ap);
2585          *     y = realtime_arguments_to_fields(ap);
2586          *     va_end(ap);
2587          *
2588          * While this works on generic amd64 machines (2014), it doesn't on the
2589          * raspberry PI. The va_arg() manpage says:
2590          *
2591          *     If ap is passed to a function that uses va_arg(ap,type) then
2592          *     the value of ap is undefined after the return of that function.
2593          *
2594          * On the raspberry, ap seems to get reset after the call: the contents
2595          * of y would be equal to the contents of x.
2596          *
2597          * So, instead we allow the caller to skip past earlier argument sets
2598          * using the skip parameter:
2599          *
2600          *     va_start(ap, last);
2601          *     x = realtime_arguments_to_fields(ap);
2602          *     va_end(ap);
2603          *     va_start(ap, last);
2604          *     y = realtime_arguments_to_fields2(ap, 1);
2605          *     va_end(ap);
2606          */
2607         while (skip--) {
2608                 /* There must be at least one argument. */
2609                 newparam = va_arg(ap, const char *);
2610                 newval = va_arg(ap, const char *);
2611                 while ((newparam = va_arg(ap, const char *))) {
2612                         newval = va_arg(ap, const char *);
2613                 }
2614         }
2615
2616         /* Load up the first vars. */
2617         newparam = va_arg(ap, const char *);
2618         newval = va_arg(ap, const char *);
2619
2620         if (!(first = ast_variable_new(newparam, newval, ""))) {
2621                 return NULL;
2622         }
2623
2624         while ((newparam = va_arg(ap, const char *))) {
2625                 struct ast_variable *field;
2626
2627                 newval = va_arg(ap, const char *);
2628                 if (!(field = ast_variable_new(newparam, newval, ""))) {
2629                         ast_variables_destroy(fields);
2630                         ast_variables_destroy(first);
2631                         return NULL;
2632                 }
2633
2634                 field->next = fields;
2635                 fields = field;
2636         }
2637
2638         first->next = fields;
2639         fields = first;
2640
2641         return fields;
2642 }
2643
2644 struct ast_variable *ast_load_realtime_all_fields(const char *family, const struct ast_variable *fields)
2645 {
2646         struct ast_config_engine *eng;
2647         char db[256];
2648         char table[256];
2649         struct ast_variable *res=NULL;
2650         int i;
2651
2652         for (i = 1; ; i++) {
2653                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2654                         if (eng->realtime_func && (res = eng->realtime_func(db, table, fields))) {
2655                                 return res;
2656                         }
2657                 } else {
2658                         return NULL;
2659                 }
2660         }
2661
2662         return res;
2663 }
2664
2665 struct ast_variable *ast_load_realtime_all(const char *family, ...)
2666 {
2667         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2668         struct ast_variable *res = NULL;
2669         va_list ap;
2670
2671         va_start(ap, family);
2672         fields = realtime_arguments_to_fields(ap);
2673         va_end(ap);
2674
2675         if (fields) {
2676                 res = ast_load_realtime_all_fields(family, fields);
2677         }
2678
2679         return res;
2680 }
2681
2682 struct ast_variable *ast_load_realtime_fields(const char *family, const struct ast_variable *fields)
2683 {
2684         struct ast_variable *res;
2685         struct ast_variable *cur;
2686         struct ast_variable **prev;
2687
2688         res = ast_load_realtime_all_fields(family, fields);
2689
2690         /* Filter the list. */
2691         prev = &res;
2692         cur = res;
2693         while (cur) {
2694                 if (ast_strlen_zero(cur->value)) {
2695                         /* Eliminate empty entries */
2696                         struct ast_variable *next;
2697
2698                         next = cur->next;
2699                         *prev = next;
2700                         ast_variable_destroy(cur);
2701                         cur = next;
2702                 } else {
2703                         /* Make blank entries empty and keep them. */
2704                         if (cur->value[0] == ' ' && cur->value[1] == '\0') {
2705                                 char *vptr = (char *) cur->value;
2706
2707                                 vptr[0] = '\0';
2708                         }
2709
2710                         prev = &cur->next;
2711                         cur = cur->next;
2712                 }
2713         }
2714         return res;
2715 }
2716
2717 struct ast_variable *ast_load_realtime(const char *family, ...)
2718 {
2719         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2720         va_list ap;
2721
2722         va_start(ap, family);
2723         fields = realtime_arguments_to_fields(ap);
2724         va_end(ap);
2725
2726         if (!fields) {
2727                 return NULL;
2728         }
2729
2730         return ast_load_realtime_fields(family, fields);
2731 }
2732
2733 /*! \brief Check if realtime engine is configured for family */
2734 int ast_check_realtime(const char *family)
2735 {
2736         struct ast_config_engine *eng;
2737         if (!ast_realtime_enabled()) {
2738                 return 0;       /* There are no engines at all so fail early */
2739         }
2740
2741         eng = find_engine(family, 1, NULL, 0, NULL, 0);
2742         if (eng)
2743                 return 1;
2744         return 0;
2745 }
2746
2747 /*! \brief Check if there's any realtime engines loaded */
2748 int ast_realtime_enabled(void)
2749 {
2750         return config_maps ? 1 : 0;
2751 }
2752
2753 int ast_realtime_require_field(const char *family, ...)
2754 {
2755         struct ast_config_engine *eng;
2756         char db[256];
2757         char table[256];
2758         va_list ap;
2759         int res = -1, i;
2760
2761         va_start(ap, family);
2762         for (i = 1; ; i++) {
2763                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2764                         /* If the require succeeds, it returns 0. */
2765                         if (eng->require_func && !(res = eng->require_func(db, table, ap))) {
2766                                 break;
2767                         }
2768                 } else {
2769                         break;
2770                 }
2771         }
2772         va_end(ap);
2773
2774         return res;
2775 }
2776
2777 int ast_unload_realtime(const char *family)
2778 {
2779         struct ast_config_engine *eng;
2780         char db[256];
2781         char table[256];
2782         int res = -1, i;
2783
2784         for (i = 1; ; i++) {
2785                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2786                         if (eng->unload_func) {
2787                                 /* Do this for ALL engines */
2788                                 res = eng->unload_func(db, table);
2789                         }
2790                 } else {
2791                         break;
2792                 }
2793         }
2794         return res;
2795 }
2796
2797 struct ast_config *ast_load_realtime_multientry_fields(const char *family, const struct ast_variable *fields)
2798 {
2799         struct ast_config_engine *eng;
2800         char db[256];
2801         char table[256];
2802         struct ast_config *res = NULL;
2803         int i;
2804
2805         for (i = 1; ; i++) {
2806                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2807                         if (eng->realtime_multi_func && (res = eng->realtime_multi_func(db, table, fields))) {
2808                                 /* If we were returned an empty cfg, destroy it and return NULL */
2809                                 if (!res->root) {
2810                                         ast_config_destroy(res);
2811                                         res = NULL;
2812                                 }
2813                                 break;
2814                         }
2815                 } else {
2816                         break;
2817                 }
2818         }
2819
2820         return res;
2821 }
2822
2823 struct ast_config *ast_load_realtime_multientry(const char *family, ...)
2824 {
2825         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2826         va_list ap;
2827
2828         va_start(ap, family);
2829         fields = realtime_arguments_to_fields(ap);
2830         va_end(ap);
2831
2832         if (!fields) {
2833                 return NULL;
2834         }
2835
2836         return ast_load_realtime_multientry_fields(family, fields);
2837 }
2838
2839 int ast_update_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
2840 {
2841         struct ast_config_engine *eng;
2842         int res = -1, i;
2843         char db[256];
2844         char table[256];
2845
2846         for (i = 1; ; i++) {
2847                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2848                         /* If the update succeeds, it returns 0. */
2849                         if (eng->update_func && !(res = eng->update_func(db, table, keyfield, lookup, fields))) {
2850                                 break;
2851                         }
2852                 } else {
2853                         break;
2854                 }
2855         }
2856
2857         return res;
2858 }
2859
2860 int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
2861 {
2862         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2863         va_list ap;
2864
2865         va_start(ap, lookup);
2866         fields = realtime_arguments_to_fields(ap);
2867         va_end(ap);
2868
2869         if (!fields) {
2870                 return -1;
2871         }
2872
2873         return ast_update_realtime_fields(family, keyfield, lookup, fields);
2874 }
2875
2876 int ast_update2_realtime_fields(const char *family, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
2877 {
2878         struct ast_config_engine *eng;
2879         int res = -1, i;
2880         char db[256];
2881         char table[256];
2882
2883         for (i = 1; ; i++) {
2884                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2885                         if (eng->update2_func && !(res = eng->update2_func(db, table, lookup_fields, update_fields))) {
2886                                 break;
2887                         }
2888                 } else {
2889                         break;
2890                 }
2891         }
2892
2893         return res;
2894 }
2895
2896 int ast_update2_realtime(const char *family, ...)
2897 {
2898         RAII_VAR(struct ast_variable *, lookup_fields, NULL, ast_variables_destroy);
2899         RAII_VAR(struct ast_variable *, update_fields, NULL, ast_variables_destroy);
2900         va_list ap;
2901
2902         va_start(ap, family);
2903         /* XXX: If we wanted to pass no lookup fields (select all), we'd be
2904          * out of luck. realtime_arguments_to_fields expects at least one key
2905          * value pair. */
2906         lookup_fields = realtime_arguments_to_fields(ap);
2907         va_end(ap);
2908
2909         va_start(ap, family);
2910         update_fields = realtime_arguments_to_fields2(ap, 1);
2911         va_end(ap);
2912
2913         if (!lookup_fields || !update_fields) {
2914                 return -1;
2915         }
2916
2917         return ast_update2_realtime_fields(family, lookup_fields, update_fields);
2918 }
2919
2920 int ast_store_realtime_fields(const char *family, const struct ast_variable *fields)
2921 {
2922         struct ast_config_engine *eng;
2923         int res = -1, i;
2924         char db[256];
2925         char table[256];
2926
2927         for (i = 1; ; i++) {
2928                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2929                         /* If the store succeeds, it returns 0. */
2930                         if (eng->store_func && !(res = eng->store_func(db, table, fields))) {
2931                                 break;
2932                         }
2933                 } else {
2934                         break;
2935                 }
2936         }
2937
2938         return res;
2939 }
2940
2941 int ast_store_realtime(const char *family, ...)
2942 {
2943         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2944         va_list ap;
2945
2946         va_start(ap, family);
2947         fields = realtime_arguments_to_fields(ap);
2948         va_end(ap);
2949
2950         if (!fields) {
2951                 return -1;
2952         }
2953
2954         return ast_store_realtime_fields(family, fields);
2955 }
2956
2957 int ast_destroy_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
2958 {
2959         struct ast_config_engine *eng;
2960         int res = -1, i;
2961         char db[256];
2962         char table[256];
2963
2964         for (i = 1; ; i++) {
2965                 if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
2966                         if (eng->destroy_func && !(res = eng->destroy_func(db, table, keyfield, lookup, fields))) {
2967                                 break;
2968                         }
2969                 } else {
2970                         break;
2971                 }
2972         }
2973
2974         return res;
2975 }
2976
2977 int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...)
2978 {
2979         RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
2980         va_list ap;
2981
2982         va_start(ap, lookup);
2983         fields = realtime_arguments_to_fields(ap);
2984         va_end(ap);
2985
2986         if (!fields) {
2987                 return -1;
2988         }
2989
2990         return ast_destroy_realtime_fields(family, keyfield, lookup, fields);
2991 }
2992
2993 char *ast_realtime_decode_chunk(char *chunk)
2994 {
2995         char *orig = chunk;
2996         for (; *chunk; chunk++) {
2997                 if (*chunk == '^' && strchr("0123456789ABCDEFabcdef", chunk[1]) && strchr("0123456789ABCDEFabcdef", chunk[2])) {
2998                         sscanf(chunk + 1, "%02hhX", chunk);
2999                         memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
3000                 }
3001         }
3002         return orig;
3003 }
3004
3005 char *ast_realtime_encode_chunk(struct ast_str **dest, ssize_t maxlen, const char *chunk)
3006 {
3007         if (!strchr(chunk, ';') && !strchr(chunk, '^')) {
3008                 ast_str_set(dest, maxlen, "%s", chunk);
3009         } else {
3010                 ast_str_reset(*dest);
3011                 for (; *chunk; chunk++) {
3012                         if (strchr(";^", *chunk)) {
3013                                 ast_str_append(dest, maxlen, "^%02hhX", *chunk);
3014                         } else {
3015                                 ast_str_append(dest, maxlen, "%c", *chunk);
3016                         }
3017                 }
3018         }
3019         return ast_str_buffer(*dest);
3020 }
3021
3022 /*! \brief Helper function to parse arguments
3023  * See documentation in config.h
3024  */
3025 int ast_parse_arg(const char *arg, enum ast_parse_flags flags,
3026         void *p_result, ...)
3027 {
3028         va_list ap;
3029         int error = 0;
3030
3031         va_start(ap, p_result);
3032         switch (flags & PARSE_TYPE) {
3033         case PARSE_INT32:
3034         {
3035                 long int x = 0;
3036                 int32_t *result = p_result;
3037                 int32_t def = result ? *result : 0, high = INT32_MAX, low = INT32_MIN;
3038                 char *endptr = NULL;
3039
3040                 /* optional arguments: default value and/or (low, high) */
3041                 if (flags & PARSE_DEFAULT) {
3042                         def = va_arg(ap, int32_t);
3043                 }
3044                 if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
3045                         low = va_arg(ap, int32_t);
3046                         high = va_arg(ap, int32_t);
3047                 }
3048                 if (ast_strlen_zero(arg)) {
3049                         error = 1;
3050                         goto int32_done;
3051                 }
3052                 errno = 0;
3053                 x = strtol(arg, &endptr, 0);
3054                 if (*endptr || errno || x < INT32_MIN || x > INT32_MAX) {
3055                         /* Parse error, or type out of int32_t bounds */
3056                         error = 1;
3057                         goto int32_done;
3058                 }
3059                 error = (x < low) || (x > high);
3060                 if (flags & PARSE_RANGE_DEFAULTS) {
3061                         if (x < low) {
3062                                 def = low;
3063                         } else if (x > high) {
3064                                 def = high;
3065                         }
3066                 }
3067                 if (flags & PARSE_OUT_RANGE) {
3068                         error = !error;
3069                 }
3070 int32_done:
3071                 if (result) {
3072                         *result  = error ? def : x;
3073                 }
3074
3075                 ast_debug(3, "extract int from [%s] in [%d, %d] gives [%ld](%d)\n",
3076                                 arg, low, high, result ? *result : x, error);
3077                 break;
3078         }
3079
3080         case PARSE_UINT32:
3081         {
3082                 unsigned long int x = 0;
3083                 uint32_t *result = p_result;
3084                 uint32_t def = result ? *result : 0, low = 0, high = UINT32_MAX;
3085                 char *endptr = NULL;
3086
3087                 /* optional argument: first default value, then range */
3088                 if (flags & PARSE_DEFAULT) {
3089                         def = va_arg(ap, uint32_t);
3090                 }
3091                 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
3092                         /* range requested, update bounds */
3093                         low = va_arg(ap, uint32_t);
3094                         high = va_arg(ap, uint32_t);
3095                 }
3096
3097                 if (ast_strlen_zero(arg)) {
3098                         error = 1;
3099                         goto uint32_done;
3100                 }
3101                 /* strtoul will happilly and silently negate negative numbers */
3102                 arg = ast_skip_blanks(arg);
3103                 if (*arg == '-') {
3104                         error = 1;
3105                         goto uint32_done;
3106                 }
3107                 errno = 0;
3108                 x = strtoul(arg, &endptr, 0);
3109                 if (*endptr || errno || x > UINT32_MAX) {
3110                         error = 1;
3111                         goto uint32_done;
3112                 }
3113                 error = (x < low) || (x > high);
3114                 if (flags & PARSE_RANGE_DEFAULTS) {
3115                         if (x < low) {
3116                                 def = low;
3117                         } else if (x > high) {
3118                                 def = high;
3119                         }
3120                 }
3121                 if (flags & PARSE_OUT_RANGE) {
3122                         error = !error;
3123                 }
3124 uint32_done:
3125                 if (result) {
3126                         *result  = error ? def : x;
3127                 }
3128                 ast_debug(3, "extract uint from [%s] in [%u, %u] gives [%lu](%d)\n",
3129                                 arg, low, high, result ? *result : x, error);
3130                 break;
3131         }
3132
3133         case PARSE_DOUBLE:
3134         {
3135                 double *result = p_result;
3136                 double x = 0, def = result ? *result : 0, low = -HUGE_VAL, high = HUGE_VAL;
3137                 char *endptr = NULL;
3138
3139                 /* optional argument: first default value, then range */
3140                 if (flags & PARSE_DEFAULT) {
3141                         def = va_arg(ap, double);
3142                 }
3143                 if (flags & (PARSE_IN_RANGE | PARSE_OUT_RANGE)) {
3144                         /* range requested, update bounds */
3145                         low = va_arg(ap, double);
3146                         high = va_arg(ap, double);
3147                 }
3148                 if (ast_strlen_zero(arg)) {
3149                         error = 1;
3150                         goto double_done;
3151                 }
3152                 errno = 0;
3153                 x = strtod(arg, &endptr);
3154                 if (*endptr || errno == ERANGE) {
3155                         error = 1;
3156                         goto double_done;
3157                 }
3158                 error = (x < low) || (x > high);
3159                 if (flags & PARSE_OUT_RANGE) {
3160                         error = !error;
3161                 }
3162 double_done:
3163                 if (result) {
3164                         *result = error ? def : x;
3165                 }
3166                 ast_debug(3, "extract double from [%s] in [%f, %f] gives [%f](%d)\n",
3167                                 arg, low, high, result ? *result : x, error);
3168                 break;
3169         }
3170         case PARSE_ADDR:
3171             {
3172                 struct ast_sockaddr *addr = (struct ast_sockaddr *)p_result;
3173
3174                 if (!ast_sockaddr_parse(addr, arg, flags & PARSE_PORT_MASK)) {
3175                         error = 1;
3176                 }
3177
3178                 ast_debug(3, "extract addr from %s gives %s(%d)\n",
3179                           arg, ast_sockaddr_stringify(addr), error);
3180
3181                 break;
3182             }
3183         case PARSE_INADDR:      /* TODO Remove this (use PARSE_ADDR instead). */
3184             {
3185                 char *port, *buf;
3186                 struct sockaddr_in _sa_buf;     /* buffer for the result */
3187                 struct sockaddr_in *sa = p_result ?
3188                         (struct sockaddr_in *)p_result : &_sa_buf;
3189                 /* default is either the supplied value or the result itself */
3190                 struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
3191                         va_arg(ap, struct sockaddr_in *) : sa;
3192                 struct hostent *hp;
3193                 struct ast_hostent ahp;
3194
3195                 memset(&_sa_buf, '\0', sizeof(_sa_buf)); /* clear buffer */
3196                 /* duplicate the string to strip away the :port */
3197                 port = ast_strdupa(arg);
3198                 buf = strsep(&port, ":");
3199                 sa->sin_family = AF_INET;       /* assign family */
3200                 /*
3201                  * honor the ports flag setting, assign default value
3202                  * in case of errors or field unset.
3203                  */
3204                 flags &= PARSE_PORT_MASK; /* the only flags left to process */
3205                 if (port) {
3206                         if (flags == PARSE_PORT_FORBID) {
3207                                 error = 1;      /* port was forbidden */
3208                                 sa->sin_port = def->sin_port;
3209                         } else if (flags == PARSE_PORT_IGNORE)
3210                                 sa->sin_port = def->sin_port;
3211                         else /* accept or require */
3212                                 sa->sin_port = htons(strtol(port, NULL, 0));
3213                 } else {
3214                         sa->sin_port = def->sin_port;
3215                         if (flags == PARSE_PORT_REQUIRE)
3216                                 error = 1;
3217                 }
3218                 /* Now deal with host part, even if we have errors before. */
3219                 hp = ast_gethostbyname(buf, &ahp);
3220                 if (hp) /* resolved successfully */
3221                         memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
3222                 else {
3223                         error = 1;
3224                         sa->sin_addr = def->sin_addr;
3225                 }
3226                 ast_debug(3,
3227                         "extract inaddr from [%s] gives [%s:%d](%d)\n",
3228                         arg, ast_inet_ntoa(sa->sin_addr),
3229                         ntohs(sa->sin_port), error);
3230                 break;
3231             }
3232         }
3233         va_end(ap);
3234         return error;
3235 }
3236
3237 static char *handle_cli_core_show_config_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3238 {
3239         struct ast_config_engine *eng;
3240         struct ast_config_map *map;
3241
3242         switch (cmd) {
3243         case CLI_INIT:
3244                 e->command = "core show config mappings";
3245                 e->usage =
3246                         "Usage: core show config mappings\n"
3247                         "       Shows the filenames to config engines.\n";
3248                 return NULL;
3249         case CLI_GENERATE:
3250                 return NULL;
3251         }
3252
3253         {
3254                 SCOPED_MUTEX(lock, &config_lock);
3255
3256                 if (!config_engine_list) {
3257                         ast_cli(a->fd, "No config mappings found.\n");
3258                 } else {
3259                         for (eng = config_engine_list; eng; eng = eng->next) {
3260                                 ast_cli(a->fd, "Config Engine: %s\n", eng->name);
3261                                 for (map = config_maps; map; map = map->next) {
3262                                         if (!strcasecmp(map->driver, eng->name)) {
3263                                                 ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
3264                                                                 map->table ? map->table : map->name);
3265                                         }
3266                                 }
3267                         }
3268                 }
3269         }
3270
3271         return CLI_SUCCESS;
3272 }
3273
3274 static char *handle_cli_config_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3275 {
3276         struct cache_file_mtime *cfmtime;
3277         char *prev = "", *completion_value = NULL;
3278         int wordlen, which = 0;
3279
3280         switch (cmd) {
3281         case CLI_INIT:
3282                 e->command = "config reload";
3283                 e->usage =
3284                         "Usage: config reload <filename.conf>\n"
3285                         "   Reloads all modules that reference <filename.conf>\n";
3286                 return NULL;
3287         case CLI_GENERATE:
3288                 if (a->pos > 2) {
3289                         return NULL;
3290                 }
3291
3292                 wordlen = strlen(a->word);
3293
3294                 AST_LIST_LOCK(&cfmtime_head);
3295                 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
3296                         /* Skip duplicates - this only works because the list is sorted by filename */
3297                         if (strcmp(cfmtime->filename, prev) == 0) {
3298                                 continue;
3299                         }
3300
3301                         /* Core configs cannot be reloaded */
3302                         if (ast_strlen_zero(cfmtime->who_asked)) {
3303                                 continue;
3304                         }
3305
3306                         if (++which > a->n && strncmp(cfmtime->filename, a->word, wordlen) == 0) {
3307                                 completion_value = ast_strdup(cfmtime->filename);
3308                                 break;
3309                         }
3310
3311                         /* Otherwise save that we've seen this filename */
3312                         prev = cfmtime->filename;
3313                 }
3314                 AST_LIST_UNLOCK(&cfmtime_head);
3315
3316                 return completion_value;
3317         }
3318
3319         if (a->argc != 3) {
3320                 return CLI_SHOWUSAGE;
3321         }
3322
3323         AST_LIST_LOCK(&cfmtime_head);
3324         AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
3325                 if (!strcmp(cfmtime->filename, a->argv[2])) {
3326                         char *buf = ast_alloca(strlen("module reload ") + strlen(cfmtime->who_asked) + 1);
3327                         sprintf(buf, "module reload %s", cfmtime->who_asked);
3328                         ast_cli_command(a->fd, buf);
3329                 }
3330         }
3331         AST_LIST_UNLOCK(&cfmtime_head);
3332
3333         return CLI_SUCCESS;
3334 }
3335
3336 static char *handle_cli_config_list(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3337 {
3338         struct cache_file_mtime *cfmtime;
3339
3340         switch (cmd) {
3341         case CLI_INIT:
3342                 e->command = "config list";
3343                 e->usage =
3344                         "Usage: config list\n"
3345                         "   Show all modules that have loaded a configuration file\n";
3346                 return NULL;
3347         case CLI_GENERATE:
3348                 return NULL;
3349         }
3350
3351         AST_LIST_LOCK(&cfmtime_head);
3352         AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
3353                 ast_cli(a->fd, "%-20.20s %-50s\n", S_OR(cfmtime->who_asked, "core"), cfmtime->filename);
3354         }
3355         AST_LIST_UNLOCK(&cfmtime_head);
3356
3357         return CLI_SUCCESS;
3358 }
3359
3360 static struct ast_cli_entry cli_config[] = {
3361         AST_CLI_DEFINE(handle_cli_core_show_config_mappings, "Display config mappings (file names to config engines)"),
3362         AST_CLI_DEFINE(handle_cli_config_reload, "Force a reload on modules using a particular configuration file"),
3363         AST_CLI_DEFINE(handle_cli_config_list, "Show all files that have loaded a configuration file"),
3364 };
3365
3366 static void config_shutdown(void)
3367 {
3368         struct cache_file_mtime *cfmtime;
3369
3370         AST_LIST_LOCK(&cfmtime_head);
3371         while ((cfmtime = AST_LIST_REMOVE_HEAD(&cfmtime_head, list))) {
3372                 struct cache_file_include *cfinclude;
3373                 while ((cfinclude = AST_LIST_REMOVE_HEAD(&cfmtime->includes, list))) {
3374                         ast_free(cfinclude);
3375                 }
3376                 ast_free(cfmtime);
3377         }
3378         AST_LIST_UNLOCK(&cfmtime_head);
3379
3380         ast_cli_unregister_multiple(cli_config, ARRAY_LEN(cli_config));
3381 }
3382
3383 int register_config_cli(void)
3384 {
3385         ast_cli_register_multiple(cli_config, ARRAY_LEN(cli_config));
3386         ast_register_atexit(config_shutdown);
3387         return 0;
3388 }
3389
3390 struct cfg_hook {
3391         const char *name;
3392         const char *filename;
3393         const char *module;
3394         config_hook_cb hook_cb;
3395 };
3396
3397 static void hook_destroy(void *obj)
3398 {
3399         struct cfg_hook *hook = obj;
3400         ast_free((void *) hook->name);
3401         ast_free((void *) hook->filename);
3402         ast_free((void *) hook->module);
3403 }
3404
3405 static int hook_cmp(void *obj, void *arg, int flags)
3406 {
3407         struct cfg_hook *hook1 = obj;
3408         struct cfg_hook *hook2 = arg;
3409
3410         return !(strcasecmp(hook1->name, hook2->name)) ? CMP_MATCH | CMP_STOP : 0;
3411 }
3412
3413 static int hook_hash(const void *obj, const int flags)
3414 {
3415         const struct cfg_hook *hook = obj;
3416
3417         return ast_str_hash(hook->name);
3418 }
3419
3420 void ast_config_hook_unregister(const char *name)
3421 {
3422         struct cfg_hook tmp;
3423
3424         tmp.name = ast_strdupa(name);
3425
3426         ao2_find(cfg_hooks, &tmp, OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
3427 }
3428
3429 static void config_hook_exec(const char *filename, const char *module, struct ast_config *cfg)
3430 {
3431         struct ao2_iterator it;
3432         struct cfg_hook *hook;
3433         if (!(cfg_hooks)) {
3434                 return;
3435         }
3436         it = ao2_iterator_init(cfg_hooks, 0);
3437         while ((hook = ao2_iterator_next(&it))) {
3438                 if (!strcasecmp(hook->filename, filename) &&
3439                                 !strcasecmp(hook->module, module)) {
3440                         struct ast_config *copy = ast_config_copy(cfg);
3441                         hook->hook_cb(copy);
3442                 }
3443                 ao2_ref(hook, -1);
3444         }
3445         ao2_iterator_destroy(&it);
3446 }
3447
3448 int ast_config_hook_register(const char *name,
3449                 const char *filename,
3450                 const char *module,
3451                 enum config_hook_flags flags,
3452                 config_hook_cb hook_cb)
3453 {
3454         struct cfg_hook *hook;
3455         if (!cfg_hooks && !(cfg_hooks = ao2_container_alloc(17, hook_hash, hook_cmp))) {
3456                 return -1;
3457         }
3458
3459         if (!(hook = ao2_alloc(sizeof(*hook), hook_destroy))) {
3460                 return -1;
3461         }
3462
3463         hook->hook_cb = hook_cb;
3464         hook->filename = ast_strdup(filename);
3465         hook->name = ast_strdup(name);
3466         hook->module = ast_strdup(module);
3467
3468         ao2_link(cfg_hooks, hook);
3469         return 0;
3470 }