4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Daemon non-inline non-template implementation */
35 #include <sys/types.h>
48 #include <boost/algorithm/string/predicate.hpp>
49 #include <boost/algorithm/string/trim.hpp>
50 #include <boost/format.hpp>
51 #include <boost/bind.hpp>
52 #include <senf/Utils/Exception.hh>
53 #include <senf/Utils/membind.hh>
54 #include <senf/Utils/Backtrace.hh>
55 #include <senf/Utils/signalnames.hh>
60 //#include "Daemon.mpp"
62 //-/////////////////////////////////////////////////////////////////////////////////////////////////
64 #define LIBC_CALL(fn, args) if (fn args < 0) \
65 SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
67 #define LIBC_CALL_RV(var, fn, args) \
68 int var (fn args); if (var < 0) SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
70 //-/////////////////////////////////////////////////////////////////////////////////////////////////
73 prefix_ senf::Daemon::~Daemon()
75 if (pidfileCreated_) {
77 LIBC_CALL( ::unlink, (pidfile_.c_str()) );
78 } catch (Exception & e) {
79 // e << "; could not unlink " << pidfile_.c_str();
85 prefix_ void senf::Daemon::daemonize(bool v)
90 prefix_ bool senf::Daemon::daemon()
95 prefix_ int senf::Daemon::argc()
100 prefix_ char const ** senf::Daemon::argv()
108 bool operator()(std::string const & str) const {
109 return str == "--no-daemon"
110 || boost::starts_with(str, std::string("--pid-file="))
111 || boost::starts_with(str, std::string("--console-log="));
116 prefix_ void senf::Daemon::removeDaemonArgs()
118 char const ** last (std::remove_if(argv_+1, argv_+argc_, IsDaemonOpt()));
120 argc_ = last - argv_;
123 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
126 case StdOut : stdoutLog_ = path; break;
127 case StdErr : stderrLog_ = path; break;
128 case Both : stdoutLog_ = path; stderrLog_ = path; break;
133 prefix_ void senf::Daemon::openLog()
136 if (! stdoutLog_.empty()) {
137 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
139 SENF_THROW_SYSTEM_EXCEPTION(
140 " Could not open \"" + stdoutLog_ + "\" for redirecting stdout.");
143 if (! stderrLog_.empty()) {
144 if (stderrLog_ == stdoutLog_) {
147 SENF_THROW_SYSTEM_EXCEPTION("::dup()");
150 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
152 SENF_THROW_SYSTEM_EXCEPTION(
153 " Could not open \"" + stderrLog_ + "\" for redirecting stderr.");
159 prefix_ void senf::Daemon::logReopen()
161 if (! stdoutLog_.empty()) {
162 int fd (::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
165 if (::dup2(fd, 1) < 0)
167 if (stderrLog_ == stdoutLog_) {
168 if (::dup2(fd, 2) < 0)
173 if (! stderrLog_.empty()) {
174 int fd (::open(stderrLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
177 if (::dup2(fd, 2) < 0)
184 (senf::log::CRITICAL)
185 ("log-file reopen failed: (" << errno << ") " << ::strerror(errno)) );
188 prefix_ void senf::Daemon::pidFile(std::string const & f)
194 bool signaled (false);
200 prefix_ void senf::Daemon::detach()
202 if (daemonize_ && ! detached_) {
204 // To ensure all data is written to the console log file in the correct order, we suspend
205 // execution here until the parent process tells us to continue via SIGUSR1: We block
206 // SIGUSR1 and install our own signal handler saving the old handler and signal mask. Then
207 // we close stdin/stderr which will send a HUP condition to the parent process. We wait for
208 // SIGUSR1 and reinstall the old signal mask and action.
211 ::sigemptyset(&usrsig);
212 LIBC_CALL( ::sigaddset, (&usrsig, SIGUSR1) );
213 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &usrsig, &oldsig) );
214 struct ::sigaction oldact;
215 struct ::sigaction usract;
216 ::memset(&usract, 0, sizeof(usract));
217 usract.sa_handler = &waitusr;
218 LIBC_CALL( ::sigaction, (SIGUSR1, &usract, &oldact) );
219 ::sigset_t waitsig (oldsig);
220 LIBC_CALL( ::sigdelset, (&waitsig, SIGUSR1) );
222 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
223 LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
224 LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
225 LIBC_CALL( ::close, (nul) );
229 ::sigsuspend(&waitsig);
231 SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()");
234 LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
235 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
242 /* Purposely *not* derived from std::exception */
243 struct DaemonExitException {
244 DaemonExitException(unsigned c) : code(c) {}
249 prefix_ void senf::Daemon::exit(unsigned code)
251 throw DaemonExitException(code);
254 prefix_ int senf::Daemon::start(int argc, char const ** argv)
266 installSighandlers();
267 if (! pidfile_.empty()) {
269 pidfileCreated_ = true;
271 std::cerr << "PID file '" << pidfile_
272 << "' creation failed. Daemon running ?" << std::endl;
279 catch (DaemonExitException & e) {
285 catch (std::exception & e) {
286 std::cerr << "\n*** Fatal exception: " << e.what() << "\n" << std::endl;
290 std::cerr << "\n*** Fatal exception: (unknown)" << "\n" << std::endl;
299 prefix_ senf::Daemon & senf::Daemon::instance()
301 BOOST_ASSERT( instance_ );
305 //-/////////////////////////////////////////////////////////////////////////////////////////////////
308 prefix_ senf::Daemon::Daemon()
309 : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
310 pidfileCreated_(false), detached_(false)
312 BOOST_ASSERT( ! instance_ );
316 senf::Daemon * senf::Daemon::instance_ (0);
318 //-/////////////////////////////////////////////////////////////////////////////////////////////////
321 prefix_ void senf::Daemon::configure()
323 // int i (not unsigned) since argc_ is int ...
324 for (int i (1); i<argc_; ++i) {
325 std::string argv (argv_[i]);
326 if (argv == "--no-daemon")
328 else if (boost::starts_with(argv, "--console-log=")) {
329 std::string arg (argv.substr(14u));
330 std::string::size_type komma (arg.find(','));
331 if (komma == std::string::npos) {
333 if (arg == std::string("none")) consoleLog("");
334 else if (!arg.empty()) consoleLog(arg);
336 std::string arg1 (arg,0,komma);
337 std::string arg2 (arg,komma+1);
340 if (arg1 == std::string("none")) consoleLog("",StdOut);
341 else if (! arg1.empty() ) consoleLog(arg1, StdOut);
342 if (arg2 == std::string("none")) consoleLog("",StdErr);
343 else if (! arg2.empty() ) consoleLog(arg2, StdErr);
346 else if (boost::starts_with(argv, "--pid-file="))
347 pidFile(std::string(std::string(argv_[i]), 11u));
351 prefix_ void senf::Daemon::main()
358 prefix_ void senf::Daemon::init()
361 prefix_ void senf::Daemon::run()
364 prefix_ void senf::Daemon::fork()
369 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
370 LIBC_CALL( ::dup2, (nul, 0) );
371 LIBC_CALL( ::close, (nul) );
372 LIBC_CALL( ::pipe, (coutpipe) );
373 LIBC_CALL( ::pipe, (cerrpipe) );
375 // We need to block the SIGCHLD signal here so we don't miss it, if the child
379 ::sigemptyset(&cldsig);
380 LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
381 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
383 if (! senf::scheduler::empty() ) {
387 "Scheduler not empty before fork(). THIS MUST NOT HAPPEN.\n"
388 "The scheduler will be reinitialized by the fork() and lose all registrations.\n\n";
389 senf::scheduler::detail::EventManager::instance().listEvents(std::cerr);
391 "\n*** WARNING ***\n"
395 LIBC_CALL_RV( pid, ::fork, () );
400 LIBC_CALL( ::dup2, (coutpipe[1],1) );
401 LIBC_CALL( ::dup2, (cerrpipe[1],2) );
402 LIBC_CALL( ::close, (coutpipe[0]) );
403 LIBC_CALL( ::close, (coutpipe[1]) );
404 LIBC_CALL( ::close, (cerrpipe[0]) );
405 LIBC_CALL( ::close, (cerrpipe[1]) );
406 LIBC_CALL( ::setsid, () );
407 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
409 senf::scheduler::restart();
413 // Ouch ... ensure, the daemon watcher does not remove the pidfile ...
416 LIBC_CALL( ::close, (coutpipe[1]) );
417 LIBC_CALL( ::close, (cerrpipe[1]) );
419 senf::scheduler::restart();
421 detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
427 prefix_ bool senf::Daemon::pidfileCreate()
429 // Create temporary file pidfile_.hostname.pid and hard-link it to pidfile_ If the hardlink
430 // fails, the pidfile exists. If the link count of the temporary file is not 2 after this, there
431 // was some race condition, probably over NFS.
433 std::string tempname;
434 boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\".");
437 char hostname[HOST_NAME_MAX+1];
438 LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
439 hostname[HOST_NAME_MAX] = 0;
440 std::stringstream tempname_s;
441 tempname_s << pidfile_ << "." << hostname << "." << ::getpid();
442 tempname = tempname_s.str();
447 std::ofstream pidf (tempname.c_str());
449 SENF_THROW_SYSTEM_EXCEPTION(" Could not open pidfile \"" + tempname + "\" for output.");
450 pidf << ::getpid() << std::endl;
452 SENF_THROW_SYSTEM_EXCEPTION(" Could not write to pidfile \"" + tempname + "\".");
455 if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
457 SENF_THROW_SYSTEM_EXCEPTION((linkErrorFormat % pidfile_ % tempname).str());
461 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
462 LIBC_CALL( ::unlink, (tempname.c_str()) );
463 return s.st_nlink == 2;
466 // pidfile exists. Check, whether the pid in the pidfile still exists.
469 std::ifstream pidf (pidfile_.c_str());
470 if ( ! (pidf >> old_pid)
472 || ::kill(old_pid, 0) >= 0
473 || errno == EPERM ) {
474 LIBC_CALL( ::unlink, (tempname.c_str()) );
479 // If we reach this point, the pid file exists but the process mentioned within the
480 // pid file does *not* exists. We assume, the pid file to be stale.
482 // I hope, the following procedure is without race condition: We remove our generated
483 // temporary pid file and recreate it as hard-link to the old pid file. Now we check, that
484 // the hard-link count of this file is 2. If it is not, we terminate, since someone else
485 // must have already created his hardlink. We then truncate the file and write our pid.
487 LIBC_CALL( ::unlink, (tempname.c_str() ));
488 if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
490 SENF_THROW_SYSTEM_EXCEPTION( (linkErrorFormat % tempname % pidfile_).str());
491 // Hmm ... the pidfile mysteriously disappeared ... try again.
497 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
498 if (s.st_nlink != 2) {
499 LIBC_CALL( ::unlink, (tempname.c_str()) );
505 std::ofstream pidf (tempname.c_str());
506 pidf << ::getpid() << std::endl;
509 LIBC_CALL( ::unlink, (tempname.c_str()) );
519 void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg)
521 // ::ucontext_t * ucontext = static_cast<ucontext_t*>(arg);
522 std::cerr << "\n" << "Signal " << senf::signalName(sig) << '(' << sig << ')'
526 std::cerr << "Invalid memory access at " << info->si_addr << "\n";
527 #ifdef SENF_BACKTRACE
528 static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
529 int nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
531 // Hack the callers address into the backtrace
532 // entries[1] = reinterpret_cast<void *>(ucontext->uc_mcontext.gregs[REG_EIP]);
534 std::cerr << "Backtrace:\n";
535 senf::formatBacktrace(std::cerr, entries, nEntries);
536 std::cerr << "-- \n";
537 #endif //SENF_BACKTRACE
538 if (sig != SIGUSR2) {
539 ::signal(sig, SIG_DFL);
540 ::kill(::getpid(), sig);
549 void sighupHandler(int sig)
551 senf::Daemon::instance().logReopen();
555 prefix_ void senf::Daemon::installSighandlers()
557 struct ::sigaction sa;
559 ::sigemptyset(&sa.sa_mask);
560 sa.sa_handler = &sighupHandler;
561 sa.sa_flags = SA_RESTART;
563 ::sigaction(SIGHUP, &sa, NULL);
565 sa.sa_handler = SIG_IGN;
566 ::sigaction(SIGPIPE, &sa, NULL);
569 sa.sa_sigaction = &fatalSignalsHandler;
570 sa.sa_flags = SA_RESTART | SA_SIGINFO;
572 ::sigaction(SIGILL, &sa, NULL);
573 ::sigaction(SIGTRAP, &sa, NULL);
574 ::sigaction(SIGABRT, &sa, NULL);
575 ::sigaction(SIGFPE, &sa, NULL);
576 ::sigaction(SIGBUS, &sa, NULL);
577 ::sigaction(SIGSEGV, &sa, NULL);
578 #ifdef SIGSTKFLT //SIGSTKFLT is used for stack faults on coprocessors. That condition doesn't exist on MIPS
579 ::sigaction(SIGSTKFLT, &sa, NULL);
581 ::sigaction(SIGSYS, &sa, NULL);
582 ::sigaction(SIGUSR2, &sa, NULL);
586 //-/////////////////////////////////////////////////////////////////////////////////////////////////
587 // senf::detail::DaemonWatcher
589 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
590 int stdout, int stderr)
591 : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
592 stderr_(stderr), sigChld_(false),
593 cldSignal_ (SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)),
594 timer_ ("senf::detail::DaemonWatcher::childOk", senf::membind(&DaemonWatcher::childOk, this)),
595 coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
596 cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
598 coutForwarder_.addTarget(1);
600 coutForwarder_.addTarget(stdout_);
601 cerrForwarder_.addTarget(2);
603 cerrForwarder_.addTarget(stderr_);
606 prefix_ void senf::detail::DaemonWatcher::run()
608 scheduler::process();
611 //-/////////////////////////////////////////////////////////////////////////////////////////////////
614 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
617 case 1 : coutpipe_ = -1; break;
618 case 2 : cerrpipe_ = -1; break;
621 if (coutpipe_ == -1 && cerrpipe_ == -1) {
623 childDied(); // does not return
624 if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH)
625 SENF_THROW_SYSTEM_EXCEPTION("::kill()");
626 timer_.timeout(scheduler::eventTime() + ClockService::seconds(1));
630 prefix_ void senf::detail::DaemonWatcher::sigChld(siginfo_t const &)
633 if (coutpipe_ == -1 && cerrpipe_ == -1)
634 childDied(); // does not return
637 prefix_ void senf::detail::DaemonWatcher::childDied()
640 if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()");
641 if (WIFSIGNALED(status)) {
642 ::signal(WTERMSIG(status),SIG_DFL);
643 ::kill(::getpid(), WTERMSIG(status));
644 // should not be reached
647 if (WEXITSTATUS(status) == 0)
649 ::_exit(WEXITSTATUS(status));
652 prefix_ void senf::detail::DaemonWatcher::childOk()
654 scheduler::terminate();
657 //-/////////////////////////////////////////////////////////////////////////////////////////////////
658 // senf::detail::DaemonWatcher::Forwarder
660 prefix_ senf::detail::DaemonWatcher::Forwarder::Target::Target(Forwarder & fwd, int fd_)
661 : fd (fd_), offset (0),
662 writeevent ("senf::detail::DaemonWatcher::Forwarder::Target::writeevent",
663 boost::bind(&Forwarder::writeData, &fwd, _1, this),
664 fd, scheduler::FdEvent::EV_WRITE, false)
667 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
668 : src_(src), cb_(cb),
669 readevent_("senf::detail::DaemonWatcher::Forwarder::readevent", senf::membind(&Forwarder::readData, this),
670 src_, scheduler::FdEvent::EV_READ)
673 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
675 targets_.clear_and_destroy(DestroyDelete());
678 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
680 targets_.push_back(*(new Target(*this, fd)));
683 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(int event)
689 n = ::read(src_,buf,1024);
692 SENF_THROW_SYSTEM_EXCEPTION("::read()");
702 readevent_.disable();
706 if (targets_.empty())
709 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
710 if (i->offset >= buffer_.size())
711 i->writeevent.enable();
713 buffer_.insert(buffer_.end(), buf, buf+n);
716 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(int event, Target * target)
718 if (event != scheduler::FdEvent::EV_WRITE) {
719 // Broken pipe while writing data ? Not much, we can do here, we just drop the data
720 targets_.erase_and_destroy(Targets::current(*target),DestroyDelete());
721 if (targets_.empty() && src_ == -1)
727 int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
728 std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
730 int w (::write(target->fd, buf, n));
732 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
737 n = std::min_element(
738 targets_.begin(), targets_.end(),
739 boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
741 buffer_.erase(buffer_.begin(), buffer_.begin()+n);
743 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
746 if (target->offset >= buffer_.size())
747 target->writeevent.disable();
748 if (src_ == -1 && (buffer_.empty() || targets_.empty()))
755 //-/////////////////////////////////////////////////////////////////////////////////////////////////
757 //#include "Daemon.mpp"
763 // comment-column: 40
764 // c-file-style: "senf"
765 // indent-tabs-mode: nil
766 // ispell-local-dictionary: "american"
767 // compile-command: "scons -u test"