diff --git a/config.h.cmake b/config.h.cmake index e8a7bdcba..c461e029f 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -21,7 +21,7 @@ #define ICINGA_INCLUDECONFDIR "${CMAKE_INSTALL_FULL_DATADIR}/icinga2/include" #define ICINGA_USER "${ICINGA2_USER}" #define ICINGA_GROUP "${ICINGA2_GROUP}" - +#define ICINGA_SYSCONFIGFILE "${ICINGA2_SYSCONFIGFILE}" #define ICINGA_BUILD_HOST_NAME "${ICINGA2_BUILD_HOST_NAME}" #define ICINGA_BUILD_COMPILER_NAME "${ICINGA2_BUILD_COMPILER_NAME}" #define ICINGA_BUILD_COMPILER_VERSION "${ICINGA2_BUILD_COMPILER_VERSION}" diff --git a/doc/17-language-reference.md b/doc/17-language-reference.md index 196cc2e54..01aba61d0 100644 --- a/doc/17-language-reference.md +++ b/doc/17-language-reference.md @@ -389,8 +389,8 @@ ObjectsPath |**Read-write.** Contains the path of the Icinga 2 objects f PidPath |**Read-write.** Contains the path of the Icinga 2 PID file. Defaults to RunDir + "/icinga2/icinga2.pid". Vars |**Read-write.** Contains a dictionary with global custom attributes. Not set by default. NodeName |**Read-write.** Contains the cluster node name. Set to the local hostname by default. -RunAsUser |**Read-write.** Defines the user the Icinga 2 daemon is running as. Used in the `init.conf` configuration file. -RunAsGroup |**Read-write.** Defines the group the Icinga 2 daemon is running as. Used in the `init.conf` configuration file. +RunAsUser |**Read-write.** Defines the user the Icinga 2 daemon is running as. Set in the Icinga 2 sysconfig. +RunAsGroup |**Read-write.** Defines the group the Icinga 2 daemon is running as. Set in the Icinga 2 sysconfig. PlatformName |**Read-only.** The name of the operating system, e.g. "Ubuntu". PlatformVersion |**Read-only.** The version of the operating system, e.g. "14.04.3 LTS". PlatformKernel |**Read-only.** The name of the operating system kernel, e.g. "Linux". @@ -407,9 +407,9 @@ Variable |Description --------------------|------------------- EventEngine |**Read-write.** The name of the socket event engine, can be `poll` or `epoll`. The epoll interface is only supported on Linux. AttachDebugger |**Read-write.** Whether to attach a debugger when Icinga 2 crashes. Defaults to `false`. -RLimitFiles |**Read-write.** Defines the resource limit for RLIMIT_NOFILE that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file. -RLimitProcesses |**Read-write.** Defines the resource limit for RLIMIT_NPROC that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file. -RLimitStack |**Read-write.** Defines the resource limit for RLIMIT_STACK that should be set at start-up. Value cannot be set lower than the default `256 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file. +RLimitFiles |**Read-write.** Defines the resource limit for RLIMIT_NOFILE that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig. +RLimitProcesses |**Read-write.** Defines the resource limit for RLIMIT_NPROC that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig. +RLimitStack |**Read-write.** Defines the resource limit for RLIMIT_STACK that should be set at start-up. Value cannot be set lower than the default `256 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig. ## Apply diff --git a/etc/CMakeLists.txt b/etc/CMakeLists.txt index bce13366b..bffca3016 100644 --- a/etc/CMakeLists.txt +++ b/etc/CMakeLists.txt @@ -15,8 +15,6 @@ # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -configure_file(icinga2/init.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/icinga2/init.conf @ONLY) - if(NOT WIN32) configure_file(icinga2/constants.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/icinga2/constants.conf @ONLY) endif() @@ -25,8 +23,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") configure_file(logrotate.d/icinga2.cmake ${CMAKE_CURRENT_BINARY_DIR}/logrotate.d/icinga2 @ONLY) endif() -install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/icinga2/init.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) - if(NOT WIN32) install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/icinga2/constants.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) install_if_not_exists(icinga2/icinga2.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) diff --git a/etc/icinga2/init.conf.cmake b/etc/icinga2/init.conf.cmake deleted file mode 100644 index 9f57bca82..000000000 --- a/etc/icinga2/init.conf.cmake +++ /dev/null @@ -1,7 +0,0 @@ -/** - * This file is read by Icinga 2 before the main - * configuration file (icinga2.conf) is processed. - */ - -const RunAsUser = "@ICINGA2_USER@" -const RunAsGroup = "@ICINGA2_GROUP@" diff --git a/etc/initsystem/icinga2.init.d.cmake b/etc/initsystem/icinga2.init.d.cmake index 080fb2779..bc41ccf67 100644 --- a/etc/initsystem/icinga2.init.d.cmake +++ b/etc/initsystem/icinga2.init.d.cmake @@ -31,16 +31,14 @@ if [ ! -e $ICINGA2_CONFIG_FILE ]; then exit 6 fi -ICINGA2_USER=`$DAEMON variable get --current RunAsUser` -if [ $? != 0 ]; then - echo "Could not fetch RunAsUser variable. Error '$ICINGA2_USER'. Exiting." - exit 6 +if [ ! $ICINGA2_USER ]; then + echo "Could not fetch \$ICINGA2_USER. Exiting." + exit 6 fi -ICINGA2_GROUP=`$DAEMON variable get --current RunAsGroup` -if [ $? != 0 ]; then - echo "Could not fetch RunAsGroup variable. Error '$ICINGA2_GROUP'. Exiting." - exit 6 +if [ ! $ICINGA2_GROUP ]; then + echo "Could not fetch \$ICINGA2_GROUP. Exiting." + exit 6 fi getent passwd $ICINGA2_USER >/dev/null 2>&1 || (echo "Icinga user '$ICINGA2_USER' does not exist. Exiting." && exit 6) @@ -49,14 +47,14 @@ getent group $ICINGA2_COMMAND_GROUP >/dev/null 2>&1 || (echo "Icinga command gro # Get function from functions library if [ -f /etc/rc.d/init.d/functions ]; then - . /etc/rc.d/init.d/functions + . /etc/rc.d/init.d/functions elif [ -f /etc/init.d/functions ]; then - . /etc/init.d/functions + . /etc/init.d/functions fi # Load extra environment variables if [ -f /etc/default/icinga2 ]; then - . /etc/default/icinga2 + . /etc/default/icinga2 fi # Start Icinga 2 @@ -74,34 +72,33 @@ start() { # Restart Icinga 2 stop() { - printf "Stopping Icinga 2: " + printf "Stopping Icinga 2: " - if [ ! -e $ICINGA2_PID_FILE ]; then - echo "The PID file '$ICINGA2_PID_FILE' does not exist." - if [ "x$1" = "xnofail" ]; then + if [ ! -e $ICINGA2_PID_FILE ]; then + echo "The PID file '$ICINGA2_PID_FILE' does not exist." + if [ "x$1" = "xnofail" ]; then return else exit 7 fi - fi + fi pid=`cat $ICINGA2_PID_FILE` - - if kill -INT $pid >/dev/null 2>&1; then + + if icinga2 internal signal -s SIGINT -p $pid >/dev/null 2>&1; then for i in 1 2 3 4 5 6 7 8 9 10; do - if ! kill -CHLD $pid >/dev/null 2>&1; then + if ! icinga2 internal signal -s SIGCHLD -p $pid >/dev/null 2>&1; then break fi printf '.' - sleep 3 done fi - if kill -CHLD $pid >/dev/null 2>&1; then - kill -KILL $pid - fi + if icinga2 internal signal -s SIGCHLD -p $pid >/dev/null 2>&1; then + icinga2 internal signal -s SIGKILL -p $pid >/dev/null 2>&1 + fi echo "Done" } @@ -116,21 +113,21 @@ checkconfig() { printf "Checking configuration: " if ! $DAEMON daemon -c $ICINGA2_CONFIG_FILE -C > $ICINGA2_STARTUP_LOG 2>&1; then - if [ "x$1" = "x" ]; then + if [ "x$1" = "x" ]; then cat $ICINGA2_STARTUP_LOG echo "Icinga 2 detected configuration errors. Check '$ICINGA2_STARTUP_LOG' for details." - exit 1 - else + exit 1 + else echo "Not "$1"ing Icinga 2 due to configuration errors. Check '$ICINGA2_STARTUP_LOG' for details." - if [ "x$2" = "xfail" ]; then - exit 1 - fi - fi - fi - + if [ "x$2" = "xfail" ]; then + exit 1 + fi + fi + fi + echo "Done" # no arguments requires full output - if [ "x$1" = "x" ]; then + if [ "x$1" = "x" ]; then cat $ICINGA2_STARTUP_LOG fi } @@ -145,7 +142,7 @@ status() { fi pid=`cat $ICINGA2_PID_FILE` - if kill -CHLD $pid >/dev/null 2>&1; then + if icinga2 internal signal -s SIGCHLD -p $pid >/dev/null 2>&1; then echo "Running" else echo "Not running" @@ -157,33 +154,34 @@ status() { case "$1" in start) checkconfig start fail - start - ;; + start + ;; stop) - stop - ;; + stop + ;; status) - status - ;; + status + ;; restart) checkconfig restart fail - stop nofail - start - ;; + stop nofail + start + ;; condrestart) - status > /dev/null 2>&1 || exit 0 - checkconfig restart fail - stop nofail - start - ;; + status > /dev/null 2>&1 || exit 0 + checkconfig restart fail + stop nofail + start + ;; reload) reload - ;; + ;; checkconfig) checkconfig - ;; + ;; *) - echo "Usage: $0 {start|stop|restart|reload|checkconfig|status}" - exit 3 + echo "Usage: $0 {start|stop|restart|reload|checkconfig|status}" + exit 3 esac + exit 0 diff --git a/etc/initsystem/icinga2.sysconfig.cmake b/etc/initsystem/icinga2.sysconfig.cmake index e7fa54baf..7daf305be 100644 --- a/etc/initsystem/icinga2.sysconfig.cmake +++ b/etc/initsystem/icinga2.sysconfig.cmake @@ -3,9 +3,10 @@ ICINGA2_CONFIG_FILE=@CMAKE_INSTALL_FULL_SYSCONFDIR@/icinga2/icinga2.conf ICINGA2_RUN_DIR=@ICINGA2_RUNDIR@ ICINGA2_STATE_DIR=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@ ICINGA2_PID_FILE=$ICINGA2_RUN_DIR/icinga2/icinga2.pid -ICINGA2_ERROR_LOG=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/error.log -ICINGA2_STARTUP_LOG=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/startup.log -ICINGA2_LOG=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/icinga2.log +ICINGA2_LOG_DIR=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2 +ICINGA2_ERROR_LOG=$ICINGA2_LOG_DIR/error.log +ICINGA2_STARTUP_LOG=$ICINGA2_LOG_DIR/startup.log +ICINGA2_LOG=$ICINGA2_LOG_DIR/icinga2.log ICINGA2_CACHE_DIR=$ICINGA2_STATE_DIR/cache/icinga2 ICINGA2_USER=@ICINGA2_USER@ ICINGA2_GROUP=@ICINGA2_GROUP@ diff --git a/etc/initsystem/prepare-dirs b/etc/initsystem/prepare-dirs index 5d67d476d..44b8343a8 100644 --- a/etc/initsystem/prepare-dirs +++ b/etc/initsystem/prepare-dirs @@ -13,49 +13,42 @@ else fi -ICINGA2_USER=`$DAEMON variable get --current RunAsUser` -if [ $? != 0 ]; then - echo "Could not fetch RunAsUser variable. Error '$ICINGA2_USER'. Exiting." - exit 6 +if [ ! $ICINGA2_USER ]; then + echo "Could not fetch \$ICINGA2_USER. Exiting." + exit 6 fi -ICINGA2_GROUP=`$DAEMON variable get --current RunAsGroup` -if [ $? != 0 ]; then - echo "Could not fetch RunAsGroup variable. Error '$ICINGA2_GROUP'. Exiting." - exit 6 +if [ ! $ICINGA2_GROUP ]; then + echo "Could not fetch \$ICINGA2_GROUP. Exiting." + exit 6 fi getent passwd $ICINGA2_USER >/dev/null 2>&1 || (echo "Icinga user '$ICINGA2_USER' does not exist. Exiting." && exit 6) getent group $ICINGA2_GROUP >/dev/null 2>&1 || (echo "Icinga group '$ICINGA2_GROUP' does not exist. Exiting." && exit 6) getent group $ICINGA2_COMMAND_GROUP >/dev/null 2>&1 || (echo "Icinga command group '$ICINGA2_COMMAND_GROUP' does not exist. Exiting." && exit 6) -mkdir -p $(dirname -- $ICINGA2_PID_FILE) -chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $(dirname -- $ICINGA2_PID_FILE) -if [ -f $ICINGA2_PID_FILE ]; then - chown $ICINGA2_USER:$ICINGA2_GROUP $ICINGA2_PID_FILE +if [ ! -e "$ICINGA2_RUN_DIR"/icinga2 ]; then + mkdir "$ICINGA2_RUN_DIR"/icinga2 + mkdir "$ICINGA2_RUN_DIR"/icinga2/cmd + chmod 755 "$ICINGA2_RUN_DIR"/icinga2 + chmod 2750 "$ICINGA2_RUN_DIR"/icinga2/cmd + chown -R $ICINGA2_USER:$ICINGA2_COMMAND_GROUP "$ICINGA2_RUN_DIR"/icinga2 fi -mkdir -p $(dirname -- $ICINGA2_ERROR_LOG) -chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $(dirname -- $ICINGA2_ERROR_LOG) -chmod 750 $(dirname -- $ICINGA2_ERROR_LOG) -if [ -f $ICINGA2_ERROR_LOG ]; then - chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_ERROR_LOG -fi -if [ -f $ICINGA2_LOG ]; then - chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_LOG +# Could be undefined in installations where sysconf is not overridden on upgrade +if [ -z "$ICINGA2_LOG_DIR" ]; then + $ICINGA2_LOG_DIR=$(dirname -- "$ICINGA2_LOG") fi -mkdir -p $ICINGA2_RUN_DIR/icinga2/cmd -chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_RUN_DIR/icinga2/cmd +test -e "$ICINGA2_LOG_DIR" || install -m 750 -o $ICINGA2_USER -g $ICINGA2_COMMAND_GROUP -d "$ICINGA2_LOG_DIR" + if type restorecon >/dev/null 2>&1; then - restorecon -R $ICINGA2_RUN_DIR/icinga2/ + restorecon -R "$ICINGA2_RUN_DIR"/icinga2/ fi -chmod 2750 $ICINGA2_RUN_DIR/icinga2/cmd # Add a fallback if the user did not specify this directory in the sysconfig file if [ -z "$ICINGA2_CACHE_DIR" ]; then - ICINGA2_CACHE_DIR=$ICINGA2_STATE_DIR/cache/icinga2 + ICINGA2_CACHE_DIR="$ICINGA2_STATE_DIR"/cache/icinga2 fi -mkdir -p $ICINGA2_CACHE_DIR -chown $ICINGA2_USER:$ICINGA2_GROUP $ICINGA2_CACHE_DIR -chmod 750 $ICINGA2_CACHE_DIR + +test -e "$ICINGA2_CACHE_DIR" || install -m 750 -o $ICINGA2_USER -g $ICINGA2_COMMAND_GROUP -d "$ICINGA2_CACHE_DIR" diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index ef6627818..af8a1dda9 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -143,6 +143,7 @@ static int Main() #endif /* _WIN32 */ Application::DeclarePrefixDir(ICINGA_PREFIX); + Application::DeclareSysconfigFile(ICINGA_SYSCONFIGFILE); Application::DeclareSysconfDir(ICINGA_SYSCONFDIR); Application::DeclareRunDir(ICINGA_RUNDIR); Application::DeclareLocalStateDir(ICINGA_LOCALSTATEDIR); @@ -153,13 +154,63 @@ static int Main() #endif /* _WIN32 */ Application::DeclareZonesDir(Application::GetSysconfDir() + "/icinga2/zones.d"); - Application::DeclareRunAsUser(ICINGA_USER); - Application::DeclareRunAsGroup(ICINGA_GROUP); -#ifdef __linux__ - Application::DeclareRLimitFiles(Application::GetDefaultRLimitFiles()); - Application::DeclareRLimitProcesses(Application::GetDefaultRLimitProcesses()); - Application::DeclareRLimitStack(Application::GetDefaultRLimitStack()); -#endif /* __linux__ */ + + String icingaUser = Utility::GetFromSysconfig("ICINGA2_USER"); + if (icingaUser.IsEmpty()) + icingaUser = ICINGA_USER; + + String icingaGroup = Utility::GetFromSysconfig("ICINGA2_GROUP"); + if (icingaGroup.IsEmpty()) + icingaGroup = ICINGA_GROUP; + + Application::DeclareRunAsUser(icingaUser); + Application::DeclareRunAsGroup(icingaGroup); + +#ifdef RLIMIT_NOFILE + String rLimitFiles = Utility::GetFromSysconfig("ICINGA2_RLIMIT_FILES"); + if (rLimitFiles.IsEmpty()) + Application::DeclareRLimitFiles(Application::GetDefaultRLimitFiles()); + else { + try { + Application::DeclareRLimitFiles(Convert::ToLong(rLimitFiles)); + } catch (const std::invalid_argument& ex) { + std::cout + << "Error while parsing \"ICINGA2_RLIMIT_FILES\" from sysconfig: " << ex.what() << '\n'; + return EXIT_FAILURE; + } + } +#endif /* RLIMIT_NOFILE */ + +#ifdef RLIMIT_NPROC + String rLimitProcesses = Utility::GetFromSysconfig("ICINGA2_RLIMIT_PROCESSES"); + if (rLimitProcesses.IsEmpty()) + Application::DeclareRLimitProcesses(Application::GetDefaultRLimitProcesses()); + else { + try { + Application::DeclareRLimitProcesses(Convert::ToLong(rLimitProcesses)); + } catch (const std::invalid_argument& ex) { + std::cout + << "Error while parsing \"ICINGA2_RLIMIT_PROCESSES\" from sysconfig: " << ex.what() << '\n'; + return EXIT_FAILURE; + } + } +#endif /* RLIMIT_NPROC */ + +#ifdef RLIMIT_STACK + String rLimitStack = Utility::GetFromSysconfig("ICINGA2_RLIMIT_STACK"); + if (rLimitStack.IsEmpty()) + Application::DeclareRLimitStack(Application::GetDefaultRLimitStack()); + else { + try { + Application::DeclareRLimitStack(Convert::ToLong(rLimitStack)); + } catch (const std::invalid_argument& ex) { + std::cout + << "Error while parsing \"ICINGA2_RLIMIT_STACK\" from sysconfig: " << ex.what() << '\n'; + return EXIT_FAILURE; + } + } +#endif /* RLIMIT_STACK */ + Application::DeclareConcurrency(std::thread::hardware_concurrency()); Application::DeclareMaxConcurrentChecks(Application::GetDefaultMaxConcurrentChecks()); @@ -175,21 +226,6 @@ static int Main() ScriptGlobal::Set("BuildCompilerName", ICINGA_BUILD_COMPILER_NAME); ScriptGlobal::Set("BuildCompilerVersion", ICINGA_BUILD_COMPILER_VERSION); - String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf"; - - if (Utility::PathExists(initconfig)) { - std::unique_ptr expression; - try { - expression = ConfigCompiler::CompileFile(initconfig); - - ScriptFrame frame(true); - expression->Evaluate(frame); - } catch (const std::exception& ex) { - Log(LogCritical, "config", DiagnosticInformation(ex)); - return EXIT_FAILURE; - } - } - if (!autocomplete) Application::SetResourceLimits(); diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 7c552eaeb..1c1aa6776 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -1326,6 +1326,27 @@ void Application::DeclareStatePath(const String& path) ScriptGlobal::Set("StatePath", path); } +/** + * Retrives the path of the sysconfig file. + * + * @returns The path. + */ +String Application::GetSysconfigFile(void) +{ + return ScriptGlobal::Get("SysconfigFile"); +} + +/** + * Sets the path of the sysconfig file. + * + * @param path The new path. + */ +void Application::DeclareSysconfigFile(const String& path) +{ + if (!ScriptGlobal::Exists("SysconfigFile")) + ScriptGlobal::Set("SysconfigFile", path); +} + /** * Retrieves the path for the modified attributes file. * diff --git a/lib/base/application.hpp b/lib/base/application.hpp index ecdb1e92b..03d83599b 100644 --- a/lib/base/application.hpp +++ b/lib/base/application.hpp @@ -106,7 +106,10 @@ public: static String GetIncludeConfDir(); static void DeclareIncludeConfDir(const String& path); - static String GetStatePath(); + static String GetSysconfigFile(void); + static void DeclareSysconfigFile(const String& path); + + static String GetStatePath(void); static void DeclareStatePath(const String& path); static String GetModAttrPath(); diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index f9cf18cdb..6869e353d 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -1935,3 +1935,35 @@ String Utility::GetIcingaDataPath() } #endif /* _WIN32 */ + +String Utility::GetFromSysconfig(const String& env) +{ +#ifndef _WIN32 + String sysconf = Application::GetSysconfigFile(); + if (sysconf.IsEmpty()) + return ""; + + String cmdInner = ". " + EscapeShellArg(sysconf) + " 2>&1 >/dev/null;echo \"$" + env + "\""; + String cmd = "sh -c " + EscapeShellArg(cmdInner); + + FILE *fp = popen(cmd.CStr(), "r"); + + if (!fp) + return ""; + + char line[1024]; + String out; + + if (fgets(line, sizeof(line), fp)) + out = line; + else + return ""; + + pclose(fp); + + return out.Trim(); +#else + //TODO: Figure out how to do this on windows + return ""; +#endif /* _WIN32 */ +} diff --git a/lib/base/utility.hpp b/lib/base/utility.hpp index dd542c30a..97bb834b8 100644 --- a/lib/base/utility.hpp +++ b/lib/base/utility.hpp @@ -147,6 +147,8 @@ public: static String GetIcingaDataPath(); #endif /* _WIN32 */ + static String GetFromSysconfig(const String& env); + #ifdef I2_DEBUG static void SetTime(double); static void IncrementTime(double); diff --git a/lib/cli/CMakeLists.txt b/lib/cli/CMakeLists.txt index bb2c75f47..258597dec 100644 --- a/lib/cli/CMakeLists.txt +++ b/lib/cli/CMakeLists.txt @@ -30,6 +30,7 @@ set(cli_SOURCES featureenablecommand.cpp featureenablecommand.hpp featurelistcommand.cpp featurelistcommand.hpp featureutility.cpp featureutility.hpp + internalsignalcommand.cpp internalsignalcommand.hpp nodesetupcommand.cpp nodesetupcommand.hpp nodeutility.cpp nodeutility.hpp nodewizardcommand.cpp nodewizardcommand.hpp diff --git a/lib/cli/internalsignalcommand.cpp b/lib/cli/internalsignalcommand.cpp new file mode 100644 index 000000000..3e196728d --- /dev/null +++ b/lib/cli/internalsignalcommand.cpp @@ -0,0 +1,84 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "cli/internalsignalcommand.hpp" +#include "base/logger.hpp" +#include + +using namespace icinga; +namespace po = boost::program_options; + +REGISTER_CLICOMMAND("internal/signal", InternalSignalCommand); + +String InternalSignalCommand::GetDescription() const +{ + return "Send signal as Icinga user"; +} + +String InternalSignalCommand::GetShortDescription() const +{ + return "Send signal as Icinga user"; +} + +ImpersonationLevel InternalSignalCommand::GetImpersonationLevel() const +{ + return ImpersonateIcinga; +} + +bool InternalSignalCommand::IsHidden() const +{ + return true; +} + +void InternalSignalCommand::InitParameters(boost::program_options::options_description& visibleDesc, + boost::program_options::options_description& hiddenDesc) const +{ + visibleDesc.add_options() + ("pid,p", po::value(), "Target PID") + ("sig,s", po::value(), "Signal (POSIX string) to send") + ; +} + +/** + * The entry point for the "internal signal" CLI command. + * + * @returns An exit status. + */ +int InternalSignalCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const +{ +#ifndef _WIN32 + String signal = vm["sig"].as(); + + /* Thank POSIX */ + if (signal == "SIGKILL") + return kill(vm["pid"].as(), SIGKILL); + if (signal == "SIGINT") + return kill(vm["pid"].as(), SIGINT); + if (signal == "SIGCHLD") + return kill(vm["pid"].as(), SIGCHLD); + if (signal == "SIGHUP") + return kill(vm["pid"].as(), SIGHUP); + + Log(LogCritical, "cli") << "Unsupported signal \"" << signal << "\""; +#else + Log(LogCritical, "cli", "Unsupported action on Windows."); +#endif /* _Win32 */ + return 1; +} + diff --git a/lib/cli/internalsignalcommand.hpp b/lib/cli/internalsignalcommand.hpp new file mode 100644 index 000000000..44830ccd9 --- /dev/null +++ b/lib/cli/internalsignalcommand.hpp @@ -0,0 +1,50 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef INTERNALSIGNALCOMMAND_H +#define INTERNALSIGNALCOMMAND_H + +#include "cli/clicommand.hpp" + +namespace icinga +{ + +/** + * The "internal signal" command. + * + * @ingroup cli + */ +class InternalSignalCommand final : public CLICommand +{ +public: + DECLARE_PTR_TYPEDEFS(InternalSignalCommand); + + String GetDescription() const override; + String GetShortDescription() const override; + ImpersonationLevel GetImpersonationLevel() const override; + bool IsHidden() const override; + void InitParameters(boost::program_options::options_description& visibleDesc, + boost::program_options::options_description& hiddenDesc) const override; + int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; + +}; + +} + +#endif /* INTERNALSIGNALCOMMAND_H */