1 /*
2  * pg_controldata
3  *
4  * reads the data from $PGDATA/global/pg_control
5  *
6  * copyright (c) Oliver Elphick <olly@lfix.co.uk>, 2001;
7  * licence: BSD
8  *
9  * src/bin/pg_controldata/pg_controldata.c
10  */
11 
12 /*
13  * We have to use postgres.h not postgres_fe.h here, because there's so much
14  * backend-only stuff in the XLOG include files we need.  But we need a
15  * frontend-ish environment otherwise.  Hence this ugly hack.
16  */
17 #define FRONTEND 1
18 
19 #include "postgres.h"
20 
21 #include <time.h>
22 
23 #include "access/xlog.h"
24 #include "access/xlog_internal.h"
25 #include "catalog/pg_control.h"
26 #include "common/controldata_utils.h"
27 #include "pg_getopt.h"
28 
29 
30 static void
usage(const char * progname)31 usage(const char *progname)
32 {
33 	printf(_("%s displays control information of a PostgreSQL database cluster.\n\n"), progname);
34 	printf(_("Usage:\n"));
35 	printf(_("  %s [OPTION] [DATADIR]\n"), progname);
36 	printf(_("\nOptions:\n"));
37 	printf(_(" [-D] DATADIR    data directory\n"));
38 	printf(_("  -V, --version  output version information, then exit\n"));
39 	printf(_("  -?, --help     show this help, then exit\n"));
40 	printf(_("\nIf no data directory (DATADIR) is specified, "
41 			 "the environment variable PGDATA\nis used.\n\n"));
42 	printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
43 }
44 
45 
46 static const char *
dbState(DBState state)47 dbState(DBState state)
48 {
49 	switch (state)
50 	{
51 		case DB_STARTUP:
52 			return _("starting up");
53 		case DB_SHUTDOWNED:
54 			return _("shut down");
55 		case DB_SHUTDOWNED_IN_RECOVERY:
56 			return _("shut down in recovery");
57 		case DB_SHUTDOWNING:
58 			return _("shutting down");
59 		case DB_IN_CRASH_RECOVERY:
60 			return _("in crash recovery");
61 		case DB_IN_ARCHIVE_RECOVERY:
62 			return _("in archive recovery");
63 		case DB_IN_PRODUCTION:
64 			return _("in production");
65 	}
66 	return _("unrecognized status code");
67 }
68 
69 static const char *
wal_level_str(WalLevel wal_level)70 wal_level_str(WalLevel wal_level)
71 {
72 	switch (wal_level)
73 	{
74 		case WAL_LEVEL_MINIMAL:
75 			return "minimal";
76 		case WAL_LEVEL_REPLICA:
77 			return "replica";
78 		case WAL_LEVEL_LOGICAL:
79 			return "logical";
80 	}
81 	return _("unrecognized wal_level");
82 }
83 
84 
85 int
main(int argc,char * argv[])86 main(int argc, char *argv[])
87 {
88 	ControlFileData *ControlFile;
89 	char	   *DataDir = NULL;
90 	time_t		time_tmp;
91 	char		pgctime_str[128];
92 	char		ckpttime_str[128];
93 	char		sysident_str[32];
94 	const char *strftime_fmt = "%c";
95 	const char *progname;
96 	XLogSegNo	segno;
97 	char		xlogfilename[MAXFNAMELEN];
98 	int			c;
99 
100 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata"));
101 
102 	progname = get_progname(argv[0]);
103 
104 	if (argc > 1)
105 	{
106 		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
107 		{
108 			usage(progname);
109 			exit(0);
110 		}
111 		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
112 		{
113 			puts("pg_controldata (PostgreSQL) " PG_VERSION);
114 			exit(0);
115 		}
116 	}
117 
118 	while ((c = getopt(argc, argv, "D:")) != -1)
119 	{
120 		switch (c)
121 		{
122 			case 'D':
123 				DataDir = optarg;
124 				break;
125 
126 			default:
127 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
128 				exit(1);
129 		}
130 	}
131 
132 	if (DataDir == NULL)
133 	{
134 		if (optind < argc)
135 			DataDir = argv[optind++];
136 		else
137 			DataDir = getenv("PGDATA");
138 	}
139 
140 	/* Complain if any arguments remain */
141 	if (optind < argc)
142 	{
143 		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
144 				progname, argv[optind]);
145 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
146 				progname);
147 		exit(1);
148 	}
149 
150 	if (DataDir == NULL)
151 	{
152 		fprintf(stderr, _("%s: no data directory specified\n"), progname);
153 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
154 		exit(1);
155 	}
156 
157 	/* get a copy of the control file */
158 	ControlFile = get_controlfile(DataDir, progname);
159 
160 	/*
161 	 * This slightly-chintzy coding will work as long as the control file
162 	 * timestamps are within the range of time_t; that should be the case in
163 	 * all foreseeable circumstances, so we don't bother importing the
164 	 * backend's timezone library into pg_controldata.
165 	 *
166 	 * Use variable for format to suppress overly-anal-retentive gcc warning
167 	 * about %c
168 	 */
169 	time_tmp = (time_t) ControlFile->time;
170 	strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt,
171 			 localtime(&time_tmp));
172 	time_tmp = (time_t) ControlFile->checkPointCopy.time;
173 	strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt,
174 			 localtime(&time_tmp));
175 
176 	/*
177 	 * Calculate name of the WAL file containing the latest checkpoint's REDO
178 	 * start point.
179 	 */
180 	XLByteToSeg(ControlFile->checkPointCopy.redo, segno);
181 	XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID, segno);
182 
183 	/*
184 	 * Format system_identifier separately to keep platform-dependent format
185 	 * code out of the translatable message string.
186 	 */
187 	snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
188 			 ControlFile->system_identifier);
189 
190 	printf(_("pg_control version number:            %u\n"),
191 		   ControlFile->pg_control_version);
192 	printf(_("Catalog version number:               %u\n"),
193 		   ControlFile->catalog_version_no);
194 	printf(_("Database system identifier:           %s\n"),
195 		   sysident_str);
196 	printf(_("Database cluster state:               %s\n"),
197 		   dbState(ControlFile->state));
198 	printf(_("pg_control last modified:             %s\n"),
199 		   pgctime_str);
200 	printf(_("Latest checkpoint location:           %X/%X\n"),
201 		   (uint32) (ControlFile->checkPoint >> 32),
202 		   (uint32) ControlFile->checkPoint);
203 	printf(_("Prior checkpoint location:            %X/%X\n"),
204 		   (uint32) (ControlFile->prevCheckPoint >> 32),
205 		   (uint32) ControlFile->prevCheckPoint);
206 	printf(_("Latest checkpoint's REDO location:    %X/%X\n"),
207 		   (uint32) (ControlFile->checkPointCopy.redo >> 32),
208 		   (uint32) ControlFile->checkPointCopy.redo);
209 	printf(_("Latest checkpoint's REDO WAL file:    %s\n"),
210 		   xlogfilename);
211 	printf(_("Latest checkpoint's TimeLineID:       %u\n"),
212 		   ControlFile->checkPointCopy.ThisTimeLineID);
213 	printf(_("Latest checkpoint's PrevTimeLineID:   %u\n"),
214 		   ControlFile->checkPointCopy.PrevTimeLineID);
215 	printf(_("Latest checkpoint's full_page_writes: %s\n"),
216 		   ControlFile->checkPointCopy.fullPageWrites ? _("on") : _("off"));
217 	printf(_("Latest checkpoint's NextXID:          %u:%u\n"),
218 		   ControlFile->checkPointCopy.nextXidEpoch,
219 		   ControlFile->checkPointCopy.nextXid);
220 	printf(_("Latest checkpoint's NextOID:          %u\n"),
221 		   ControlFile->checkPointCopy.nextOid);
222 	printf(_("Latest checkpoint's NextMultiXactId:  %u\n"),
223 		   ControlFile->checkPointCopy.nextMulti);
224 	printf(_("Latest checkpoint's NextMultiOffset:  %u\n"),
225 		   ControlFile->checkPointCopy.nextMultiOffset);
226 	printf(_("Latest checkpoint's oldestXID:        %u\n"),
227 		   ControlFile->checkPointCopy.oldestXid);
228 	printf(_("Latest checkpoint's oldestXID's DB:   %u\n"),
229 		   ControlFile->checkPointCopy.oldestXidDB);
230 	printf(_("Latest checkpoint's oldestActiveXID:  %u\n"),
231 		   ControlFile->checkPointCopy.oldestActiveXid);
232 	printf(_("Latest checkpoint's oldestMultiXid:   %u\n"),
233 		   ControlFile->checkPointCopy.oldestMulti);
234 	printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
235 		   ControlFile->checkPointCopy.oldestMultiDB);
236 	printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"),
237 		   ControlFile->checkPointCopy.oldestCommitTsXid);
238 	printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
239 		   ControlFile->checkPointCopy.newestCommitTsXid);
240 	printf(_("Time of latest checkpoint:            %s\n"),
241 		   ckpttime_str);
242 	printf(_("Fake LSN counter for unlogged rels:   %X/%X\n"),
243 		   (uint32) (ControlFile->unloggedLSN >> 32),
244 		   (uint32) ControlFile->unloggedLSN);
245 	printf(_("Minimum recovery ending location:     %X/%X\n"),
246 		   (uint32) (ControlFile->minRecoveryPoint >> 32),
247 		   (uint32) ControlFile->minRecoveryPoint);
248 	printf(_("Min recovery ending loc's timeline:   %u\n"),
249 		   ControlFile->minRecoveryPointTLI);
250 	printf(_("Backup start location:                %X/%X\n"),
251 		   (uint32) (ControlFile->backupStartPoint >> 32),
252 		   (uint32) ControlFile->backupStartPoint);
253 	printf(_("Backup end location:                  %X/%X\n"),
254 		   (uint32) (ControlFile->backupEndPoint >> 32),
255 		   (uint32) ControlFile->backupEndPoint);
256 	printf(_("End-of-backup record required:        %s\n"),
257 		   ControlFile->backupEndRequired ? _("yes") : _("no"));
258 	printf(_("wal_level setting:                    %s\n"),
259 		   wal_level_str(ControlFile->wal_level));
260 	printf(_("wal_log_hints setting:                %s\n"),
261 		   ControlFile->wal_log_hints ? _("on") : _("off"));
262 	printf(_("max_connections setting:              %d\n"),
263 		   ControlFile->MaxConnections);
264 	printf(_("max_worker_processes setting:         %d\n"),
265 		   ControlFile->max_worker_processes);
266 	printf(_("max_prepared_xacts setting:           %d\n"),
267 		   ControlFile->max_prepared_xacts);
268 	printf(_("max_locks_per_xact setting:           %d\n"),
269 		   ControlFile->max_locks_per_xact);
270 	printf(_("track_commit_timestamp setting:       %s\n"),
271 		   ControlFile->track_commit_timestamp ? _("on") : _("off"));
272 	printf(_("Maximum data alignment:               %u\n"),
273 		   ControlFile->maxAlign);
274 	/* we don't print floatFormat since can't say much useful about it */
275 	printf(_("Database block size:                  %u\n"),
276 		   ControlFile->blcksz);
277 	printf(_("Blocks per segment of large relation: %u\n"),
278 		   ControlFile->relseg_size);
279 	printf(_("WAL block size:                       %u\n"),
280 		   ControlFile->xlog_blcksz);
281 	printf(_("Bytes per WAL segment:                %u\n"),
282 		   ControlFile->xlog_seg_size);
283 	printf(_("Maximum length of identifiers:        %u\n"),
284 		   ControlFile->nameDataLen);
285 	printf(_("Maximum columns in an index:          %u\n"),
286 		   ControlFile->indexMaxKeys);
287 	printf(_("Maximum size of a TOAST chunk:        %u\n"),
288 		   ControlFile->toast_max_chunk_size);
289 	printf(_("Size of a large-object chunk:         %u\n"),
290 		   ControlFile->loblksize);
291 	printf(_("Date/time type storage:               %s\n"),
292 		   (ControlFile->enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
293 	printf(_("Float4 argument passing:              %s\n"),
294 		   (ControlFile->float4ByVal ? _("by value") : _("by reference")));
295 	printf(_("Float8 argument passing:              %s\n"),
296 		   (ControlFile->float8ByVal ? _("by value") : _("by reference")));
297 	printf(_("Data page checksum version:           %u\n"),
298 		   ControlFile->data_checksum_version);
299 	return 0;
300 }
301