Increase log level on SIGRTMAX. Reset it on SIGHUP
[bpdyndnsd] / src / main.cpp
1 /** @file
2  * @brief The main function.
3  *
4  *
5  *
6  * @copyright Intra2net AG
7  * @license GPLv2
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #define PIDFILE "/var/run/bpdyndnsd/bpdyndnsd.pid"
15
16 #include <iostream>
17 #include <fstream>
18 #include <list>
19 #include <string>
20 #include <boost/foreach.hpp>
21 #include <sys/types.h>
22 #include <signal.h>
23
24 #include "updater.hpp"
25
26 using namespace std;
27
28 Updater::Ptr updater;
29 volatile bool exit_now = false;
30 volatile bool caught_sig_hup = false;
31 volatile bool caught_sig_usr1 = false;
32 volatile bool caught_sig_usr2 = false;
33 volatile bool caught_sig_rtmin = false;
34 volatile bool caught_sig_rtmax = false;
35 volatile bool caught_sig_term = false;
36
37 /**
38  * Checks if a bpdyndnsd process is already running.
39  * @param updater Shared Pointer to updater, needed for logging.
40  * @return 0 if process not running already or pid of already running process.
41  */
42 int check_for_running_process()
43 {
44     ifstream pidfile(PIDFILE);
45     if ( pidfile.is_open() )
46     {
47         int pid;
48         pidfile >> pid;
49         if ( pid > 0 )
50             updater->get_logger()->print_pid_found(pid);
51         else
52             return 0;
53
54         // check if process still running ret_val==-1 -> not runnig, ret_val==0 -> running
55         if ( kill(pid,0) == 0)
56         {
57             updater->get_logger()->print_process_already_running(pid);
58             pidfile.close();
59             return pid;
60         }
61     }
62     pidfile.close();
63     return 0;
64 }
65
66
67 /**
68  * Writes the pid into the pidfile.
69  * @param pid The process's pid.
70  */
71 int write_pidfile(int pid)
72 {
73     ofstream pidfile(PIDFILE);
74     if ( pidfile.is_open() )
75     {
76         pidfile << pid << endl;
77     }
78     else
79     {
80         updater->get_logger()->print_error_opening_rw(PIDFILE);
81         return -1;
82     }
83     pidfile.close();
84     return 0;
85 }
86
87
88 /**
89  * Parent shutdown function
90  * @return 0 if all is fine, -1 otherwise
91  */
92 int shutdown_parent(bool remove_pid, int ret_val)
93 {
94     // starting shutdown_parent
95     updater->get_logger()->print_starting_shutdown_parent();
96
97     // remove pidfile if requested
98     if(remove_pid)
99         unlink(PIDFILE);
100
101     // shutdown parent complete
102     updater->get_logger()->print_shutdown_parent_succeeded();
103
104     // release shared pointer
105     updater.reset();
106
107     exit(ret_val);
108 }
109
110
111 /**
112  * Shutdown function
113  * @return 0 if all is fine, -1 otherwise
114  */
115 int shutdown()
116 {
117     int ret_val = 0;
118
119     // starting shutdown
120     updater->get_logger()->print_starting_shutdown();
121
122     // serialize actual service objects
123     if ( updater->get_service_holder()->serialize_services() != 0 )
124         ret_val = -1;
125
126     // unlink pidfile
127     unlink(PIDFILE);
128
129     // shutdown complete
130     updater->get_logger()->print_shutdown_succeeded();
131
132     // release shared pointer
133     updater.reset();
134
135     return ret_val;
136 }
137
138
139 /**
140  * Signal SIGTERM caught (exit program)
141  * @param param Parameter from the signal interface.
142  */
143 void sigterm_func(int param)
144 {
145     caught_sig_term = true;
146 } /*lint !e715 */
147
148
149 /**
150  * Signal SIGUSR1 caught (switch to offline mode)
151  * @param param Parameter from the signal interface.
152  */
153 void sigusr1_func(int param)
154 {
155     caught_sig_usr1 = true;
156 } /*lint !e715 */
157
158
159 /**
160  * Signal SIGHUP caught (reload config and reset log level)
161  * @param param Parameter from the signal interface.
162  */
163 void sighup_func(int param)
164 {
165     caught_sig_hup = true;
166 } /*lint !e715 */
167
168
169 /**
170  * Signal SIGUSR2 caught (switch to online mode)
171  * @param param Parameter from the signal interface.
172  */
173 void sigusr2_func(int param)
174 {
175     caught_sig_usr2 = true;
176 } /*lint !e715 */
177
178
179 /**
180  * Signal SIGRTMIN caught (switch to online mode with webcheck enabled)
181  * @param param Parameter from the signal interface.
182  */
183 void sigrtmin_func(int param)
184 {
185     caught_sig_rtmin = true;
186 } /*lint !e715 */
187
188
189 /**
190  * Signal SIGRTMAX caught (increase log level)
191  * @param param Parameter from the signal interface.
192  */
193 void sigrtmax_func(int param)
194 {
195     caught_sig_rtmax = true;
196 } /*lint !e715 */
197
198
199 /**
200  * Initialize the signals we handle.
201  * @return 0 if all is fine, -1 on error.
202  */
203 int init_signals()
204 {
205     sighandler_t ret_val;
206     ret_val = signal(SIGTERM, sigterm_func);
207     if ( ret_val == SIG_ERR )
208     {
209         updater->get_logger()->print_error_setting_signal("SIGTERM");
210         return -1;
211     }
212     ret_val = signal(SIGUSR1, sigusr1_func);
213     if ( ret_val == SIG_ERR )
214     {
215         updater->get_logger()->print_error_setting_signal("SIGUSR1");
216         return -1;
217     }
218     ret_val = signal(SIGHUP, sighup_func);
219     if ( ret_val == SIG_ERR )
220     {
221         updater->get_logger()->print_error_setting_signal("SIGHUP");
222         return -1;
223     }
224     ret_val = signal(SIGUSR2, sigusr2_func);
225     if ( ret_val == SIG_ERR )
226     {
227         updater->get_logger()->print_error_setting_signal("SIGUSR2");
228         return -1;
229     }
230     ret_val = signal(SIGRTMIN, sigrtmin_func);
231     if ( ret_val == SIG_ERR )
232     {
233         updater->get_logger()->print_error_setting_signal("SIGRTMIN");
234         return -1;
235     }
236     ret_val = signal(SIGRTMAX, sigrtmax_func);
237     if ( ret_val == SIG_ERR )
238     {
239         updater->get_logger()->print_error_setting_signal("SIGRTMAX");
240         return -1;
241     }
242
243     return 0;
244 }
245
246
247 /**
248  * Try to run in daemon mode if enabled in config.
249  * @param daemon_mode True if process should detach to init (run as daemon), false if not detach to init.
250  * @return 0 if all is fine, -1 on error.
251  */
252 int init_daemon_mode(bool daemon_mode)
253 {
254     updater->get_logger()->print_daemon_mode(daemon_mode);
255     if ( daemon_mode == true )
256     {
257         int pid = fork();
258         if ( pid < 0 )
259         {
260             // error fork
261             updater->get_logger()->print_error_fork();
262             return -1;
263         }
264         else if ( pid > 0 )
265         {
266             // parent continues here
267             if ( write_pidfile(pid) != 0 )
268             {
269                 if ( kill(pid,SIGTERM) != 0 )
270                 {
271                     updater->get_logger()->print_error_kill_child(pid);
272                     shutdown_parent(false,-1); /*lint !e534 */
273                 }
274                 else
275                 {
276                     updater->get_logger()->print_child_killed(pid);
277                     shutdown_parent(true,-1); /*lint !e534 */
278                 }
279             }
280             updater->get_logger()->print_runnig_as_daemon(pid);
281             shutdown_parent(false,0); /*lint !e534 */
282         }
283         // child starts here
284     }
285     else
286     {
287         if ( write_pidfile(getpid()) != 0 )
288         {
289             shutdown(); /*lint !e534 */
290             exit(-1);
291         }
292     }
293     return 0;
294 }
295
296 /**
297  * @brief The main part.
298  * @param argc Number of arguments
299  * @param argv Command line arguments
300  * @return 0 if all is fine.
301  */
302 int main(int argc, char *argv[])
303 {
304     // initialize Updater
305     updater = Updater::Ptr(new Updater);
306
307     // load config and initialize helper classes
308     if ( updater->load_config(argc,argv) != 0 )
309         return -1;
310
311     // open pidfile and check for running process
312     if ( check_for_running_process() != 0)
313         return -1;
314
315     // init signal handling
316     if ( init_signals() != 0)
317         return -1;
318
319     // init daemon_mode if enabled
320     if ( init_daemon_mode(updater->get_config()->get_daemon_mode()) != 0 )
321         return -1;
322
323     // Should we start in offline mode?
324     bool old_online_state = false;
325     bool is_online = !updater->get_config()->get_start_offline();
326     bool webcheck_enabled = updater->get_config()->get_webcheck_enabled();
327
328     // One shot run if daemon mode is disabled
329     if (updater->get_config()->get_daemon_mode() != 1)
330         exit_now = true;
331
332     // Tell the world we are running
333     updater->get_logger()->print_started();
334
335     int original_log_level = updater->get_logger()->get_loglevel();
336
337     // service processing starts here
338     do
339     {
340         // Signal processing
341         if (caught_sig_usr1)
342         {
343             caught_sig_usr1 = false;
344             updater->get_logger()->print_caught_siguser1();
345
346             // Go offline
347             is_online = false;
348         } else if (caught_sig_usr2)
349         {
350             caught_sig_usr2 = false;
351             updater->get_logger()->print_caught_siguser2();
352
353             // Go online
354             is_online = true;
355             webcheck_enabled = false;
356         } else if (caught_sig_rtmin)
357         {
358             caught_sig_rtmin = false;
359             updater->get_logger()->print_caught_sigrtmin();
360
361             // Go online - with webcheck
362             is_online = true;
363             webcheck_enabled = true;
364         } else if (caught_sig_rtmax)
365         {
366             caught_sig_rtmax = false;
367
368             // Increase log level
369             int new_loglevel = updater->get_logger()->get_loglevel() + 1;
370             updater->get_logger()->print_caught_sigrtmax(new_loglevel);
371             updater->get_logger()->set_loglevel(new_loglevel);
372         } else if (caught_sig_term)
373         {
374             caught_sig_term = false;
375             updater->get_logger()->print_caught_sigterm();
376
377             exit_now = true;
378         } else if (caught_sig_hup)
379         {
380             caught_sig_hup = false;
381             updater->get_logger()->print_caught_sighup();
382
383             if ( updater->reload_config() != 0 )
384             {
385                 updater->get_logger()->print_conf_reload_failed_exit();
386                 exit(-1);
387             }
388
389             // Reset log level to startup log level in case it got elevated by SIGRTMAX
390             updater->get_logger()->set_loglevel(original_log_level);
391         }
392
393         // State handling
394         if ( is_online == true )
395         {
396             // Check if webcheck_enabled differs due to caught singnal then set it in config correspondingly
397             if ( updater->get_config()->get_webcheck_enabled() != webcheck_enabled )    /*lint !e731 */
398                 updater->get_config()->set_webcheck_enabled(webcheck_enabled);
399
400             // update all configured services
401             updater->update_services(is_online != old_online_state);
402         }
403         else
404         {
405             // We are in offline mode, do nothing, expect printing "offline mode".
406             updater->get_logger()->print_offline_mode();
407         }
408
409         // Keep old online state so we can determine
410         // if we switched from offline to online
411         old_online_state = is_online;
412
413         // Snore, snore... don't hog the cpu if we are in daemon_mode.
414         if ( !exit_now )
415             sleep(10); /*lint !e534 */
416     } while ( !exit_now );
417
418     // Serialize services to save their actual state.
419     if ( shutdown() != 0 )
420         return -1;
421
422     return 0;
423 }