2019-02-25 14:48:22 +01:00
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2012-05-10 12:06:41 +02:00
2014-10-20 13:58:21 +02:00
# include "cli/clicommand.hpp"
2014-05-25 16:23:35 +02:00
# include "config/configcompilercontext.hpp"
# include "config/configcompiler.hpp"
# include "config/configitembuilder.hpp"
2018-08-07 13:55:41 +02:00
# include "config/expression.hpp"
2014-05-25 16:23:35 +02:00
# include "base/application.hpp"
2018-08-09 15:37:23 +02:00
# include "base/configuration.hpp"
2014-05-25 16:23:35 +02:00
# include "base/logger.hpp"
# include "base/timer.hpp"
# include "base/utility.hpp"
2015-03-18 13:24:31 +01:00
# include "base/loader.hpp"
2014-05-25 16:23:35 +02:00
# include "base/exception.hpp"
# include "base/convert.hpp"
2014-12-14 11:33:45 +01:00
# include "base/scriptglobal.hpp"
2014-05-25 16:23:35 +02:00
# include "base/context.hpp"
2014-10-17 09:45:46 +02:00
# include "base/console.hpp"
2016-09-29 12:35:10 +02:00
# include "base/process.hpp"
2013-11-03 13:45:26 +01:00
# include "config.h"
2013-03-15 18:21:29 +01:00
# include <boost/program_options.hpp>
2018-01-28 22:21:27 +01:00
# include <boost/algorithm/string/split.hpp>
2017-11-21 12:12:58 +01:00
# include <thread>
2012-05-28 10:41:21 +02:00
2014-10-13 13:43:05 +02:00
# ifndef _WIN32
# include <sys / types.h>
# include <pwd.h>
# include <grp.h>
2017-08-22 10:26:23 +02:00
# else
# include <windows.h>
# include <Lmcons.h>
# include <Shellapi.h>
# include <tchar.h>
2014-10-13 13:43:05 +02:00
# endif /* _WIN32 */
2012-04-13 13:10:35 +02:00
using namespace icinga ;
2013-02-02 23:22:27 +01:00
namespace po = boost : : program_options ;
2012-04-13 13:10:35 +02:00
2014-04-16 15:05:50 +02:00
# ifdef _WIN32
2015-08-10 15:28:10 +02:00
static SERVICE_STATUS l_SvcStatus ;
static SERVICE_STATUS_HANDLE l_SvcStatusHandle ;
static HANDLE l_Job ;
2014-04-16 15:05:50 +02:00
# endif /* _WIN32 */
2014-10-17 15:54:46 +02:00
static std : : vector < String > GetLogLevelCompletionSuggestions ( const String & arg )
2014-10-14 16:45:00 +02:00
{
std : : vector < String > result ;
2017-12-13 12:54:14 +01:00
2014-10-14 16:45:00 +02:00
String debugLevel = " debug " ;
if ( debugLevel . Find ( arg ) = = 0 )
result . push_back ( debugLevel ) ;
String noticeLevel = " notice " ;
if ( noticeLevel . Find ( arg ) = = 0 )
result . push_back ( noticeLevel ) ;
String informationLevel = " information " ;
if ( informationLevel . Find ( arg ) = = 0 )
result . push_back ( informationLevel ) ;
String warningLevel = " warning " ;
if ( warningLevel . Find ( arg ) = = 0 )
result . push_back ( warningLevel ) ;
String criticalLevel = " critical " ;
if ( criticalLevel . Find ( arg ) = = 0 )
result . push_back ( criticalLevel ) ;
return result ;
}
2014-10-17 15:54:46 +02:00
static std : : vector < String > GlobalArgumentCompletion ( const String & argument , const String & word )
{
if ( argument = = " include " )
return GetBashCompletionSuggestions ( " directory " , word ) ;
else if ( argument = = " log-level " )
return GetLogLevelCompletionSuggestions ( word ) ;
else
return std : : vector < String > ( ) ;
}
2018-07-31 11:59:09 +02:00
static void HandleLegacyDefines ( )
{
# ifdef _WIN32
String dataPrefix = Utility : : GetIcingaDataPath ( ) ;
# endif /* _WIN32 */
2018-08-09 15:37:23 +02:00
Value localStateDir = Configuration : : LocalStateDir ;
2018-08-07 17:58:22 +02:00
2018-07-31 11:59:09 +02:00
if ( ! localStateDir . IsEmpty ( ) ) {
Log ( LogWarning , " icinga-app " )
2018-08-07 17:58:22 +02:00
< < " Please do not set the deprecated 'LocalStateDir' constant, "
< < " use the 'DataDir', 'LogDir', 'CacheDir' and 'SpoolDir' constants instead! "
< < " For compatibility reasons, these are now set based on the 'LocalStateDir' constant. " ;
2018-07-31 11:59:09 +02:00
# ifdef _WIN32
2018-08-09 15:37:23 +02:00
Configuration : : DataDir = localStateDir + " \\ lib \\ icinga2 " ;
Configuration : : LogDir = localStateDir + " \\ log \\ icinga2 " ;
Configuration : : CacheDir = localStateDir + " \\ cache \\ icinga2 " ;
Configuration : : SpoolDir = localStateDir + " \\ spool \\ icinga2 " ;
2018-07-31 11:59:09 +02:00
} else {
2018-08-09 15:37:23 +02:00
Configuration : : LocalStateDir = dataPrefix + " \\ var " ;
2018-07-31 11:59:09 +02:00
# else /* _WIN32 */
2018-08-09 15:37:23 +02:00
Configuration : : DataDir = localStateDir + " /lib/icinga2 " ;
Configuration : : LogDir = localStateDir + " /log/icinga2 " ;
Configuration : : CacheDir = localStateDir + " /cache/icinga2 " ;
Configuration : : SpoolDir = localStateDir + " /spool/icinga2 " ;
2018-07-31 11:59:09 +02:00
} else {
2018-08-09 15:37:23 +02:00
Configuration : : LocalStateDir = ICINGA_LOCALSTATEDIR ;
2018-07-31 11:59:09 +02:00
# endif /* _WIN32 */
}
2018-08-09 15:37:23 +02:00
Value sysconfDir = Configuration : : SysconfDir ;
2018-07-31 11:59:09 +02:00
if ( ! sysconfDir . IsEmpty ( ) ) {
Log ( LogWarning , " icinga-app " )
2018-08-07 17:58:22 +02:00
< < " Please do not set the deprecated 'Sysconfdir' constant, use the 'ConfigDir' constant instead! For compatibility reasons, their value is set based on the 'SysconfDir' constant. " ;
2018-07-31 11:59:09 +02:00
# ifdef _WIN32
2018-08-09 15:37:23 +02:00
Configuration : : ConfigDir = sysconfDir + " \\ icinga2 " ;
2018-07-31 11:59:09 +02:00
} else {
2018-08-09 15:37:23 +02:00
Configuration : : SysconfDir = dataPrefix + " \\ etc " ;
2018-07-31 11:59:09 +02:00
# else /* _WIN32 */
2018-08-09 15:37:23 +02:00
Configuration : : ConfigDir = sysconfDir + " /icinga2 " ;
2018-07-31 11:59:09 +02:00
} else {
2018-08-09 15:37:23 +02:00
Configuration : : SysconfDir = ICINGA_SYSCONFDIR ;
2018-07-31 11:59:09 +02:00
# endif /* _WIN32 */
}
2018-08-09 15:37:23 +02:00
Value runDir = Configuration : : RunDir ;
2018-07-31 11:59:09 +02:00
if ( ! runDir . IsEmpty ( ) ) {
Log ( LogWarning , " icinga-app " )
2018-10-15 08:56:18 +02:00
< < " Please do not set the deprecated 'RunDir' constant, use the 'InitRunDir' constant instead! For compatibility reasons, their value is set based on the 'RunDir' constant. " ;
2018-07-31 11:59:09 +02:00
# ifdef _WIN32
2018-08-09 15:37:23 +02:00
Configuration : : InitRunDir = runDir + " \\ icinga2 " ;
2018-07-31 11:59:09 +02:00
} else {
2018-08-09 15:37:23 +02:00
Configuration : : RunDir = dataPrefix + " \\ var \\ run " ;
2018-07-31 11:59:09 +02:00
# else /* _WIN32 */
2018-08-09 15:37:23 +02:00
Configuration : : InitRunDir = runDir + " /icinga2 " ;
2018-07-31 11:59:09 +02:00
} else {
2018-08-09 15:37:23 +02:00
Configuration : : RunDir = ICINGA_RUNDIR ;
2018-07-31 11:59:09 +02:00
# endif /* _WIN32 */
}
}
2018-01-04 04:25:35 +01:00
static int Main ( )
2012-05-14 19:14:23 +02:00
{
2014-04-16 15:01:15 +02:00
int argc = Application : : GetArgC ( ) ;
char * * argv = Application : : GetArgV ( ) ;
2014-10-10 10:07:56 +02:00
bool autocomplete = false ;
int autoindex = 0 ;
if ( argc > = 4 & & strcmp ( argv [ 1 ] , " --autocomplete " ) = = 0 ) {
autocomplete = true ;
2015-03-03 09:23:38 +01:00
try {
autoindex = Convert : : ToLong ( argv [ 2 ] ) ;
2017-12-13 12:47:51 +01:00
} catch ( const std : : invalid_argument & ) {
2015-03-03 09:23:38 +01:00
Log ( LogCritical , " icinga-app " )
2017-12-19 15:50:05 +01:00
< < " Invalid index for --autocomplete: " < < argv [ 2 ] ;
2015-03-03 09:23:38 +01:00
return EXIT_FAILURE ;
}
2014-10-10 10:07:56 +02:00
argc - = 3 ;
argv + = 3 ;
}
2013-10-26 09:41:45 +02:00
Application : : SetStartTime ( Utility : : GetTime ( ) ) ;
2013-03-25 18:36:15 +01:00
/* Set thread title. */
2013-09-03 15:44:31 +02:00
Utility : : SetThreadName ( " Main Thread " , false ) ;
2013-03-25 18:36:15 +01:00
2013-01-30 11:51:15 +01:00
/* Install exception handlers to make debugging easier. */
Application : : InstallExceptionHandlers ( ) ;
2014-04-18 16:15:34 +02:00
# ifdef _WIN32
bool builtinPaths = true ;
2018-08-07 17:58:22 +02:00
/* Programm install location, C:/Program Files/Icinga2 */
2016-04-01 08:25:36 +02:00
String binaryPrefix = Utility : : GetIcingaInstallPath ( ) ;
2018-08-07 17:58:22 +02:00
/* Returns the datapath for daemons, %PROGRAMDATA%/icinga2 */
2016-04-01 08:25:36 +02:00
String dataPrefix = Utility : : GetIcingaDataPath ( ) ;
if ( ! binaryPrefix . IsEmpty ( ) & & ! dataPrefix . IsEmpty ( ) ) {
2018-08-09 15:37:23 +02:00
Configuration : : ProgramData = dataPrefix ;
2018-07-31 11:59:09 +02:00
2018-08-09 15:37:23 +02:00
Configuration : : ConfigDir = dataPrefix + " \\ etc \\ icinga2 " ;
2018-07-31 11:59:09 +02:00
2018-08-09 15:37:23 +02:00
Configuration : : DataDir = dataPrefix + " \\ var \\ lib \\ icinga2 " ;
Configuration : : LogDir = dataPrefix + " \\ var \\ log \\ icinga2 " ;
Configuration : : CacheDir = dataPrefix + " \\ var \\ cache \\ icinga2 " ;
Configuration : : SpoolDir = dataPrefix + " \\ var \\ spool \\ icinga2 " ;
2018-07-31 11:59:09 +02:00
2018-10-12 16:18:55 +02:00
Configuration : : PrefixDir = binaryPrefix ;
2018-08-07 17:58:22 +02:00
/* Internal constants. */
2018-08-09 15:37:23 +02:00
Configuration : : PkgDataDir = binaryPrefix + " \\ share \\ icinga2 " ;
Configuration : : IncludeConfDir = binaryPrefix + " \\ share \\ icinga2 \\ include " ;
2018-10-12 16:18:55 +02:00
Configuration : : InitRunDir = dataPrefix + " \\ var \\ run \\ icinga2 " ;
2016-03-30 11:47:39 +02:00
} else {
2014-04-18 16:15:34 +02:00
Log ( LogWarning , " icinga-app " , " Registry key could not be read. Falling back to built-in paths. " ) ;
2014-04-20 07:22:04 +02:00
# endif /* _WIN32 */
2018-08-09 15:37:23 +02:00
Configuration : : ConfigDir = ICINGA_CONFIGDIR ;
2018-07-31 11:59:09 +02:00
2018-08-09 15:37:23 +02:00
Configuration : : DataDir = ICINGA_DATADIR ;
Configuration : : LogDir = ICINGA_LOGDIR ;
Configuration : : CacheDir = ICINGA_CACHEDIR ;
Configuration : : SpoolDir = ICINGA_SPOOLDIR ;
2018-07-31 11:59:09 +02:00
2018-08-09 15:37:23 +02:00
Configuration : : PrefixDir = ICINGA_PREFIX ;
2018-07-31 11:59:09 +02:00
2018-08-07 17:58:22 +02:00
/* Internal constants. */
2018-08-09 15:37:23 +02:00
Configuration : : PkgDataDir = ICINGA_PKGDATADIR ;
Configuration : : IncludeConfDir = ICINGA_INCLUDECONFDIR ;
2018-07-31 11:59:09 +02:00
2018-08-09 15:37:23 +02:00
Configuration : : InitRunDir = ICINGA_INITRUNDIR ;
2018-07-31 11:59:09 +02:00
2014-04-18 16:15:34 +02:00
# ifdef _WIN32
}
# endif /* _WIN32 */
2012-09-28 13:16:08 +02:00
2018-08-09 15:37:23 +02:00
Configuration : : ZonesDir = Configuration : : ConfigDir + " /zones.d " ;
2018-01-26 16:27:16 +01:00
2018-05-23 13:37:29 +02:00
String icingaUser = Utility : : GetFromEnvironment ( " ICINGA2_USER " ) ;
2018-01-29 14:23:53 +01:00
if ( icingaUser . IsEmpty ( ) )
icingaUser = ICINGA_USER ;
2018-05-23 13:37:29 +02:00
String icingaGroup = Utility : : GetFromEnvironment ( " ICINGA2_GROUP " ) ;
2018-01-29 14:23:53 +01:00
if ( icingaGroup . IsEmpty ( ) )
icingaGroup = ICINGA_GROUP ;
2018-08-09 15:37:23 +02:00
Configuration : : RunAsUser = icingaUser ;
Configuration : : RunAsGroup = icingaGroup ;
2018-01-29 14:23:53 +01:00
2018-05-23 14:23:48 +02:00
if ( ! autocomplete ) {
2018-01-29 14:23:53 +01:00
# ifdef RLIMIT_NOFILE
2018-05-23 14:23:48 +02:00
String rLimitFiles = Utility : : GetFromEnvironment ( " ICINGA2_RLIMIT_FILES " ) ;
if ( rLimitFiles . IsEmpty ( ) )
2018-08-09 15:37:23 +02:00
Configuration : : RLimitFiles = Application : : GetDefaultRLimitFiles ( ) ;
2018-05-23 14:23:48 +02:00
else {
try {
2018-08-09 15:37:23 +02:00
Configuration : : RLimitFiles = Convert : : ToLong ( rLimitFiles ) ;
2018-05-23 14:23:48 +02:00
} catch ( const std : : invalid_argument & ex ) {
std : : cout
< < " Error setting \" ICINGA2_RLIMIT_FILES \" : " < < ex . what ( ) < < ' \n ' ;
return EXIT_FAILURE ;
}
2018-01-29 14:23:53 +01:00
}
# endif /* RLIMIT_NOFILE */
# ifdef RLIMIT_NPROC
2018-05-23 14:23:48 +02:00
String rLimitProcesses = Utility : : GetFromEnvironment ( " ICINGA2_RLIMIT_PROCESSES " ) ;
if ( rLimitProcesses . IsEmpty ( ) )
2018-08-09 15:37:23 +02:00
Configuration : : RLimitProcesses = Application : : GetDefaultRLimitProcesses ( ) ;
2018-05-23 14:23:48 +02:00
else {
try {
2018-08-09 15:37:23 +02:00
Configuration : : RLimitProcesses = Convert : : ToLong ( rLimitProcesses ) ;
2018-05-23 14:23:48 +02:00
} catch ( const std : : invalid_argument & ex ) {
std : : cout
< < " Error setting \" ICINGA2_RLIMIT_PROCESSES \" : " < < ex . what ( ) < < ' \n ' ;
return EXIT_FAILURE ;
}
2018-01-29 14:23:53 +01:00
}
# endif /* RLIMIT_NPROC */
# ifdef RLIMIT_STACK
2018-05-23 14:23:48 +02:00
String rLimitStack = Utility : : GetFromEnvironment ( " ICINGA2_RLIMIT_STACK " ) ;
if ( rLimitStack . IsEmpty ( ) )
2018-08-09 15:37:23 +02:00
Configuration : : RLimitStack = Application : : GetDefaultRLimitStack ( ) ;
2018-05-23 14:23:48 +02:00
else {
try {
2018-08-09 15:37:23 +02:00
Configuration : : RLimitStack = Convert : : ToLong ( rLimitStack ) ;
2018-05-23 14:23:48 +02:00
} catch ( const std : : invalid_argument & ex ) {
std : : cout
< < " Error setting \" ICINGA2_RLIMIT_STACK \" : " < < ex . what ( ) < < ' \n ' ;
return EXIT_FAILURE ;
}
2018-01-29 14:23:53 +01:00
}
# endif /* RLIMIT_STACK */
2018-05-23 14:23:48 +02:00
}
2018-01-29 14:23:53 +01:00
2018-08-09 15:37:23 +02:00
ScriptGlobal : : Set ( " MaxConcurrentChecks " , Application : : GetDefaultMaxConcurrentChecks ( ) ) ;
2013-08-30 12:04:24 +02:00
2018-08-07 13:55:41 +02:00
ScriptGlobal : : Set ( " System.PlatformKernel " , Utility : : GetPlatformKernel ( ) , true ) ;
ScriptGlobal : : Set ( " System.PlatformKernelVersion " , Utility : : GetPlatformKernelVersion ( ) , true ) ;
ScriptGlobal : : Set ( " System.PlatformName " , Utility : : GetPlatformName ( ) , true ) ;
ScriptGlobal : : Set ( " System.PlatformVersion " , Utility : : GetPlatformVersion ( ) , true ) ;
ScriptGlobal : : Set ( " System.PlatformArchitecture " , Utility : : GetPlatformArchitecture ( ) , true ) ;
ScriptGlobal : : Set ( " System.BuildHostName " , ICINGA_BUILD_HOST_NAME , true ) ;
ScriptGlobal : : Set ( " System.BuildCompilerName " , ICINGA_BUILD_COMPILER_NAME , true ) ;
ScriptGlobal : : Set ( " System.BuildCompilerVersion " , ICINGA_BUILD_COMPILER_VERSION , true ) ;
2016-08-10 08:03:54 +02:00
2017-06-21 11:36:14 +02:00
if ( ! autocomplete )
Application : : SetResourceLimits ( ) ;
2014-10-06 14:21:18 +02:00
LogSeverity logLevel = Logger : : GetConsoleLogSeverity ( ) ;
Logger : : SetConsoleLogSeverity ( LogWarning ) ;
2014-10-13 18:07:52 +02:00
2014-10-10 11:08:24 +02:00
po : : options_description visibleDesc ( " Global options " ) ;
2014-10-06 14:21:18 +02:00
2014-10-10 11:08:24 +02:00
visibleDesc . add_options ( )
2014-10-20 14:31:39 +02:00
( " help,h " , " show this help message " )
2013-02-03 01:21:11 +01:00
( " version,V " , " show version information " )
2014-10-17 09:45:46 +02:00
# ifndef _WIN32
( " color " , " use VT100 color codes even when stdout is not a terminal " )
# endif /* _WIN32 */
2014-10-06 14:21:18 +02:00
( " define,D " , po : : value < std : : vector < std : : string > > ( ) , " define a constant " )
2014-03-31 02:08:15 +02:00
( " include,I " , po : : value < std : : vector < std : : string > > ( ) , " add include search directory " )
2015-11-05 14:29:45 +01:00
( " log-level,x " , po : : value < std : : string > ( ) , " specify the log level for the console log. \n "
2017-12-19 15:50:05 +01:00
" The valid value is either debug, notice, information (default), warning, or critical " )
2018-07-26 17:09:06 +02:00
( " script-debugger,X " , " whether to enable the script debugger " ) ;
2014-10-10 11:08:24 +02:00
po : : options_description hiddenDesc ( " Hidden options " ) ;
hiddenDesc . add_options ( )
2014-10-14 14:27:37 +02:00
( " no-stack-rlimit " , " used internally, do not specify manually " )
( " arg " , po : : value < std : : vector < std : : string > > ( ) , " positional argument " ) ;
po : : positional_options_description positionalDesc ;
positionalDesc . add ( " arg " , - 1 ) ;
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
String cmdname ;
CLICommand : : Ptr command ;
po : : variables_map vm ;
2013-02-02 23:22:27 +01:00
2013-02-02 23:29:02 +01:00
try {
2014-10-17 15:54:46 +02:00
CLICommand : : ParseCommand ( argc , argv , visibleDesc , hiddenDesc , positionalDesc ,
2017-12-19 15:50:05 +01:00
vm , cmdname , command , autocomplete ) ;
2013-03-16 21:18:53 +01:00
} catch ( const std : : exception & ex ) {
2014-10-19 17:52:17 +02:00
Log ( LogCritical , " icinga-app " )
2017-12-19 15:50:05 +01:00
< < " Error while parsing command-line options: " < < ex . what ( ) ;
2013-02-02 23:29:02 +01:00
return EXIT_FAILURE ;
}
2017-08-22 10:26:23 +02:00
# ifdef _WIN32
char username [ UNLEN + 1 ] ;
DWORD usernameLen = UNLEN + 1 ;
GetUserName ( username , & usernameLen ) ;
std : : ifstream userFile ;
2018-08-07 18:33:59 +02:00
/* The implicit string assignment is needed for Windows builds. */
2018-08-09 15:37:23 +02:00
String configDir = Configuration : : ConfigDir ;
2018-08-07 18:33:59 +02:00
userFile . open ( configDir + " /user " ) ;
2017-08-22 10:26:23 +02:00
if ( userFile & & command & & ! Application : : IsProcessElevated ( ) ) {
std : : string userLine ;
if ( std : : getline ( userFile , userLine ) ) {
userFile . close ( ) ;
std : : vector < std : : string > strs ;
boost : : split ( strs , userLine , boost : : is_any_of ( " \\ " ) ) ;
if ( username ! = strs [ 1 ] & & command - > GetImpersonationLevel ( ) = = ImpersonationLevel : : ImpersonateIcinga
| | command - > GetImpersonationLevel ( ) = = ImpersonationLevel : : ImpersonateRoot ) {
TCHAR szPath [ MAX_PATH ] ;
2017-12-14 15:37:20 +01:00
if ( GetModuleFileName ( nullptr , szPath , ARRAYSIZE ( szPath ) ) ) {
2017-08-22 10:26:23 +02:00
SHELLEXECUTEINFO sei = { sizeof ( sei ) } ;
sei . lpVerb = _T ( " runas " ) ;
sei . lpFile = " cmd.exe " ;
sei . fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI ;
sei . nShow = SW_SHOW ;
std : : stringstream parameters ;
parameters < < " /C " < < " \" " < < szPath < < " \" " < < " " ;
for ( int i = 1 ; i < argc ; i + + ) {
if ( i ! = 1 )
parameters < < " " ;
parameters < < argv [ i ] ;
}
parameters < < " & SET exitcode=%errorlevel% " ;
parameters < < " & pause " ;
parameters < < " & EXIT /B %exitcode% " ;
std : : string str = parameters . str ( ) ;
LPCSTR cstr = str . c_str ( ) ;
sei . lpParameters = cstr ;
if ( ! ShellExecuteEx ( & sei ) ) {
DWORD dwError = GetLastError ( ) ;
if ( dwError = = ERROR_CANCELLED )
Application : : Exit ( 0 ) ;
} else {
WaitForSingleObject ( sei . hProcess , INFINITE ) ;
DWORD exitCode ;
GetExitCodeProcess ( sei . hProcess , & exitCode ) ;
CloseHandle ( sei . hProcess ) ;
Application : : Exit ( exitCode ) ;
}
}
}
} else {
userFile . close ( ) ;
}
}
# endif /* _WIN32 */
2014-10-17 09:45:46 +02:00
# ifndef _WIN32
if ( vm . count ( " color " ) ) {
Console : : SetType ( std : : cout , Console_VT100 ) ;
Console : : SetType ( std : : cerr , Console_VT100 ) ;
}
# endif /* _WIN32 */
2014-10-06 14:21:18 +02:00
if ( vm . count ( " define " ) ) {
2016-08-25 06:19:44 +02:00
for ( const String & define : vm [ " define " ] . as < std : : vector < std : : string > > ( ) ) {
2014-04-13 23:35:42 +02:00
String key , value ;
size_t pos = define . FindFirstOf ( ' = ' ) ;
if ( pos ! = String : : NPos ) {
key = define . SubStr ( 0 , pos ) ;
value = define . SubStr ( pos + 1 ) ;
} else {
key = define ;
value = " 1 " ;
}
2018-08-07 13:55:41 +02:00
std : : vector < String > keyTokens = key . Split ( " . " ) ;
std : : unique_ptr < Expression > expr ;
std : : unique_ptr < VariableExpression > varExpr { new VariableExpression ( keyTokens [ 0 ] , { } , DebugInfo ( ) ) } ;
expr = std : : move ( varExpr ) ;
for ( size_t i = 1 ; i < keyTokens . size ( ) ; i + + ) {
std : : unique_ptr < IndexerExpression > indexerExpr { new IndexerExpression ( std : : move ( expr ) , MakeLiteral ( keyTokens [ i ] ) ) } ;
indexerExpr - > SetOverrideFrozen ( ) ;
expr = std : : move ( indexerExpr ) ;
}
std : : unique_ptr < SetExpression > setExpr { new SetExpression ( std : : move ( expr ) , OpSetLiteral , MakeLiteral ( value ) ) } ;
setExpr - > SetOverrideFrozen ( ) ;
ScriptFrame frame ( true ) ;
setExpr - > Evaluate ( frame ) ;
2014-04-13 23:35:42 +02:00
}
}
2014-10-13 13:43:05 +02:00
2018-08-09 15:37:23 +02:00
Configuration : : SetReadOnly ( true ) ;
2018-08-07 17:58:22 +02:00
/* Ensure that all defined constants work in the way we expect them. */
2018-07-31 11:59:09 +02:00
HandleLegacyDefines ( ) ;
2015-11-05 14:29:45 +01:00
if ( vm . count ( " script-debugger " ) )
Application : : SetScriptDebuggerEnabled ( true ) ;
2018-08-09 15:37:23 +02:00
Configuration : : StatePath = Configuration : : DataDir + " /icinga2.state " ;
Configuration : : ModAttrPath = Configuration : : DataDir + " /modified-attributes.conf " ;
Configuration : : ObjectsPath = Configuration : : CacheDir + " /icinga2.debug " ;
Configuration : : VarsPath = Configuration : : CacheDir + " /icinga2.vars " ;
Configuration : : PidPath = Configuration : : InitRunDir + " /icinga2.pid " ;
2014-04-13 23:35:42 +02:00
2018-08-09 15:37:23 +02:00
ConfigCompiler : : AddIncludeSearchDir ( Configuration : : IncludeConfDir ) ;
2014-07-11 14:26:21 +02:00
2014-10-06 14:21:18 +02:00
if ( ! autocomplete & & vm . count ( " include " ) ) {
2016-08-25 06:19:44 +02:00
for ( const String & includePath : vm [ " include " ] . as < std : : vector < std : : string > > ( ) ) {
2014-10-06 14:21:18 +02:00
ConfigCompiler : : AddIncludeSearchDir ( includePath ) ;
2013-09-15 10:28:54 +02:00
}
}
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
if ( ! autocomplete ) {
2014-10-27 14:13:55 +01:00
Logger : : SetConsoleLogSeverity ( logLevel ) ;
2014-10-06 14:21:18 +02:00
if ( vm . count ( " log-level " ) ) {
String severity = vm [ " log-level " ] . as < std : : string > ( ) ;
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
LogSeverity logLevel = LogInformation ;
try {
logLevel = Logger : : StringToSeverity ( severity ) ;
} catch ( std : : exception & ) {
2015-01-15 11:45:12 +01:00
/* Inform user and exit */
2015-01-21 16:16:47 +01:00
Log ( LogCritical , " icinga-app " , " Invalid log level set. Default is 'information'. " ) ;
2015-01-15 11:45:12 +01:00
return EXIT_FAILURE ;
2013-10-10 11:28:07 +02:00
}
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
Logger : : SetConsoleLogSeverity ( logLevel ) ;
2013-09-15 10:28:54 +02:00
}
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
if ( ! command | | vm . count ( " help " ) | | vm . count ( " version " ) ) {
2015-03-03 09:24:21 +01:00
String appName ;
try {
2015-03-09 15:02:53 +01:00
appName = Utility : : BaseName ( Application : : GetArgV ( ) [ 0 ] ) ;
2015-03-03 09:24:21 +01:00
} catch ( const std : : bad_alloc & ) {
Log ( LogCritical , " icinga-app " , " Allocation failed. " ) ;
return EXIT_FAILURE ;
}
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
if ( appName . GetLength ( ) > 3 & & appName . SubStr ( 0 , 3 ) = = " lt- " )
appName = appName . SubStr ( 3 , appName . GetLength ( ) - 3 ) ;
2014-10-13 18:07:52 +02:00
2014-10-24 15:54:11 +02:00
std : : cout < < appName < < " " < < " - The Icinga 2 network monitoring daemon (version: "
2017-12-19 15:50:05 +01:00
< < ConsoleColorTag ( vm . count ( " version " ) ? Console_ForegroundRed : Console_Normal )
< < Application : : GetAppVersion ( )
2014-12-19 12:19:28 +01:00
# ifdef I2_DEBUG
2017-12-19 15:50:05 +01:00
< < " ; debug "
2014-12-19 12:19:28 +01:00
# endif /* I2_DEBUG */
2017-12-19 15:50:05 +01:00
< < ConsoleColorTag ( Console_Normal )
< < " ) " < < std : : endl < < std : : endl ;
2014-10-13 18:07:52 +02:00
2014-12-18 05:28:51 +01:00
if ( ( ! command | | vm . count ( " help " ) ) & & ! vm . count ( " version " ) ) {
2014-10-24 15:54:11 +02:00
std : : cout < < " Usage: " < < std : : endl
2017-12-19 15:50:05 +01:00
< < " " < < Utility : : BaseName ( argv [ 0 ] ) < < " " ;
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
if ( cmdname . IsEmpty ( ) )
std : : cout < < " <command> " ;
else
std : : cout < < cmdname ;
2014-10-13 18:07:52 +02:00
2014-10-24 15:54:11 +02:00
std : : cout < < " [<arguments>] " < < std : : endl ;
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
if ( command ) {
2014-10-24 15:54:11 +02:00
std : : cout < < std : : endl
2017-12-19 15:50:05 +01:00
< < command - > GetDescription ( ) < < std : : endl ;
2014-10-06 14:21:18 +02:00
}
}
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
if ( vm . count ( " version " ) ) {
2019-01-07 15:59:24 +01:00
std : : cout < < " Copyright (c) 2012- " < < Utility : : FormatDateTime ( " %Y " , Utility : : GetTime ( ) )
< < " Icinga GmbH (https://icinga.com/) " < < std : : endl
2014-10-06 14:21:18 +02:00
< < " License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl2.html> " < < std : : endl
< < " This is free software: you are free to change and redistribute it. " < < std : : endl
< < " There is NO WARRANTY, to the extent permitted by law. " ;
}
2014-10-13 18:07:52 +02:00
2014-07-23 09:30:56 +02:00
std : : cout < < std : : endl ;
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
if ( vm . count ( " version " ) ) {
std : : cout < < std : : endl ;
2014-10-13 18:07:52 +02:00
2014-12-20 15:29:04 +01:00
Application : : DisplayInfoMessage ( std : : cout , true ) ;
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
return EXIT_SUCCESS ;
}
2014-04-14 00:16:48 +02:00
}
2014-10-13 18:07:52 +02:00
2014-10-06 14:21:18 +02:00
if ( ! command | | vm . count ( " help " ) ) {
2014-10-20 14:13:57 +02:00
if ( ! command )
2017-12-14 15:37:20 +01:00
CLICommand : : ShowCommands ( argc , argv , nullptr ) ;
2014-10-13 18:07:52 +02:00
2014-10-20 14:13:57 +02:00
std : : cout < < visibleDesc < < std : : endl
2017-01-17 16:50:22 +01:00
< < " Report bugs at <https://github.com/Icinga/icinga2> " < < std : : endl
2018-10-18 09:39:34 +02:00
< < " Get support: <https://icinga.com/support/> " < < std : : endl
< < " Documentation: <https://icinga.com/docs/> " < < std : : endl
< < " Icinga home page: <https://icinga.com/> " < < std : : endl ;
2014-10-06 14:21:18 +02:00
return EXIT_SUCCESS ;
2014-05-18 16:23:16 +02:00
}
2014-06-24 13:04:07 +02:00
}
2014-10-06 14:21:18 +02:00
int rc = 1 ;
2013-08-30 14:27:24 +02:00
2014-10-06 14:21:18 +02:00
if ( autocomplete ) {
2014-10-17 15:54:46 +02:00
CLICommand : : ShowCommands ( argc , argv , & visibleDesc , & hiddenDesc ,
2017-12-19 15:50:05 +01:00
& GlobalArgumentCompletion , true , autoindex ) ;
2014-10-06 14:21:18 +02:00
rc = 0 ;
2014-10-14 14:27:37 +02:00
} else if ( command ) {
2018-05-03 11:35:29 +02:00
Logger : : DisableTimestamp ( ) ;
2014-10-14 17:03:14 +02:00
# ifndef _WIN32
2014-10-24 15:29:46 +02:00
if ( command - > GetImpersonationLevel ( ) = = ImpersonateRoot ) {
2015-10-26 06:53:36 +01:00
if ( getuid ( ) ! = 0 ) {
2014-10-24 15:29:46 +02:00
Log ( LogCritical , " cli " , " This command must be run as root. " ) ;
return 0 ;
2015-10-26 06:53:36 +01:00
}
2014-10-24 15:29:46 +02:00
} else if ( command & & command - > GetImpersonationLevel ( ) = = ImpersonateIcinga ) {
2018-08-09 15:37:23 +02:00
String group = Configuration : : RunAsGroup ;
String user = Configuration : : RunAsUser ;
2017-12-13 12:54:14 +01:00
2014-10-24 15:29:46 +02:00
errno = 0 ;
struct group * gr = getgrnam ( group . CStr ( ) ) ;
2017-12-13 12:54:14 +01:00
2014-10-24 15:29:46 +02:00
if ( ! gr ) {
if ( errno = = 0 ) {
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " Invalid group specified: " < < group ;
2014-10-24 15:29:46 +02:00
return EXIT_FAILURE ;
} else {
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " getgrnam() failed with error code " < < errno < < " , \" " < < Utility : : FormatErrorNumber ( errno ) < < " \" " ;
2014-10-24 15:29:46 +02:00
return EXIT_FAILURE ;
}
2014-10-14 17:03:14 +02:00
}
2017-12-13 12:54:14 +01:00
2014-10-24 15:29:46 +02:00
if ( getgid ( ) ! = gr - > gr_gid ) {
2017-12-14 15:37:20 +01:00
if ( ! vm . count ( " reload-internal " ) & & setgroups ( 0 , nullptr ) < 0 ) {
2014-10-24 15:29:46 +02:00
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " setgroups() failed with error code " < < errno < < " , \" " < < Utility : : FormatErrorNumber ( errno ) < < " \" " ;
2015-02-09 14:58:20 +01:00
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " Please re-run this command as a privileged user or using the \" " < < user < < " \" account. " ;
2014-10-24 15:29:46 +02:00
return EXIT_FAILURE ;
}
2017-12-13 12:54:14 +01:00
2014-10-24 15:29:46 +02:00
if ( setgid ( gr - > gr_gid ) < 0 ) {
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " setgid() failed with error code " < < errno < < " , \" " < < Utility : : FormatErrorNumber ( errno ) < < " \" " ;
2014-10-24 15:29:46 +02:00
return EXIT_FAILURE ;
}
2014-10-14 17:03:14 +02:00
}
2017-12-13 12:54:14 +01:00
2014-10-24 15:29:46 +02:00
errno = 0 ;
struct passwd * pw = getpwnam ( user . CStr ( ) ) ;
2017-12-13 12:54:14 +01:00
2014-10-24 15:29:46 +02:00
if ( ! pw ) {
if ( errno = = 0 ) {
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " Invalid user specified: " < < user ;
2014-10-24 15:29:46 +02:00
return EXIT_FAILURE ;
} else {
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " getpwnam() failed with error code " < < errno < < " , \" " < < Utility : : FormatErrorNumber ( errno ) < < " \" " ;
2014-10-24 15:29:46 +02:00
return EXIT_FAILURE ;
}
2014-10-14 17:03:14 +02:00
}
2017-12-13 12:54:14 +01:00
2014-10-24 15:29:46 +02:00
// also activate the additional groups the configured user is member of
if ( getuid ( ) ! = pw - > pw_uid ) {
if ( ! vm . count ( " reload-internal " ) & & initgroups ( user . CStr ( ) , pw - > pw_gid ) < 0 ) {
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " initgroups() failed with error code " < < errno < < " , \" " < < Utility : : FormatErrorNumber ( errno ) < < " \" " ;
2015-02-09 14:58:20 +01:00
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " Please re-run this command as a privileged user or using the \" " < < user < < " \" account. " ;
2014-10-24 15:29:46 +02:00
return EXIT_FAILURE ;
}
2017-12-13 12:54:14 +01:00
2014-10-24 15:29:46 +02:00
if ( setuid ( pw - > pw_uid ) < 0 ) {
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " setuid() failed with error code " < < errno < < " , \" " < < Utility : : FormatErrorNumber ( errno ) < < " \" " ;
2015-02-09 14:58:20 +01:00
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " Please re-run this command as a privileged user or using the \" " < < user < < " \" account. " ;
2014-10-24 15:29:46 +02:00
return EXIT_FAILURE ;
}
2014-10-14 17:03:14 +02:00
}
}
2016-09-29 12:35:10 +02:00
Process : : InitializeSpawnHelper ( ) ;
2014-10-14 17:03:14 +02:00
# endif /* _WIN32 */
2014-10-14 14:27:37 +02:00
std : : vector < std : : string > args ;
if ( vm . count ( " arg " ) )
args = vm [ " arg " ] . as < std : : vector < std : : string > > ( ) ;
2016-08-24 19:59:13 +02:00
if ( static_cast < int > ( args . size ( ) ) < command - > GetMinArguments ( ) ) {
2014-10-24 13:15:21 +02:00
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " Too few arguments. Command needs at least " < < command - > GetMinArguments ( )
< < " argument " < < ( command - > GetMinArguments ( ) ! = 1 ? " s " : " " ) < < " . " ;
2014-10-24 13:15:21 +02:00
return EXIT_FAILURE ;
}
2016-08-24 19:59:13 +02:00
if ( command - > GetMaxArguments ( ) > = 0 & & static_cast < int > ( args . size ( ) ) > command - > GetMaxArguments ( ) ) {
2014-10-24 13:15:21 +02:00
Log ( LogCritical , " cli " )
2017-12-19 15:50:05 +01:00
< < " Too many arguments. At most " < < command - > GetMaxArguments ( )
< < " argument " < < ( command - > GetMaxArguments ( ) ! = 1 ? " s " : " " ) < < " may be specified. " ;
2014-10-24 13:15:21 +02:00
return EXIT_FAILURE ;
}
2014-10-14 14:27:37 +02:00
rc = command - > Run ( vm , args ) ;
}
2013-10-17 10:56:42 +02:00
2014-04-16 15:01:15 +02:00
return rc ;
}
2014-04-16 15:05:50 +02:00
# ifdef _WIN32
2014-04-16 15:01:15 +02:00
static int SetupService ( bool install , int argc , char * * argv )
{
2017-12-14 15:37:20 +01:00
SC_HANDLE schSCManager = OpenSCManager ( nullptr , nullptr , SC_MANAGER_ALL_ACCESS ) ;
2014-04-16 15:01:15 +02:00
2017-12-14 15:37:20 +01:00
if ( ! schSCManager ) {
2014-04-16 15:01:15 +02:00
printf ( " OpenSCManager failed (%d) \n " , GetLastError ( ) ) ;
return 1 ;
}
2014-04-18 12:14:21 +02:00
TCHAR szPath [ MAX_PATH ] ;
2014-04-16 15:01:15 +02:00
2017-12-14 15:37:20 +01:00
if ( ! GetModuleFileName ( nullptr , szPath , MAX_PATH ) ) {
2014-04-18 12:14:21 +02:00
printf ( " Cannot install service (%d) \n " , GetLastError ( ) ) ;
return 1 ;
2014-04-16 15:01:15 +02:00
}
2014-04-18 12:14:21 +02:00
String szArgs ;
szArgs = Utility : : EscapeShellArg ( szPath ) + " --scm " ;
2016-02-26 13:42:36 +01:00
std : : string scmUser = " NT AUTHORITY \\ NetworkService " ;
std : : ifstream initf ( Utility : : GetIcingaDataPath ( ) + " \\ etc \\ icinga2 \\ user " ) ;
if ( initf . good ( ) ) {
std : : getline ( initf , scmUser ) ;
}
initf . close ( ) ;
for ( int i = 0 ; i < argc ; i + + ) {
if ( ! strcmp ( argv [ i ] , " --scm-user " ) & & i + 1 < argc ) {
scmUser = argv [ i + 1 ] ;
i + + ;
} else
szArgs + = " " + Utility : : EscapeShellArg ( argv [ i ] ) ;
}
2014-04-18 12:14:21 +02:00
2015-05-12 14:39:44 +02:00
SC_HANDLE schService = OpenService ( schSCManager , " icinga2 " , SERVICE_ALL_ACCESS ) ;
2014-04-16 15:01:15 +02:00
2017-12-14 15:37:20 +01:00
if ( schService ) {
2014-04-20 15:35:51 +02:00
SERVICE_STATUS status ;
ControlService ( schService , SERVICE_CONTROL_STOP , & status ) ;
2014-04-20 15:47:57 +02:00
double start = Utility : : GetTime ( ) ;
while ( status . dwCurrentState ! = SERVICE_STOPPED ) {
double end = Utility : : GetTime ( ) ;
if ( end - start > 30 ) {
printf ( " Could not stop the service. \n " ) ;
break ;
}
Utility : : Sleep ( 5 ) ;
if ( ! QueryServiceStatus ( schService , & status ) ) {
printf ( " QueryServiceStatus failed (%d) \n " , GetLastError ( ) ) ;
return 1 ;
}
}
2015-05-12 14:39:44 +02:00
} else if ( install ) {
2014-04-16 15:01:15 +02:00
schService = CreateService (
2014-04-16 15:05:50 +02:00
schSCManager ,
" icinga2 " ,
" Icinga 2 " ,
SERVICE_ALL_ACCESS ,
SERVICE_WIN32_OWN_PROCESS ,
SERVICE_DEMAND_START ,
SERVICE_ERROR_NORMAL ,
2014-04-18 12:14:21 +02:00
szArgs . CStr ( ) ,
2017-12-14 15:37:20 +01:00
nullptr ,
nullptr ,
nullptr ,
2016-02-26 13:42:36 +01:00
scmUser . c_str ( ) ,
2017-12-14 15:37:20 +01:00
nullptr ) ;
2014-04-16 15:01:15 +02:00
2017-12-14 15:37:20 +01:00
if ( ! schService ) {
2014-04-16 15:01:15 +02:00
printf ( " CreateService failed (%d) \n " , GetLastError ( ) ) ;
CloseServiceHandle ( schSCManager ) ;
return 1 ;
2016-02-26 13:42:36 +01:00
}
2015-05-12 14:39:44 +02:00
} else {
printf ( " Service isn't installed. \n " ) ;
CloseServiceHandle ( schSCManager ) ;
return 0 ;
}
if ( ! install ) {
if ( ! DeleteService ( schService ) ) {
printf ( " DeleteService failed (%d) \n " , GetLastError ( ) ) ;
CloseServiceHandle ( schService ) ;
CloseServiceHandle ( schSCManager ) ;
return 1 ;
}
2014-04-16 15:01:15 +02:00
2015-05-12 14:39:44 +02:00
printf ( " Service uninstalled successfully \n " ) ;
} else {
2016-02-26 13:42:36 +01:00
if ( ! ChangeServiceConfig ( schService , SERVICE_NO_CHANGE , SERVICE_AUTO_START ,
2017-12-14 15:37:20 +01:00
SERVICE_ERROR_NORMAL , szArgs . CStr ( ) , nullptr , nullptr , nullptr , scmUser . c_str ( ) , nullptr , nullptr ) ) {
2016-02-26 13:42:36 +01:00
printf ( " ChangeServiceConfig failed (%d) \n " , GetLastError ( ) ) ;
CloseServiceHandle ( schService ) ;
CloseServiceHandle ( schSCManager ) ;
return 1 ;
}
2014-04-26 23:22:12 +02:00
2014-04-16 15:01:15 +02:00
SERVICE_DESCRIPTION sdDescription = { " The Icinga 2 monitoring application " } ;
2016-02-26 13:42:36 +01:00
if ( ! ChangeServiceConfig2 ( schService , SERVICE_CONFIG_DESCRIPTION , & sdDescription ) ) {
printf ( " ChangeServiceConfig2 failed (%d) \n " , GetLastError ( ) ) ;
CloseServiceHandle ( schService ) ;
CloseServiceHandle ( schSCManager ) ;
return 1 ;
}
2014-04-16 15:01:15 +02:00
2017-12-14 15:37:20 +01:00
if ( ! StartService ( schService , 0 , nullptr ) ) {
2014-04-20 15:35:51 +02:00
printf ( " StartService failed (%d) \n " , GetLastError ( ) ) ;
CloseServiceHandle ( schService ) ;
CloseServiceHandle ( schSCManager ) ;
return 1 ;
}
2017-12-13 12:48:14 +01:00
std : : cout < < " Service successfully installed for user ' " < < scmUser < < " ' \n " ;
2016-02-26 13:42:36 +01:00
2017-12-13 12:48:14 +01:00
String userFilePath = Utility : : GetIcingaDataPath ( ) + " \\ etc \\ icinga2 \\ user " ;
std : : ofstream fuser ( userFilePath . CStr ( ) , std : : ios : : out | std : : ios : : trunc ) ;
2016-02-26 13:42:36 +01:00
if ( fuser )
fuser < < scmUser ;
else
2017-12-13 12:48:14 +01:00
std : : cout < < " Could not write user to " < < userFilePath < < " \n " ;
2014-04-16 15:01:15 +02:00
}
2015-05-12 14:39:44 +02:00
CloseServiceHandle ( schService ) ;
2014-04-16 15:01:15 +02:00
CloseServiceHandle ( schSCManager ) ;
return 0 ;
}
2017-11-21 14:15:00 +01:00
static VOID ReportSvcStatus ( DWORD dwCurrentState ,
2014-04-16 15:01:15 +02:00
DWORD dwWin32ExitCode ,
DWORD dwWaitHint )
{
static DWORD dwCheckPoint = 1 ;
l_SvcStatus . dwCurrentState = dwCurrentState ;
l_SvcStatus . dwWin32ExitCode = dwWin32ExitCode ;
l_SvcStatus . dwWaitHint = dwWaitHint ;
if ( dwCurrentState = = SERVICE_START_PENDING )
l_SvcStatus . dwControlsAccepted = 0 ;
else
l_SvcStatus . dwControlsAccepted = SERVICE_ACCEPT_STOP ;
if ( ( dwCurrentState = = SERVICE_RUNNING ) | |
2017-12-19 15:50:05 +01:00
( dwCurrentState = = SERVICE_STOPPED ) )
2014-04-16 15:01:15 +02:00
l_SvcStatus . dwCheckPoint = 0 ;
else
l_SvcStatus . dwCheckPoint = dwCheckPoint + + ;
SetServiceStatus ( l_SvcStatusHandle , & l_SvcStatus ) ;
}
2017-11-21 14:15:00 +01:00
static VOID WINAPI ServiceControlHandler ( DWORD dwCtrl )
2014-04-16 15:01:15 +02:00
{
if ( dwCtrl = = SERVICE_CONTROL_STOP ) {
ReportSvcStatus ( SERVICE_STOP_PENDING , NO_ERROR , 0 ) ;
2015-08-10 15:28:10 +02:00
TerminateJobObject ( l_Job , 0 ) ;
2014-04-16 15:01:15 +02:00
}
}
2017-11-21 14:15:00 +01:00
static VOID WINAPI ServiceMain ( DWORD argc , LPSTR * argv )
2014-04-16 15:01:15 +02:00
{
l_SvcStatusHandle = RegisterServiceCtrlHandler (
" icinga2 " ,
ServiceControlHandler ) ;
l_SvcStatus . dwServiceType = SERVICE_WIN32_OWN_PROCESS ;
l_SvcStatus . dwServiceSpecificExitCode = 0 ;
ReportSvcStatus ( SERVICE_RUNNING , NO_ERROR , 0 ) ;
2017-12-14 15:37:20 +01:00
l_Job = CreateJobObject ( nullptr , nullptr ) ;
2014-04-16 15:01:15 +02:00
2015-08-10 15:28:10 +02:00
for ( ; ; ) {
LPSTR arg = argv [ 0 ] ;
String args ;
int uargc = Application : : GetArgC ( ) ;
char * * uargv = Application : : GetArgV ( ) ;
2014-11-12 09:33:13 +01:00
2015-08-10 15:28:10 +02:00
args + = Utility : : EscapeShellArg ( Application : : GetExePath ( uargv [ 0 ] ) ) ;
for ( int i = 2 ; i < uargc & & uargv [ i ] ; i + + ) {
if ( args ! = " " )
args + = " " ;
args + = Utility : : EscapeShellArg ( uargv [ i ] ) ;
}
STARTUPINFO si = { sizeof ( si ) } ;
PROCESS_INFORMATION pi ;
char * uargs = strdup ( args . CStr ( ) ) ;
2017-12-14 15:37:20 +01:00
BOOL res = CreateProcess ( nullptr , uargs , nullptr , nullptr , FALSE , 0 , nullptr , nullptr , & si , & pi ) ;
2015-08-10 15:28:10 +02:00
free ( uargs ) ;
if ( ! res )
break ;
CloseHandle ( pi . hThread ) ;
AssignProcessToJobObject ( l_Job , pi . hProcess ) ;
if ( WaitForSingleObject ( pi . hProcess , INFINITE ) ! = WAIT_OBJECT_0 )
break ;
DWORD exitStatus ;
2017-12-13 12:54:14 +01:00
2015-08-10 15:28:10 +02:00
if ( ! GetExitCodeProcess ( pi . hProcess , & exitStatus ) )
break ;
if ( exitStatus ! = 7 )
break ;
}
TerminateJobObject ( l_Job , 0 ) ;
CloseHandle ( l_Job ) ;
ReportSvcStatus ( SERVICE_STOPPED , NO_ERROR , 0 ) ;
Application : : Exit ( 0 ) ;
2014-04-16 15:01:15 +02:00
}
# endif /* _WIN32 */
/**
* Entry point for the Icinga application .
*
* @ params argc Number of command line arguments .
* @ params argv Command line arguments .
* @ returns The application ' s exit status .
*/
int main ( int argc , char * * argv )
{
2015-02-20 19:57:26 +01:00
# ifndef _WIN32
2018-11-19 14:59:20 +01:00
String keepFDs = Utility : : GetFromEnvironment ( " ICINGA2_KEEP_FDS " ) ;
if ( keepFDs . IsEmpty ( ) ) {
2016-08-23 05:11:22 +02:00
rlimit rl ;
if ( getrlimit ( RLIMIT_NOFILE , & rl ) > = 0 ) {
rlim_t maxfds = rl . rlim_max ;
2015-02-20 19:57:26 +01:00
2016-08-23 05:11:22 +02:00
if ( maxfds = = RLIM_INFINITY )
maxfds = 65536 ;
2015-02-20 19:57:26 +01:00
2016-08-23 05:11:22 +02:00
for ( rlim_t i = 3 ; i < maxfds ; i + + ) {
int rc = close ( i ) ;
2015-02-20 19:57:26 +01:00
# ifdef I2_DEBUG
2016-08-23 05:11:22 +02:00
if ( rc > = 0 )
std : : cerr < < " Closed FD " < < i < < " which we inherited from our parent process. " < < std : : endl ;
2019-03-08 14:07:29 +01:00
# else /* I2_DEBUG */
( void ) rc ;
2015-02-20 19:57:26 +01:00
# endif /* I2_DEBUG */
2016-08-23 05:11:22 +02:00
}
2015-02-20 19:57:26 +01:00
}
}
# endif /* _WIN32 */
2015-02-20 20:45:41 +01:00
/* must be called before using any other libbase functions */
Application : : InitializeBase ( ) ;
2014-04-16 15:01:15 +02:00
/* Set command-line arguments. */
Application : : SetArgC ( argc ) ;
Application : : SetArgV ( argv ) ;
# ifdef _WIN32
if ( argc > 1 & & strcmp ( argv [ 1 ] , " --scm-install " ) = = 0 ) {
return SetupService ( true , argc - 2 , & argv [ 2 ] ) ;
}
if ( argc > 1 & & strcmp ( argv [ 1 ] , " --scm-uninstall " ) = = 0 ) {
return SetupService ( false , argc - 2 , & argv [ 2 ] ) ;
}
if ( argc > 1 & & strcmp ( argv [ 1 ] , " --scm " ) = = 0 ) {
SERVICE_TABLE_ENTRY dispatchTable [ ] = {
{ " icinga2 " , ServiceMain } ,
2017-12-14 15:37:20 +01:00
{ nullptr , nullptr }
2014-04-16 15:01:15 +02:00
} ;
StartServiceCtrlDispatcher ( dispatchTable ) ;
2015-02-26 17:09:45 +01:00
Application : : Exit ( EXIT_FAILURE ) ;
2014-04-16 15:01:15 +02:00
}
# endif /* _WIN32 */
int rc = Main ( ) ;
2014-06-05 16:36:03 +02:00
2014-08-04 16:43:34 +02:00
Application : : Exit ( rc ) ;
2012-05-14 19:14:23 +02:00
}