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