diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index f9eea76..c03b59f 100644
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
*************** SELECT collation for ('foo' COLLATE "de_
*** 16674,16679 ****
--- 16674,16789 ----
      </tgroup>
     </table>
  
+    <para>
+     The functions shown in <xref linkend="functions-controldata">
+     print information initialized during <command>initdb</>, such
+     as the catalog version. They also show information about write-ahead
+     logging and checkpoint processing. This information is cluster-wide,
+     and not specific to any one database. They provide most of the same
+     information, from the same source, as
+     <xref linkend="APP-PGCONTROLDATA">, although in a form better suited
+     to <acronym>SQL</acronym> functions.
+    </para>
+ 
+    <table id="functions-controldata">
+     <title>Control Data Functions</title>
+     <tgroup cols="3">
+      <thead>
+       <row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry></row>
+      </thead>
+ 
+      <tbody>
+       <row>
+        <entry>
+         <indexterm><primary>pg_checkpoint_state</primary></indexterm>
+         <literal><function>pg_checkpoint_state()</function></literal>
+        </entry>
+        <entry><type>record</type></entry>
+        <entry>
+         Returns information about current checkpoint state.
+        </entry>
+       </row>
+ 
+       <row>
+        <entry>
+         <indexterm><primary>pg_controldata_state</primary></indexterm>
+         <literal><function>pg_controldata_state()</function></literal>
+        </entry>
+        <entry><type>record</type></entry>
+        <entry>
+         Returns information about current controldata file state.
+        </entry>
+       </row>
+ 
+       <row>
+        <entry>
+         <indexterm><primary>pg_init_state</primary></indexterm>
+         <literal><function>pg_init_state()</function></literal>
+        </entry>
+        <entry><type>record</type></entry>
+        <entry>
+         Returns information about cluster initialization state.
+        </entry>
+       </row>
+ 
+       <row>
+        <entry>
+         <indexterm><primary>pg_recovery_state</primary></indexterm>
+         <literal><function>pg_recovery_state()</function></literal>
+        </entry>
+        <entry><type>record</type></entry>
+        <entry>
+         Returns information about recovery state.
+        </entry>
+       </row>
+ 
+      </tbody>
+     </tgroup>
+    </table>
+ 
+    <indexterm>
+     <primary>pg_checkpoint_state</primary>
+    </indexterm>
+    <para>
+     <function>pg_checkpoint_state</> returns a record containing
+     checkpoint_location, prior_location, redo_location, redo_wal_file,
+     timeline_id, prev_timeline_id, full_page_writes, next_xid, next_oid,
+     next_multixact_id, next_multi_offset, oldest_xid, oldest_xid_dbid,
+     oldest_active_xid, oldest_multi_xid, oldest_multi_dbid,
+     oldest_commit_ts_xid, newest_commit_ts_xid, and checkpoint_time.
+    </para>
+ 
+    <indexterm>
+     <primary>pg_controldata_state</primary>
+    </indexterm>
+    <para>
+     <function>pg_controldata_state</> returns a record containing
+     pg_control_version, catalog_version_no, system_identifier, and
+     pg_control_last_modified.
+    </para>
+ 
+    <indexterm>
+     <primary>pg_init_state</primary>
+    </indexterm>
+    <para>
+     <function>pg_init_state</> returns a record containing
+     max_data_alignment, database_block_size, blocks_per_segment,
+     wal_block_size, bytes_per_wal_segment, max_identifier_length,
+     max_index_columns, max_toast_chunk_size, large_object_chunk_size,
+     bigint_timestamps, float4_pass_by_value, float8_pass_by_value, and
+     data_page_checksum_version.
+    </para>
+ 
+    <indexterm>
+     <primary>pg_recovery_state</primary>
+    </indexterm>
+    <para>
+     <function>pg_recovery_state</> returns a record containing
+     min_recovery_end_location, min_recovery_end_timeline,
+     backup_start_location, backup_end_location, and
+     end_of_backup_record_required.
+    </para>
+ 
    </sect1>
  
    <sect1 id="functions-admin">
diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile
index a0c82c1..a5b487d 100644
*** a/src/backend/utils/misc/Makefile
--- b/src/backend/utils/misc/Makefile
*************** include $(top_builddir)/src/Makefile.glo
*** 14,20 ****
  
  override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
  
! OBJS = guc.o help_config.o pg_config.o pg_rusage.o \
         ps_status.o rls.o sampling.o superuser.o timeout.o tzparser.o
  
  # This location might depend on the installation directories. Therefore
--- 14,20 ----
  
  override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
  
! OBJS = guc.o help_config.o pg_config.o pg_controldata.o pg_rusage.o \
         ps_status.o rls.o sampling.o superuser.o timeout.o tzparser.o
  
  # This location might depend on the installation directories. Therefore
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index ...489bf67 .
*** a/src/backend/utils/misc/pg_controldata.c
--- b/src/backend/utils/misc/pg_controldata.c
***************
*** 0 ****
--- 1,358 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_controldata.c
+  *		Expose select pg_controldata output, except via SQL functions
+  *
+  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * IDENTIFICATION
+  *	  src/backend/utils/misc/pg_controldata.c
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "postgres.h"
+ 
+ #include "funcapi.h"
+ #include "miscadmin.h"
+ #include "access/htup_details.h"
+ #include "access/xlog_internal.h"
+ #include "catalog/pg_control.h"
+ #include "catalog/pg_type.h"
+ #include "common/controldata_utils.h"
+ #include "utils/builtins.h"
+ #include "utils/pg_lsn.h"
+ #include "utils/timestamp.h"
+ 
+ extern ControlData *controldata;
+ 
+ Datum
+ pg_controldata_state(PG_FUNCTION_ARGS)
+ {
+ 	Datum				values[4];
+ 	bool				nulls[4];
+ 	TupleDesc			tupdesc;
+ 	HeapTuple			htup;
+ 	ControlFileData	   *ControlFile;
+ 
+ 	/*
+ 	 * Construct a tuple descriptor for the result row.  This must match this
+ 	 * function's pg_proc entry!
+ 	 */
+ 	tupdesc = CreateTemplateTupleDesc(4, false);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "pg_control_version",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "catalog_version_no",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "system_identifier",
+ 					   INT8OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pg_control_last_modified",
+ 					   TIMESTAMPTZOID, -1, 0);
+ 	tupdesc = BlessTupleDesc(tupdesc);
+ 
+ 	/* read the control file */
+ 	ControlFile = get_controlfile(DataDir, NULL);
+ 
+ 	if (ControlFile->pg_control_version % 65536 == 0 &&
+ 		ControlFile->pg_control_version / 65536 != 0)
+ 		elog(ERROR, _("byte ordering mismatch"));
+ 
+ 	values[0] = Int32GetDatum(ControlFile->pg_control_version);
+ 	nulls[0] = false;
+ 
+ 	values[1] = Int32GetDatum(ControlFile->catalog_version_no);
+ 	nulls[1] = false;
+ 
+ 	values[2] = Int64GetDatum(ControlFile->system_identifier);
+ 	nulls[2] = false;
+ 
+ 	values[3] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->time));
+ 	nulls[3] = false;
+ 
+ 	htup = heap_form_tuple(tupdesc, values, nulls);
+ 
+ 	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+ }
+ 
+ Datum
+ pg_checkpoint_state(PG_FUNCTION_ARGS)
+ {
+ 	Datum				values[19];
+ 	bool				nulls[19];
+ 	TupleDesc			tupdesc;
+ 	HeapTuple			htup;
+ 	ControlFileData	   *ControlFile;
+ 	XLogSegNo			segno;
+ 	char				xlogfilename[MAXFNAMELEN];
+ 
+ 	/*
+ 	 * Construct a tuple descriptor for the result row.  This must match this
+ 	 * function's pg_proc entry!
+ 	 */
+ 	tupdesc = CreateTemplateTupleDesc(19, false);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "checkpoint_location",
+ 					   LSNOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "prior_location",
+ 					   LSNOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "redo_location",
+ 					   LSNOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "redo_wal_file",
+ 					   TEXTOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 5, "timeline_id",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 6, "prev_timeline_id",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 7, "full_page_writes",
+ 					   BOOLOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 8, "next_xid",
+ 					   TEXTOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 9, "next_oid",
+ 					   OIDOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 10, "next_multixact_id",
+ 					   XIDOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 11, "next_multi_offset",
+ 					   XIDOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 12, "oldest_xid",
+ 					   XIDOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 13, "oldest_xid_dbid",
+ 					   OIDOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 14, "oldest_active_xid",
+ 					   XIDOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 15, "oldest_multi_xid",
+ 					   XIDOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 16, "oldest_multi_dbid",
+ 					   OIDOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 17, "oldest_commit_ts_xid",
+ 					   XIDOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 18, "newest_commit_ts_xid",
+ 					   XIDOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 19, "checkpoint_time",
+ 					   TIMESTAMPTZOID, -1, 0);
+ 	tupdesc = BlessTupleDesc(tupdesc);
+ 
+ 	/* Read the control file. */
+ 	ControlFile = get_controlfile(DataDir, NULL);
+ 
+ 	/* Make sure it is valid. */
+ 	if (ControlFile->pg_control_version % 65536 == 0 &&
+ 		ControlFile->pg_control_version / 65536 != 0)
+ 		elog(ERROR, _("byte ordering mismatch"));
+ 
+ 	/*
+ 	 * Calculate name of the WAL file containing the latest checkpoint's REDO
+ 	 * start point.
+ 	 */
+ 	XLByteToSeg(ControlFile->checkPointCopy.redo, segno);
+ 	XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID, segno);
+ 
+ 	/* Populate the values and null arrays */
+ 	values[0] = LSNGetDatum(ControlFile->checkPoint);
+ 	nulls[0] = false;
+ 
+ 	values[1] = LSNGetDatum(ControlFile->prevCheckPoint);
+ 	nulls[1] = false;
+ 
+ 	values[2] = LSNGetDatum(ControlFile->checkPointCopy.redo);
+ 	nulls[2] = false;
+ 
+ 	values[3] = CStringGetTextDatum(xlogfilename);
+ 	nulls[3] = false;
+ 
+ 	values[4] = Int32GetDatum(ControlFile->checkPointCopy.ThisTimeLineID);
+ 	nulls[4] = false;
+ 
+ 	values[5] = Int32GetDatum(ControlFile->checkPointCopy.PrevTimeLineID);
+ 	nulls[5] = false;
+ 
+ 	values[6] = BoolGetDatum(ControlFile->checkPointCopy.fullPageWrites);
+ 	nulls[6] = false;
+ 
+ 	values[7] = CStringGetTextDatum(psprintf("%u:%u",
+ 								ControlFile->checkPointCopy.nextXidEpoch,
+ 								ControlFile->checkPointCopy.nextXid));
+ 	nulls[7] = false;
+ 
+ 	values[8] = ObjectIdGetDatum(ControlFile->checkPointCopy.nextOid);
+ 	nulls[8] = false;
+ 
+ 	values[9] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMulti);
+ 	nulls[9] = false;
+ 
+ 	values[10] = TransactionIdGetDatum(ControlFile->checkPointCopy.nextMultiOffset);
+ 	nulls[10] = false;
+ 
+ 	values[11] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestXid);
+ 	nulls[11] = false;
+ 
+ 	values[12] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestXidDB);
+ 	nulls[12] = false;
+ 
+ 	values[13] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestActiveXid);
+ 	nulls[13] = false;
+ 
+ 	values[14] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestMulti);
+ 	nulls[14] = false;
+ 
+ 	values[15] = ObjectIdGetDatum(ControlFile->checkPointCopy.oldestMultiDB);
+ 	nulls[15] = false;
+ 
+ 	values[16] = TransactionIdGetDatum(ControlFile->checkPointCopy.oldestCommitTsXid);
+ 	nulls[16] = false;
+ 
+ 	values[17] = TransactionIdGetDatum(ControlFile->checkPointCopy.newestCommitTsXid);
+ 	nulls[17] = false;
+ 
+ 	values[18] = TimestampTzGetDatum(
+ 					time_t_to_timestamptz(ControlFile->checkPointCopy.time));
+ 	nulls[18] = false;
+ 
+ 	htup = heap_form_tuple(tupdesc, values, nulls);
+ 
+ 	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+ }
+ 
+ Datum
+ pg_recovery_state(PG_FUNCTION_ARGS)
+ {
+ 	Datum				values[5];
+ 	bool				nulls[5];
+ 	TupleDesc			tupdesc;
+ 	HeapTuple			htup;
+ 	ControlFileData	   *ControlFile;
+ 
+ 	/*
+ 	 * Construct a tuple descriptor for the result row.  This must match this
+ 	 * function's pg_proc entry!
+ 	 */
+ 	tupdesc = CreateTemplateTupleDesc(5, false);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "min_recovery_end_location",
+ 					   LSNOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "min_recovery_end_timeline",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "backup_start_location",
+ 					   LSNOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "backup_end_location",
+ 					   LSNOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 5, "end_of_backup_record_required",
+ 					   BOOLOID, -1, 0);
+ 	tupdesc = BlessTupleDesc(tupdesc);
+ 
+ 	/* read the control file */
+ 	ControlFile = get_controlfile(DataDir, NULL);
+ 
+ 	if (ControlFile->pg_control_version % 65536 == 0 &&
+ 		ControlFile->pg_control_version / 65536 != 0)
+ 		elog(ERROR, _("byte ordering mismatch"));
+ 
+ 	values[0] = LSNGetDatum(ControlFile->minRecoveryPoint);
+ 	nulls[0] = false;
+ 
+ 	values[1] = Int32GetDatum(ControlFile->minRecoveryPointTLI);
+ 	nulls[1] = false;
+ 
+ 	values[2] = LSNGetDatum(ControlFile->backupStartPoint);
+ 	nulls[2] = false;
+ 
+ 	values[3] = LSNGetDatum(ControlFile->backupEndPoint);
+ 	nulls[3] = false;
+ 
+ 	values[4] = BoolGetDatum(ControlFile->backupEndRequired);
+ 	nulls[4] = false;
+ 
+ 	htup = heap_form_tuple(tupdesc, values, nulls);
+ 
+ 	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+ }
+ 
+ Datum
+ pg_init_state(PG_FUNCTION_ARGS)
+ {
+ 	Datum				values[13];
+ 	bool				nulls[13];
+ 	TupleDesc			tupdesc;
+ 	HeapTuple			htup;
+ 	ControlFileData	   *ControlFile;
+ 
+ 	/*
+ 	 * Construct a tuple descriptor for the result row.  This must match this
+ 	 * function's pg_proc entry!
+ 	 */
+ 	tupdesc = CreateTemplateTupleDesc(13, false);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "max_data_alignment",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database_block_size",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "blocks_per_segment",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_block_size",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 5, "bytes_per_wal_segment",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 6, "max_identifier_length",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 7, "max_index_columns",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 8, "max_toast_chunk_size",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 9, "large_object_chunk_size",
+ 					   INT4OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 10, "bigint_timestamps",
+ 					   BOOLOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 11, "float4_pass_by_value",
+ 					   BOOLOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 12, "float8_pass_by_value",
+ 					   BOOLOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 13, "data_page_checksum_version",
+ 					   INT4OID, -1, 0);
+ 	tupdesc = BlessTupleDesc(tupdesc);
+ 
+ 	/* read the control file */
+ 	ControlFile = get_controlfile(DataDir, NULL);
+ 
+ 	if (ControlFile->pg_control_version % 65536 == 0 &&
+ 		ControlFile->pg_control_version / 65536 != 0)
+ 		elog(ERROR, _("byte ordering mismatch"));
+ 
+ 	values[0] = Int32GetDatum(ControlFile->maxAlign);
+ 	nulls[0] = false;
+ 
+ 	values[1] = Int32GetDatum(ControlFile->blcksz);
+ 	nulls[1] = false;
+ 
+ 	values[2] = Int32GetDatum(ControlFile->relseg_size);
+ 	nulls[2] = false;
+ 
+ 	values[3] = Int32GetDatum(ControlFile->xlog_blcksz);
+ 	nulls[3] = false;
+ 
+ 	values[4] = Int32GetDatum(ControlFile->xlog_seg_size);
+ 	nulls[4] = false;
+ 
+ 	values[5] = Int32GetDatum(ControlFile->nameDataLen);
+ 	nulls[5] = false;
+ 
+ 	values[6] = Int32GetDatum(ControlFile->indexMaxKeys);
+ 	nulls[6] = false;
+ 
+ 	values[7] = Int32GetDatum(ControlFile->toast_max_chunk_size);
+ 	nulls[7] = false;
+ 
+ 	values[8] = Int32GetDatum(ControlFile->loblksize);
+ 	nulls[8] = false;
+ 
+ 	values[9] = BoolGetDatum(ControlFile->enableIntTimes);
+ 	nulls[9] = false;
+ 
+ 	values[10] = BoolGetDatum(ControlFile->float4ByVal);
+ 	nulls[10] = false;
+ 
+ 	values[11] = BoolGetDatum(ControlFile->float8ByVal);
+ 	nulls[11] = false;
+ 
+ 	values[12] = Int32GetDatum(ControlFile->data_checksum_version);
+ 	nulls[12] = false;
+ 
+ 	htup = heap_form_tuple(tupdesc, values, nulls);
+ 
+ 	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
+ }
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index 5dd2dbc..944a879 100644
*** a/src/bin/pg_controldata/pg_controldata.c
--- b/src/bin/pg_controldata/pg_controldata.c
***************
*** 9,31 ****
   * src/bin/pg_controldata/pg_controldata.c
   */
  
! /*
!  * 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 <unistd.h>
! #include <time.h>
! #include <sys/stat.h>
! #include <fcntl.h>
  
- #include "access/xlog.h"
- #include "access/xlog_internal.h"
  #include "catalog/pg_control.h"
  #include "pg_getopt.h"
  
  
--- 9,18 ----
   * src/bin/pg_controldata/pg_controldata.c
   */
  
! #include "postgres_fe.h"
  
  #include "catalog/pg_control.h"
+ #include "common/controldata_utils.h"
  #include "pg_getopt.h"
  
  
*************** usage(const char *progname)
*** 45,108 ****
  }
  
  
! static const char *
! dbState(DBState state)
! {
! 	switch (state)
! 	{
! 		case DB_STARTUP:
! 			return _("starting up");
! 		case DB_SHUTDOWNED:
! 			return _("shut down");
! 		case DB_SHUTDOWNED_IN_RECOVERY:
! 			return _("shut down in recovery");
! 		case DB_SHUTDOWNING:
! 			return _("shutting down");
! 		case DB_IN_CRASH_RECOVERY:
! 			return _("in crash recovery");
! 		case DB_IN_ARCHIVE_RECOVERY:
! 			return _("in archive recovery");
! 		case DB_IN_PRODUCTION:
! 			return _("in production");
! 	}
! 	return _("unrecognized status code");
! }
! 
! static const char *
! wal_level_str(WalLevel wal_level)
! {
! 	switch (wal_level)
! 	{
! 		case WAL_LEVEL_MINIMAL:
! 			return "minimal";
! 		case WAL_LEVEL_ARCHIVE:
! 			return "archive";
! 		case WAL_LEVEL_HOT_STANDBY:
! 			return "hot_standby";
! 		case WAL_LEVEL_LOGICAL:
! 			return "logical";
! 	}
! 	return _("unrecognized wal_level");
! }
! 
! 
  int
  main(int argc, char *argv[])
  {
! 	ControlFileData ControlFile;
! 	int			fd;
! 	char		ControlFilePath[MAXPGPATH];
! 	char	   *DataDir = NULL;
! 	pg_crc32c	crc;
! 	time_t		time_tmp;
! 	char		pgctime_str[128];
! 	char		ckpttime_str[128];
! 	char		sysident_str[32];
! 	const char *strftime_fmt = "%c";
! 	const char *progname;
! 	XLogSegNo	segno;
! 	char		xlogfilename[MAXFNAMELEN];
! 	int			c;
  
  	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata"));
  
--- 32,48 ----
  }
  
  
! #define CONTROLDATANAME_LEN 39
! #define CONTROLDATANAME_FMT "%-39s%s\n"
  int
  main(int argc, char *argv[])
  {
! 	char		   *DataDir = NULL;
! 	ControlData	   *controldata;
! 	size_t			controldata_len;
! 	char			controldata_name[CONTROLDATANAME_LEN + 1];
! 	const char	   *progname;
! 	int				c, i;
  
  	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata"));
  
*************** main(int argc, char *argv[])
*** 161,338 ****
  		exit(1);
  	}
  
! 	snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
! 
! 	if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
! 	{
! 		fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
! 				progname, ControlFilePath, strerror(errno));
! 		exit(2);
! 	}
! 
! 	if (read(fd, &ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
  	{
! 		fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
! 				progname, ControlFilePath, strerror(errno));
! 		exit(2);
  	}
- 	close(fd);
- 
- 	/* Check the CRC. */
- 	INIT_CRC32C(crc);
- 	COMP_CRC32C(crc,
- 				(char *) &ControlFile,
- 				offsetof(ControlFileData, crc));
- 	FIN_CRC32C(crc);
- 
- 	if (!EQ_CRC32C(crc, ControlFile.crc))
- 		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"));
- 
- 	/*
- 	 * This slightly-chintzy coding will work as long as the control file
- 	 * timestamps are within the range of time_t; that should be the case in
- 	 * all foreseeable circumstances, so we don't bother importing the
- 	 * backend's timezone library into pg_controldata.
- 	 *
- 	 * Use variable for format to suppress overly-anal-retentive gcc warning
- 	 * about %c
- 	 */
- 	time_tmp = (time_t) ControlFile.time;
- 	strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt,
- 			 localtime(&time_tmp));
- 	time_tmp = (time_t) ControlFile.checkPointCopy.time;
- 	strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt,
- 			 localtime(&time_tmp));
  
- 	/*
- 	 * Calculate name of the WAL file containing the latest checkpoint's REDO
- 	 * start point.
- 	 */
- 	XLByteToSeg(ControlFile.checkPointCopy.redo, segno);
- 	XLogFileName(xlogfilename, ControlFile.checkPointCopy.ThisTimeLineID, segno);
- 
- 	/*
- 	 * 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);
- 	if (ControlFile.pg_control_version % 65536 == 0 && ControlFile.pg_control_version / 65536 != 0)
- 		printf(_("WARNING: possible byte ordering mismatch\n"
- 				 "The byte ordering used to store the pg_control file might not match the one\n"
- 				 "used by this program.  In that case the results below would be incorrect, and\n"
- 				 "the PostgreSQL installation would be incompatible with this data directory.\n"));
- 	printf(_("Catalog version number:               %u\n"),
- 		   ControlFile.catalog_version_no);
- 	printf(_("Database system identifier:           %s\n"),
- 		   sysident_str);
- 	printf(_("Database cluster state:               %s\n"),
- 		   dbState(ControlFile.state));
- 	printf(_("pg_control last modified:             %s\n"),
- 		   pgctime_str);
- 	printf(_("Latest checkpoint location:           %X/%X\n"),
- 		   (uint32) (ControlFile.checkPoint >> 32),
- 		   (uint32) ControlFile.checkPoint);
- 	printf(_("Prior checkpoint location:            %X/%X\n"),
- 		   (uint32) (ControlFile.prevCheckPoint >> 32),
- 		   (uint32) ControlFile.prevCheckPoint);
- 	printf(_("Latest checkpoint's REDO location:    %X/%X\n"),
- 		   (uint32) (ControlFile.checkPointCopy.redo >> 32),
- 		   (uint32) ControlFile.checkPointCopy.redo);
- 	printf(_("Latest checkpoint's REDO WAL file:    %s\n"),
- 		   xlogfilename);
- 	printf(_("Latest checkpoint's TimeLineID:       %u\n"),
- 		   ControlFile.checkPointCopy.ThisTimeLineID);
- 	printf(_("Latest checkpoint's PrevTimeLineID:   %u\n"),
- 		   ControlFile.checkPointCopy.PrevTimeLineID);
- 	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 oldestCommitTsXid:%u\n"),
- 		   ControlFile.checkPointCopy.oldestCommitTsXid);
- 	printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
- 		   ControlFile.checkPointCopy.newestCommitTsXid);
- 	printf(_("Time of latest checkpoint:            %s\n"),
- 		   ckpttime_str);
- 	printf(_("Fake LSN counter for unlogged rels:   %X/%X\n"),
- 		   (uint32) (ControlFile.unloggedLSN >> 32),
- 		   (uint32) ControlFile.unloggedLSN);
- 	printf(_("Minimum recovery ending location:     %X/%X\n"),
- 		   (uint32) (ControlFile.minRecoveryPoint >> 32),
- 		   (uint32) ControlFile.minRecoveryPoint);
- 	printf(_("Min recovery ending loc's timeline:   %u\n"),
- 		   ControlFile.minRecoveryPointTLI);
- 	printf(_("Backup start location:                %X/%X\n"),
- 		   (uint32) (ControlFile.backupStartPoint >> 32),
- 		   (uint32) ControlFile.backupStartPoint);
- 	printf(_("Backup end location:                  %X/%X\n"),
- 		   (uint32) (ControlFile.backupEndPoint >> 32),
- 		   (uint32) ControlFile.backupEndPoint);
- 	printf(_("End-of-backup record required:        %s\n"),
- 		   ControlFile.backupEndRequired ? _("yes") : _("no"));
- 	printf(_("wal_level setting:                    %s\n"),
- 		   wal_level_str(ControlFile.wal_level));
- 	printf(_("wal_log_hints setting:                %s\n"),
- 		   ControlFile.wal_log_hints ? _("on") : _("off"));
- 	printf(_("max_connections setting:              %d\n"),
- 		   ControlFile.MaxConnections);
- 	printf(_("max_worker_processes setting:         %d\n"),
- 		   ControlFile.max_worker_processes);
- 	printf(_("max_prepared_xacts setting:           %d\n"),
- 		   ControlFile.max_prepared_xacts);
- 	printf(_("max_locks_per_xact setting:           %d\n"),
- 		   ControlFile.max_locks_per_xact);
- 	printf(_("track_commit_timestamp setting:       %s\n"),
- 		   ControlFile.track_commit_timestamp ? _("on") : _("off"));
- 	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);
  	return 0;
  }
--- 101,114 ----
  		exit(1);
  	}
  
! 	controldata = get_controldata(DataDir, progname, &controldata_len);
! 	for (i = 0; i < controldata_len; i++)
  	{
! 		memset(controldata_name, ' ', CONTROLDATANAME_LEN);
! 		snprintf (controldata_name, CONTROLDATANAME_LEN,
! 				  "%s:", controldata[i].name);
! 		printf(CONTROLDATANAME_FMT, controldata_name, controldata[i].setting);
  	}
  
  	return 0;
  }
diff --git a/src/common/Makefile b/src/common/Makefile
index bde4fc2..f7a4a4d 100644
*** a/src/common/Makefile
--- b/src/common/Makefile
*************** override CPPFLAGS += -DVAL_LDFLAGS_EX="\
*** 36,43 ****
  override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\""
  override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\""
  
! OBJS_COMMON = config_info.o exec.o pg_lzcompress.o pgfnames.o psprintf.o \
! 	relpath.o rmtree.o string.o username.o wait_error.o
  
  OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o restricted_token.o
  
--- 36,43 ----
  override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\""
  override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\""
  
! OBJS_COMMON = config_info.o controldata_utils.o exec.o pg_lzcompress.o \
! 	pgfnames.o psprintf.o relpath.o rmtree.o string.o username.o wait_error.o
  
  OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o restricted_token.o
  
diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c
index ...686be76 .
*** a/src/common/controldata_utils.c
--- b/src/common/controldata_utils.c
***************
*** 0 ****
--- 1,382 ----
+ /*-------------------------------------------------------------------------
+  *
+  * controldata_utils.c
+  *		Common code for pg_controldata output
+  *
+  *
+  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *	  src/common/controldata_utils.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ /*
+  * 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.
+  */
+ #include "postgres.h"
+ 
+ #include <unistd.h>
+ #include <time.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ 
+ #include "miscadmin.h"
+ #include "access/xlog.h"
+ #include "access/xlog_internal.h"
+ #include "catalog/pg_control.h"
+ #include "catalog/pg_type.h"
+ #include "common/controldata_utils.h"
+ #include "port/pg_crc32c.h"
+ #include "utils/builtins.h"
+ 
+ #ifndef FRONTEND
+ /* NOTE: caller must provide gettext call around str */
+ #define log_error(str, param1, param2)	\
+ 	elog(ERROR, str, param1, param2)
+ #else
+ #define log_error(str, param1, param2)	\
+ 	do { \
+ 			char *buf = psprintf("%%s: %s", str); \
+ 			fprintf(stderr, buf, progname, param1, param2); \
+ 			exit(2); \
+ 	} while (0)
+ #endif
+ 
+ static const char *dbState(DBState state);
+ static const char *wal_level_str(WalLevel wal_level);
+ 
+ static const char *const controldata_names[] =
+ {
+ 	gettext_noop("pg_control version number"),
+ 	gettext_noop("Catalog version number"),
+ 	gettext_noop("Database system identifier"),
+ 	gettext_noop("Database cluster state"),
+ 	gettext_noop("pg_control last modified"),
+ 	gettext_noop("Latest checkpoint location"),
+ 	gettext_noop("Prior checkpoint location"),
+ 	gettext_noop("Latest checkpoint's REDO location"),
+ 	gettext_noop("Latest checkpoint's REDO WAL file"),
+ 	gettext_noop("Latest checkpoint's TimeLineID"),
+ 	gettext_noop("Latest checkpoint's PrevTimeLineID"),
+ 	gettext_noop("Latest checkpoint's full_page_writes"),
+ 	gettext_noop("Latest checkpoint's NextXID"),
+ 	gettext_noop("Latest checkpoint's NextOID"),
+ 	gettext_noop("Latest checkpoint's NextMultiXactId"),
+ 	gettext_noop("Latest checkpoint's NextMultiOffset"),
+ 	gettext_noop("Latest checkpoint's oldestXID"),
+ 	gettext_noop("Latest checkpoint's oldestXID's DB"),
+ 	gettext_noop("Latest checkpoint's oldestActiveXID"),
+ 	gettext_noop("Latest checkpoint's oldestMultiXid"),
+ 	gettext_noop("Latest checkpoint's oldestMulti's DB"),
+ 	gettext_noop("Latest checkpoint's oldestCommitTsXid"),
+ 	gettext_noop("Latest checkpoint's newestCommitTsXid"),
+ 	gettext_noop("Time of latest checkpoint"),
+ 	gettext_noop("Fake LSN counter for unlogged rels"),
+ 	gettext_noop("Minimum recovery ending location"),
+ 	gettext_noop("Min recovery ending loc's timeline"),
+ 	gettext_noop("Backup start location"),
+ 	gettext_noop("Backup end location"),
+ 	gettext_noop("End-of-backup record required"),
+ 	gettext_noop("wal_level setting"),
+ 	gettext_noop("wal_log_hints setting"),
+ 	gettext_noop("max_connections setting"),
+ 	gettext_noop("max_worker_processes setting"),
+ 	gettext_noop("max_prepared_xacts setting"),
+ 	gettext_noop("max_locks_per_xact setting"),
+ 	gettext_noop("track_commit_timestamp setting"),
+ 	gettext_noop("Maximum data alignment"),
+ 	gettext_noop("Database block size"),
+ 	gettext_noop("Blocks per segment of large relation"),
+ 	gettext_noop("WAL block size"),
+ 	gettext_noop("Bytes per WAL segment"),
+ 	gettext_noop("Maximum length of identifiers"),
+ 	gettext_noop("Maximum columns in an index"),
+ 	gettext_noop("Maximum size of a TOAST chunk"),
+ 	gettext_noop("Size of a large-object chunk"),
+ 	gettext_noop("Date/time type storage"),
+ 	gettext_noop("Float4 argument passing"),
+ 	gettext_noop("Float8 argument passing"),
+ 	gettext_noop("Data page checksum version"),
+ 	NULL
+ };
+ 
+ static size_t
+ controldata_names_len(void)
+ {
+ 	size_t	i = 0;
+ 
+ 	while (controldata_names[i])
+ 		i++;
+ 
+ 	return i;
+ }
+ 
+ 
+ static const char *
+ dbState(DBState state)
+ {
+ 	switch (state)
+ 	{
+ 		case DB_STARTUP:
+ 			return _("starting up");
+ 		case DB_SHUTDOWNED:
+ 			return _("shut down");
+ 		case DB_SHUTDOWNED_IN_RECOVERY:
+ 			return _("shut down in recovery");
+ 		case DB_SHUTDOWNING:
+ 			return _("shutting down");
+ 		case DB_IN_CRASH_RECOVERY:
+ 			return _("in crash recovery");
+ 		case DB_IN_ARCHIVE_RECOVERY:
+ 			return _("in archive recovery");
+ 		case DB_IN_PRODUCTION:
+ 			return _("in production");
+ 	}
+ 	return _("unrecognized status code");
+ }
+ 
+ static const char *
+ wal_level_str(WalLevel wal_level)
+ {
+ 	switch (wal_level)
+ 	{
+ 		case WAL_LEVEL_MINIMAL:
+ 			return "minimal";
+ 		case WAL_LEVEL_ARCHIVE:
+ 			return "archive";
+ 		case WAL_LEVEL_HOT_STANDBY:
+ 			return "hot_standby";
+ 		case WAL_LEVEL_LOGICAL:
+ 			return "logical";
+ 	}
+ 	return _("unrecognized wal_level");
+ }
+ 
+ 
+ ControlFileData *
+ get_controlfile(char *DataDir, const char *progname)
+ {
+ 	ControlFileData	   *ControlFile;
+ 	int					fd;
+ 	char				ControlFilePath[MAXPGPATH];
+ 	pg_crc32c			crc;
+ 
+ 	ControlFile = palloc(sizeof(ControlFileData));
+ 	snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
+ 
+ 	if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
+ 		log_error(_("could not open file \"%s\" for reading: %s"),
+ 				  ControlFilePath, strerror(errno));
+ 
+ 	if (read(fd, ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
+ 		log_error(_("could not read file \"%s\": %s"),
+ 				  ControlFilePath, strerror(errno));
+ 
+ 	close(fd);
+ 
+ 	/* Check the CRC. */
+ 	INIT_CRC32C(crc);
+ 	COMP_CRC32C(crc,
+ 			   (char *) ControlFile,
+ 			   offsetof(ControlFileData, crc));
+ 	FIN_CRC32C(crc);
+ 
+ 	if (!EQ_CRC32C(crc, ControlFile->crc))
+ #ifndef FRONTEND
+ 		elog(ERROR, _("calculated CRC checksum does not match value stored in file"));
+ #else
+ 		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"));
+ #endif
+ 
+ 	return ControlFile;
+ }
+ 
+ ControlData *
+ get_controldata(char *DataDir, const char *progname,
+ 				size_t *controldata_len)
+ {
+ 	ControlFileData	   *ControlFile;
+ 	ControlData		   *controldata;
+ 	time_t				time_tmp;
+ 	char				pgctime_str[128];
+ 	char				ckpttime_str[128];
+ 	char				sysident_str[32];
+ 	const char		   *strftime_fmt = "%c";
+ 	XLogSegNo			segno;
+ 	char				xlogfilename[MAXFNAMELEN];
+ 	int					i;
+ 	int					idx = 0;
+ 
+ 	*controldata_len = controldata_names_len();
+ 	controldata = palloc(*controldata_len * sizeof(ControlData));
+ 
+ 	/*
+ 	 * initialize controldata names
+ 	 *
+ 	 * These better be in sync with the settings manually
+ 	 * defined below.
+ 	 */
+ 	for (i = 0; i < *controldata_len; i++)
+ 		controldata[i].name = pstrdup(_(controldata_names[i]));
+ 
+ 	/* get a copy of the control file */
+ 	ControlFile = get_controlfile(DataDir, progname);
+ 
+ 	/*
+ 	 * This slightly-chintzy coding will work as long as the control file
+ 	 * timestamps are within the range of time_t; that should be the case in
+ 	 * all foreseeable circumstances, so we don't bother importing the
+ 	 * backend's timezone library.
+ 	 *
+ 	 * Use variable for format to suppress overly-anal-retentive gcc warning
+ 	 * about %c
+ 	 */
+ 	time_tmp = (time_t) ControlFile->time;
+ 	strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt,
+ 			 localtime(&time_tmp));
+ 	time_tmp = (time_t) ControlFile->checkPointCopy.time;
+ 	strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt,
+ 			 localtime(&time_tmp));
+ 
+ 	/*
+ 	 * Calculate name of the WAL file containing the latest checkpoint's REDO
+ 	 * start point.
+ 	 */
+ 	XLByteToSeg(ControlFile->checkPointCopy.redo, segno);
+ 	XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID, segno);
+ 
+ 	/*
+ 	 * 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);
+ 
+ 	if (ControlFile->pg_control_version % 65536 == 0 &&
+ 		ControlFile->pg_control_version / 65536 != 0)
+ #ifndef FRONTEND
+ 		elog(ERROR, _("byte ordering mismatch"));
+ #else
+ 		printf(_("WARNING: possible byte ordering mismatch\n"
+ 				 "The byte ordering used to store the pg_control file might not match the one\n"
+ 				 "used by this program.  In that case the results below would be incorrect, and\n"
+ 				 "the PostgreSQL installation would be incompatible with this data directory.\n"));
+ #endif
+ 
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->pg_control_version);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->catalog_version_no);
+ 	controldata[idx++].setting = psprintf("%s",
+ 		sysident_str);
+ 	controldata[idx++].setting = psprintf("%s",
+ 		dbState(ControlFile->state));
+ 	controldata[idx++].setting = psprintf("%s",
+ 		pgctime_str);
+ 	controldata[idx++].setting = psprintf("%X/%X",
+ 		(uint32) (ControlFile->checkPoint >> 32),
+ 		(uint32) ControlFile->checkPoint);
+ 	controldata[idx++].setting = psprintf("%X/%X",
+ 		(uint32) (ControlFile->prevCheckPoint >> 32),
+ 		(uint32) ControlFile->prevCheckPoint);
+ 	controldata[idx++].setting = psprintf("%X/%X",
+ 		(uint32) (ControlFile->checkPointCopy.redo >> 32),
+ 		(uint32) ControlFile->checkPointCopy.redo);
+ 	controldata[idx++].setting = psprintf("%s", xlogfilename);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.ThisTimeLineID);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.PrevTimeLineID);
+ 	controldata[idx++].setting = psprintf("%s",
+ 		ControlFile->checkPointCopy.fullPageWrites ? _("on") : _("off"));
+ 	controldata[idx++].setting = psprintf("%u:%u",
+ 		ControlFile->checkPointCopy.nextXidEpoch,
+ 		ControlFile->checkPointCopy.nextXid);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.nextOid);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.nextMulti);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.nextMultiOffset);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.oldestXid);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.oldestXidDB);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.oldestActiveXid);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.oldestMulti);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.oldestMultiDB);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.oldestCommitTsXid);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->checkPointCopy.newestCommitTsXid);
+ 	controldata[idx++].setting = psprintf("%s", ckpttime_str);
+ 	controldata[idx++].setting = psprintf("%X/%X",
+ 		(uint32) (ControlFile->unloggedLSN >> 32),
+ 		(uint32) ControlFile->unloggedLSN);
+ 	controldata[idx++].setting = psprintf("%X/%X",
+ 		(uint32) (ControlFile->minRecoveryPoint >> 32),
+ 		(uint32) ControlFile->minRecoveryPoint);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->minRecoveryPointTLI);
+ 	controldata[idx++].setting = psprintf("%X/%X",
+ 		(uint32) (ControlFile->backupStartPoint >> 32),
+ 		(uint32) ControlFile->backupStartPoint);
+ 	controldata[idx++].setting = psprintf("%X/%X",
+ 		(uint32) (ControlFile->backupEndPoint >> 32),
+ 		(uint32) ControlFile->backupEndPoint);
+ 	controldata[idx++].setting = psprintf("%s",
+ 		ControlFile->backupEndRequired ? _("yes") : _("no"));
+ 	controldata[idx++].setting = psprintf("%s",
+ 		wal_level_str(ControlFile->wal_level));
+ 	controldata[idx++].setting = psprintf("%s",
+ 		ControlFile->wal_log_hints ? _("on") : _("off"));
+ 	controldata[idx++].setting = psprintf("%d",
+ 		ControlFile->MaxConnections);
+ 	controldata[idx++].setting = psprintf("%d",
+ 		ControlFile->max_worker_processes);
+ 	controldata[idx++].setting = psprintf("%d",
+ 		ControlFile->max_prepared_xacts);
+ 	controldata[idx++].setting = psprintf("%d",
+ 		ControlFile->max_locks_per_xact);
+ 	controldata[idx++].setting = psprintf("%s",
+ 		ControlFile->track_commit_timestamp ? _("on") : _("off"));
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->maxAlign);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->blcksz);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->relseg_size);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->xlog_blcksz);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->xlog_seg_size);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->nameDataLen);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->indexMaxKeys);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->toast_max_chunk_size);
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->loblksize);
+ 	controldata[idx++].setting = psprintf("%s",
+ 		(ControlFile->enableIntTimes ?
+ 		 _("64-bit integers") : _("floating-point numbers")));
+ 	controldata[idx++].setting = psprintf("%s",
+ 		(ControlFile->float4ByVal ? _("by value") : _("by reference")));
+ 	controldata[idx++].setting = psprintf("%s",
+ 		(ControlFile->float8ByVal ? _("by value") : _("by reference")));
+ 	controldata[idx++].setting = psprintf("%u",
+ 		ControlFile->data_checksum_version);
+ 
+ 	return controldata;
+ }
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 2222e8f..2e269aa 100644
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("row security for current context
*** 5212,5217 ****
--- 5212,5230 ----
  DATA(insert OID = 3400 ( pg_config PGNSP PGUID 12 1 23 0 0 f f f f t t i r 0 0 2249 "" "{25,25}" "{o,o}" "{name,setting}" _null_ _null_ pg_config _null_ _null_ _null_ ));
  DESCR("pg_config binary as a function");
  
+ /* pg_controldata related functions */
+ DATA(insert OID = 3441 ( pg_controldata_state PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{23,23,20,1184}" "{o,o,o,o}" "{pg_control_version,catalog_version_no,system_identifier,pg_control_last_modified}" _null_ _null_ pg_controldata_state _null_ _null_ _null_ ));
+ DESCR("pg_controldata general state information as a function");
+ 
+ DATA(insert OID = 3442 ( pg_checkpoint_state PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{3220,3220,3220,25,23,23,16,25,26,28,28,28,26,28,28,26,28,28,1184}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{checkpoint_location,prior_location,redo_location,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,next_xid,next_oid,next_multixact_id,next_multi_offset,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time}" _null_ _null_ pg_checkpoint_state _null_ _null_ _null_ ));
+ DESCR("pg_controldata checkpoint state information as a function");
+ 
+ DATA(insert OID = 3443 ( pg_recovery_state PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{3220,23,3220,3220,16}" "{o,o,o,o,o}" "{min_recovery_end_location,min_recovery_end_timeline,backup_start_location,backup_end_location,end_of_backup_record_required}" _null_ _null_ pg_recovery_state _null_ _null_ _null_ ));
+ DESCR("pg_controldata recovery state information as a function");
+ 
+ DATA(insert OID = 3444 ( pg_init_state PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{23,23,23,23,23,23,23,23,23,16,16,16,23}" "{o,o,o,o,o,o,o,o,o,o,o,o,o}" "{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,bigint_timestamps,float4_pass_by_value,float8_pass_by_value,data_page_checksum_version}" _null_ _null_ pg_init_state _null_ _null_ _null_ ));
+ DESCR("pg_controldata init state information as a function");
+ 
  /*
   * Symbolic values for provolatile column: these indicate whether the result
   * of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/common/controldata_utils.h b/src/include/common/controldata_utils.h
index ...5dcc45f .
*** a/src/include/common/controldata_utils.h
--- b/src/include/common/controldata_utils.h
***************
*** 0 ****
--- 1,23 ----
+ /*
+  * controldata_utils.h
+  *		Common code for pg_controldata output
+  *
+  *	Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+  *	Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *	src/include/common/controldata_utils.h
+  */
+ #ifndef COMMON_CONTROLDATA_UTILS_H
+ #define COMMON_CONTROLDATA_UTILS_H
+ 
+ typedef struct ControlData
+ {
+ 	char	   *name;
+ 	char	   *setting;
+ } ControlData;
+ 
+ extern ControlFileData *get_controlfile(char *DataDir, const char *progname);
+ extern ControlData *get_controldata(char *DataDir, const char *progname,
+ 									size_t *controldata_len);
+ 
+ #endif   /* COMMON_CONTROLDATA_UTILS_H */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index a784de9..6fbd89c 100644
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
*************** extern Datum show_all_file_settings(PG_F
*** 1150,1155 ****
--- 1150,1161 ----
  /* pg_config.c */
  extern Datum pg_config(PG_FUNCTION_ARGS);
  
+ /* pg_controldata.c */
+ extern Datum pg_checkpoint_state(PG_FUNCTION_ARGS);
+ extern Datum pg_controldata_state(PG_FUNCTION_ARGS);
+ extern Datum pg_init_state(PG_FUNCTION_ARGS);
+ extern Datum pg_recovery_state(PG_FUNCTION_ARGS);
+ 
  /* rls.c */
  extern Datum row_security_active(PG_FUNCTION_ARGS);
  extern Datum row_security_active_name(PG_FUNCTION_ARGS);
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index e4fb44e..1a9c996 100644
*** a/src/tools/msvc/Mkvcbuild.pm
--- b/src/tools/msvc/Mkvcbuild.pm
*************** sub mkvcbuild
*** 106,112 ****
  	}
  
  	our @pgcommonallfiles = qw(
! 	  config_info.c exec.c pg_lzcompress.c pgfnames.c psprintf.c
  	  relpath.c rmtree.c string.c username.c wait_error.c);
  
  	our @pgcommonfrontendfiles = (
--- 106,112 ----
  	}
  
  	our @pgcommonallfiles = qw(
! 	  config_info.c controldata_utils.c exec.c pg_lzcompress.c pgfnames.c
  	  relpath.c rmtree.c string.c username.c wait_error.c);
  
  	our @pgcommonfrontendfiles = (
