From c69fe2c18d62f3dd64b5153c0acfa0a6e9aaf4e1 Mon Sep 17 00:00:00 2001
From: Neil Chen <chenze@highgo.com>
Date: Wed, 28 Apr 2021 13:13:24 +0800
Subject: [PATCH] pg_rewind patch

---
 src/bin/pg_rewind/pg_rewind.c | 102 +++++++++++++++++++++++++++++++++-
 1 file changed, 101 insertions(+), 1 deletion(-)

diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 5157f59cf7..89e56ea9b7 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -47,6 +47,8 @@ static void sanityChecks(void);
 static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex);
 static void ensureCleanShutdown(const char *argv0);
 static void disconnect_atexit(void);
+static void adjust_data_dir(const char *argv0);
+static char *find_other_exec_or_die(const char *argv0, const char *target, const char *versionstr);
 
 static ControlFileData ControlFile_target;
 static ControlFileData ControlFile_source;
@@ -57,6 +59,7 @@ int			WalSegSz;
 
 /* Configuration options */
 char	   *datadir_target = NULL;
+char	   *config_target = NULL;
 char	   *datadir_source = NULL;
 char	   *connstr_source = NULL;
 char	   *restore_command = NULL;
@@ -191,6 +194,7 @@ main(int argc, char **argv)
 
 			case 'D':			/* -D or --target-pgdata */
 				datadir_target = pg_strdup(optarg);
+				config_target = pg_strdup(optarg);
 				break;
 
 			case 1:				/* --source-pgdata */
@@ -228,6 +232,9 @@ main(int argc, char **argv)
 		exit(1);
 	}
 
+	/* -D might point at config-only directory; if so find the real PGDATA */
+	adjust_data_dir(argv[0]);
+
 	if (writerecoveryconf && connstr_source == NULL)
 	{
 		pg_log_error("no source server information (--source-server) specified for --write-recovery-conf");
@@ -1125,7 +1132,7 @@ ensureCleanShutdown(const char *argv0)
 	 * is synced at the end anyway.
 	 */
 	snprintf(cmd, MAXCMDLEN, "\"%s\" --single -F -D \"%s\" template1 < \"%s\"",
-			 exec_path, datadir_target, DEVNULL);
+			 exec_path, config_target, DEVNULL);
 
 	if (system(cmd) != 0)
 	{
@@ -1140,3 +1147,96 @@ disconnect_atexit(void)
 	if (conn != NULL)
 		PQfinish(conn);
 }
+
+/*
+ * adjust_data_dir
+ *
+ * If a configuration-only directory was specified, find the real data dir.
+ */
+static void
+adjust_data_dir(const char *argv0)
+{
+	char	   *pgdata_opt;
+	char		cmd[MAXPGPATH],
+				filename[MAXPGPATH],
+			   *my_exec_path;
+	FILE	   *fd;
+
+	/* do nothing if we're working without knowledge of data dir */
+	if (config_target == NULL)
+		return;
+
+	canonicalize_path(config_target);
+	pgdata_opt = psprintf("-D \"%s\" ", config_target);
+
+	/* If there is no postgresql.conf, it can't be a config-only dir */
+	snprintf(filename, sizeof(filename), "%s/postgresql.conf", config_target);
+	if ((fd = fopen(filename, "r")) == NULL)
+		return;
+	fclose(fd);
+
+	/* If PG_VERSION exists, it can't be a config-only dir */
+	snprintf(filename, sizeof(filename), "%s/PG_VERSION", config_target);
+	if ((fd = fopen(filename, "r")) != NULL)
+	{
+		fclose(fd);
+		return;
+	}
+
+	/* Must be a configuration directory, so find the data directory */
+
+	/* we use a private my_exec_path to avoid interfering with later uses */
+	my_exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
+
+	/* it's important for -C to be the first option, see main.c */
+	snprintf(cmd, MAXPGPATH, "\"%s\" -C data_directory %s",
+			 my_exec_path,
+			 pgdata_opt ? pgdata_opt : "");
+
+	fd = popen(cmd, "r");
+	if (fd == NULL || fgets(filename, sizeof(filename), fd) == NULL)
+	{
+		pg_log_error(_("%s: could not determine the data directory using command \"%s\"\n"), progname, cmd);
+		exit(1);
+	}
+	pclose(fd);
+	free(my_exec_path);
+
+	/* strip trailing newline and carriage return */
+	(void) pg_strip_crlf(filename);
+
+	datadir_target = pg_strdup(filename);
+	canonicalize_path(datadir_target);
+}
+
+static char *
+find_other_exec_or_die(const char *argv0, const char *target, const char *versionstr)
+{
+	int			ret;
+	char	   *found_path;
+
+	found_path = pg_malloc(MAXPGPATH);
+
+	if ((ret = find_other_exec(argv0, target, versionstr, found_path)) < 0)
+	{
+		char		full_path[MAXPGPATH];
+
+		if (find_my_exec(argv0, full_path) < 0)
+			strlcpy(full_path, progname, sizeof(full_path));
+
+		if (ret == -1)
+			pg_log_error(_("The program \"%s\" is needed by %s but was not found in the\n"
+						   "same directory as \"%s\".\n"
+						   "Check your installation.\n"),
+						 target, progname, full_path);
+		else
+			pg_log_error(_("The program \"%s\" was found by \"%s\"\n"
+						   "but was not the same version as %s.\n"
+						   "Check your installation.\n"),
+						 target, full_path, progname);
+		exit(1);
+	}
+
+	return found_path;
+}
+
-- 
2.25.1

