From 12665d0926aca46e63ce3a0e6be1c5da7e470091 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Mon, 26 Sep 2016 12:00:00 -0400
Subject: [PATCH] Fix CRC check handling in get_controlfile

---
 src/backend/utils/misc/pg_controldata.c |  8 ++++----
 src/bin/pg_controldata/pg_controldata.c |  5 +++--
 src/bin/pg_ctl/pg_ctl.c                 | 23 ++++++-----------------
 src/common/controldata_utils.c          | 22 +++++++++++++++++-----
 src/include/common/controldata_utils.h  |  2 +-
 5 files changed, 31 insertions(+), 29 deletions(-)

diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 4f9de83..2ba505c 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -51,7 +51,7 @@ pg_control_system(PG_FUNCTION_ARGS)
 	tupdesc = BlessTupleDesc(tupdesc);
 
 	/* read the control file */
-	ControlFile = get_controlfile(DataDir, NULL);
+	ControlFile = get_controlfile(DataDir, NULL, NULL);
 	if (!ControlFile)
 		ereport(ERROR,
 				(errmsg("calculated CRC checksum does not match value stored in file")));
@@ -130,7 +130,7 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 	tupdesc = BlessTupleDesc(tupdesc);
 
 	/* Read the control file. */
-	ControlFile = get_controlfile(DataDir, NULL);
+	ControlFile = get_controlfile(DataDir, NULL, NULL);
 	if (!ControlFile)
 		ereport(ERROR,
 				(errmsg("calculated CRC checksum does not match value stored in file")));
@@ -235,7 +235,7 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 	tupdesc = BlessTupleDesc(tupdesc);
 
 	/* read the control file */
-	ControlFile = get_controlfile(DataDir, NULL);
+	ControlFile = get_controlfile(DataDir, NULL, NULL);
 	if (!ControlFile)
 		ereport(ERROR,
 				(errmsg("calculated CRC checksum does not match value stored in file")));
@@ -303,7 +303,7 @@ pg_control_init(PG_FUNCTION_ARGS)
 	tupdesc = BlessTupleDesc(tupdesc);
 
 	/* read the control file */
-	ControlFile = get_controlfile(DataDir, NULL);
+	ControlFile = get_controlfile(DataDir, NULL, NULL);
 	if (!ControlFile)
 		ereport(ERROR,
 				(errmsg("calculated CRC checksum does not match value stored in file")));
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index e92feab..20077a6 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -86,6 +86,7 @@ int
 main(int argc, char *argv[])
 {
 	ControlFileData *ControlFile;
+	bool		crc_ok;
 	char	   *DataDir = NULL;
 	time_t		time_tmp;
 	char		pgctime_str[128];
@@ -155,8 +156,8 @@ main(int argc, char *argv[])
 	}
 
 	/* get a copy of the control file */
-	ControlFile = get_controlfile(DataDir, progname);
-	if (!ControlFile)
+	ControlFile = get_controlfile(DataDir, progname, &crc_ok);
+	if (!crc_ok)
 		printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n"
 				 "Either the file is corrupt, or it has a different layout than this program\n"
 				 "is expecting.  The results below are untrustworthy.\n\n"));
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 052b02e..7400a54 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -2147,28 +2147,17 @@ static DBState
 get_control_dbstate(void)
 {
 	DBState ret;
+	ControlFileData *control_file_data = get_controlfile(pg_data, progname, NULL);
 
-	for (;;)
+	if (!control_file_data)
 	{
-		ControlFileData *control_file_data = get_controlfile(pg_data, progname);
-
-		if (control_file_data)
-		{
-			ret = control_file_data->state;
-			pfree(control_file_data);
-			return ret;
-		}
-
-		if (wait_seconds > 0)
-		{
-			pg_usleep(1000000);		/* 1 sec */
-			wait_seconds--;
-			continue;
-		}
-
 		write_stderr(_("%s: control file appears to be corrupt\n"), progname);
 		exit(1);
 	}
+
+	ret = control_file_data->state;
+	pfree(control_file_data);
+	return ret;
 }
 
 
diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c
index f218d25..a24ef8b 100644
--- a/src/common/controldata_utils.c
+++ b/src/common/controldata_utils.c
@@ -29,15 +29,17 @@
 #include "port/pg_crc32c.h"
 
 /*
- * get_controlfile(char *DataDir, const char *progname)
+ * get_controlfile(char *DataDir, const char *progname, bool *crc_ok_p)
  *
  * Get controlfile values. The caller is responsible
  * for pfreeing the result.
  *
- * Returns NULL if the CRC did not match.
+ * If crc_ok_p is not NULL, the result of the CRC check will be returned there
+ * and the actual control file data will be returned either way.  If crc_ok_p
+ * is NULL and the CRC check fails, the return value is NULL.
  */
 ControlFileData *
-get_controlfile(const char *DataDir, const char *progname)
+get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
 {
 	ControlFileData *ControlFile;
 	int			fd;
@@ -85,8 +87,18 @@ get_controlfile(const char *DataDir, const char *progname)
 
 	if (!EQ_CRC32C(crc, ControlFile->crc))
 	{
-		pfree(ControlFile);
-		return NULL;
+		if (crc_ok_p)
+			*crc_ok_p = false;
+		else
+		{
+			pfree(ControlFile);
+			return NULL;
+		}
+	}
+	else
+	{
+		if (crc_ok_p)
+			*crc_ok_p = true;
 	}
 
 	/* Make sure the control file is valid byte order. */
diff --git a/src/include/common/controldata_utils.h b/src/include/common/controldata_utils.h
index f834624..a822cba 100644
--- a/src/include/common/controldata_utils.h
+++ b/src/include/common/controldata_utils.h
@@ -12,6 +12,6 @@
 
 #include "catalog/pg_control.h"
 
-extern ControlFileData *get_controlfile(const char *DataDir, const char *progname);
+extern ControlFileData *get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p);
 
 #endif   /* COMMON_CONTROLDATA_UTILS_H */
-- 
2.10.0

