IBR-DTNSuite  0.12
Main.cpp
Go to the documentation of this file.
1 /*
2  * Main.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "config.h"
23 #include "Configuration.h"
24 #include <ibrcommon/Logger.h>
25 #include <ibrcommon/data/File.h>
27 
28 #ifdef HAVE_LIBDAEMON
29 #include <libdaemon/daemon.h>
30 #endif
31 
32 #include <string.h>
33 #include <set>
34 
35 #include <sys/types.h>
36 #include <unistd.h>
37 
38 #ifdef __WIN32__
39 #define LOG_PID 0
40 #define LOG_DAEMON 0
41 #else
42 #include <syslog.h>
43 #include <pwd.h>
44 #endif
45 
46 #include "NativeDaemon.h"
47 
49 
54 // logging options
56 
57 // error filter
59 
60 // logging filter, everything but debug, notice, err and crit
62 
63 // syslog filter, everything but DEBUG and NOTICE
65 
66 // debug off by default
67 bool _debug = false;
68 
69 // marker if the shutdown was called
71 bool _shutdown = false;
72 
73 // on interruption do this!
74 void func_sighandler(int signal)
75 {
76  // do not handle further signals if the shutdown is in progress
77  if (_shutdown) return;
78 
79  switch (signal)
80  {
81  case SIGTERM:
82  case SIGINT:
83  {
84  ibrcommon::MutexLock l(_shutdown_cond);
85  _shutdown = true;
86  _shutdown_cond.signal(true);
87  break;
88  }
89 #ifndef __WIN32__
90  case SIGUSR1:
91  if (!_debug)
92  {
94  _debug = true;
95  }
96 
97  _dtnd.setDebug(99);
98  break;
99  case SIGUSR2:
100  _dtnd.setDebug(0);
101  break;
102  case SIGHUP:
103  _dtnd.reload();
104  break;
105 #endif
106  default:
107  // dummy handler
108  break;
109  }
110 }
111 
113 {
114  // catch process signals
116  sighandler.handle(SIGINT);
117  sighandler.handle(SIGTERM);
118 #ifndef __WIN32__
119  sighandler.handle(SIGHUP);
120  sighandler.handle(SIGQUIT);
121  sighandler.handle(SIGUSR1);
122  sighandler.handle(SIGUSR2);
123 
124  sigset_t blockset;
125  sigemptyset(&blockset);
126  sigaddset(&blockset, SIGPIPE);
127  ::sigprocmask(SIG_BLOCK, &blockset, NULL);
128 #endif
129 
130  // initialize signal handler
131  sighandler.initialize();
132 
134 
135  // set default logging tag
137 
138  // enable ring-buffer
140 
141  // enable timestamps in logging if requested
142  if (conf.getLogger().display_timestamps())
143  {
145  }
146 
147  // init syslog
148  ibrcommon::Logger::enableAsync(); // enable asynchronous logging feature (thread-safe)
149  ibrcommon::Logger::enableSyslog("ibrdtn-daemon", LOG_PID, LOG_DAEMON, logsys);
150 
151  if (!conf.getDebug().quiet())
152  {
153  if (conf.getLogger().verbose()) {
154  // add logging to the cout
156  } else {
157  // add logging to the cout
159  }
160 
161  // add logging to the cerr
163  }
164 
165  // activate debugging
166  if (conf.getDebug().enabled() && !conf.getDebug().quiet())
167  {
168  // init logger
170 
172 
173  _debug = true;
174  }
175 
176  // load the configuration file
177  conf.load(true);
178 
179  try {
180  const ibrcommon::File &lf = conf.getLogger().getLogfile();
183 
184  // initialize the daemon up to runlevel "Routing Extensions"
186 
187 #ifdef HAVE_LIBDAEMON
188  if (conf.getDaemon().daemonize())
189  {
190  /* Send OK to parent process */
191  daemon_retval_send(0);
192  daemon_log(LOG_INFO, "Sucessfully started");
193  }
194 #endif
195 
196  ibrcommon::MutexLock l(_shutdown_cond);
197  while (!_shutdown) _shutdown_cond.wait();
198 
200 
201  // stop the asynchronous logger
203 
204  return 0;
205 }
206 
207 static char* __daemon_pidfile__ = NULL;
208 
209 static const char* __daemon_pid_file_proc__(void) {
210  return __daemon_pidfile__;
211 }
212 
213 int main(int argc, char *argv[])
214 {
215  // create a configuration
217 
218  // load parameter into the configuration
219  conf.params(argc, argv);
220 
221 #ifdef HAVE_LIBDAEMON
222  if (conf.getDaemon().daemonize())
223  {
224  int ret = 0;
225  pid_t pid;
226 
227 #ifdef HAVE_DAEMON_RESET_SIGS
228  /* Reset signal handlers */
229  if (daemon_reset_sigs(-1) < 0) {
230  daemon_log(LOG_ERR, "Failed to reset all signal handlers: %s", strerror(errno));
231  return 1;
232  }
233 
234  /* Unblock signals */
235  if (daemon_unblock_sigs(-1) < 0) {
236  daemon_log(LOG_ERR, "Failed to unblock all signals: %s", strerror(errno));
237  return 1;
238  }
239 #endif
240 
241  /* Set identification string for the daemon for both syslog and PID file */
242  daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
243 
244  /* set the pid file path */
245  try {
246  std::string p = conf.getDaemon().getPidFile().getPath();
247  __daemon_pidfile__ = new char[p.length() + 1];
248  ::strcpy(__daemon_pidfile__, p.c_str());
249  daemon_pid_file_proc = __daemon_pid_file_proc__;
251 
252  /* Check if we are called with -k parameter */
253  if (conf.getDaemon().kill_daemon())
254  {
255  int ret;
256 
257  /* Kill daemon with SIGTERM */
258 
259  /* Check if the new function daemon_pid_file_kill_wait() is available, if it is, use it. */
260  if ((ret = daemon_pid_file_kill_wait(SIGTERM, 5)) < 0)
261  daemon_log(LOG_WARNING, "Failed to kill daemon: %s", strerror(errno));
262 
263  return ret < 0 ? 1 : 0;
264  }
265 
266  /* Check that the daemon is not rung twice a the same time */
267  if ((pid = daemon_pid_file_is_running()) >= 0) {
268  daemon_log(LOG_ERR, "Daemon already running on PID file %u", pid);
269  return 1;
270  }
271 
272  /* Prepare for return value passing from the initialization procedure of the daemon process */
273  if (daemon_retval_init() < 0) {
274  daemon_log(LOG_ERR, "Failed to create pipe.");
275  return 1;
276  }
277 
278  /* Do the fork */
279  if ((pid = daemon_fork()) < 0) {
280 
281  /* Exit on error */
282  daemon_retval_done();
283  return 1;
284 
285  } else if (pid) { /* The parent */
286  int ret;
287 
288  /* Wait for 20 seconds for the return value passed from the daemon process */
289  if ((ret = daemon_retval_wait(20)) < 0) {
290  daemon_log(LOG_ERR, "Could not recieve return value from daemon process: %s", strerror(errno));
291  return 255;
292  }
293 
294  //daemon_log(ret != 0 ? LOG_ERR : LOG_INFO, "Daemon returned %i as return value.", ret);
295  return ret;
296 
297  } else { /* The daemon */
298  /* Close FDs */
299  if (daemon_close_all(-1) < 0) {
300  daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
301 
302  /* Send the error condition to the parent process */
303  daemon_retval_send(1);
304  goto finish;
305  }
306 
307  /* Create the PID file */
308  if (daemon_pid_file_create() < 0) {
309  daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
310  daemon_retval_send(2);
311  goto finish;
312  }
313 
314  /* Initialize signal handling */
315  if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGUSR1, SIGUSR2, 0) < 0) {
316  daemon_log(LOG_ERR, "Could not register signal handlers (%s).", strerror(errno));
317  daemon_retval_send(3);
318  goto finish;
319  }
320 
321  ret = __daemon_run();
322 
323  finish:
324  /* Do a cleanup */
325  daemon_log(LOG_INFO, "Exiting...");
326  daemon_retval_send(255);
327  daemon_signal_done();
328  daemon_pid_file_remove();
329  }
330 
331  return ret;
332  } else {
333 #endif
334  // run the daemon
335  return __daemon_run();
336 #ifdef HAVE_LIBDAEMON
337  }
338 #endif
339 }