Hi,

This is an attempt to revive the resetsysid tool submission that didn't go anywhere last year [1].

In that thread there were mainly two complains, one that pg_resetxlog would preferably be tool for more advanced stuff and similar utilities that are not as dangerous should have separate binaries using some of the functionality of pg_resetxlog as library and the other was with the string to uint64 parsing which is apparently not so easy to do portably. About the second one there was also separate discussion between Andres and Tom [2].

Here is series of patches that implements both the original feature and solves the issues mentioned above.

0001 - This patch splits the code of pg_resetxlog to common.c/h api and pg_resetxlog.c itself which does the program logic using the api. The only logical change in the XLogSegNoOffsetToRecPtr call is moved into main() function, which I think is ok as the main() does all the other ControlFile changes. All other changes should be just cosmetic in order to not rely on global static variables.

0002 - Adds pg_resetsysid utility which changes the system id to newly generated one.

0003 - Adds -s option to pg_resetxlog to change the system id to the one specified - this is separate from the other one as it can be potentially more dangerous. It also adds some defines that try to portably map pg_strtoint64 and pg_strtouint64 to the underlying implementations (strtol/strtoll/_strtoi64 and unsigned variants of those). It will leave the pg_strtoint64/pg_strtouint64 undefined if the platform does not support the functionality. Tom was unsure if there are such platforms on our supported list anymore.

Which is why I also added 0004, that adds fall-back implementation of the two functions based on very slightly modified code from OpenBSD. This is here mostly in case buildfarm gets red after applying 0003 or we have reports from users that things got broken.

[1] http://www.postgresql.org/message-id/539b97fc.8040...@2ndquadrant.com
[2] http://www.postgresql.org/message-id/20140603144654.gm24...@awork2.anarazel.de

--
 Petr Jelinek                  http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training & Services
>From f587fd47c9e43f5c08cf840978ff21b64f39d24d Mon Sep 17 00:00:00 2001
From: Petr Jelinek <pjmo...@pjmodos.net>
Date: Sun, 14 Jun 2015 16:23:39 +0200
Subject: [PATCH 4/4] Add fallback implementations of pg_strto(u)int64.

---
 src/include/c.h          |   6 ++
 src/port/Makefile        |   2 +-
 src/port/pgstrtoint64.c  | 169 +++++++++++++++++++++++++++++++++++++++++++++++
 src/port/pgstrtouint64.c | 129 ++++++++++++++++++++++++++++++++++++
 4 files changed, 305 insertions(+), 1 deletion(-)
 create mode 100644 src/port/pgstrtoint64.c
 create mode 100644 src/port/pgstrtouint64.c

diff --git a/src/include/c.h b/src/include/c.h
index 537b4d0..a01b455 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -1102,6 +1102,9 @@ extern int	fdatasync(int fildes);
 #define pg_strtoint64 strtoll
 #elif defined(WIN32)
 #define pg_strtoint64 _strtoi64
+#else
+extern int64 pg_strtoint64(const char *nptr, char **endptr, int base);
+#define PGSTRTOINT64_IMPL 1
 #endif
 
 /* Define portable pg_strtouint64() */
@@ -1111,6 +1114,9 @@ extern int	fdatasync(int fildes);
 #define pg_strtouint64 strtoull
 #elif defined(WIN32)
 #define pg_strtouint64 _strtoui64
+#else
+extern uint64 pg_strtouint64(const char *nptr, char **endptr, int base);
+#define PGSTRTOUINT64_IMPL 1
 #endif
 
 /*
diff --git a/src/port/Makefile b/src/port/Makefile
index bc9b63a..91e4a2b 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -32,7 +32,7 @@ LIBS += $(PTHREAD_LIBS)
 
 OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.o \
 	noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \
-	pgstrcasecmp.o pqsignal.o \
+	pgstrcasecmp.o pgstrtoint64.o pgstrtouint64.o pqsignal.o \
 	qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o
 
 # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
diff --git a/src/port/pgstrtoint64.c b/src/port/pgstrtoint64.c
new file mode 100644
index 0000000..e968df0
--- /dev/null
+++ b/src/port/pgstrtoint64.c
@@ -0,0 +1,169 @@
+/*-------------------------------------------------------------------------
+ *
+ * pgstrtoint64.c
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *	  src/port/pgstrtoint64.c
+ *
+ * Based on OpenBSD strtoll() implementation.
+ * Differences from vanilla implementaion:
+ *  - renamed to pg_strtoint64
+ *  - returns int64 instead of long long
+ *  - internal params defined as int64 instead of long long
+ *  - uses PG_INT64_MIN/PG_INT64_MAX
+ *
+ * The OpenBSD copyright terms follow.
+ */
+
+/* $OpenBSD: strtoll.c,v 1.7 2013/03/28 18:09:38 martynas Exp $ */
+/*-
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include "c.h"
+
+#ifdef PGSTRTOINT64_IMPL
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+
+/*
+ * Convert a string to a int64.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+int64
+pg_strtoint64(const char *nptr, char **endptr, int base)
+{
+	const char *s;
+	int64 acc, cutoff;
+	int c;
+	int neg, any, cutlim;
+
+	/*
+	 * Skip white space and pick up leading +/- sign if any.
+	 * If base is 0, allow 0x for hex and 0 for octal, else
+	 * assume decimal; if base is already 16, allow 0x.
+	 */
+	s = nptr;
+	do {
+		c = (unsigned char) *s++;
+	} while (isspace(c));
+	if (c == '-') {
+		neg = 1;
+		c = *s++;
+	} else {
+		neg = 0;
+		if (c == '+')
+			c = *s++;
+	}
+	if ((base == 0 || base == 16) &&
+	    c == '0' && (*s == 'x' || *s == 'X')) {
+		c = s[1];
+		s += 2;
+		base = 16;
+	}
+	if (base == 0)
+		base = c == '0' ? 8 : 10;
+
+	/*
+	 * Compute the cutoff value between legal numbers and illegal
+	 * numbers.  That is the largest legal value, divided by the
+	 * base.  An input number that is greater than this value, if
+	 * followed by a legal input character, is too big.  One that
+	 * is equal to this value may be valid or not; the limit
+	 * between valid and invalid numbers is then based on the last
+	 * digit.  For instance, if the range for long longs is
+	 * [-9223372036854775808..9223372036854775807] and the input base
+	 * is 10, cutoff will be set to 922337203685477580 and cutlim to
+	 * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+	 * accumulated a value > 922337203685477580, or equal but the
+	 * next digit is > 7 (or 8), the number is too big, and we will
+	 * return a range error.
+	 *
+	 * Set any if any `digits' consumed; make it negative to indicate
+	 * overflow.
+	 */
+	cutoff = neg ? PG_INT64_MIN : PG_INT64_MAX;
+	cutlim = cutoff % base;
+	cutoff /= base;
+	if (neg) {
+		if (cutlim > 0) {
+			cutlim -= base;
+			cutoff += 1;
+		}
+		cutlim = -cutlim;
+	}
+	for (acc = 0, any = 0;; c = (unsigned char) *s++) {
+		if (isdigit(c))
+			c -= '0';
+		else if (isalpha(c))
+			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+		else
+			break;
+		if (c >= base)
+			break;
+		if (any < 0)
+			continue;
+		if (neg) {
+			if (acc < cutoff || (acc == cutoff && c > cutlim)) {
+				any = -1;
+				acc = PG_INT64_MIN;
+				errno = ERANGE;
+			} else {
+				any = 1;
+				acc *= base;
+				acc -= c;
+			}
+		} else {
+			if (acc > cutoff || (acc == cutoff && c > cutlim)) {
+				any = -1;
+				acc = PG_INT64_MAX;
+				errno = ERANGE;
+			} else {
+				any = 1;
+				acc *= base;
+				acc += c;
+			}
+		}
+	}
+	if (endptr != 0)
+		*endptr = (char *) (any ? s - 1 : nptr);
+	return (acc);
+}
+
+#endif
diff --git a/src/port/pgstrtouint64.c b/src/port/pgstrtouint64.c
new file mode 100644
index 0000000..02a79fb
--- /dev/null
+++ b/src/port/pgstrtouint64.c
@@ -0,0 +1,129 @@
+/*-------------------------------------------------------------------------
+ *
+ * pgstrtouint64.c
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *	  src/port/pgstrtouint64.c
+ *
+ * Based on OpenBSD strtoll() implementation.
+ * Differences from vanilla implementaion:
+ *  - renamed to pg_strtouint64
+ *  - returns uint64 instead of unsigned long long
+ *  - internal params defined as uint64 instead of unsigned long long
+ *  - uses PG_UINT64_MIN/PG_UINT64_MAX
+ *
+ * The OpenBSD copyright terms follow.
+ */
+
+/*	$OpenBSD: strtoull.c,v 1.6 2013/03/28 18:09:38 martynas Exp $ */
+/*-
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "c.h"
+
+#ifdef PGSTRTOUINT64_IMPL
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long long.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+uint64
+pg_strtouint64(const char *nptr, char **endptr, int base)
+{
+	const char *s;
+	uint64 acc, cutoff;
+	int c;
+	int neg, any, cutlim;
+
+	/*
+	 * See strtoq for comments as to the logic used.
+	 */
+	s = nptr;
+	do {
+		c = (unsigned char) *s++;
+	} while (isspace(c));
+	if (c == '-') {
+		neg = 1;
+		c = *s++;
+	} else {
+		neg = 0;
+		if (c == '+')
+			c = *s++;
+	}
+	if ((base == 0 || base == 16) &&
+		c == '0' && (*s == 'x' || *s == 'X')) {
+		c = s[1];
+		s += 2;
+		base = 16;
+	}
+	if (base == 0)
+		base = c == '0' ? 8 : 10;
+
+	cutoff = PG_UINT64_MAX / (unsigned long long)base;
+	cutlim = PG_UINT64_MAX % (unsigned long long)base;
+	for (acc = 0, any = 0;; c = (unsigned char) *s++) {
+		if (isdigit(c))
+			c -= '0';
+		else if (isalpha(c))
+			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+		else
+			break;
+		if (c >= base)
+			break;
+		if (any < 0)
+			continue;
+		if (acc > cutoff || (acc == cutoff && c > cutlim)) {
+			any = -1;
+			acc = PG_UINT64_MAX;
+			errno = ERANGE;
+		} else {
+			any = 1;
+			acc *= (unsigned long long)base;
+			acc += c;
+		}
+	}
+	if (neg && any > 0)
+		acc = -acc;
+	if (endptr != 0)
+		*endptr = (char *) (any ? s - 1 : nptr);
+	return (acc);
+}
+
+#endif
-- 
1.9.1

>From ce33dd5c708feed330127e7964b73a14c6b0b913 Mon Sep 17 00:00:00 2001
From: Petr Jelinek <pjmo...@pjmodos.net>
Date: Sat, 13 Jun 2015 21:48:31 +0200
Subject: [PATCH 3/4] Set sysid via pg_resetxlog

---
 src/bin/pg_resetxlog/pg_resetxlog.c | 44 +++++++++++++++++++++++++++++++++++--
 src/include/c.h                     | 18 +++++++++++++++
 2 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c
index 2c061fa..f0f3658 100644
--- a/src/bin/pg_resetxlog/pg_resetxlog.c
+++ b/src/bin/pg_resetxlog/pg_resetxlog.c
@@ -61,6 +61,7 @@ static TransactionId set_newest_commit_ts = 0;
 static Oid	set_oid = 0;
 static MultiXactId set_mxid = 0;
 static MultiXactOffset set_mxoff = (MultiXactOffset) -1;
+static uint64 set_sysid = 0;
 static uint32 minXlogTli = 0;
 static XLogSegNo minXlogSegNo = 0;
 
@@ -99,7 +100,7 @@ main(int argc, char *argv[])
 	}
 
 
-	while ((c = getopt(argc, argv, "c:D:e:fl:m:no:O:x:")) != -1)
+	while ((c = getopt(argc, argv, "c:D:e:fl:m:no:O:s:x:")) != -1)
 	{
 		switch (c)
 		{
@@ -252,6 +253,25 @@ main(int argc, char *argv[])
 				XLogFromFileName(optarg, &minXlogTli, &minXlogSegNo);
 				break;
 
+			case 's':
+
+				set_sysid = pg_strtouint64(optarg, &endptr, 10);
+
+				/*
+				 * Validate input, we use strspn because some underlying
+				 * implementations of pg_strtouint64 accept negative numbers
+				 * and silently converts them to unsigned.
+				 */
+				if (set_sysid == 0 || errno != 0 ||
+					endptr == optarg || *endptr != '\0' ||
+					strspn(optarg, " 0123456789") != strlen(optarg))
+				{
+					fprintf(stderr, _("%s: invalid argument \"%s\" for option -s\n"), progname, optarg);
+					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
+					exit(1);
+				}
+				break;
+
 			default:
 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 				exit(1);
@@ -388,6 +408,9 @@ main(int argc, char *argv[])
 	if (set_mxoff != -1)
 		ControlFile.checkPointCopy.nextMultiOffset = set_mxoff;
 
+	if (set_sysid != 0)
+		ControlFile.system_identifier = set_sysid;
+
 	if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
 	{
 		ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli;
@@ -443,7 +466,7 @@ main(int argc, char *argv[])
  * Print the values to be changed.
  */
 static void
-PrintNewControlValues()
+PrintNewControlValues(void)
 {
 	char		fname[MAXFNAMELEN];
 
@@ -501,6 +524,22 @@ PrintNewControlValues()
 		printf(_("newestCommitTs:                       %u\n"),
 			   ControlFile.checkPointCopy.newestCommitTs);
 	}
+
+	if (set_sysid != 0)
+	{
+		char            sysident_str[32];
+
+		/*
+		 * Format system_identifier separately to keep platform-dependent
+		 * format code out of the translatable message string.
+		 */
+		snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
+				 ControlFile.system_identifier);
+
+		printf(_("Database system identifier:           %s\n"),
+			   sysident_str);
+	}
+
 }
 
 
@@ -519,6 +558,7 @@ usage(void)
 	printf(_("  -n               no update, just show what would be done (for testing)\n"));
 	printf(_("  -o OID           set next OID\n"));
 	printf(_("  -O OFFSET        set next multitransaction offset\n"));
+	printf(_("  -s SYSID         set system identifier\n"));
 	printf(_("  -V, --version    output version information, then exit\n"));
 	printf(_("  -x XID           set next transaction ID\n"));
 	printf(_("  -?, --help       show this help, then exit\n"));
diff --git a/src/include/c.h b/src/include/c.h
index 92c5202..537b4d0 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -1095,6 +1095,24 @@ extern int	fdatasync(int fildes);
 #define HAVE_STRTOULL 1
 #endif
 
+/* Define portable pg_strtoint64() */
+#if defined(HAVE_LONG_INT_64)
+#define pg_strtoint64 strtol
+#elif defined(HAVE_STRTOULL)
+#define pg_strtoint64 strtoll
+#elif defined(WIN32)
+#define pg_strtoint64 _strtoi64
+#endif
+
+/* Define portable pg_strtouint64() */
+#if defined(HAVE_LONG_INT_64)
+#define pg_strtouint64 strtoul
+#elif defined(HAVE_STRTOULL)
+#define pg_strtouint64 strtoull
+#elif defined(WIN32)
+#define pg_strtouint64 _strtoui64
+#endif
+
 /*
  * We assume if we have these two functions, we have their friends too, and
  * can use the wide-character functions.
-- 
1.9.1

>From 6de7841715e446a9fc3726f3dd0e5ae37525e141 Mon Sep 17 00:00:00 2001
From: Petr Jelinek <pjmo...@pjmodos.net>
Date: Sat, 13 Jun 2015 16:29:26 +0200
Subject: [PATCH 2/4] Add pg_resetsysid utility

---
 doc/src/sgml/ref/allfiles.sgml       |   1 +
 doc/src/sgml/ref/pg_resetsysid.sgml  |  85 +++++++++++
 doc/src/sgml/reference.sgml          |   1 +
 src/bin/pg_resetxlog/.gitignore      |   1 +
 src/bin/pg_resetxlog/Makefile        |  10 +-
 src/bin/pg_resetxlog/nls.mk          |   2 +-
 src/bin/pg_resetxlog/pg_resetsysid.c | 265 +++++++++++++++++++++++++++++++++++
 7 files changed, 361 insertions(+), 4 deletions(-)
 create mode 100644 doc/src/sgml/ref/pg_resetsysid.sgml
 create mode 100644 src/bin/pg_resetxlog/pg_resetsysid.c

diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index bf95453..46c23f3 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -192,6 +192,7 @@ Complete list of usable sgml source files in this directory.
 <!ENTITY pgIsready          SYSTEM "pg_isready.sgml">
 <!ENTITY pgReceivexlog      SYSTEM "pg_receivexlog.sgml">
 <!ENTITY pgRecvlogical      SYSTEM "pg_recvlogical.sgml">
+<!ENTITY pgResetsysid       SYSTEM "pg_resetsysid.sgml">
 <!ENTITY pgResetxlog        SYSTEM "pg_resetxlog.sgml">
 <!ENTITY pgRestore          SYSTEM "pg_restore.sgml">
 <!ENTITY pgRewind           SYSTEM "pg_rewind.sgml">
diff --git a/doc/src/sgml/ref/pg_resetsysid.sgml b/doc/src/sgml/ref/pg_resetsysid.sgml
new file mode 100644
index 0000000..e64caad
--- /dev/null
+++ b/doc/src/sgml/ref/pg_resetsysid.sgml
@@ -0,0 +1,85 @@
+<!--
+doc/src/sgml/ref/pg_resetsysid.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="APP-PGRESETSYSID">
+ <indexterm zone="app-pgresetsysid">
+  <primary>pg_resetsysid</primary>
+ </indexterm>
+
+ <refmeta>
+  <refentrytitle><application>pg_resetsysid</application></refentrytitle>
+  <manvolnum>1</manvolnum>
+  <refmiscinfo>Application</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+  <refname>pg_resetsysid</refname>
+  <refpurpose>reset the system identifier of a <productname>PostgreSQL</productname> database cluster</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+  <cmdsynopsis>
+   <command>pg_resetsysid</command>
+   <arg choice="opt"><option>-f</option></arg>
+   <arg choice="opt"><option>-n</option></arg>
+   <arg choice="req"><arg choice="opt"><option>-D</option></arg> <replaceable class="parameter">datadir</replaceable></arg>
+  </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-APP-PGRESETSYSID-1">
+  <title>Description</title>
+  <para>
+   <command>pg_resetsysid</command> generates new system identifier
+   using same algorithm as <command>initdb</command> and sets it in the
+   <filename>pg_control</> file.
+  </para>
+
+  <para>
+   Note that <command>pg_resetsysid</command> will also clear the
+   write-ahead log (WAL) as existing WALs cannot be replayed after the
+   system identifier change.
+  </para>
+
+  <para>
+   The <option>-n</> (no operation) option instructs
+   <command>pg_resetsysid</command> to print the values reconstructed from
+   <filename>pg_control</> and values about to be changed, and then exit
+   without modifying anything. This is mainly a debugging tool, but can be
+   useful as a sanity check before allowing <command>pg_resetsysid</command>
+   to proceed for real.
+  </para>
+
+  <para>
+   The <option>-V</> and <option>--version</> options print
+   the <application>pg_resetsysid</application> version and exit.  The
+   options <option>-?</> and <option>--help</> show supported arguments,
+   and exit.
+  </para>
+
+ </refsect1>
+
+ <refsect1>
+  <title>Notes</title>
+
+  <para>
+   This command must not be used when the server is
+   running.  <command>pg_resetsysid</command> will refuse to start up if
+   it finds a server lock file in the data directory.  If the
+   server crashed then a lock file might have been left
+   behind; in that case you can remove the lock file to allow
+   <command>pg_resetsysid</command> to run.  But before you do
+   so, make doubly certain that there is no server process still alive.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simplelist type="inline">
+   <member><xref linkend="app-pgresetxlog"></member>
+  </simplelist>
+ </refsect1>
+
+</refentry>
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index 03020df..7e02a5e 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -263,6 +263,7 @@
    &pgarchivecleanup;
    &pgControldata;
    &pgCtl;
+   &pgResetsysid;
    &pgResetxlog;
    &pgRewind;
    &pgtestfsync;
diff --git a/src/bin/pg_resetxlog/.gitignore b/src/bin/pg_resetxlog/.gitignore
index 6b84208..9a0e1b9 100644
--- a/src/bin/pg_resetxlog/.gitignore
+++ b/src/bin/pg_resetxlog/.gitignore
@@ -1 +1,2 @@
 /pg_resetxlog
+/pg_resetsysid
diff --git a/src/bin/pg_resetxlog/Makefile b/src/bin/pg_resetxlog/Makefile
index acaa3f7..37aa07c 100644
--- a/src/bin/pg_resetxlog/Makefile
+++ b/src/bin/pg_resetxlog/Makefile
@@ -17,19 +17,23 @@ include $(top_builddir)/src/Makefile.global
 
 OBJS= common.o $(WIN32RES)
 
-all: pg_resetxlog
+all: pg_resetxlog pg_resetsysid
 
 pg_resetxlog: $(OBJS) pg_resetxlog.o | submake-libpgport
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
+pg_resetsysid: $(OBJS) pg_resetsysid.o | submake-libpgport
+	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+
 install: all installdirs
 	$(INSTALL_PROGRAM) pg_resetxlog$(X) '$(DESTDIR)$(bindir)/pg_resetxlog$(X)'
+	$(INSTALL_PROGRAM) pg_resetsysid$(X) '$(DESTDIR)$(bindir)/pg_resetsysid$(X)'
 
 installdirs:
 	$(MKDIR_P) '$(DESTDIR)$(bindir)'
 
 uninstall:
-	rm -f '$(DESTDIR)$(bindir)/pg_resetxlog$(X)'
+	rm -f '$(DESTDIR)$(bindir)/pg_resetxlog$(X)' '$(DESTDIR)$(bindir)/pg_resetsysid$(X)'
 
 clean distclean maintainer-clean:
-	rm -f pg_resetxlog$(X) $(OBJS) pg_resetxlog.o
+	rm -f pg_resetxlog$(X) $(OBJS) pg_resetxlog.o pg_resetsysid.o
diff --git a/src/bin/pg_resetxlog/nls.mk b/src/bin/pg_resetxlog/nls.mk
index b753ace..9064d30 100644
--- a/src/bin/pg_resetxlog/nls.mk
+++ b/src/bin/pg_resetxlog/nls.mk
@@ -1,4 +1,4 @@
 # src/bin/pg_resetxlog/nls.mk
 CATALOG_NAME     = pg_resetxlog
 AVAIL_LANGUAGES  = cs de es fr it ja pl pt_BR ru sv zh_CN
-GETTEXT_FILES    = common.c pg_resetxlog.c ../../common/restricted_token.c
+GETTEXT_FILES    = common.c pg_resetxlog.c pg_resetsysid.c ../../common/restricted_token.c
diff --git a/src/bin/pg_resetxlog/pg_resetsysid.c b/src/bin/pg_resetxlog/pg_resetsysid.c
new file mode 100644
index 0000000..dee1387
--- /dev/null
+++ b/src/bin/pg_resetxlog/pg_resetsysid.c
@@ -0,0 +1,265 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_resetsysid.c
+ *	  A utility to reset system identifier.
+ *
+ * Inner workings are shared with pg_resetxlog.c
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/bin/pg_resetxlog/pg_resetsysid.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "common.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "access/transam.h"
+#include "access/tuptoaster.h"
+#include "access/multixact.h"
+#include "catalog/catversion.h"
+#include "common/fe_memutils.h"
+#include "storage/large_object.h"
+#include "pg_getopt.h"
+
+const char *progname;
+static ControlFileData ControlFile;             /* pg_control values */
+static XLogSegNo newXlogSegNo;  /* new XLOG segment # */
+static bool guessed = false;    /* T if we had to guess at any values */
+static uint64 set_sysid = 0;
+
+static void PrintNewControlValues(void);
+static void usage(void);
+
+
+int
+main(int argc, char *argv[])
+{
+	int			c;
+	bool		force = false;
+	bool		noupdate = false;
+	char	   *DataDir = NULL;
+	int			fd;
+
+	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetsysid"));
+
+	progname = get_progname(argv[0]);
+
+	if (argc > 1)
+	{
+		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
+		{
+			usage();
+			exit(0);
+		}
+		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
+		{
+			puts("pg_resetsysid (PostgreSQL) " PG_VERSION);
+			exit(0);
+		}
+	}
+
+
+	while ((c = getopt(argc, argv, "D:fn")) != -1)
+	{
+		switch (c)
+		{
+			case 'D':
+				DataDir = optarg;
+				break;
+
+			case 'f':
+				force = true;
+				break;
+
+			case 'n':
+				noupdate = true;
+				break;
+
+			default:
+				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
+				exit(1);
+		}
+	}
+
+	if (DataDir == NULL && optind < argc)
+		DataDir = argv[optind++];
+
+	/* Complain if any arguments remain */
+	if (optind < argc)
+	{
+		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
+				progname, argv[optind]);
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (DataDir == NULL)
+	{
+		fprintf(stderr, _("%s: no data directory specified\n"), progname);
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
+		exit(1);
+	}
+
+	/*
+	 * Don't allow pg_resetsysid to be run as root, to avoid overwriting the
+	 * ownership of files in the data directory. We need only check for root
+	 * -- any other user won't have sufficient permissions to modify files in
+	 * the data directory.
+	 */
+#ifndef WIN32
+	if (geteuid() == 0)
+	{
+		fprintf(stderr, _("%s: cannot be executed by \"root\"\n"),
+				progname);
+		fprintf(stderr, _("You must run %s as the PostgreSQL superuser.\n"),
+				progname);
+		exit(1);
+	}
+#endif
+
+	if (chdir(DataDir) < 0)
+	{
+		fprintf(stderr, _("%s: could not change directory to \"%s\": %s\n"),
+				progname, DataDir, strerror(errno));
+		exit(1);
+	}
+
+	/*
+	 * Check for a postmaster lock file --- if there is one, refuse to
+	 * proceed, on grounds we might be interfering with a live installation.
+	 */
+	if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0)
+	{
+		if (errno != ENOENT)
+		{
+			fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
+					progname, "postmaster.pid", strerror(errno));
+			exit(1);
+		}
+	}
+	else
+	{
+		fprintf(stderr, _("%s: lock file \"%s\" exists\n"
+						  "Is a server running?  If not, delete the lock file and try again.\n"),
+				progname, "postmaster.pid");
+		exit(1);
+	}
+
+	/*
+	 * Generate new system identifier.
+	 */
+	set_sysid = GenerateSystemIdentifier();
+
+	/*
+	 * Attempt to read the existing pg_control file
+	 */
+	if (!ReadControlFile(&ControlFile, &guessed))
+		GuessControlValues(&ControlFile);
+
+	/*
+	 * Also look at existing segment files to set up newXlogSegNo
+	 */
+	newXlogSegNo = FindEndOfXLOG(&ControlFile);
+
+	/*
+	 * If we're not going to proceed with the reset, print the current control
+	 * file parameters.
+	 */
+	if ((guessed && !force) || noupdate)
+		PrintControlValues(&ControlFile, guessed);
+
+	ControlFile.system_identifier = set_sysid;
+
+	/*
+	 * If we had to guess anything, and -f was not given, just print the
+	 * guessed values and exit.  Also print if -n is given.
+	 */
+	if ((guessed && !force) || noupdate)
+	{
+		PrintNewControlValues();
+		if (!noupdate)
+		{
+			printf(_("\nIf these values seem acceptable, use -f to force reset.\n"));
+			exit(1);
+		}
+		else
+			exit(0);
+	}
+
+	/*
+	 * Don't reset from a dirty pg_control without -f, either.
+	 */
+	if (ControlFile.state != DB_SHUTDOWNED && !force)
+	{
+		printf(_("The database server was not shut down cleanly.\n"
+			   "Resetting the transaction log might cause data to be lost.\n"
+			   "If you want to proceed anyway, use -f to force reset.\n"));
+		exit(1);
+	}
+
+	/*
+	 * Else, do the dirty deed.
+	 */
+	XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD,
+							ControlFile.checkPointCopy.redo);
+	RewriteControlFile(&ControlFile);
+	KillExistingXLOG();
+	KillExistingArchiveStatus();
+	WriteEmptyXLOG(&ControlFile);
+
+	printf(_("System identifier and transaction log reset\n"));
+	return 0;
+}
+
+
+/*
+ * Print the values to be changed.
+ */
+static void
+PrintNewControlValues(void)
+{
+	char		fname[MAXFNAMELEN];
+	char		sysident_str[32];
+
+	/* This will be always printed in order to keep format same. */
+	printf(_("\n\nValues to be changed:\n\n"));
+
+	XLogFileName(fname, ControlFile.checkPointCopy.ThisTimeLineID, newXlogSegNo);
+	printf(_("First log segment after reset:        %s\n"), fname);
+
+
+	/*
+	 * Format system_identifier separately to keep platform-dependent format
+	 * code out of the translatable message string.
+	 */
+	snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
+		 ControlFile.system_identifier);
+
+	printf(_("Database system identifier:           %s\n"),
+		   sysident_str);
+}
+
+
+static void
+usage(void)
+{
+	printf(_("%s generates new system identifier for the PostgreSQL instance.\n\n"), progname);
+	printf(_("Usage:\n  %s [OPTION]... {[-D] DATADIR}\n\n"), progname);
+	printf(_("Options:\n"));
+	printf(_("  -f               force update to be done\n"));
+	printf(_("  -n               no update, just show what would be done (for testing)\n"));
+	printf(_("  -V, --version    output version information, then exit\n"));
+	printf(_("  -?, --help       show this help, then exit\n"));
+	printf(_("\nReport bugs to <pgsql-b...@postgresql.org>.\n"));
+}
-- 
1.9.1

>From 7218cd92b83288681bf670d910ab7fa3d1cb619e Mon Sep 17 00:00:00 2001
From: Petr Jelinek <pjmo...@pjmodos.net>
Date: Sat, 13 Jun 2015 16:14:31 +0200
Subject: [PATCH 1/4] Refactor pg_resetxlog to common API + the actual
 pg_resetxlog.

This will enable writing other similar less dangerous utilities.
---
 src/bin/pg_resetxlog/Makefile       |   6 +-
 src/bin/pg_resetxlog/common.c       | 683 ++++++++++++++++++++++++++++++++++++
 src/bin/pg_resetxlog/common.h       |  30 ++
 src/bin/pg_resetxlog/nls.mk         |   2 +-
 src/bin/pg_resetxlog/pg_resetxlog.c | 676 +----------------------------------
 5 files changed, 727 insertions(+), 670 deletions(-)
 create mode 100644 src/bin/pg_resetxlog/common.c
 create mode 100644 src/bin/pg_resetxlog/common.h

diff --git a/src/bin/pg_resetxlog/Makefile b/src/bin/pg_resetxlog/Makefile
index 2ed3adf..acaa3f7 100644
--- a/src/bin/pg_resetxlog/Makefile
+++ b/src/bin/pg_resetxlog/Makefile
@@ -15,11 +15,11 @@ subdir = src/bin/pg_resetxlog
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS= pg_resetxlog.o $(WIN32RES)
+OBJS= common.o $(WIN32RES)
 
 all: pg_resetxlog
 
-pg_resetxlog: $(OBJS) | submake-libpgport
+pg_resetxlog: $(OBJS) pg_resetxlog.o | submake-libpgport
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
@@ -32,4 +32,4 @@ uninstall:
 	rm -f '$(DESTDIR)$(bindir)/pg_resetxlog$(X)'
 
 clean distclean maintainer-clean:
-	rm -f pg_resetxlog$(X) $(OBJS)
+	rm -f pg_resetxlog$(X) $(OBJS) pg_resetxlog.o
diff --git a/src/bin/pg_resetxlog/common.c b/src/bin/pg_resetxlog/common.c
new file mode 100644
index 0000000..d05e557
--- /dev/null
+++ b/src/bin/pg_resetxlog/common.c
@@ -0,0 +1,683 @@
+/*-------------------------------------------------------------------------
+ *
+ * common.c
+ *	  Common code for pg_resetxlog type of utilities.
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/bin/pg_resetxlog/common.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "common.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "access/transam.h"
+#include "access/tuptoaster.h"
+#include "access/multixact.h"
+#include "catalog/catversion.h"
+#include "common/fe_memutils.h"
+#include "storage/large_object.h"
+#include "access/xlog.h"
+
+/*
+ * Create a new unique installation identifier.
+ *
+ * See notes in xlog.c about the algorithm.
+ */
+uint64
+GenerateSystemIdentifier(void)
+{
+	uint64			sysidentifier;
+	struct timeval	tv;
+
+	gettimeofday(&tv, NULL);
+	sysidentifier = ((uint64) tv.tv_sec) << 32;
+	sysidentifier |= ((uint64) tv.tv_usec) << 12;
+	sysidentifier |= getpid() & 0xFFF;
+
+	return sysidentifier;
+}
+
+/*
+ * Try to read the existing pg_control file.
+ *
+ * This routine is also responsible for updating old pg_control versions
+ * to the current format.  (Currently we don't do anything of the sort.)
+ */
+bool
+ReadControlFile(ControlFileData *ControlFile, bool *guessed)
+{
+	int			fd;
+	int			len;
+	char	   *buffer;
+	pg_crc32c	crc;
+
+	*guessed = false;
+
+	if ((fd = open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0)
+	{
+		/*
+		 * If pg_control is not there at all, or we can't read it, the odds
+		 * are we've been handed a bad DataDir path, so give up. User can do
+		 * "touch pg_control" to force us to proceed.
+		 */
+		fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
+				progname, XLOG_CONTROL_FILE, strerror(errno));
+		if (errno == ENOENT)
+			fprintf(stderr, _("If you are sure the data directory path is correct, execute\n"
+							  "  touch %s\n"
+							  "and try again.\n"),
+					XLOG_CONTROL_FILE);
+		exit(1);
+	}
+
+	/* Use malloc to ensure we have a maxaligned buffer */
+	buffer = (char *) pg_malloc(PG_CONTROL_SIZE);
+
+	len = read(fd, buffer, PG_CONTROL_SIZE);
+	if (len < 0)
+	{
+		fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
+				progname, XLOG_CONTROL_FILE, strerror(errno));
+		exit(1);
+	}
+	close(fd);
+
+	if (len >= sizeof(ControlFileData) &&
+	  ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
+	{
+		/* Check the CRC. */
+		INIT_CRC32C(crc);
+		COMP_CRC32C(crc,
+					buffer,
+					offsetof(ControlFileData, crc));
+		FIN_CRC32C(crc);
+
+		if (EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
+		{
+			/* Valid data... */
+			memcpy(ControlFile, buffer, sizeof(ControlFileData));
+			return true;
+		}
+
+		fprintf(stderr, _("%s: pg_control exists but has invalid CRC; proceed with caution\n"),
+				progname);
+		/* We will use the data anyway, but treat it as guessed. */
+		memcpy(ControlFile, buffer, sizeof(ControlFileData));
+		*guessed = true;
+		return true;
+	}
+
+	/* Looks like it's a mess. */
+	fprintf(stderr, _("%s: pg_control exists but is broken or unknown version; ignoring it\n"),
+			progname);
+	return false;
+}
+
+
+/*
+ * Guess at pg_control values when we can't read the old ones.
+ */
+void
+GuessControlValues(ControlFileData *ControlFile)
+{
+	/*
+	 * Set up a completely default set of pg_control values.
+	 */
+	memset(ControlFile, 0, sizeof(ControlFileData));
+
+	ControlFile->pg_control_version = PG_CONTROL_VERSION;
+	ControlFile->catalog_version_no = CATALOG_VERSION_NO;
+
+	/*
+	 * Create a new unique installation identifier, since we can no longer use
+	 * any old XLOG records.  See notes in xlog.c about the algorithm.
+	 */
+
+	ControlFile->system_identifier = GenerateSystemIdentifier();
+
+	ControlFile->checkPointCopy.redo = SizeOfXLogLongPHD;
+	ControlFile->checkPointCopy.ThisTimeLineID = 1;
+	ControlFile->checkPointCopy.PrevTimeLineID = 1;
+	ControlFile->checkPointCopy.fullPageWrites = false;
+	ControlFile->checkPointCopy.nextXidEpoch = 0;
+	ControlFile->checkPointCopy.nextXid = FirstNormalTransactionId;
+	ControlFile->checkPointCopy.nextOid = FirstBootstrapObjectId;
+	ControlFile->checkPointCopy.nextMulti = FirstMultiXactId;
+	ControlFile->checkPointCopy.nextMultiOffset = 0;
+	ControlFile->checkPointCopy.oldestXid = FirstNormalTransactionId;
+	ControlFile->checkPointCopy.oldestXidDB = InvalidOid;
+	ControlFile->checkPointCopy.oldestMulti = FirstMultiXactId;
+	ControlFile->checkPointCopy.oldestMultiDB = InvalidOid;
+	ControlFile->checkPointCopy.time = (pg_time_t) time(NULL);
+	ControlFile->checkPointCopy.oldestActiveXid = InvalidTransactionId;
+
+	ControlFile->state = DB_SHUTDOWNED;
+	ControlFile->time = (pg_time_t) time(NULL);
+	ControlFile->checkPoint = ControlFile->checkPointCopy.redo;
+	ControlFile->unloggedLSN = 1;
+
+	/* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */
+
+	ControlFile->wal_level = WAL_LEVEL_MINIMAL;
+	ControlFile->wal_log_hints = false;
+	ControlFile->track_commit_timestamp = false;
+	ControlFile->MaxConnections = 100;
+	ControlFile->max_worker_processes = 8;
+	ControlFile->max_prepared_xacts = 0;
+	ControlFile->max_locks_per_xact = 64;
+
+	ControlFile->maxAlign = MAXIMUM_ALIGNOF;
+	ControlFile->floatFormat = FLOATFORMAT_VALUE;
+	ControlFile->blcksz = BLCKSZ;
+	ControlFile->relseg_size = RELSEG_SIZE;
+	ControlFile->xlog_blcksz = XLOG_BLCKSZ;
+	ControlFile->xlog_seg_size = XLOG_SEG_SIZE;
+	ControlFile->nameDataLen = NAMEDATALEN;
+	ControlFile->indexMaxKeys = INDEX_MAX_KEYS;
+	ControlFile->toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE;
+	ControlFile->loblksize = LOBLKSIZE;
+#ifdef HAVE_INT64_TIMESTAMP
+	ControlFile->enableIntTimes = true;
+#else
+	ControlFile->enableIntTimes = false;
+#endif
+	ControlFile->float4ByVal = FLOAT4PASSBYVAL;
+	ControlFile->float8ByVal = FLOAT8PASSBYVAL;
+
+	/*
+	 * XXX eventually, should try to grovel through old XLOG to develop more
+	 * accurate values for TimeLineID, nextXID, etc.
+	 */
+}
+
+
+/*
+ * Print the guessed pg_control values when we had to guess.
+ *
+ * NB: this display should be just those fields that will not be
+ * reset by RewriteControlFile().
+ */
+void
+PrintControlValues(ControlFileData *ControlFile, bool guessed)
+{
+	char		sysident_str[32];
+
+	if (guessed)
+		printf(_("Guessed pg_control values:\n\n"));
+	else
+		printf(_("Current pg_control values:\n\n"));
+
+	/*
+	 * Format system_identifier separately to keep platform-dependent format
+	 * code out of the translatable message string.
+	 */
+	snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
+			 ControlFile->system_identifier);
+
+	printf(_("pg_control version number:            %u\n"),
+		   ControlFile->pg_control_version);
+	printf(_("Catalog version number:               %u\n"),
+		   ControlFile->catalog_version_no);
+	printf(_("Database system identifier:           %s\n"),
+		   sysident_str);
+	printf(_("Latest checkpoint's TimeLineID:       %u\n"),
+		   ControlFile->checkPointCopy.ThisTimeLineID);
+	printf(_("Latest checkpoint's full_page_writes: %s\n"),
+		   ControlFile->checkPointCopy.fullPageWrites ? _("on") : _("off"));
+	printf(_("Latest checkpoint's NextXID:          %u/%u\n"),
+		   ControlFile->checkPointCopy.nextXidEpoch,
+		   ControlFile->checkPointCopy.nextXid);
+	printf(_("Latest checkpoint's NextOID:          %u\n"),
+		   ControlFile->checkPointCopy.nextOid);
+	printf(_("Latest checkpoint's NextMultiXactId:  %u\n"),
+		   ControlFile->checkPointCopy.nextMulti);
+	printf(_("Latest checkpoint's NextMultiOffset:  %u\n"),
+		   ControlFile->checkPointCopy.nextMultiOffset);
+	printf(_("Latest checkpoint's oldestXID:        %u\n"),
+		   ControlFile->checkPointCopy.oldestXid);
+	printf(_("Latest checkpoint's oldestXID's DB:   %u\n"),
+		   ControlFile->checkPointCopy.oldestXidDB);
+	printf(_("Latest checkpoint's oldestActiveXID:  %u\n"),
+		   ControlFile->checkPointCopy.oldestActiveXid);
+	printf(_("Latest checkpoint's oldestMultiXid:   %u\n"),
+		   ControlFile->checkPointCopy.oldestMulti);
+	printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
+		   ControlFile->checkPointCopy.oldestMultiDB);
+	printf(_("Latest checkpoint's oldest CommitTs:  %u\n"),
+		   ControlFile->checkPointCopy.oldestCommitTs);
+	printf(_("Latest checkpoint's newest CommitTs:  %u\n"),
+		   ControlFile->checkPointCopy.newestCommitTs);
+	printf(_("Maximum data alignment:               %u\n"),
+		   ControlFile->maxAlign);
+	/* we don't print floatFormat since can't say much useful about it */
+	printf(_("Database block size:                  %u\n"),
+		   ControlFile->blcksz);
+	printf(_("Blocks per segment of large relation: %u\n"),
+		   ControlFile->relseg_size);
+	printf(_("WAL block size:                       %u\n"),
+		   ControlFile->xlog_blcksz);
+	printf(_("Bytes per WAL segment:                %u\n"),
+		   ControlFile->xlog_seg_size);
+	printf(_("Maximum length of identifiers:        %u\n"),
+		   ControlFile->nameDataLen);
+	printf(_("Maximum columns in an index:          %u\n"),
+		   ControlFile->indexMaxKeys);
+	printf(_("Maximum size of a TOAST chunk:        %u\n"),
+		   ControlFile->toast_max_chunk_size);
+	printf(_("Size of a large-object chunk:         %u\n"),
+		   ControlFile->loblksize);
+	printf(_("Date/time type storage:               %s\n"),
+		   (ControlFile->enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
+	printf(_("Float4 argument passing:              %s\n"),
+		   (ControlFile->float4ByVal ? _("by value") : _("by reference")));
+	printf(_("Float8 argument passing:              %s\n"),
+		   (ControlFile->float8ByVal ? _("by value") : _("by reference")));
+	printf(_("Data page checksum version:           %u\n"),
+		   ControlFile->data_checksum_version);
+}
+
+/*
+ * Write out the new pg_control file.
+ */
+void
+RewriteControlFile(ControlFileData *ControlFile)
+{
+	int			fd;
+	char		buffer[PG_CONTROL_SIZE];		/* need not be aligned */
+
+	/*
+	 * Adjust fields as needed to force an empty XLOG starting at
+	 * redo.
+	 */
+	ControlFile->checkPointCopy.time = (pg_time_t) time(NULL);
+
+	ControlFile->state = DB_SHUTDOWNED;
+	ControlFile->time = (pg_time_t) time(NULL);
+	ControlFile->checkPoint = ControlFile->checkPointCopy.redo;
+	ControlFile->prevCheckPoint = 0;
+	ControlFile->minRecoveryPoint = 0;
+	ControlFile->minRecoveryPointTLI = 0;
+	ControlFile->backupStartPoint = 0;
+	ControlFile->backupEndPoint = 0;
+	ControlFile->backupEndRequired = false;
+
+	/*
+	 * Force the defaults for max_* settings. The values don't really matter
+	 * as long as wal_level='minimal'; the postmaster will reset these fields
+	 * anyway at startup.
+	 */
+	ControlFile->wal_level = WAL_LEVEL_MINIMAL;
+	ControlFile->wal_log_hints = false;
+	ControlFile->track_commit_timestamp = false;
+	ControlFile->MaxConnections = 100;
+	ControlFile->max_worker_processes = 8;
+	ControlFile->max_prepared_xacts = 0;
+	ControlFile->max_locks_per_xact = 64;
+
+	/* Now we can force the recorded xlog seg size to the right thing. */
+	ControlFile->xlog_seg_size = XLogSegSize;
+
+	/* Contents are protected with a CRC */
+	INIT_CRC32C(ControlFile->crc);
+	COMP_CRC32C(ControlFile->crc,
+				(char *) ControlFile,
+				offsetof(ControlFileData, crc));
+	FIN_CRC32C(ControlFile->crc);
+
+	/*
+	 * We write out PG_CONTROL_SIZE bytes into pg_control, zero-padding the
+	 * excess over sizeof(ControlFileData).  This reduces the odds of
+	 * premature-EOF errors when reading pg_control.  We'll still fail when we
+	 * check the contents of the file, but hopefully with a more specific
+	 * error than "couldn't read pg_control".
+	 */
+	if (sizeof(ControlFileData) > PG_CONTROL_SIZE)
+	{
+		fprintf(stderr,
+				_("%s: internal error -- sizeof(ControlFileData) is too large ... fix PG_CONTROL_SIZE\n"),
+				progname);
+		exit(1);
+	}
+
+	memset(buffer, 0, PG_CONTROL_SIZE);
+	memcpy(buffer, &ControlFile, sizeof(ControlFileData));
+
+	unlink(XLOG_CONTROL_FILE);
+
+	fd = open(XLOG_CONTROL_FILE,
+			  O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
+			  S_IRUSR | S_IWUSR);
+	if (fd < 0)
+	{
+		fprintf(stderr, _("%s: could not create pg_control file: %s\n"),
+				progname, strerror(errno));
+		exit(1);
+	}
+
+	errno = 0;
+	if (write(fd, buffer, PG_CONTROL_SIZE) != PG_CONTROL_SIZE)
+	{
+		/* if write didn't set errno, assume problem is no disk space */
+		if (errno == 0)
+			errno = ENOSPC;
+		fprintf(stderr, _("%s: could not write pg_control file: %s\n"),
+				progname, strerror(errno));
+		exit(1);
+	}
+
+	if (fsync(fd) != 0)
+	{
+		fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
+		exit(1);
+	}
+
+	close(fd);
+}
+
+
+/*
+ * Scan existing XLOG files and determine the highest existing WAL address
+ *
+ * On entry, ControlFile.checkPointCopy.redo and ControlFile.xlog_seg_size
+ * are assumed valid (note that we allow the old xlog seg size to differ
+ * from what we're using).  On exit, newXlogId and newXlogSeg are set to
+ * suitable values for the beginning of replacement WAL (in our seg size).
+ */
+XLogSegNo
+FindEndOfXLOG(ControlFileData *ControlFile)
+{
+	DIR		   *xldir;
+	struct dirent *xlde;
+	uint64		segs_per_xlogid;
+	uint64		xlogbytepos;
+	XLogSegNo	newXlogSegNo;
+
+	/*
+	 * Initialize the max() computation using the last checkpoint address from
+	 * old pg_control.  Note that for the moment we are working with segment
+	 * numbering according to the old xlog seg size.
+	 */
+	segs_per_xlogid = (UINT64CONST(0x0000000100000000) / ControlFile->xlog_seg_size);
+	newXlogSegNo = ControlFile->checkPointCopy.redo / ControlFile->xlog_seg_size;
+
+	/*
+	 * Scan the pg_xlog directory to find existing WAL segment files. We
+	 * assume any present have been used; in most scenarios this should be
+	 * conservative, because of xlog.c's attempts to pre-create files.
+	 */
+	xldir = opendir(XLOGDIR);
+	if (xldir == NULL)
+	{
+		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
+				progname, XLOGDIR, strerror(errno));
+		exit(1);
+	}
+
+	while (errno = 0, (xlde = readdir(xldir)) != NULL)
+	{
+		if (IsXLogFileName(xlde->d_name))
+		{
+			unsigned int tli,
+						log,
+						seg;
+			XLogSegNo	segno;
+
+			/*
+			 * Note: We don't use XLogFromFileName here, because we want to
+			 * use the segment size from the control file, not the size the
+			 * pg_resetxlog binary was compiled with
+			 */
+			sscanf(xlde->d_name, "%08X%08X%08X", &tli, &log, &seg);
+			segno = ((uint64) log) * segs_per_xlogid + seg;
+
+			/*
+			 * Note: we take the max of all files found, regardless of their
+			 * timelines.  Another possibility would be to ignore files of
+			 * timelines other than the target TLI, but this seems safer.
+			 * Better too large a result than too small...
+			 */
+			if (segno > newXlogSegNo)
+				newXlogSegNo = segno;
+		}
+	}
+
+	if (errno)
+	{
+		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
+				progname, XLOGDIR, strerror(errno));
+		exit(1);
+	}
+
+	if (closedir(xldir))
+	{
+		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
+				progname, XLOGDIR, strerror(errno));
+		exit(1);
+	}
+
+	/*
+	 * Finally, convert to new xlog seg size, and advance by one to ensure we
+	 * are in virgin territory.
+	 */
+	xlogbytepos = newXlogSegNo * ControlFile->xlog_seg_size;
+	newXlogSegNo = (xlogbytepos + XLogSegSize - 1) / XLogSegSize;
+	newXlogSegNo++;
+
+	return newXlogSegNo;
+}
+
+
+/*
+ * Remove existing XLOG files
+ */
+void
+KillExistingXLOG(void)
+{
+	DIR		   *xldir;
+	struct dirent *xlde;
+	char		path[MAXPGPATH];
+
+	xldir = opendir(XLOGDIR);
+	if (xldir == NULL)
+	{
+		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
+				progname, XLOGDIR, strerror(errno));
+		exit(1);
+	}
+
+	while (errno = 0, (xlde = readdir(xldir)) != NULL)
+	{
+		if (strlen(xlde->d_name) == 24 &&
+			strspn(xlde->d_name, "0123456789ABCDEF") == 24)
+		{
+			snprintf(path, MAXPGPATH, "%s/%s", XLOGDIR, xlde->d_name);
+			if (unlink(path) < 0)
+			{
+				fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
+						progname, path, strerror(errno));
+				exit(1);
+			}
+		}
+	}
+
+	if (errno)
+	{
+		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
+				progname, XLOGDIR, strerror(errno));
+		exit(1);
+	}
+
+	if (closedir(xldir))
+	{
+		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
+				progname, XLOGDIR, strerror(errno));
+		exit(1);
+	}
+}
+
+
+/*
+ * Remove existing archive status files
+ */
+void
+KillExistingArchiveStatus(void)
+{
+	DIR		   *xldir;
+	struct dirent *xlde;
+	char		path[MAXPGPATH];
+
+#define ARCHSTATDIR XLOGDIR "/archive_status"
+
+	xldir = opendir(ARCHSTATDIR);
+	if (xldir == NULL)
+	{
+		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
+				progname, ARCHSTATDIR, strerror(errno));
+		exit(1);
+	}
+
+	while (errno = 0, (xlde = readdir(xldir)) != NULL)
+	{
+		if (strspn(xlde->d_name, "0123456789ABCDEF") == 24 &&
+			(strcmp(xlde->d_name + 24, ".ready") == 0 ||
+			 strcmp(xlde->d_name + 24, ".done") == 0))
+		{
+			snprintf(path, MAXPGPATH, "%s/%s", ARCHSTATDIR, xlde->d_name);
+			if (unlink(path) < 0)
+			{
+				fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
+						progname, path, strerror(errno));
+				exit(1);
+			}
+		}
+	}
+
+	if (errno)
+	{
+		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
+				progname, ARCHSTATDIR, strerror(errno));
+		exit(1);
+	}
+
+	if (closedir(xldir))
+	{
+		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
+				progname, ARCHSTATDIR, strerror(errno));
+		exit(1);
+	}
+}
+
+
+/*
+ * Write an empty XLOG file, containing only the checkpoint record
+ * already set up in ControlFile.
+ */
+void
+WriteEmptyXLOG(ControlFileData *ControlFile)
+{
+	char	   *buffer;
+	XLogPageHeader page;
+	XLogLongPageHeader longpage;
+	XLogRecord *record;
+	pg_crc32c	crc;
+	char		path[MAXPGPATH];
+	int			fd;
+	int			nbytes;
+	char	   *recptr;
+
+	/* Use malloc() to ensure buffer is MAXALIGNED */
+	buffer = (char *) pg_malloc(XLOG_BLCKSZ);
+	page = (XLogPageHeader) buffer;
+	memset(buffer, 0, XLOG_BLCKSZ);
+
+	/* Set up the XLOG page header */
+	page->xlp_magic = XLOG_PAGE_MAGIC;
+	page->xlp_info = XLP_LONG_HEADER;
+	page->xlp_tli = ControlFile->checkPointCopy.ThisTimeLineID;
+	page->xlp_pageaddr = ControlFile->checkPointCopy.redo - SizeOfXLogLongPHD;
+	longpage = (XLogLongPageHeader) page;
+	longpage->xlp_sysid = ControlFile->system_identifier;
+	longpage->xlp_seg_size = XLogSegSize;
+	longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
+
+	/* Insert the initial checkpoint record */
+	recptr = (char *) page + SizeOfXLogLongPHD;
+	record = (XLogRecord *) recptr;
+	record->xl_prev = 0;
+	record->xl_xid = InvalidTransactionId;
+	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
+	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
+	record->xl_rmid = RM_XLOG_ID;
+
+	recptr += SizeOfXLogRecord;
+	*(recptr++) = XLR_BLOCK_ID_DATA_SHORT;
+	*(recptr++) = sizeof(CheckPoint);
+	memcpy(recptr, &ControlFile->checkPointCopy,
+		   sizeof(CheckPoint));
+
+	INIT_CRC32C(crc);
+	COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
+	COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
+	FIN_CRC32C(crc);
+	record->xl_crc = crc;
+
+	/* Write the first page */
+	XLogFilePath(path, ControlFile->checkPointCopy.ThisTimeLineID,
+				 ControlFile->checkPointCopy.redo);
+
+	unlink(path);
+
+	fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
+			  S_IRUSR | S_IWUSR);
+	if (fd < 0)
+	{
+		fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
+				progname, path, strerror(errno));
+		exit(1);
+	}
+
+	errno = 0;
+	if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
+	{
+		/* if write didn't set errno, assume problem is no disk space */
+		if (errno == 0)
+			errno = ENOSPC;
+		fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
+				progname, path, strerror(errno));
+		exit(1);
+	}
+
+	/* Fill the rest of the file with zeroes */
+	memset(buffer, 0, XLOG_BLCKSZ);
+	for (nbytes = XLOG_BLCKSZ; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
+	{
+		errno = 0;
+		if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
+		{
+			if (errno == 0)
+				errno = ENOSPC;
+			fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
+					progname, path, strerror(errno));
+			exit(1);
+		}
+	}
+
+	if (fsync(fd) != 0)
+	{
+		fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
+		exit(1);
+	}
+
+	close(fd);
+}
diff --git a/src/bin/pg_resetxlog/common.h b/src/bin/pg_resetxlog/common.h
new file mode 100644
index 0000000..74fe987
--- /dev/null
+++ b/src/bin/pg_resetxlog/common.h
@@ -0,0 +1,30 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+/*
+ * We have to use postgres.h not postgres_fe.h here, because there's so much
+ * backend-only stuff in the XLOG include files we need.  But we need a
+ * frontend-ish environment otherwise.  Hence this ugly hack.
+ */
+#define FRONTEND 1
+
+#include "postgres.h"
+
+#include "access/xlog_internal.h"
+
+#include "catalog/pg_control.h"
+
+/* For error messaging */
+extern const char *progname;
+
+extern uint64 GenerateSystemIdentifier(void);
+extern bool ReadControlFile(ControlFileData *ControlFile, bool *guessed);
+extern void GuessControlValues(ControlFileData *ControlFile);
+extern void PrintControlValues(ControlFileData *ControlFile, bool guessed);
+extern void RewriteControlFile(ControlFileData *ControlFile);
+extern XLogSegNo FindEndOfXLOG(ControlFileData *ControlFile);
+extern void KillExistingXLOG(void);
+extern void KillExistingArchiveStatus(void);
+extern void WriteEmptyXLOG(ControlFileData *ControlFile);
+
+#endif   /* COMMON_H */
diff --git a/src/bin/pg_resetxlog/nls.mk b/src/bin/pg_resetxlog/nls.mk
index cde0ed4..b753ace 100644
--- a/src/bin/pg_resetxlog/nls.mk
+++ b/src/bin/pg_resetxlog/nls.mk
@@ -1,4 +1,4 @@
 # src/bin/pg_resetxlog/nls.mk
 CATALOG_NAME     = pg_resetxlog
 AVAIL_LANGUAGES  = cs de es fr it ja pl pt_BR ru sv zh_CN
-GETTEXT_FILES    = pg_resetxlog.c ../../common/restricted_token.c
+GETTEXT_FILES    = common.c pg_resetxlog.c ../../common/restricted_token.c
diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c
index 6ffe795..2c061fa 100644
--- a/src/bin/pg_resetxlog/pg_resetxlog.c
+++ b/src/bin/pg_resetxlog/pg_resetxlog.c
@@ -28,14 +28,7 @@
  *-------------------------------------------------------------------------
  */
 
-/*
- * We have to use postgres.h not postgres_fe.h here, because there's so much
- * backend-only stuff in the XLOG include files we need.  But we need a
- * frontend-ish environment otherwise.  Hence this ugly hack.
- */
-#define FRONTEND 1
-
-#include "postgres.h"
+#include "common.h"
 
 #include <dirent.h>
 #include <fcntl.h>
@@ -48,10 +41,7 @@
 #include "access/transam.h"
 #include "access/tuptoaster.h"
 #include "access/multixact.h"
-#include "access/xlog.h"
-#include "access/xlog_internal.h"
 #include "catalog/catversion.h"
-#include "catalog/pg_control.h"
 #include "common/fe_memutils.h"
 #include "common/restricted_token.h"
 #include "storage/large_object.h"
@@ -60,10 +50,10 @@
 #include "replication/origin.h"
 
 
+const char *progname;
 static ControlFileData ControlFile;		/* pg_control values */
 static XLogSegNo newXlogSegNo;	/* new XLOG segment # */
 static bool guessed = false;	/* T if we had to guess at any values */
-static const char *progname;
 static uint32 set_xid_epoch = (uint32) -1;
 static TransactionId set_xid = 0;
 static TransactionId set_oldest_commit_ts = 0;
@@ -74,15 +64,7 @@ static MultiXactOffset set_mxoff = (MultiXactOffset) -1;
 static uint32 minXlogTli = 0;
 static XLogSegNo minXlogSegNo = 0;
 
-static bool ReadControlFile(void);
-static void GuessControlValues(void);
-static void PrintControlValues(bool guessed);
 static void PrintNewControlValues(void);
-static void RewriteControlFile(void);
-static void FindEndOfXLOG(void);
-static void KillExistingXLOG(void);
-static void KillExistingArchiveStatus(void);
-static void WriteEmptyXLOG(void);
 static void usage(void);
 
 
@@ -346,20 +328,20 @@ main(int argc, char *argv[])
 	/*
 	 * Attempt to read the existing pg_control file
 	 */
-	if (!ReadControlFile())
-		GuessControlValues();
+	if (!ReadControlFile(&ControlFile, &guessed))
+		GuessControlValues(&ControlFile);
 
 	/*
 	 * Also look at existing segment files to set up newXlogSegNo
 	 */
-	FindEndOfXLOG();
+	newXlogSegNo = FindEndOfXLOG(&ControlFile);
 
 	/*
 	 * If we're not going to proceed with the reset, print the current control
 	 * file parameters.
 	 */
 	if ((guessed && !force) || noupdate)
-		PrintControlValues(guessed);
+		PrintControlValues(&ControlFile, guessed);
 
 	/*
 	 * Adjust fields if required by switches.  (Do this now so that printout,
@@ -445,10 +427,12 @@ main(int argc, char *argv[])
 	/*
 	 * Else, do the dirty deed.
 	 */
-	RewriteControlFile();
+	XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD,
+							ControlFile.checkPointCopy.redo);
+	RewriteControlFile(&ControlFile);
 	KillExistingXLOG();
 	KillExistingArchiveStatus();
-	WriteEmptyXLOG();
+	WriteEmptyXLOG(&ControlFile);
 
 	printf(_("Transaction log reset\n"));
 	return 0;
@@ -456,252 +440,6 @@ main(int argc, char *argv[])
 
 
 /*
- * Try to read the existing pg_control file.
- *
- * This routine is also responsible for updating old pg_control versions
- * to the current format.  (Currently we don't do anything of the sort.)
- */
-static bool
-ReadControlFile(void)
-{
-	int			fd;
-	int			len;
-	char	   *buffer;
-	pg_crc32c	crc;
-
-	if ((fd = open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0)
-	{
-		/*
-		 * If pg_control is not there at all, or we can't read it, the odds
-		 * are we've been handed a bad DataDir path, so give up. User can do
-		 * "touch pg_control" to force us to proceed.
-		 */
-		fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
-				progname, XLOG_CONTROL_FILE, strerror(errno));
-		if (errno == ENOENT)
-			fprintf(stderr, _("If you are sure the data directory path is correct, execute\n"
-							  "  touch %s\n"
-							  "and try again.\n"),
-					XLOG_CONTROL_FILE);
-		exit(1);
-	}
-
-	/* Use malloc to ensure we have a maxaligned buffer */
-	buffer = (char *) pg_malloc(PG_CONTROL_SIZE);
-
-	len = read(fd, buffer, PG_CONTROL_SIZE);
-	if (len < 0)
-	{
-		fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
-				progname, XLOG_CONTROL_FILE, strerror(errno));
-		exit(1);
-	}
-	close(fd);
-
-	if (len >= sizeof(ControlFileData) &&
-	  ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
-	{
-		/* Check the CRC. */
-		INIT_CRC32C(crc);
-		COMP_CRC32C(crc,
-					buffer,
-					offsetof(ControlFileData, crc));
-		FIN_CRC32C(crc);
-
-		if (EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
-		{
-			/* Valid data... */
-			memcpy(&ControlFile, buffer, sizeof(ControlFile));
-			return true;
-		}
-
-		fprintf(stderr, _("%s: pg_control exists but has invalid CRC; proceed with caution\n"),
-				progname);
-		/* We will use the data anyway, but treat it as guessed. */
-		memcpy(&ControlFile, buffer, sizeof(ControlFile));
-		guessed = true;
-		return true;
-	}
-
-	/* Looks like it's a mess. */
-	fprintf(stderr, _("%s: pg_control exists but is broken or unknown version; ignoring it\n"),
-			progname);
-	return false;
-}
-
-
-/*
- * Guess at pg_control values when we can't read the old ones.
- */
-static void
-GuessControlValues(void)
-{
-	uint64		sysidentifier;
-	struct timeval tv;
-
-	/*
-	 * Set up a completely default set of pg_control values.
-	 */
-	guessed = true;
-	memset(&ControlFile, 0, sizeof(ControlFile));
-
-	ControlFile.pg_control_version = PG_CONTROL_VERSION;
-	ControlFile.catalog_version_no = CATALOG_VERSION_NO;
-
-	/*
-	 * Create a new unique installation identifier, since we can no longer use
-	 * any old XLOG records.  See notes in xlog.c about the algorithm.
-	 */
-	gettimeofday(&tv, NULL);
-	sysidentifier = ((uint64) tv.tv_sec) << 32;
-	sysidentifier |= ((uint64) tv.tv_usec) << 12;
-	sysidentifier |= getpid() & 0xFFF;
-
-	ControlFile.system_identifier = sysidentifier;
-
-	ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
-	ControlFile.checkPointCopy.ThisTimeLineID = 1;
-	ControlFile.checkPointCopy.PrevTimeLineID = 1;
-	ControlFile.checkPointCopy.fullPageWrites = false;
-	ControlFile.checkPointCopy.nextXidEpoch = 0;
-	ControlFile.checkPointCopy.nextXid = FirstNormalTransactionId;
-	ControlFile.checkPointCopy.nextOid = FirstBootstrapObjectId;
-	ControlFile.checkPointCopy.nextMulti = FirstMultiXactId;
-	ControlFile.checkPointCopy.nextMultiOffset = 0;
-	ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId;
-	ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
-	ControlFile.checkPointCopy.oldestMulti = FirstMultiXactId;
-	ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
-	ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
-	ControlFile.checkPointCopy.oldestActiveXid = InvalidTransactionId;
-
-	ControlFile.state = DB_SHUTDOWNED;
-	ControlFile.time = (pg_time_t) time(NULL);
-	ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
-	ControlFile.unloggedLSN = 1;
-
-	/* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */
-
-	ControlFile.wal_level = WAL_LEVEL_MINIMAL;
-	ControlFile.wal_log_hints = false;
-	ControlFile.track_commit_timestamp = false;
-	ControlFile.MaxConnections = 100;
-	ControlFile.max_worker_processes = 8;
-	ControlFile.max_prepared_xacts = 0;
-	ControlFile.max_locks_per_xact = 64;
-
-	ControlFile.maxAlign = MAXIMUM_ALIGNOF;
-	ControlFile.floatFormat = FLOATFORMAT_VALUE;
-	ControlFile.blcksz = BLCKSZ;
-	ControlFile.relseg_size = RELSEG_SIZE;
-	ControlFile.xlog_blcksz = XLOG_BLCKSZ;
-	ControlFile.xlog_seg_size = XLOG_SEG_SIZE;
-	ControlFile.nameDataLen = NAMEDATALEN;
-	ControlFile.indexMaxKeys = INDEX_MAX_KEYS;
-	ControlFile.toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE;
-	ControlFile.loblksize = LOBLKSIZE;
-#ifdef HAVE_INT64_TIMESTAMP
-	ControlFile.enableIntTimes = true;
-#else
-	ControlFile.enableIntTimes = false;
-#endif
-	ControlFile.float4ByVal = FLOAT4PASSBYVAL;
-	ControlFile.float8ByVal = FLOAT8PASSBYVAL;
-
-	/*
-	 * XXX eventually, should try to grovel through old XLOG to develop more
-	 * accurate values for TimeLineID, nextXID, etc.
-	 */
-}
-
-
-/*
- * Print the guessed pg_control values when we had to guess.
- *
- * NB: this display should be just those fields that will not be
- * reset by RewriteControlFile().
- */
-static void
-PrintControlValues(bool guessed)
-{
-	char		sysident_str[32];
-
-	if (guessed)
-		printf(_("Guessed pg_control values:\n\n"));
-	else
-		printf(_("Current pg_control values:\n\n"));
-
-	/*
-	 * Format system_identifier separately to keep platform-dependent format
-	 * code out of the translatable message string.
-	 */
-	snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
-			 ControlFile.system_identifier);
-
-	printf(_("pg_control version number:            %u\n"),
-		   ControlFile.pg_control_version);
-	printf(_("Catalog version number:               %u\n"),
-		   ControlFile.catalog_version_no);
-	printf(_("Database system identifier:           %s\n"),
-		   sysident_str);
-	printf(_("Latest checkpoint's TimeLineID:       %u\n"),
-		   ControlFile.checkPointCopy.ThisTimeLineID);
-	printf(_("Latest checkpoint's full_page_writes: %s\n"),
-		   ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
-	printf(_("Latest checkpoint's NextXID:          %u/%u\n"),
-		   ControlFile.checkPointCopy.nextXidEpoch,
-		   ControlFile.checkPointCopy.nextXid);
-	printf(_("Latest checkpoint's NextOID:          %u\n"),
-		   ControlFile.checkPointCopy.nextOid);
-	printf(_("Latest checkpoint's NextMultiXactId:  %u\n"),
-		   ControlFile.checkPointCopy.nextMulti);
-	printf(_("Latest checkpoint's NextMultiOffset:  %u\n"),
-		   ControlFile.checkPointCopy.nextMultiOffset);
-	printf(_("Latest checkpoint's oldestXID:        %u\n"),
-		   ControlFile.checkPointCopy.oldestXid);
-	printf(_("Latest checkpoint's oldestXID's DB:   %u\n"),
-		   ControlFile.checkPointCopy.oldestXidDB);
-	printf(_("Latest checkpoint's oldestActiveXID:  %u\n"),
-		   ControlFile.checkPointCopy.oldestActiveXid);
-	printf(_("Latest checkpoint's oldestMultiXid:   %u\n"),
-		   ControlFile.checkPointCopy.oldestMulti);
-	printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
-		   ControlFile.checkPointCopy.oldestMultiDB);
-	printf(_("Latest checkpoint's oldest CommitTs:  %u\n"),
-		   ControlFile.checkPointCopy.oldestCommitTs);
-	printf(_("Latest checkpoint's newest CommitTs:  %u\n"),
-		   ControlFile.checkPointCopy.newestCommitTs);
-	printf(_("Maximum data alignment:               %u\n"),
-		   ControlFile.maxAlign);
-	/* we don't print floatFormat since can't say much useful about it */
-	printf(_("Database block size:                  %u\n"),
-		   ControlFile.blcksz);
-	printf(_("Blocks per segment of large relation: %u\n"),
-		   ControlFile.relseg_size);
-	printf(_("WAL block size:                       %u\n"),
-		   ControlFile.xlog_blcksz);
-	printf(_("Bytes per WAL segment:                %u\n"),
-		   ControlFile.xlog_seg_size);
-	printf(_("Maximum length of identifiers:        %u\n"),
-		   ControlFile.nameDataLen);
-	printf(_("Maximum columns in an index:          %u\n"),
-		   ControlFile.indexMaxKeys);
-	printf(_("Maximum size of a TOAST chunk:        %u\n"),
-		   ControlFile.toast_max_chunk_size);
-	printf(_("Size of a large-object chunk:         %u\n"),
-		   ControlFile.loblksize);
-	printf(_("Date/time type storage:               %s\n"),
-		   (ControlFile.enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
-	printf(_("Float4 argument passing:              %s\n"),
-		   (ControlFile.float4ByVal ? _("by value") : _("by reference")));
-	printf(_("Float8 argument passing:              %s\n"),
-		   (ControlFile.float8ByVal ? _("by value") : _("by reference")));
-	printf(_("Data page checksum version:           %u\n"),
-		   ControlFile.data_checksum_version);
-}
-
-
-/*
  * Print the values to be changed.
  */
 static void
@@ -766,400 +504,6 @@ PrintNewControlValues()
 }
 
 
-/*
- * Write out the new pg_control file.
- */
-static void
-RewriteControlFile(void)
-{
-	int			fd;
-	char		buffer[PG_CONTROL_SIZE];		/* need not be aligned */
-
-	/*
-	 * Adjust fields as needed to force an empty XLOG starting at
-	 * newXlogSegNo.
-	 */
-	XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD,
-							ControlFile.checkPointCopy.redo);
-	ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
-
-	ControlFile.state = DB_SHUTDOWNED;
-	ControlFile.time = (pg_time_t) time(NULL);
-	ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
-	ControlFile.prevCheckPoint = 0;
-	ControlFile.minRecoveryPoint = 0;
-	ControlFile.minRecoveryPointTLI = 0;
-	ControlFile.backupStartPoint = 0;
-	ControlFile.backupEndPoint = 0;
-	ControlFile.backupEndRequired = false;
-
-	/*
-	 * Force the defaults for max_* settings. The values don't really matter
-	 * as long as wal_level='minimal'; the postmaster will reset these fields
-	 * anyway at startup.
-	 */
-	ControlFile.wal_level = WAL_LEVEL_MINIMAL;
-	ControlFile.wal_log_hints = false;
-	ControlFile.track_commit_timestamp = false;
-	ControlFile.MaxConnections = 100;
-	ControlFile.max_worker_processes = 8;
-	ControlFile.max_prepared_xacts = 0;
-	ControlFile.max_locks_per_xact = 64;
-
-	/* Now we can force the recorded xlog seg size to the right thing. */
-	ControlFile.xlog_seg_size = XLogSegSize;
-
-	/* Contents are protected with a CRC */
-	INIT_CRC32C(ControlFile.crc);
-	COMP_CRC32C(ControlFile.crc,
-				(char *) &ControlFile,
-				offsetof(ControlFileData, crc));
-	FIN_CRC32C(ControlFile.crc);
-
-	/*
-	 * We write out PG_CONTROL_SIZE bytes into pg_control, zero-padding the
-	 * excess over sizeof(ControlFileData).  This reduces the odds of
-	 * premature-EOF errors when reading pg_control.  We'll still fail when we
-	 * check the contents of the file, but hopefully with a more specific
-	 * error than "couldn't read pg_control".
-	 */
-	if (sizeof(ControlFileData) > PG_CONTROL_SIZE)
-	{
-		fprintf(stderr,
-				_("%s: internal error -- sizeof(ControlFileData) is too large ... fix PG_CONTROL_SIZE\n"),
-				progname);
-		exit(1);
-	}
-
-	memset(buffer, 0, PG_CONTROL_SIZE);
-	memcpy(buffer, &ControlFile, sizeof(ControlFileData));
-
-	unlink(XLOG_CONTROL_FILE);
-
-	fd = open(XLOG_CONTROL_FILE,
-			  O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
-			  S_IRUSR | S_IWUSR);
-	if (fd < 0)
-	{
-		fprintf(stderr, _("%s: could not create pg_control file: %s\n"),
-				progname, strerror(errno));
-		exit(1);
-	}
-
-	errno = 0;
-	if (write(fd, buffer, PG_CONTROL_SIZE) != PG_CONTROL_SIZE)
-	{
-		/* if write didn't set errno, assume problem is no disk space */
-		if (errno == 0)
-			errno = ENOSPC;
-		fprintf(stderr, _("%s: could not write pg_control file: %s\n"),
-				progname, strerror(errno));
-		exit(1);
-	}
-
-	if (fsync(fd) != 0)
-	{
-		fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
-		exit(1);
-	}
-
-	close(fd);
-}
-
-
-/*
- * Scan existing XLOG files and determine the highest existing WAL address
- *
- * On entry, ControlFile.checkPointCopy.redo and ControlFile.xlog_seg_size
- * are assumed valid (note that we allow the old xlog seg size to differ
- * from what we're using).  On exit, newXlogId and newXlogSeg are set to
- * suitable values for the beginning of replacement WAL (in our seg size).
- */
-static void
-FindEndOfXLOG(void)
-{
-	DIR		   *xldir;
-	struct dirent *xlde;
-	uint64		segs_per_xlogid;
-	uint64		xlogbytepos;
-
-	/*
-	 * Initialize the max() computation using the last checkpoint address from
-	 * old pg_control.  Note that for the moment we are working with segment
-	 * numbering according to the old xlog seg size.
-	 */
-	segs_per_xlogid = (UINT64CONST(0x0000000100000000) / ControlFile.xlog_seg_size);
-	newXlogSegNo = ControlFile.checkPointCopy.redo / ControlFile.xlog_seg_size;
-
-	/*
-	 * Scan the pg_xlog directory to find existing WAL segment files. We
-	 * assume any present have been used; in most scenarios this should be
-	 * conservative, because of xlog.c's attempts to pre-create files.
-	 */
-	xldir = opendir(XLOGDIR);
-	if (xldir == NULL)
-	{
-		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
-		exit(1);
-	}
-
-	while (errno = 0, (xlde = readdir(xldir)) != NULL)
-	{
-		if (IsXLogFileName(xlde->d_name))
-		{
-			unsigned int tli,
-						log,
-						seg;
-			XLogSegNo	segno;
-
-			/*
-			 * Note: We don't use XLogFromFileName here, because we want to
-			 * use the segment size from the control file, not the size the
-			 * pg_resetxlog binary was compiled with
-			 */
-			sscanf(xlde->d_name, "%08X%08X%08X", &tli, &log, &seg);
-			segno = ((uint64) log) * segs_per_xlogid + seg;
-
-			/*
-			 * Note: we take the max of all files found, regardless of their
-			 * timelines.  Another possibility would be to ignore files of
-			 * timelines other than the target TLI, but this seems safer.
-			 * Better too large a result than too small...
-			 */
-			if (segno > newXlogSegNo)
-				newXlogSegNo = segno;
-		}
-	}
-
-	if (errno)
-	{
-		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
-		exit(1);
-	}
-
-	if (closedir(xldir))
-	{
-		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
-		exit(1);
-	}
-
-	/*
-	 * Finally, convert to new xlog seg size, and advance by one to ensure we
-	 * are in virgin territory.
-	 */
-	xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
-	newXlogSegNo = (xlogbytepos + XLogSegSize - 1) / XLogSegSize;
-	newXlogSegNo++;
-}
-
-
-/*
- * Remove existing XLOG files
- */
-static void
-KillExistingXLOG(void)
-{
-	DIR		   *xldir;
-	struct dirent *xlde;
-	char		path[MAXPGPATH];
-
-	xldir = opendir(XLOGDIR);
-	if (xldir == NULL)
-	{
-		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
-		exit(1);
-	}
-
-	while (errno = 0, (xlde = readdir(xldir)) != NULL)
-	{
-		if (strlen(xlde->d_name) == 24 &&
-			strspn(xlde->d_name, "0123456789ABCDEF") == 24)
-		{
-			snprintf(path, MAXPGPATH, "%s/%s", XLOGDIR, xlde->d_name);
-			if (unlink(path) < 0)
-			{
-				fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
-						progname, path, strerror(errno));
-				exit(1);
-			}
-		}
-	}
-
-	if (errno)
-	{
-		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
-		exit(1);
-	}
-
-	if (closedir(xldir))
-	{
-		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
-				progname, XLOGDIR, strerror(errno));
-		exit(1);
-	}
-}
-
-
-/*
- * Remove existing archive status files
- */
-static void
-KillExistingArchiveStatus(void)
-{
-	DIR		   *xldir;
-	struct dirent *xlde;
-	char		path[MAXPGPATH];
-
-#define ARCHSTATDIR XLOGDIR "/archive_status"
-
-	xldir = opendir(ARCHSTATDIR);
-	if (xldir == NULL)
-	{
-		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
-				progname, ARCHSTATDIR, strerror(errno));
-		exit(1);
-	}
-
-	while (errno = 0, (xlde = readdir(xldir)) != NULL)
-	{
-		if (strspn(xlde->d_name, "0123456789ABCDEF") == 24 &&
-			(strcmp(xlde->d_name + 24, ".ready") == 0 ||
-			 strcmp(xlde->d_name + 24, ".done") == 0))
-		{
-			snprintf(path, MAXPGPATH, "%s/%s", ARCHSTATDIR, xlde->d_name);
-			if (unlink(path) < 0)
-			{
-				fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
-						progname, path, strerror(errno));
-				exit(1);
-			}
-		}
-	}
-
-	if (errno)
-	{
-		fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
-				progname, ARCHSTATDIR, strerror(errno));
-		exit(1);
-	}
-
-	if (closedir(xldir))
-	{
-		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
-				progname, ARCHSTATDIR, strerror(errno));
-		exit(1);
-	}
-}
-
-
-/*
- * Write an empty XLOG file, containing only the checkpoint record
- * already set up in ControlFile.
- */
-static void
-WriteEmptyXLOG(void)
-{
-	char	   *buffer;
-	XLogPageHeader page;
-	XLogLongPageHeader longpage;
-	XLogRecord *record;
-	pg_crc32c	crc;
-	char		path[MAXPGPATH];
-	int			fd;
-	int			nbytes;
-	char	   *recptr;
-
-	/* Use malloc() to ensure buffer is MAXALIGNED */
-	buffer = (char *) pg_malloc(XLOG_BLCKSZ);
-	page = (XLogPageHeader) buffer;
-	memset(buffer, 0, XLOG_BLCKSZ);
-
-	/* Set up the XLOG page header */
-	page->xlp_magic = XLOG_PAGE_MAGIC;
-	page->xlp_info = XLP_LONG_HEADER;
-	page->xlp_tli = ControlFile.checkPointCopy.ThisTimeLineID;
-	page->xlp_pageaddr = ControlFile.checkPointCopy.redo - SizeOfXLogLongPHD;
-	longpage = (XLogLongPageHeader) page;
-	longpage->xlp_sysid = ControlFile.system_identifier;
-	longpage->xlp_seg_size = XLogSegSize;
-	longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
-
-	/* Insert the initial checkpoint record */
-	recptr = (char *) page + SizeOfXLogLongPHD;
-	record = (XLogRecord *) recptr;
-	record->xl_prev = 0;
-	record->xl_xid = InvalidTransactionId;
-	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
-	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
-	record->xl_rmid = RM_XLOG_ID;
-
-	recptr += SizeOfXLogRecord;
-	*(recptr++) = XLR_BLOCK_ID_DATA_SHORT;
-	*(recptr++) = sizeof(CheckPoint);
-	memcpy(recptr, &ControlFile.checkPointCopy,
-		   sizeof(CheckPoint));
-
-	INIT_CRC32C(crc);
-	COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
-	COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
-	FIN_CRC32C(crc);
-	record->xl_crc = crc;
-
-	/* Write the first page */
-	XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID, newXlogSegNo);
-
-	unlink(path);
-
-	fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
-			  S_IRUSR | S_IWUSR);
-	if (fd < 0)
-	{
-		fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
-				progname, path, strerror(errno));
-		exit(1);
-	}
-
-	errno = 0;
-	if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
-	{
-		/* if write didn't set errno, assume problem is no disk space */
-		if (errno == 0)
-			errno = ENOSPC;
-		fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
-				progname, path, strerror(errno));
-		exit(1);
-	}
-
-	/* Fill the rest of the file with zeroes */
-	memset(buffer, 0, XLOG_BLCKSZ);
-	for (nbytes = XLOG_BLCKSZ; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
-	{
-		errno = 0;
-		if (write(fd, buffer, XLOG_BLCKSZ) != XLOG_BLCKSZ)
-		{
-			if (errno == 0)
-				errno = ENOSPC;
-			fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
-					progname, path, strerror(errno));
-			exit(1);
-		}
-	}
-
-	if (fsync(fd) != 0)
-	{
-		fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
-		exit(1);
-	}
-
-	close(fd);
-}
-
-
 static void
 usage(void)
 {
-- 
1.9.1

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to