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