X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Utils%2FDaemon%2FDaemon.cc;h=1b6e8ae9a62817b28f81fc36a462ebb24c579745;hb=b89e3166f7680755683dccee5e48cb3a820185c0;hp=fe55821ae29462a3a8e16b52c68eb384539c171a;hpb=d5ba3d7759212c90a5f4a25baf0dc38e290c3b64;p=senf.git diff --git a/Utils/Daemon/Daemon.cc b/Utils/Daemon/Daemon.cc index fe55821..1b6e8ae 100644 --- a/Utils/Daemon/Daemon.cc +++ b/Utils/Daemon/Daemon.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #include "../Exception.hh" #include "../membind.hh" #include "../Backtrace.hh" +#include "../signalnames.hh" // #define __USE_GNU #include @@ -87,11 +89,29 @@ prefix_ int senf::Daemon::argc() return argc_; } -prefix_ char ** senf::Daemon::argv() +prefix_ char const ** 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 const ** 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) { @@ -112,17 +132,51 @@ prefix_ void senf::Daemon::openLog() << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout."; stdout_ = fd; } - if (stderrLog_ == stdoutLog_) - stderr_ = fd; - else if (! stderrLog_.empty()) { - fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666); - if (fd < 0) - SENF_THROW_SYSTEM_EXCEPTION("") - << " Could not open \"" << stderrLog_ << "\" for redirecting stderr."; - stderr_ = fd; + if (! stderrLog_.empty()) { + if (stderrLog_ == stdoutLog_) { + stderr_ = ::dup(fd); + if (stderr_ < 0) + SENF_THROW_SYSTEM_EXCEPTION("::dup()"); + } + else { + fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666); + if (fd < 0) + 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; @@ -189,7 +243,7 @@ prefix_ void senf::Daemon::exit(unsigned code) throw DaemonExitException(code); } -prefix_ int senf::Daemon::start(int argc, char ** argv) +prefix_ int senf::Daemon::start(int argc, char const ** argv) { argc_ = argc; argv_ = argv; @@ -234,19 +288,31 @@ prefix_ int senf::Daemon::start(int argc, char ** 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_(""), pidfileCreated_(false), detached_(false) -{} +{ + BOOST_ASSERT( ! instance_ ); + instance_ = this; +} + +senf::Daemon * senf::Daemon::instance_ (0); //////////////////////////////////////// // private members prefix_ void senf::Daemon::configure() { + // int i (not unsigned) since argc_ is int ... for (int i (1); i(arg); - std::cerr << "\n" << "Signal " << sig; - if (unsigned(sig) < sizeof(signames) / sizeof(signames[0])) - std::cerr << " (" << signames[unsigned(sig)] << ")"; - std::cerr << " received\n"; + std::cerr << "\n" << "Signal " << senf::signalName(sig) << '(' << sig << ')' + << " received\n"; if (sig == SIGSEGV) std::cerr << "Invalid memory access at " << info->si_addr << "\n"; @@ -466,12 +538,28 @@ namespace { #endif +namespace { + void sighupHandler(int sig) + { + senf::Daemon::instance().logReopen(); + } +} + prefix_ void senf::Daemon::installSighandlers() { -#ifdef SENF_DEBUG struct ::sigaction sa; - sa.sa_sigaction = &fatalSignalsHandler; + ::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); @@ -493,6 +581,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)) { @@ -506,8 +596,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(); } //////////////////////////////////////// @@ -523,15 +612,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) SENF_THROW_SYSTEM_EXCEPTION("::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) @@ -546,45 +633,38 @@ prefix_ void senf::detail::DaemonWatcher::childDied() ::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); @@ -592,17 +672,18 @@ prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId while (1) { n = ::read(src_,buf,1024); if (n<0) { - if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::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; } @@ -611,20 +692,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; @@ -651,7 +728,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_(); }