X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Utils%2FDaemon%2FDaemon.cc;h=9457d8c43c9b5d98e70a8e564c12116de6c62c43;hb=8e708e9784c76461252c3bdf646d291c593a49be;hp=c60939ab77908e96bfe5e28400beca60b704fbc8;hpb=cb2920bff3d35e88f195be7f5e03c217b9cf484c;p=senf.git diff --git a/Utils/Daemon/Daemon.cc b/Utils/Daemon/Daemon.cc index c60939a..9457d8c 100644 --- a/Utils/Daemon/Daemon.cc +++ b/Utils/Daemon/Daemon.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -41,25 +42,32 @@ #include #include "../Exception.hh" #include "../membind.hh" +#include "../Backtrace.hh" + +// #define __USE_GNU +#include //#include "Daemon.mpp" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// -#define LIBC_CALL(fn, args) if (fn args < 0) throw SystemException(#fn "()") -#define LIBC_CALL_RV(var, fn, args) int var (fn args); if (var < 0) throw SystemException(#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()) { + if (pidfileCreated_) { try { LIBC_CALL( ::unlink, (pidfile_.c_str()) ); - } catch (SystemException e) { - e << "; could not unlink " << pidfile_.c_str(); - throw; + } catch (Exception e) { + // e << "; could not unlink " << pidfile_.c_str(); + // throw; } } } @@ -74,14 +82,34 @@ prefix_ bool senf::Daemon::daemon() return daemonize_; } -prefix_ int senf::Daemon::argc() { +prefix_ int senf::Daemon::argc() +{ return argc_; } -prefix_ char const ** senf::Daemon::argv() { +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) { @@ -98,7 +126,8 @@ prefix_ void senf::Daemon::openLog() if (! stdoutLog_.empty()) { fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd < 0) - throw SystemException("::open()"); + SENF_THROW_SYSTEM_EXCEPTION("") + << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout."; stdout_ = fd; } if (stderrLog_ == stdoutLog_) @@ -106,11 +135,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) - throw SystemException("::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; @@ -154,7 +213,7 @@ prefix_ void senf::Daemon::detach() while (! signaled) { ::sigsuspend(&waitsig); if (errno != EINTR) - throw SystemException("::sigsuspend()"); + SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()"); } LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) ); @@ -177,7 +236,7 @@ prefix_ void senf::Daemon::exit(unsigned code) throw DaemonExitException(code); } -prefix_ int senf::Daemon::start(int argc, char const ** argv) +prefix_ int senf::Daemon::start(int argc, char ** argv) { argc_ = argc; argv_ = argv; @@ -189,10 +248,15 @@ prefix_ int senf::Daemon::start(int argc, char const ** argv) 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(); @@ -204,11 +268,11 @@ prefix_ int senf::Daemon::start(int argc, char const ** argv) #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; } @@ -217,13 +281,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 @@ -323,7 +398,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%\""); + boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\"."); { char hostname[HOST_NAME_MAX+1]; @@ -337,13 +412,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) - throw SystemException("::link()") - << linkErrorFormat % pidfile_.c_str() % tempname.c_str(); + SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % pidfile_ % tempname; } else { struct ::stat s; @@ -359,8 +439,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 @@ -374,8 +456,7 @@ prefix_ bool senf::Daemon::pidfileCreate() LIBC_CALL( ::unlink, (tempname.c_str() )); if (::link(pidfile_.c_str(), tempname.c_str()) < 0) { if (errno != ENOENT) - throw SystemException("::link()") - << linkErrorFormat % tempname.c_str() % pidfile_.c_str(); + SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % tempname % pidfile_; // Hmm ... the pidfile mysteriously disappeared ... try again. continue; } @@ -400,6 +481,82 @@ prefix_ bool senf::Daemon::pidfileCreate() return true; } + +#ifdef SENF_DEBUG + +namespace { + void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg) + { + static char const * const signames[] = { + "", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM", + "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU", + "SIGURG", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO", + "SIGPWR", "SIGSYS" }; + + // ::ucontext_t * ucontext = static_cast(arg); + std::cerr << "\n" << "Signal " << sig; + if (unsigned(sig) < sizeof(signames) / sizeof(signames[0])) + std::cerr << " (" << signames[unsigned(sig)] << ")"; + std::cerr << " 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); + +#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 @@ -438,7 +595,7 @@ prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id) if (sigChld_) childDied(); // does not return if (::kill(childPid_, SIGUSR1) < 0) - if (errno != ESRCH) throw SystemException("::kill()"); + if (errno != ESRCH) SENF_THROW_SYSTEM_EXCEPTION("::kill()"); Scheduler::instance().timeout( Scheduler::instance().eventTime() + ClockService::seconds(1), senf::membind(&DaemonWatcher::childOk, this)); @@ -455,7 +612,7 @@ prefix_ void senf::detail::DaemonWatcher::sigChld() prefix_ void senf::detail::DaemonWatcher::childDied() { int status (0); - if (::waitpid(childPid_,&status,0) < 0) throw SystemException("::waitpid()"); + if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()"); if (WIFSIGNALED(status)) { ::signal(WTERMSIG(status),SIG_DFL); ::kill(::getpid(), WTERMSIG(status)); @@ -506,7 +663,7 @@ prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId while (1) { n = ::read(src_,buf,1024); if (n<0) { - if (errno != EINTR) throw SystemException("::read()"); + if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::read()"); } else break; } @@ -550,7 +707,7 @@ prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventI int w (::write(target->fd, buf, n)); if (w < 0) { - if (errno != EINTR) throw SystemException("::write()"); + if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()"); return; } target->offset += w;