diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index fa79a8dc1..dedfb1587 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -24,7 +24,7 @@ mkclass_target(sysloglogger.ti sysloglogger.thpp) set(base_SOURCES application.cpp application.thpp array.cpp context.cpp - convert.cpp dictionary.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp + convert.cpp debuginfo.cpp dictionary.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp exception.cpp fifo.cpp filelogger.cpp filelogger.thpp logger.cpp logger.thpp netstring.cpp networkstream.cpp object.cpp objectlock.cpp process.cpp qstring.cpp ringbuffer.cpp scriptfunction.cpp scriptfunctionwrapper.cpp diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 0264f7324..8d5365bc7 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -50,6 +50,7 @@ bool Application::m_RequestRestart = false; bool Application::m_RequestReopenLogs = false; pid_t Application::m_ReloadProcess = 0; static bool l_Restarting = false; +static bool l_InExceptionHandler = false; int Application::m_ArgC; char **Application::m_ArgV; double Application::m_StartTime; @@ -578,6 +579,12 @@ BOOL WINAPI Application::CtrlHandler(DWORD type) */ void Application::ExceptionHandler(void) { + if (l_InExceptionHandler) + for (;;) + Utility::Sleep(5); + + l_InExceptionHandler = true; + #ifndef _WIN32 struct sigaction sa; memset(&sa, 0, sizeof(sa)); @@ -607,6 +614,11 @@ void Application::ExceptionHandler(void) #ifdef _WIN32 LONG CALLBACK Application::SEHUnhandledExceptionFilter(PEXCEPTION_POINTERS exi) { + if (l_InExceptionHandler) + return EXCEPTION_CONTINUE_SEARCH; + + l_InExceptionHandler = true; + DisplayInfoMessage(); std::cerr << "Caught unhandled SEH exception." << std::endl diff --git a/lib/config/debuginfo.cpp b/lib/base/debuginfo.cpp similarity index 93% rename from lib/config/debuginfo.cpp rename to lib/base/debuginfo.cpp index 1fbbe8ba7..3b4cec312 100644 --- a/lib/config/debuginfo.cpp +++ b/lib/base/debuginfo.cpp @@ -17,7 +17,7 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -#include "config/debuginfo.hpp" +#include "base/debuginfo.hpp" #include "base/convert.hpp" #include @@ -107,3 +107,12 @@ void icinga::ShowCodeFragment(std::ostream& out, const DebugInfo& di, bool verbo } } } + +std::string icinga::to_string(const errinfo_debuginfo& e) +{ + std::ostringstream msgbuf; + msgbuf << "Config location: " << e.value() << "\n"; + ShowCodeFragment(msgbuf, e.value(), true); + return msgbuf.str(); +} + diff --git a/lib/config/debuginfo.hpp b/lib/base/debuginfo.hpp similarity index 79% rename from lib/config/debuginfo.hpp rename to lib/base/debuginfo.hpp index 84c97e74d..9162fb968 100644 --- a/lib/config/debuginfo.hpp +++ b/lib/base/debuginfo.hpp @@ -20,8 +20,9 @@ #ifndef DEBUGINFO_H #define DEBUGINFO_H -#include "config/i2-config.hpp" +#include "base/i2-base.hpp" #include "base/qstring.hpp" +#include "base/exception.hpp" namespace icinga { @@ -60,11 +61,16 @@ struct DebugInfo }; }; -I2_CONFIG_API std::ostream& operator<<(std::ostream& out, const DebugInfo& val); +I2_BASE_API std::ostream& operator<<(std::ostream& out, const DebugInfo& val); -I2_CONFIG_API DebugInfo DebugInfoRange(const DebugInfo& start, const DebugInfo& end); +I2_BASE_API DebugInfo DebugInfoRange(const DebugInfo& start, const DebugInfo& end); -I2_CONFIG_API void ShowCodeFragment(std::ostream& out, const DebugInfo& di, bool verbose); +I2_BASE_API void ShowCodeFragment(std::ostream& out, const DebugInfo& di, bool verbose); + +struct errinfo_debuginfo_; +typedef boost::error_info errinfo_debuginfo; + +std::string to_string(const errinfo_debuginfo& e); } diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index c56e0c5a4..0d6ac6629 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -54,6 +54,16 @@ DynamicType::Ptr DynamicObject::GetType(void) const return DynamicType::GetByName(GetTypeName()); } +DebugInfo DynamicObject::GetDebugInfo(void) const +{ + return m_DebugInfo; +} + +void DynamicObject::SetDebugInfo(const DebugInfo& di) +{ + m_DebugInfo = di; +} + bool DynamicObject::IsActive(void) const { return GetActive(); diff --git a/lib/base/dynamicobject.hpp b/lib/base/dynamicobject.hpp index fabf34b9b..1b64b0d2c 100644 --- a/lib/base/dynamicobject.hpp +++ b/lib/base/dynamicobject.hpp @@ -25,6 +25,7 @@ #include "base/object.hpp" #include "base/serializer.hpp" #include "base/dictionary.hpp" +#include "base/debuginfo.hpp" #include #include @@ -53,6 +54,9 @@ public: shared_ptr GetType(void) const; + DebugInfo GetDebugInfo(void) const; + void SetDebugInfo(const DebugInfo& di); + bool IsActive(void) const; bool IsPaused(void) const; @@ -93,6 +97,8 @@ protected: private: static DynamicObject::Ptr GetObject(const String& type, const String& name); static void RestoreObject(const String& message, int attributeTypes); + + DebugInfo m_DebugInfo; }; #define DECLARE_TYPENAME(klass) \ diff --git a/lib/base/dynamictype.cpp b/lib/base/dynamictype.cpp index 219dfcc18..57a09639a 100644 --- a/lib/base/dynamictype.cpp +++ b/lib/base/dynamictype.cpp @@ -21,6 +21,7 @@ #include "base/serializer.hpp" #include "base/debug.hpp" #include "base/objectlock.hpp" +#include "base/convert.hpp" using namespace icinga; @@ -99,7 +100,9 @@ void DynamicType::RegisterObject(const DynamicObject::Ptr& object) if (it->second == object) return; - BOOST_THROW_EXCEPTION(std::runtime_error("RegisterObject() found existing object with the same name: " + name)); + BOOST_THROW_EXCEPTION(user_error("An object with type '" + m_Name + "' and name '" + name + "' already exists (" + + Convert::ToString(it->second->GetDebugInfo()) + "), new declaration: " + Convert::ToString(object->GetDebugInfo())) + << errinfo_debuginfo(object->GetDebugInfo())); } m_ObjectMap[name] = object; diff --git a/lib/base/exception.cpp b/lib/base/exception.cpp index a2a9c6a9b..f809dbe3d 100644 --- a/lib/base/exception.cpp +++ b/lib/base/exception.cpp @@ -153,3 +153,18 @@ String icinga::DiagnosticInformation(boost::exception_ptr eptr) return boost::diagnostic_information(eptr); } +user_error::user_error(void) +{ } + +user_error::user_error(const String& message) + : m_Message(message) +{ } + +user_error::~user_error(void) throw() +{ } + +const char *user_error::what(void) const throw() +{ + return m_Message.CStr(); +} + diff --git a/lib/base/exception.hpp b/lib/base/exception.hpp index dbbb1906c..c47ce34d7 100644 --- a/lib/base/exception.hpp +++ b/lib/base/exception.hpp @@ -38,7 +38,17 @@ namespace icinga { -class I2_BASE_API user_error : virtual public std::exception, virtual public boost::exception { }; +class I2_BASE_API user_error : virtual public std::exception, virtual public boost::exception { +public: + user_error(void); + user_error(const String& message); + ~user_error(void) throw(); + + const char *what(void) const throw(); + +private: + String m_Message; +}; I2_BASE_API StackTrace *GetLastExceptionStack(void); I2_BASE_API void SetLastExceptionStack(const StackTrace& trace); diff --git a/lib/config/CMakeLists.txt b/lib/config/CMakeLists.txt index a44254061..db582cbe3 100644 --- a/lib/config/CMakeLists.txt +++ b/lib/config/CMakeLists.txt @@ -34,7 +34,7 @@ set(config_SOURCES aexpression.cpp applyrule.cpp base-type.conf base-type.cpp configcompilercontext.cpp configcompiler.cpp configerror.cpp configitembuilder.cpp configitem.cpp ${FLEX_config_lexer_OUTPUTS} ${BISON_config_parser_OUTPUTS} - configtype.cpp debuginfo.cpp objectrule.cpp typerule.cpp typerulelist.cpp + configtype.cpp objectrule.cpp typerule.cpp typerulelist.cpp ) if(ICINGA2_UNITY_BUILD) diff --git a/lib/config/aexpression.hpp b/lib/config/aexpression.hpp index 8a416c4a7..0e2f97c22 100644 --- a/lib/config/aexpression.hpp +++ b/lib/config/aexpression.hpp @@ -21,7 +21,7 @@ #define AEXPRESSION_H #include "config/i2-config.hpp" -#include "config/debuginfo.hpp" +#include "base/debuginfo.hpp" #include "base/array.hpp" #include "base/dictionary.hpp" diff --git a/lib/config/applyrule.hpp b/lib/config/applyrule.hpp index b6fc6088c..147298c9f 100644 --- a/lib/config/applyrule.hpp +++ b/lib/config/applyrule.hpp @@ -22,7 +22,7 @@ #include "config/i2-config.hpp" #include "config/aexpression.hpp" -#include "config/debuginfo.hpp" +#include "base/debuginfo.hpp" #include namespace icinga diff --git a/lib/config/configcompiler.hpp b/lib/config/configcompiler.hpp index 69557b797..3d1968bdb 100644 --- a/lib/config/configcompiler.hpp +++ b/lib/config/configcompiler.hpp @@ -21,7 +21,7 @@ #define CONFIGCOMPILER_H #include "config/i2-config.hpp" -#include "config/debuginfo.hpp" +#include "base/debuginfo.hpp" #include "base/registry.hpp" #include "base/initialize.hpp" #include "base/singleton.hpp" diff --git a/lib/config/configcompilercontext.hpp b/lib/config/configcompilercontext.hpp index 22f611287..2a3401e0c 100644 --- a/lib/config/configcompilercontext.hpp +++ b/lib/config/configcompilercontext.hpp @@ -21,7 +21,7 @@ #define CONFIGCOMPILERCONTEXT_H #include "config/i2-config.hpp" -#include "config/debuginfo.hpp" +#include "base/debuginfo.hpp" #include #include diff --git a/lib/config/configerror.cpp b/lib/config/configerror.cpp index 845f359b6..453cae65e 100644 --- a/lib/config/configerror.cpp +++ b/lib/config/configerror.cpp @@ -23,21 +23,6 @@ using namespace icinga; ConfigError::ConfigError(const String& message) - : m_Message(message) + : user_error(message) { } -ConfigError::~ConfigError(void) throw() -{ } - -const char *ConfigError::what(void) const throw() -{ - return m_Message.CStr(); -} - -std::string icinga::to_string(const errinfo_debuginfo& e) -{ - std::ostringstream msgbuf; - msgbuf << "Config location: " << e.value() << "\n"; - ShowCodeFragment(msgbuf, e.value(), true); - return msgbuf.str(); -} diff --git a/lib/config/configerror.hpp b/lib/config/configerror.hpp index dc085c00d..f389b9b11 100644 --- a/lib/config/configerror.hpp +++ b/lib/config/configerror.hpp @@ -21,7 +21,7 @@ #define CONFIGERROR_H #include "config/i2-config.hpp" -#include "config/debuginfo.hpp" +#include "base/debuginfo.hpp" #include "base/exception.hpp" namespace icinga @@ -34,19 +34,8 @@ class I2_CONFIG_API ConfigError : virtual public user_error { public: ConfigError(const String& message); - ~ConfigError(void) throw(); - - const char *what(void) const throw(); - -private: - String m_Message; }; -struct errinfo_debuginfo_; -typedef boost::error_info errinfo_debuginfo; - -std::string to_string(const errinfo_debuginfo& e); - } #endif /* CONFIGERROR_H */ diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index 61bc1cb0a..6de092d48 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -22,6 +22,7 @@ #include "config/applyrule.hpp" #include "config/objectrule.hpp" #include "config/configtype.hpp" +#include "config/configerror.hpp" #include "base/application.hpp" #include "base/dynamictype.hpp" #include "base/objectlock.hpp" @@ -180,9 +181,6 @@ DynamicObject::Ptr ConfigItem::Commit(void) if (!dtype) BOOST_THROW_EXCEPTION(std::runtime_error("Type '" + GetType() + "' does not exist.")); - if (dtype->GetObject(GetName())) - BOOST_THROW_EXCEPTION(std::runtime_error("An object with type '" + GetType() + "' and name '" + GetName() + "' already exists.")); - if (IsAbstract()) return DynamicObject::Ptr(); @@ -195,6 +193,7 @@ DynamicObject::Ptr ConfigItem::Commit(void) } DynamicObject::Ptr dobj = dtype->CreateObject(properties); + dobj->SetDebugInfo(m_DebugInfo); dobj->Register(); m_Object = dobj; diff --git a/lib/config/configitembuilder.hpp b/lib/config/configitembuilder.hpp index 9c9a2a842..f53fb7b7c 100644 --- a/lib/config/configitembuilder.hpp +++ b/lib/config/configitembuilder.hpp @@ -20,9 +20,9 @@ #ifndef CONFIGITEMBUILDER_H #define CONFIGITEMBUILDER_H -#include "config/debuginfo.hpp" #include "config/aexpression.hpp" #include "config/configitem.hpp" +#include "base/debuginfo.hpp" #include "base/object.hpp" namespace icinga diff --git a/lib/config/objectrule.hpp b/lib/config/objectrule.hpp index 6098fb60a..f3ed2505c 100644 --- a/lib/config/objectrule.hpp +++ b/lib/config/objectrule.hpp @@ -22,7 +22,7 @@ #include "config/i2-config.hpp" #include "config/aexpression.hpp" -#include "config/debuginfo.hpp" +#include "base/debuginfo.hpp" #include "base/dynamictype.hpp" namespace icinga diff --git a/lib/config/typerule.hpp b/lib/config/typerule.hpp index 8a1ab737e..2e6ece95a 100644 --- a/lib/config/typerule.hpp +++ b/lib/config/typerule.hpp @@ -22,7 +22,7 @@ #include "config/i2-config.hpp" #include "config/typerulelist.hpp" -#include "config/debuginfo.hpp" +#include "base/debuginfo.hpp" namespace icinga {