Added and improved some error handling.
[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  * @brief The main part.
172  * @param argc Number of arguments
173  * @param argv Command line arguments
174  * @return 0 if all is fine.
175  */
176 int main(int argc, char *argv[])
177 {
178     // initialize Updater
179     Updater::Ptr _updater(new Updater);
180     updater = _updater;
181     _updater.reset();
182
183     // load the cmd options
184     if ( updater->init_config_from_cmd(argc,argv) != 0 )
185         return -1;
186
187     // load the config and service files
188     if ( updater->init_config_from_files() != 0 )
189         return -1;
190
191     // open pidfile and check for running process
192     if ( check_for_running_process() != 0)
193         return -1;
194
195     // init signal handling
196     if ( init_signals() != 0)
197         return -1;
198
199     // initialize daemon mode if configured TODO: into separate function
200     updater->get_logger()->print_daemon_mode(updater->get_config()->get_daemon_mode());
201     if ( updater->get_config()->get_daemon_mode() == 1 )
202     {
203         int pid = fork();
204         if ( pid < 0 )
205         {
206             // error fork
207             updater->get_logger()->print_error_fork();
208             return -1;
209         }
210         else if ( pid > 0 )
211         {
212             // parent
213             if ( write_pidfile(pid) != 0 )
214             {
215                 if ( kill(pid,SIGTERM) != 0 )
216                     updater->get_logger()->print_error_kill_child(pid);
217                 return -1;
218             }
219             updater->get_logger()->print_runnig_as_daemon(pid);
220             return 0;
221         }
222         // child starts here
223     }
224
225     // service processing starts here
226     do
227     {
228         if ( is_online == true )
229         {
230             // update all configured services
231             updater->update_services();
232         }
233         else
234         {
235             updater->get_logger()->print_offline_mode();
236         }
237
238         if ( updater->get_config()->get_daemon_mode() == 1 )
239             sleep(10);  // TODO: in a final release, correct the sleep value to something suitable
240
241     }while ( updater->get_config()->get_daemon_mode() == 1 );
242
243
244     // serialize services to save their actual status
245     if ( updater->get_config()->serialize_services() != 0 )
246         return -1;
247
248     return 0;
249 }