Separated init of daemon mode into extra function.
[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 VERSION     0
15 #define REVISION    1
16 #define RELEASE     0
17
18 #define PIDFILE "/var/run/bpdyndnsd.pid"
19 #define OBJECT_FILE "/home/bjoern/intranator/bpdyndnsd/objects.ser"
20
21 #include <iostream>
22 #include <fstream>
23 #include <list>
24 #include <string>
25 #include <boost/foreach.hpp>
26 #include <sys/types.h>
27 #include <signal.h>
28
29 #include "updater.h"
30
31 #include "config.cpp"
32 #include "dhs.cpp"
33 #include "logger.cpp"
34 #include "ods.cpp"
35 #include "service.cpp"
36 #include "serviceholder.cpp"
37 #include "updater.cpp"
38
39
40 using namespace std;
41
42 Updater::Ptr updater;
43 bool is_online = true;
44
45 /**
46  * Checks if a bpdyndnsd process is already running.
47  * @param updater Shared Pointer to updater, needed for logging.
48  * @return 0 if process not running already or pid of already running process.
49  */
50 int check_for_running_process()
51 {
52     ifstream pidfile(PIDFILE);
53     if ( pidfile.is_open() )
54     {
55         int pid;
56         pidfile >> pid;
57         if ( pid > 0 )
58             updater->get_logger()->print_pid_found(pid);
59         else
60             return 0;
61
62         // check if process still running ret_val==-1 -> not runnig, ret_val==0 -> running
63         if ( kill(pid,0) == 0)
64         {
65             updater->get_logger()->print_process_already_running(pid);
66             pidfile.close();
67             return pid;
68         }
69     }
70     pidfile.close();
71     return 0;
72 }
73
74
75 /**
76  * Writes the pid into the pidfile.
77  * @param pid The process's pid.
78  */
79 int write_pidfile(int pid)
80 {
81     ofstream pidfile(PIDFILE);
82     if ( pidfile.is_open() )
83     {
84         pidfile << pid << endl;
85     }
86     else
87     {
88         updater->get_logger()->print_error_opening_rw(PIDFILE);
89         return -1;
90     }
91     pidfile.close();
92     return 0;
93 }
94
95
96 /**
97  * Signal SIGTERM caught, releasing resources and exit.
98  * @param param Parameter from the signal interface.
99  */
100 void terminate(int param)
101 {
102     updater->get_logger()->print_caught_sigterm();
103
104     // unfortunately we can't call serialize_services in any destructor
105     // cause some singleton are already destroyed !?!
106     if ( updater->get_config()->serialize_services() != 0 )
107     {
108         updater.reset();
109         exit(-1);
110     }
111     updater.reset();
112     exit(0);
113 }
114
115
116
117 /**
118  * Signal SIGUSR1 caught, switching to offline mode.
119  * @param param Parameter from the signal interface.
120  */
121 void switch_to_offline(int param)
122 {
123     updater->get_logger()->print_caught_siguser1();
124     is_online = false;
125 }
126
127
128 /**
129  * Signal SIGHUP caught, reloading config and switching to online mode.
130  * @param param Parameter from the signal interface.
131  */
132 void reload_config(int param)
133 {
134     updater->get_logger()->print_caught_sighup();
135     if ( updater->reload_config() != 0 )
136         exit(-1);
137     is_online = true;
138 }
139
140
141 /**
142  * Initialize the signals we handle.
143  */
144 int init_signals()
145 {
146     sighandler_t ret_val;
147     ret_val = signal(SIGTERM,terminate);
148     if ( ret_val == SIG_ERR )
149     {
150         updater->get_logger()->print_error_setting_signal("SIGTERM");
151         return -1;
152     }
153     ret_val = signal(SIGUSR1,switch_to_offline);
154     if ( ret_val == SIG_ERR )
155     {
156         updater->get_logger()->print_error_setting_signal("SIGUSR1");
157         return -1;
158     }
159     ret_val = signal(SIGHUP,reload_config);
160     if ( ret_val == SIG_ERR )
161     {
162         updater->get_logger()->print_error_setting_signal("SIGHUP");
163         return -1;
164     }
165
166     return 0;
167 }
168
169
170 /**
171  * Try to run in daemon mode if enabled in config.
172  * @param daemon_mode True if process should detach to init (run as daemon), false if not detach to init.
173  * @return 0 if all is fine, -1 on error.
174  */
175 int init_daemon_mode(bool daemon_mode)
176 {
177     updater->get_logger()->print_daemon_mode(daemon_mode);
178     if ( daemon_mode == true )
179     {
180         int pid = fork();
181         if ( pid < 0 )
182         {
183             // error fork
184             updater->get_logger()->print_error_fork();
185             return -1;
186         }
187         else if ( pid > 0 )
188         {
189             // parent continues here
190             if ( write_pidfile(pid) != 0 )
191             {
192                 if ( kill(pid,SIGTERM) != 0 )
193                     updater->get_logger()->print_error_kill_child(pid);
194                 else
195                     updater->get_logger()->print_child_killed(pid);
196                 exit(-1);
197             }
198             updater->get_logger()->print_runnig_as_daemon(pid);
199             exit(0);
200         }
201         // child starts here
202     }
203     return 0;
204 }
205
206 /**
207  * @brief The main part.
208  * @param argc Number of arguments
209  * @param argv Command line arguments
210  * @return 0 if all is fine.
211  */
212 int main(int argc, char *argv[])
213 {
214     // initialize Updater
215     Updater::Ptr _updater(new Updater);
216     updater = _updater;
217     _updater.reset();
218
219     // load the cmd options
220     if ( updater->init_config_from_cmd(argc,argv) != 0 )
221         return -1;
222
223     // load the config and service files
224     if ( updater->init_config_from_files() != 0 )
225         return -1;
226
227     // open pidfile and check for running process
228     if ( check_for_running_process() != 0)
229         return -1;
230
231     // init signal handling
232     if ( init_signals() != 0)
233         return -1;
234
235     // init daemon_mode if enabled
236     if ( init_daemon_mode(updater->get_config()->get_daemon_mode()) != 0 )
237         return -1;
238
239     // service processing starts here
240     do
241     {
242         if ( is_online == true )
243         {
244             // update all configured services
245             updater->update_services();
246         }
247         else
248         {
249             updater->get_logger()->print_offline_mode();
250         }
251
252         if ( updater->get_config()->get_daemon_mode() == 1 )
253             sleep(5);
254
255     }while ( updater->get_config()->get_daemon_mode() == 1 );
256
257
258     // serialize services to save their actual status
259     if ( updater->get_config()->serialize_services() != 0 )
260         return -1;
261
262     return 0;
263 }