Update to cleaned up commons API
[oonf.git] / src / olsr_main.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 <unistd.h>
43 #include <getopt.h>
44 #include <signal.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <sys/types.h>
48 #include <strings.h>
49 #include <sys/socket.h>
50 #include <net/if.h>
51
52 #include "common/daemonize.h"
53 #include "common/list.h"
54 #include "config/cfg_cmd.h"
55 #include "config/cfg_db.h"
56 #include "config/cfg_schema.h"
57 #include "builddata/plugin_static.h"
58 #include "builddata/data.h"
59 #include "os_net.h"
60 #include "os_system.h"
61 #include "os_routing.h"
62 #include "olsr_cfg.h"
63 #include "olsr_clock.h"
64 #include "olsr_http.h"
65 #include "olsr_interface.h"
66 #include "olsr_logging.h"
67 #include "olsr_logging_cfg.h"
68 #include "olsr_memcookie.h"
69 #include "olsr_packet_socket.h"
70 #include "olsr_plugins.h"
71 #include "olsr_socket.h"
72 #include "olsr_stream_socket.h"
73 #include "olsr_telnet.h"
74 #include "olsr_timer.h"
75 #include "olsr_setup.h"
76 #include "olsr.h"
77
78 static bool _end_olsr_signal, _display_schema;
79 static char *_schema_name;
80
81 enum argv_short_options {
82   argv_option_schema = 256,
83 };
84
85 static struct option olsr_options[] = {
86 #if !defined(REMOVE_HELPTEXT)
87   { "help",         no_argument,       0, 'h' },
88 #endif
89   { "version",      no_argument,       0, 'v' },
90   { "plugin",       required_argument, 0, 'p' },
91   { "load",         required_argument, 0, 'l' },
92   { "save",         required_argument, 0, 'S' },
93   { "set",          required_argument, 0, 's' },
94   { "remove",       required_argument, 0, 'r' },
95   { "get",          optional_argument, 0, 'g' },
96   { "format",       required_argument, 0, 'f' },
97   { "quit",         no_argument,       0, 'q' },
98   { "schema",       optional_argument, 0, argv_option_schema },
99   { NULL, 0,0,0 }
100 };
101
102 #if !defined(REMOVE_HELPTEXT)
103 static const char *help_text =
104     "Mandatory arguments to long options are mandatory for short options too.\n"
105     "  -h, --help                             Display this help file\n"
106     "  -v, --version                          Display the version string and the included static plugins\n"
107     "  -p, --plugin=shared-library            Load a shared library as a plugin\n"
108     "      --quit                             Load plugins and validate configuration, then end\n"
109     "      --schema                           Display all allowed section types of configuration\n"
110     "              =section_type              Display all allowed entries of one configuration section\n"
111     "              =section_type.key          Display help text for configuration entry\n"
112     "  -l, --load=SOURCE                      Load configuration from a SOURCE\n"
113     "  -S, --save=TARGET                      Save configuration to a TARGET\n"
114     "  -s, --set=section_type.                Add an unnamed section to the configuration\n"
115     "           =section_type.key=value       Add a key/value pair to an unnamed section\n"
116     "           =section_type[name].          Add a named section to the configuration\n"
117     "           =section_type[name].key=value Add a key/value pair to a named section\n"
118     "  -r, --remove=section_type.             Remove all sections of a certain type\n"
119     "              =section_type.key          Remove a key in an unnamed section\n"
120     "              =section_type[name].       Remove a named section\n"
121     "              =section_type[name].key    Remove a key in a named section\n"
122     "  -g, --get                              Show all section types in database\n"
123     "           =section_type.                Show all named sections of a certain type\n"
124     "           =section_type.key             Show the value(s) of a key in an unnamed section\n"
125     "           =section_type[name].key       Show the value(s) of a key in a named section\n"
126     "  -f, --format=FORMAT                    Set the format for loading/saving data\n"
127     "                                         (use 'AUTO' for automatic detection of format)\n"
128 ;
129 #endif
130
131 /* prototype for local statics */
132 static void quit_signal_handler(int);
133 static void hup_signal_handler(int);
134 static void setup_signalhandler(void);
135 static int mainloop(int argc, char **argv);
136 static int parse_commandline(int argc, char **argv, bool reload_only);
137 static int display_schema(void);
138
139 /**
140  * Main program
141  */
142 int
143 main(int argc, char **argv) {
144   int return_code;
145   int fork_pipe;
146
147   /* early initialization */
148   return_code = 1;
149   fork_pipe = -1;
150   _schema_name = NULL;
151   _display_schema = false;
152
153   /* setup signal handler */
154   _end_olsr_signal = false;
155   setup_signalhandler();
156
157   /* initialize logger */
158   if (olsr_log_init(olsr_builddata_get(), SEVERITY_WARN,
159       olsr_setup_get_lognames(), olsr_setup_get_logcount())) {
160     goto olsrd_cleanup;
161   }
162
163   /* add configuration definition */
164   if (olsr_cfg_init()) {
165     goto olsrd_cleanup;
166   }
167
168   /* add custom configuration definitions */
169   olsr_logcfg_init(olsr_setup_get_level1_logs(), olsr_setup_get_level1count());
170
171   /* initialize logging schema */
172   olsr_logcfg_addschema(olsr_cfg_get_schema());
173
174   /* prepare plugin initialization */
175   olsr_plugins_init();
176
177   /* load static plugins */
178   olsr_plugins_load_static();
179   if (olsr_plugins_init_static()) {
180     goto olsrd_cleanup;
181   }
182
183   /* parse command line and read configuration files */
184   return_code = parse_commandline(argc, argv, false);
185   if (return_code != -1) {
186     /* end OLSRd now */
187     goto olsrd_cleanup;
188   }
189
190   /* preload plugins to show their schemas */
191   if (olsr_cfg_loadplugins()) {
192     goto olsrd_cleanup;
193   }
194
195   /* prepare for an error during initialization */
196   return_code = 1;
197
198   /* read global section early */
199   if (olsr_cfg_update_globalcfg(true)) {
200     OLSR_WARN(LOG_MAIN, "Cannot read global configuration section");
201     goto olsrd_cleanup;
202   }
203
204   /* check if we are root, otherwise stop */
205 #ifdef NEED_ROOT
206   if (geteuid() != 0) {
207     OLSR_WARN(LOG_MAIN, "You must be root(uid = 0) to run %s!\n",
208         olsr_builddata_get()->app_name);
209     goto olsrd_cleanup;
210   }
211 #endif
212
213   /* see if we need to fork */
214   if (config_global.fork) {
215     /* fork into background */
216     fork_pipe = daemonize_prepare();
217     if (fork_pipe == -1) {
218       OLSR_WARN(LOG_MAIN, "Cannot fork into background");
219       goto olsrd_cleanup;
220     }
221   }
222
223   /* configure logger */
224   if (olsr_logcfg_apply(olsr_cfg_get_rawdb())) {
225     goto olsrd_cleanup;
226   }
227
228   /* initialize basic framework */
229   os_system_openlog();
230   olsr_memcookie_init();
231   if (olsr_clock_init()) {
232     goto olsrd_cleanup;
233   }
234   if (olsr_timer_init()) {
235     goto olsrd_cleanup;
236   }
237   olsr_socket_init();
238   olsr_packet_init();
239   if (olsr_stream_init()) {
240     goto olsrd_cleanup;
241   }
242
243   /* activate os-specific code */
244   if (os_system_init()) {
245     goto olsrd_cleanup;
246   }
247
248 #ifdef NEED_ROUTING
249   if (os_routing_init()) {
250     goto olsrd_cleanup;
251   }
252 #endif
253
254   if (os_net_init()) {
255     goto olsrd_cleanup;
256   }
257
258   /* activate interface listening system */
259   if (olsr_interface_init()) {
260     goto olsrd_cleanup;
261   }
262
263   /* activate telnet and http */
264   if (olsr_telnet_init()) {
265     goto olsrd_cleanup;
266   }
267   olsr_http_init();
268
269   /* activate custom additions to framework */
270   if (olsr_setup_init()) {
271     goto olsrd_cleanup;
272   }
273
274   /* show schema if necessary */
275   if (_display_schema) {
276     return_code = display_schema();
277     goto olsrd_cleanup;
278   }
279
280   /* apply configuration */
281   if (olsr_cfg_apply()) {
282     goto olsrd_cleanup;
283   }
284
285   if (!olsr_is_running()) {
286     /*
287      * mayor error during late initialization
288      * or maybe the user decided otherwise and pressed CTRL-C
289      */
290     return_code = _end_olsr_signal ? 0 : 1;
291     goto olsrd_cleanup;
292   }
293
294   if (fork_pipe != -1) {
295     /* tell main process that we are finished with initialization */
296     daemonize_finish(fork_pipe, 0);
297     fork_pipe = -1;
298   }
299
300   /* activate mainloop */
301   return_code = mainloop(argc, argv);
302
303 olsrd_cleanup:
304   /* free plugins */
305   olsr_plugins_cleanup();
306
307   /* free custom framework additions */
308   olsr_setup_cleanup();
309
310   /* free framework resources */
311   olsr_http_cleanup();
312   olsr_telnet_cleanup();
313   olsr_interface_cleanup();
314   os_net_cleanup();
315 #ifdef NEED_ROUTING
316   os_routing_cleanup();
317 #endif
318   os_system_cleanup();
319   olsr_stream_cleanup();
320   olsr_packet_cleanup();
321   olsr_socket_cleanup();
322   olsr_timer_cleanup();
323   olsr_memcookie_cleanup();
324   os_system_closelog();
325   olsr_logcfg_cleanup();
326
327   /* free configuration resources */
328   olsr_cfg_cleanup();
329
330   /* free logger resources */
331   olsr_log_cleanup();
332
333   if (fork_pipe != -1) {
334     /* tell main process that we had a problem */
335     daemonize_finish(fork_pipe, return_code);
336   }
337
338   return return_code;
339 }
340
341 /**
342  * Handle incoming SIGINT signal
343  * @param signo
344  */
345 static void
346 quit_signal_handler(int signo __attribute__ ((unused))) {
347   olsr_exit();
348 }
349
350 /**
351  * Handle incoming SIGHUP signal
352  * @param signo
353  */
354 static void
355 hup_signal_handler(int signo __attribute__ ((unused))) {
356   olsr_cfg_trigger_reload();
357 }
358
359 /**
360  * Mainloop of olsrd
361  * @return exit code for olsrd
362  */
363 static int
364 mainloop(int argc, char **argv) {
365   uint32_t next_interval;
366   int exit_code = 0;
367
368   OLSR_INFO(LOG_MAIN, "Starting %s.", olsr_log_get_builddata()->app_name);
369
370   /* enter main loop */
371   while (olsr_is_running()) {
372     /*
373      * Update the global timestamp. We are using a non-wallclock timer here
374      * to avoid any undesired side effects if the system clock changes.
375      */
376     if (olsr_clock_update()) {
377       exit_code = 1;
378       break;
379     }
380
381     next_interval = olsr_clock_get_absolute(1000);
382
383     /* Process timers */
384     olsr_timer_walk();
385
386     /* Read incoming data and handle it immediately */
387     if (olsr_socket_handle(next_interval)) {
388       exit_code = 1;
389       break;
390     }
391
392     /* reload configuration if triggered */
393     if (olsr_cfg_is_reload_set()) {
394       OLSR_INFO(LOG_MAIN, "Reloading configuration");
395       if (olsr_cfg_clear_rawdb()) {
396         break;
397       }
398       if (parse_commandline(argc, argv, true) == -1) {
399         if (olsr_cfg_apply()) {
400           break;
401         }
402       }
403     }
404
405     /* commit config if triggered */
406     if (olsr_cfg_is_commit_set()) {
407       OLSR_INFO(LOG_MAIN, "Commiting configuration");
408       if (olsr_cfg_apply()) {
409         break;
410       }
411     }
412   }
413
414   /* wait for 500 milliseconds and process socket events */
415   next_interval = olsr_clock_get_absolute(500);
416   olsr_timer_walk();
417   if (olsr_socket_handle(next_interval)) {
418     exit_code = 1;
419   }
420
421   OLSR_INFO(LOG_MAIN, "Ending %s.", olsr_log_get_builddata()->app_name);
422   return exit_code;
423 }
424
425 /**
426  * Setup signal handling for olsrd
427  */
428 static void
429 setup_signalhandler(void) {
430   static struct sigaction act;
431
432   memset(&act, 0, sizeof(act));
433
434   /* setup signal handler first */
435   sigemptyset(&act.sa_mask);
436   act.sa_flags = 0;
437
438   act.sa_handler = quit_signal_handler;
439   sigaction(SIGINT, &act, NULL);
440   sigaction(SIGQUIT, &act, NULL);
441   sigaction(SIGILL, &act, NULL);
442   sigaction(SIGABRT, &act, NULL);
443   sigaction(SIGTERM, &act, NULL);
444
445   act.sa_handler = SIG_IGN;
446   sigaction(SIGPIPE, &act, NULL);
447   sigaction(SIGUSR1, &act, NULL);
448   sigaction(SIGUSR2, &act, NULL);
449
450   act.sa_handler = hup_signal_handler;
451   sigaction(SIGHUP, &act, NULL);
452 }
453
454 /**
455  * Parse command line of olsrd
456  * @param argc number of arguments
457  * @param argv argument vector
458  * @param def_config default configuration file, NULL if
459  *   no default config file should be loaded
460  * @param reload_only true if only the command line arguments should
461  *   be parsed that load a configuration (--set, --remove, --load,
462  *   and --format), false for normal full parsing.
463  * @return -1 if olsrd should start normally, otherwise olsrd should
464  *   exit with the returned number
465  */
466 static int
467 parse_commandline(int argc, char **argv, bool reload_only) {
468   const char *parameters;
469   struct olsr_plugin *plugin, *plugin_it;
470   struct autobuf log;
471   struct cfg_db *db;
472   int opt, opt_idx, return_code;
473   bool loaded_file;
474
475   return_code = -1;
476   loaded_file = false;
477   db = olsr_cfg_get_rawdb();
478
479   /* reset getopt_long */
480   opt_idx = -1;
481   optind = 1;
482
483   abuf_init(&log);
484   cfg_cmd_clear_state(olsr_cfg_get_instance());
485
486   if (reload_only) {
487     /* only parameters that load and change configuration data */
488     parameters = "l:s:r:f:";
489   }
490   else {
491     parameters = "hvp:ql:S:s:r:g::f:";
492   }
493   while (return_code == -1
494       && 0 <= (opt = getopt_long(argc, argv, parameters, olsr_options, &opt_idx))) {
495     switch (opt) {
496       case 'h':
497 #if !defined(REMOVE_HELPTEXT)
498         abuf_appendf(&log, "Usage: %s [OPTION]...\n%s%s%s", argv[0],
499             olsr_builddata_get()->help_prefix,
500             help_text,
501             olsr_builddata_get()->help_suffix);
502 #endif
503         return_code = 0;
504         break;
505
506       case 'v':
507         olsr_log_printversion(&log);
508         OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin, plugin_it) {
509           abuf_appendf(&log, " Static plugin: %s\n", plugin->name);
510         }
511         return_code = 0;
512         break;
513       case 'p':
514         if (olsr_plugins_load(optarg) == NULL) {
515           return_code = 1;
516         }
517         break;
518       case 'q':
519         olsr_exit();
520         break;
521
522       case argv_option_schema:
523         _schema_name = optarg;
524         _display_schema = true;
525         break;
526
527       case 'l':
528         if (cfg_cmd_handle_load(olsr_cfg_get_instance(), db, optarg, &log)) {
529           return_code = 1;
530         }
531         loaded_file = true;
532         break;
533       case 'S':
534         if (cfg_cmd_handle_save(olsr_cfg_get_instance(), db, optarg, &log)) {
535           return_code = 1;
536         }
537         break;
538       case 's':
539         if (cfg_cmd_handle_set(olsr_cfg_get_instance(), db, optarg, &log)) {
540           return_code = 1;
541         }
542         break;
543       case 'r':
544         if (cfg_cmd_handle_remove(olsr_cfg_get_instance(), db, optarg, &log)) {
545           return_code = 1;
546         }
547         break;
548       case 'g':
549         if (cfg_cmd_handle_get(olsr_cfg_get_instance(), db, optarg, &log)) {
550           return_code = 1;
551         }
552         else {
553           return_code = 0;
554         }
555         break;
556       case 'f':
557         if (cfg_cmd_handle_format(olsr_cfg_get_instance(), optarg)) {
558           return_code = 1;
559         }
560         break;
561
562       default:
563         if (!reload_only) {
564           return_code = 1;
565         }
566         break;
567     }
568   }
569
570   if (return_code == -1 && !loaded_file) {
571     /* try to load default config file if no other loaded */
572     cfg_cmd_handle_load(olsr_cfg_get_instance(), db,
573         olsr_builddata_get()->default_config, NULL);
574   }
575
576   if (return_code == -1) {
577     /* validate configuration */
578     if (cfg_schema_validate(db, false, true, &log)) {
579       return_code = 1;
580     }
581   }
582
583   if (abuf_getlen(&log) > 0) {
584     if (reload_only) {
585       OLSR_WARN(LOG_MAIN, "Cannot reload configuration.\n%s", abuf_getptr(&log));
586     }
587     else {
588       fputs(abuf_getptr(&log), return_code == 0 ? stdout : stderr);
589     }
590   }
591
592   abuf_free(&log);
593
594   return return_code;
595 }
596
597 /**
598  * Call the handle_schema command to give the user the schema of
599  * the configuration including plugins
600  * @return -1 if an error happened, 0 otherwise
601  */
602 static int
603 display_schema(void) {
604   struct autobuf log;
605   int return_code;
606
607   return_code = 0;
608
609   abuf_init(&log);
610   cfg_cmd_clear_state(olsr_cfg_get_instance());
611
612   if (cfg_cmd_handle_schema(olsr_cfg_get_rawdb(), _schema_name, &log)) {
613     return_code = -1;
614   }
615
616   if (abuf_getlen(&log) > 0) {
617     fputs(abuf_getptr(&log), stdout);
618   }
619
620   abuf_free(&log);
621
622   return return_code;
623 }