From 9b1471afee485a96c32e393989ca4eb0aed52f88 Mon Sep 17 00:00:00 2001
From: Michael Banck <mbanck@debian.org>
Date: Thu, 14 Mar 2019 16:02:49 +0100
Subject: [PATCH] Rename away pg_control while enabling checksums.

In order to prevent that the cluster is accidently started during the
operation, the pg_control file is renamed to
pg_control.pg_checksums_in_progress during the operation and renamed back at
the end.
---
 doc/src/sgml/ref/pg_checksums.sgml  |  5 +++--
 src/bin/pg_checksums/pg_checksums.c | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/doc/src/sgml/ref/pg_checksums.sgml b/doc/src/sgml/ref/pg_checksums.sgml
index c3ccbf4eb7..91dfd3515a 100644
--- a/doc/src/sgml/ref/pg_checksums.sgml
+++ b/doc/src/sgml/ref/pg_checksums.sgml
@@ -48,8 +48,9 @@ PostgreSQL documentation
   <para>
    While checking or enabling checksums needs to scan or write every file in
    the cluster, disabling will only update the file
-   <filename>pg_control</filename>.
-  </para>
+   <filename>pg_control</filename>. During enabling,
+   the <filename>pg_control</filename> </para> file is renamed in order to
+   prevent accidentally starting the cluster.
  </refsect1>
 
  <refsect1>
diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
index 852ddafc94..590fb925e8 100644
--- a/src/bin/pg_checksums/pg_checksums.c
+++ b/src/bin/pg_checksums/pg_checksums.c
@@ -55,6 +55,12 @@ typedef enum
 #define PG_TEMP_FILES_DIR "pgsql_tmp"
 #define PG_TEMP_FILE_PREFIX "pgsql_tmp"
 
+#ifndef WIN32
+#define pg_mv_file			rename
+#else
+#define pg_mv_file			pgrename
+#endif
+
 static PgChecksumMode mode = PG_MODE_CHECK;
 
 static const char *progname;
@@ -88,6 +94,7 @@ usage(void)
  */
 static const char *const skip[] = {
 	"pg_control",
+	"pg_control.pg_checksums_in_progress",
 	"pg_filenode.map",
 	"pg_internal.init",
 	"PG_VERSION",
@@ -306,6 +313,8 @@ main(int argc, char *argv[])
 	};
 
 	char	   *DataDir = NULL;
+	char		old_controlfile_path[MAXPGPATH];
+	char		new_controlfile_path[MAXPGPATH];
 	int			c;
 	int			option_index;
 	bool		crc_ok;
@@ -440,6 +449,23 @@ main(int argc, char *argv[])
 		exit(1);
 	}
 
+	/*
+	 * Disable cluster by renaming pg_control when enabling checksums so
+	 * that it cannot be started by accident during the operation
+	 */
+	if (mode == PG_MODE_ENABLE)
+	{
+		snprintf(old_controlfile_path, sizeof(old_controlfile_path),
+				 "%s/global/pg_control", DataDir);
+		snprintf(new_controlfile_path, sizeof(new_controlfile_path),
+				 "%s/global/pg_control.pg_checksums_in_progress", DataDir);
+		if (pg_mv_file(old_controlfile_path, new_controlfile_path) != 0)
+		{
+			fprintf(stderr, _("%s: unable to rename %s to %s.\n"), progname, old_controlfile_path, new_controlfile_path);
+			exit(1);
+		}
+	}
+
 	/* Operate on all files if checking or enabling checksums */
 	if (mode == PG_MODE_CHECK || mode == PG_MODE_ENABLE)
 	{
@@ -466,6 +492,16 @@ main(int argc, char *argv[])
 	 */
 	if (mode == PG_MODE_ENABLE || mode == PG_MODE_DISABLE)
 	{
+
+		/* Move back pg_control */
+		if (mode == PG_MODE_ENABLE)
+		{
+			if (pg_mv_file(new_controlfile_path, old_controlfile_path) != 0)
+			{
+				fprintf(stderr, _("%s: unable to rename %s to %s.\n"), progname, new_controlfile_path, old_controlfile_path);
+				exit(1);
+			}
+		}
 		/* Update control file */
 		ControlFile->data_checksum_version =
 			(mode == PG_MODE_ENABLE) ? PG_DATA_CHECKSUM_VERSION : 0;
-- 
2.11.0

