4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \brief Daemon non-inline non-template implementation */
30 #include <sys/types.h>
40 #include <boost/algorithm/string/predicate.hpp>
41 #include <boost/algorithm/string/trim.hpp>
42 #include <boost/format.hpp>
43 #include "../Exception.hh"
44 #include "../membind.hh"
45 #include "../Backtrace.hh"
50 //#include "Daemon.mpp"
52 ///////////////////////////////cc.p////////////////////////////////////////
54 #define LIBC_CALL(fn, args) if (fn args < 0) \
55 SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
57 #define LIBC_CALL_RV(var, fn, args) \
58 int var (fn args); if (var < 0) SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
60 ///////////////////////////////////////////////////////////////////////////
63 prefix_ senf::Daemon::~Daemon()
65 if (pidfileCreated_) {
67 LIBC_CALL( ::unlink, (pidfile_.c_str()) );
68 } catch (Exception e) {
69 // e << "; could not unlink " << pidfile_.c_str();
75 prefix_ void senf::Daemon::daemonize(bool v)
80 prefix_ bool senf::Daemon::daemon()
85 prefix_ int senf::Daemon::argc()
90 prefix_ char ** senf::Daemon::argv()
98 bool operator()(std::string const & str) const {
99 return str == "--no-daemon"
100 || boost::starts_with(str, std::string("--pid-file="))
101 || boost::starts_with(str, std::string("--console-log="));
106 prefix_ void senf::Daemon::removeDaemonArgs()
108 char ** last (std::remove_if(argv_+1, argv_+argc_, IsDaemonOpt()));
110 argc_ = last - argv_;
113 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
116 case StdOut : stdoutLog_ = path; break;
117 case StdErr : stderrLog_ = path; break;
118 case Both : stdoutLog_ = path; stderrLog_ = path; break;
123 prefix_ void senf::Daemon::openLog()
126 if (! stdoutLog_.empty()) {
127 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
129 SENF_THROW_SYSTEM_EXCEPTION("")
130 << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout.";
133 if (stderrLog_ == stdoutLog_)
135 else if (! stderrLog_.empty()) {
136 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
138 SENF_THROW_SYSTEM_EXCEPTION("")
139 << " Could not open \"" << stderrLog_ << "\" for redirecting stderr.";
144 prefix_ void senf::Daemon::logReopen()
146 if (! stdoutLog_.empty()) {
147 int fd (::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
150 if (::dup2(fd, 1) < 0)
152 if (stderrLog_ == stdoutLog_) {
153 if (::dup2(fd, 2) < 0)
158 if (! stderrLog_.empty()) {
159 int fd (::open(stderrLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
162 if (::dup2(fd, 2) < 0)
169 (senf::log::CRITICAL)
170 ("log-file reopen failed: (" << errno << ") " << ::strerror(errno)) );
173 prefix_ void senf::Daemon::pidFile(std::string const & f)
179 bool signaled (false);
185 prefix_ void senf::Daemon::detach()
187 if (daemonize_ && ! detached_) {
189 // To ensure all data is written to the console log file in the correct order, we suspend
190 // execution here until the parent process tells us to continue via SIGUSR1: We block
191 // SIGUSR1 and install our own signal handler saving the old handler and signal mask. Then
192 // we close stdin/stderr which will send a HUP condition to the parent process. We wait for
193 // SIGUSR1 and reinstall the old signal mask and action.
196 ::sigemptyset(&usrsig);
197 LIBC_CALL( ::sigaddset, (&usrsig, SIGUSR1) );
198 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &usrsig, &oldsig) );
199 struct ::sigaction oldact;
200 struct ::sigaction usract;
201 ::memset(&usract, 0, sizeof(usract));
202 usract.sa_handler = &waitusr;
203 LIBC_CALL( ::sigaction, (SIGUSR1, &usract, &oldact) );
204 ::sigset_t waitsig (oldsig);
205 LIBC_CALL( ::sigdelset, (&waitsig, SIGUSR1) );
207 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
208 LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
209 LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
210 LIBC_CALL( ::close, (nul) );
214 ::sigsuspend(&waitsig);
216 SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()");
219 LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
220 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
227 /* Purposely *not* derived from std::exception */
228 struct DaemonExitException {
229 DaemonExitException(unsigned c) : code(c) {}
234 prefix_ void senf::Daemon::exit(unsigned code)
236 throw DaemonExitException(code);
239 prefix_ int senf::Daemon::start(int argc, char ** argv)
251 installSighandlers();
252 if (! pidfile_.empty()) {
254 pidfileCreated_ = true;
256 std::cerr << "PID file '" << pidfile_
257 << "' creation failed. Daemon running ?" << std::endl;
264 catch (DaemonExitException & e) {
270 catch (std::exception & e) {
271 std::cerr << "\n*** Fatal exception: " << e.what() << "\n" << std::endl;
275 std::cerr << "\n*** Fatal exception: (unknown)" << "\n" << std::endl;
284 prefix_ senf::Daemon & senf::Daemon::instance()
286 BOOST_ASSERT( instance_ );
290 ////////////////////////////////////////
293 prefix_ senf::Daemon::Daemon()
294 : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
295 pidfileCreated_(false), detached_(false)
297 BOOST_ASSERT( ! instance_ );
301 senf::Daemon * senf::Daemon::instance_ (0);
303 ////////////////////////////////////////
306 prefix_ void senf::Daemon::configure()
308 for (int i (1); i<argc_; ++i) {
309 if (argv_[i] == std::string("--no-daemon"))
311 else if (boost::starts_with(argv_[i], std::string("--console-log="))) {
312 std::string arg (std::string(argv_[i]), 14u);
313 std::string::size_type komma (arg.find(','));
314 if (komma == std::string::npos) {
316 if (arg == std::string("none")) consoleLog("");
317 else if (!arg.empty()) consoleLog(arg);
319 std::string arg1 (arg,0,komma);
320 std::string arg2 (arg,komma+1);
323 if (arg1 == std::string("none")) consoleLog("",StdOut);
324 else if (! arg1.empty() ) consoleLog(arg1, StdOut);
325 if (arg2 == std::string("none")) consoleLog("",StdErr);
326 else if (! arg2.empty() ) consoleLog(arg2, StdErr);
329 else if (boost::starts_with(argv_[i], std::string("--pid-file=")))
330 pidFile(std::string(std::string(argv_[i]), 11u));
334 prefix_ void senf::Daemon::main()
341 prefix_ void senf::Daemon::init()
344 prefix_ void senf::Daemon::run()
347 prefix_ void senf::Daemon::fork()
352 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
353 LIBC_CALL( ::dup2, (nul, 0) );
354 LIBC_CALL( ::close, (nul) );
355 LIBC_CALL( ::pipe, (coutpipe) );
356 LIBC_CALL( ::pipe, (cerrpipe) );
358 // We need to block the SIGCHLD signal here so we don't miss it, if the child
362 ::sigemptyset(&cldsig);
363 LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
364 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
366 LIBC_CALL_RV( pid, ::fork, () );
371 LIBC_CALL( ::dup2, (coutpipe[1],1) );
372 LIBC_CALL( ::dup2, (cerrpipe[1],2) );
373 LIBC_CALL( ::close, (coutpipe[0]) );
374 LIBC_CALL( ::close, (coutpipe[1]) );
375 LIBC_CALL( ::close, (cerrpipe[0]) );
376 LIBC_CALL( ::close, (cerrpipe[1]) );
377 LIBC_CALL( ::setsid, () );
378 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
382 // Ouch ... ensure, the daemon watcher does not remove the pidfile ...
385 LIBC_CALL( ::close, (coutpipe[1]) );
386 LIBC_CALL( ::close, (cerrpipe[1]) );
388 detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
394 prefix_ bool senf::Daemon::pidfileCreate()
396 // Create temporary file pidfile_.hostname.pid and hard-link it to pidfile_ If the hardlink
397 // fails, the pidfile exists. If the link count of the temporary file is not 2 after this, there
398 // was some race condition, probably over NFS.
400 std::string tempname;
401 boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\".");
404 char hostname[HOST_NAME_MAX+1];
405 LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
406 hostname[HOST_NAME_MAX] = 0;
407 std::stringstream tempname_s;
408 tempname_s << pidfile_ << "." << hostname << "." << ::getpid();
409 tempname = tempname_s.str();
414 std::ofstream pidf (tempname.c_str());
416 SENF_THROW_SYSTEM_EXCEPTION("")
417 << " Could not open pidfile \"" << tempname << "\" for output.";
418 pidf << ::getpid() << std::endl;
420 SENF_THROW_SYSTEM_EXCEPTION("")
421 << " Could not write to pidfile \"" << tempname << "\".";
424 if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
426 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % pidfile_ % tempname;
430 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
431 LIBC_CALL( ::unlink, (tempname.c_str()) );
432 return s.st_nlink == 2;
435 // pidfile exists. Check, whether the pid in the pidfile still exists.
438 std::ifstream pidf (pidfile_.c_str());
439 if ( ! (pidf >> old_pid)
441 || ::kill(old_pid, 0) >= 0
442 || errno == EPERM ) {
443 LIBC_CALL( ::unlink, (tempname.c_str()) );
448 // If we reach this point, the pid file exists but the process mentioned within the
449 // pid file does *not* exists. We assume, the pid file to be stale.
451 // I hope, the following procedure is without race condition: We remove our generated
452 // temporary pid file and recreate it as hard-link to the old pid file. Now we check, that
453 // the hard-link count of this file is 2. If it is not, we terminate, since someone else
454 // must have already created his hardlink. We then truncate the file and write our pid.
456 LIBC_CALL( ::unlink, (tempname.c_str() ));
457 if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
459 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % tempname % pidfile_;
460 // Hmm ... the pidfile mysteriously disappeared ... try again.
466 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
467 if (s.st_nlink != 2) {
468 LIBC_CALL( ::unlink, (tempname.c_str()) );
474 std::ofstream pidf (tempname.c_str());
475 pidf << ::getpid() << std::endl;
478 LIBC_CALL( ::unlink, (tempname.c_str()) );
488 void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg)
490 static char const * const signames[] = {
492 "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE",
493 "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM",
494 "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU",
495 "SIGURG", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO",
496 "SIGPWR", "SIGSYS" };
498 // ::ucontext_t * ucontext = static_cast<ucontext_t*>(arg);
499 std::cerr << "\n" << "Signal " << sig;
500 if (unsigned(sig) < sizeof(signames) / sizeof(signames[0]))
501 std::cerr << " (" << signames[unsigned(sig)] << ")";
502 std::cerr << " received\n";
505 std::cerr << "Invalid memory access at " << info->si_addr << "\n";
507 static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
508 unsigned nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
510 // Hack the callers address into the backtrace
511 // entries[1] = reinterpret_cast<void *>(ucontext->uc_mcontext.gregs[REG_EIP]);
513 std::cerr << "Backtrace:\n";
514 senf::formatBacktrace(std::cerr, entries, nEntries);
515 std::cerr << "-- \n";
517 if (sig != SIGUSR2) {
518 ::signal(sig, SIG_DFL);
519 ::kill(::getpid(), sig);
528 void sighupHandler(int sig)
530 senf::Daemon::instance().logReopen();
534 prefix_ void senf::Daemon::installSighandlers()
536 struct ::sigaction sa;
538 ::sigemptyset(&sa.sa_mask);
539 sa.sa_handler = &sighupHandler;
540 sa.sa_flags = SA_RESTART;
542 ::sigaction(SIGHUP, &sa, NULL);
544 sa.sa_handler = SIG_IGN;
545 ::sigaction(SIGPIPE, &sa, NULL);
548 sa.sa_sigaction = &fatalSignalsHandler;
549 sa.sa_flags = SA_RESTART | SA_SIGINFO;
551 ::sigaction(SIGILL, &sa, NULL);
552 ::sigaction(SIGTRAP, &sa, NULL);
553 ::sigaction(SIGABRT, &sa, NULL);
554 ::sigaction(SIGFPE, &sa, NULL);
555 ::sigaction(SIGBUS, &sa, NULL);
556 ::sigaction(SIGSEGV, &sa, NULL);
557 ::sigaction(SIGSTKFLT, &sa, NULL);
558 ::sigaction(SIGSYS, &sa, NULL);
559 ::sigaction(SIGUSR2, &sa, NULL);
563 ///////////////////////////////////////////////////////////////////////////
564 // senf::detail::DaemonWatcher
566 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
567 int stdout, int stderr)
568 : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
569 stderr_(stderr), sigChld_(false),
570 coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
571 cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
573 coutForwarder_.addTarget(1);
575 coutForwarder_.addTarget(stdout_);
576 cerrForwarder_.addTarget(2);
578 cerrForwarder_.addTarget(stderr_);
581 prefix_ void senf::detail::DaemonWatcher::run()
583 Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this));
584 Scheduler::instance().process();
587 ////////////////////////////////////////
590 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
593 case 1 : coutpipe_ = -1; break;
594 case 2 : cerrpipe_ = -1; break;
597 if (coutpipe_ == -1 && cerrpipe_ == -1) {
599 childDied(); // does not return
600 if (::kill(childPid_, SIGUSR1) < 0)
601 if (errno != ESRCH) SENF_THROW_SYSTEM_EXCEPTION("::kill()");
602 Scheduler::instance().timeout(
603 Scheduler::instance().eventTime() + ClockService::seconds(1),
604 senf::membind(&DaemonWatcher::childOk, this));
608 prefix_ void senf::detail::DaemonWatcher::sigChld()
611 if (coutpipe_ == -1 && cerrpipe_ == -1)
612 childDied(); // does not return
615 prefix_ void senf::detail::DaemonWatcher::childDied()
618 if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()");
619 if (WIFSIGNALED(status)) {
620 ::signal(WTERMSIG(status),SIG_DFL);
621 ::kill(::getpid(), WTERMSIG(status));
622 // should not be reached
625 if (WEXITSTATUS(status) == 0)
627 ::_exit(WEXITSTATUS(status));
630 prefix_ void senf::detail::DaemonWatcher::childOk()
632 Scheduler::instance().terminate();
635 ///////////////////////////////////////////////////////////////////////////
636 // senf::detail::DaemonWatcher::Forwarder
638 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
641 Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
645 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
648 Scheduler::instance().remove(src_);
650 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
651 if (i->offset >= buffer_.size())
652 Scheduler::instance().remove(i->fd);
655 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
657 Target target = { fd, 0 };
658 targets_.push_back(target);
661 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
667 n = ::read(src_,buf,1024);
669 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::read()");
676 Scheduler::instance().remove(src_);
683 if (targets_.empty())
686 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
687 if (i->offset >= buffer_.size())
688 Scheduler::instance().add( i->fd,
689 boost::bind(&Forwarder::writeData, this, _1, i),
690 Scheduler::EV_WRITE );
692 buffer_.insert(buffer_.end(), buf, buf+n);
695 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event,
696 Targets::iterator target)
698 if (event != Scheduler::EV_WRITE) {
699 // Broken pipe while writing data ? Not much, we can do here, we just drop the data
700 Scheduler::instance().remove(target->fd);
701 targets_.erase(target);
702 if (targets_.empty() && src_ == -1)
708 int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
709 std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
711 int w (::write(target->fd, buf, n));
713 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
718 n = std::min_element(
719 targets_.begin(), targets_.end(),
720 boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
722 buffer_.erase(buffer_.begin(), buffer_.begin()+n);
724 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
727 if (target->offset >= buffer_.size())
728 Scheduler::instance().remove(target->fd);
729 if (src_ == -1 && (buffer_.empty() || targets_.empty()))
736 ///////////////////////////////cc.e////////////////////////////////////////
738 //#include "Daemon.mpp"
744 // comment-column: 40
745 // c-file-style: "senf"
746 // indent-tabs-mode: nil
747 // ispell-local-dictionary: "american"
748 // compile-command: "scons -u test"