diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index 05d359d77..3b023fad8 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -161,7 +161,7 @@ static void SigHupHandler(int) } #endif /* _WIN32 */ -static bool Daemonize(const String& stderrFile) +static bool Daemonize(void) { #ifndef _WIN32 pid_t pid = fork(); @@ -170,11 +170,38 @@ static bool Daemonize(const String& stderrFile) } if (pid) { - // TODO: do a real wait till the pidfile is written by the daemon - Utility::Sleep(5); + // systemd requires that the pidfile of the daemon is written before the forking + // process terminates. So wait till either the forked daemon has written a pidfile or died. + + int status; + int ret; + pid_t readpid; + do { + Utility::Sleep(0.1); + + readpid = Application::ReadPidFile(Application::GetPidPath()); + ret = waitpid(pid, &status, WNOHANG); + } while (readpid != pid && ret == 0); + + if (ret == pid) { + Log(LogCritical, "icinga-app", "The daemon could not be started. See logfile for details."); + exit(EXIT_FAILURE); + } else if (ret == -1) { + BOOST_THROW_EXCEPTION(posix_error() + << boost::errinfo_api_function("waitpid") + << boost::errinfo_errno(errno)); + } + exit(0); } +#endif /* _WIN32 */ + return true; +} + +static bool SetDaemonIO(const String& stderrFile) +{ +#ifndef _WIN32 int fdnull = open("/dev/null", O_RDWR); if (fdnull >= 0) { if (fdnull != 0) @@ -486,13 +513,17 @@ int Main(void) Log(LogInformation, "icinga-app", "Previous instance has ended, taking over now."); } - if (g_AppParams.count("daemonize") && !g_AppParams.count("reload-internal")) { - String errorLog; + if (g_AppParams.count("daemonize")) { + if (!g_AppParams.count("reload-internal")) { + // no additional fork neccessary on reload + Daemonize(); + } + String errorLog; if (g_AppParams.count("errorlog")) errorLog = g_AppParams["errorlog"].as(); - Daemonize(errorLog); + SetDaemonIO(errorLog); Logger::DisableConsoleLog(); } diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 4dca02028..9de7f7d4d 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -96,10 +96,11 @@ void Application::Stop(void) // means that the restart succeeded and the new process wants to take // over. Write the PID of the new process to the pidfile before this // process exits to keep systemd happy. - if (l_Restarting) - UpdatePidFile(GetPidPath(),m_ReloadProcess); - - ClosePidFile(); + if (l_Restarting) { + UpdatePidFile(GetPidPath(), m_ReloadProcess); + ClosePidFile(false); + } else + ClosePidFile(true); DynamicObject::Stop(); } @@ -681,13 +682,20 @@ void Application::UpdatePidFile(const String& filename, pid_t pid) /** * Closes the PID file. Does nothing if the PID file is not currently open. */ -void Application::ClosePidFile(void) +void Application::ClosePidFile(bool unlink) { ASSERT(!OwnsLock()); ObjectLock olock(this); if (m_PidFile != NULL) + { + if (unlink) { + String pidpath = GetPidPath(); + ::unlink(pidpath.CStr()); + } + fclose(m_PidFile); + } m_PidFile = NULL; } diff --git a/lib/base/application.h b/lib/base/application.h index 28e589d96..490937d07 100644 --- a/lib/base/application.h +++ b/lib/base/application.h @@ -69,7 +69,7 @@ public: static bool IsDebugging(void); void UpdatePidFile(const String& filename, pid_t pid = Utility::GetPid()); - void ClosePidFile(void); + void ClosePidFile(bool unlink); static pid_t ReadPidFile(const String& filename); static String GetExePath(const String& argv0);