13668eec5b648a20efdeff29c73fb3bb2b26bfd8
[senf.git] / Utils / Daemon / Daemon.cc
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
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.
12 //
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.
17 //
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.
22
23 /** \file
24     \brief Daemon non-inline non-template implementation */
25
26 #include "Daemon.hh"
27 #include "Daemon.ih"
28
29 // Custom includes
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/wait.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include <sstream>
38 #include <algorithm>
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"
44
45 //#include "Daemon.mpp"
46 #define prefix_
47 ///////////////////////////////cc.p////////////////////////////////////////
48
49 #define LIBC_CALL(fn, args) if (fn args < 0) \
50     SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
51
52 #define LIBC_CALL_RV(var, fn, args) \
53     int var (fn args); if (var < 0) SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
54
55 ///////////////////////////////////////////////////////////////////////////
56 // senf::Daemon
57
58 prefix_ senf::Daemon::~Daemon()
59 {
60     if (! pidfile_.empty()) {
61         try {
62             LIBC_CALL( ::unlink, (pidfile_.c_str()) );
63         } catch (Exception e) {
64             // e << "; could not unlink " << pidfile_.c_str();
65             // throw;
66         }
67     }
68 }
69
70 prefix_ void senf::Daemon::daemonize(bool v)
71 {
72     daemonize_ = v;
73 }
74
75 prefix_ bool senf::Daemon::daemon()
76 {
77     return daemonize_;
78 }
79
80 prefix_ int senf::Daemon::argc() {
81     return argc_;
82 }
83
84 prefix_ char const ** senf::Daemon::argv() {
85     return argv_;
86 }
87
88 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
89 {
90     switch (which) {
91     case StdOut : stdoutLog_ = path; break;
92     case StdErr : stderrLog_ = path; break;
93     case Both : stdoutLog_ = path; stderrLog_ = path; break;
94     }
95 }
96
97
98 prefix_ void senf::Daemon::openLog()
99 {
100     int fd (-1);
101     if (! stdoutLog_.empty()) {
102         fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
103         if (fd < 0)
104             SENF_THROW_SYSTEM_EXCEPTION("")
105                   << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout.";
106         stdout_ = fd;
107     }
108     if (stderrLog_ == stdoutLog_)
109         stderr_ = fd;
110     else if (! stderrLog_.empty()) {
111         fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
112         if (fd < 0)
113             SENF_THROW_SYSTEM_EXCEPTION("")
114                   << " Could not open \"" << stderrLog_ << "\" for redirecting stderr.";
115         stderr_ = fd;
116     }
117 }
118
119 prefix_ void senf::Daemon::pidFile(std::string const & f)
120 {
121     pidfile_ = f;
122 }
123
124 namespace {
125     bool signaled (false);
126     void waitusr(int) {
127         signaled = true;
128     }
129 }
130
131 prefix_ void senf::Daemon::detach()
132 {
133     if (daemonize_ && ! detached_) {
134         // Wow .. ouch .. 
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.
140         ::sigset_t oldsig;
141         ::sigset_t usrsig;
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) );
152
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) );
157
158         signaled = false;
159         while (! signaled) {
160             ::sigsuspend(&waitsig);
161             if (errno != EINTR)
162                 SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()");
163         }
164
165         LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
166         LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
167
168         detached_ = true;
169     }
170 }
171
172 namespace {
173     /* Purposely *not* derived from std::exception */
174     struct DaemonExitException {
175         DaemonExitException(unsigned c) : code(c) {}
176         unsigned code;
177     };
178 }
179
180 prefix_ void senf::Daemon::exit(unsigned code)
181 {
182     throw DaemonExitException(code);
183 }
184
185 prefix_ int senf::Daemon::start(int argc, char const ** argv)
186 {
187     argc_ = argc;
188     argv_ = argv;
189
190     try {
191         configure();
192
193         if (daemonize_) {
194             openLog();
195             fork();
196         }
197         if (! pidfile_.empty() && ! pidfileCreate()) {
198             std::cerr << "\n*** PID file '" << pidfile_ << "' creation failed. Daemon running ?" 
199                       << std::endl;
200             return 1;
201         }
202
203         main();
204     }
205     catch (DaemonExitException & e) {
206         return e.code;
207     }
208
209 #ifndef SENF_DEBUG
210
211     catch (std::exception & e) {
212         std::cerr << "\n*** Fatal exception: " << e.what() << std::endl;
213         return 1;
214     }
215     catch (...) {
216         std::cerr << "\n*** Fatal exception: (unknown)" << std::endl;
217         return 1;
218     }
219
220 #   endif
221
222     return 0;
223 }
224
225 ////////////////////////////////////////
226 // protected members
227
228 prefix_ senf::Daemon::Daemon()
229     : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
230       detached_(false)
231 {}
232
233 ////////////////////////////////////////
234 // private members
235
236 prefix_ void senf::Daemon::configure()
237 {
238     for (int i (1); i<argc_; ++i) {
239         if (argv_[i] == std::string("--no-daemon"))
240             daemonize(false);
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) {
245                 boost::trim(arg);
246                 if (arg == std::string("none")) consoleLog("");
247                 else if (!arg.empty())          consoleLog(arg);
248             } else {
249                 std::string arg1 (arg,0,komma);
250                 std::string arg2 (arg,komma+1);
251                 boost::trim(arg1);
252                 boost::trim(arg2);
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);
257             }
258         }
259         else if (boost::starts_with(argv_[i], std::string("--pid-file="))) 
260             pidFile(std::string(std::string(argv_[i]), 11u));
261     }
262 }
263
264 prefix_ void senf::Daemon::main()
265 {
266     init();
267     detach();
268     run();
269 }
270
271 prefix_ void senf::Daemon::init()
272 {}
273
274 prefix_ void senf::Daemon::run()
275 {}
276
277 prefix_ void senf::Daemon::fork()
278 {
279     int coutpipe[2];
280     int cerrpipe[2];
281
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) );
287
288     // We need to block the SIGCHLD signal here so we don't miss it, if the child
289     // dies immediately
290     ::sigset_t oldsig;
291     ::sigset_t cldsig;
292     ::sigemptyset(&cldsig);
293     LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
294     LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
295     
296     LIBC_CALL_RV( pid, ::fork, () );
297
298     if (pid == 0) {
299         // Daemon process
300
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) );
309         return;
310     }
311
312     // Ouch ... ensure, the daemon watcher does not remove the pidfile ...
313     pidfile_ = "";
314     
315     LIBC_CALL( ::close, (coutpipe[1]) );
316     LIBC_CALL( ::close, (cerrpipe[1]) );
317
318     detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
319     watcher.run();
320
321     ::_exit(0);
322 }
323
324 prefix_ bool senf::Daemon::pidfileCreate()
325 {
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.
329
330     std::string tempname;
331     boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\".");
332
333     {
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();
340     }
341
342     while (1) {
343         {
344             std::ofstream pidf (tempname.c_str());
345             if (! pidf)
346                 SENF_THROW_SYSTEM_EXCEPTION("")
347                       << " Could not open pidfile \"" << tempname << "\" for output.";
348             pidf << ::getpid() << std::endl;
349             if (! pidf)
350                 SENF_THROW_SYSTEM_EXCEPTION("")
351                       << " Could not write to pidfile \"" << tempname << "\".";
352         }
353
354         if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
355             if (errno != EEXIST) 
356                 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % pidfile_ % tempname;
357         }
358         else {
359             struct ::stat s;
360             LIBC_CALL( ::stat, (tempname.c_str(), &s) );
361             LIBC_CALL( ::unlink, (tempname.c_str()) );
362             return s.st_nlink == 2;
363         }
364
365         // pidfile exists. Check, whether the pid in the pidfile still exists.
366         {
367             int old_pid (-1);
368             std::ifstream pidf (pidfile_.c_str());
369             if ( ! (pidf >> old_pid)
370                  || old_pid < 0 
371                  || ::kill(old_pid, 0) >= 0 
372                  || errno == EPERM )
373                 return false;
374         }
375
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.
378
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.
383
384         LIBC_CALL( ::unlink, (tempname.c_str() ));
385         if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
386             if (errno != ENOENT)
387                 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % tempname % pidfile_;
388             // Hmm ... the pidfile mysteriously disappeared ... try again.
389             continue;
390         }
391
392         {
393             struct ::stat s;
394             LIBC_CALL( ::stat, (tempname.c_str(), &s) );
395             if (s.st_nlink != 2) {
396                 LIBC_CALL( ::unlink, (tempname.c_str()) );
397                 return false;
398             }
399         }
400         
401         {
402             std::ofstream pidf (tempname.c_str());
403             pidf << ::getpid() << std::endl;
404         }
405
406         LIBC_CALL( ::unlink, (tempname.c_str()) );
407         break;
408     }
409     return true;
410 }
411
412 ///////////////////////////////////////////////////////////////////////////
413 // senf::detail::DaemonWatcher
414
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)) 
421 {
422     coutForwarder_.addTarget(1);
423     if (stdout_ >= 0)
424         coutForwarder_.addTarget(stdout_);
425     cerrForwarder_.addTarget(2);
426     if (stderr_ >= 0)
427         cerrForwarder_.addTarget(stderr_);
428 }
429
430 prefix_ void senf::detail::DaemonWatcher::run()
431 {
432     Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this));
433     Scheduler::instance().process();
434 }
435
436 ////////////////////////////////////////
437 // private members
438
439 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
440 {
441     switch (id) {
442     case 1 : coutpipe_ = -1; break;
443     case 2 : cerrpipe_ = -1; break;
444     }
445
446     if (coutpipe_ == -1 && cerrpipe_ == -1) {
447         if (sigChld_)
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));
454     }
455 }
456
457 prefix_ void senf::detail::DaemonWatcher::sigChld()
458 {
459     sigChld_ = true;
460     if (coutpipe_ == -1 && cerrpipe_ == -1)
461         childDied(); // does not return
462 }
463
464 prefix_ void senf::detail::DaemonWatcher::childDied()
465 {
466     int status (0);
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
472         ::_exit(1);
473     }
474     if (WEXITSTATUS(status) == 0)
475         ::_exit(1);
476     ::_exit(WEXITSTATUS(status));
477 }
478
479 prefix_ void senf::detail::DaemonWatcher::childOk()
480 {
481     Scheduler::instance().terminate();
482 }
483
484 ///////////////////////////////////////////////////////////////////////////
485 // senf::detail::DaemonWatcher::Forwarder
486
487 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
488     : src_(src), cb_(cb)
489 {
490     Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
491                               Scheduler::EV_READ);
492 }
493
494 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
495 {
496     if (src_ != -1)
497         Scheduler::instance().remove(src_);
498     
499     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
500         if (i->offset >= buffer_.size())
501             Scheduler::instance().remove(i->fd);
502 }
503
504 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
505 {
506     Target target = { fd, 0 };
507     targets_.push_back(target);
508 }
509
510 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
511 {
512     char buf[1024];
513     int n (0);
514
515     while (1) {
516         n = ::read(src_,buf,1024);
517         if (n<0) {
518             if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::read()");
519         } else 
520             break;
521     }
522
523     if (n == 0) {
524         // Hangup
525         Scheduler::instance().remove(src_);
526         if (buffer_.empty())
527             cb_(); 
528         src_ = -1;
529         return;
530     }
531
532     if (targets_.empty())
533         return;
534
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 );
540
541     buffer_.insert(buffer_.end(), buf, buf+n);
542 }
543
544 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event,
545                                                                Targets::iterator target)
546 {    
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)
552             cb_();
553         return;
554     }
555
556     char buf[1024];
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);
559
560     int w (::write(target->fd, buf, n));
561     if (w < 0) {
562         if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
563         return;
564     }
565     target->offset += w;
566
567     n = std::min_element(
568         targets_.begin(), targets_.end(),
569         boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
570
571     buffer_.erase(buffer_.begin(), buffer_.begin()+n);
572
573     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
574         i->offset -= n;
575
576     if (target->offset >= buffer_.size())
577         Scheduler::instance().remove(target->fd);
578     if (src_ == -1 && (buffer_.empty() || targets_.empty()))
579         cb_();
580 }
581
582 #undef LIBC_CALL
583 #undef LIBC_CALL_RV
584
585 ///////////////////////////////cc.e////////////////////////////////////////
586 #undef prefix_
587 //#include "Daemon.mpp"
588
589 \f
590 // Local Variables:
591 // mode: c++
592 // fill-column: 100
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"
598 // End: