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>
39 #include <boost/algorithm/string/predicate.hpp>
40 #include <boost/algorithm/string/trim.hpp>
41 #include <boost/format.hpp>
42 #include "../Exception.hh"
43 #include "../membind.hh"
45 //#include "Daemon.mpp"
47 ///////////////////////////////cc.p////////////////////////////////////////
49 #define LIBC_CALL(fn, args) if (fn args < 0) \
50 SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
52 #define LIBC_CALL_RV(var, fn, args) \
53 int var (fn args); if (var < 0) SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
55 ///////////////////////////////////////////////////////////////////////////
58 prefix_ senf::Daemon::~Daemon()
60 if (! pidfile_.empty()) {
62 LIBC_CALL( ::unlink, (pidfile_.c_str()) );
63 } catch (Exception e) {
64 // e << "; could not unlink " << pidfile_.c_str();
70 prefix_ void senf::Daemon::daemonize(bool v)
75 prefix_ bool senf::Daemon::daemon()
80 prefix_ int senf::Daemon::argc() {
84 prefix_ char const ** senf::Daemon::argv() {
88 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
91 case StdOut : stdoutLog_ = path; break;
92 case StdErr : stderrLog_ = path; break;
93 case Both : stdoutLog_ = path; stderrLog_ = path; break;
98 prefix_ void senf::Daemon::openLog()
101 if (! stdoutLog_.empty()) {
102 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
104 SENF_THROW_SYSTEM_EXCEPTION("")
105 << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout.";
108 if (stderrLog_ == stdoutLog_)
110 else if (! stderrLog_.empty()) {
111 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
113 SENF_THROW_SYSTEM_EXCEPTION("")
114 << " Could not open \"" << stderrLog_ << "\" for redirecting stderr.";
119 prefix_ void senf::Daemon::pidFile(std::string const & f)
125 bool signaled (false);
131 prefix_ void senf::Daemon::detach()
133 if (daemonize_ && ! detached_) {
135 // To ensure all data is written to the console log file in the correct order, we suspend
136 // execution here until the parent process tells us to continue via SIGUSR1: We block
137 // SIGUSR1 and install our own signal handler saving the old handler and signal mask. Then
138 // we close stdin/stderr which will send a HUP condition to the parent process. We wait for
139 // SIGUSR1 and reinstall the old signal mask and action.
142 ::sigemptyset(&usrsig);
143 LIBC_CALL( ::sigaddset, (&usrsig, SIGUSR1) );
144 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &usrsig, &oldsig) );
145 struct ::sigaction oldact;
146 struct ::sigaction usract;
147 ::memset(&usract, 0, sizeof(usract));
148 usract.sa_handler = &waitusr;
149 LIBC_CALL( ::sigaction, (SIGUSR1, &usract, &oldact) );
150 ::sigset_t waitsig (oldsig);
151 LIBC_CALL( ::sigdelset, (&waitsig, SIGUSR1) );
153 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
154 LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
155 LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
156 LIBC_CALL( ::close, (nul) );
160 ::sigsuspend(&waitsig);
162 SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()");
165 LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
166 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
173 /* Purposely *not* derived from std::exception */
174 struct DaemonExitException {
175 DaemonExitException(unsigned c) : code(c) {}
180 prefix_ void senf::Daemon::exit(unsigned code)
182 throw DaemonExitException(code);
185 prefix_ int senf::Daemon::start(int argc, char const ** argv)
197 if (! pidfile_.empty() && ! pidfileCreate()) {
198 std::cerr << "\n*** PID file '" << pidfile_ << "' creation failed. Daemon running ?"
205 catch (DaemonExitException & e) {
211 catch (std::exception & e) {
212 std::cerr << "\n*** Fatal exception: " << e.what() << std::endl;
216 std::cerr << "\n*** Fatal exception: (unknown)" << std::endl;
225 ////////////////////////////////////////
228 prefix_ senf::Daemon::Daemon()
229 : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
233 ////////////////////////////////////////
236 prefix_ void senf::Daemon::configure()
238 for (int i (1); i<argc_; ++i) {
239 if (argv_[i] == std::string("--no-daemon"))
241 else if (boost::starts_with(argv_[i], std::string("--console-log="))) {
242 std::string arg (std::string(argv_[i]), 14u);
243 std::string::size_type komma (arg.find(','));
244 if (komma == std::string::npos) {
246 if (arg == std::string("none")) consoleLog("");
247 else if (!arg.empty()) consoleLog(arg);
249 std::string arg1 (arg,0,komma);
250 std::string arg2 (arg,komma+1);
253 if (arg1 == std::string("none")) consoleLog("",StdOut);
254 else if (! arg1.empty() ) consoleLog(arg1, StdOut);
255 if (arg2 == std::string("none")) consoleLog("",StdErr);
256 else if (! arg2.empty() ) consoleLog(arg2, StdErr);
259 else if (boost::starts_with(argv_[i], std::string("--pid-file=")))
260 pidFile(std::string(std::string(argv_[i]), 11u));
264 prefix_ void senf::Daemon::main()
271 prefix_ void senf::Daemon::init()
274 prefix_ void senf::Daemon::run()
277 prefix_ void senf::Daemon::fork()
282 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
283 LIBC_CALL( ::dup2, (nul, 0) );
284 LIBC_CALL( ::close, (nul) );
285 LIBC_CALL( ::pipe, (coutpipe) );
286 LIBC_CALL( ::pipe, (cerrpipe) );
288 // We need to block the SIGCHLD signal here so we don't miss it, if the child
292 ::sigemptyset(&cldsig);
293 LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
294 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
296 LIBC_CALL_RV( pid, ::fork, () );
301 LIBC_CALL( ::dup2, (coutpipe[1],1) );
302 LIBC_CALL( ::dup2, (cerrpipe[1],2) );
303 LIBC_CALL( ::close, (coutpipe[0]) );
304 LIBC_CALL( ::close, (coutpipe[1]) );
305 LIBC_CALL( ::close, (cerrpipe[0]) );
306 LIBC_CALL( ::close, (cerrpipe[1]) );
307 LIBC_CALL( ::setsid, () );
308 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
312 // Ouch ... ensure, the daemon watcher does not remove the pidfile ...
315 LIBC_CALL( ::close, (coutpipe[1]) );
316 LIBC_CALL( ::close, (cerrpipe[1]) );
318 detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
324 prefix_ bool senf::Daemon::pidfileCreate()
326 // Create temporary file pidfile_.hostname.pid and hard-link it to pidfile_ If the hardlink
327 // fails, the pidfile exists. If the link count of the temporary file is not 2 after this, there
328 // was some race condition, probably over NFS.
330 std::string tempname;
331 boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\".");
334 char hostname[HOST_NAME_MAX+1];
335 LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
336 hostname[HOST_NAME_MAX] = 0;
337 std::stringstream tempname_s;
338 tempname_s << pidfile_ << "." << hostname << "." << ::getpid();
339 tempname = tempname_s.str();
344 std::ofstream pidf (tempname.c_str());
346 SENF_THROW_SYSTEM_EXCEPTION("")
347 << " Could not open pidfile \"" << tempname << "\" for output.";
348 pidf << ::getpid() << std::endl;
350 SENF_THROW_SYSTEM_EXCEPTION("")
351 << " Could not write to pidfile \"" << tempname << "\".";
354 if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
356 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % pidfile_ % tempname;
360 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
361 LIBC_CALL( ::unlink, (tempname.c_str()) );
362 return s.st_nlink == 2;
365 // pidfile exists. Check, whether the pid in the pidfile still exists.
368 std::ifstream pidf (pidfile_.c_str());
369 if ( ! (pidf >> old_pid)
371 || ::kill(old_pid, 0) >= 0
376 // If we reach this point, the pid file exists but the process mentioned within the
377 // pid file does *not* exists. We assume, the pid file to be stale.
379 // I hope, the following procedure is without race condition: We remove our generated
380 // temporary pid file and recreate it as hard-link to the old pid file. Now we check, that
381 // the hard-link count of this file is 2. If it is not, we terminate, since someone else
382 // must have already created his hardlink. We then truncate the file and write our pid.
384 LIBC_CALL( ::unlink, (tempname.c_str() ));
385 if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
387 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % tempname % pidfile_;
388 // Hmm ... the pidfile mysteriously disappeared ... try again.
394 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
395 if (s.st_nlink != 2) {
396 LIBC_CALL( ::unlink, (tempname.c_str()) );
402 std::ofstream pidf (tempname.c_str());
403 pidf << ::getpid() << std::endl;
406 LIBC_CALL( ::unlink, (tempname.c_str()) );
412 ///////////////////////////////////////////////////////////////////////////
413 // senf::detail::DaemonWatcher
415 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
416 int stdout, int stderr)
417 : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
418 stderr_(stderr), sigChld_(false),
419 coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
420 cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
422 coutForwarder_.addTarget(1);
424 coutForwarder_.addTarget(stdout_);
425 cerrForwarder_.addTarget(2);
427 cerrForwarder_.addTarget(stderr_);
430 prefix_ void senf::detail::DaemonWatcher::run()
432 Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this));
433 Scheduler::instance().process();
436 ////////////////////////////////////////
439 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
442 case 1 : coutpipe_ = -1; break;
443 case 2 : cerrpipe_ = -1; break;
446 if (coutpipe_ == -1 && cerrpipe_ == -1) {
448 childDied(); // does not return
449 if (::kill(childPid_, SIGUSR1) < 0)
450 if (errno != ESRCH) SENF_THROW_SYSTEM_EXCEPTION("::kill()");
451 Scheduler::instance().timeout(
452 Scheduler::instance().eventTime() + ClockService::seconds(1),
453 senf::membind(&DaemonWatcher::childOk, this));
457 prefix_ void senf::detail::DaemonWatcher::sigChld()
460 if (coutpipe_ == -1 && cerrpipe_ == -1)
461 childDied(); // does not return
464 prefix_ void senf::detail::DaemonWatcher::childDied()
467 if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()");
468 if (WIFSIGNALED(status)) {
469 ::signal(WTERMSIG(status),SIG_DFL);
470 ::kill(::getpid(), WTERMSIG(status));
471 // should not be reached
474 if (WEXITSTATUS(status) == 0)
476 ::_exit(WEXITSTATUS(status));
479 prefix_ void senf::detail::DaemonWatcher::childOk()
481 Scheduler::instance().terminate();
484 ///////////////////////////////////////////////////////////////////////////
485 // senf::detail::DaemonWatcher::Forwarder
487 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
490 Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
494 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
497 Scheduler::instance().remove(src_);
499 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
500 if (i->offset >= buffer_.size())
501 Scheduler::instance().remove(i->fd);
504 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
506 Target target = { fd, 0 };
507 targets_.push_back(target);
510 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
516 n = ::read(src_,buf,1024);
518 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::read()");
525 Scheduler::instance().remove(src_);
532 if (targets_.empty())
535 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
536 if (i->offset >= buffer_.size())
537 Scheduler::instance().add( i->fd,
538 boost::bind(&Forwarder::writeData, this, _1, i),
539 Scheduler::EV_WRITE );
541 buffer_.insert(buffer_.end(), buf, buf+n);
544 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event,
545 Targets::iterator target)
547 if (event != Scheduler::EV_WRITE) {
548 // Broken pipe while writing data ? Not much, we can do here, we just drop the data
549 Scheduler::instance().remove(target->fd);
550 targets_.erase(target);
551 if (targets_.empty() && src_ == -1)
557 int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
558 std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
560 int w (::write(target->fd, buf, n));
562 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
567 n = std::min_element(
568 targets_.begin(), targets_.end(),
569 boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
571 buffer_.erase(buffer_.begin(), buffer_.begin()+n);
573 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
576 if (target->offset >= buffer_.size())
577 Scheduler::instance().remove(target->fd);
578 if (src_ == -1 && (buffer_.empty() || targets_.empty()))
585 ///////////////////////////////cc.e////////////////////////////////////////
587 //#include "Daemon.mpp"
593 // comment-column: 40
594 // c-file-style: "senf"
595 // indent-tabs-mode: nil
596 // ispell-local-dictionary: "american"
597 // compile-command: "scons -u test"