chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_STATE_DIR/run/icinga2/cmd
chmod 2755 $ICINGA2_STATE_DIR/run/icinga2/cmd
- echo "Starting Icinga 2: "
- $DAEMON -c $ICINGA2_CONFIG_FILE -d -e $ICINGA2_ERROR_LOG -u $ICINGA2_USER -g $ICINGA2_GROUP
-
- echo "Done"
- echo
+ echo "Starting Icinga 2: "
+ if ! $DAEMON -c $ICINGA2_CONFIG_FILE -d -e $ICINGA2_ERROR_LOG -u $ICINGA2_USER -g $ICINGA2_GROUP; then
+ echo "Error starting Icinga."
+ exit 1
+ else
+ echo "Done"
+ fi
}
# Restart Icinga 2
# Reload Icinga 2
reload() {
printf "Reloading Icinga 2: "
- if [ ! -e $ICINGA2_PID_FILE ]; then
- echo "The PID file '$ICINGA2_PID_FILE' does not exist."
+ if ! $DAEMON -c $ICINGA2_CONFIG_FILE -d --reload -e $ICINGA2_ERROR_LOG -u $ICINGA2_USER -g $ICINGA2_GROUP; then
+ echo "Error reloading Icinga."
exit 1
- fi
-
- pid=`cat $ICINGA2_PID_FILE`
-
- if ! kill -HUP $pid >/dev/null 2>&1; then
- echo "Failed - Icinga 2 is not running."
else
echo "Done"
fi
start
;;
reload)
- checkconfig reload fail
reload
;;
checkconfig)
return true;
}
+/**
+ * Terminate another process and wait till it has ended
+ *
+ * @params target PID of the process to end
+ */
+static void TerminateAndWaitForEnd(pid_t target)
+{
+#ifndef _WIN32
+ // allow 15 seconds timeout
+ double timeout = Utility::GetTime() + 15;
+
+ int ret = kill(target, SIGTERM);
+
+ while(Utility::GetTime() < timeout && (ret==0 || errno!=ESRCH))
+ {
+ Utility::Sleep(0.1);
+ ret = kill(target, 0);
+ }
+
+ // timeout and the process still seems to live: kill it
+ if (ret == 0 || errno != ESRCH)
+ kill(target, SIGKILL);
+
+#else
+ // TODO: implement this for Win32
+#endif /* _WIN32 */
+}
+
int Main(void)
{
int argc = Application::GetArgC();
("validate,C", "exit after validating the configuration")
("debug,x", "enable debugging")
("errorlog,e", po::value<std::string>(), "log fatal errors to the specified log file (only works in combination with --daemonize)")
+ ("reload,r", "reload a running icinga instance")
#ifndef _WIN32
("daemonize,d", "detach from the controlling terminal")
("user,u", po::value<std::string>(), "user to run Icinga as")
return EXIT_FAILURE;
}
+ pid_t runningpid = Application::ReadPidFile(Application::GetPidPath());
+ if (g_AppParams.count("reload")) {
+ if (runningpid < 0) {
+ Log(LogCritical, "icinga-app", "No instance of Icinga currently running: can't reload.");
+ return EXIT_FAILURE;
+ }
+ } else if (!g_AppParams.count("validate") && runningpid >= 0) {
+ Log(LogCritical, "icinga-app", "Another instance of Icinga already running at PID " + Convert::ToString(runningpid));
+ return EXIT_FAILURE;
+ }
+
if (!LoadConfigFiles(appType))
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
+ if (g_AppParams.count("reload")) {
+ Log(LogInformation, "icinga-app", "Terminating previous instance of icinga (PID " + Convert::ToString(runningpid) + ")");
+ TerminateAndWaitForEnd(runningpid);
+ Log(LogInformation, "icinga-app", "Previous instance has ended, taking over now.");
+ }
+
if (g_AppParams.count("daemonize")) {
String errorLog;
}
#endif /* _WIN32 */
- fprintf(m_PidFile, "%d", Utility::GetPid());
+ fprintf(m_PidFile, "%d\n", Utility::GetPid());
fflush(m_PidFile);
}
m_PidFile = NULL;
}
+/**
+ * Checks if another process currently owns the pidfile and read it
+ *
+ * @param filename The name of the PID file.
+ * @returns -1: no process owning the pidfile, pid of the process otherwise
+ */
+pid_t Application::ReadPidFile(const String& filename)
+{
+ FILE *pidfile = fopen(filename.CStr(), "r");
+
+ if (pidfile == NULL)
+ return -1;
+
+#ifndef _WIN32
+ int fd = fileno(pidfile);
+
+ struct flock lock;
+
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+
+ if (fcntl(fd, F_GETLK, &lock) < 0) {
+ int error = errno;
+ fclose(pidfile);
+ BOOST_THROW_EXCEPTION(posix_error()
+ << boost::errinfo_api_function("fcntl")
+ << boost::errinfo_errno(error));
+ }
+
+ if (lock.l_type == F_UNLCK) {
+ // nobody has locked the file: no icinga running
+ fclose(pidfile);
+ return -1;
+ }
+#endif /* _WIN32 */
+
+ pid_t runningpid;
+ int res = fscanf(pidfile, "%d", &runningpid);
+ fclose(pidfile);
+
+ // bogus result?
+ if (res != 1)
+ return -1;
+
+#ifdef _WIN32
+ // TODO: add check if the read pid is still running or not
+#endif /* _WIN32 */
+
+ return runningpid;
+}
+
+
/**
* Retrieves the path of the installation prefix.
*
void UpdatePidFile(const String& filename);
void ClosePidFile(void);
+ static pid_t ReadPidFile(const String& filename);
static String GetExePath(const String& argv0);