21 #include <sys/types.h> 35 #include <boost/algorithm/string/predicate.hpp> 36 #include <boost/algorithm/string/trim.hpp> 37 #include <boost/format.hpp> 38 #include <boost/bind.hpp> 51 #define LIBC_CALL(fn, args) if (fn args < 0) \ 52 SENF_THROW_SYSTEM_EXCEPTION(#fn "()") 54 #define LIBC_CALL_RV(var, fn, args) \ 55 int var (fn args); if (var < 0) SENF_THROW_SYSTEM_EXCEPTION(#fn "()") 62 if (pidfileCreated_) {
64 LIBC_CALL( ::unlink, (pidfile_.c_str()) );
79 catchExceptions_ = flag;
97 #if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 4 98 namespace _senf_detail_gccfix_ {}
99 using namespace _senf_detail_gccfix_;
100 namespace _senf_detail_gccfix_
106 bool operator()(std::string
const &
str)
const {
107 return str ==
"--no-daemon" 108 || boost::starts_with(str, std::string(
"--pid-file="))
109 || boost::starts_with(str, std::string(
"--console-log="));
116 char const ** last (std::remove_if(argv_+1, argv_+argc_, IsDaemonOpt()));
118 argc_ = last - argv_;
124 case StdOut : stdoutLog_ = path;
break;
125 case StdErr : stderrLog_ = path;
break;
126 case Both : stdoutLog_ = path; stderrLog_ = path;
break;
131 prefix_ void senf::Daemon::openLog()
134 if (! stdoutLog_.empty()) {
135 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
138 " Could not open \"" + stdoutLog_ +
"\" for redirecting stdout.");
141 if (! stderrLog_.empty()) {
142 if (stderrLog_ == stdoutLog_) {
148 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
151 " Could not open \"" + stderrLog_ +
"\" for redirecting stderr.");
159 if (! stdoutLog_.empty()) {
160 int fd (::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
163 if (::dup2(fd, 1) < 0)
165 if (stderrLog_ == stdoutLog_) {
166 if (::dup2(fd, 2) < 0)
171 if (! stderrLog_.empty()) {
172 int fd (::open(stderrLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
175 if (::dup2(fd, 2) < 0)
183 (
"log-file reopen failed: (" << errno <<
") " << ::strerror(errno)) );
192 bool signaled (
false);
200 if (daemonize_ && ! detached_) {
209 ::sigemptyset(&usrsig);
210 LIBC_CALL( ::sigaddset, (&usrsig, SIGUSR1) );
211 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &usrsig, &oldsig) );
212 struct ::sigaction oldact;
213 struct ::sigaction usract;
214 ::memset(&usract, 0,
sizeof(usract));
215 usract.sa_handler = &waitusr;
216 LIBC_CALL( ::sigaction, (SIGUSR1, &usract, &oldact) );
217 ::sigset_t waitsig (oldsig);
218 LIBC_CALL( ::sigdelset, (&waitsig, SIGUSR1) );
223 LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
224 LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
228 ::sigsuspend(&waitsig);
233 LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
234 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
242 struct DaemonExitException {
243 DaemonExitException(
unsigned c) : code(c) {}
250 throw DaemonExitException(code);
253 #define catchAllOtherExceptions() \ 254 catch (std::exception & e) { \ 255 std::cerr << "\n*** Fatal exception: " << e.what() << "\n" << std::endl; \ 259 std::cerr << "\n*** Fatal exception: (unknown)" << "\n" << std::endl; \ 275 installSighandlers();
276 if (! pidfile_.empty()) {
278 pidfileCreated_ =
true;
280 std::cerr <<
"PID file '" << pidfile_
281 <<
"' creation failed. Daemon running ?" << std::endl;
286 catch (DaemonExitException & e) {
291 if (catchExceptions_) {
296 catch (DaemonExitException & e) {
305 catch (DaemonExitException & e) {
312 #undef catchAllOtherExceptions 316 BOOST_ASSERT( instance_ );
324 : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(
""),
325 pidfileCreated_(false), detached_(false)
327 BOOST_ASSERT( ! instance_ );
330 catchExceptions_ =
false;
332 catchExceptions_ =
true;
344 for (
int i (1); i<argc_; ++i) {
345 std::string
argv (argv_[i]);
346 if (argv ==
"--no-daemon")
348 else if (boost::starts_with(argv,
"--console-log=")) {
349 std::string arg (argv.substr(14u));
350 std::string::size_type komma (arg.find(
','));
351 if (komma == std::string::npos) {
353 if (arg == std::string(
"none"))
consoleLog(
"");
356 std::string arg1 (arg,0,komma);
357 std::string arg2 (arg,komma+1);
366 else if (boost::starts_with(argv,
"--pid-file="))
367 pidFile(std::string(std::string(argv_[i]), 11u));
384 prefix_ void senf::Daemon::fork()
399 ::sigemptyset(&cldsig);
400 LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
401 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
403 if (! senf::scheduler::empty() ) {
407 "Scheduler not empty before fork(). THIS MUST NOT HAPPEN.\n" 408 "The scheduler will be reinitialized by the fork() and lose all registrations.\n\n";
409 senf::scheduler::detail::EventManager::instance().listEvents(std::cerr);
411 "\n*** WARNING ***\n" 427 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
429 senf::scheduler::restart();
439 senf::scheduler::restart();
441 detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
447 prefix_ bool senf::Daemon::pidfileCreate()
453 std::string tempname;
454 boost::format linkErrorFormat(
" Could not link \"%1%\" to \"%2%\".");
457 char hostname[HOST_NAME_MAX+1];
458 LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
459 hostname[HOST_NAME_MAX] = 0;
460 std::stringstream tempname_s;
461 tempname_s << pidfile_ <<
"." << hostname <<
"." << ::getpid();
462 tempname = tempname_s.str();
467 std::ofstream pidf (tempname.c_str());
470 pidf << ::getpid() << std::endl;
475 if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
481 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
482 LIBC_CALL( ::unlink, (tempname.c_str()) );
483 return s.st_nlink == 2;
489 std::ifstream pidf (pidfile_.c_str());
490 if ( ! (pidf >> old_pid)
492 || ::kill(old_pid, 0) >= 0
493 || errno == EPERM ) {
494 LIBC_CALL( ::unlink, (tempname.c_str()) );
507 LIBC_CALL( ::unlink, (tempname.c_str() ));
508 if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
517 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
518 if (s.st_nlink != 2) {
519 LIBC_CALL( ::unlink, (tempname.c_str()) );
525 std::ofstream pidf (tempname.c_str());
526 pidf << ::getpid() << std::endl;
529 LIBC_CALL( ::unlink, (tempname.c_str()) );
539 void fatalSignalsHandler(
int sig, ::siginfo_t * info,
void * arg)
542 std::cerr <<
"\n" <<
"Signal " << senf::signalName(sig) <<
'(' << sig <<
')' 546 std::cerr <<
"Invalid memory access at " << info->si_addr <<
"\n";
547 #ifdef SENF_BACKTRACE 548 static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
549 int nEntries( ::
backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
554 std::cerr <<
"Backtrace:\n";
556 std::cerr <<
"-- \n";
557 #endif //SENF_BACKTRACE 558 if (sig != SIGUSR2) {
559 ::signal(sig, SIG_DFL);
560 ::kill(::getpid(), sig);
569 void sighupHandler(
int sig)
575 prefix_ void senf::Daemon::installSighandlers()
577 struct ::sigaction sa;
579 ::sigemptyset(&sa.sa_mask);
580 sa.sa_handler = &sighupHandler;
581 sa.sa_flags = SA_RESTART;
583 ::sigaction(SIGHUP, &sa, NULL);
585 sa.sa_handler = SIG_IGN;
586 ::sigaction(SIGPIPE, &sa, NULL);
589 sa.sa_sigaction = &fatalSignalsHandler;
590 sa.sa_flags = SA_RESTART | SA_SIGINFO;
592 ::sigaction(SIGILL, &sa, NULL);
593 ::sigaction(SIGTRAP, &sa, NULL);
594 ::sigaction(SIGABRT, &sa, NULL);
595 ::sigaction(SIGFPE, &sa, NULL);
596 ::sigaction(SIGBUS, &sa, NULL);
597 ::sigaction(SIGSEGV, &sa, NULL);
598 #ifdef SIGSTKFLT //SIGSTKFLT is used for stack faults on coprocessors. That condition doesn't exist on MIPS 599 ::sigaction(SIGSTKFLT, &sa, NULL);
601 ::sigaction(SIGSYS, &sa, NULL);
602 ::sigaction(SIGUSR2, &sa, NULL);
609 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(
int pid,
int coutpipe,
int cerrpipe,
610 int stdout,
int stderr)
611 : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
612 stderr_(stderr), sigChld_(
false),
613 cldSignal_ (SIGCHLD,
senf::membind(&DaemonWatcher::sigChld,
this)),
614 timer_ (
"senf::detail::DaemonWatcher::childOk",
senf::membind(&DaemonWatcher::childOk,
this)),
615 coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed,
this, 1)),
616 cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed,
this, 2))
618 coutForwarder_.addTarget(1);
620 coutForwarder_.addTarget(stdout_);
621 cerrForwarder_.addTarget(2);
623 cerrForwarder_.addTarget(stderr_);
626 prefix_ void senf::detail::DaemonWatcher::run()
628 scheduler::process();
634 prefix_ void senf::detail::DaemonWatcher::pipeClosed(
int id)
637 case 1 : coutpipe_ = -1;
break;
638 case 2 : cerrpipe_ = -1;
break;
641 if (coutpipe_ == -1 && cerrpipe_ == -1) {
644 if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH)
650 prefix_ void senf::detail::DaemonWatcher::sigChld(siginfo_t
const &)
653 if (coutpipe_ == -1 && cerrpipe_ == -1)
657 prefix_ void senf::detail::DaemonWatcher::childDied()
661 if (WIFSIGNALED(status)) {
662 ::signal(WTERMSIG(status),SIG_DFL);
663 ::kill(::getpid(), WTERMSIG(status));
667 if (WEXITSTATUS(status) == 0)
669 ::_exit(WEXITSTATUS(status));
672 prefix_ void senf::detail::DaemonWatcher::childOk()
680 prefix_ senf::detail::DaemonWatcher::Forwarder::Target::Target(
Forwarder & fwd,
int fd_)
681 : fd (fd_), offset (0),
682 writeevent (
"senf::detail::DaemonWatcher::Forwarder::Target::writeevent",
683 boost::bind(&Forwarder::writeData, &fwd, _1,
this),
687 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(
int src, Callback cb)
688 : src_(src), cb_(cb),
689 readevent_(
"senf::detail::DaemonWatcher::Forwarder::readevent",
senf::membind(&Forwarder::readData,
this),
693 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
695 targets_.clear_and_dispose(DestroyDelete());
698 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(
int fd)
700 targets_.push_back(*(
new Target(*
this, fd)));
703 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(
int event)
709 n = ::read(src_,buf,1024);
722 readevent_.disable();
726 if (targets_.empty())
729 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
730 if (i->offset >= buffer_.size())
731 i->writeevent.enable();
733 buffer_.insert(buffer_.end(), buf, buf+n);
736 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(
int event, Target * target)
740 targets_.erase_and_dispose(Targets::s_iterator_to(*target),DestroyDelete());
741 if (targets_.empty() && src_ == -1)
747 int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
748 std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
750 int w (::write(target->fd, buf, n));
757 n = std::min_element(
758 targets_.begin(), targets_.end(),
759 boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
761 buffer_.erase(buffer_.begin(), buffer_.begin()+n);
763 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
766 if (target->offset >= buffer_.size())
767 target->writeevent.disable();
768 if (src_ == -1 && (buffer_.empty() || targets_.empty()))
void detach()
Detach into background now.
void daemonize(bool)
Configure whether to run in fore- or background.
virtual void configure()
Called before forking to configure the daemon class.
#define catchAllOtherExceptions()
char const ** argv()
Access command line parameters.
#define SENF_THROW_SYSTEM_EXCEPTION(desc)
std::string str(T const &t)
virtual void run()
Called to execute main application.
virtual void terminate() const
static SENF_CLOCKSERVICE_CONSTEXPR clock_type seconds(int64_type const &v)
StdStream
Select standard stream to redirect.
static void exit(unsigned code=0)
Terminate daemon with failure.
boost::function< R(Args)> membind(R(T::*fn)(Args), T *ob)
void catchExceptions(bool flag)
void pidFile(std::string const &)
Configure pid file.
void consoleLog(std::string const &, StdStream which=Both)
Configure console log file.
int start(int argc, char const **argv)
Called from main() to launch daemon.
static Daemon & instance()
Return the Daemon instance.
#define LIBC_CALL_RV(var, fn, args)
int argc()
Access command line parameter count.
virtual void init()
Called to initialize the main application.
bool daemon()
true, if running as daemon
void logReopen()
Reopen the log files.
void removeDaemonArgs()
Remove the daemon arguments from argc()/argv()
#define LIBC_CALL(fn, args)
void backtrace(std::ostream &os, int numEntries)
virtual void main()
Called after forking to execute the main application.
void formatBacktrace(std::ostream &os, void **backtrace, int numEntries)