2019-02-25 08:48:22 -05:00
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2012-05-10 06:06:41 -04:00
2014-05-25 10:23:35 -04:00
# include "base/application.hpp"
2018-01-18 07:50:38 -05:00
# include "base/application-ti.cpp"
2014-05-25 10:23:35 -04:00
# include "base/stacktrace.hpp"
# include "base/timer.hpp"
2014-08-07 02:34:38 -04:00
# include "base/logger.hpp"
2014-05-25 10:23:35 -04:00
# include "base/exception.hpp"
# include "base/objectlock.hpp"
# include "base/utility.hpp"
2015-03-18 08:24:31 -04:00
# include "base/loader.hpp"
2014-05-25 10:23:35 -04:00
# include "base/debug.hpp"
# include "base/type.hpp"
# include "base/convert.hpp"
2014-12-14 05:33:45 -05:00
# include "base/scriptglobal.hpp"
2014-05-25 10:23:35 -04:00
# include "base/process.hpp"
2015-04-27 10:21:59 -04:00
# include <boost/algorithm/string/trim.hpp>
2013-03-18 12:04:22 -04:00
# include <boost/exception/errinfo_api_function.hpp>
# include <boost/exception/errinfo_errno.hpp>
# include <boost/exception/errinfo_file_name.hpp>
2014-12-20 09:29:04 -05:00
# include <sstream>
2013-03-17 17:14:40 -04:00
# include <iostream>
2014-12-20 09:29:04 -05:00
# include <fstream>
2017-11-21 06:12:58 -05:00
# include <thread>
2015-03-03 07:53:11 -05:00
# ifdef __linux__
# include <sys/prctl.h>
# endif /* __linux__ */
2017-08-22 04:26:23 -04:00
# ifdef _WIN32
# include <windows.h>
2019-07-15 07:59:17 -04:00
# else /* _WIN32 */
# include <signal.h>
2018-01-17 07:52:23 -05:00
# endif /* _WIN32 */
2017-08-22 04:26:23 -04:00
2012-03-28 07:24:49 -04:00
using namespace icinga ;
2013-11-08 10:07:21 -05:00
REGISTER_TYPE ( Application ) ;
2013-11-08 05:17:46 -05:00
2018-01-03 22:25:35 -05:00
boost : : signals2 : : signal < void ( ) > Application : : OnReopenLogs ;
2017-12-14 09:37:20 -05:00
Application : : Ptr Application : : m_Instance = nullptr ;
2012-07-10 06:21:19 -04:00
bool Application : : m_ShuttingDown = false ;
2014-04-27 15:47:25 -04:00
bool Application : : m_RequestRestart = false ;
2014-05-22 05:22:30 -04:00
bool Application : : m_RequestReopenLogs = false ;
2014-05-17 17:07:10 -04:00
pid_t Application : : m_ReloadProcess = 0 ;
2019-07-15 07:59:17 -04:00
# ifndef _WIN32
pid_t Application : : m_UmbrellaProcess = 0 ;
# endif /* _WIN32 */
2014-05-11 11:14:35 -04:00
static bool l_Restarting = false ;
2014-09-09 08:49:21 -04:00
static bool l_InExceptionHandler = false ;
2013-02-14 10:18:58 -05:00
int Application : : m_ArgC ;
char * * Application : : m_ArgV ;
2013-10-26 03:41:45 -04:00
double Application : : m_StartTime ;
2016-05-11 06:50:08 -04:00
double Application : : m_MainTime ;
2015-11-05 08:29:45 -05:00
bool Application : : m_ScriptDebuggerEnabled = false ;
2016-05-11 10:07:28 -04:00
double Application : : m_LastReloadFailed ;
2012-03-28 07:24:49 -04:00
2012-04-24 08:02:15 -04:00
/**
* Constructor for the Application class .
*/
2018-01-03 22:25:35 -05:00
void Application : : OnConfigLoaded ( )
2012-03-28 07:24:49 -04:00
{
2017-12-14 09:37:20 -05:00
m_PidFile = nullptr ;
2012-08-14 06:51:51 -04:00
2017-12-14 09:37:20 -05:00
ASSERT ( m_Instance = = nullptr ) ;
2012-08-14 06:51:51 -04:00
m_Instance = this ;
2012-03-28 07:24:49 -04:00
}
2012-04-24 08:02:15 -04:00
/**
* Destructor for the application class .
*/
2015-08-20 11:18:48 -04:00
void Application : : Stop ( bool runtimeRemoved )
2012-03-28 07:24:49 -04:00
{
2012-05-25 16:04:03 -04:00
m_ShuttingDown = true ;
2012-04-01 09:20:13 -04:00
# ifdef _WIN32
WSACleanup ( ) ;
# endif /* _WIN32 */
2012-07-12 11:03:34 -04:00
2019-07-15 10:08:08 -04:00
# ifdef _WIN32
2018-03-14 05:01:11 -04:00
ClosePidFile ( true ) ;
2019-07-15 10:08:08 -04:00
# endif /* _WIN32 */
2014-04-16 09:01:31 -04:00
2015-08-20 11:18:48 -04:00
ObjectImpl < Application > : : Stop ( runtimeRemoved ) ;
2012-03-28 07:24:49 -04:00
}
2018-01-03 22:25:35 -05:00
Application : : ~ Application ( )
2013-08-20 05:06:04 -04:00
{
2017-12-14 09:37:20 -05:00
m_Instance = nullptr ;
2013-08-20 05:06:04 -04:00
}
2014-08-04 10:43:34 -04:00
void Application : : Exit ( int rc )
2014-08-04 10:26:17 -04:00
{
2014-08-05 07:52:24 -04:00
std : : cout . flush ( ) ;
2015-03-20 07:27:40 -04:00
std : : cerr . flush ( ) ;
2014-08-07 02:34:38 -04:00
2016-08-25 00:19:44 -04:00
for ( const Logger : : Ptr & logger : Logger : : GetLoggers ( ) ) {
2014-08-07 02:34:38 -04:00
logger - > Flush ( ) ;
}
2014-12-04 15:45:15 -05:00
UninitializeBase ( ) ;
2014-12-19 06:19:28 -05:00
# ifdef I2_DEBUG
2014-11-12 03:33:13 -05:00
exit ( rc ) ;
2014-12-19 06:19:28 -05:00
# else /* I2_DEBUG */
2014-08-04 10:43:34 -04:00
_exit ( rc ) ; // Yay, our static destructors are pretty much beyond repair at this point.
2014-12-19 06:19:28 -05:00
# endif /* I2_DEBUG */
2014-08-04 10:26:17 -04:00
}
2018-01-03 22:25:35 -05:00
void Application : : InitializeBase ( )
2014-05-03 14:02:22 -04:00
{
2014-10-21 10:07:22 -04:00
# ifdef _WIN32
/* disable GUI-based error messages for LoadLibrary() */
SetErrorMode ( SEM_FAILCRITICALERRORS ) ;
WSADATA wsaData ;
if ( WSAStartup ( MAKEWORD ( 1 , 1 ) , & wsaData ) ! = 0 ) {
BOOST_THROW_EXCEPTION ( win32_error ( )
< < boost : : errinfo_api_function ( " WSAStartup " )
< < errinfo_win32_error ( WSAGetLastError ( ) ) ) ;
}
2017-01-12 04:50:04 -05:00
# else /* _WIN32 */
struct sigaction sa ;
memset ( & sa , 0 , sizeof ( sa ) ) ;
sa . sa_handler = SIG_IGN ;
2017-12-14 09:37:20 -05:00
sigaction ( SIGPIPE , & sa , nullptr ) ;
2014-10-21 10:07:22 -04:00
# endif /* _WIN32 */
2015-03-18 08:24:31 -04:00
Loader : : ExecuteDeferredInitializers ( ) ;
2014-12-04 15:45:15 -05:00
2018-07-19 07:34:12 -04:00
/* Make sure the thread pool gets initialized. */
2015-10-21 01:02:49 -04:00
GetTP ( ) . Start ( ) ;
2018-07-19 06:49:27 -04:00
2018-07-19 07:34:12 -04:00
/* Make sure the timer thread gets initialized. */
2018-07-19 06:49:27 -04:00
Timer : : Initialize ( ) ;
2014-12-04 15:45:15 -05:00
}
2018-01-03 22:25:35 -05:00
void Application : : UninitializeBase ( )
2014-12-04 15:45:15 -05:00
{
Timer : : Uninitialize ( ) ;
GetTP ( ) . Stop ( ) ;
2014-05-03 14:02:22 -04:00
}
2012-05-21 06:53:38 -04:00
/**
* Retrieves a pointer to the application singleton object .
*
* @ returns The application object .
*/
2018-01-03 22:25:35 -05:00
Application : : Ptr Application : : GetInstance ( )
2012-05-21 06:53:38 -04:00
{
2014-11-08 15:17:16 -05:00
return m_Instance ;
2012-05-21 06:53:38 -04:00
}
2018-01-03 22:25:35 -05:00
void Application : : SetResourceLimits ( )
2013-12-05 05:04:47 -05:00
{
2015-01-09 05:43:57 -05:00
# ifdef __linux__
2013-12-05 05:04:47 -05:00
rlimit rl ;
2014-04-22 13:47:19 -04:00
# ifdef RLIMIT_NOFILE
2018-08-09 09:37:23 -04:00
rlim_t fileLimit = Configuration : : RLimitFiles ;
2013-12-05 05:04:47 -05:00
2017-06-21 05:36:14 -04:00
if ( fileLimit ! = 0 ) {
2019-03-08 08:07:29 -05:00
if ( fileLimit < ( rlim_t ) GetDefaultRLimitFiles ( ) ) {
2017-06-21 05:36:14 -04:00
Log ( LogWarning , " Application " )
2017-12-19 09:50:05 -05:00
< < " The user-specified value for RLimitFiles cannot be smaller than the default value ( " < < GetDefaultRLimitFiles ( ) < < " ). Using the default value instead. " ;
2017-06-21 05:36:14 -04:00
fileLimit = GetDefaultRLimitFiles ( ) ;
}
rl . rlim_cur = fileLimit ;
rl . rlim_max = rl . rlim_cur ;
if ( setrlimit ( RLIMIT_NOFILE , & rl ) < 0 )
2018-04-16 07:39:20 -04:00
Log ( LogWarning , " Application " )
2018-04-23 04:18:31 -04:00
< < " Failed to adjust resource limit for open file handles (RLIMIT_NOFILE) with error \" " < < strerror ( errno ) < < " \" " ;
2013-12-05 05:04:47 -05:00
# else /* RLIMIT_NOFILE */
2017-06-21 05:36:14 -04:00
Log ( LogNotice , " Application " , " System does not support adjusting the resource limit for open file handles (RLIMIT_NOFILE) " ) ;
2013-12-05 05:04:47 -05:00
# endif /* RLIMIT_NOFILE */
2017-06-21 05:36:14 -04:00
}
2013-12-05 05:04:47 -05:00
# ifdef RLIMIT_NPROC
2018-08-09 09:37:23 -04:00
rlim_t processLimit = Configuration : : RLimitProcesses ;
2017-06-21 05:36:14 -04:00
if ( processLimit ! = 0 ) {
2019-03-08 08:07:29 -05:00
if ( processLimit < ( rlim_t ) GetDefaultRLimitProcesses ( ) ) {
2017-06-21 05:36:14 -04:00
Log ( LogWarning , " Application " )
2017-12-19 09:50:05 -05:00
< < " The user-specified value for RLimitProcesses cannot be smaller than the default value ( " < < GetDefaultRLimitProcesses ( ) < < " ). Using the default value instead. " ;
2017-06-21 05:36:14 -04:00
processLimit = GetDefaultRLimitProcesses ( ) ;
}
2013-12-05 05:04:47 -05:00
2017-06-21 05:36:14 -04:00
rl . rlim_cur = processLimit ;
rl . rlim_max = rl . rlim_cur ;
if ( setrlimit ( RLIMIT_NPROC , & rl ) < 0 )
2018-04-16 07:39:20 -04:00
Log ( LogWarning , " Application " )
< < " Failed adjust resource limit for number of processes (RLIMIT_NPROC) with error \" " < < strerror ( errno ) < < " \" " ;
2013-12-05 05:04:47 -05:00
# else /* RLIMIT_NPROC */
2017-06-21 05:36:14 -04:00
Log ( LogNotice , " Application " , " System does not support adjusting the resource limit for number of processes (RLIMIT_NPROC) " ) ;
2013-12-05 05:04:47 -05:00
# endif /* RLIMIT_NPROC */
2017-06-21 05:36:14 -04:00
}
2014-04-22 13:47:19 -04:00
# ifdef RLIMIT_STACK
int argc = Application : : GetArgC ( ) ;
char * * argv = Application : : GetArgV ( ) ;
bool set_stack_rlimit = true ;
for ( int i = 0 ; i < argc ; i + + ) {
if ( strcmp ( argv [ i ] , " --no-stack-rlimit " ) = = 0 ) {
set_stack_rlimit = false ;
break ;
}
}
2014-07-21 07:33:01 -04:00
if ( getrlimit ( RLIMIT_STACK , & rl ) < 0 ) {
Log ( LogWarning , " Application " , " Could not determine resource limit for stack size (RLIMIT_STACK) " ) ;
rl . rlim_max = RLIM_INFINITY ;
}
2014-04-22 13:47:19 -04:00
2017-06-21 05:36:14 -04:00
rlim_t stackLimit ;
2014-04-22 13:47:19 -04:00
2018-08-09 09:37:23 -04:00
stackLimit = Configuration : : RLimitStack ;
2014-04-22 13:47:19 -04:00
2017-06-21 05:36:14 -04:00
if ( stackLimit ! = 0 ) {
2019-03-08 08:07:29 -05:00
if ( stackLimit < ( rlim_t ) GetDefaultRLimitStack ( ) ) {
2017-06-21 05:36:14 -04:00
Log ( LogWarning , " Application " )
2017-12-19 09:50:05 -05:00
< < " The user-specified value for RLimitStack cannot be smaller than the default value ( " < < GetDefaultRLimitStack ( ) < < " ). Using the default value instead. " ;
2017-06-21 05:36:14 -04:00
stackLimit = GetDefaultRLimitStack ( ) ;
2014-07-21 07:33:01 -04:00
}
2014-04-22 13:47:19 -04:00
2017-06-21 05:36:14 -04:00
if ( set_stack_rlimit )
rl . rlim_cur = stackLimit ;
else
rl . rlim_cur = rl . rlim_max ;
2014-04-22 13:47:19 -04:00
2018-04-25 08:26:40 -04:00
if ( setrlimit ( RLIMIT_STACK , & rl ) < 0 )
2018-04-16 07:39:20 -04:00
Log ( LogWarning , " Application " )
< < " Failed adjust resource limit for stack size (RLIMIT_STACK) with error \" " < < strerror ( errno ) < < " \" " ;
2018-04-25 08:26:40 -04:00
else if ( set_stack_rlimit ) {
char * * new_argv = static_cast < char * * > ( malloc ( sizeof ( char * ) * ( argc + 2 ) ) ) ;
2014-07-21 07:33:01 -04:00
2018-04-25 08:26:40 -04:00
if ( ! new_argv ) {
perror ( " malloc " ) ;
Exit ( EXIT_FAILURE ) ;
}
2014-08-06 04:35:27 -04:00
2018-04-25 08:26:40 -04:00
new_argv [ 0 ] = argv [ 0 ] ;
new_argv [ 1 ] = strdup ( " --no-stack-rlimit " ) ;
2014-07-21 07:33:01 -04:00
2018-04-25 08:26:40 -04:00
if ( ! new_argv [ 1 ] ) {
perror ( " strdup " ) ;
exit ( 1 ) ;
}
2017-06-21 05:36:14 -04:00
2018-04-25 08:26:40 -04:00
for ( int i = 1 ; i < argc ; i + + )
new_argv [ i + 1 ] = argv [ i ] ;
2017-06-21 05:36:14 -04:00
2018-04-25 08:26:40 -04:00
new_argv [ argc + 1 ] = nullptr ;
2017-06-21 05:36:14 -04:00
2018-04-25 08:26:40 -04:00
( void ) execvp ( new_argv [ 0 ] , new_argv ) ;
perror ( " execvp " ) ;
_exit ( EXIT_FAILURE ) ;
2017-06-21 05:36:14 -04:00
}
2014-04-22 13:47:19 -04:00
# else /* RLIMIT_STACK */
2017-06-21 05:36:14 -04:00
Log ( LogNotice , " Application " , " System does not support adjusting the resource limit for stack size (RLIMIT_STACK) " ) ;
2014-04-22 13:47:19 -04:00
# endif /* RLIMIT_STACK */
2017-06-21 05:36:14 -04:00
}
2015-01-09 05:43:57 -05:00
# endif /* __linux__ */
2013-12-05 05:04:47 -05:00
}
2018-01-03 22:25:35 -05:00
int Application : : GetArgC ( )
2013-02-14 10:18:58 -05:00
{
return m_ArgC ;
}
void Application : : SetArgC ( int argc )
{
m_ArgC = argc ;
}
2018-01-03 22:25:35 -05:00
char * * Application : : GetArgV ( )
2013-02-14 10:18:58 -05:00
{
return m_ArgV ;
}
void Application : : SetArgV ( char * * argv )
{
m_ArgV = argv ;
}
2012-04-24 08:02:15 -04:00
/**
2012-05-18 16:53:35 -04:00
* Processes events for registered sockets and timers and calls whatever
* handlers have been set up for these events .
2012-04-24 08:02:15 -04:00
*/
2018-01-03 22:25:35 -05:00
void Application : : RunEventLoop ( )
2012-03-28 07:24:49 -04:00
{
2014-04-22 13:47:19 -04:00
double lastLoop = Utility : : GetTime ( ) ;
2019-03-08 08:59:01 -05:00
while ( ! m_ShuttingDown ) {
if ( m_RequestRestart ) {
m_RequestRestart = false ; // we are now handling the request, once is enough
2014-04-22 13:47:19 -04:00
2019-07-15 07:59:17 -04:00
# ifdef _WIN32
2019-03-08 08:59:01 -05:00
// are we already restarting? ignore request if we already are
if ( ! l_Restarting ) {
l_Restarting = true ;
m_ReloadProcess = StartReloadProcess ( ) ;
}
2019-07-15 07:59:17 -04:00
# else /* _WIN32 */
2019-07-16 05:43:47 -04:00
Log ( LogNotice , " Application " )
< < " Got reload command, forwarding to umbrella process (PID " < < m_UmbrellaProcess < < " ) " ;
2019-07-15 12:29:15 -04:00
2019-07-15 07:59:17 -04:00
( void ) kill ( m_UmbrellaProcess , SIGHUP ) ;
# endif /* _WIN32 */
2019-03-08 08:59:01 -05:00
} else {
/* Watches for changes to the system time. Adjusts timers if necessary. */
Utility : : Sleep ( 2.5 ) ;
if ( m_RequestReopenLogs ) {
Log ( LogNotice , " Application " , " Reopening log files " ) ;
m_RequestReopenLogs = false ;
OnReopenLogs ( ) ;
}
2014-08-04 08:03:37 -04:00
2019-03-08 08:59:01 -05:00
double now = Utility : : GetTime ( ) ;
double timeDiff = lastLoop - now ;
2014-04-27 15:47:25 -04:00
2019-03-08 08:59:01 -05:00
if ( std : : fabs ( timeDiff ) > 15 ) {
/* We made a significant jump in time. */
Log ( LogInformation , " Application " )
< < " We jumped "
< < ( timeDiff < 0 ? " forward " : " backward " )
< < " in time: " < < std : : fabs ( timeDiff ) < < " seconds " ;
2014-04-28 17:30:56 -04:00
2019-03-08 08:59:01 -05:00
Timer : : AdjustTimers ( - timeDiff ) ;
}
2014-04-28 17:30:56 -04:00
2019-03-08 08:59:01 -05:00
lastLoop = now ;
}
2014-04-27 15:47:25 -04:00
}
2014-08-04 08:03:37 -04:00
2015-03-12 10:53:56 -04:00
Log ( LogInformation , " Application " , " Shutting down... " ) ;
2015-08-15 14:28:05 -04:00
ConfigObject : : StopObjects ( ) ;
2013-10-17 04:56:42 -04:00
Application : : GetInstance ( ) - > OnShutdown ( ) ;
2014-12-04 15:45:15 -05:00
UninitializeBase ( ) ;
2012-09-25 09:24:14 -04:00
}
2018-01-03 22:25:35 -05:00
bool Application : : IsShuttingDown ( )
2016-08-17 13:24:22 -04:00
{
return m_ShuttingDown ;
}
2019-05-03 06:44:29 -04:00
bool Application : : IsRestarting ( )
{
return l_Restarting ;
}
2018-01-03 22:25:35 -05:00
void Application : : OnShutdown ( )
2013-11-04 09:57:46 -05:00
{
/* Nothing to do here. */
}
2015-08-10 09:28:10 -04:00
static void ReloadProcessCallbackInternal ( const ProcessResult & pr )
2014-05-11 11:14:35 -04:00
{
2016-05-11 10:07:28 -04:00
if ( pr . ExitStatus ! = 0 ) {
Application : : SetLastReloadFailed ( Utility : : GetTime ( ) ) ;
2014-05-28 07:17:02 -04:00
Log ( LogCritical , " Application " , " Found error in config: reloading aborted " ) ;
2016-05-11 10:07:28 -04:00
}
2015-08-10 09:28:10 -04:00
# ifdef _WIN32
else
Application : : Exit ( 7 ) ; /* keep this exit code in sync with icinga-app */
# endif /* _WIN32 */
}
static void ReloadProcessCallback ( const ProcessResult & pr )
{
2014-05-11 11:14:35 -04:00
l_Restarting = false ;
2015-08-10 09:28:10 -04:00
2017-11-21 06:12:58 -05:00
std : : thread t ( std : : bind ( & ReloadProcessCallbackInternal , pr ) ) ;
2015-08-10 09:28:10 -04:00
t . detach ( ) ;
2014-05-11 11:14:35 -04:00
}
2018-01-03 22:25:35 -05:00
pid_t Application : : StartReloadProcess ( )
2014-04-27 15:47:25 -04:00
{
// prepare arguments
2018-01-11 05:17:38 -05:00
ArrayData args ;
args . push_back ( GetExePath ( m_ArgV [ 0 ] ) ) ;
2014-04-27 15:47:25 -04:00
2014-04-28 18:05:39 -04:00
for ( int i = 1 ; i < Application : : GetArgC ( ) ; i + + ) {
2014-04-27 15:47:25 -04:00
if ( std : : string ( Application : : GetArgV ( ) [ i ] ) ! = " --reload-internal " )
2018-01-11 05:17:38 -05:00
args . push_back ( Application : : GetArgV ( ) [ i ] ) ;
2014-04-28 18:05:39 -04:00
else
i + + ; // the next parameter after --reload-internal is the pid, remove that too
}
2015-08-10 09:28:10 -04:00
# ifndef _WIN32
2018-01-11 05:17:38 -05:00
args . push_back ( " --reload-internal " ) ;
args . push_back ( Convert : : ToString ( Utility : : GetPid ( ) ) ) ;
2015-08-10 09:28:10 -04:00
# else /* _WIN32 */
2018-06-12 06:19:16 -04:00
args . push_back ( " --validate " ) ;
2015-08-10 09:28:10 -04:00
# endif /* _WIN32 */
2014-04-27 15:47:25 -04:00
2019-04-15 10:56:30 -04:00
double reloadTimeout = Application : : GetReloadTimeout ( ) ;
2018-01-11 05:17:38 -05:00
Process : : Ptr process = new Process ( Process : : PrepareCommand ( new Array ( std : : move ( args ) ) ) ) ;
2019-04-15 10:56:30 -04:00
process - > SetTimeout ( reloadTimeout ) ;
2014-05-11 11:14:35 -04:00
process - > Run ( & ReloadProcessCallback ) ;
2014-08-04 08:03:37 -04:00
2019-02-22 09:53:38 -05:00
Log ( LogInformation , " Application " )
< < " Got reload command: Started new instance with PID ' "
< < ( unsigned long ) ( process - > GetPID ( ) ) < < " ' (timeout is "
2019-04-15 10:56:30 -04:00
< < reloadTimeout < < " s). " ;
2019-02-22 09:53:38 -05:00
2014-05-18 12:04:34 -04:00
return process - > GetPID ( ) ;
2014-04-27 15:47:25 -04:00
}
2012-04-24 08:02:15 -04:00
/**
* Signals the application to shut down during the next
* execution of the event loop .
*/
2018-01-03 22:25:35 -05:00
void Application : : RequestShutdown ( )
2012-03-28 07:24:49 -04:00
{
2015-03-12 06:43:04 -04:00
Log ( LogInformation , " Application " , " Received request to shut down. " ) ;
2012-03-28 07:24:49 -04:00
m_ShuttingDown = true ;
}
2012-03-31 09:18:09 -04:00
2013-08-30 08:27:24 -04:00
/**
* Signals the application to restart during the next
* execution of the event loop .
*/
2018-01-03 22:25:35 -05:00
void Application : : RequestRestart ( )
2013-08-30 08:27:24 -04:00
{
2014-04-27 15:47:25 -04:00
m_RequestRestart = true ;
2013-08-30 08:27:24 -04:00
}
2014-05-22 05:22:30 -04:00
/**
* Signals the application to reopen log files during the
* next execution of the event loop .
*/
2018-01-03 22:25:35 -05:00
void Application : : RequestReopenLogs ( )
2014-05-22 05:22:30 -04:00
{
m_RequestReopenLogs = true ;
}
2019-07-15 07:59:17 -04:00
# ifndef _WIN32
2019-07-16 05:11:10 -04:00
/**
* Sets the PID of the Icinga umbrella process .
*
* @ param pid The PID of the Icinga umbrella process .
*/
2019-07-15 07:59:17 -04:00
void Application : : SetUmbrellaProcess ( pid_t pid )
{
m_UmbrellaProcess = pid ;
}
# endif /* _WIN32 */
2012-04-24 08:02:15 -04:00
/**
2012-07-10 07:31:17 -04:00
* Retrieves the full path of the executable .
2012-04-24 08:02:15 -04:00
*
2012-08-14 06:51:51 -04:00
* @ param argv0 The first command - line argument .
2012-07-10 07:31:17 -04:00
* @ returns The path .
2012-04-24 08:02:15 -04:00
*/
2012-08-14 06:51:51 -04:00
String Application : : GetExePath ( const String & argv0 )
2012-04-02 07:09:33 -04:00
{
2012-08-02 03:38:08 -04:00
String executablePath ;
2012-07-08 15:18:35 -04:00
2012-04-02 07:09:33 -04:00
# ifndef _WIN32
2012-06-15 16:26:25 -04:00
char buffer [ MAXPATHLEN ] ;
2017-12-14 09:37:20 -05:00
if ( ! getcwd ( buffer , sizeof ( buffer ) ) ) {
2013-03-11 08:45:08 -04:00
BOOST_THROW_EXCEPTION ( posix_error ( )
2017-12-19 09:50:05 -05:00
< < boost : : errinfo_api_function ( " getcwd " )
< < boost : : errinfo_errno ( errno ) ) ;
2013-03-11 08:45:08 -04:00
}
2012-08-02 03:38:08 -04:00
String workingDirectory = buffer ;
2012-04-02 07:09:33 -04:00
if ( argv0 [ 0 ] ! = ' / ' )
2012-07-08 15:18:35 -04:00
executablePath = workingDirectory + " / " + argv0 ;
2012-04-02 07:09:33 -04:00
else
2012-07-08 15:18:35 -04:00
executablePath = argv0 ;
2012-04-02 07:09:33 -04:00
2012-08-02 03:38:08 -04:00
bool foundSlash = false ;
2012-08-04 03:58:31 -04:00
for ( size_t i = 0 ; i < argv0 . GetLength ( ) ; i + + ) {
2012-08-02 03:38:08 -04:00
if ( argv0 [ i ] = = ' / ' ) {
foundSlash = true ;
break ;
}
}
if ( ! foundSlash ) {
2018-11-19 08:59:20 -05:00
String pathEnv = Utility : : GetFromEnvironment ( " PATH " ) ;
if ( ! pathEnv . IsEmpty ( ) ) {
2018-01-04 12:24:45 -05:00
std : : vector < String > paths = String ( pathEnv ) . Split ( " : " ) ;
2012-04-02 07:09:33 -04:00
2012-06-15 16:26:25 -04:00
bool foundPath = false ;
2016-08-25 00:19:44 -04:00
for ( const String & path : paths ) {
2012-08-02 03:38:08 -04:00
String pathTest = path + " / " + argv0 ;
2012-04-02 07:09:33 -04:00
2012-08-02 03:38:08 -04:00
if ( access ( pathTest . CStr ( ) , X_OK ) = = 0 ) {
2012-07-08 15:18:35 -04:00
executablePath = pathTest ;
2012-06-15 16:26:25 -04:00
foundPath = true ;
2012-04-02 07:09:33 -04:00
break ;
}
}
2012-06-15 16:26:25 -04:00
if ( ! foundPath ) {
2012-08-02 03:38:08 -04:00
executablePath . Clear ( ) ;
2013-03-16 16:18:53 -04:00
BOOST_THROW_EXCEPTION ( std : : runtime_error ( " Could not determine executable path. " ) ) ;
2012-06-15 16:26:25 -04:00
}
2012-04-02 07:09:33 -04:00
}
}
2017-12-14 09:37:20 -05:00
if ( ! realpath ( executablePath . CStr ( ) , buffer ) ) {
2013-03-11 08:45:08 -04:00
BOOST_THROW_EXCEPTION ( posix_error ( )
2017-12-19 09:50:05 -05:00
< < boost : : errinfo_api_function ( " realpath " )
< < boost : : errinfo_errno ( errno )
< < boost : : errinfo_file_name ( executablePath ) ) ;
2013-03-11 08:45:08 -04:00
}
2012-04-02 07:09:33 -04:00
2012-08-14 06:51:51 -04:00
return buffer ;
2012-04-02 07:09:33 -04:00
# else /* _WIN32 */
char FullExePath [ MAXPATHLEN ] ;
2017-12-14 09:37:20 -05:00
if ( ! GetModuleFileName ( nullptr , FullExePath , sizeof ( FullExePath ) ) )
2013-03-11 09:03:01 -04:00
BOOST_THROW_EXCEPTION ( win32_error ( )
2017-12-19 09:50:05 -05:00
< < boost : : errinfo_api_function ( " GetModuleFileName " )
< < errinfo_win32_error ( GetLastError ( ) ) ) ;
2012-04-02 07:09:33 -04:00
2012-08-14 06:51:51 -04:00
return FullExePath ;
2012-04-02 07:09:33 -04:00
# endif /* _WIN32 */
}
2013-11-15 03:04:39 -05:00
/**
2014-07-23 03:30:56 -04:00
* Display version and path information .
2013-11-15 03:04:39 -05:00
*/
2014-12-20 09:29:04 -05:00
void Application : : DisplayInfoMessage ( std : : ostream & os , bool skipVersion )
2013-11-15 03:04:39 -05:00
{
2018-08-07 12:44:08 -04:00
/* icinga-app prints its own version information, stack traces need it here. */
2014-07-23 03:30:56 -04:00
if ( ! skipVersion )
2018-08-07 12:44:08 -04:00
os < < " Application version: " < < GetAppVersion ( ) < < " \n \n " ;
os < < " System information: \n "
< < " Platform: " < < Utility : : GetPlatformName ( ) < < " \n "
< < " Platform version: " < < Utility : : GetPlatformVersion ( ) < < " \n "
< < " Kernel: " < < Utility : : GetPlatformKernel ( ) < < " \n "
< < " Kernel version: " < < Utility : : GetPlatformKernelVersion ( ) < < " \n "
< < " Architecture: " < < Utility : : GetPlatformArchitecture ( ) < < " \n " ;
2018-08-09 09:37:23 -04:00
Namespace : : Ptr systemNS = ScriptGlobal : : Get ( " System " ) ;
2018-08-07 12:44:08 -04:00
os < < " \n Build information: \n "
2018-08-09 09:37:23 -04:00
< < " Compiler: " < < systemNS - > Get ( " BuildCompilerName " ) < < " " < < systemNS - > Get ( " BuildCompilerVersion " ) < < " \n "
< < " Build host: " < < systemNS - > Get ( " BuildHostName " ) < < " \n " ;
2014-12-20 09:29:04 -05:00
2018-08-07 12:44:08 -04:00
os < < " \n Application information: \n "
< < " \n General paths: \n "
2018-08-09 09:37:23 -04:00
< < " Config directory: " < < Configuration : : ConfigDir < < " \n "
< < " Data directory: " < < Configuration : : DataDir < < " \n "
< < " Log directory: " < < Configuration : : LogDir < < " \n "
< < " Cache directory: " < < Configuration : : CacheDir < < " \n "
< < " Spool directory: " < < Configuration : : SpoolDir < < " \n "
< < " Run directory: " < < Configuration : : InitRunDir < < " \n "
2018-08-07 12:44:08 -04:00
< < " \n Old paths (deprecated): \n "
2018-08-09 09:37:23 -04:00
< < " Installation root: " < < Configuration : : PrefixDir < < " \n "
< < " Sysconf directory: " < < Configuration : : SysconfDir < < " \n "
< < " Run directory (base): " < < Configuration : : RunDir < < " \n "
< < " Local state directory: " < < Configuration : : LocalStateDir < < " \n "
2018-08-07 12:44:08 -04:00
< < " \n Internal paths: \n "
2018-08-09 09:37:23 -04:00
< < " Package data directory: " < < Configuration : : PkgDataDir < < " \n "
< < " State path: " < < Configuration : : StatePath < < " \n "
< < " Modified attributes path: " < < Configuration : : ModAttrPath < < " \n "
< < " Objects path: " < < Configuration : : ObjectsPath < < " \n "
< < " Vars path: " < < Configuration : : VarsPath < < " \n "
< < " PID path: " < < Configuration : : PidPath < < " \n " ;
2015-03-16 08:32:13 -04:00
2013-11-15 03:04:39 -05:00
}
2013-02-01 13:36:47 -05:00
/**
* Displays a message that tells users what to do when they encounter a bug .
*/
2014-12-20 09:29:04 -05:00
void Application : : DisplayBugMessage ( std : : ostream & os )
2013-02-01 13:36:47 -05:00
{
2014-12-20 09:29:04 -05:00
os < < " *** " < < " \n "
2017-12-19 09:50:05 -05:00
< < " * This would indicate a runtime problem or configuration error. If you believe this is a bug in Icinga 2 " < < " \n "
< < " * please submit a bug report at https://github.com/Icinga/icinga2 and include this stack trace as well as any other " < < " \n "
< < " * information that might be useful in order to reproduce this problem. " < < " \n "
< < " *** " < < " \n " ;
2013-02-01 13:36:47 -05:00
}
2018-01-03 22:25:35 -05:00
String Application : : GetCrashReportFilename ( )
2014-12-22 08:14:16 -05:00
{
2018-08-09 09:37:23 -04:00
return Configuration : : LogDir + " /crash/report. " + Convert : : ToString ( Utility : : GetTime ( ) ) ;
2014-12-22 08:14:16 -05:00
}
2015-03-03 07:53:11 -05:00
2015-08-08 03:40:16 -04:00
void Application : : AttachDebugger ( const String & filename , bool interactive )
2015-03-03 07:53:11 -05:00
{
2015-08-08 03:40:16 -04:00
# ifndef _WIN32
2015-03-03 07:53:11 -05:00
# ifdef __linux__
prctl ( PR_SET_DUMPABLE , 1 ) ;
# endif /* __linux __ */
String my_pid = Convert : : ToString ( Utility : : GetPid ( ) ) ;
pid_t pid = fork ( ) ;
if ( pid < 0 ) {
BOOST_THROW_EXCEPTION ( posix_error ( )
2017-12-19 09:50:05 -05:00
< < boost : : errinfo_api_function ( " fork " )
< < boost : : errinfo_errno ( errno ) ) ;
2015-03-03 07:53:11 -05:00
}
if ( pid = = 0 ) {
2015-08-08 03:40:16 -04:00
if ( ! interactive ) {
int fd = open ( filename . CStr ( ) , O_CREAT | O_RDWR | O_APPEND , 0600 ) ;
if ( fd < 0 ) {
BOOST_THROW_EXCEPTION ( posix_error ( )
2017-12-19 09:50:05 -05:00
< < boost : : errinfo_api_function ( " open " )
< < boost : : errinfo_errno ( errno )
< < boost : : errinfo_file_name ( filename ) ) ;
2015-08-08 03:40:16 -04:00
}
2015-03-03 07:53:11 -05:00
2015-08-08 03:40:16 -04:00
if ( fd ! = 1 ) {
/* redirect stdout to the file */
dup2 ( fd , 1 ) ;
close ( fd ) ;
}
2015-03-03 07:53:11 -05:00
2015-08-08 03:40:16 -04:00
/* redirect stderr to stdout */
if ( fd ! = 2 )
close ( 2 ) ;
dup2 ( 1 , 2 ) ;
2015-03-03 07:53:11 -05:00
}
2015-08-08 03:40:16 -04:00
char * * argv ;
char * my_pid_str = strdup ( my_pid . CStr ( ) ) ;
2015-03-03 07:53:11 -05:00
2015-08-08 03:40:16 -04:00
if ( interactive ) {
const char * uargv [ ] = {
" gdb " ,
" -p " ,
my_pid_str ,
2017-12-14 09:37:20 -05:00
nullptr
2015-08-08 03:40:16 -04:00
} ;
2017-12-14 09:04:25 -05:00
2015-08-08 03:40:16 -04:00
argv = const_cast < char * * > ( uargv ) ;
2017-12-14 09:04:25 -05:00
( void ) execvp ( argv [ 0 ] , argv ) ;
2015-08-08 03:40:16 -04:00
} else {
const char * uargv [ ] = {
" gdb " ,
" --batch " ,
" -p " ,
my_pid_str ,
" -ex " ,
" thread apply all bt full " ,
" -ex " ,
" detach " ,
" -ex " ,
" quit " ,
2017-12-14 09:37:20 -05:00
nullptr
2015-08-08 03:40:16 -04:00
} ;
2017-12-14 09:04:25 -05:00
2015-08-08 03:40:16 -04:00
argv = const_cast < char * * > ( uargv ) ;
2017-12-14 09:04:25 -05:00
( void ) execvp ( argv [ 0 ] , argv ) ;
2015-08-08 03:40:16 -04:00
}
2015-03-03 07:53:11 -05:00
perror ( " Failed to launch GDB " ) ;
free ( my_pid_str ) ;
_exit ( 0 ) ;
}
int status ;
if ( waitpid ( pid , & status , 0 ) < 0 ) {
BOOST_THROW_EXCEPTION ( posix_error ( )
2017-12-19 09:50:05 -05:00
< < boost : : errinfo_api_function ( " waitpid " )
< < boost : : errinfo_errno ( errno ) ) ;
2015-03-03 07:53:11 -05:00
}
# ifdef __linux__
prctl ( PR_SET_DUMPABLE , 0 ) ;
# endif /* __linux __ */
2015-08-08 03:40:16 -04:00
# else /* _WIN32 */
DebugBreak ( ) ;
# endif /* _WIN32 */
2015-03-03 07:53:11 -05:00
}
2014-05-22 05:22:30 -04:00
/**
* Signal handler for SIGUSR1 . This signal causes Icinga to re - open
* its log files and is mainly for use by logrotate .
*
* @ param - The signal number .
*/
void Application : : SigUsr1Handler ( int )
{
2019-04-24 05:33:43 -04:00
Log ( LogInformation , " Application " )
< < " Received USR1 signal, reopening application logs. " ;
2014-05-22 05:22:30 -04:00
RequestReopenLogs ( ) ;
}
2013-01-30 05:51:15 -05:00
/**
2013-03-07 10:00:10 -05:00
* Signal handler for SIGABRT . Helps with debugging ASSERT ( ) s .
2013-01-30 05:51:15 -05:00
*
2013-08-20 05:06:04 -04:00
* @ param - The signal number .
2013-01-30 05:51:15 -05:00
*/
2013-08-20 05:06:04 -04:00
void Application : : SigAbrtHandler ( int )
2013-01-30 05:51:15 -05:00
{
2013-03-07 09:00:26 -05:00
# ifndef _WIN32
2013-03-06 05:03:50 -05:00
struct sigaction sa ;
memset ( & sa , 0 , sizeof ( sa ) ) ;
sa . sa_handler = SIG_DFL ;
2017-12-14 09:37:20 -05:00
sigaction ( SIGABRT , & sa , nullptr ) ;
2013-03-07 09:00:26 -05:00
# endif /* _WIN32 */
2013-03-06 05:03:50 -05:00
2013-11-15 03:04:39 -05:00
std : : cerr < < " Caught SIGABRT. " < < std : : endl
2017-12-19 09:50:05 -05:00
< < " Current time: " < < Utility : : FormatDateTime ( " %Y-%m-%d %H:%M:%S %z " , Utility : : GetTime ( ) ) < < std : : endl
< < std : : endl ;
2013-11-15 03:04:39 -05:00
2014-12-20 09:29:04 -05:00
String fname = GetCrashReportFilename ( ) ;
2015-12-08 09:12:13 -05:00
String dirName = Utility : : DirName ( fname ) ;
if ( ! Utility : : PathExists ( dirName ) ) {
# ifndef _WIN32
if ( mkdir ( dirName . CStr ( ) , 0700 ) < 0 & & errno ! = EEXIST ) {
# else /*_ WIN32 */
if ( mkdir ( dirName . CStr ( ) ) < 0 & & errno ! = EEXIST ) {
# endif /* _WIN32 */
std : : cerr < < " Could not create directory ' " < < dirName < < " ': Error " < < errno < < " , " < < strerror ( errno ) < < " \n " ;
}
}
2015-03-11 11:06:04 -04:00
2018-08-09 09:37:23 -04:00
bool interactive_debugger = Configuration : : AttachDebugger ;
2014-12-20 09:29:04 -05:00
2015-08-08 03:40:16 -04:00
if ( ! interactive_debugger ) {
std : : ofstream ofs ;
ofs . open ( fname . CStr ( ) ) ;
2014-12-20 09:29:04 -05:00
2015-08-08 03:40:16 -04:00
Log ( LogCritical , " Application " )
2017-12-19 09:50:05 -05:00
< < " Icinga 2 has terminated unexpectedly. Additional information can be found in ' " < < fname < < " ' " < < " \n " ;
2013-01-30 05:51:15 -05:00
2015-08-08 03:40:16 -04:00
DisplayInfoMessage ( ofs ) ;
2014-12-20 09:29:04 -05:00
2015-08-08 03:40:16 -04:00
StackTrace trace ;
ofs < < " Stacktrace: " < < " \n " ;
trace . Print ( ofs , 1 ) ;
2013-02-01 08:46:06 -05:00
2015-08-08 03:40:16 -04:00
DisplayBugMessage ( ofs ) ;
2015-03-03 07:53:11 -05:00
2015-08-08 03:40:16 -04:00
ofs < < " \n " ;
ofs . close ( ) ;
} else {
2015-12-08 09:12:13 -05:00
Log ( LogCritical , " Application " , " Icinga 2 has terminated unexpectedly. Attaching debugger... " ) ;
2015-08-08 03:40:16 -04:00
}
AttachDebugger ( fname , interactive_debugger ) ;
2013-01-30 05:51:15 -05:00
}
2015-08-08 03:40:16 -04:00
# ifdef _WIN32
2012-05-21 06:53:38 -04:00
/**
* Console control handler . Prepares the application for cleanly
* shutting down during the next execution of the event loop .
*/
BOOL WINAPI Application : : CtrlHandler ( DWORD type )
{
2013-03-02 03:07:47 -05:00
Application : : Ptr instance = Application : : GetInstance ( ) ;
2012-06-20 09:23:10 -04:00
if ( ! instance )
return TRUE ;
2013-03-01 06:07:52 -05:00
instance - > RequestShutdown ( ) ;
2012-06-20 09:23:10 -04:00
2017-12-14 09:37:20 -05:00
SetConsoleCtrlHandler ( nullptr , FALSE ) ;
2012-05-21 06:53:38 -04:00
return TRUE ;
}
2017-08-22 04:26:23 -04:00
2018-01-03 22:25:35 -05:00
bool Application : : IsProcessElevated ( ) {
2017-08-22 04:26:23 -04:00
BOOL fIsElevated = FALSE ;
DWORD dwError = ERROR_SUCCESS ;
2017-12-14 09:37:20 -05:00
HANDLE hToken = nullptr ;
2017-08-22 04:26:23 -04:00
if ( ! OpenProcessToken ( GetCurrentProcess ( ) , TOKEN_QUERY , & hToken ) )
dwError = GetLastError ( ) ;
else {
TOKEN_ELEVATION elevation ;
DWORD dwSize ;
if ( ! GetTokenInformation ( hToken , TokenElevation , & elevation , sizeof ( elevation ) , & dwSize ) )
dwError = GetLastError ( ) ;
else
fIsElevated = elevation . TokenIsElevated ;
}
if ( hToken ) {
CloseHandle ( hToken ) ;
2017-12-14 09:37:20 -05:00
hToken = nullptr ;
2017-08-22 04:26:23 -04:00
}
if ( ERROR_SUCCESS ! = dwError ) {
2017-12-14 09:37:20 -05:00
LPSTR mBuf = nullptr ;
2017-08-22 04:26:23 -04:00
if ( ! FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ,
2017-12-14 09:37:20 -05:00
nullptr , dwError , MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , mBuf , 0 , nullptr ) )
2017-08-22 04:26:23 -04:00
BOOST_THROW_EXCEPTION ( std : : runtime_error ( " Failed to format error message, last error was: " + dwError ) ) ;
else
BOOST_THROW_EXCEPTION ( std : : runtime_error ( mBuf ) ) ;
}
return fIsElevated ;
}
2012-04-22 10:45:31 -04:00
# endif /* _WIN32 */
2012-04-06 02:56:52 -04:00
2013-01-30 05:51:15 -05:00
/**
* Handler for unhandled exceptions .
*/
2018-01-03 22:25:35 -05:00
void Application : : ExceptionHandler ( )
2013-01-30 05:51:15 -05:00
{
2014-09-09 08:49:21 -04:00
if ( l_InExceptionHandler )
for ( ; ; )
Utility : : Sleep ( 5 ) ;
l_InExceptionHandler = true ;
2013-03-06 05:03:50 -05:00
# ifndef _WIN32
struct sigaction sa ;
memset ( & sa , 0 , sizeof ( sa ) ) ;
sa . sa_handler = SIG_DFL ;
2017-12-14 09:37:20 -05:00
sigaction ( SIGABRT , & sa , nullptr ) ;
2013-03-06 05:03:50 -05:00
# endif /* _WIN32 */
2014-12-20 09:29:04 -05:00
String fname = GetCrashReportFilename ( ) ;
2015-12-08 09:12:13 -05:00
String dirName = Utility : : DirName ( fname ) ;
if ( ! Utility : : PathExists ( dirName ) ) {
# ifndef _WIN32
if ( mkdir ( dirName . CStr ( ) , 0700 ) < 0 & & errno ! = EEXIST ) {
# else /*_ WIN32 */
if ( mkdir ( dirName . CStr ( ) ) < 0 & & errno ! = EEXIST ) {
# endif /* _WIN32 */
std : : cerr < < " Could not create directory ' " < < dirName < < " ': Error " < < errno < < " , " < < strerror ( errno ) < < " \n " ;
}
}
2015-03-11 11:06:04 -04:00
2018-08-09 09:37:23 -04:00
bool interactive_debugger = Configuration : : AttachDebugger ;
2013-11-15 03:04:39 -05:00
2015-12-08 09:12:13 -05:00
if ( ! interactive_debugger ) {
2015-08-08 03:40:16 -04:00
std : : ofstream ofs ;
ofs . open ( fname . CStr ( ) ) ;
2014-12-20 09:29:04 -05:00
2015-08-08 03:40:16 -04:00
ofs < < " Caught unhandled exception. " < < " \n "
2017-12-19 09:50:05 -05:00
< < " Current time: " < < Utility : : FormatDateTime ( " %Y-%m-%d %H:%M:%S %z " , Utility : : GetTime ( ) ) < < " \n "
< < " \n " ;
2013-11-15 03:04:39 -05:00
2015-08-08 03:40:16 -04:00
DisplayInfoMessage ( ofs ) ;
2014-12-20 09:29:04 -05:00
2015-08-08 03:40:16 -04:00
try {
RethrowUncaughtException ( ) ;
} catch ( const std : : exception & ex ) {
Log ( LogCritical , " Application " )
2017-12-19 09:50:05 -05:00
< < DiagnosticInformation ( ex , false ) < < " \n "
< < " \n "
< < " Additional information is available in ' " < < fname < < " ' " < < " \n " ;
2015-08-08 03:40:16 -04:00
ofs < < " \n "
2017-12-19 09:50:05 -05:00
< < DiagnosticInformation ( ex )
< < " \n " ;
2015-08-08 03:40:16 -04:00
}
2013-01-30 05:51:15 -05:00
2015-08-08 03:40:16 -04:00
DisplayBugMessage ( ofs ) ;
2014-12-20 09:29:04 -05:00
2015-08-08 03:40:16 -04:00
ofs . close ( ) ;
}
2013-02-01 13:11:15 -05:00
2015-08-08 03:40:16 -04:00
AttachDebugger ( fname , interactive_debugger ) ;
2015-03-03 07:53:11 -05:00
2013-01-30 05:51:15 -05:00
abort ( ) ;
}
2013-03-07 09:00:26 -05:00
# ifdef _WIN32
LONG CALLBACK Application : : SEHUnhandledExceptionFilter ( PEXCEPTION_POINTERS exi )
{
2014-09-09 08:49:21 -04:00
if ( l_InExceptionHandler )
return EXCEPTION_CONTINUE_SEARCH ;
l_InExceptionHandler = true ;
2014-12-20 09:29:04 -05:00
String fname = GetCrashReportFilename ( ) ;
2015-12-08 09:12:13 -05:00
String dirName = Utility : : DirName ( fname ) ;
if ( ! Utility : : PathExists ( dirName ) ) {
# ifndef _WIN32
if ( mkdir ( dirName . CStr ( ) , 0700 ) < 0 & & errno ! = EEXIST ) {
# else /*_ WIN32 */
if ( mkdir ( dirName . CStr ( ) ) < 0 & & errno ! = EEXIST ) {
# endif /* _WIN32 */
std : : cerr < < " Could not create directory ' " < < dirName < < " ': Error " < < errno < < " , " < < strerror ( errno ) < < " \n " ;
}
}
2015-03-11 11:06:04 -04:00
2014-12-20 09:29:04 -05:00
std : : ofstream ofs ;
ofs . open ( fname . CStr ( ) ) ;
2013-11-15 03:04:39 -05:00
2014-12-20 09:29:04 -05:00
Log ( LogCritical , " Application " )
2017-12-19 09:50:05 -05:00
< < " Icinga 2 has terminated unexpectedly. Additional information can be found in ' " < < fname < < " ' " ;
2014-12-20 09:29:04 -05:00
DisplayInfoMessage ( ofs ) ;
ofs < < " Caught unhandled SEH exception. " < < " \n "
2017-12-19 09:50:05 -05:00
< < " Current time: " < < Utility : : FormatDateTime ( " %Y-%m-%d %H:%M:%S %z " , Utility : : GetTime ( ) ) < < " \n "
< < " \n " ;
2013-03-07 09:00:26 -05:00
StackTrace trace ( exi ) ;
2014-12-20 09:29:04 -05:00
ofs < < " Stacktrace: " < < " \n " ;
trace . Print ( ofs , 1 ) ;
2013-03-07 09:00:26 -05:00
2014-12-20 09:29:04 -05:00
DisplayBugMessage ( ofs ) ;
2013-03-07 09:00:26 -05:00
return EXCEPTION_CONTINUE_SEARCH ;
}
2013-03-09 06:56:40 -05:00
# endif /* _WIN32 */
2013-01-30 05:51:15 -05:00
/**
* Installs the exception handlers .
*/
2018-01-03 22:25:35 -05:00
void Application : : InstallExceptionHandlers ( )
2013-01-30 05:51:15 -05:00
{
std : : set_terminate ( & Application : : ExceptionHandler ) ;
# ifndef _WIN32
struct sigaction sa ;
memset ( & sa , 0 , sizeof ( sa ) ) ;
sa . sa_handler = & Application : : SigAbrtHandler ;
2017-12-14 09:37:20 -05:00
sigaction ( SIGABRT , & sa , nullptr ) ;
2013-03-07 09:00:26 -05:00
# else /* _WIN32 */
SetUnhandledExceptionFilter ( & Application : : SEHUnhandledExceptionFilter ) ;
2013-01-30 05:51:15 -05:00
# endif /* _WIN32 */
}
2012-04-24 08:02:15 -04:00
/**
2012-05-15 04:58:14 -04:00
* Runs the application .
2012-04-24 08:02:15 -04:00
*
* @ returns The application ' s exit code .
*/
2018-01-03 22:25:35 -05:00
int Application : : Run ( )
2012-04-06 02:56:52 -04:00
{
# ifndef _WIN32
struct sigaction sa ;
memset ( & sa , 0 , sizeof ( sa ) ) ;
2014-05-22 05:22:30 -04:00
sa . sa_handler = & Application : : SigUsr1Handler ;
2017-12-14 09:37:20 -05:00
sigaction ( SIGUSR1 , & sa , nullptr ) ;
2013-01-30 05:51:15 -05:00
# else /* _WIN32 */
2012-05-21 06:53:38 -04:00
SetConsoleCtrlHandler ( & Application : : CtrlHandler , TRUE ) ;
2012-04-06 02:56:52 -04:00
# endif /* _WIN32 */
2019-07-15 10:08:08 -04:00
# ifdef _WIN32
2014-06-05 11:44:41 -04:00
try {
2018-08-09 09:37:23 -04:00
UpdatePidFile ( Configuration : : PidPath ) ;
2014-08-25 02:35:35 -04:00
} catch ( const std : : exception & ) {
2014-10-19 11:52:17 -04:00
Log ( LogCritical , " Application " )
2018-08-09 09:37:23 -04:00
< < " Cannot update PID file ' " < < Configuration : : PidPath < < " '. Aborting. " ;
2015-03-02 06:41:02 -05:00
return EXIT_FAILURE ;
2014-06-05 11:44:41 -04:00
}
2019-07-15 10:08:08 -04:00
# endif /* _WIN32 */
2013-09-10 10:03:36 -04:00
2016-05-11 06:50:08 -04:00
SetMainTime ( Utility : : GetTime ( ) ) ;
2015-03-02 06:41:02 -05:00
return Main ( ) ;
2012-04-16 10:27:41 -04:00
}
2012-07-12 11:03:34 -04:00
2018-01-04 12:24:45 -05:00
void Application : : UpdatePidFile ( const String & filename )
{
UpdatePidFile ( filename , Utility : : GetPid ( ) ) ;
}
2012-09-14 08:41:17 -04:00
/**
2012-09-27 03:58:16 -04:00
* Grabs the PID file lock and updates the PID . Terminates the application
* if the PID file is already locked by another instance of the application .
2012-09-14 08:41:17 -04:00
*
* @ param filename The name of the PID file .
2014-05-17 17:07:10 -04:00
* @ param pid The PID to write ; default is the current PID
2012-09-14 08:41:17 -04:00
*/
2014-05-17 17:07:10 -04:00
void Application : : UpdatePidFile ( const String & filename , pid_t pid )
2012-07-12 11:03:34 -04:00
{
2013-03-02 03:07:47 -05:00
ObjectLock olock ( this ) ;
2017-12-14 09:37:20 -05:00
if ( m_PidFile )
2013-03-04 09:52:42 -05:00
fclose ( m_PidFile ) ;
2012-07-12 11:03:34 -04:00
/* There's just no sane way of getting a file descriptor for a
* C + + ofstream which is why we ' re using FILEs here . */
2013-03-12 11:02:35 -04:00
m_PidFile = fopen ( filename . CStr ( ) , " r+ " ) ;
2017-12-14 09:37:20 -05:00
if ( ! m_PidFile )
2013-03-12 11:02:35 -04:00
m_PidFile = fopen ( filename . CStr ( ) , " w " ) ;
2012-07-12 11:03:34 -04:00
2017-12-14 09:37:20 -05:00
if ( ! m_PidFile ) {
2014-10-19 11:52:17 -04:00
Log ( LogCritical , " Application " )
2017-12-19 09:50:05 -05:00
< < " Could not open PID file ' " < < filename < < " '. " ;
2013-03-16 16:18:53 -04:00
BOOST_THROW_EXCEPTION ( std : : runtime_error ( " Could not open PID file ' " + filename + " ' " ) ) ;
2014-06-05 11:44:41 -04:00
}
2012-07-12 11:03:34 -04:00
2013-02-13 06:47:51 -05:00
# ifndef _WIN32
2013-03-02 03:07:47 -05:00
int fd = fileno ( m_PidFile ) ;
Utility : : SetCloExec ( fd ) ;
2013-11-23 18:27:10 -05:00
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_SETLK , & lock ) < 0 ) {
2014-05-28 07:17:02 -04:00
Log ( LogCritical , " Application " , " Could not lock PID file. Make sure that only one instance of the application is running. " ) ;
2013-03-02 03:07:47 -05:00
2014-08-04 10:43:34 -04:00
Application : : Exit ( EXIT_FAILURE ) ;
2013-03-02 03:07:47 -05:00
}
2013-03-12 09:06:59 -04:00
2013-08-28 04:48:19 -04:00
if ( ftruncate ( fd , 0 ) < 0 ) {
2014-10-19 11:52:17 -04:00
Log ( LogCritical , " Application " )
2017-12-19 09:50:05 -05:00
< < " ftruncate() failed with error code " < < errno < < " , \" " < < Utility : : FormatErrorNumber ( errno ) < < " \" " ;
2014-06-05 11:44:41 -04:00
2013-08-28 04:48:19 -04:00
BOOST_THROW_EXCEPTION ( posix_error ( )
2017-12-19 09:50:05 -05:00
< < boost : : errinfo_api_function ( " ftruncate " )
< < boost : : errinfo_errno ( errno ) ) ;
2013-08-28 04:48:19 -04:00
}
2012-07-13 09:29:39 -04:00
# endif /* _WIN32 */
2012-07-12 11:03:34 -04:00
2015-03-02 06:40:02 -05:00
fprintf ( m_PidFile , " %lu \n " , ( unsigned long ) pid ) ;
2012-07-12 11:03:34 -04:00
fflush ( m_PidFile ) ;
}
2012-09-14 08:41:17 -04:00
/**
* Closes the PID file . Does nothing if the PID file is not currently open .
*/
2014-05-18 10:23:16 -04:00
void Application : : ClosePidFile ( bool unlink )
2012-07-12 11:03:34 -04:00
{
2013-03-02 03:07:47 -05:00
ObjectLock olock ( this ) ;
2017-12-14 09:37:20 -05:00
if ( m_PidFile ) {
2014-05-18 10:23:16 -04:00
if ( unlink ) {
2018-08-09 09:37:23 -04:00
String pidpath = Configuration : : PidPath ;
2014-05-18 10:23:16 -04:00
: : unlink ( pidpath . CStr ( ) ) ;
}
2012-07-12 11:03:34 -04:00
fclose ( m_PidFile ) ;
2014-05-18 10:23:16 -04:00
}
2012-07-12 11:03:34 -04:00
2017-12-14 09:37:20 -05:00
m_PidFile = nullptr ;
2012-07-12 11:03:34 -04:00
}
2014-04-13 18:16:48 -04:00
/**
* Checks if another process currently owns the pidfile and read it
*
* @ param filename The name of the PID file .
2014-05-01 12:42:36 -04:00
* @ returns 0 : no process owning the pidfile , pid of the process otherwise
2014-04-13 18:16:48 -04:00
*/
pid_t Application : : ReadPidFile ( const String & filename )
{
FILE * pidfile = fopen ( filename . CStr ( ) , " r " ) ;
2017-12-14 09:37:20 -05:00
if ( ! pidfile )
2014-05-01 12:42:36 -04:00
return 0 ;
2014-04-13 18:16:48 -04:00
# 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 ( )
2017-12-19 09:50:05 -05:00
< < boost : : errinfo_api_function ( " fcntl " )
< < boost : : errinfo_errno ( error ) ) ;
2014-04-13 18:16:48 -04:00
}
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 )
2014-05-01 12:42:36 -04:00
return 0 ;
2014-04-13 18:16:48 -04:00
# ifdef _WIN32
2014-05-01 12:42:36 -04:00
HANDLE hProcess = OpenProcess ( 0 , FALSE , runningpid ) ;
if ( ! hProcess )
return 0 ;
CloseHandle ( hProcess ) ;
2014-04-13 18:16:48 -04:00
# endif /* _WIN32 */
return runningpid ;
}
2018-01-03 22:25:35 -05:00
int Application : : GetDefaultRLimitFiles ( )
2017-06-21 05:36:14 -04:00
{
return 16 * 1024 ;
}
2018-01-03 22:25:35 -05:00
int Application : : GetDefaultRLimitProcesses ( )
2017-06-21 05:36:14 -04:00
{
return 16 * 1024 ;
}
2018-01-03 22:25:35 -05:00
int Application : : GetDefaultRLimitStack ( )
2017-06-21 05:36:14 -04:00
{
return 256 * 1024 ;
}
2019-04-15 10:56:30 -04:00
double Application : : GetReloadTimeout ( )
2018-01-16 06:58:45 -05:00
{
2019-04-15 10:56:30 -04:00
return ScriptGlobal : : Get ( " ReloadTimeout " ) ;
2018-01-16 06:58:45 -05:00
}
2013-02-15 00:47:26 -05:00
/**
2013-03-25 13:36:15 -04:00
* Returns the global thread pool .
2013-02-15 00:47:26 -05:00
*
2013-03-25 13:36:15 -04:00
* @ returns The global thread pool .
2013-02-15 00:47:26 -05:00
*/
2018-01-03 22:25:35 -05:00
ThreadPool & Application : : GetTP ( )
2013-02-15 00:47:26 -05:00
{
2013-03-25 13:36:15 -04:00
static ThreadPool tp ;
return tp ;
2013-02-15 00:47:26 -05:00
}
2013-10-09 02:46:10 -04:00
2018-01-03 22:25:35 -05:00
double Application : : GetStartTime ( )
2013-10-26 03:41:45 -04:00
{
return m_StartTime ;
}
void Application : : SetStartTime ( double ts )
{
m_StartTime = ts ;
}
2015-09-22 12:18:29 -04:00
2018-01-03 22:25:35 -05:00
double Application : : GetMainTime ( )
2016-05-11 06:50:08 -04:00
{
return m_MainTime ;
}
void Application : : SetMainTime ( double ts )
{
m_MainTime = ts ;
}
2020-01-31 10:49:49 -05:00
double Application : : GetUptime ( )
{
return Utility : : GetTime ( ) - m_StartTime ;
}
2018-01-03 22:25:35 -05:00
bool Application : : GetScriptDebuggerEnabled ( )
2015-11-05 08:29:45 -05:00
{
return m_ScriptDebuggerEnabled ;
}
void Application : : SetScriptDebuggerEnabled ( bool enabled )
{
m_ScriptDebuggerEnabled = enabled ;
}
2018-01-03 22:25:35 -05:00
double Application : : GetLastReloadFailed ( )
2016-05-11 10:07:28 -04:00
{
return m_LastReloadFailed ;
}
void Application : : SetLastReloadFailed ( double ts )
{
m_LastReloadFailed = ts ;
}
2018-01-11 01:08:09 -05:00
void Application : : ValidateName ( const Lazy < String > & lvalue , const ValidationUtils & utils )
2015-09-22 12:18:29 -04:00
{
2018-01-11 01:08:09 -05:00
ObjectImpl < Application > : : ValidateName ( lvalue , utils ) ;
2015-09-22 12:18:29 -04:00
2018-01-11 01:08:09 -05:00
if ( lvalue ( ) ! = " app " )
2017-11-30 12:09:38 -05:00
BOOST_THROW_EXCEPTION ( ValidationError ( this , { " name " } , " Application object must be named 'app'. " ) ) ;
2015-09-22 12:18:29 -04:00
}