4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer NETwork research (NET)
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 "../Utils/Exception.hh"
40 #include "../Utils/membind.hh"
42 //#include "Daemon.mpp"
44 ///////////////////////////////cc.p////////////////////////////////////////
46 #define LIBC_CALL(fn, args) if (fn args < 0) throwErrno(#fn "()")
47 #define LIBC_CALL_RV(var, fn, args) int var (fn args); if (var < 0) throwErrno(#fn "()")
49 ///////////////////////////////////////////////////////////////////////////
52 prefix_ senf::Daemon::~Daemon()
54 if (! pidfile_.empty())
55 LIBC_CALL( ::unlink, (pidfile_.c_str()) );
58 prefix_ void senf::Daemon::daemonize(bool v)
63 prefix_ bool senf::Daemon::daemon()
68 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
72 fd = ::open(path.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
74 throwErrno("::open()");
90 prefix_ void senf::Daemon::pidFile(std::string const & f)
95 prefix_ void senf::Daemon::detach()
98 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
99 LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
100 LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
101 LIBC_CALL( ::close, (nul) );
103 // We need to wait here to give the daemon watcher time to flush all data to the log file.
106 ts.tv_nsec = 100 * 1000000ul;
107 while (::nanosleep(&ts,&ts) < 0 && errno == EINTR) ;
111 prefix_ int senf::Daemon::start(int argc, char const ** argv)
126 if (! pidfile_.empty() && ! pidfileCreate()) {
127 std::cerr << "\n*** PID file '" << pidfile_ << "' creation failed. Daemon running ?"
137 catch (std::exception & e) {
138 std::cerr << "\n*** Fatal exception: " << e.what() << std::endl;
142 std::cerr << "\n*** Fatal exception: (unknown)" << std::endl;
151 ////////////////////////////////////////
154 prefix_ senf::Daemon::Daemon()
155 : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
159 ////////////////////////////////////////
162 prefix_ void senf::Daemon::configure()
165 prefix_ void senf::Daemon::main()
172 prefix_ void senf::Daemon::init()
175 prefix_ void senf::Daemon::run()
178 prefix_ void senf::Daemon::fork()
183 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
184 LIBC_CALL( ::dup2, (nul, 0) );
185 LIBC_CALL( ::close, (nul) );
186 LIBC_CALL( ::pipe, (coutpipe) );
187 LIBC_CALL( ::pipe, (cerrpipe) );
189 // We need to block the SIGCHLD signal here so we don't miss it, if the child
193 ::sigemptyset(&cldsig);
194 LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
195 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
197 LIBC_CALL_RV( pid, ::fork, () );
202 LIBC_CALL( ::dup2, (coutpipe[1],1) );
203 LIBC_CALL( ::dup2, (cerrpipe[1],2) );
204 LIBC_CALL( ::close, (coutpipe[0]) );
205 LIBC_CALL( ::close, (coutpipe[1]) );
206 LIBC_CALL( ::close, (cerrpipe[0]) );
207 LIBC_CALL( ::close, (cerrpipe[1]) );
208 LIBC_CALL( ::setsid, () );
209 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
213 // Ouch ... ensure, the daemon watcher does not remove the pidfile ...
216 LIBC_CALL( ::close, (coutpipe[1]) );
217 LIBC_CALL( ::close, (cerrpipe[1]) );
219 detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
225 prefix_ bool senf::Daemon::pidfileCreate()
227 // Create temporary file pidfile_.hostname.pid and hard-link it to pidfile_ If the hardlink
228 // fails, the pidfile exists. If the link count of the temporary file is not 2 after this, there
229 // was some race condition, probably over NFS.
231 std::string tempname;
234 char hostname[HOST_NAME_MAX+1];
235 LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
236 hostname[HOST_NAME_MAX] = 0;
237 std::stringstream tempname_s;
238 tempname_s << pidfile_ << "." << hostname << "." << ::getpid();
239 tempname = tempname_s.str();
244 std::ofstream pidf (tempname.c_str());
245 pidf << ::getpid() << std::endl;
248 if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
250 throwErrno("::link()");
254 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
255 LIBC_CALL( ::unlink, (tempname.c_str()) );
256 return s.st_nlink == 2;
259 // pidfile exists. Check, whether the pid in the pidfile still exists.
262 std::ifstream pidf (pidfile_.c_str());
263 if ( ! (pidf >> old_pid)
265 || ::kill(old_pid, 0) >= 0
270 // If we reach this point, the pid file exists but the process mentioned within the
271 // pid file does *not* exists. We assume, the pid file to be stale.
273 // I hope, the following procedure is without race condition: We remove our generated
274 // temporary pid file and recreate it as hard-link to the old pid file. Now we check, that
275 // the hard-link count of this file is 2. If it is not, we terminate, since someone else
276 // must have already created his hardlink. We then truncate the file and write our pid.
278 LIBC_CALL( ::unlink, (tempname.c_str() ));
279 if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
280 if (errno != ENOENT) throwErrno("::link()");
281 // Hmm ... the pidfile mysteriously disappeared ... try again.
287 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
288 if (s.st_nlink != 2) {
289 LIBC_CALL( ::unlink, (tempname.c_str()) );
295 std::ofstream pidf (tempname.c_str());
296 pidf << ::getpid() << std::endl;
299 LIBC_CALL( ::unlink, (tempname.c_str()) );
305 ///////////////////////////////////////////////////////////////////////////
306 // senf::detail::DaemonWatcher
308 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
309 int stdout, int stderr)
310 : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
311 stderr_(stderr), sigChld_(false),
312 coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
313 cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
315 coutForwarder_.addTarget(1);
317 coutForwarder_.addTarget(stdout_);
318 cerrForwarder_.addTarget(2);
320 cerrForwarder_.addTarget(stderr_);
323 prefix_ void senf::detail::DaemonWatcher::run()
325 Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this));
326 Scheduler::instance().process();
329 ////////////////////////////////////////
332 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
335 case 1 : coutpipe_ = -1; break;
336 case 2 : cerrpipe_ = -1; break;
339 if (coutpipe_ == -1 && cerrpipe_ == -1) {
341 childDied(); // does not return
342 Scheduler::instance().timeout(
343 Scheduler::instance().eventTime() + ClockService::seconds(1),
344 senf::membind(&DaemonWatcher::childOk, this));
348 prefix_ void senf::detail::DaemonWatcher::sigChld()
351 if (coutpipe_ == -1 && cerrpipe_ == -1)
352 childDied(); // does not return
355 prefix_ void senf::detail::DaemonWatcher::childDied()
358 if (::waitpid(childPid_,&status,0) < 0) throwErrno("::waitpid()");
359 if (WIFSIGNALED(status)) {
360 ::signal(WTERMSIG(status),SIG_DFL);
361 ::kill(::getpid(), WTERMSIG(status));
362 // should not be reached
365 if (WEXITSTATUS(status) == 0)
367 ::_exit(WEXITSTATUS(status));
370 prefix_ void senf::detail::DaemonWatcher::childOk()
372 Scheduler::instance().terminate();
375 ///////////////////////////////////////////////////////////////////////////
376 // senf::detail::DaemonWatcher::Forwarder
378 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
381 Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
385 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
388 Scheduler::instance().remove(src_);
390 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
391 if (i->offset >= buffer_.size())
392 Scheduler::instance().remove(i->fd);
395 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
397 Target target = { fd, 0 };
398 targets_.push_back(target);
401 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
407 n = ::read(src_,buf,1024);
409 if (errno != EINTR) throwErrno("::read()");
416 Scheduler::instance().remove(src_);
423 if (targets_.empty())
426 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
427 if (i->offset >= buffer_.size())
428 Scheduler::instance().add( i->fd,
429 boost::bind(&Forwarder::writeData, this, _1, i),
430 Scheduler::EV_WRITE );
432 buffer_.insert(buffer_.end(), buf, buf+n);
435 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event,
436 Targets::iterator target)
438 if (event != Scheduler::EV_WRITE) {
439 // Broken pipe while writing data ? Not much, we can do here, we just drop the data
440 Scheduler::instance().remove(target->fd);
441 targets_.erase(target);
442 if (targets_.empty() && src_ == -1)
448 int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
449 std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
451 int w (::write(target->fd, buf, n));
453 if (errno != EINTR) throwErrno("::write()");
458 n = std::min_element(
459 targets_.begin(), targets_.end(),
460 boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
462 buffer_.erase(buffer_.begin(), buffer_.begin()+n);
464 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
467 if (target->offset >= buffer_.size())
468 Scheduler::instance().remove(target->fd);
469 if (src_ == -1 && (buffer_.empty() || targets_.empty()))
476 ///////////////////////////////cc.e////////////////////////////////////////
478 //#include "Daemon.mpp"
484 // comment-column: 40
485 // c-file-style: "senf"
486 // indent-tabs-mode: nil
487 // ispell-local-dictionary: "american"
488 // compile-command: "scons -u test"