#include <fcntl.h>
#include <errno.h>
#include <signal.h>
+#include <execinfo.h>
#include <sstream>
#include <algorithm>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/format.hpp>
#include "../Exception.hh"
#include "../membind.hh"
+#include "../Backtrace.hh"
+
+// #define __USE_GNU
+#include <ucontext.h>
//#include "Daemon.mpp"
#define prefix_
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) {
}
}
+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;
openLog();
fork();
}
+ installSighandlers();
if (! pidfile_.empty()) {
if (pidfileCreate())
pidfileCreated_ = true;
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
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<ucontext_t*>(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<void *>(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