From 327d12295cc446cd0b3078a1433c5f460f541382 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Fri, 1 Apr 2016 08:25:36 +0200 Subject: [PATCH] Implement support for upgrading NSIS-based installations refs #11449 --- etc/CMakeLists.txt | 5 +- icinga-app/icinga.cpp | 17 +++--- icinga-installer/icinga-installer.cpp | 85 ++++++++++++++++++++------- lib/base/utility.cpp | 9 +++ lib/base/utility.hpp | 1 + lib/checker/CMakeLists.txt | 5 +- lib/notification/CMakeLists.txt | 5 +- 7 files changed, 87 insertions(+), 40 deletions(-) diff --git a/etc/CMakeLists.txt b/etc/CMakeLists.txt index a95f90a51..4dc5eec7d 100644 --- a/etc/CMakeLists.txt +++ b/etc/CMakeLists.txt @@ -82,10 +82,7 @@ if(NOT WIN32) DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/bash_completion.d ) else() - install( - FILES icinga2/features-enabled/mainlog.conf - DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-enabled - ) + install_if_not_exists(icinga2/features-enabled/mainlog.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-enabled) endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index 2f465bd0b..75ef69578 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -125,15 +125,16 @@ int Main(void) #ifdef _WIN32 bool builtinPaths = true; - String prefix = Utility::GetIcingaInstallPath(); + String binaryPrefix = Utility::GetIcingaInstallPath(); + String dataPrefix = Utility::GetIcingaDataPath(); - if (!prefix.IsEmpty()) { - Application::DeclarePrefixDir(prefix); - Application::DeclareSysconfDir(prefix + "\\etc"); - Application::DeclareRunDir(prefix + "\\var\\run"); - Application::DeclareLocalStateDir(prefix + "\\var"); - Application::DeclarePkgDataDir(prefix + "\\share\\icinga2"); - Application::DeclareIncludeConfDir(prefix + "\\share\\icinga2\\include"); + if (!binaryPrefix.IsEmpty() && !dataPrefix.IsEmpty()) { + Application::DeclarePrefixDir(binaryPrefix); + Application::DeclareSysconfDir(dataPrefix + "\\etc"); + Application::DeclareRunDir(dataPrefix + "\\var\\run"); + Application::DeclareLocalStateDir(dataPrefix + "\\var"); + Application::DeclarePkgDataDir(binaryPrefix + "\\share\\icinga2"); + Application::DeclareIncludeConfDir(binaryPrefix + "\\share\\icinga2\\include"); } else { Log(LogWarning, "icinga-app", "Registry key could not be read. Falling back to built-in paths."); diff --git a/icinga-installer/icinga-installer.cpp b/icinga-installer/icinga-installer.cpp index 764f47b53..a91c8b3ff 100644 --- a/icinga-installer/icinga-installer.cpp +++ b/icinga-installer/icinga-installer.cpp @@ -23,7 +23,7 @@ using namespace icinga; -static String GetIcingaInstallDir(void) +static String GetIcingaInstallPath(void) { char szFileName[MAX_PATH]; if (!GetModuleFileName(NULL, szFileName, sizeof(szFileName))) @@ -59,12 +59,12 @@ static bool ExecuteCommand(const String& app, const String& arguments) static bool ExecuteIcingaCommand(const String& arguments) { - return ExecuteCommand(GetIcingaInstallDir() + "\\sbin\\icinga2.exe", arguments); + return ExecuteCommand(GetIcingaInstallPath() + "\\sbin\\icinga2.exe", arguments); } static void CopyConfigFile(const String& installDir, const String& sourceConfigPath, size_t skelPrefixLength) { - String relativeConfigPath = sourceConfigPath.SubStr(installDir.GetLength() + skelPrefixLength); + String relativeConfigPath = sourceConfigPath.SubStr(skelPrefixLength); String targetConfigPath = installDir + relativeConfigPath; @@ -74,29 +74,74 @@ static void CopyConfigFile(const String& installDir, const String& sourceConfigP } } +static String GetNSISInstallPath(void) +{ + HKEY hKey; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Icinga Development Team\\ICINGA2", 0, + KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS) { + BYTE pvData[MAX_PATH]; + DWORD cbData = sizeof(pvData) - 1; + DWORD lType; + if (RegQueryValueEx(hKey, NULL, NULL, &lType, pvData, &cbData) == ERROR_SUCCESS && lType == REG_SZ) { + pvData[cbData] = '\0'; + + return (char *)pvData; + } + + RegCloseKey(hKey); + } + + return ""; +} + +static int UpgradeNSIS(void) +{ + String installPath = GetNSISInstallPath(); + + if (installPath.IsEmpty()) + return 0; + + if (!Utility::PathExists(installPath + "\\uninstall.exe")) + return 0; + + ExecuteCommand(installPath + "\\uninstall.exe", "/S"); + + String dataPath = Utility::GetIcingaDataPath(); + + if (!Utility::PathExists(dataPath)) + CreateSymbolicLink(dataPath.CStr(), installPath.CStr(), SYMBOLIC_LINK_FLAG_DIRECTORY); + + return 0; +} + static int InstallIcinga(void) { - String installDir = GetIcingaInstallDir(); + UpgradeNSIS(); - ExecuteCommand("icacls", "\"" + installDir + "\" /grant *S-1-5-20:(oi)(ci)m"); - ExecuteCommand("icacls", "\"" + installDir + "\\etc\" /inheritance:r /grant:r *S-1-5-20:(oi)(ci)m *S-1-5-32-544:(oi)(ci)f"); + String installDir = GetIcingaInstallPath(); + String dataDir = Utility::GetIcingaDataPath(); - Utility::MkDirP(installDir + "/etc/icinga2/pki", 0700); - Utility::MkDirP(installDir + "/var/cache/icinga2", 0700); - Utility::MkDirP(installDir + "/var/lib/icinga2/pki", 0700); - Utility::MkDirP(installDir + "/var/lib/icinga2/agent/inventory", 0700); - Utility::MkDirP(installDir + "/var/lib/icinga2/api/config", 0700); - Utility::MkDirP(installDir + "/var/lib/icinga2/api/log", 0700); - Utility::MkDirP(installDir + "/var/lib/icinga2/api/zones", 0700); - Utility::MkDirP(installDir + "/var/lib/icinga2/api/zones", 0700); - Utility::MkDirP(installDir + "/var/log/icinga2/compat/archive", 0700); - Utility::MkDirP(installDir + "/var/log/icinga2/crash", 0700); - Utility::MkDirP(installDir + "/var/run/icinga2/cmd", 0700); - Utility::MkDirP(installDir + "/var/spool/icinga2/perfdata", 0700); - Utility::MkDirP(installDir + "/var/spool/icinga2/tmp", 0700); + Utility::MkDirP(dataDir, 0700); + + ExecuteCommand("icacls", "\"" + dataDir + "\" /grant *S-1-5-20:(oi)(ci)m"); + ExecuteCommand("icacls", "\"" + dataDir + "\\etc\" /inheritance:r /grant:r *S-1-5-20:(oi)(ci)m *S-1-5-32-544:(oi)(ci)f"); + + Utility::MkDirP(dataDir + "/etc/icinga2/pki", 0700); + Utility::MkDirP(dataDir + "/var/cache/icinga2", 0700); + Utility::MkDirP(dataDir + "/var/lib/icinga2/pki", 0700); + Utility::MkDirP(dataDir + "/var/lib/icinga2/agent/inventory", 0700); + Utility::MkDirP(dataDir + "/var/lib/icinga2/api/config", 0700); + Utility::MkDirP(dataDir + "/var/lib/icinga2/api/log", 0700); + Utility::MkDirP(dataDir + "/var/lib/icinga2/api/zones", 0700); + Utility::MkDirP(dataDir + "/var/lib/icinga2/api/zones", 0700); + Utility::MkDirP(dataDir + "/var/log/icinga2/compat/archive", 0700); + Utility::MkDirP(dataDir + "/var/log/icinga2/crash", 0700); + Utility::MkDirP(dataDir + "/var/run/icinga2/cmd", 0700); + Utility::MkDirP(dataDir + "/var/spool/icinga2/perfdata", 0700); + Utility::MkDirP(dataDir + "/var/spool/icinga2/tmp", 0700); String skelDir = "/share/skel"; - Utility::GlobRecursive(installDir + skelDir, "*", boost::bind(&CopyConfigFile, installDir, _1, skelDir.GetLength()), GlobFile); + Utility::GlobRecursive(installDir + skelDir, "*", boost::bind(&CopyConfigFile, dataDir, _1, installDir.GetLength() + skelDir.GetLength()), GlobFile); ExecuteIcingaCommand("--scm-install daemon"); diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index 8d6466839..0b09516b7 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -56,6 +56,7 @@ # include # include # include +# include #endif /*_WIN32*/ using namespace icinga; @@ -1883,4 +1884,12 @@ String Utility::GetIcingaInstallPath(void) return ""; } +String Utility::GetIcingaDataPath(void) +{ + char path[MAX_PATH]; + if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, path))) + return ""; + return String(path) + "\\icinga2"; +} + #endif /* _WIN32 */ \ No newline at end of file diff --git a/lib/base/utility.hpp b/lib/base/utility.hpp index 9af1b8f8a..c1c50cc53 100644 --- a/lib/base/utility.hpp +++ b/lib/base/utility.hpp @@ -145,6 +145,7 @@ public: #ifdef _WIN32 static String GetIcingaInstallPath(void); + static String GetIcingaDataPath(void); #endif /* _WIN32 */ private: diff --git a/lib/checker/CMakeLists.txt b/lib/checker/CMakeLists.txt index 8777e0640..cdbf1a9a5 100644 --- a/lib/checker/CMakeLists.txt +++ b/lib/checker/CMakeLists.txt @@ -45,10 +45,7 @@ if(NOT WIN32) install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled\")") install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink ../features-available/checker.conf \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled/checker.conf\")") else() - install( - FILES ${PROJECT_SOURCE_DIR}/etc/icinga2/features-enabled/checker.conf - DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-enabled - ) + install_if_not_exists(${PROJECT_SOURCE_DIR}/etc/icinga2/features-enabled/checker.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-enabled) endif() install( diff --git a/lib/notification/CMakeLists.txt b/lib/notification/CMakeLists.txt index f05180149..22ebb482b 100644 --- a/lib/notification/CMakeLists.txt +++ b/lib/notification/CMakeLists.txt @@ -45,10 +45,7 @@ if(NOT WIN32) install(CODE "file(MAKE_DIRECTORY \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled\")") install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink ../features-available/notification.conf \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_SYSCONFDIR}/icinga2/features-enabled/notification.conf\")") else() - install( - FILES ${PROJECT_SOURCE_DIR}/etc/icinga2/features-enabled/notification.conf - DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-enabled - ) + install_if_not_exists(${PROJECT_SOURCE_DIR}/etc/icinga2/features-enabled/notification.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-enabled) endif() install(TARGETS notification RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/icinga2)