Allow default name for sections
[oonf.git] / src-api / config / cfg_db.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include "common/common_types.h"
47 #include "common/avl.h"
48 #include "common/avl_comp.h"
49 #include "common/string.h"
50
51 #include "config/cfg.h"
52 #include "config/cfg_schema.h"
53 #include "config/cfg_db.h"
54
55 static struct cfg_section_type *_alloc_section(struct cfg_db *, const char *);
56 static void _free_sectiontype(struct cfg_section_type *);
57
58 static struct cfg_named_section *_alloc_namedsection(
59     struct cfg_section_type *, const char *);
60 static void _free_namedsection(struct cfg_named_section *);
61
62 static struct cfg_entry *_alloc_entry(
63     struct cfg_named_section *, const char *);
64 static void _free_entry(struct cfg_entry *);
65
66 /**
67  * @return new configuration database without entries,
68  *   NULL if no memory left
69  */
70 struct cfg_db *
71 cfg_db_add(void) {
72   struct cfg_db *db;
73
74   db = calloc(1, sizeof(*db));
75   if (db) {
76     avl_init(&db->sectiontypes, cfg_avlcmp_keys, false);
77   }
78   return db;
79 }
80
81 /**
82  * Removes a configuration database including all data from memory
83  * @param db pointer to configuration database
84  */
85 void
86 cfg_db_remove(struct cfg_db *db) {
87   struct cfg_section_type *section, *section_it;
88
89   CFG_FOR_ALL_SECTION_TYPES(db, section, section_it) {
90     _free_sectiontype(section);
91   }
92   free(db);
93 }
94
95 /**
96  * Copy parts of a configuration database into a new db
97  * @param dst pointer to target db
98  * @param src pointer to source database
99  * @param section_type section type to copy, NULL for all types
100  * @param section_name section name to copy, NULL for all names
101  * @param entry_name entry name to copy, NULL for all entries
102  * @return 0 if copy was successful, -1 if an error happened.
103  *   In case of an error, the destination might contain a partial
104  *   copy.
105  */
106 int
107 _cfg_db_append(struct cfg_db *dst, struct cfg_db *src,
108     const char *section_type, const char *section_name, const char *entry_name) {
109   struct cfg_section_type *section, *section_it;
110   struct cfg_named_section *named, *named_it;
111   struct cfg_entry *entry, *entry_it;
112   char *ptr;
113   bool dummy;
114
115   CFG_FOR_ALL_SECTION_TYPES(src, section, section_it) {
116     if (section_type != NULL && cfg_cmp_keys(section->type, section_type) != 0) {
117       continue;
118     }
119
120     CFG_FOR_ALL_SECTION_NAMES(section, named, named_it) {
121       if (section_name != NULL && cfg_cmp_keys(named->name, section_name) != 0) {
122         continue;
123       }
124
125       if (_cfg_db_add_section(dst, section->type, named->name, &dummy) == NULL) {
126         return -1;
127       }
128
129       CFG_FOR_ALL_ENTRIES(named, entry, entry_it) {
130         if (entry_name != NULL && cfg_cmp_keys(entry->name, entry_name) != 0) {
131           continue;
132         }
133
134         FOR_ALL_STRINGS(&entry->val, ptr) {
135           if (cfg_db_set_entry_ext(
136               dst, section->type, named->name, entry->name, ptr, true, false) == NULL) {
137             return -1;
138           }
139         }
140       }
141     }
142   }
143   return 0;
144 }
145
146 /**
147  * Adds a named section to a configuration database
148  * @param db pointer to configuration database
149  * @param section_type type of section
150  * @param section_name name of section, NULL if an unnamed one
151  * @param new_section pointer to bool, will be set to true if a new
152  *   section was created, false otherwise
153  * @return pointer to named section, NULL if an error happened
154  */
155 struct cfg_named_section *
156 _cfg_db_add_section(struct cfg_db *db, const char *section_type,
157     const char *section_name, bool *new_section) {
158   struct cfg_section_type *section;
159   struct cfg_named_section *named = NULL;
160
161   /* consistency check */
162   assert (section_type);
163
164   *new_section = false;
165
166   /* get section */
167   section = avl_find_element(&db->sectiontypes, section_type, section, node);
168   if (section == NULL) {
169     section = _alloc_section(db, section_type);
170     if (section == NULL) {
171       return NULL;
172     }
173     *new_section = true;
174   }
175   else {
176     /* get named section */
177     named = avl_find_element(&section->names, section_name, named, node);
178   }
179
180   if (named == NULL) {
181     named = _alloc_namedsection(section, section_name);
182     *new_section = true;
183   }
184
185   return named;
186 }
187
188 /**
189  * Removes a section type (including all namedsections and entries of it)
190  * from a configuration database
191  * @param db pointer to configuration database
192  * @param section_type type of section
193  * @return -1 if section type did not exist, 0 otherwise
194  */
195 int
196 cfg_db_remove_sectiontype(struct cfg_db *db, const char *section_type) {
197   struct cfg_section_type *section;
198
199   /* find section */
200   section = cfg_db_find_sectiontype(db, section_type);
201   if (section == NULL) {
202     return -1;
203   }
204
205   _free_sectiontype(section);
206   return 0;
207 }
208
209 /**
210  * Finds a named section object inside a configuration database
211  * @param db pointer to configuration database
212  * @param section_type type of section
213  * @param section_name name of section, NULL if an unnamed section
214  * @return pointer to named section, NULL if not found
215  */
216 struct cfg_named_section *
217 cfg_db_find_namedsection(
218     struct cfg_db *db, const char *section_type, const char *section_name) {
219   struct cfg_section_type *section;
220   struct cfg_named_section *named = NULL;
221
222   section = cfg_db_find_sectiontype(db, section_type);
223   if (section != NULL) {
224     named = avl_find_element(&section->names, section_name, named, node);
225   }
226   return named;
227 }
228
229 /**
230  * Removes a named section (including all entries of it)
231  * from a configuration database.
232  * If the section_type below is empty afterwards, you might
233  * want to delete it too.
234  * @param db pointer to configuration database
235  * @param section_type type of section
236  * @param section_name name of section, NULL if an unnamed section
237  * @return -1 if section type did not exist, 0 otherwise
238  */
239 int
240 cfg_db_remove_namedsection(struct cfg_db *db, const char *section_type,
241     const char *section_name) {
242   struct cfg_named_section *named;
243
244   named = cfg_db_find_namedsection(db, section_type, section_name);
245   if (named == NULL) {
246     return -1;
247   }
248
249   /* only free named section */
250   _free_namedsection(named);
251   return 0;
252 }
253
254 /**
255  * Sets an entry to a configuration database
256  * @param db pointer to configuration database
257  * @param section_type type of section
258  * @param section_name name of section, NULL if an unnamed one
259  * @param entry_name entry name
260  * @param value entry value
261  * @param append true if the value should be appended to a list,
262  *   false if it should overwrite all old values
263  * @param front true if the value should be put in front of existing
264  *   values, false if it should be put at the end
265  * @return pointer to cfg_entry, NULL if an error happened
266  */
267 struct cfg_entry *
268 cfg_db_set_entry_ext(struct cfg_db *db, const char *section_type,
269     const char *section_name, const char *entry_name, const char *value,
270     bool append, bool front) {
271   struct cfg_entry *entry;
272   struct cfg_named_section *named;
273   bool new_section = false, new_entry = NULL;
274
275   /* create section */
276   named = _cfg_db_add_section(db, section_type, section_name, &new_section);
277   if (!named) {
278     return NULL;
279   }
280
281   /* get entry */
282   entry = avl_find_element(&named->entries, entry_name, entry, node);
283   if (!entry) {
284     entry = _alloc_entry(named, entry_name);
285     if (!entry) {
286       goto set_entry_error;
287     }
288     new_entry = true;
289   }
290
291   if (!append) {
292     strarray_free(&entry->val);
293   }
294   /* prepend new entry */
295   if (front) {
296     if (strarray_prepend(&entry->val, value)) {
297       goto set_entry_error;
298     }
299   }
300   else {
301     if (strarray_append(&entry->val, value)) {
302       goto set_entry_error;
303     }
304   }
305
306   return entry;
307 set_entry_error:
308   if (new_entry) {
309     _free_entry(entry);
310   }
311   if (new_section) {
312     _free_namedsection(named);
313   }
314   return NULL;
315 }
316
317 /**
318  * Finds a specific entry inside a configuration database
319  * @param db pointer to configuration database
320  * @param section_type type of section
321  * @param section_name name of section, NULL if an unnamed section
322  * @param entry_name name of the entry
323  * @return pointer to configuration entry, NULL if not found
324  */
325 struct cfg_entry *
326 cfg_db_find_entry(struct cfg_db *db,
327     const char *section_type, const char *section_name, const char *entry_name) {
328   struct cfg_named_section *named;
329   struct cfg_entry *entry = NULL;
330
331   /* get named section */
332   named = cfg_db_find_namedsection(db, section_type, section_name);
333   if (named != NULL) {
334     entry = avl_find_element(&named->entries, entry_name, entry, node);
335   }
336   return entry;
337 }
338
339 /**
340  * Removes an entry from a configuration database
341  * @param db pointer to configuration database
342  * @param section_type type of section
343  * @param section_name name of section, NULL if an unnamed one
344  * @param entry_name entry name
345  * @return -1 if the entry did not exist, 0 if it was removed
346  */
347 int
348 cfg_db_remove_entry(struct cfg_db *db, const char *section_type,
349     const char *section_name, const char *entry_name) {
350   struct cfg_entry *entry;
351
352   /* get entry */
353   entry = cfg_db_find_entry(db, section_type, section_name, entry_name);
354   if (entry == NULL) {
355     /* entry not there */
356     return -1;
357   }
358
359   _free_entry(entry);
360   return 0;
361 }
362
363 /**
364  * Accessor function to read the string value of a single entry
365  * from a configuration database.
366  * @param db pointer to configuration database
367  * @param section_type type of section
368  * @param section_name name of section, NULL if an unnamed section
369  * @param entry_name name of the entry
370  * @return string value, NULL if not found or list of values
371  */
372 const struct const_strarray *
373 cfg_db_get_entry_value(struct cfg_db *db, const char *section_type,
374     const char *section_name, const char *entry_name) {
375   struct cfg_schema_entry_key key;
376   struct cfg_schema_entry *s_entry;
377   struct cfg_entry *entry;
378
379   entry = cfg_db_find_entry(db, section_type, section_name, entry_name);
380   if (entry != NULL) {
381     return (const struct const_strarray *)&entry->val;
382   }
383
384   /* look for value of default section */
385   if (section_name != NULL) {
386     entry = cfg_db_find_entry(db, section_type, NULL, entry_name);
387     if (entry != NULL) {
388       return (const struct const_strarray *)&entry->val;
389     }
390   }
391
392   /* look for schema default value */
393   if (db->schema == NULL) {
394     return NULL;
395   }
396
397   key.type = section_type;
398   key.entry = entry_name;
399
400   s_entry = avl_find_element(&db->schema->entries, &key, s_entry, _node);
401   if (s_entry != NULL && s_entry->def.value != NULL) {
402     return &s_entry->def;
403   }
404   return NULL;
405 }
406
407 /**
408  * Removes an element from a configuration entry list
409  * @param db pointer to configuration database
410  * @param section_type type of section
411  * @param section_name name of section, NULL if an unnamed one
412  * @param entry_name entry name
413  * @param value value to be removed from the list
414  * @return 0 if the element was removed, -1 if it wasn't there
415  */
416 int
417 cfg_db_remove_element(struct cfg_db *db, const char *section_type,
418     const char *section_name, const char *entry_name, const char *value) {
419   struct cfg_entry *entry;
420   char *ptr;
421
422   /* find entry */
423   entry = cfg_db_find_entry(db, section_type, section_name, entry_name);
424   if (entry == NULL) {
425     return -1;
426   }
427
428   if (!cfg_db_is_multipart_entry(entry)) {
429     /* only a single element in list */
430     if (strcmp(value, entry->val.value) == 0) {
431       _free_entry(entry);
432       return 0;
433     }
434     return -1;
435   }
436
437   FOR_ALL_STRINGS(&entry->val, ptr) {
438     if (strcmp(ptr, value) == 0) {
439       strarray_remove(&entry->val, ptr);
440       return 0;
441     }
442   }
443
444   /* element not in list */
445   return -1;
446 }
447
448 /**
449  * Creates a section type in a configuration database
450  * @param db pointer to configuration database
451  * @param type type of section
452  * @return pointer to section type, NULL if allocation failed
453  */
454 static struct cfg_section_type *
455 _alloc_section(struct cfg_db *db, const char *type) {
456   struct cfg_section_type *section;
457
458   assert(type);
459
460   section = calloc(1, sizeof(*section));
461   if (!section) {
462     return NULL;
463   }
464
465   section->type = strdup(type);
466   if (!section->type) {
467     free (section);
468     return NULL;
469   }
470
471   section->node.key = section->type;
472   avl_insert(&db->sectiontypes, &section->node);
473
474   section->db = db;
475
476   avl_init(&section->names, cfg_avlcmp_keys, false);
477   return section;
478 }
479
480 /**
481  * Removes a section type from a configuration database
482  * including its named section and entries.
483  * @param section pointer to section
484  */
485 static void
486 _free_sectiontype(struct cfg_section_type *section) {
487   struct cfg_named_section *named, *named_it;
488
489   /* remove all named sections */
490   CFG_FOR_ALL_SECTION_NAMES(section, named, named_it) {
491     _free_namedsection(named);
492   }
493
494   avl_remove(&section->db->sectiontypes, &section->node);
495   free((void *)section->type);
496   free(section);
497 }
498
499 /**
500  * Creates a named section in a configuration database.
501  * @param section pointer to section type
502  * @param name name of section (might be NULL)
503  * @return pointer to named section, NULL if allocation failed
504  */
505 static struct cfg_named_section *
506 _alloc_namedsection(struct cfg_section_type *section,
507     const char *name) {
508   struct cfg_named_section *named;
509
510   named = calloc(1, sizeof(*section));
511   if (!named) {
512     return NULL;
513   }
514
515   named->name = (name == NULL) ? NULL : strdup(name);
516   if (!named->name && name != NULL) {
517     free (named);
518     return NULL;
519   }
520
521   named->node.key = named->name;
522   avl_insert(&section->names, &named->node);
523
524   named->section_type = section;
525   avl_init(&named->entries, cfg_avlcmp_keys, false);
526   return named;
527 }
528
529 /**
530  * Removes a named section from a database including entries.
531  * @param named pointer to named section.
532  */
533 static void
534 _free_namedsection(struct cfg_named_section *named) {
535   struct cfg_entry *entry, *entry_it;
536
537   /* remove all entries first */
538   CFG_FOR_ALL_ENTRIES(named, entry, entry_it) {
539     _free_entry(entry);
540   }
541
542   avl_remove(&named->section_type->names, &named->node);
543   free ((void *)named->name);
544   free (named);
545 }
546
547 /**
548  * Creates an entry in a configuration database.
549  * It will not initialize the value.
550  * @param named pointer to named section
551  * @param name name of entry
552  * @return pointer to configuration entry, NULL if allocation failed
553  */
554 static struct cfg_entry *
555 _alloc_entry(struct cfg_named_section *named,
556     const char *name) {
557   struct cfg_entry *entry;
558
559   assert(name);
560
561   entry = calloc (1, sizeof(*entry));
562   if (!entry) {
563     return NULL;
564   }
565
566   entry->name = strdup(name);
567   if (!entry->name) {
568     free (entry);
569     return NULL;
570   }
571
572   entry->node.key = entry->name;
573   avl_insert(&named->entries, &entry->node);
574
575   entry->named_section = named;
576   return entry;
577 }
578
579 /**
580  * Removes a configuration entry from a database
581  * @param entry pointer to configuration entry
582  */
583 static void
584 _free_entry(struct cfg_entry *entry) {
585   avl_remove(&entry->named_section->entries, &entry->node);
586
587   strarray_free(&entry->val);
588   free(entry->name);
589   free(entry);
590 }