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