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