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()
95 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
98 case StdOut : stdoutLog_ = path; break;
99 case StdErr : stderrLog_ = path; break;
100 case Both : stdoutLog_ = path; stderrLog_ = path; break;
105 prefix_ void senf::Daemon::openLog()
108 if (! stdoutLog_.empty()) {
109 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
111 SENF_THROW_SYSTEM_EXCEPTION("")
112 << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout.";
115 if (stderrLog_ == stdoutLog_)
117 else if (! stderrLog_.empty()) {
118 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
120 SENF_THROW_SYSTEM_EXCEPTION("")
121 << " Could not open \"" << stderrLog_ << "\" for redirecting stderr.";
126 prefix_ void senf::Daemon::logReopen()
128 if (! stdoutLog_.empty()) {
129 int fd (::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
132 if (::dup2(fd, 1) < 0)
134 if (stderrLog_ == stdoutLog_) {
135 if (::dup2(fd, 2) < 0)
140 if (! stderrLog_.empty()) {
141 int fd (::open(stderrLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
144 if (::dup2(fd, 2) < 0)
151 (senf::log::CRITICAL)
152 ("log-file reopen failed: (" << errno << ") " << ::strerror(errno)) );
155 prefix_ void senf::Daemon::pidFile(std::string const & f)
161 bool signaled (false);
167 prefix_ void senf::Daemon::detach()
169 if (daemonize_ && ! detached_) {
171 // To ensure all data is written to the console log file in the correct order, we suspend
172 // execution here until the parent process tells us to continue via SIGUSR1: We block
173 // SIGUSR1 and install our own signal handler saving the old handler and signal mask. Then
174 // we close stdin/stderr which will send a HUP condition to the parent process. We wait for
175 // SIGUSR1 and reinstall the old signal mask and action.
178 ::sigemptyset(&usrsig);
179 LIBC_CALL( ::sigaddset, (&usrsig, SIGUSR1) );
180 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &usrsig, &oldsig) );
181 struct ::sigaction oldact;
182 struct ::sigaction usract;
183 ::memset(&usract, 0, sizeof(usract));
184 usract.sa_handler = &waitusr;
185 LIBC_CALL( ::sigaction, (SIGUSR1, &usract, &oldact) );
186 ::sigset_t waitsig (oldsig);
187 LIBC_CALL( ::sigdelset, (&waitsig, SIGUSR1) );
189 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
190 LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
191 LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
192 LIBC_CALL( ::close, (nul) );
196 ::sigsuspend(&waitsig);
198 SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()");
201 LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
202 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
209 /* Purposely *not* derived from std::exception */
210 struct DaemonExitException {
211 DaemonExitException(unsigned c) : code(c) {}
216 prefix_ void senf::Daemon::exit(unsigned code)
218 throw DaemonExitException(code);
221 prefix_ int senf::Daemon::start(int argc, char ** argv)
233 installSighandlers();
234 if (! pidfile_.empty()) {
236 pidfileCreated_ = true;
238 std::cerr << "PID file '" << pidfile_
239 << "' creation failed. Daemon running ?" << std::endl;
246 catch (DaemonExitException & e) {
252 catch (std::exception & e) {
253 std::cerr << "\n*** Fatal exception: " << e.what() << "\n" << std::endl;
257 std::cerr << "\n*** Fatal exception: (unknown)" << "\n" << std::endl;
266 prefix_ senf::Daemon & senf::Daemon::instance()
268 BOOST_ASSERT( instance_ );
272 ////////////////////////////////////////
275 prefix_ senf::Daemon::Daemon()
276 : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
277 pidfileCreated_(false), detached_(false)
279 BOOST_ASSERT( ! instance_ );
283 senf::Daemon * senf::Daemon::instance_ (0);
285 ////////////////////////////////////////
288 prefix_ void senf::Daemon::configure()
290 for (int i (1); i<argc_; ++i) {
291 if (argv_[i] == std::string("--no-daemon"))
293 else if (boost::starts_with(argv_[i], std::string("--console-log="))) {
294 std::string arg (std::string(argv_[i]), 14u);
295 std::string::size_type komma (arg.find(','));
296 if (komma == std::string::npos) {
298 if (arg == std::string("none")) consoleLog("");
299 else if (!arg.empty()) consoleLog(arg);
301 std::string arg1 (arg,0,komma);
302 std::string arg2 (arg,komma+1);
305 if (arg1 == std::string("none")) consoleLog("",StdOut);
306 else if (! arg1.empty() ) consoleLog(arg1, StdOut);
307 if (arg2 == std::string("none")) consoleLog("",StdErr);
308 else if (! arg2.empty() ) consoleLog(arg2, StdErr);
311 else if (boost::starts_with(argv_[i], std::string("--pid-file=")))
312 pidFile(std::string(std::string(argv_[i]), 11u));
316 prefix_ void senf::Daemon::main()
323 prefix_ void senf::Daemon::init()
326 prefix_ void senf::Daemon::run()
329 prefix_ void senf::Daemon::fork()
334 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
335 LIBC_CALL( ::dup2, (nul, 0) );
336 LIBC_CALL( ::close, (nul) );
337 LIBC_CALL( ::pipe, (coutpipe) );
338 LIBC_CALL( ::pipe, (cerrpipe) );
340 // We need to block the SIGCHLD signal here so we don't miss it, if the child
344 ::sigemptyset(&cldsig);
345 LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
346 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
348 LIBC_CALL_RV( pid, ::fork, () );
353 LIBC_CALL( ::dup2, (coutpipe[1],1) );
354 LIBC_CALL( ::dup2, (cerrpipe[1],2) );
355 LIBC_CALL( ::close, (coutpipe[0]) );
356 LIBC_CALL( ::close, (coutpipe[1]) );
357 LIBC_CALL( ::close, (cerrpipe[0]) );
358 LIBC_CALL( ::close, (cerrpipe[1]) );
359 LIBC_CALL( ::setsid, () );
360 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
364 // Ouch ... ensure, the daemon watcher does not remove the pidfile ...
367 LIBC_CALL( ::close, (coutpipe[1]) );
368 LIBC_CALL( ::close, (cerrpipe[1]) );
370 detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
376 prefix_ bool senf::Daemon::pidfileCreate()
378 // Create temporary file pidfile_.hostname.pid and hard-link it to pidfile_ If the hardlink
379 // fails, the pidfile exists. If the link count of the temporary file is not 2 after this, there
380 // was some race condition, probably over NFS.
382 std::string tempname;
383 boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\".");
386 char hostname[HOST_NAME_MAX+1];
387 LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
388 hostname[HOST_NAME_MAX] = 0;
389 std::stringstream tempname_s;
390 tempname_s << pidfile_ << "." << hostname << "." << ::getpid();
391 tempname = tempname_s.str();
396 std::ofstream pidf (tempname.c_str());
398 SENF_THROW_SYSTEM_EXCEPTION("")
399 << " Could not open pidfile \"" << tempname << "\" for output.";
400 pidf << ::getpid() << std::endl;
402 SENF_THROW_SYSTEM_EXCEPTION("")
403 << " Could not write to pidfile \"" << tempname << "\".";
406 if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
408 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % pidfile_ % tempname;
412 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
413 LIBC_CALL( ::unlink, (tempname.c_str()) );
414 return s.st_nlink == 2;
417 // pidfile exists. Check, whether the pid in the pidfile still exists.
420 std::ifstream pidf (pidfile_.c_str());
421 if ( ! (pidf >> old_pid)
423 || ::kill(old_pid, 0) >= 0
424 || errno == EPERM ) {
425 LIBC_CALL( ::unlink, (tempname.c_str()) );
430 // If we reach this point, the pid file exists but the process mentioned within the
431 // pid file does *not* exists. We assume, the pid file to be stale.
433 // I hope, the following procedure is without race condition: We remove our generated
434 // temporary pid file and recreate it as hard-link to the old pid file. Now we check, that
435 // the hard-link count of this file is 2. If it is not, we terminate, since someone else
436 // must have already created his hardlink. We then truncate the file and write our pid.
438 LIBC_CALL( ::unlink, (tempname.c_str() ));
439 if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
441 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % tempname % pidfile_;
442 // Hmm ... the pidfile mysteriously disappeared ... try again.
448 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
449 if (s.st_nlink != 2) {
450 LIBC_CALL( ::unlink, (tempname.c_str()) );
456 std::ofstream pidf (tempname.c_str());
457 pidf << ::getpid() << std::endl;
460 LIBC_CALL( ::unlink, (tempname.c_str()) );
470 void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg)
472 static char const * const signames[] = {
474 "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE",
475 "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM", "SIGTERM",
476 "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", "SIGTTOU",
477 "SIGURG", "SIGXCPU", "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO",
478 "SIGPWR", "SIGSYS" };
480 // ::ucontext_t * ucontext = static_cast<ucontext_t*>(arg);
481 std::cerr << "\n" << "Signal " << sig;
482 if (unsigned(sig) < sizeof(signames) / sizeof(signames[0]))
483 std::cerr << " (" << signames[unsigned(sig)] << ")";
484 std::cerr << " received\n";
487 std::cerr << "Invalid memory access at " << info->si_addr << "\n";
489 static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
490 unsigned nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
492 // Hack the callers address into the backtrace
493 // entries[1] = reinterpret_cast<void *>(ucontext->uc_mcontext.gregs[REG_EIP]);
495 std::cerr << "Backtrace:\n";
496 senf::formatBacktrace(std::cerr, entries, nEntries);
497 std::cerr << "-- \n";
499 if (sig != SIGUSR2) {
500 ::signal(sig, SIG_DFL);
501 ::kill(::getpid(), sig);
510 void sighupHandler(int sig)
512 senf::Daemon::instance().logReopen();
516 prefix_ void senf::Daemon::installSighandlers()
518 struct ::sigaction sa;
520 ::sigemptyset(&sa.sa_mask);
521 sa.sa_handler = &sighupHandler;
522 sa.sa_flags = SA_RESTART;
524 ::sigaction(SIGHUP, &sa, NULL);
527 sa.sa_sigaction = &fatalSignalsHandler;
528 sa.sa_flags = SA_RESTART | SA_SIGINFO;
530 ::sigaction(SIGILL, &sa, NULL);
531 ::sigaction(SIGTRAP, &sa, NULL);
532 ::sigaction(SIGABRT, &sa, NULL);
533 ::sigaction(SIGFPE, &sa, NULL);
534 ::sigaction(SIGBUS, &sa, NULL);
535 ::sigaction(SIGSEGV, &sa, NULL);
536 ::sigaction(SIGSTKFLT, &sa, NULL);
537 ::sigaction(SIGSYS, &sa, NULL);
538 ::sigaction(SIGUSR2, &sa, NULL);
542 ///////////////////////////////////////////////////////////////////////////
543 // senf::detail::DaemonWatcher
545 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
546 int stdout, int stderr)
547 : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
548 stderr_(stderr), sigChld_(false),
549 coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
550 cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
552 coutForwarder_.addTarget(1);
554 coutForwarder_.addTarget(stdout_);
555 cerrForwarder_.addTarget(2);
557 cerrForwarder_.addTarget(stderr_);
560 prefix_ void senf::detail::DaemonWatcher::run()
562 Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this));
563 Scheduler::instance().process();
566 ////////////////////////////////////////
569 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
572 case 1 : coutpipe_ = -1; break;
573 case 2 : cerrpipe_ = -1; break;
576 if (coutpipe_ == -1 && cerrpipe_ == -1) {
578 childDied(); // does not return
579 if (::kill(childPid_, SIGUSR1) < 0)
580 if (errno != ESRCH) SENF_THROW_SYSTEM_EXCEPTION("::kill()");
581 Scheduler::instance().timeout(
582 Scheduler::instance().eventTime() + ClockService::seconds(1),
583 senf::membind(&DaemonWatcher::childOk, this));
587 prefix_ void senf::detail::DaemonWatcher::sigChld()
590 if (coutpipe_ == -1 && cerrpipe_ == -1)
591 childDied(); // does not return
594 prefix_ void senf::detail::DaemonWatcher::childDied()
597 if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()");
598 if (WIFSIGNALED(status)) {
599 ::signal(WTERMSIG(status),SIG_DFL);
600 ::kill(::getpid(), WTERMSIG(status));
601 // should not be reached
604 if (WEXITSTATUS(status) == 0)
606 ::_exit(WEXITSTATUS(status));
609 prefix_ void senf::detail::DaemonWatcher::childOk()
611 Scheduler::instance().terminate();
614 ///////////////////////////////////////////////////////////////////////////
615 // senf::detail::DaemonWatcher::Forwarder
617 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
620 Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
624 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
627 Scheduler::instance().remove(src_);
629 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
630 if (i->offset >= buffer_.size())
631 Scheduler::instance().remove(i->fd);
634 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
636 Target target = { fd, 0 };
637 targets_.push_back(target);
640 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
646 n = ::read(src_,buf,1024);
648 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::read()");
655 Scheduler::instance().remove(src_);
662 if (targets_.empty())
665 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
666 if (i->offset >= buffer_.size())
667 Scheduler::instance().add( i->fd,
668 boost::bind(&Forwarder::writeData, this, _1, i),
669 Scheduler::EV_WRITE );
671 buffer_.insert(buffer_.end(), buf, buf+n);
674 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event,
675 Targets::iterator target)
677 if (event != Scheduler::EV_WRITE) {
678 // Broken pipe while writing data ? Not much, we can do here, we just drop the data
679 Scheduler::instance().remove(target->fd);
680 targets_.erase(target);
681 if (targets_.empty() && src_ == -1)
687 int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
688 std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
690 int w (::write(target->fd, buf, n));
692 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
697 n = std::min_element(
698 targets_.begin(), targets_.end(),
699 boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
701 buffer_.erase(buffer_.begin(), buffer_.begin()+n);
703 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
706 if (target->offset >= buffer_.size())
707 Scheduler::instance().remove(target->fd);
708 if (src_ == -1 && (buffer_.empty() || targets_.empty()))
715 ///////////////////////////////cc.e////////////////////////////////////////
717 //#include "Daemon.mpp"
723 // comment-column: 40
724 // c-file-style: "senf"
725 // indent-tabs-mode: nil
726 // ispell-local-dictionary: "american"
727 // compile-command: "scons -u test"