}
}
+prefix_ void senf::Daemon::logReopen()
+{
+ if (! stdoutLog_.empty()) {
+ int fd (::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
+ if (fd < 0)
+ goto error;
+ if (::dup2(fd, 1) < 0)
+ goto error;
+ if (stderrLog_ == stdoutLog_) {
+ if (::dup2(fd, 2) < 0)
+ goto error;
+ return;
+ }
+ }
+ if (! stderrLog_.empty()) {
+ int fd (::open(stderrLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
+ if (fd < 0)
+ goto error;
+ if (::dup2(fd, 2) < 0)
+ goto error;
+ }
+ return;
+
+ error:
+ SENF_LOG(
+ (senf::log::CRITICAL)
+ ("log-file reopen failed: (" << errno << ") " << ::strerror(errno)) );
+}
+
prefix_ void senf::Daemon::pidFile(std::string const & f)
{
pidfile_ = f;
return 0;
}
+prefix_ senf::Daemon & senf::Daemon::instance()
+{
+ BOOST_ASSERT( instance_ );
+ return *instance_;
+}
+
////////////////////////////////////////
// protected members
prefix_ senf::Daemon::Daemon()
: argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
pidfileCreated_(false), detached_(false)
-{}
+{
+ BOOST_ASSERT( ! instance_ );
+ instance_ = this;
+}
+
+senf::Daemon * senf::Daemon::instance_ (0);
////////////////////////////////////////
// private members
#endif
+namespace {
+ void sighupHandler(int sig)
+ {
+ senf::Daemon::instance().logReopen();
+ }
+}
+
prefix_ void senf::Daemon::installSighandlers()
{
-#ifdef SENF_DEBUG
struct ::sigaction sa;
- sa.sa_sigaction = &fatalSignalsHandler;
+
::sigemptyset(&sa.sa_mask);
+ sa.sa_handler = &sighupHandler;
+ sa.sa_flags = SA_RESTART;
+
+ ::sigaction(SIGHUP, &sa, NULL);
+
+#ifdef SENF_DEBUG
+ sa.sa_sigaction = &fatalSignalsHandler;
sa.sa_flags = SA_RESTART | SA_SIGINFO;
::sigaction(SIGILL, &sa, NULL);
// Custom includes
#include <boost/utility.hpp>
+#include "../Logger/SenfLog.hh"
//#include "Daemon.mpp"
///////////////////////////////hh.p////////////////////////////////////////
class Daemon : boost::noncopyable
{
public:
+ SENF_LOG_CLASS_AREA();
+
///////////////////////////////////////////////////////////////////////////
// Types
static void exit(unsigned code=0); ///< Terminate daemon with failure
+ void logReopen(); ///< Reopen the log files
+ /**< This is used when rotating the logs. By default,
+ SIGHUP calls logReopen. */
+
///\}
int start(int argc, char ** argv); ///< Called from main() to launch daemon.
/**< Normally not called directly but from the
\ref SENF_DAEMON_MAIN macro. */
+ static Daemon & instance(); ///< Return the Daemon instance
+
protected:
Daemon();
bool pidfileCreated_;
bool detached_;
+
+ static Daemon * instance_;
};
/** \brief Provide \c main() function
return instance.start(argc, argv);
}
+ int pid;
+
int run(int argc, char ** argv)
{
- int pid (::fork());
+ pid = ::fork();
if (pid < 0) throw senf::SystemException("::fork()");
if (pid == 0) {
::_exit(myMain(argc, argv));
BOOST_CHECK( ! boost::filesystem::exists("invalid.log") );
BOOST_CHECK( ! boost::filesystem::exists("invalid.pid") );
- BOOST_CHECK( boost::filesystem::exists("testDaemon.pid") );
+ BOOST_REQUIRE( boost::filesystem::exists("testDaemon.pid") );
+ BOOST_REQUIRE( boost::filesystem::exists("testDaemon.log") );
+
+ boost::filesystem::rename("testDaemon.log", "testDaemon.log.1");
+ {
+ std::ifstream pidFile ("testDaemon.pid");
+ int pid (0);
+ BOOST_REQUIRE( pidFile >> pid );
+ BOOST_REQUIRE( pid != 0 );
+ ::kill(pid, SIGHUP);
+ }
+
delay(1000);
BOOST_CHECK( ! boost::filesystem::exists("testDaemon.pid") );
- BOOST_REQUIRE( boost::filesystem::exists("testDaemon.log") );
+ BOOST_CHECK( boost::filesystem::exists("testDaemon.log") );
+ BOOST_REQUIRE( boost::filesystem::exists("testDaemon.log.1") );
- std::ifstream log ("testDaemon.log");
+ std::ifstream log ("testDaemon.log.1");
std::stringstream data;
data << log.rdbuf();
BOOST_CHECK_EQUAL( data.str(), "Running init()\nRunning run()\n" );
BOOST_CHECK_NO_THROW( boost::filesystem::remove("testDaemon.log") );
+ BOOST_CHECK_NO_THROW( boost::filesystem::remove("testDaemon.log.1") );
}
///////////////////////////////cc.e////////////////////////////////////////