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