Implemented senf::Daemon::arg[cv] member functions
[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 "../Exception.hh"
42 #include "../membind.hh"
43
44 //#include "Daemon.mpp"
45 #define prefix_
46 ///////////////////////////////cc.p////////////////////////////////////////
47
48 #define LIBC_CALL(fn, args) if (fn args < 0) throw SystemException(#fn "()")
49 #define LIBC_CALL_RV(var, fn, args) int var (fn args); if (var < 0) throw SystemException(#fn "()")
50
51 ///////////////////////////////////////////////////////////////////////////
52 // senf::Daemon
53
54 prefix_ senf::Daemon::~Daemon()
55 {
56     if (! pidfile_.empty())
57         LIBC_CALL( ::unlink, (pidfile_.c_str()) );
58 }
59
60 prefix_ void senf::Daemon::daemonize(bool v)
61 {
62     daemonize_ = v;
63 }
64
65 prefix_ bool senf::Daemon::daemon()
66 {
67     return daemonize_;
68 }
69
70 prefix_ int senf::Daemon::argc() {
71     return argc_;
72 }
73
74 prefix_ char const ** senf::Daemon::argv() {
75     return argv_;
76 }
77
78 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
79 {
80     switch (which) {
81     case StdOut : stdoutLog_ = path; break;
82     case StdErr : stderrLog_ = path; break;
83     case Both : stdoutLog_ = path; stderrLog_ = path; break;
84     }
85 }
86
87
88 prefix_ void senf::Daemon::openLog()
89 {
90     int fd (-1);
91     if (! stdoutLog_.empty()) {
92         fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
93         if (fd < 0)
94             throw SystemException("::open()");
95         stdout_ = fd;
96     }
97     if (stderrLog_ == stdoutLog_)
98         stderr_ = fd;
99     else if (! stderrLog_.empty()) {
100         fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
101         if (fd < 0)
102             throw SystemException("::open()");
103         stderr_ = fd;
104     }
105 }
106
107 prefix_ void senf::Daemon::pidFile(std::string const & f)
108 {
109     pidfile_ = f;
110 }
111
112 namespace {
113     bool signaled (false);
114     void waitusr(int) {
115         signaled = true;
116     }
117 }
118
119 prefix_ void senf::Daemon::detach()
120 {
121     if (daemonize_ && ! detached_) {
122         // Wow .. ouch .. 
123         // To ensure all data is written to the console log file in the correct order, we suspend
124         // execution here until the parent process tells us to continue via SIGUSR1: We block
125         // SIGUSR1 and install our own signal handler saving the old handler and signal mask. Then
126         // we close stdin/stderr which will send a HUP condition to the parent process. We wait for
127         // SIGUSR1 and reinstall the old signal mask and action.
128         ::sigset_t oldsig;
129         ::sigset_t usrsig;
130         ::sigemptyset(&usrsig);
131         LIBC_CALL( ::sigaddset, (&usrsig, SIGUSR1) );
132         LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &usrsig, &oldsig) );
133         struct ::sigaction oldact;
134         struct ::sigaction usract;
135         ::memset(&usract, 0, sizeof(usract));
136         usract.sa_handler = &waitusr;
137         LIBC_CALL( ::sigaction, (SIGUSR1, &usract, &oldact) );
138         ::sigset_t waitsig (oldsig);
139         LIBC_CALL( ::sigdelset, (&waitsig, SIGUSR1) );
140
141         LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
142         LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
143         LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
144         LIBC_CALL( ::close, (nul) );
145
146         signaled = false;
147         while (! signaled) {
148             ::sigsuspend(&waitsig);
149             if (errno != EINTR)
150                 throw SystemException("::sigsuspend()");
151         }
152
153         LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
154         LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
155
156         detached_ = true;
157     }
158 }
159
160 namespace {
161     /* Purposely *not* derived from std::exception */
162     struct DaemonExitException {
163         DaemonExitException(unsigned c) : code(c) {}
164         unsigned code;
165     };
166 }
167
168 prefix_ void senf::Daemon::exit(unsigned code)
169 {
170     throw DaemonExitException(code);
171 }
172
173 prefix_ int senf::Daemon::start(int argc, char const ** argv)
174 {
175     argc_ = argc;
176     argv_ = argv;
177
178     try {
179         configure();
180
181         if (daemonize_) {
182             openLog();
183             fork();
184         }
185         if (! pidfile_.empty() && ! pidfileCreate()) {
186             std::cerr << "\n*** PID file '" << pidfile_ << "' creation failed. Daemon running ?" 
187                       << std::endl;
188             return 1;
189         }
190
191         main();
192     }
193     catch (DaemonExitException & e) {
194         return e.code;
195     }
196
197 #ifndef SENF_DEBUG
198
199     catch (std::exception & e) {
200         std::cerr << "\n*** Fatal exception: " << e.what() << std::endl;
201         return 1;
202     }
203     catch (...) {
204         std::cerr << "\n*** Fatal exception: (unknown)" << std::endl;
205         return 1;
206     }
207
208 #   endif
209
210     return 0;
211 }
212
213 ////////////////////////////////////////
214 // protected members
215
216 prefix_ senf::Daemon::Daemon()
217     : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
218       detached_(false)
219 {}
220
221 ////////////////////////////////////////
222 // private members
223
224 prefix_ void senf::Daemon::configure()
225 {
226     for (int i (1); i<argc_; ++i) {
227         if (argv_[i] == std::string("--no-daemon"))
228             daemonize(false);
229         else if (boost::starts_with(argv_[i], std::string("--console-log="))) {
230             std::string arg (std::string(argv_[i]), 14u);
231             std::string::size_type komma (arg.find(','));
232             if (komma == std::string::npos) {
233                 boost::trim(arg);
234                 if (arg == std::string("none")) consoleLog("");
235                 else if (!arg.empty())          consoleLog(arg);
236             } else {
237                 std::string arg1 (arg,0,komma);
238                 std::string arg2 (arg,komma+1);
239                 boost::trim(arg1);
240                 boost::trim(arg2);
241                 if (arg1 == std::string("none")) consoleLog("",StdOut);
242                 else if (! arg1.empty() )        consoleLog(arg1, StdOut);
243                 if (arg2 == std::string("none")) consoleLog("",StdErr);
244                 else if (! arg2.empty() )        consoleLog(arg2, StdErr);
245             }
246         }
247         else if (boost::starts_with(argv_[i], std::string("--pid-file="))) 
248             pidFile(std::string(std::string(argv_[i]), 11u));
249     }
250 }
251
252 prefix_ void senf::Daemon::main()
253 {
254     init();
255     detach();
256     run();
257 }
258
259 prefix_ void senf::Daemon::init()
260 {}
261
262 prefix_ void senf::Daemon::run()
263 {}
264
265 prefix_ void senf::Daemon::fork()
266 {
267     int coutpipe[2];
268     int cerrpipe[2];
269
270     LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
271     LIBC_CALL( ::dup2, (nul, 0) );
272     LIBC_CALL( ::close, (nul) );
273     LIBC_CALL( ::pipe, (coutpipe) );
274     LIBC_CALL( ::pipe, (cerrpipe) );
275
276     // We need to block the SIGCHLD signal here so we don't miss it, if the child
277     // dies immediately
278     ::sigset_t oldsig;
279     ::sigset_t cldsig;
280     ::sigemptyset(&cldsig);
281     LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
282     LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
283     
284     LIBC_CALL_RV( pid, ::fork, () );
285
286     if (pid == 0) {
287         // Daemon process
288
289         LIBC_CALL( ::dup2, (coutpipe[1],1) );
290         LIBC_CALL( ::dup2, (cerrpipe[1],2) );
291         LIBC_CALL( ::close, (coutpipe[0]) );
292         LIBC_CALL( ::close, (coutpipe[1]) );
293         LIBC_CALL( ::close, (cerrpipe[0]) );
294         LIBC_CALL( ::close, (cerrpipe[1]) );
295         LIBC_CALL( ::setsid, () );
296         LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
297         return;
298     }
299
300     // Ouch ... ensure, the daemon watcher does not remove the pidfile ...
301     pidfile_ = "";
302     
303     LIBC_CALL( ::close, (coutpipe[1]) );
304     LIBC_CALL( ::close, (cerrpipe[1]) );
305
306     detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
307     watcher.run();
308
309     ::_exit(0);
310 }
311
312 prefix_ bool senf::Daemon::pidfileCreate()
313 {
314     // Create temporary file pidfile_.hostname.pid and hard-link it to pidfile_ If the hardlink
315     // fails, the pidfile exists. If the link count of the temporary file is not 2 after this, there
316     // was some race condition, probably over NFS.
317
318     std::string tempname;
319
320     {
321         char hostname[HOST_NAME_MAX+1];
322         LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
323         hostname[HOST_NAME_MAX] = 0;
324         std::stringstream tempname_s;
325         tempname_s << pidfile_ << "." << hostname << "." << ::getpid();
326         tempname = tempname_s.str();
327     }
328
329     while (1) {
330         {
331             std::ofstream pidf (tempname.c_str());
332             pidf << ::getpid() << std::endl;
333         }
334
335         if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
336             if (errno != EEXIST) 
337                 throw SystemException("::link()");
338         }
339         else {
340             struct ::stat s;
341             LIBC_CALL( ::stat, (tempname.c_str(), &s) );
342             LIBC_CALL( ::unlink, (tempname.c_str()) );
343             return s.st_nlink == 2;
344         }
345
346         // pidfile exists. Check, whether the pid in the pidfile still exists.
347         {
348             int old_pid (-1);
349             std::ifstream pidf (pidfile_.c_str());
350             if ( ! (pidf >> old_pid)
351                  || old_pid < 0 
352                  || ::kill(old_pid, 0) >= 0 
353                  || errno == EPERM )
354                 return false;
355         }
356
357         // If we reach this point, the pid file exists but the process mentioned within the
358         // pid file does *not* exists. We assume, the pid file to be stale.
359
360         // I hope, the following procedure is without race condition: We remove our generated
361         // temporary pid file and recreate it as hard-link to the old pid file. Now we check, that
362         // the hard-link count of this file is 2. If it is not, we terminate, since someone else
363         // must have already created his hardlink. We then truncate the file and write our pid.
364
365         LIBC_CALL( ::unlink, (tempname.c_str() ));
366         if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
367             if (errno != ENOENT) throw SystemException("::link()");
368             // Hmm ... the pidfile mysteriously disappeared ... try again.
369             continue;
370         }
371
372         {
373             struct ::stat s;
374             LIBC_CALL( ::stat, (tempname.c_str(), &s) );
375             if (s.st_nlink != 2) {
376                 LIBC_CALL( ::unlink, (tempname.c_str()) );
377                 return false;
378             }
379         }
380         
381         {
382             std::ofstream pidf (tempname.c_str());
383             pidf << ::getpid() << std::endl;
384         }
385
386         LIBC_CALL( ::unlink, (tempname.c_str()) );
387         break;
388     }
389     return true;
390 }
391
392 ///////////////////////////////////////////////////////////////////////////
393 // senf::detail::DaemonWatcher
394
395 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
396                                                    int stdout, int stderr)
397     : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
398       stderr_(stderr), sigChld_(false),
399       coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)), 
400       cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2)) 
401 {
402     coutForwarder_.addTarget(1);
403     if (stdout_ >= 0)
404         coutForwarder_.addTarget(stdout_);
405     cerrForwarder_.addTarget(2);
406     if (stderr_ >= 0)
407         cerrForwarder_.addTarget(stderr_);
408 }
409
410 prefix_ void senf::detail::DaemonWatcher::run()
411 {
412     Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this));
413     Scheduler::instance().process();
414 }
415
416 ////////////////////////////////////////
417 // private members
418
419 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
420 {
421     switch (id) {
422     case 1 : coutpipe_ = -1; break;
423     case 2 : cerrpipe_ = -1; break;
424     }
425
426     if (coutpipe_ == -1 && cerrpipe_ == -1) {
427         if (sigChld_)
428             childDied(); // does not return
429         if (::kill(childPid_, SIGUSR1) < 0)
430             if (errno != ESRCH) throw SystemException("::kill()");
431         Scheduler::instance().timeout(
432             Scheduler::instance().eventTime() + ClockService::seconds(1),
433             senf::membind(&DaemonWatcher::childOk, this));
434     }
435 }
436
437 prefix_ void senf::detail::DaemonWatcher::sigChld()
438 {
439     sigChld_ = true;
440     if (coutpipe_ == -1 && cerrpipe_ == -1)
441         childDied(); // does not return
442 }
443
444 prefix_ void senf::detail::DaemonWatcher::childDied()
445 {
446     int status (0);
447     if (::waitpid(childPid_,&status,0) < 0) throw SystemException("::waitpid()");
448     if (WIFSIGNALED(status)) {
449         ::signal(WTERMSIG(status),SIG_DFL);
450         ::kill(::getpid(), WTERMSIG(status));
451         // should not be reached
452         ::_exit(1);
453     }
454     if (WEXITSTATUS(status) == 0)
455         ::_exit(1);
456     ::_exit(WEXITSTATUS(status));
457 }
458
459 prefix_ void senf::detail::DaemonWatcher::childOk()
460 {
461     Scheduler::instance().terminate();
462 }
463
464 ///////////////////////////////////////////////////////////////////////////
465 // senf::detail::DaemonWatcher::Forwarder
466
467 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
468     : src_(src), cb_(cb)
469 {
470     Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
471                               Scheduler::EV_READ);
472 }
473
474 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
475 {
476     if (src_ != -1)
477         Scheduler::instance().remove(src_);
478     
479     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
480         if (i->offset >= buffer_.size())
481             Scheduler::instance().remove(i->fd);
482 }
483
484 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
485 {
486     Target target = { fd, 0 };
487     targets_.push_back(target);
488 }
489
490 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
491 {
492     char buf[1024];
493     int n (0);
494
495     while (1) {
496         n = ::read(src_,buf,1024);
497         if (n<0) {
498             if (errno != EINTR) throw SystemException("::read()");
499         } else 
500             break;
501     }
502
503     if (n == 0) {
504         // Hangup
505         Scheduler::instance().remove(src_);
506         if (buffer_.empty())
507             cb_(); 
508         src_ = -1;
509         return;
510     }
511
512     if (targets_.empty())
513         return;
514
515     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
516         if (i->offset >= buffer_.size())
517             Scheduler::instance().add( i->fd, 
518                                        boost::bind(&Forwarder::writeData, this, _1, i),
519                                        Scheduler::EV_WRITE );
520
521     buffer_.insert(buffer_.end(), buf, buf+n);
522 }
523
524 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event,
525                                                                Targets::iterator target)
526 {    
527     if (event != Scheduler::EV_WRITE) {
528         // Broken pipe while writing data ? Not much, we can do here, we just drop the data
529         Scheduler::instance().remove(target->fd);
530         targets_.erase(target);
531         if (targets_.empty() && src_ == -1)
532             cb_();
533         return;
534     }
535
536     char buf[1024];
537     int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
538     std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
539
540     int w (::write(target->fd, buf, n));
541     if (w < 0) {
542         if (errno != EINTR) throw SystemException("::write()");
543         return;
544     }
545     target->offset += w;
546
547     n = std::min_element(
548         targets_.begin(), targets_.end(),
549         boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
550
551     buffer_.erase(buffer_.begin(), buffer_.begin()+n);
552
553     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
554         i->offset -= n;
555
556     if (target->offset >= buffer_.size())
557         Scheduler::instance().remove(target->fd);
558     if (src_ == -1 && (buffer_.empty() || targets_.empty()))
559         cb_();
560 }
561
562 #undef LIBC_CALL
563 #undef LIBC_CALL_RV
564
565 ///////////////////////////////cc.e////////////////////////////////////////
566 #undef prefix_
567 //#include "Daemon.mpp"
568
569 \f
570 // Local Variables:
571 // mode: c++
572 // fill-column: 100
573 // comment-column: 40
574 // c-file-style: "senf"
575 // indent-tabs-mode: nil
576 // ispell-local-dictionary: "american"
577 // compile-command: "scons -u test"
578 // End: