Adjusted exit code on terminate through SIGTERM.
[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
20 #include <iostream>
21 #include <list>
22 #include <string>
23
24 #include <boost/foreach.hpp>
25
26 #include "updater.cpp"
27 #include "config.cpp"
28 #include "logger.cpp"
29
30 #include "service.cpp"
31
32 #include "dhs.cpp"
33 #include "ods.cpp"
34
35 #include <sys/types.h>
36 #include <signal.h>
37
38
39 using namespace std;
40
41 typedef boost::shared_ptr<Updater> UpdaterPtr;
42
43 UpdaterPtr updater;
44 bool online_mode = 1;
45
46 /**
47  * Checks if a bpdyndnsd process is already running.
48  * @param updater Shared Pointer to updater, needed for logging.
49  * @return 0 if process not running already or pid of already running process.
50  */
51 int check_for_running_process()
52 {
53     ifstream pidfile(PIDFILE);
54     if ( pidfile.is_open() )
55     {
56         int pid;
57         pidfile >> pid;
58         if ( pid > 0 )
59             updater->get_logger()->print_pid_found(pid);
60         else
61             return 0;
62
63         // check if process still running ret_val==-1 -> not runnig, ret_val==0 -> running
64         if ( kill(pid,0) == 0)
65         {
66             updater->get_logger()->print_process_already_running(pid);
67             pidfile.close();
68             return pid;
69         }
70     }
71     pidfile.close();
72     return 0;
73 }
74
75
76 /**
77  * Writes the pid into the pidfile.
78  * @param pid The process's pid.
79  */
80 void write_pidfile(int pid)
81 {
82     ofstream pidfile(PIDFILE);
83     if ( pidfile.is_open() )
84     {
85         pidfile << pid << endl;
86     }
87     pidfile.close();
88 }
89
90
91 /**
92  * Signal SIGTERM caught, releasing resources and exit.
93  * @param param Parameter from the signal interface.
94  */
95 void terminate(int param)
96 {
97     updater->get_logger()->print_caught_sigterm();
98     updater.reset();
99     exit(0);
100 }
101
102
103 /**
104  * Signal SIGUSR1 caught, switching to offline mode.
105  * @param param Parameter from the signal interface.
106  */
107 void switch_to_offline(int param)
108 {
109     updater->get_logger()->print_caught_siguser1();
110     online_mode = 0;
111 }
112
113
114 /**
115  * Signal SIGHUP caught, reloading config and switching to online mode.
116  * @param param Parameter from the signal interface.
117  */
118 void reload_config(int param)
119 {
120     updater->get_logger()->print_caught_sighup();
121     updater->reload_config();
122     online_mode = 1;
123 }
124
125
126 /**
127  * Initialize the signals we handle.
128  */
129 int init_signals()
130 {
131     sighandler_t ret_val;
132     ret_val = signal(SIGTERM,terminate);
133     if ( ret_val == SIG_ERR )
134         return -1;
135     ret_val = signal(SIGUSR1,switch_to_offline);
136     if ( ret_val == SIG_ERR )
137         return -1;
138     ret_val = signal(SIGHUP,reload_config);
139     if ( ret_val == SIG_ERR )
140         return -1;
141
142     return 0;
143 }
144
145
146 /**
147  * @brief The main part.
148  * @param argc Number of arguments
149  * @param argv Command line arguments
150  * @return 0 if all is fine.
151  */
152 int main(int argc, char *argv[])
153 {
154     // initialize Updater
155     UpdaterPtr _updater(new Updater);
156     updater = _updater;
157     _updater.reset();
158
159     // load the cmd options
160     if ( updater->init_config_from_cmd(argc,argv) != 0 )
161         return 0;
162
163     // load the config and service files
164     if ( updater->init_config_from_files() != 0 )
165         return 0;
166
167     // open pidfile and check for running process
168     if ( check_for_running_process() != 0)
169         return 0;
170
171     // init signal handling
172     if ( init_signals() != 0)
173     {
174         updater->get_logger()->print_error_setting_signal();
175         return 0;
176     }
177
178     // initialize daemon mode if configured
179     updater->get_logger()->print_daemon_mode(updater->get_config()->get_daemon_mode());
180     if ( updater->get_config()->get_daemon_mode() == 1 )
181     {
182         int pid = fork();
183         if ( pid < 0 )
184         {
185             // error fork
186             updater->get_logger()->print_error_fork();
187             return 0;
188         }
189         else if ( pid > 0 )
190         {
191             // parent
192             write_pidfile(pid);
193             updater->get_logger()->print_runnig_as_daemon(pid);
194             return 0;
195         }
196         // child starts here
197     }
198
199
200     // service processing starts here
201     do
202     {
203         if ( online_mode == 1 )
204         {
205             // update all configured services
206             updater->update_services();
207         }
208         else
209         {
210             updater->get_logger()->print_offline_mode();
211         }
212
213         if ( updater->get_config()->get_daemon_mode() == 1 )
214             sleep(10);  // TODO: in a final release, correct the sleep value to something suitable
215
216     }while ( updater->get_config()->get_daemon_mode() == 1 );
217
218     return 0;
219 }