4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \brief Daemon non-inline non-template implementation */
30 #include <sys/types.h>
40 #include <boost/algorithm/string/predicate.hpp>
41 #include <boost/algorithm/string/trim.hpp>
42 #include <boost/format.hpp>
43 #include "../Exception.hh"
44 #include "../membind.hh"
45 #include "../Backtrace.hh"
50 //#include "Daemon.mpp"
52 ///////////////////////////////cc.p////////////////////////////////////////
54 #define LIBC_CALL(fn, args) if (fn args < 0) \
55 SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
57 #define LIBC_CALL_RV(var, fn, args) \
58 int var (fn args); if (var < 0) SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
60 ///////////////////////////////////////////////////////////////////////////
63 prefix_ senf::Daemon::~Daemon()
65 if (pidfileCreated_) {
67 LIBC_CALL( ::unlink, (pidfile_.c_str()) );
68 } catch (Exception e) {
69 // e << "; could not unlink " << pidfile_.c_str();
75 prefix_ void senf::Daemon::daemonize(bool v)
80 prefix_ bool senf::Daemon::daemon()
85 prefix_ int senf::Daemon::argc()
90 prefix_ char ** senf::Daemon::argv()
95 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
98 case StdOut : stdoutLog_ = path; break;
99 case StdErr : stderrLog_ = path; break;
100 case Both : stdoutLog_ = path; stderrLog_ = path; break;
105 prefix_ void senf::Daemon::openLog()
108 if (! stdoutLog_.empty()) {
109 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
111 SENF_THROW_SYSTEM_EXCEPTION("")
112 << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout.";
115 if (stderrLog_ == stdoutLog_)
117 else if (! stderrLog_.empty()) {
118 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
120 SENF_THROW_SYSTEM_EXCEPTION("")
121 << " Could not open \"" << stderrLog_ << "\" for redirecting stderr.";
126 prefix_ void senf::Daemon::pidFile(std::string const & f)
132 bool signaled (false);
138 prefix_ void senf::Daemon::detach()
140 if (daemonize_ && ! detached_) {
142 // To ensure all data is written to the console log file in the correct order, we suspend
143 // execution here until the parent process tells us to continue via SIGUSR1: We block
144 // SIGUSR1 and install our own signal handler saving the old handler and signal mask. Then
145 // we close stdin/stderr which will send a HUP condition to the parent process. We wait for
146 // SIGUSR1 and reinstall the old signal mask and action.
149 ::sigemptyset(&usrsig);
150 LIBC_CALL( ::sigaddset, (&usrsig, SIGUSR1) );
151 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &usrsig, &oldsig) );
152 struct ::sigaction oldact;
153 struct ::sigaction usract;
154 ::memset(&usract, 0, sizeof(usract));
155 usract.sa_handler = &waitusr;
156 LIBC_CALL( ::sigaction, (SIGUSR1, &usract, &oldact) );
157 ::sigset_t waitsig (oldsig);
158 LIBC_CALL( ::sigdelset, (&waitsig, SIGUSR1) );
160 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
161 LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
162 LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
163 LIBC_CALL( ::close, (nul) );
167 ::sigsuspend(&waitsig);
169 SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()");
172 LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
173 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
180 /* Purposely *not* derived from std::exception */
181 struct DaemonExitException {
182 DaemonExitException(unsigned c) : code(c) {}
187 prefix_ void senf::Daemon::exit(unsigned code)
189 throw DaemonExitException(code);
192 prefix_ int senf::Daemon::start(int argc, char ** argv)
204 installSighandlers();
205 if (! pidfile_.empty()) {
207 pidfileCreated_ = true;
209 std::cerr << "PID file '" << pidfile_
210 << "' creation failed. Daemon running ?" << std::endl;
217 catch (DaemonExitException & e) {
223 catch (std::exception & e) {
224 std::cerr << "\n*** Fatal exception: " << e.what() << "\n" << std::endl;
228 std::cerr << "\n*** Fatal exception: (unknown)" << "\n" << std::endl;
237 ////////////////////////////////////////
240 prefix_ senf::Daemon::Daemon()
241 : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
242 pidfileCreated_(false), detached_(false)
245 ////////////////////////////////////////
248 prefix_ void senf::Daemon::configure()
250 for (int i (1); i<argc_; ++i) {
251 if (argv_[i] == std::string("--no-daemon"))
253 else if (boost::starts_with(argv_[i], std::string("--console-log="))) {
254 std::string arg (std::string(argv_[i]), 14u);
255 std::string::size_type komma (arg.find(','));
256 if (komma == std::string::npos) {
258 if (arg == std::string("none")) consoleLog("");
259 else if (!arg.empty()) consoleLog(arg);
261 std::string arg1 (arg,0,komma);
262 std::string arg2 (arg,komma+1);
265 if (arg1 == std::string("none")) consoleLog("",StdOut);
266 else if (! arg1.empty() ) consoleLog(arg1, StdOut);
267 if (arg2 == std::string("none")) consoleLog("",StdErr);
268 else if (! arg2.empty() ) consoleLog(arg2, StdErr);
271 else if (boost::starts_with(argv_[i], std::string("--pid-file=")))
272 pidFile(std::string(std::string(argv_[i]), 11u));
276 prefix_ void senf::Daemon::main()
283 prefix_ void senf::Daemon::init()
286 prefix_ void senf::Daemon::run()
289 prefix_ void senf::Daemon::fork()
294 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
295 LIBC_CALL( ::dup2, (nul, 0) );
296 LIBC_CALL( ::close, (nul) );
297 LIBC_CALL( ::pipe, (coutpipe) );
298 LIBC_CALL( ::pipe, (cerrpipe) );
300 // We need to block the SIGCHLD signal here so we don't miss it, if the child
304 ::sigemptyset(&cldsig);
305 LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
306 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
308 LIBC_CALL_RV( pid, ::fork, () );
313 LIBC_CALL( ::dup2, (coutpipe[1],1) );
314 LIBC_CALL( ::dup2, (cerrpipe[1],2) );
315 LIBC_CALL( ::close, (coutpipe[0]) );
316 LIBC_CALL( ::close, (coutpipe[1]) );
317 LIBC_CALL( ::close, (cerrpipe[0]) );
318 LIBC_CALL( ::close, (cerrpipe[1]) );
319 LIBC_CALL( ::setsid, () );
320 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
324 // Ouch ... ensure, the daemon watcher does not remove the pidfile ...
327 LIBC_CALL( ::close, (coutpipe[1]) );
328 LIBC_CALL( ::close, (cerrpipe[1]) );
330 detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
336 prefix_ bool senf::Daemon::pidfileCreate()
338 // Create temporary file pidfile_.hostname.pid and hard-link it to pidfile_ If the hardlink
339 // fails, the pidfile exists. If the link count of the temporary file is not 2 after this, there
340 // was some race condition, probably over NFS.
342 std::string tempname;
343 boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\".");
346 char hostname[HOST_NAME_MAX+1];
347 LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
348 hostname[HOST_NAME_MAX] = 0;
349 std::stringstream tempname_s;
350 tempname_s << pidfile_ << "." << hostname << "." << ::getpid();
351 tempname = tempname_s.str();
356 std::ofstream pidf (tempname.c_str());
358 SENF_THROW_SYSTEM_EXCEPTION("")
359 << " Could not open pidfile \"" << tempname << "\" for output.";
360 pidf << ::getpid() << std::endl;
362 SENF_THROW_SYSTEM_EXCEPTION("")
363 << " Could not write to pidfile \"" << tempname << "\".";
366 if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
368 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % pidfile_ % tempname;
372 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
373 LIBC_CALL( ::unlink, (tempname.c_str()) );
374 return s.st_nlink == 2;
377 // pidfile exists. Check, whether the pid in the pidfile still exists.
380 std::ifstream pidf (pidfile_.c_str());
381 if ( ! (pidf >> old_pid)
383 || ::kill(old_pid, 0) >= 0
384 || errno == EPERM ) {
385 LIBC_CALL( ::unlink, (tempname.c_str()) );
390 // If we reach this point, the pid file exists but the process mentioned within the
391 // pid file does *not* exists. We assume, the pid file to be stale.
393 // I hope, the following procedure is without race condition: We remove our generated
394 // temporary pid file and recreate it as hard-link to the old pid file. Now we check, that
395 // the hard-link count of this file is 2. If it is not, we terminate, since someone else
396 // must have already created his hardlink. We then truncate the file and write our pid.
398 LIBC_CALL( ::unlink, (tempname.c_str() ));
399 if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
401 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % tempname % pidfile_;
402 // Hmm ... the pidfile mysteriously disappeared ... try again.
408 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
409 if (s.st_nlink != 2) {
410 LIBC_CALL( ::unlink, (tempname.c_str()) );
416 std::ofstream pidf (tempname.c_str());
417 pidf << ::getpid() << std::endl;
420 LIBC_CALL( ::unlink, (tempname.c_str()) );
430 void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg)
432 static char const * const signames[] = {
434 "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE",
435 "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM",
436 "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU",
437 "SIGURG", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO",
438 "SIGPWR", "SIGSYS" };
440 // ::ucontext_t * ucontext = static_cast<ucontext_t*>(arg);
441 std::cerr << "\n" << "Signal " << sig;
442 if (unsigned(sig) < sizeof(signames) / sizeof(signames[0]))
443 std::cerr << " (" << signames[unsigned(sig)] << ")";
444 std::cerr << " received\n";
447 std::cerr << "Invalid memory access at " << info->si_addr << "\n";
449 static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
450 unsigned nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
452 // Hack the callers address into the backtrace
453 // entries[1] = reinterpret_cast<void *>(ucontext->uc_mcontext.gregs[REG_EIP]);
455 std::cerr << "Backtrace:\n";
456 senf::formatBacktrace(std::cerr, entries, nEntries);
457 std::cerr << "-- \n";
459 if (sig != SIGUSR2) {
460 ::signal(sig, SIG_DFL);
461 ::kill(::getpid(), sig);
469 prefix_ void senf::Daemon::installSighandlers()
472 struct ::sigaction sa;
473 sa.sa_sigaction = &fatalSignalsHandler;
474 ::sigemptyset(&sa.sa_mask);
475 sa.sa_flags = SA_RESTART | SA_SIGINFO;
477 ::sigaction(SIGILL, &sa, NULL);
478 ::sigaction(SIGTRAP, &sa, NULL);
479 ::sigaction(SIGABRT, &sa, NULL);
480 ::sigaction(SIGFPE, &sa, NULL);
481 ::sigaction(SIGBUS, &sa, NULL);
482 ::sigaction(SIGSEGV, &sa, NULL);
483 ::sigaction(SIGSTKFLT, &sa, NULL);
484 ::sigaction(SIGSYS, &sa, NULL);
485 ::sigaction(SIGUSR2, &sa, NULL);
489 ///////////////////////////////////////////////////////////////////////////
490 // senf::detail::DaemonWatcher
492 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
493 int stdout, int stderr)
494 : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
495 stderr_(stderr), sigChld_(false),
496 coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
497 cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
499 coutForwarder_.addTarget(1);
501 coutForwarder_.addTarget(stdout_);
502 cerrForwarder_.addTarget(2);
504 cerrForwarder_.addTarget(stderr_);
507 prefix_ void senf::detail::DaemonWatcher::run()
509 Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this));
510 Scheduler::instance().process();
513 ////////////////////////////////////////
516 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
519 case 1 : coutpipe_ = -1; break;
520 case 2 : cerrpipe_ = -1; break;
523 if (coutpipe_ == -1 && cerrpipe_ == -1) {
525 childDied(); // does not return
526 if (::kill(childPid_, SIGUSR1) < 0)
527 if (errno != ESRCH) SENF_THROW_SYSTEM_EXCEPTION("::kill()");
528 Scheduler::instance().timeout(
529 Scheduler::instance().eventTime() + ClockService::seconds(1),
530 senf::membind(&DaemonWatcher::childOk, this));
534 prefix_ void senf::detail::DaemonWatcher::sigChld()
537 if (coutpipe_ == -1 && cerrpipe_ == -1)
538 childDied(); // does not return
541 prefix_ void senf::detail::DaemonWatcher::childDied()
544 if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()");
545 if (WIFSIGNALED(status)) {
546 ::signal(WTERMSIG(status),SIG_DFL);
547 ::kill(::getpid(), WTERMSIG(status));
548 // should not be reached
551 if (WEXITSTATUS(status) == 0)
553 ::_exit(WEXITSTATUS(status));
556 prefix_ void senf::detail::DaemonWatcher::childOk()
558 Scheduler::instance().terminate();
561 ///////////////////////////////////////////////////////////////////////////
562 // senf::detail::DaemonWatcher::Forwarder
564 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
567 Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
571 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
574 Scheduler::instance().remove(src_);
576 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
577 if (i->offset >= buffer_.size())
578 Scheduler::instance().remove(i->fd);
581 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
583 Target target = { fd, 0 };
584 targets_.push_back(target);
587 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
593 n = ::read(src_,buf,1024);
595 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::read()");
602 Scheduler::instance().remove(src_);
609 if (targets_.empty())
612 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
613 if (i->offset >= buffer_.size())
614 Scheduler::instance().add( i->fd,
615 boost::bind(&Forwarder::writeData, this, _1, i),
616 Scheduler::EV_WRITE );
618 buffer_.insert(buffer_.end(), buf, buf+n);
621 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event,
622 Targets::iterator target)
624 if (event != Scheduler::EV_WRITE) {
625 // Broken pipe while writing data ? Not much, we can do here, we just drop the data
626 Scheduler::instance().remove(target->fd);
627 targets_.erase(target);
628 if (targets_.empty() && src_ == -1)
634 int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
635 std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
637 int w (::write(target->fd, buf, n));
639 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
644 n = std::min_element(
645 targets_.begin(), targets_.end(),
646 boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
648 buffer_.erase(buffer_.begin(), buffer_.begin()+n);
650 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
653 if (target->offset >= buffer_.size())
654 Scheduler::instance().remove(target->fd);
655 if (src_ == -1 && (buffer_.empty() || targets_.empty()))
662 ///////////////////////////////cc.e////////////////////////////////////////
664 //#include "Daemon.mpp"
670 // comment-column: 40
671 // c-file-style: "senf"
672 // indent-tabs-mode: nil
673 // ispell-local-dictionary: "american"
674 // compile-command: "scons -u test"