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