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);
545 sa.sa_sigaction = &fatalSignalsHandler;
546 sa.sa_flags = SA_RESTART | SA_SIGINFO;
548 ::sigaction(SIGILL, &sa, NULL);
549 ::sigaction(SIGTRAP, &sa, NULL);
550 ::sigaction(SIGABRT, &sa, NULL);
551 ::sigaction(SIGFPE, &sa, NULL);
552 ::sigaction(SIGBUS, &sa, NULL);
553 ::sigaction(SIGSEGV, &sa, NULL);
554 ::sigaction(SIGSTKFLT, &sa, NULL);
555 ::sigaction(SIGSYS, &sa, NULL);
556 ::sigaction(SIGUSR2, &sa, NULL);
560 ///////////////////////////////////////////////////////////////////////////
561 // senf::detail::DaemonWatcher
563 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
564 int stdout, int stderr)
565 : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
566 stderr_(stderr), sigChld_(false),
567 coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
568 cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
570 coutForwarder_.addTarget(1);
572 coutForwarder_.addTarget(stdout_);
573 cerrForwarder_.addTarget(2);
575 cerrForwarder_.addTarget(stderr_);
578 prefix_ void senf::detail::DaemonWatcher::run()
580 Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this));
581 Scheduler::instance().process();
584 ////////////////////////////////////////
587 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
590 case 1 : coutpipe_ = -1; break;
591 case 2 : cerrpipe_ = -1; break;
594 if (coutpipe_ == -1 && cerrpipe_ == -1) {
596 childDied(); // does not return
597 if (::kill(childPid_, SIGUSR1) < 0)
598 if (errno != ESRCH) SENF_THROW_SYSTEM_EXCEPTION("::kill()");
599 Scheduler::instance().timeout(
600 Scheduler::instance().eventTime() + ClockService::seconds(1),
601 senf::membind(&DaemonWatcher::childOk, this));
605 prefix_ void senf::detail::DaemonWatcher::sigChld()
608 if (coutpipe_ == -1 && cerrpipe_ == -1)
609 childDied(); // does not return
612 prefix_ void senf::detail::DaemonWatcher::childDied()
615 if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()");
616 if (WIFSIGNALED(status)) {
617 ::signal(WTERMSIG(status),SIG_DFL);
618 ::kill(::getpid(), WTERMSIG(status));
619 // should not be reached
622 if (WEXITSTATUS(status) == 0)
624 ::_exit(WEXITSTATUS(status));
627 prefix_ void senf::detail::DaemonWatcher::childOk()
629 Scheduler::instance().terminate();
632 ///////////////////////////////////////////////////////////////////////////
633 // senf::detail::DaemonWatcher::Forwarder
635 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
638 Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
642 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
645 Scheduler::instance().remove(src_);
647 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
648 if (i->offset >= buffer_.size())
649 Scheduler::instance().remove(i->fd);
652 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
654 Target target = { fd, 0 };
655 targets_.push_back(target);
658 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
664 n = ::read(src_,buf,1024);
666 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::read()");
673 Scheduler::instance().remove(src_);
680 if (targets_.empty())
683 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
684 if (i->offset >= buffer_.size())
685 Scheduler::instance().add( i->fd,
686 boost::bind(&Forwarder::writeData, this, _1, i),
687 Scheduler::EV_WRITE );
689 buffer_.insert(buffer_.end(), buf, buf+n);
692 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event,
693 Targets::iterator target)
695 if (event != Scheduler::EV_WRITE) {
696 // Broken pipe while writing data ? Not much, we can do here, we just drop the data
697 Scheduler::instance().remove(target->fd);
698 targets_.erase(target);
699 if (targets_.empty() && src_ == -1)
705 int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
706 std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
708 int w (::write(target->fd, buf, n));
710 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
715 n = std::min_element(
716 targets_.begin(), targets_.end(),
717 boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
719 buffer_.erase(buffer_.begin(), buffer_.begin()+n);
721 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
724 if (target->offset >= buffer_.size())
725 Scheduler::instance().remove(target->fd);
726 if (src_ == -1 && (buffer_.empty() || targets_.empty()))
733 ///////////////////////////////cc.e////////////////////////////////////////
735 //#include "Daemon.mpp"
741 // comment-column: 40
742 // c-file-style: "senf"
743 // indent-tabs-mode: nil
744 // ispell-local-dictionary: "american"
745 // compile-command: "scons -u test"