From 6e2e90cc625ef8f15753764db786f2a25c417483 Mon Sep 17 00:00:00 2001
From: Gunnar Beutner <gunnar.beutner@netways.de>
Date: Wed, 13 Apr 2016 13:43:38 +0200
Subject: [PATCH] Make sure the etc and var directories are in the common data
 directory

refs #11449
---
 .../ServiceStatus.Designer.cs                 | 168 ++++++++++--------
 agent/windows-setup-agent/ServiceStatus.cs    |   7 +-
 icinga-installer/icinga-installer.cpp         |  57 +++++-
 3 files changed, 150 insertions(+), 82 deletions(-)

diff --git a/agent/windows-setup-agent/ServiceStatus.Designer.cs b/agent/windows-setup-agent/ServiceStatus.Designer.cs
index 23973d500..874f29672 100644
--- a/agent/windows-setup-agent/ServiceStatus.Designer.cs
+++ b/agent/windows-setup-agent/ServiceStatus.Designer.cs
@@ -28,82 +28,95 @@
 		/// </summary>
 		private void InitializeComponent()
 		{
-			System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServiceStatus));
-			this.picBanner = new System.Windows.Forms.PictureBox();
-			this.lblStatus = new System.Windows.Forms.Label();
-			this.txtStatus = new System.Windows.Forms.TextBox();
-			this.btnReconfigure = new System.Windows.Forms.Button();
-			this.btnOK = new System.Windows.Forms.Button();
-			((System.ComponentModel.ISupportInitialize)(this.picBanner)).BeginInit();
-			this.SuspendLayout();
-			// 
-			// picBanner
-			// 
-			this.picBanner.Image = global::Icinga.Properties.Resources.icinga_banner;
-			this.picBanner.Location = new System.Drawing.Point(0, 0);
-			this.picBanner.Name = "picBanner";
-			this.picBanner.Size = new System.Drawing.Size(625, 77);
-			this.picBanner.TabIndex = 2;
-			this.picBanner.TabStop = false;
-			// 
-			// lblStatus
-			// 
-			this.lblStatus.AutoSize = true;
-			this.lblStatus.Location = new System.Drawing.Point(12, 105);
-			this.lblStatus.Name = "lblStatus";
-			this.lblStatus.Size = new System.Drawing.Size(79, 13);
-			this.lblStatus.TabIndex = 3;
-			this.lblStatus.Text = "Service Status:";
-			// 
-			// txtStatus
-			// 
-			this.txtStatus.Location = new System.Drawing.Point(97, 102);
-			this.txtStatus.Name = "txtStatus";
-			this.txtStatus.ReadOnly = true;
-			this.txtStatus.Size = new System.Drawing.Size(278, 20);
-			this.txtStatus.TabIndex = 2;
-			// 
-			// btnReconfigure
-			// 
-			this.btnReconfigure.Location = new System.Drawing.Point(219, 143);
-			this.btnReconfigure.Name = "btnReconfigure";
-			this.btnReconfigure.Size = new System.Drawing.Size(75, 23);
-			this.btnReconfigure.TabIndex = 1;
-			this.btnReconfigure.Text = "Reconfigure";
-			this.btnReconfigure.UseVisualStyleBackColor = true;
-			this.btnReconfigure.Click += new System.EventHandler(this.btnReconfigure_Click);
-			// 
-			// btnOK
-			// 
-			this.btnOK.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-			this.btnOK.Location = new System.Drawing.Point(300, 143);
-			this.btnOK.Name = "btnOK";
-			this.btnOK.Size = new System.Drawing.Size(75, 23);
-			this.btnOK.TabIndex = 0;
-			this.btnOK.Text = "OK";
-			this.btnOK.UseVisualStyleBackColor = true;
-			this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
-			// 
-			// ServiceStatus
-			// 
-			this.AcceptButton = this.btnOK;
-			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-			this.CancelButton = this.btnOK;
-			this.ClientSize = new System.Drawing.Size(391, 186);
-			this.Controls.Add(this.btnOK);
-			this.Controls.Add(this.btnReconfigure);
-			this.Controls.Add(this.txtStatus);
-			this.Controls.Add(this.lblStatus);
-			this.Controls.Add(this.picBanner);
-			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
-			this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
-			this.MaximizeBox = false;
-			this.Name = "ServiceStatus";
-			this.Text = "Icinga 2 Service Status";
-			((System.ComponentModel.ISupportInitialize)(this.picBanner)).EndInit();
-			this.ResumeLayout(false);
-			this.PerformLayout();
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServiceStatus));
+            this.picBanner = new System.Windows.Forms.PictureBox();
+            this.lblStatus = new System.Windows.Forms.Label();
+            this.txtStatus = new System.Windows.Forms.TextBox();
+            this.btnReconfigure = new System.Windows.Forms.Button();
+            this.btnOK = new System.Windows.Forms.Button();
+            this.btnOpenConfigDir = new System.Windows.Forms.Button();
+            ((System.ComponentModel.ISupportInitialize)(this.picBanner)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // picBanner
+            // 
+            this.picBanner.Image = global::Icinga.Properties.Resources.icinga_banner;
+            this.picBanner.Location = new System.Drawing.Point(0, 0);
+            this.picBanner.Name = "picBanner";
+            this.picBanner.Size = new System.Drawing.Size(625, 77);
+            this.picBanner.TabIndex = 2;
+            this.picBanner.TabStop = false;
+            // 
+            // lblStatus
+            // 
+            this.lblStatus.AutoSize = true;
+            this.lblStatus.Location = new System.Drawing.Point(12, 105);
+            this.lblStatus.Name = "lblStatus";
+            this.lblStatus.Size = new System.Drawing.Size(79, 13);
+            this.lblStatus.TabIndex = 3;
+            this.lblStatus.Text = "Service Status:";
+            // 
+            // txtStatus
+            // 
+            this.txtStatus.Location = new System.Drawing.Point(97, 102);
+            this.txtStatus.Name = "txtStatus";
+            this.txtStatus.ReadOnly = true;
+            this.txtStatus.Size = new System.Drawing.Size(278, 20);
+            this.txtStatus.TabIndex = 3;
+            // 
+            // btnReconfigure
+            // 
+            this.btnReconfigure.Location = new System.Drawing.Point(195, 143);
+            this.btnReconfigure.Name = "btnReconfigure";
+            this.btnReconfigure.Size = new System.Drawing.Size(89, 23);
+            this.btnReconfigure.TabIndex = 1;
+            this.btnReconfigure.Text = "Reconfigure";
+            this.btnReconfigure.UseVisualStyleBackColor = true;
+            this.btnReconfigure.Click += new System.EventHandler(this.btnReconfigure_Click);
+            // 
+            // btnOK
+            // 
+            this.btnOK.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnOK.Location = new System.Drawing.Point(290, 143);
+            this.btnOK.Name = "btnOK";
+            this.btnOK.Size = new System.Drawing.Size(89, 23);
+            this.btnOK.TabIndex = 0;
+            this.btnOK.Text = "OK";
+            this.btnOK.UseVisualStyleBackColor = true;
+            this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
+            // 
+            // btnOpenConfigDir
+            // 
+            this.btnOpenConfigDir.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.btnOpenConfigDir.Location = new System.Drawing.Point(100, 143);
+            this.btnOpenConfigDir.Name = "btnOpenConfigDir";
+            this.btnOpenConfigDir.Size = new System.Drawing.Size(89, 23);
+            this.btnOpenConfigDir.TabIndex = 2;
+            this.btnOpenConfigDir.Text = "Examine Config";
+            this.btnOpenConfigDir.UseVisualStyleBackColor = true;
+            this.btnOpenConfigDir.Click += new System.EventHandler(this.btnOpenConfigDir_Click);
+            // 
+            // ServiceStatus
+            // 
+            this.AcceptButton = this.btnOK;
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.CancelButton = this.btnOK;
+            this.ClientSize = new System.Drawing.Size(391, 186);
+            this.Controls.Add(this.btnOpenConfigDir);
+            this.Controls.Add(this.btnOK);
+            this.Controls.Add(this.btnReconfigure);
+            this.Controls.Add(this.txtStatus);
+            this.Controls.Add(this.lblStatus);
+            this.Controls.Add(this.picBanner);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+            this.MaximizeBox = false;
+            this.Name = "ServiceStatus";
+            this.Text = "Icinga 2 Service Status";
+            ((System.ComponentModel.ISupportInitialize)(this.picBanner)).EndInit();
+            this.ResumeLayout(false);
+            this.PerformLayout();
 
 		}
 
@@ -114,5 +127,6 @@
 		private System.Windows.Forms.TextBox txtStatus;
 		private System.Windows.Forms.Button btnReconfigure;
 		private System.Windows.Forms.Button btnOK;
-	}
+        private System.Windows.Forms.Button btnOpenConfigDir;
+    }
 }
\ No newline at end of file
diff --git a/agent/windows-setup-agent/ServiceStatus.cs b/agent/windows-setup-agent/ServiceStatus.cs
index 3f9ae1ada..cdceb99b8 100644
--- a/agent/windows-setup-agent/ServiceStatus.cs
+++ b/agent/windows-setup-agent/ServiceStatus.cs
@@ -6,6 +6,7 @@ using System.Drawing;
 using System.Text;
 using System.Windows.Forms;
 using System.ServiceProcess;
+using System.Diagnostics;
 
 namespace Icinga
 {
@@ -33,5 +34,9 @@ namespace Icinga
 		{
 			Close();
 		}
-	}
+
+        private void btnOpenConfigDir_Click(object sender, EventArgs e) {
+            Process.Start("explorer.exe", Program.Icinga2DataDir + "\\etc\\icinga2");
+        }
+    }
 }
diff --git a/icinga-installer/icinga-installer.cpp b/icinga-installer/icinga-installer.cpp
index a91c8b3ff..e5560a965 100644
--- a/icinga-installer/icinga-installer.cpp
+++ b/icinga-installer/icinga-installer.cpp
@@ -19,6 +19,7 @@
 
 #include "base/utility.hpp"
 #include "base/application.hpp"
+#include <boost/foreach.hpp>
 #include <shellapi.h>
 
 using namespace icinga;
@@ -48,7 +49,7 @@ static bool ExecuteCommand(const String& app, const String& arguments)
 	WaitForSingleObject(sei.hProcess, INFINITE);
 
 	DWORD exitCode;
-	bool res = GetExitCodeProcess(sei.hProcess, &exitCode);
+	BOOL res = GetExitCodeProcess(sei.hProcess, &exitCode);
 	CloseHandle(sei.hProcess);
 
 	if (!res)
@@ -94,6 +95,41 @@ static String GetNSISInstallPath(void)
 	return "";
 }
 
+static void CollectPaths(std::vector<String>& paths, const String& path)
+{
+	paths.push_back(path);
+}
+
+static bool MoveDirectory(const String& source, const String& destination)
+{
+	if (!MoveFileEx(source.CStr(), destination.CStr(), MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH)) {
+		// SHFileOperation requires file names to be terminated with two \0s
+		String tmpSource = source + String(1, '\0');
+		String tmpDestination = destination + String(1, '\0');
+
+		SHFILEOPSTRUCT fop;
+		fop.wFunc = FO_COPY;
+		fop.pFrom = tmpSource.CStr();
+		fop.pTo = tmpDestination.CStr();
+		fop.fFlags = FOF_NO_UI;
+		if (SHFileOperation(&fop) != 0)
+			return false;
+
+		std::vector<String> paths;
+		paths.push_back(source);
+		Utility::GlobRecursive(source, "*", boost::bind(&CollectPaths, boost::ref(paths), _1), GlobDirectory);
+		Utility::GlobRecursive(source, "*", boost::bind(&CollectPaths, boost::ref(paths), _1), GlobFile);
+
+		std::reverse(paths.begin(), paths.end());
+
+		BOOST_FOREACH(const String& path, paths) {
+			(void)MoveFileEx(path.CStr(), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
+		}
+	}
+
+	return true;
+}
+
 static int UpgradeNSIS(void)
 {
 	String installPath = GetNSISInstallPath();
@@ -108,15 +144,28 @@ static int UpgradeNSIS(void)
 
 	String dataPath = Utility::GetIcingaDataPath();
 
-	if (!Utility::PathExists(dataPath))
-		CreateSymbolicLink(dataPath.CStr(), installPath.CStr(), SYMBOLIC_LINK_FLAG_DIRECTORY);
+	/* perform open heart surgery on the user's data dirs - yay */
+	if (!Utility::PathExists(dataPath)) {
+		Utility::MkDirP(dataPath, 0700);
+
+		String oldNameEtc = installPath + "\\etc";
+		String newNameEtc = dataPath + "\\etc";
+		if (!MoveDirectory(oldNameEtc, newNameEtc))
+			return 1;
+
+		String oldNameVar = installPath + "\\var";
+		String newNameVar = dataPath + "\\var";
+		if (!MoveDirectory(oldNameVar, newNameVar))
+			return 1;
+	}	
 
 	return 0;
 }
 
 static int InstallIcinga(void)
 {
-	UpgradeNSIS();
+	if (UpgradeNSIS() != 0)
+		return 1;
 
 	String installDir = GetIcingaInstallPath();
 	String dataDir = Utility::GetIcingaDataPath();
-- 
2.40.0