Remove memory allocation in olsr_timer_add()
[oonf.git] / src / core / olsr_cfg.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2011, 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 <stdio.h>
43 #include <stdlib.h>
44
45 #include "common/common_types.h"
46 #include "config/cfg_schema.h"
47 #include "config/cfg.h"
48
49 #include "olsr_logging.h"
50 #include "olsr_plugins.h"
51 #include "olsr_cfg.h"
52 #include "olsr.h"
53
54 /* static prototypes */
55 static int _cb_validate_global(struct cfg_schema_section *, const char *section_name,
56     struct cfg_named_section *, struct autobuf *);
57
58 /* global config */
59 struct olsr_config_global config_global;
60
61 static struct cfg_instance _olsr_cfg_instance;
62 static struct cfg_db *_olsr_raw_db = NULL;
63 static struct cfg_db *_olsr_work_db = NULL;
64 static struct cfg_schema _olsr_schema;
65 static bool _first_apply;
66
67 /* remember to trigger reload/commit */
68 static bool _trigger_reload, _trigger_commit;
69
70 /* remember if initialized or not */
71 OLSR_SUBSYSTEM_STATE(_cfg_state);
72
73 /* define global configuration template */
74 static struct cfg_schema_section global_section = {
75   .type = CFG_SECTION_GLOBAL,
76   .cb_validate = _cb_validate_global,
77 };
78
79 static struct cfg_schema_entry global_entries[] = {
80   CFG_MAP_BOOL(olsr_config_global, fork, "fork", "no",
81       "Set to true to fork daemon into background."),
82   CFG_MAP_BOOL(olsr_config_global, failfast, "failfast", "no",
83       "Set to true to stop daemon statup if at least one plugin doesn't load."),
84   CFG_MAP_BOOL(olsr_config_global, ipv4, "ipv4", "yes",
85       "Set to true to enable ipv4 support in program."),
86   CFG_MAP_BOOL(olsr_config_global, ipv6, "ipv6", "yes",
87       "Set to true to enable ipv6 support in program."),
88
89   CFG_MAP_STRINGLIST(olsr_config_global, plugin, "plugin", "",
90       "Set list of plugins to be loaded by daemon. Some might need configuration options."),
91 };
92
93 /**
94  * Initializes the olsrd configuration subsystem
95  * @return -1 if an error happened, 0 otherwise
96  */
97 int
98 olsr_cfg_init(void) {
99   if (olsr_subsystem_is_initialized(&_cfg_state))
100     return 0;
101
102   cfg_add(&_olsr_cfg_instance);
103
104   /* initialize schema */
105   cfg_schema_add(&_olsr_schema);
106   cfg_schema_add_section(&_olsr_schema, &global_section,
107       global_entries, ARRAYSIZE(global_entries));
108
109   /* initialize database */
110   if ((_olsr_raw_db = cfg_db_add()) == NULL) {
111     OLSR_WARN(LOG_CONFIG, "Cannot create raw configuration database.");
112     cfg_remove(&_olsr_cfg_instance);
113     return -1;
114   }
115
116   /* initialize database */
117   if ((_olsr_work_db = cfg_db_add()) == NULL) {
118     OLSR_WARN(LOG_CONFIG, "Cannot create configuration database.");
119     cfg_db_remove(_olsr_raw_db);
120     cfg_remove(&_olsr_cfg_instance);
121     return -1;
122   }
123
124   cfg_db_link_schema(_olsr_raw_db, &_olsr_schema);
125
126   /* initialize global config */
127   memset(&config_global, 0, sizeof(config_global));
128   _first_apply = true;
129   _trigger_reload = false;
130   _trigger_commit = false;
131
132   olsr_subsystem_init(&_cfg_state);
133   return 0;
134 }
135
136 /**
137  * Cleans up all data allocated by the olsrd configuration subsystem
138  */
139 void
140 olsr_cfg_cleanup(void) {
141   if (olsr_subsystem_cleanup(&_cfg_state))
142     return;
143
144   free(config_global.plugin.value);
145
146   cfg_db_remove(_olsr_raw_db);
147   cfg_db_remove(_olsr_work_db);
148
149   cfg_remove(&_olsr_cfg_instance);
150 }
151
152 /**
153  * Trigger lazy configuration reload
154  */
155 void
156 olsr_cfg_trigger_reload(void) {
157   _trigger_reload = true;
158 }
159
160 /**
161  * @return true if lazy configuration reload was triggered
162  */
163 bool
164 olsr_cfg_is_reload_set(void) {
165   return _trigger_reload;
166 }
167
168 /**
169  * Trigger lazy configuration commit
170  */
171 void
172 olsr_cfg_trigger_commit(void) {
173   _trigger_reload = true;
174 }
175
176 /**
177  * @return true if lazy configuration commit was triggered
178  */
179 bool
180 olsr_cfg_is_commit_set(void) {
181   return _trigger_reload;
182 }
183
184 /**
185  * Load all plugins that are not already loaded and remove
186  * the plugins that are not needed anymore.
187  * @return -1 if an error happened, 0 otherwise
188  */
189 int
190 olsr_cfg_loadplugins(void) {
191   struct olsr_plugin *plugin, *plugin_it;
192   char *ptr;
193   bool found;
194
195   /* load plugins */
196   FOR_ALL_STRINGS(&config_global.plugin, ptr) {
197     /* ignore empty strings */
198     if (*ptr == 0) {
199       continue;
200     }
201
202     if (olsr_plugins_load(ptr) == NULL && config_global.failfast) {
203       return -1;
204     }
205   }
206
207   /* unload all plugins that are not in use anymore */
208   OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin, plugin_it) {
209     found = false;
210
211     /* search if plugin should still be active */
212     FOR_ALL_STRINGS(&config_global.plugin, ptr) {
213       if (olsr_plugins_get(ptr) == plugin) {
214         found = true;
215         break;
216       }
217     }
218
219     if (!found && !olsr_plugins_is_static(plugin)) {
220       /* if not, unload it (if not static) */
221       olsr_plugins_unload(plugin);
222     }
223   }
224   return 0;
225 }
226
227 /**
228  * Applies to content of the raw configuration database into the
229  * work database and triggers the change calculation.
230  * @return 0 if successful, -1 otherwise
231  */
232 int
233 olsr_cfg_apply(void) {
234   struct olsr_plugin *plugin, *plugin_it;
235   struct cfg_db *new_db, *old_db;
236   struct autobuf log;
237   int result;
238
239   if (abuf_init(&log)) {
240     OLSR_WARN_OOM(LOG_CONFIG);
241     return -1;
242   }
243
244   OLSR_INFO(LOG_CONFIG, "Apply configuration");
245
246   /*** phase 1: activate all plugins ***/
247   result = -1;
248   old_db = NULL;
249
250   if (olsr_cfg_loadplugins()) {
251     goto apply_failed;
252   }
253
254   /*** phase 2: check configuration and apply it ***/
255   /* re-validate configuration data */
256   if (cfg_schema_validate(_olsr_raw_db, false, true, &log)) {
257     OLSR_WARN(LOG_CONFIG, "Configuration validation failed");
258     OLSR_WARN_NH(LOG_CONFIG, "%s", abuf_getptr(&log));
259     goto apply_failed;
260   }
261
262   /* create new configuration database with correct values */
263   new_db = cfg_db_duplicate(_olsr_raw_db);
264   if (new_db == NULL) {
265     OLSR_WARN_OOM(LOG_CONFIG);
266     goto apply_failed;
267   }
268
269   /* switch databases */
270   old_db = _olsr_work_db;
271   _olsr_work_db = new_db;
272
273   /* bind schema */
274   cfg_db_link_schema(_olsr_work_db, &_olsr_schema);
275
276   /* enable all plugins */
277   OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin, plugin_it) {
278     if (plugin->int_enabled)
279       continue;
280     if (olsr_plugins_enable(plugin) != 0
281         && config_global.failfast) {
282       goto apply_failed;
283     }
284   }
285
286   /* remove everything not valid */
287   cfg_schema_validate(new_db, true, false, NULL);
288
289   if (olsr_cfg_update_globalcfg(false)) {
290     /* this should not happen at all */
291     OLSR_WARN(LOG_CONFIG, "Updating global config failed");
292     goto apply_failed;
293   }
294
295   /* calculate delta and call handlers */
296   if (_first_apply) {
297     cfg_schema_handle_db_startup_changes(_olsr_work_db);
298     _first_apply = false;
299   }
300   else {
301     cfg_schema_handle_db_changes(old_db, _olsr_work_db);
302   }
303
304   /* success */
305   result = 0;
306   _trigger_reload = false;
307   _trigger_commit = false;
308
309 apply_failed:
310   /* look for loaded but not enabled plugins and unload them */
311   OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin, plugin_it) {
312     if (plugin->int_loaded && !plugin->int_enabled) {
313       olsr_plugins_unload(plugin);
314     }
315   }
316
317   if (old_db) {
318     cfg_db_remove(old_db);
319   }
320
321   abuf_free(&log);
322   return result;
323 }
324
325 /**
326  * Copy work-db into raw-db to roll back changes before commit.
327  * @return -1 if an error happened, 0 otherwise
328  */
329 int
330 olsr_cfg_rollback(void) {
331   struct cfg_db *db;
332
333   /* remember old db */
334   db = _olsr_raw_db;
335
336   OLSR_INFO(LOG_CONFIG, "Rollback configuration");
337
338   _olsr_raw_db = cfg_db_duplicate(_olsr_work_db);
339   if (_olsr_raw_db == NULL) {
340     OLSR_WARN(LOG_CONFIG, "Cannot create raw configuration database.");
341     _olsr_raw_db = db;
342     return -1;
343   }
344
345   /* free old db */
346   cfg_db_remove(db);
347   return 0;
348 }
349
350 /**
351  * Update binary copy of global config section
352  * @param raw true if data shall be taken from raw database,
353  *   false if work-db should be taken as a source.
354  * @return -1 if an error happened, 0 otherwise
355  */
356 int
357 olsr_cfg_update_globalcfg(bool raw) {
358   struct cfg_named_section *named;
359
360   named = cfg_db_find_namedsection(
361       raw ? _olsr_raw_db : _olsr_work_db, CFG_SECTION_GLOBAL, NULL);
362
363   return cfg_schema_tobin(&config_global,
364       named, global_entries, ARRAYSIZE(global_entries));
365 }
366
367 /**
368  * This function will clear the raw configuration database
369  * @return -1 if an error happened, 0 otherwise
370  */
371 int
372 olsr_cfg_clear_rawdb(void) {
373   struct cfg_db *db;
374
375   /* remember old db */
376   db = _olsr_raw_db;
377
378   /* initialize database */
379   if ((_olsr_raw_db = cfg_db_add()) == NULL) {
380     OLSR_WARN(LOG_CONFIG, "Cannot create raw configuration database.");
381     _olsr_raw_db = db;
382     return -1;
383   }
384
385   /* free old db */
386   cfg_db_remove(db);
387
388   cfg_db_link_schema(_olsr_raw_db, &_olsr_schema);
389   return 0;
390 }
391
392 /**
393  * @return pointer to configuration instance object
394  */
395 struct cfg_instance *
396 olsr_cfg_get_instance(void) {
397   return &_olsr_cfg_instance;
398 }
399
400 /**
401  * @return pointer to olsr configuration database
402  */
403 struct cfg_db *
404 olsr_cfg_get_db(void) {
405   return _olsr_work_db;
406 }
407
408 /**
409  * @return pointer to olsr raw configuration database
410  */
411 struct cfg_db *
412 olsr_cfg_get_rawdb(void) {
413   return _olsr_raw_db;
414 }
415
416 /**
417  * @return pointer to olsr configuration schema
418  */
419 struct cfg_schema *
420 olsr_cfg_get_schema(void) {
421   return &_olsr_schema;
422 }
423
424 /**
425  * Validates if the settings of the global section are
426  * consistent.
427  * @param schema pointer to section schema
428  * @param section_name name of section
429  * @param section pointer to named section of database
430  * @param log pointer to logging output buffer
431  * @return -1 if section is not valid, 0 otherwise
432  */
433 static int
434 _cb_validate_global(struct cfg_schema_section *schema __attribute__((unused)),
435     const char *section_name __attribute__((unused)),
436     struct cfg_named_section *section, struct autobuf *log) {
437   struct olsr_config_global config;
438
439   memset(&config, 0, sizeof(config));
440
441   if (cfg_schema_tobin(&config,
442         section, global_entries, ARRAYSIZE(global_entries))) {
443     cfg_append_printable_line(log, "Could not generate binary template of global section");
444     return -1;
445   }
446
447   if (!config.ipv4 && !config.ipv6) {
448     cfg_append_printable_line(log, "You have to activate either ipv4 or ipv6 (or both)");
449     return -1;
450   }
451
452   free(config.plugin.value);
453   return 0;
454 }