5eb040d6e7d6f76a0e376966e714b0c778ac80b4
[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 need_config_reload = false;
30 volatile bool exit_now = false;
31
32 volatile bool caught_sig_usr1 = false;
33 volatile bool caught_sig_usr2 = false;
34 volatile bool caught_sig_rtmin1 = false;
35
36 /**
37  * Checks if a bpdyndnsd process is already running.
38  * @param updater Shared Pointer to updater, needed for logging.
39  * @return 0 if process not running already or pid of already running process.
40  */
41 int check_for_running_process()
42 {
43     ifstream pidfile(PIDFILE);
44     if ( pidfile.is_open() )
45     {
46         int pid;
47         pidfile >> pid;
48         if ( pid > 0 )
49             updater->get_logger()->print_pid_found(pid);
50         else
51             return 0;
52
53         // check if process still running ret_val==-1 -> not runnig, ret_val==0 -> running
54         if ( kill(pid,0) == 0)
55         {
56             updater->get_logger()->print_process_already_running(pid);
57             pidfile.close();
58             return pid;
59         }
60     }
61     pidfile.close();
62     return 0;
63 }
64
65
66 /**
67  * Writes the pid into the pidfile.
68  * @param pid The process's pid.
69  */
70 int write_pidfile(int pid)
71 {
72     ofstream pidfile(PIDFILE);
73     if ( pidfile.is_open() )
74     {
75         pidfile << pid << endl;
76     }
77     else
78     {
79         updater->get_logger()->print_error_opening_rw(PIDFILE);
80         return -1;
81     }
82     pidfile.close();
83     return 0;
84 }
85
86
87 /**
88  * Parent shutdown function
89  * @return 0 if all is fine, -1 otherwise
90  */
91 int shutdown_parent(bool remove_pid, int ret_val)
92 {
93     // starting shutdown_parent
94     updater->get_logger()->print_starting_shutdown_parent();
95
96     // remove pidfile if requested
97     if(remove_pid)
98         unlink(PIDFILE);
99
100     // shutdown parent complete
101     updater->get_logger()->print_shutdown_parent_succeeded();
102
103     // release shared pointer
104     updater.reset();
105
106     exit(ret_val);
107 }
108
109
110 /**
111  * Shutdown function
112  * @return 0 if all is fine, -1 otherwise
113  */
114 int shutdown()
115 {
116     int ret_val = 0;
117
118     // starting shutdown
119     updater->get_logger()->print_starting_shutdown();
120
121     // serialize actual service objects
122     if ( updater->get_service_holder()->serialize_services() != 0 )
123         ret_val = -1;
124
125     // unlink pidfile
126     unlink(PIDFILE);
127
128     // shutdown complete
129     updater->get_logger()->print_shutdown_succeeded();
130
131     // release shared pointer
132     updater.reset();
133
134     return ret_val;
135 }
136
137
138 /**
139  * Signal SIGTERM caught, releasing resources and exit.
140  * @param param Parameter from the signal interface.
141  */
142 void terminate(int param)
143 {
144     updater->get_logger()->print_caught_sigterm();
145     exit_now = true;
146 } /*lint !e715 */
147
148
149 /**
150  * Signal SIGUSR1 caught, switching to offline mode.
151  * @param param Parameter from the signal interface.
152  */
153 void switch_to_offline(int param)
154 {
155     caught_sig_usr1 = true;
156 } /*lint !e715 */
157
158
159 /**
160  * Signal SIGHUP caught, reloading config.
161  * @param param Parameter from the signal interface.
162  */
163 void reload_config(int param)
164 {
165     need_config_reload = true;
166 } /*lint !e715 */
167
168
169 /**
170  * Signal SIGUSR2 caught, switching to online mode.
171  * @param param Parameter from the signal interface.
172  */
173 void switch_to_online(int param)
174 {
175     caught_sig_usr2 = true;
176 } /*lint !e715 */
177
178
179 /**
180  * Signal SIGRTMIN caught, switching to online mode with webcheck enabled.
181  * @param param Parameter from the signal interface.
182  */
183 void switch_to_online_webcheck(int param)
184 {
185     caught_sig_rtmin1 = true;
186 } /*lint !e715 */
187
188
189 /**
190  * Initialize the signals we handle.
191  * @return 0 if all is fine, -1 on error.
192  */
193 int init_signals()
194 {
195     sighandler_t ret_val;
196     ret_val = signal(SIGTERM,terminate);
197     if ( ret_val == SIG_ERR )
198     {
199         updater->get_logger()->print_error_setting_signal("SIGTERM");
200         return -1;
201     }
202     ret_val = signal(SIGUSR1,switch_to_offline);
203     if ( ret_val == SIG_ERR )
204     {
205         updater->get_logger()->print_error_setting_signal("SIGUSR1");
206         return -1;
207     }
208     ret_val = signal(SIGHUP,reload_config);
209     if ( ret_val == SIG_ERR )
210     {
211         updater->get_logger()->print_error_setting_signal("SIGHUP");
212         return -1;
213     }
214     ret_val = signal(SIGUSR2,switch_to_online);
215     if ( ret_val == SIG_ERR )
216     {
217         updater->get_logger()->print_error_setting_signal("SIGUSR2");
218         return -1;
219     }
220     ret_val = signal(SIGRTMIN,switch_to_online_webcheck);
221     if ( ret_val == SIG_ERR )
222     {
223         updater->get_logger()->print_error_setting_signal("SIGRTMIN");
224         return -1;
225     }
226
227     return 0;
228 }
229
230
231 /**
232  * Try to run in daemon mode if enabled in config.
233  * @param daemon_mode True if process should detach to init (run as daemon), false if not detach to init.
234  * @return 0 if all is fine, -1 on error.
235  */
236 int init_daemon_mode(bool daemon_mode)
237 {
238     updater->get_logger()->print_daemon_mode(daemon_mode);
239     if ( daemon_mode == true )
240     {
241         int pid = fork();
242         if ( pid < 0 )
243         {
244             // error fork
245             updater->get_logger()->print_error_fork();
246             return -1;
247         }
248         else if ( pid > 0 )
249         {
250             // parent continues here
251             if ( write_pidfile(pid) != 0 )
252             {
253                 if ( kill(pid,SIGTERM) != 0 )
254                 {
255                     updater->get_logger()->print_error_kill_child(pid);
256                     shutdown_parent(false,-1); /*lint !e534 */
257                 }
258                 else
259                 {
260                     updater->get_logger()->print_child_killed(pid);
261                     shutdown_parent(true,-1); /*lint !e534 */
262                 }
263             }
264             updater->get_logger()->print_runnig_as_daemon(pid);
265             shutdown_parent(false,0); /*lint !e534 */
266         }
267         // child starts here
268     }
269     else
270     {
271         if ( write_pidfile(getpid()) != 0 )
272         {
273             shutdown(); /*lint !e534 */
274             exit(-1);
275         }
276     }
277     return 0;
278 }
279
280 /**
281  * @brief The main part.
282  * @param argc Number of arguments
283  * @param argv Command line arguments
284  * @return 0 if all is fine.
285  */
286 int main(int argc, char *argv[])
287 {
288     // initialize Updater
289     updater = Updater::Ptr(new Updater);
290
291     // load config and initialize helper classes
292     if ( updater->load_config(argc,argv) != 0 )
293         return -1;
294
295     // open pidfile and check for running process
296     if ( check_for_running_process() != 0)
297         return -1;
298
299     // init signal handling
300     if ( init_signals() != 0)
301         return -1;
302
303     // init daemon_mode if enabled
304     if ( init_daemon_mode(updater->get_config()->get_daemon_mode()) != 0 )
305         return -1;
306
307     // Should we start in offline mode?
308     bool is_online = !updater->get_config()->get_start_offline();
309     bool webcheck_enabled = updater->get_config()->get_webcheck_enabled();
310
311     // One shot run if daemon mode is disabled
312     if (updater->get_config()->get_daemon_mode() != 1)
313         exit_now = true;
314
315     // service processing starts here
316     do
317     {
318         // Signal processing
319         if (caught_sig_usr1)
320         {
321             caught_sig_usr1 = false;
322             updater->get_logger()->print_caught_siguser1();
323
324             // Go offline
325             is_online = false;
326         } else if (caught_sig_usr2)
327         {
328             caught_sig_usr2 = false;
329             updater->get_logger()->print_caught_siguser2();
330
331             // Go online
332             is_online = true;
333             webcheck_enabled = false;
334         } else if (caught_sig_rtmin1)
335         {
336             caught_sig_rtmin1 = false;
337             updater->get_logger()->print_caught_sigrtmin();
338
339             // Go online - with webcheck
340             is_online = true;
341             webcheck_enabled = true;
342         }
343
344         // State handling
345         if ( is_online == true )
346         {
347             // Check if webcheck_enabled differs due to caught singnal then set it in config correspondingly
348             if ( updater->get_config()->get_webcheck_enabled() != webcheck_enabled )    /*lint !e731 */
349                 updater->get_config()->set_webcheck_enabled(webcheck_enabled);
350
351             // update all configured services
352             updater->update_services();
353         }
354         else
355         {
356             // We are in offline mode, do nothing, expect printing "offline mode".
357             updater->get_logger()->print_offline_mode();
358         }
359
360         if (need_config_reload)
361         {
362             updater->get_logger()->print_caught_sighup();
363             need_config_reload = false;
364
365             if ( updater->reload_config() != 0 )
366             {
367                 updater->get_logger()->print_conf_reload_failed_exit();
368                 exit(-1);
369             }
370         }
371
372         // Snore, snore... don't hog the cpu if we are in daemon_mode.
373         if ( !exit_now )
374             sleep(10); /*lint !e534 */
375     } while ( !exit_now );
376
377     // Serialize services to save their actual state.
378     if ( shutdown() != 0 )
379         return -1;
380
381     return 0;
382 }