X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Utils%2FDaemon%2FDaemon.cc;h=93bfba5428a85036f8d02e035121142f84181a03;hb=412024ed31a4ab4eaea7a4165a434f8efebee325;hp=34f476a1b21f397885787b01a87c4abfe95a6b20;hpb=9e69297ff7a7bcd9d952a38e35bbf124cb7f1dda;p=senf.git diff --git a/Utils/Daemon/Daemon.cc b/Utils/Daemon/Daemon.cc index 34f476a..93bfba5 100644 --- a/Utils/Daemon/Daemon.cc +++ b/Utils/Daemon/Daemon.cc @@ -1,8 +1,8 @@ // $Id$ // -// Copyright (C) 2007 -// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) -// Kompetenzzentrum fuer NETwork research (NET) +// Copyright (C) 2007 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY // Stefan Bund // // This program is free software; you can redistribute it and/or modify @@ -31,30 +31,47 @@ #include #include #include +#include #include #include #include +#include #include #include #include #include +#include #include "../Exception.hh" #include "../membind.hh" +#include "../Backtrace.hh" +#include "../signalnames.hh" + +// #define __USE_GNU +#include //#include "Daemon.mpp" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// -#define LIBC_CALL(fn, args) if (fn args < 0) throwErrno(#fn "()") -#define LIBC_CALL_RV(var, fn, args) int var (fn args); if (var < 0) throwErrno(#fn "()") +#define LIBC_CALL(fn, args) if (fn args < 0) \ + SENF_THROW_SYSTEM_EXCEPTION(#fn "()") + +#define LIBC_CALL_RV(var, fn, args) \ + int var (fn args); if (var < 0) SENF_THROW_SYSTEM_EXCEPTION(#fn "()") /////////////////////////////////////////////////////////////////////////// // senf::Daemon prefix_ senf::Daemon::~Daemon() { - if (! pidfile_.empty()) - LIBC_CALL( ::unlink, (pidfile_.c_str()) ); + if (pidfileCreated_) { + try { + LIBC_CALL( ::unlink, (pidfile_.c_str()) ); + } catch (Exception e) { + // e << "; could not unlink " << pidfile_.c_str(); + // throw; + } + } } prefix_ void senf::Daemon::daemonize(bool v) @@ -67,6 +84,34 @@ prefix_ bool senf::Daemon::daemon() return daemonize_; } +prefix_ int senf::Daemon::argc() +{ + return argc_; +} + +prefix_ char ** senf::Daemon::argv() +{ + return argv_; +} + +namespace { + + struct IsDaemonOpt { + bool operator()(std::string const & str) const { + return str == "--no-daemon" + || boost::starts_with(str, std::string("--pid-file=")) + || boost::starts_with(str, std::string("--console-log=")); + } + }; +} + +prefix_ void senf::Daemon::removeDaemonArgs() +{ + char ** last (std::remove_if(argv_+1, argv_+argc_, IsDaemonOpt())); + *last = 0; + argc_ = last - argv_; +} + prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which) { switch (which) { @@ -83,7 +128,8 @@ prefix_ void senf::Daemon::openLog() if (! stdoutLog_.empty()) { fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd < 0) - throwErrno("::open()"); + SENF_THROW_SYSTEM_EXCEPTION("") + << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout."; stdout_ = fd; } if (stderrLog_ == stdoutLog_) @@ -91,11 +137,41 @@ prefix_ void senf::Daemon::openLog() else if (! stderrLog_.empty()) { fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd < 0) - throwErrno("::open()"); + SENF_THROW_SYSTEM_EXCEPTION("") + << " Could not open \"" << stderrLog_ << "\" for redirecting stderr."; stderr_ = fd; } } +prefix_ void senf::Daemon::logReopen() +{ + if (! stdoutLog_.empty()) { + int fd (::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666)); + if (fd < 0) + goto error; + if (::dup2(fd, 1) < 0) + goto error; + if (stderrLog_ == stdoutLog_) { + if (::dup2(fd, 2) < 0) + goto error; + return; + } + } + if (! stderrLog_.empty()) { + int fd (::open(stderrLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666)); + if (fd < 0) + goto error; + if (::dup2(fd, 2) < 0) + goto error; + } + return; + + error: + SENF_LOG( + (senf::log::CRITICAL) + ("log-file reopen failed: (" << errno << ") " << ::strerror(errno)) ); +} + prefix_ void senf::Daemon::pidFile(std::string const & f) { pidfile_ = f; @@ -110,7 +186,7 @@ namespace { prefix_ void senf::Daemon::detach() { - if (daemonize_) { + if (daemonize_ && ! detached_) { // Wow .. ouch .. // To ensure all data is written to the console log file in the correct order, we suspend // execution here until the parent process tells us to continue via SIGUSR1: We block @@ -139,48 +215,66 @@ prefix_ void senf::Daemon::detach() while (! signaled) { ::sigsuspend(&waitsig); if (errno != EINTR) - throwErrno("::sigsuspend()"); + SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()"); } LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) ); LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) ); + + detached_ = true; } } -prefix_ int senf::Daemon::start(int argc, char const ** argv) +namespace { + /* Purposely *not* derived from std::exception */ + struct DaemonExitException { + DaemonExitException(unsigned c) : code(c) {} + unsigned code; + }; +} + +prefix_ void senf::Daemon::exit(unsigned code) +{ + throw DaemonExitException(code); +} + +prefix_ int senf::Daemon::start(int argc, char ** argv) { argc_ = argc; argv_ = argv; -# ifdef NDEBUG - try { - -# endif - configure(); if (daemonize_) { openLog(); fork(); } - if (! pidfile_.empty() && ! pidfileCreate()) { - std::cerr << "\n*** PID file '" << pidfile_ << "' creation failed. Daemon running ?" - << std::endl; - return 1; + installSighandlers(); + if (! pidfile_.empty()) { + if (pidfileCreate()) + pidfileCreated_ = true; + else { + std::cerr << "PID file '" << pidfile_ + << "' creation failed. Daemon running ?" << std::endl; + return 1; + } } main(); + } + catch (DaemonExitException & e) { + return e.code; + } -# ifdef NDEBUG +#ifndef SENF_DEBUG - } catch (std::exception & e) { - std::cerr << "\n*** Fatal exception: " << e.what() << std::endl; + std::cerr << "\n*** Fatal exception: " << e.what() << "\n" << std::endl; return 1; } catch (...) { - std::cerr << "\n*** Fatal exception: (unknown)" << std::endl; + std::cerr << "\n*** Fatal exception: (unknown)" << "\n" << std::endl; return 1; } @@ -189,13 +283,24 @@ prefix_ int senf::Daemon::start(int argc, char const ** argv) return 0; } +prefix_ senf::Daemon & senf::Daemon::instance() +{ + BOOST_ASSERT( instance_ ); + return *instance_; +} + //////////////////////////////////////// // protected members prefix_ senf::Daemon::Daemon() : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""), - detached_(false) -{} + pidfileCreated_(false), detached_(false) +{ + BOOST_ASSERT( ! instance_ ); + instance_ = this; +} + +senf::Daemon * senf::Daemon::instance_ (0); //////////////////////////////////////// // private members @@ -210,7 +315,8 @@ prefix_ void senf::Daemon::configure() std::string::size_type komma (arg.find(',')); if (komma == std::string::npos) { boost::trim(arg); - consoleLog(arg); + if (arg == std::string("none")) consoleLog(""); + else if (!arg.empty()) consoleLog(arg); } else { std::string arg1 (arg,0,komma); std::string arg2 (arg,komma+1); @@ -258,6 +364,15 @@ prefix_ void senf::Daemon::fork() ::sigemptyset(&cldsig); LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) ); LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) ); + + if (! senf::scheduler::empty() ) + std::cerr << + "\n" + "*** WARNING ***\n" + "Scheduler not empty before fork(). THIS MUST NOT HAPPEN.\n" + "The scheduler will be reinitialized by the fork() and lose all registrations.\n" + "*** WARNING ***\n" + "\n"; LIBC_CALL_RV( pid, ::fork, () ); @@ -272,6 +387,8 @@ prefix_ void senf::Daemon::fork() LIBC_CALL( ::close, (cerrpipe[1]) ); LIBC_CALL( ::setsid, () ); LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) ); + + senf::scheduler::restart(); return; } @@ -281,6 +398,8 @@ prefix_ void senf::Daemon::fork() LIBC_CALL( ::close, (coutpipe[1]) ); LIBC_CALL( ::close, (cerrpipe[1]) ); + senf::scheduler::restart(); + detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_); watcher.run(); @@ -294,6 +413,7 @@ prefix_ bool senf::Daemon::pidfileCreate() // was some race condition, probably over NFS. std::string tempname; + boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\"."); { char hostname[HOST_NAME_MAX+1]; @@ -307,12 +427,18 @@ prefix_ bool senf::Daemon::pidfileCreate() while (1) { { std::ofstream pidf (tempname.c_str()); + if (! pidf) + SENF_THROW_SYSTEM_EXCEPTION("") + << " Could not open pidfile \"" << tempname << "\" for output."; pidf << ::getpid() << std::endl; + if (! pidf) + SENF_THROW_SYSTEM_EXCEPTION("") + << " Could not write to pidfile \"" << tempname << "\"."; } if (::link(tempname.c_str(), pidfile_.c_str()) < 0) { if (errno != EEXIST) - throwErrno("::link()"); + SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % pidfile_ % tempname; } else { struct ::stat s; @@ -328,8 +454,10 @@ prefix_ bool senf::Daemon::pidfileCreate() if ( ! (pidf >> old_pid) || old_pid < 0 || ::kill(old_pid, 0) >= 0 - || errno == EPERM ) + || errno == EPERM ) { + LIBC_CALL( ::unlink, (tempname.c_str()) ); return false; + } } // If we reach this point, the pid file exists but the process mentioned within the @@ -342,7 +470,8 @@ prefix_ bool senf::Daemon::pidfileCreate() LIBC_CALL( ::unlink, (tempname.c_str() )); if (::link(pidfile_.c_str(), tempname.c_str()) < 0) { - if (errno != ENOENT) throwErrno("::link()"); + if (errno != ENOENT) + SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % tempname % pidfile_; // Hmm ... the pidfile mysteriously disappeared ... try again. continue; } @@ -367,6 +496,75 @@ prefix_ bool senf::Daemon::pidfileCreate() return true; } + +#ifdef SENF_DEBUG + +namespace { + void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg) + { + // ::ucontext_t * ucontext = static_cast(arg); + std::cerr << "\n" << "Signal " << senf::signalName(sig) << '(' << sig << ')' + << " received\n"; + + if (sig == SIGSEGV) + std::cerr << "Invalid memory access at " << info->si_addr << "\n"; + + static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS]; + unsigned nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) ); + + // Hack the callers address into the backtrace + // entries[1] = reinterpret_cast(ucontext->uc_mcontext.gregs[REG_EIP]); + + std::cerr << "Backtrace:\n"; + senf::formatBacktrace(std::cerr, entries, nEntries); + std::cerr << "-- \n"; + + if (sig != SIGUSR2) { + ::signal(sig, SIG_DFL); + ::kill(::getpid(), sig); + } + } + +} + +#endif + +namespace { + void sighupHandler(int sig) + { + senf::Daemon::instance().logReopen(); + } +} + +prefix_ void senf::Daemon::installSighandlers() +{ + struct ::sigaction sa; + + ::sigemptyset(&sa.sa_mask); + sa.sa_handler = &sighupHandler; + sa.sa_flags = SA_RESTART; + + ::sigaction(SIGHUP, &sa, NULL); + + sa.sa_handler = SIG_IGN; + ::sigaction(SIGPIPE, &sa, NULL); + +#ifdef SENF_DEBUG + sa.sa_sigaction = &fatalSignalsHandler; + sa.sa_flags = SA_RESTART | SA_SIGINFO; + + ::sigaction(SIGILL, &sa, NULL); + ::sigaction(SIGTRAP, &sa, NULL); + ::sigaction(SIGABRT, &sa, NULL); + ::sigaction(SIGFPE, &sa, NULL); + ::sigaction(SIGBUS, &sa, NULL); + ::sigaction(SIGSEGV, &sa, NULL); + ::sigaction(SIGSTKFLT, &sa, NULL); + ::sigaction(SIGSYS, &sa, NULL); + ::sigaction(SIGUSR2, &sa, NULL); +#endif +} + /////////////////////////////////////////////////////////////////////////// // senf::detail::DaemonWatcher @@ -374,6 +572,8 @@ prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int ce int stdout, int stderr) : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout), stderr_(stderr), sigChld_(false), + cldSignal_ (SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)), + timer_ ("senf::detail::DaemonWatcher::childOk", senf::membind(&DaemonWatcher::childOk, this)), coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)), cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2)) { @@ -387,8 +587,7 @@ prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int ce prefix_ void senf::detail::DaemonWatcher::run() { - Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)); - Scheduler::instance().process(); + scheduler::process(); } //////////////////////////////////////// @@ -404,15 +603,13 @@ prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id) if (coutpipe_ == -1 && cerrpipe_ == -1) { if (sigChld_) childDied(); // does not return - if (::kill(childPid_, SIGUSR1) < 0) - if (errno != ESRCH) throwErrno("::kill()"); - Scheduler::instance().timeout( - Scheduler::instance().eventTime() + ClockService::seconds(1), - senf::membind(&DaemonWatcher::childOk, this)); + if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH) + SENF_THROW_SYSTEM_EXCEPTION("::kill()"); + timer_.timeout(scheduler::eventTime() + ClockService::seconds(1)); } } -prefix_ void senf::detail::DaemonWatcher::sigChld() +prefix_ void senf::detail::DaemonWatcher::sigChld(siginfo_t const &) { sigChld_ = true; if (coutpipe_ == -1 && cerrpipe_ == -1) @@ -422,50 +619,43 @@ prefix_ void senf::detail::DaemonWatcher::sigChld() prefix_ void senf::detail::DaemonWatcher::childDied() { int status (0); - if (::waitpid(childPid_,&status,0) < 0) throwErrno("::waitpid()"); + if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()"); if (WIFSIGNALED(status)) { ::signal(WTERMSIG(status),SIG_DFL); ::kill(::getpid(), WTERMSIG(status)); // should not be reached - ::_exit(1); + ::_exit(126); } if (WEXITSTATUS(status) == 0) - ::_exit(1); + ::_exit(127); ::_exit(WEXITSTATUS(status)); } prefix_ void senf::detail::DaemonWatcher::childOk() { - Scheduler::instance().terminate(); + scheduler::terminate(); } /////////////////////////////////////////////////////////////////////////// // senf::detail::DaemonWatcher::Forwarder prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb) - : src_(src), cb_(cb) -{ - Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this), - Scheduler::EV_READ); -} + : src_(src), cb_(cb), + readevent_("senf::detail::DaemonWatcher::Forwarder::readevent", senf::membind(&Forwarder::readData, this), + src_, scheduler::FdEvent::EV_READ) +{} prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder() { - if (src_ != -1) - Scheduler::instance().remove(src_); - - for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i) - if (i->offset >= buffer_.size()) - Scheduler::instance().remove(i->fd); + targets_.clear_and_destroy(DestroyDelete()); } prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd) { - Target target = { fd, 0 }; - targets_.push_back(target); + targets_.push_back(*(new Target(*this, fd))); } -prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event) +prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(int event) { char buf[1024]; int n (0); @@ -473,17 +663,18 @@ prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId while (1) { n = ::read(src_,buf,1024); if (n<0) { - if (errno != EINTR) throwErrno("::read()"); - } else + if (errno != EINTR) + SENF_THROW_SYSTEM_EXCEPTION("::read()"); + } + else break; } if (n == 0) { - // Hangup - Scheduler::instance().remove(src_); if (buffer_.empty()) cb_(); src_ = -1; + readevent_.disable(); return; } @@ -492,20 +683,16 @@ prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i) if (i->offset >= buffer_.size()) - Scheduler::instance().add( i->fd, - boost::bind(&Forwarder::writeData, this, _1, i), - Scheduler::EV_WRITE ); + i->writeevent.enable(); buffer_.insert(buffer_.end(), buf, buf+n); } -prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event, - Targets::iterator target) +prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(int event, Target * target) { - if (event != Scheduler::EV_WRITE) { + if (event != scheduler::FdEvent::EV_WRITE) { // Broken pipe while writing data ? Not much, we can do here, we just drop the data - Scheduler::instance().remove(target->fd); - targets_.erase(target); + targets_.erase_and_destroy(Targets::current(*target),DestroyDelete()); if (targets_.empty() && src_ == -1) cb_(); return; @@ -517,7 +704,7 @@ prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventI int w (::write(target->fd, buf, n)); if (w < 0) { - if (errno != EINTR) throwErrno("::write()"); + if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()"); return; } target->offset += w; @@ -532,7 +719,7 @@ prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventI i->offset -= n; if (target->offset >= buffer_.size()) - Scheduler::instance().remove(target->fd); + target->writeevent.disable(); if (src_ == -1 && (buffer_.empty() || targets_.empty())) cb_(); }