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