From a2f04776839228bfde8d1a7ed16173e5bccd129a Mon Sep 17 00:00:00 2001
From: Dan McGee <dan@archlinux.org>
Date: Tue, 21 Jun 2011 18:53:42 -0500
Subject: [PATCH 3/3] Add a function to check the provided binary versions

This is similar to our cluster version checks, except that we are
ensuring the binaries from our respective paths both match the versions
of the data directories they are to act on, as well as ensuring the new
binaries are compatible with this verison of pg_upgrade.
---
 contrib/pg_upgrade/check.c      |   56 +++++++++++++++++++++++++++++++++++++++
 contrib/pg_upgrade/pg_upgrade.h |    2 +
 2 files changed, 58 insertions(+), 0 deletions(-)

diff --git a/contrib/pg_upgrade/check.c b/contrib/pg_upgrade/check.c
index 5ff2d81..9163ff6 100644
--- a/contrib/pg_upgrade/check.c
+++ b/contrib/pg_upgrade/check.c
@@ -20,6 +20,7 @@ static void check_for_prepared_transactions(ClusterInfo *cluster);
 static void check_for_isn_and_int8_passing_mismatch(ClusterInfo *cluster);
 static void check_for_reg_data_type_usage(ClusterInfo *cluster);
 static char *get_pkglibdir(const char *bindir);
+static void get_pg_ctl_version(ClusterInfo *cluster);
 
 
 void
@@ -217,9 +218,14 @@ output_completion_banner(char *deletion_script_file_name)
 void
 check_cluster_versions(void)
 {
+	prep_status("Checking cluster versions");
+
 	/* get old and new cluster versions */
 	old_cluster.major_version = get_major_server_version(&old_cluster);
 	new_cluster.major_version = get_major_server_version(&new_cluster);
+	/* get old and new binary versions */
+	get_pg_ctl_version(&old_cluster);
+	get_pg_ctl_version(&new_cluster);
 
 	/*
 	 * We allow upgrades from/to the same major version for alpha/beta
@@ -240,6 +246,19 @@ check_cluster_versions(void)
 	 */
 	if (old_cluster.major_version > new_cluster.major_version)
 		pg_log(PG_FATAL, "This utility cannot be used to downgrade to older major PostgreSQL versions.\n");
+
+	/* Ensure binaries match the designated data directories */
+	if (GET_MAJOR_VERSION(old_cluster.major_version) != GET_MAJOR_VERSION(old_cluster.bin_version))
+		pg_log(PG_FATAL, "Old cluster binaries and data are not compatible.\n");
+	if (GET_MAJOR_VERSION(new_cluster.major_version) != GET_MAJOR_VERSION(new_cluster.bin_version))
+		pg_log(PG_FATAL, "New cluster binaries and data are not compatible.\n");
+
+	/* And ensure new binaries are the expected PG version */
+	if (GET_MAJOR_VERSION(new_cluster.bin_version) != GET_MAJOR_VERSION(PG_VERSION_NUM))
+		pg_log(PG_FATAL, "This utility can only upgrade to PostgreSQL version %s.\n",
+			   PG_MAJORVERSION);
+
+	check_ok();
 }
 
 
@@ -763,3 +782,40 @@ get_pkglibdir(const char *bindir)
 
 	return pg_strdup(bufin);
 }
+
+
+static void
+get_pg_ctl_version(ClusterInfo *cluster)
+{
+	char		cmd[MAXPGPATH];
+	char		bufin[MAX_STRING];
+	FILE	   *output;
+	int			i;
+	int			integer_version = 0;
+	int			fractional_version = 0;
+	int			minor_version = 0;
+
+	snprintf(cmd, sizeof(cmd), "\"%s/pg_ctl\" --version", cluster->bindir);
+
+	if ((output = popen(cmd, "r")) == NULL)
+		pg_log(PG_FATAL, "Could not get pg_ctl version data: %s\n",
+			   getErrorText(errno));
+
+	fgets(bufin, sizeof(bufin), output);
+
+	if (output)
+		pclose(output);
+
+	/* Remove trailing newline */
+	i = strlen(bufin) - 1;
+
+	if (bufin[i] == '\n')
+		bufin[i] = '\0';
+
+	if (sscanf(bufin, "pg_ctl (PostgreSQL) %d.%d.%d", &integer_version,
+			   &fractional_version, &minor_version) != 3)
+		pg_log(PG_FATAL, "could not get version from %s\n", cmd);
+
+	cluster->bin_version_str = pg_strdup(bufin);
+	cluster->bin_version = ((integer_version * 100 + fractional_version) * 100) + minor_version;
+}
diff --git a/contrib/pg_upgrade/pg_upgrade.h b/contrib/pg_upgrade/pg_upgrade.h
index c27b58a..d9ea3f9 100644
--- a/contrib/pg_upgrade/pg_upgrade.h
+++ b/contrib/pg_upgrade/pg_upgrade.h
@@ -184,6 +184,8 @@ typedef struct
 	unsigned short port;		/* port number where postmaster is waiting */
 	uint32		major_version;	/* PG_VERSION of cluster */
 	char		major_version_str[64];	/* string PG_VERSION of cluster */
+	uint32		bin_version;	/* version returned from pg_ctl */
+	char	   *bin_version_str;	/* string version returned from pg_ctl */
 	Oid			pg_database_oid;	/* OID of pg_database relation */
 	char	   *tablespace_suffix;		/* directory specification */
 } ClusterInfo;
-- 
1.7.5.4

