IBR-DTNSuite  0.10
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>
26 
27 #ifdef HAVE_LIBDAEMON
28 #include <libdaemon/daemon.h>
29 #endif
30 
31 #include <string.h>
32 #include <csignal>
33 #include <set>
34 
35 #include <sys/types.h>
36 #include <syslog.h>
37 #include <pwd.h>
38 #include <unistd.h>
39 
40 #include "NativeDaemon.h"
41 
43 
48 // logging options
50 
51 // error filter
53 
54 // logging filter, everything but debug, notice, err and crit
56 
57 // syslog filter, everything but DEBUG and NOTICE
59 
60 // debug off by default
61 bool _debug = false;
62 
63 // marker if the shutdown was called
65 bool _shutdown = false;
66 
67 // on interruption do this!
68 void sighandler(int signal)
69 {
70  // do not handle further signals if the shutdown is in progress
71  if (_shutdown) return;
72 
73  switch (signal)
74  {
75  case SIGTERM:
76  case SIGINT:
77  {
78  ibrcommon::MutexLock l(_shutdown_cond);
79  _shutdown = true;
80  _shutdown_cond.signal(true);
81  break;
82  }
83 
84  case SIGUSR1:
85  if (!_debug)
86  {
88  _debug = true;
89  }
90 
91  _dtnd.setDebug(99);
92  break;
93  case SIGUSR2:
94  _dtnd.setDebug(0);
95  break;
96  case SIGHUP:
97  _dtnd.reload();
98  break;
99  default:
100  // dummy handler
101  break;
102  }
103 }
104 
106 {
107  // catch process signals
108  signal(SIGINT, sighandler);
109  signal(SIGTERM, sighandler);
110  signal(SIGHUP, sighandler);
111  signal(SIGQUIT, sighandler);
112  signal(SIGUSR1, sighandler);
113  signal(SIGUSR2, sighandler);
114 
115  sigset_t blockset;
116  sigemptyset(&blockset);
117  sigaddset(&blockset, SIGPIPE);
118  ::sigprocmask(SIG_BLOCK, &blockset, NULL);
119 
121 
122  // set default logging tag
124 
125  // enable ring-buffer
127 
128  // enable timestamps in logging if requested
129  if (conf.getLogger().display_timestamps())
130  {
132  }
133 
134  // init syslog
135  ibrcommon::Logger::enableAsync(); // enable asynchronous logging feature (thread-safe)
136  ibrcommon::Logger::enableSyslog("ibrdtn-daemon", LOG_PID, LOG_DAEMON, logsys);
137 
138  if (!conf.getDebug().quiet())
139  {
140  if (conf.getLogger().verbose()) {
141  // add logging to the cout
143  } else {
144  // add logging to the cout
146  }
147 
148  // add logging to the cerr
150  }
151 
152  // activate debugging
153  if (conf.getDebug().enabled() && !conf.getDebug().quiet())
154  {
155  // init logger
157 
159 
160  _debug = true;
161  }
162 
163  // load the configuration file
164  conf.load();
165 
166  try {
167  const ibrcommon::File &lf = conf.getLogger().getLogfile();
170 
171  // initialize the daemon up to runlevel "Routing Extensions"
173 
174 #ifdef HAVE_LIBDAEMON
175  if (conf.getDaemon().daemonize())
176  {
177  /* Send OK to parent process */
178  daemon_retval_send(0);
179  daemon_log(LOG_INFO, "Sucessfully started");
180  }
181 #endif
182 
183  ibrcommon::MutexLock l(_shutdown_cond);
184  while (!_shutdown) _shutdown_cond.wait();
185 
187 
188  // stop the asynchronous logger
190 
191  return 0;
192 }
193 
194 static char* __daemon_pidfile__ = NULL;
195 
196 static const char* __daemon_pid_file_proc__(void) {
197  return __daemon_pidfile__;
198 }
199 
200 int main(int argc, char *argv[])
201 {
202  // create a configuration
204 
205  // load parameter into the configuration
206  conf.params(argc, argv);
207 
208 #ifdef HAVE_LIBDAEMON
209  if (conf.getDaemon().daemonize())
210  {
211  int ret = 0;
212  pid_t pid;
213 
214 #ifdef HAVE_DAEMON_RESET_SIGS
215  /* Reset signal handlers */
216  if (daemon_reset_sigs(-1) < 0) {
217  daemon_log(LOG_ERR, "Failed to reset all signal handlers: %s", strerror(errno));
218  return 1;
219  }
220 
221  /* Unblock signals */
222  if (daemon_unblock_sigs(-1) < 0) {
223  daemon_log(LOG_ERR, "Failed to unblock all signals: %s", strerror(errno));
224  return 1;
225  }
226 #endif
227 
228  /* Set identification string for the daemon for both syslog and PID file */
229  daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
230 
231  /* set the pid file path */
232  try {
233  std::string p = conf.getDaemon().getPidFile().getPath();
234  __daemon_pidfile__ = new char[p.length() + 1];
235  ::strcpy(__daemon_pidfile__, p.c_str());
236  daemon_pid_file_proc = __daemon_pid_file_proc__;
238 
239  /* Check if we are called with -k parameter */
240  if (conf.getDaemon().kill_daemon())
241  {
242  int ret;
243 
244  /* Kill daemon with SIGTERM */
245 
246  /* Check if the new function daemon_pid_file_kill_wait() is available, if it is, use it. */
247  if ((ret = daemon_pid_file_kill_wait(SIGTERM, 5)) < 0)
248  daemon_log(LOG_WARNING, "Failed to kill daemon: %s", strerror(errno));
249 
250  return ret < 0 ? 1 : 0;
251  }
252 
253  /* Check that the daemon is not rung twice a the same time */
254  if ((pid = daemon_pid_file_is_running()) >= 0) {
255  daemon_log(LOG_ERR, "Daemon already running on PID file %u", pid);
256  return 1;
257  }
258 
259  /* Prepare for return value passing from the initialization procedure of the daemon process */
260  if (daemon_retval_init() < 0) {
261  daemon_log(LOG_ERR, "Failed to create pipe.");
262  return 1;
263  }
264 
265  /* Do the fork */
266  if ((pid = daemon_fork()) < 0) {
267 
268  /* Exit on error */
269  daemon_retval_done();
270  return 1;
271 
272  } else if (pid) { /* The parent */
273  int ret;
274 
275  /* Wait for 20 seconds for the return value passed from the daemon process */
276  if ((ret = daemon_retval_wait(20)) < 0) {
277  daemon_log(LOG_ERR, "Could not recieve return value from daemon process: %s", strerror(errno));
278  return 255;
279  }
280 
281  //daemon_log(ret != 0 ? LOG_ERR : LOG_INFO, "Daemon returned %i as return value.", ret);
282  return ret;
283 
284  } else { /* The daemon */
285  /* Close FDs */
286  if (daemon_close_all(-1) < 0) {
287  daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno));
288 
289  /* Send the error condition to the parent process */
290  daemon_retval_send(1);
291  goto finish;
292  }
293 
294  /* Create the PID file */
295  if (daemon_pid_file_create() < 0) {
296  daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno));
297  daemon_retval_send(2);
298  goto finish;
299  }
300 
301  /* Initialize signal handling */
302  if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGUSR1, SIGUSR2, 0) < 0) {
303  daemon_log(LOG_ERR, "Could not register signal handlers (%s).", strerror(errno));
304  daemon_retval_send(3);
305  goto finish;
306  }
307 
308  ret = __daemon_run();
309 
310  finish:
311  /* Do a cleanup */
312  daemon_log(LOG_INFO, "Exiting...");
313  daemon_retval_send(255);
314  daemon_signal_done();
315  daemon_pid_file_remove();
316  }
317 
318  return ret;
319  } else {
320 #endif
321  // run the daemon
322  return __daemon_run();
323 #ifdef HAVE_LIBDAEMON
324  }
325 #endif
326 }