Do the SIGTERM cleanup outside the signal handler
[bpdyndnsd] / src / main.cpp
CommitLineData
b1be615b
BS
1/** @file
2 * @brief The main function.
3 *
4 *
5 *
6 * @copyright Intra2net AG
7 * @license GPLv2
8*/
4545a371
BS
9
10#ifdef HAVE_CONFIG_H
11#include <config.h>
12#endif
13
c47386eb 14#define PIDFILE "/var/run/bpdyndnsd/bpdyndnsd.pid"
388f4ab0 15
4545a371 16#include <iostream>
88a594e8 17#include <fstream>
4545a371
BS
18#include <list>
19#include <string>
4545a371 20#include <boost/foreach.hpp>
88a594e8
BS
21#include <sys/types.h>
22#include <signal.h>
23
4de6a9b8 24#include "updater.hpp"
4545a371 25
4545a371
BS
26using namespace std;
27
88a594e8 28Updater::Ptr updater;
a292c8c4
TJ
29volatile bool is_online = false;
30volatile bool webcheck_enabled = false;
4f4a6039 31volatile bool need_config_reload = false;
c5a6b1fe 32volatile bool exit_now = false;
c5675c01 33
4545a371 34/**
388f4ab0
BS
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 */
c5675c01 39int check_for_running_process()
388f4ab0
BS
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
c5675c01
BS
63
64/**
65 * Writes the pid into the pidfile.
66 * @param pid The process's pid.
67 */
667c672c 68int write_pidfile(int pid)
388f4ab0
BS
69{
70 ofstream pidfile(PIDFILE);
71 if ( pidfile.is_open() )
72 {
73 pidfile << pid << endl;
74 }
667c672c
BS
75 else
76 {
77 updater->get_logger()->print_error_opening_rw(PIDFILE);
78 return -1;
79 }
388f4ab0 80 pidfile.close();
667c672c 81 return 0;
388f4ab0
BS
82}
83
c5675c01
BS
84
85/**
e304c27b
BS
86 * Parent shutdown function
87 * @return 0 if all is fine, -1 otherwise
88 */
89int 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 */
112int 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/**
c5675c01
BS
137 * Signal SIGTERM caught, releasing resources and exit.
138 * @param param Parameter from the signal interface.
139 */
140void terminate(int param)
141{
142 updater->get_logger()->print_caught_sigterm();
c5a6b1fe 143 exit_now = true;
08a5a621 144} /*lint !e715 */
c5675c01
BS
145
146
147/**
148 * Signal SIGUSR1 caught, switching to offline mode.
149 * @param param Parameter from the signal interface.
150 */
151void switch_to_offline(int param)
152{
8bca3c5d 153 updater->get_logger()->print_caught_siguser1();
98dd88bd 154 is_online = false;
08a5a621 155} /*lint !e715 */
c5675c01
BS
156
157
158/**
64ff14c3 159 * Signal SIGHUP caught, reloading config.
39acb828 160 * @param param Parameter from the signal interface.
c5675c01
BS
161 */
162void reload_config(int param)
163{
4f4a6039 164 need_config_reload = true;
64ff14c3
BS
165} /*lint !e715 */
166
167
168/**
169 * Signal SIGUSR2 caught, switching to online mode.
170 * @param param Parameter from the signal interface.
171 */
172void switch_to_online(int param)
173{
174 updater->get_logger()->print_caught_siguser2();
98dd88bd 175 is_online = true;
64ff14c3
BS
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 */
184void switch_to_online_webcheck(int param)
185{
186 updater->get_logger()->print_caught_sigrtmin();
187 is_online = true;
188 webcheck_enabled = true;
08a5a621 189} /*lint !e715 */
c5675c01
BS
190
191
192/**
193 * Initialize the signals we handle.
e0080b78 194 * @return 0 if all is fine, -1 on error.
c5675c01 195 */
8bca3c5d 196int init_signals()
c5675c01 197{
8bca3c5d
BS
198 sighandler_t ret_val;
199 ret_val = signal(SIGTERM,terminate);
200 if ( ret_val == SIG_ERR )
667c672c
BS
201 {
202 updater->get_logger()->print_error_setting_signal("SIGTERM");
8bca3c5d 203 return -1;
667c672c 204 }
8bca3c5d
BS
205 ret_val = signal(SIGUSR1,switch_to_offline);
206 if ( ret_val == SIG_ERR )
667c672c
BS
207 {
208 updater->get_logger()->print_error_setting_signal("SIGUSR1");
8bca3c5d 209 return -1;
667c672c 210 }
8bca3c5d
BS
211 ret_val = signal(SIGHUP,reload_config);
212 if ( ret_val == SIG_ERR )
667c672c
BS
213 {
214 updater->get_logger()->print_error_setting_signal("SIGHUP");
8bca3c5d 215 return -1;
667c672c 216 }
64ff14c3
BS
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 }
5ac72dd8
BS
229
230 return 0;
c5675c01
BS
231}
232
233
388f4ab0 234/**
584b9407
BS
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 */
239int 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 )
e304c27b 257 {
584b9407 258 updater->get_logger()->print_error_kill_child(pid);
557b6f56 259 shutdown_parent(false,-1); /*lint !e534 */
e304c27b 260 }
584b9407 261 else
e304c27b 262 {
584b9407 263 updater->get_logger()->print_child_killed(pid);
557b6f56 264 shutdown_parent(true,-1); /*lint !e534 */
e304c27b 265 }
584b9407
BS
266 }
267 updater->get_logger()->print_runnig_as_daemon(pid);
557b6f56 268 shutdown_parent(false,0); /*lint !e534 */
584b9407
BS
269 }
270 // child starts here
271 }
e304c27b
BS
272 else
273 {
274 if ( write_pidfile(getpid()) != 0 )
275 {
557b6f56 276 shutdown(); /*lint !e534 */
e304c27b
BS
277 exit(-1);
278 }
279 }
584b9407
BS
280 return 0;
281}
282
283/**
b1be615b
BS
284 * @brief The main part.
285 * @param argc Number of arguments
286 * @param argv Command line arguments
287 * @return 0 if all is fine.
4545a371
BS
288 */
289int main(int argc, char *argv[])
290{
38060291 291 // initialize Updater
c3c84086 292 updater = Updater::Ptr(new Updater);
38060291 293
efbde536
BS
294 // load config and initialize helper classes
295 if ( updater->load_config(argc,argv) != 0 )
667c672c 296 return -1;
4545a371 297
388f4ab0 298 // open pidfile and check for running process
c5675c01 299 if ( check_for_running_process() != 0)
667c672c 300 return -1;
3434b35f 301
c5675c01 302 // init signal handling
8bca3c5d 303 if ( init_signals() != 0)
667c672c 304 return -1;
254bbf53 305
584b9407
BS
306 // init daemon_mode if enabled
307 if ( init_daemon_mode(updater->get_config()->get_daemon_mode()) != 0 )
308 return -1;
388f4ab0 309
dbaf4b42
BS
310 // Should we start in offline mode?
311 is_online = !updater->get_config()->get_start_offline();
46fffdd6 312 webcheck_enabled = updater->get_config()->get_webcheck_enabled();
dbaf4b42 313
c5a6b1fe
TJ
314 // One shot run if daemon mode is disabled
315 if (updater->get_config()->get_daemon_mode() != 1)
316 exit_now = true;
317
388f4ab0
BS
318 // service processing starts here
319 do
320 {
98dd88bd 321 if ( is_online == true )
c5675c01 322 {
46fffdd6 323 // Check if webcheck_enabled differs due to caught singnal then set it in config correspondingly
43f4565e 324 if ( updater->get_config()->get_webcheck_enabled() != webcheck_enabled ) /*lint !e731 */
46fffdd6
BS
325 updater->get_config()->set_webcheck_enabled(webcheck_enabled);
326
c5675c01
BS
327 // update all configured services
328 updater->update_services();
329 }
8bca3c5d
BS
330 else
331 {
50d63110 332 // We are in offline mode, do nothing, expect printing "offline mode".
8bca3c5d
BS
333 updater->get_logger()->print_offline_mode();
334 }
388f4ab0 335
4f4a6039
TJ
336 if (need_config_reload)
337 {
c5a6b1fe 338 updater->get_logger()->print_caught_sighup();
4f4a6039
TJ
339 need_config_reload = false;
340
341 if ( updater->reload_config() != 0 )
5b3f3f54
TJ
342 {
343 updater->get_logger()->print_conf_reload_failed_exit();
4f4a6039 344 exit(-1);
5b3f3f54 345 }
4f4a6039
TJ
346 }
347
a7beeb20 348 // Snore, snore... don't hog the cpu if we are in daemon_mode.
c5a6b1fe 349 if ( !exit_now )
557b6f56 350 sleep(10); /*lint !e534 */
c5a6b1fe 351 } while ( !exit_now );
4545a371 352
50d63110 353 // Serialize services to save their actual state.
e304c27b 354 if ( shutdown() != 0 )
667c672c 355 return -1;
2bc1878a 356
4545a371
BS
357 return 0;
358}