Remove memory allocation in olsr_timer_add()
[oonf.git] / src / core / olsr_logging_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 <errno.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include "common/common_types.h"
48 #include "config/cfg_schema.h"
49 #include "config/cfg_db.h"
50 #include "config/cfg.h"
51
52 #include "olsr_logging.h"
53 #include "olsr_logging_cfg.h"
54 #include "olsr_cfg.h"
55 #include "olsr.h"
56 #include "os_system.h"
57
58 #define LOG_SECTION     "log"
59 #define LOG_LEVEL_ENTRY "level"
60 #define LOG_DEBUG_ENTRY "debug"
61 #define LOG_INFO_ENTRY  "info"
62 #define LOG_WARN_ENTRY  "warn"
63 #define LOG_STDERR_ENTRY "stderr"
64 #define LOG_SYSLOG_ENTRY "syslog"
65 #define LOG_FILE_ENTRY   "file"
66
67 /* prototype for configuration change handler */
68 static void _cb_logcfg_apply(void);
69 static void _apply_log_setting(struct cfg_named_section *named,
70     const char *entry_name, enum log_severity severity);
71
72 /* define logging configuration template */
73 static struct cfg_schema_section logging_section = {
74   .type = LOG_SECTION,
75   .cb_delta_handler = _cb_logcfg_apply,
76 };
77
78 static const char *_dummy[0];
79 static struct cfg_schema_entry logging_entries[] = {
80   /* the next three parameters are configured to a different list during runtime */
81   CFG_VALIDATE_CHOICE(LOG_DEBUG_ENTRY, "",
82       "Set logging sources that display debug, info and warnings",
83       _dummy, .list = true),
84   CFG_VALIDATE_CHOICE(LOG_INFO_ENTRY, "",
85       "Set logging sources that display info and warnings",
86       _dummy, .list = true),
87   CFG_VALIDATE_CHOICE(LOG_WARN_ENTRY, "",
88       "Set logging sources that display warnings",
89       _dummy, .list = true),
90
91   CFG_VALIDATE_INT_MINMAX(LOG_LEVEL_ENTRY, "0", "Set debug level template", -2, 3),
92   CFG_VALIDATE_BOOL(LOG_STDERR_ENTRY, "false", "Set to true to activate logging to stderr"),
93   CFG_VALIDATE_BOOL(LOG_SYSLOG_ENTRY, "false", "Set to true to activate logging to syslog"),
94   CFG_VALIDATE_STRING(LOG_FILE_ENTRY, "", "Set a filename to log to a file"),
95 };
96
97 static enum log_source *debug_lvl_1 = NULL;
98 static size_t debug_lvl_1_count = 0;
99
100 /* global logger configuration */
101 static struct log_handler_mask_entry *logging_cfg;
102 static struct log_handler_entry stderr_handler = {
103   .handler = olsr_log_stderr
104 };
105 static struct log_handler_entry syslog_handler = {
106   .handler = olsr_log_syslog
107 };
108 static struct log_handler_entry file_handler = {
109   .handler = olsr_log_file
110 };
111
112 /* remember if initialized or not */
113 OLSR_SUBSYSTEM_STATE(_logcfg_state);
114
115 /**
116  * Initialize logging configuration
117  * @param debug_lvl_1_ptr array of logging sources for debug level 1
118  * @param length number of level 1 logging sources
119  */
120 void
121 olsr_logcfg_init(enum log_source *debug_lvl_1_ptr, size_t length) {
122   if (olsr_subsystem_init(&_logcfg_state))
123     return;
124
125   debug_lvl_1 = debug_lvl_1_ptr;
126   debug_lvl_1_count = length;
127
128   logging_cfg = olsr_log_allocate_mask();
129   stderr_handler.bitmask = logging_cfg;
130   syslog_handler.bitmask = logging_cfg;
131   file_handler.bitmask = logging_cfg;
132 }
133
134 /**
135  * Cleanup all allocated resources of logging configuration
136  */
137 void
138 olsr_logcfg_cleanup(void) {
139   if (olsr_subsystem_cleanup(&_logcfg_state))
140     return;
141
142   /* clean up former handlers */
143   if (list_is_node_added(&stderr_handler.node)) {
144     olsr_log_removehandler(&stderr_handler);
145   }
146   if (list_is_node_added(&syslog_handler.node)) {
147     olsr_log_removehandler(&syslog_handler);
148   }
149   if (list_is_node_added(&file_handler.node)) {
150     FILE *f;
151
152     f = file_handler.custom;
153     fflush(f);
154     fclose(f);
155
156     olsr_log_removehandler(&file_handler);
157   }
158
159   olsr_log_free_mask(logging_cfg);
160 }
161
162 /**
163  * Add logging section to global configuration schema
164  * @param schema pointer to schema
165  */
166 void
167 olsr_logcfg_addschema(struct cfg_schema *schema) {
168   int i;
169
170   for (i=0; i<3; i++) {
171     logging_entries[i].validate_params.p_i1 = olsr_log_get_sourcecount();
172     logging_entries[i].validate_params.p_ptr = LOG_SOURCE_NAMES;
173   }
174
175   cfg_schema_add_section(schema, &logging_section,
176       logging_entries, ARRAYSIZE(logging_entries));
177 }
178
179 /**
180  * Apply the configuration settings of a db to the logging system
181  * @param db pointer to configuration database
182  * @return -1 if an error happened, 0 otherwise
183  */
184 int
185 olsr_logcfg_apply(struct cfg_db *db) {
186   struct cfg_named_section *named;
187   const char *ptr, *file_name;
188   size_t i;
189   int file_errno = 0;
190   bool activate_syslog, activate_file, activate_stderr;
191
192   /* clean up logging mask */
193   olsr_log_clear_mask(logging_cfg);
194
195   /* first apply debug level */
196   ptr = cfg_db_get_entry_value(db, LOG_SECTION, NULL, LOG_LEVEL_ENTRY)->value;
197   switch (atoi(ptr)) {
198     case -1:
199       /* no logging */
200       break;
201     case 0:
202       /* only warnings */
203       logging_cfg[LOG_ALL].log_for_severity[SEVERITY_WARN] = true;
204       break;
205     case 1:
206       /* warnings and some info */
207       logging_cfg[LOG_ALL].log_for_severity[SEVERITY_WARN] = true;
208       for (i=0; i<debug_lvl_1_count; i++) {
209         logging_cfg[debug_lvl_1[i]].log_for_severity[SEVERITY_INFO] = true;
210       }
211       break;
212     case 2:
213       /* warning and info */
214       logging_cfg[LOG_ALL].log_for_severity[SEVERITY_INFO] = true;
215       break;
216     case 3:
217       /* all logging messages */
218       logging_cfg[LOG_ALL].log_for_severity[SEVERITY_DEBUG] = true;
219       break;
220     default:
221       break;
222   }
223
224   /* now apply specific settings */
225   named = cfg_db_find_namedsection(db, LOG_SECTION, NULL);
226   if (named != NULL) {
227     _apply_log_setting(named, LOG_WARN_ENTRY, SEVERITY_WARN);
228     _apply_log_setting(named, LOG_INFO_ENTRY, SEVERITY_INFO);
229     _apply_log_setting(named, LOG_DEBUG_ENTRY, SEVERITY_DEBUG);
230   }
231
232   /* load settings which loggershould be activated */
233   ptr = cfg_db_get_entry_value(db, LOG_SECTION, NULL, LOG_SYSLOG_ENTRY)->value;
234   activate_syslog = cfg_get_bool(ptr);
235
236   file_name = cfg_db_get_entry_value(db, LOG_SECTION, NULL, LOG_FILE_ENTRY)->value;
237   activate_file = file_name != NULL && *file_name != 0;
238
239   ptr = cfg_db_get_entry_value(db, LOG_SECTION, NULL, LOG_STDERR_ENTRY)->value;
240   activate_stderr = cfg_get_bool(ptr);
241
242   /* and finally modify the logging handlers */
243   /* log.file */
244   if (activate_file && !list_is_node_added(&file_handler.node)) {
245     FILE *f;
246
247     f = fopen(file_name, "w");
248     if (f != NULL) {
249       olsr_log_addhandler(&file_handler);
250       file_handler.custom = f;
251     }
252     else {
253       file_errno = errno;
254       activate_file = false;
255     }
256   }
257   else if (!activate_file && list_is_node_added(&file_handler.node)) {
258     FILE *f = file_handler.custom;
259     olsr_log_removehandler(&file_handler);
260
261     fflush(f);
262     fclose(f);
263   }
264
265   /* log.stderr (activate if syslog and file ar offline) */
266   if (!config_global.fork) {
267     activate_stderr |= !(activate_syslog || activate_file);
268   }
269
270   if (activate_stderr && !list_is_node_added(&stderr_handler.node)) {
271     olsr_log_addhandler(&stderr_handler);
272   }
273   else if (!activate_stderr && list_is_node_added(&stderr_handler.node)) {
274     olsr_log_removehandler(&stderr_handler);
275   }
276
277   /* log.syslog */
278   if (config_global.fork) {
279     activate_syslog |= !(activate_stderr || activate_file);
280   }
281
282   if (activate_syslog && !list_is_node_added(&syslog_handler.node)) {
283     olsr_log_addhandler(&syslog_handler);
284   }
285   else if (!activate_syslog && list_is_node_added(&syslog_handler.node)) {
286     olsr_log_removehandler(&syslog_handler);
287   }
288
289   /* reload logging mask */
290   olsr_log_updatemask();
291
292   if (file_errno) {
293     OLSR_WARN(LOG_MAIN, "Cannot open file '%s' for logging: %s (%d)",
294         file_name, strerror(file_errno), file_errno);
295     return 1;
296   }
297
298   return 0;
299 }
300
301 /**
302  * Apply the logging options of one severity setting to the logging mask
303  * @param named pointer to configuration section
304  * @param entry_name name of setting (debug, info, warn)
305  * @param severity severity level corresponding severity level
306  */
307 static void
308 _apply_log_setting(struct cfg_named_section *named,
309     const char *entry_name, enum log_severity severity) {
310   struct cfg_entry *entry;
311   char *ptr;
312   size_t i;
313
314   entry = cfg_db_get_entry(named, entry_name);
315   if (entry) {
316     FOR_ALL_STRINGS(&entry->val, ptr) {
317       i = cfg_get_choice_index(ptr, LOG_SOURCE_NAMES, olsr_log_get_sourcecount());
318       logging_cfg[i].log_for_severity[severity] = true;
319     }
320   }
321 }
322
323 /**
324  * Wrapper for configuration delta handling
325  */
326 static void
327 _cb_logcfg_apply(void) {
328   if (olsr_logcfg_apply(olsr_cfg_get_db())) {
329     os_system_log(SEVERITY_WARN, "Could not open logging file");
330   }
331 }