Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * pg_resetwal.c
4 : : * A utility to "zero out" the xlog when it's corrupt beyond recovery.
5 : : * Can also rebuild pg_control if needed.
6 : : *
7 : : * The theory of operation is fairly simple:
8 : : * 1. Read the existing pg_control (which will include the last
9 : : * checkpoint record).
10 : : * 2. If pg_control is corrupt, attempt to intuit reasonable values,
11 : : * by scanning the old xlog if necessary.
12 : : * 3. Modify pg_control to reflect a "shutdown" state with a checkpoint
13 : : * record at the start of xlog.
14 : : * 4. Flush the existing xlog files and write a new segment with
15 : : * just a checkpoint record in it. The new segment is positioned
16 : : * just past the end of the old xlog, so that existing LSNs in
17 : : * data pages will appear to be "in the past".
18 : : * This is all pretty straightforward except for the intuition part of
19 : : * step 2 ...
20 : : *
21 : : *
22 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
23 : : * Portions Copyright (c) 1994, Regents of the University of California
24 : : *
25 : : * src/bin/pg_resetwal/pg_resetwal.c
26 : : *
27 : : *-------------------------------------------------------------------------
28 : : */
29 : :
30 : : /*
31 : : * We have to use postgres.h not postgres_fe.h here, because there's so much
32 : : * backend-only stuff in the XLOG include files we need. But we need a
33 : : * frontend-ish environment otherwise. Hence this ugly hack.
34 : : */
35 : : #define FRONTEND 1
36 : :
37 : : #include "postgres.h"
38 : :
39 : : #include <dirent.h>
40 : : #include <fcntl.h>
41 : : #include <sys/stat.h>
42 : : #include <sys/time.h>
43 : : #include <time.h>
44 : : #include <unistd.h>
45 : :
46 : : #include "access/heaptoast.h"
47 : : #include "access/multixact.h"
48 : : #include "access/transam.h"
49 : : #include "access/xlog.h"
50 : : #include "access/xlog_internal.h"
51 : : #include "common/controldata_utils.h"
52 : : #include "common/fe_memutils.h"
53 : : #include "common/file_perm.h"
54 : : #include "common/logging.h"
55 : : #include "common/restricted_token.h"
56 : : #include "common/string.h"
57 : : #include "fe_utils/option_utils.h"
58 : : #include "fe_utils/version.h"
59 : : #include "getopt_long.h"
60 : : #include "pg_getopt.h"
61 : : #include "storage/large_object.h"
62 : :
63 : : static ControlFileData ControlFile; /* pg_control values */
64 : : static XLogSegNo newXlogSegNo; /* new XLOG segment # */
65 : : static bool guessed = false; /* T if we had to guess at any values */
66 : : static const char *progname;
67 : :
68 : : /*
69 : : * New values given on the command-line
70 : : */
71 : : static bool next_xid_epoch_given = false;
72 : : static uint32 next_xid_epoch_val;
73 : :
74 : : static bool oldest_xid_given = false;
75 : : static TransactionId oldest_xid_val;
76 : :
77 : : static bool next_xid_given = false;
78 : : static TransactionId next_xid_val;
79 : :
80 : : static bool commit_ts_xids_given = false;
81 : : static TransactionId oldest_commit_ts_xid_val;
82 : : static TransactionId newest_commit_ts_xid_val;
83 : :
84 : : static bool next_oid_given = false;
85 : : static Oid next_oid_val;
86 : :
87 : : static bool mxids_given = false;
88 : : static MultiXactId next_mxid_val;
89 : : static MultiXactId oldest_mxid_val = 0;
90 : :
91 : : static bool next_mxoff_given = false;
92 : : static MultiXactOffset next_mxoff_val;
93 : :
94 : : static bool wal_segsize_given = false;
95 : : static int wal_segsize_val;
96 : :
97 : : static bool char_signedness_given = false;
98 : : static bool char_signedness_val;
99 : :
100 : :
101 : : static TimeLineID minXlogTli = 0;
102 : : static XLogSegNo minXlogSegNo = 0;
103 : : static int WalSegSz;
104 : :
105 : : static void CheckDataVersion(void);
106 : : static bool read_controlfile(void);
107 : : static void GuessControlValues(void);
108 : : static void PrintControlValues(bool guessed);
109 : : static void PrintNewControlValues(void);
110 : : static void RewriteControlFile(void);
111 : : static void FindEndOfXLOG(void);
112 : : static void KillExistingXLOG(void);
113 : : static void KillExistingArchiveStatus(void);
114 : : static void KillExistingWALSummaries(void);
115 : : static void WriteEmptyXLOG(void);
116 : : static void usage(void);
117 : : static uint32 strtouint32_strict(const char *restrict s, char **restrict endptr, int base);
118 : : static uint64 strtouint64_strict(const char *restrict s, char **restrict endptr, int base);
119 : :
120 : :
121 : : int
8510 peter_e@gmx.net 122 :CBC 193 : main(int argc, char *argv[])
123 : : {
124 : : static struct option long_options[] = {
125 : : {"commit-timestamp-ids", required_argument, NULL, 'c'},
126 : : {"pgdata", required_argument, NULL, 'D'},
127 : : {"epoch", required_argument, NULL, 'e'},
128 : : {"force", no_argument, NULL, 'f'},
129 : : {"next-wal-file", required_argument, NULL, 'l'},
130 : : {"multixact-ids", required_argument, NULL, 'm'},
131 : : {"dry-run", no_argument, NULL, 'n'},
132 : : {"next-oid", required_argument, NULL, 'o'},
133 : : {"multixact-offset", required_argument, NULL, 'O'},
134 : : {"oldest-transaction-id", required_argument, NULL, 'u'},
135 : : {"next-transaction-id", required_argument, NULL, 'x'},
136 : : {"wal-segsize", required_argument, NULL, 1},
137 : : {"char-signedness", required_argument, NULL, 2},
138 : : {NULL, 0, NULL, 0}
139 : : };
140 : :
141 : : int c;
142 : 193 : bool force = false;
143 : 193 : bool noupdate = false;
144 : : char *endptr;
145 : : char *endptr2;
4100 heikki.linnakangas@i 146 : 193 : char *DataDir = NULL;
3010 andres@anarazel.de 147 : 193 : char *log_fname = NULL;
148 : : int fd;
149 : :
2451 peter@eisentraut.org 150 : 193 : pg_logging_init(argv[0]);
3232 rhaas@postgresql.org 151 : 193 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetwal"));
8292 bruce@momjian.us 152 : 193 : progname = get_progname(argv[0]);
153 : :
8510 peter_e@gmx.net 154 [ + + ]: 193 : if (argc > 1)
155 : : {
156 [ + + - + ]: 192 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
157 : : {
158 : 1 : usage();
159 : 1 : exit(0);
160 : : }
161 [ + + + + ]: 191 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
162 : : {
3232 rhaas@postgresql.org 163 : 47 : puts("pg_resetwal (PostgreSQL) " PG_VERSION);
8510 peter_e@gmx.net 164 : 47 : exit(0);
165 : : }
166 : : }
167 : :
168 : :
1604 bruce@momjian.us 169 [ + + ]: 323 : while ((c = getopt_long(argc, argv, "c:D:e:fl:m:no:O:u:x:", long_options, NULL)) != -1)
170 : : {
8510 peter_e@gmx.net 171 [ + + + + : 204 : switch (c)
+ + + + +
+ + + +
+ ]
172 : : {
4100 heikki.linnakangas@i 173 : 4 : case 'D':
174 : 4 : DataDir = optarg;
175 : 4 : break;
176 : :
8510 peter_e@gmx.net 177 : 39 : case 'f':
178 : 39 : force = true;
179 : 39 : break;
180 : :
181 : 41 : case 'n':
182 : 41 : noupdate = true;
183 : 41 : break;
184 : :
7057 tgl@sss.pgh.pa.us 185 : 14 : case 'e':
1579 peter@eisentraut.org 186 : 14 : errno = 0;
8 heikki.linnakangas@i 187 :GNC 14 : next_xid_epoch_val = strtouint32_strict(optarg, &endptr, 0);
1579 peter@eisentraut.org 188 [ + + + - :CBC 14 : if (endptr == optarg || *endptr != '\0' || errno != 0)
+ + ]
189 : : {
190 : : /*------
191 : : translator: the second %s is a command line argument (-e, etc) */
2451 192 : 2 : pg_log_error("invalid argument for option %s", "-e");
1348 tgl@sss.pgh.pa.us 193 : 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7057 194 : 2 : exit(1);
195 : : }
8 heikki.linnakangas@i 196 :GNC 12 : next_xid_epoch_given = true;
7057 tgl@sss.pgh.pa.us 197 :CBC 12 : break;
198 : :
1604 bruce@momjian.us 199 : 13 : case 'u':
1579 peter@eisentraut.org 200 : 13 : errno = 0;
8 heikki.linnakangas@i 201 :GNC 13 : oldest_xid_val = strtouint32_strict(optarg, &endptr, 0);
1579 peter@eisentraut.org 202 [ + + + - :CBC 13 : if (endptr == optarg || *endptr != '\0' || errno != 0)
- + ]
203 : : {
1604 bruce@momjian.us 204 : 1 : pg_log_error("invalid argument for option %s", "-u");
1348 tgl@sss.pgh.pa.us 205 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
1604 bruce@momjian.us 206 : 1 : exit(1);
207 : : }
8 heikki.linnakangas@i 208 [ + + ]:GNC 12 : if (!TransactionIdIsNormal(oldest_xid_val))
1348 tgl@sss.pgh.pa.us 209 :CBC 1 : pg_fatal("oldest transaction ID (-u) must be greater than or equal to %u", FirstNormalTransactionId);
8 heikki.linnakangas@i 210 :GNC 11 : oldest_xid_given = true;
1604 bruce@momjian.us 211 :CBC 11 : break;
212 : :
8510 peter_e@gmx.net 213 : 16 : case 'x':
1579 peter@eisentraut.org 214 : 16 : errno = 0;
8 heikki.linnakangas@i 215 :GNC 16 : next_xid_val = strtouint32_strict(optarg, &endptr, 0);
1579 peter@eisentraut.org 216 [ + + + - :CBC 16 : if (endptr == optarg || *endptr != '\0' || errno != 0)
+ + ]
217 : : {
2451 218 : 4 : pg_log_error("invalid argument for option %s", "-x");
1348 tgl@sss.pgh.pa.us 219 : 4 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8476 220 : 4 : exit(1);
221 : : }
8 heikki.linnakangas@i 222 [ + + ]:GNC 12 : if (!TransactionIdIsNormal(next_xid_val))
1348 tgl@sss.pgh.pa.us 223 :CBC 1 : pg_fatal("transaction ID (-x) must be greater than or equal to %u", FirstNormalTransactionId);
8 heikki.linnakangas@i 224 :GNC 11 : next_xid_given = true;
8510 peter_e@gmx.net 225 :CBC 11 : break;
226 : :
4031 alvherre@alvh.no-ip. 227 : 15 : case 'c':
1579 peter@eisentraut.org 228 : 15 : errno = 0;
8 heikki.linnakangas@i 229 :GNC 15 : oldest_commit_ts_xid_val = strtouint32_strict(optarg, &endptr, 0);
1579 peter@eisentraut.org 230 [ + + + - :CBC 15 : if (endptr == optarg || *endptr != ',' || errno != 0)
- + ]
231 : : {
2451 232 : 1 : pg_log_error("invalid argument for option %s", "-c");
1348 tgl@sss.pgh.pa.us 233 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4031 alvherre@alvh.no-ip. 234 : 1 : exit(1);
235 : : }
8 heikki.linnakangas@i 236 :GNC 14 : newest_commit_ts_xid_val = strtoul(endptr + 1, &endptr2, 0);
1579 peter@eisentraut.org 237 [ + + + - :CBC 14 : if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
- + ]
238 : : {
2451 239 : 1 : pg_log_error("invalid argument for option %s", "-c");
1348 tgl@sss.pgh.pa.us 240 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4031 alvherre@alvh.no-ip. 241 : 1 : exit(1);
242 : : }
243 : :
8 heikki.linnakangas@i 244 [ + + ]:GNC 13 : if (oldest_commit_ts_xid_val < FirstNormalTransactionId &&
245 [ + - ]: 1 : oldest_commit_ts_xid_val != InvalidTransactionId)
798 peter@eisentraut.org 246 :CBC 1 : pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
247 : :
8 heikki.linnakangas@i 248 [ + + ]:GNC 12 : if (newest_commit_ts_xid_val < FirstNormalTransactionId &&
249 [ + + ]: 3 : newest_commit_ts_xid_val != InvalidTransactionId)
798 peter@eisentraut.org 250 :CBC 1 : pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
8 heikki.linnakangas@i 251 :GNC 11 : commit_ts_xids_given = true;
4031 alvherre@alvh.no-ip. 252 :CBC 11 : break;
253 : :
8476 tgl@sss.pgh.pa.us 254 : 13 : case 'o':
1579 peter@eisentraut.org 255 : 13 : errno = 0;
8 heikki.linnakangas@i 256 :GNC 13 : next_oid_val = strtouint32_strict(optarg, &endptr, 0);
1579 peter@eisentraut.org 257 [ + + + - :CBC 13 : if (endptr == optarg || *endptr != '\0' || errno != 0)
- + ]
258 : : {
2451 259 : 1 : pg_log_error("invalid argument for option %s", "-o");
1348 tgl@sss.pgh.pa.us 260 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8476 261 : 1 : exit(1);
262 : : }
8 heikki.linnakangas@i 263 [ + + ]:GNC 12 : if (next_oid_val == 0)
1348 tgl@sss.pgh.pa.us 264 :CBC 1 : pg_fatal("OID (-o) must not be 0");
8 heikki.linnakangas@i 265 :GNC 11 : next_oid_given = true;
8476 tgl@sss.pgh.pa.us 266 :CBC 11 : break;
267 : :
7537 268 : 16 : case 'm':
1579 peter@eisentraut.org 269 : 16 : errno = 0;
8 heikki.linnakangas@i 270 :GNC 16 : next_mxid_val = strtouint32_strict(optarg, &endptr, 0);
1579 peter@eisentraut.org 271 [ + + + - :CBC 16 : if (endptr == optarg || *endptr != ',' || errno != 0)
- + ]
272 : : {
2451 273 : 1 : pg_log_error("invalid argument for option %s", "-m");
1348 tgl@sss.pgh.pa.us 274 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4710 alvherre@alvh.no-ip. 275 : 1 : exit(1);
276 : : }
277 : :
8 heikki.linnakangas@i 278 :GNC 15 : oldest_mxid_val = strtouint32_strict(endptr + 1, &endptr2, 0);
1579 peter@eisentraut.org 279 [ + + + - :CBC 15 : if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
- + ]
280 : : {
2451 281 : 1 : pg_log_error("invalid argument for option %s", "-m");
1348 tgl@sss.pgh.pa.us 282 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7537 283 : 1 : exit(1);
284 : : }
285 : :
286 : : /*
287 : : * XXX It'd be nice to have more sanity checks here, e.g. so
288 : : * that oldest is not wrapped around w.r.t. nextMulti.
289 : : */
4 heikki.linnakangas@i 290 [ + + ]:GNC 14 : if (next_mxid_val == 0)
291 : 1 : pg_fatal("next multitransaction ID (-m) must not be 0");
8 292 [ + + ]: 13 : if (oldest_mxid_val == 0)
1348 tgl@sss.pgh.pa.us 293 :CBC 1 : pg_fatal("oldest multitransaction ID (-m) must not be 0");
8 heikki.linnakangas@i 294 :GNC 12 : mxids_given = true;
7537 tgl@sss.pgh.pa.us 295 :CBC 12 : break;
296 : :
7496 297 : 13 : case 'O':
1579 peter@eisentraut.org 298 : 13 : errno = 0;
7 heikki.linnakangas@i 299 :GNC 13 : next_mxoff_val = strtouint64_strict(optarg, &endptr, 0);
1579 peter@eisentraut.org 300 [ + + + - :CBC 13 : if (endptr == optarg || *endptr != '\0' || errno != 0)
+ + ]
301 : : {
2451 302 : 2 : pg_log_error("invalid argument for option %s", "-O");
1348 tgl@sss.pgh.pa.us 303 : 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7496 304 : 2 : exit(1);
305 : : }
8 heikki.linnakangas@i 306 :GNC 11 : next_mxoff_given = true;
7496 tgl@sss.pgh.pa.us 307 :CBC 11 : break;
308 : :
8510 peter_e@gmx.net 309 : 12 : case 'l':
3820 fujii@postgresql.org 310 [ + + ]: 12 : if (strspn(optarg, "01234567890ABCDEFabcdef") != XLOG_FNAME_LEN)
311 : : {
2451 peter@eisentraut.org 312 : 1 : pg_log_error("invalid argument for option %s", "-l");
1348 tgl@sss.pgh.pa.us 313 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8510 peter_e@gmx.net 314 : 1 : exit(1);
315 : : }
316 : :
317 : : /*
318 : : * XLogFromFileName requires wal segment size which is not yet
319 : : * set. Hence wal details are set later on.
320 : : */
3010 andres@anarazel.de 321 : 11 : log_fname = pg_strdup(optarg);
8510 peter_e@gmx.net 322 : 11 : break;
323 : :
2823 324 : 4 : case 1:
325 : : {
326 : : int wal_segsize_mb;
327 : :
841 peter@eisentraut.org 328 [ + + ]: 4 : if (!option_parse_int(optarg, "--wal-segsize", 1, 1024, &wal_segsize_mb))
329 : 1 : exit(1);
8 heikki.linnakangas@i 330 :GNC 3 : wal_segsize_val = wal_segsize_mb * 1024 * 1024;
331 [ + - + + : 3 : if (!IsValidWalSegSize(wal_segsize_val))
+ - - + ]
840 dgustafsson@postgres 332 :CBC 1 : pg_fatal("argument of %s must be a power of two between 1 and 1024", "--wal-segsize");
8 heikki.linnakangas@i 333 :GNC 2 : wal_segsize_given = true;
841 peter@eisentraut.org 334 :CBC 2 : break;
335 : : }
336 : :
298 msawada@postgresql.o 337 : 3 : case 2:
338 : : {
339 : 3 : errno = 0;
340 : :
341 [ - + ]: 3 : if (pg_strcasecmp(optarg, "signed") == 0)
8 heikki.linnakangas@i 342 :UNC 0 : char_signedness_val = true;
298 msawada@postgresql.o 343 [ + + ]:CBC 3 : else if (pg_strcasecmp(optarg, "unsigned") == 0)
8 heikki.linnakangas@i 344 :GNC 2 : char_signedness_val = false;
345 : : else
346 : : {
298 msawada@postgresql.o 347 :CBC 1 : pg_log_error("invalid argument for option %s", "--char-signedness");
348 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
349 : 1 : exit(1);
350 : : }
8 heikki.linnakangas@i 351 :GNC 2 : char_signedness_given = true;
298 msawada@postgresql.o 352 :CBC 2 : break;
353 : : }
354 : :
8510 peter_e@gmx.net 355 : 1 : default:
356 : : /* getopt_long already emitted a complaint */
1348 tgl@sss.pgh.pa.us 357 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8510 peter_e@gmx.net 358 : 1 : exit(1);
359 : : }
360 : : }
361 : :
4071 heikki.linnakangas@i 362 [ + + + + ]: 119 : if (DataDir == NULL && optind < argc)
363 : 114 : DataDir = argv[optind++];
364 : :
365 : : /* Complain if any arguments remain */
366 [ + + ]: 119 : if (optind < argc)
367 : : {
2451 peter@eisentraut.org 368 : 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
369 : : argv[optind]);
1348 tgl@sss.pgh.pa.us 370 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4071 heikki.linnakangas@i 371 : 1 : exit(1);
372 : : }
373 : :
374 [ + + ]: 118 : if (DataDir == NULL)
375 : : {
2451 peter@eisentraut.org 376 : 1 : pg_log_error("no data directory specified");
1348 tgl@sss.pgh.pa.us 377 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8510 peter_e@gmx.net 378 : 1 : exit(1);
379 : : }
380 : :
381 : : /*
382 : : * Don't allow pg_resetwal to be run as root, to avoid overwriting the
383 : : * ownership of files in the data directory. We need only check for root
384 : : * -- any other user won't have sufficient permissions to modify files in
385 : : * the data directory.
386 : : */
387 : : #ifndef WIN32
7672 neilc@samurai.com 388 [ - + ]: 117 : if (geteuid() == 0)
389 : : {
2451 peter@eisentraut.org 390 :UBC 0 : pg_log_error("cannot be executed by \"root\"");
1348 tgl@sss.pgh.pa.us 391 : 0 : pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
392 : : progname);
7672 neilc@samurai.com 393 : 0 : exit(1);
394 : : }
395 : : #endif
396 : :
2451 peter@eisentraut.org 397 :CBC 117 : get_restricted_token();
398 : :
399 : : /* Set mask based on PGDATA permissions */
2810 sfrost@snowman.net 400 [ + + ]: 117 : if (!GetDataDirectoryCreatePerm(DataDir))
1348 tgl@sss.pgh.pa.us 401 : 1 : pg_fatal("could not read permissions of directory \"%s\": %m",
402 : : DataDir);
403 : :
2810 sfrost@snowman.net 404 : 116 : umask(pg_mode_mask);
405 : :
809 peter@eisentraut.org 406 [ - + ]: 116 : if (chdir(DataDir) < 0)
809 peter@eisentraut.org 407 :UBC 0 : pg_fatal("could not change directory to \"%s\": %m",
408 : : DataDir);
409 : :
410 : : /* Check that data directory matches our server version */
3123 tgl@sss.pgh.pa.us 411 :CBC 116 : CheckDataVersion();
412 : :
413 : : /*
414 : : * Check for a postmaster lock file --- if there is one, refuse to
415 : : * proceed, on grounds we might be interfering with a live installation.
416 : : */
4772 417 [ + + ]: 116 : if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0)
418 : : {
8510 peter_e@gmx.net 419 [ - + ]: 115 : if (errno != ENOENT)
1348 tgl@sss.pgh.pa.us 420 :UBC 0 : pg_fatal("could not open file \"%s\" for reading: %m",
421 : : "postmaster.pid");
422 : : }
423 : : else
424 : : {
2451 peter@eisentraut.org 425 :CBC 1 : pg_log_error("lock file \"%s\" exists", "postmaster.pid");
1348 tgl@sss.pgh.pa.us 426 : 1 : pg_log_error_hint("Is a server running? If not, delete the lock file and try again.");
7136 bruce@momjian.us 427 : 1 : exit(1);
428 : : }
429 : :
430 : : /*
431 : : * Attempt to read the existing pg_control file
432 : : */
2129 peter@eisentraut.org 433 [ + + ]: 115 : if (!read_controlfile())
7136 bruce@momjian.us 434 : 4 : GuessControlValues();
435 : :
436 : : /*
437 : : * If no new WAL segment size was specified, use the control file value.
438 : : */
8 heikki.linnakangas@i 439 [ + + ]:GNC 115 : if (wal_segsize_given)
440 : 2 : WalSegSz = wal_segsize_val;
441 : : else
2823 peter_e@gmx.net 442 :CBC 113 : WalSegSz = ControlFile.xlog_seg_size;
443 : :
3010 andres@anarazel.de 444 [ + + ]: 115 : if (log_fname != NULL)
445 : 11 : XLogFromFileName(log_fname, &minXlogTli, &minXlogSegNo, WalSegSz);
446 : :
447 : : /*
448 : : * Also look at existing segment files to set up newXlogSegNo
449 : : */
6948 tgl@sss.pgh.pa.us 450 : 115 : FindEndOfXLOG();
451 : :
452 : : /*
453 : : * If we're not going to proceed with the reset, print the current control
454 : : * file parameters.
455 : : */
4387 heikki.linnakangas@i 456 [ + + + + : 115 : if ((guessed && !force) || noupdate)
+ + ]
457 : 42 : PrintControlValues(guessed);
458 : :
459 : : /*
460 : : * Adjust fields if required by switches. (Do this now so that printout,
461 : : * if any, includes these values.)
462 : : */
8 heikki.linnakangas@i 463 [ + + ]:GNC 115 : if (next_xid_epoch_given)
464 : : ControlFile.checkPointCopy.nextXid =
465 : 12 : FullTransactionIdFromEpochAndXid(next_xid_epoch_val,
1953 andres@anarazel.de 466 :CBC 12 : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
467 : :
8 heikki.linnakangas@i 468 [ + + ]:GNC 115 : if (oldest_xid_given)
469 : : {
470 : 11 : ControlFile.checkPointCopy.oldestXid = oldest_xid_val;
1604 bruce@momjian.us 471 :CBC 11 : ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
472 : : }
473 : :
8 heikki.linnakangas@i 474 [ + + ]:GNC 115 : if (next_xid_given)
475 : : ControlFile.checkPointCopy.nextXid =
1953 andres@anarazel.de 476 :CBC 11 : FullTransactionIdFromEpochAndXid(EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid),
477 : : next_xid_val);
478 : :
8 heikki.linnakangas@i 479 [ + + ]:GNC 115 : if (commit_ts_xids_given)
480 : : {
481 : 11 : ControlFile.checkPointCopy.oldestCommitTsXid = oldest_commit_ts_xid_val;
482 : 11 : ControlFile.checkPointCopy.newestCommitTsXid = newest_commit_ts_xid_val;
483 : : }
484 : :
485 [ + + ]: 115 : if (next_oid_given)
486 : 11 : ControlFile.checkPointCopy.nextOid = next_oid_val;
487 : :
488 [ + + ]: 115 : if (mxids_given)
489 : : {
490 : 12 : ControlFile.checkPointCopy.nextMulti = next_mxid_val;
491 : :
492 : 12 : ControlFile.checkPointCopy.oldestMulti = oldest_mxid_val;
4710 alvherre@alvh.no-ip. 493 [ - + ]:CBC 12 : if (ControlFile.checkPointCopy.oldestMulti < FirstMultiXactId)
4710 alvherre@alvh.no-ip. 494 :UBC 0 : ControlFile.checkPointCopy.oldestMulti += FirstMultiXactId;
4710 alvherre@alvh.no-ip. 495 :CBC 12 : ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
496 : : }
497 : :
8 heikki.linnakangas@i 498 [ + + ]:GNC 115 : if (next_mxoff_given)
499 : 11 : ControlFile.checkPointCopy.nextMultiOffset = next_mxoff_val;
500 : :
7666 tgl@sss.pgh.pa.us 501 [ - + ]:CBC 115 : if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
502 : : {
7666 tgl@sss.pgh.pa.us 503 :UBC 0 : ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli;
4691 heikki.linnakangas@i 504 : 0 : ControlFile.checkPointCopy.PrevTimeLineID = minXlogTli;
505 : : }
506 : :
8 heikki.linnakangas@i 507 [ + + ]:GNC 115 : if (wal_segsize_given)
2823 peter_e@gmx.net 508 :CBC 2 : ControlFile.xlog_seg_size = WalSegSz;
509 : :
8 heikki.linnakangas@i 510 [ + + ]:GNC 115 : if (char_signedness_given)
511 : 2 : ControlFile.default_char_signedness = char_signedness_val;
512 : :
4923 heikki.linnakangas@i 513 [ + + ]:CBC 115 : if (minXlogSegNo > newXlogSegNo)
514 : 3 : newXlogSegNo = minXlogSegNo;
515 : :
810 peter@eisentraut.org 516 [ + + ]: 115 : if (noupdate)
517 : : {
518 : 41 : PrintNewControlValues();
519 : 41 : exit(0);
520 : : }
521 : :
522 : : /*
523 : : * If we had to guess anything, and -f was not given, just print the
524 : : * guessed values and exit.
525 : : */
526 [ + + + + ]: 74 : if (guessed && !force)
527 : : {
4387 heikki.linnakangas@i 528 : 1 : PrintNewControlValues();
810 peter@eisentraut.org 529 : 1 : pg_log_error("not proceeding because control file values were guessed");
530 : 1 : pg_log_error_hint("If these values seem acceptable, use -f to force reset.");
531 : 1 : exit(1);
532 : : }
533 : :
534 : : /*
535 : : * Don't reset from a dirty pg_control without -f, either.
536 : : */
7136 bruce@momjian.us 537 [ + + + + ]: 73 : if (ControlFile.state != DB_SHUTDOWNED && !force)
538 : : {
810 peter@eisentraut.org 539 : 1 : pg_log_error("database server was not shut down cleanly");
540 : 1 : pg_log_error_detail("Resetting the write-ahead log might cause data to be lost.");
541 : 1 : pg_log_error_hint("If you want to proceed anyway, use -f to force reset.");
8510 peter_e@gmx.net 542 : 1 : exit(1);
543 : : }
544 : :
545 : : /*
546 : : * Else, do the dirty deed.
547 : : */
548 : 72 : RewriteControlFile();
549 : 72 : KillExistingXLOG();
6071 tgl@sss.pgh.pa.us 550 : 72 : KillExistingArchiveStatus();
727 rhaas@postgresql.org 551 : 72 : KillExistingWALSummaries();
8510 peter_e@gmx.net 552 : 72 : WriteEmptyXLOG();
553 : :
3140 554 : 72 : printf(_("Write-ahead log reset\n"));
8510 555 : 72 : return 0;
556 : : }
557 : :
558 : :
559 : : /*
560 : : * Look at the version string stored in PG_VERSION and decide if this utility
561 : : * can be run safely or not.
562 : : *
563 : : * We don't want to inject pg_control and WAL files that are for a different
564 : : * major version; that can't do anything good. Note that we don't treat
565 : : * mismatching version info in pg_control as a reason to bail out, because
566 : : * recovering from a corrupted pg_control is one of the main reasons for this
567 : : * program to exist at all. However, PG_VERSION is unlikely to get corrupted,
568 : : * and if it were it would be easy to fix by hand. So let's make this check
569 : : * to prevent simple user errors.
570 : : */
571 : : static void
3123 tgl@sss.pgh.pa.us 572 : 116 : CheckDataVersion(void)
573 : : {
574 : : char *version_str;
62 michael@paquier.xyz 575 :GNC 116 : uint32 version = get_pg_version(".", &version_str);
576 : :
577 [ - + ]: 116 : if (GET_PG_MAJORVERSION_NUM(version) != PG_MAJORVERSION_NUM)
578 : : {
2451 peter@eisentraut.org 579 :UBC 0 : pg_log_error("data directory is of wrong version");
1348 tgl@sss.pgh.pa.us 580 : 0 : pg_log_error_detail("File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".",
581 : : "PG_VERSION",
582 : : version_str,
583 : : PG_MAJORVERSION);
3123 584 : 0 : exit(1);
585 : : }
3123 tgl@sss.pgh.pa.us 586 :CBC 116 : }
587 : :
588 : :
589 : : /*
590 : : * Try to read the existing pg_control file.
591 : : *
592 : : * This routine is also responsible for updating old pg_control versions
593 : : * to the current format. (Currently we don't do anything of the sort.)
594 : : */
595 : : static bool
2129 peter@eisentraut.org 596 : 115 : read_controlfile(void)
597 : : {
598 : : int fd;
599 : : int len;
600 : : char *buffer;
601 : : pg_crc32c crc;
602 : :
6292 magnus@hagander.net 603 [ - + ]: 115 : if ((fd = open(XLOG_CONTROL_FILE, O_RDONLY | PG_BINARY, 0)) < 0)
604 : : {
605 : : /*
606 : : * If pg_control is not there at all, or we can't read it, the odds
607 : : * are we've been handed a bad DataDir path, so give up. User can do
608 : : * "touch pg_control" to force us to proceed.
609 : : */
2451 peter@eisentraut.org 610 :UBC 0 : pg_log_error("could not open file \"%s\" for reading: %m",
611 : : XLOG_CONTROL_FILE);
8522 bruce@momjian.us 612 [ # # ]: 0 : if (errno == ENOENT)
1348 tgl@sss.pgh.pa.us 613 : 0 : pg_log_error_hint("If you are sure the data directory path is correct, execute\n"
614 : : " touch %s\n"
615 : : "and try again.",
616 : : XLOG_CONTROL_FILE);
8522 bruce@momjian.us 617 : 0 : exit(1);
618 : : }
619 : :
620 : : /* Use malloc to ensure we have a maxaligned buffer */
3072 tgl@sss.pgh.pa.us 621 :CBC 115 : buffer = (char *) pg_malloc(PG_CONTROL_FILE_SIZE);
622 : :
623 : 115 : len = read(fd, buffer, PG_CONTROL_FILE_SIZE);
8522 bruce@momjian.us 624 [ - + ]: 115 : if (len < 0)
1348 tgl@sss.pgh.pa.us 625 :UBC 0 : pg_fatal("could not read file \"%s\": %m", XLOG_CONTROL_FILE);
8522 bruce@momjian.us 626 :CBC 115 : close(fd);
627 : :
628 [ + - ]: 115 : if (len >= sizeof(ControlFileData) &&
3100 tgl@sss.pgh.pa.us 629 [ + + ]: 115 : ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
630 : : {
631 : : /* Check the CRC. */
4060 heikki.linnakangas@i 632 : 114 : INIT_CRC32C(crc);
633 : 114 : COMP_CRC32C(crc,
634 : : buffer,
635 : : offsetof(ControlFileData, crc));
636 : 114 : FIN_CRC32C(crc);
637 : :
3010 andres@anarazel.de 638 [ + + ]: 114 : if (!EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
639 : : {
640 : : /* We will use the data but treat it as guessed. */
2451 peter@eisentraut.org 641 : 3 : pg_log_warning("pg_control exists but has invalid CRC; proceed with caution");
3010 andres@anarazel.de 642 : 3 : guessed = true;
643 : : }
644 : :
8522 bruce@momjian.us 645 : 114 : memcpy(&ControlFile, buffer, sizeof(ControlFile));
646 : :
647 : : /* return false if WAL segment size is not valid */
2823 peter_e@gmx.net 648 [ + + + - : 114 : if (!IsValidWalSegSize(ControlFile.xlog_seg_size))
+ - - + ]
649 : : {
2451 peter@eisentraut.org 650 : 3 : pg_log_warning(ngettext("pg_control specifies invalid WAL segment size (%d byte); proceed with caution",
651 : : "pg_control specifies invalid WAL segment size (%d bytes); proceed with caution",
652 : : ControlFile.xlog_seg_size),
653 : : ControlFile.xlog_seg_size);
2825 peter_e@gmx.net 654 : 3 : return false;
655 : : }
656 : :
8522 bruce@momjian.us 657 : 111 : return true;
658 : : }
659 : :
660 : : /* Looks like it's a mess. */
2451 peter@eisentraut.org 661 : 1 : pg_log_warning("pg_control exists but is broken or wrong version; ignoring it");
8522 bruce@momjian.us 662 : 1 : return false;
663 : : }
664 : :
665 : :
666 : : /*
667 : : * Guess at pg_control values when we can't read the old ones.
668 : : */
669 : : static void
7136 670 : 4 : GuessControlValues(void)
671 : : {
672 : : uint64 sysidentifier;
673 : : struct timeval tv;
674 : :
675 : : /*
676 : : * Set up a completely default set of pg_control values.
677 : : */
678 : 4 : guessed = true;
8522 679 : 4 : memset(&ControlFile, 0, sizeof(ControlFile));
680 : :
681 : 4 : ControlFile.pg_control_version = PG_CONTROL_VERSION;
682 : 4 : ControlFile.catalog_version_no = CATALOG_VERSION_NO;
683 : :
684 : : /*
685 : : * Create a new unique installation identifier, since we can no longer use
686 : : * any old XLOG records. See notes in xlog.c about the algorithm.
687 : : */
7136 688 : 4 : gettimeofday(&tv, NULL);
689 : 4 : sysidentifier = ((uint64) tv.tv_sec) << 32;
4221 tgl@sss.pgh.pa.us 690 : 4 : sysidentifier |= ((uint64) tv.tv_usec) << 12;
691 : 4 : sysidentifier |= getpid() & 0xFFF;
692 : :
7136 bruce@momjian.us 693 : 4 : ControlFile.system_identifier = sysidentifier;
694 : :
4923 heikki.linnakangas@i 695 : 4 : ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
7136 bruce@momjian.us 696 : 4 : ControlFile.checkPointCopy.ThisTimeLineID = 1;
4691 heikki.linnakangas@i 697 : 4 : ControlFile.checkPointCopy.PrevTimeLineID = 1;
5074 simon@2ndQuadrant.co 698 : 4 : ControlFile.checkPointCopy.fullPageWrites = false;
699 : : ControlFile.checkPointCopy.nextXid =
2455 tmunro@postgresql.or 700 : 4 : FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId);
1615 tgl@sss.pgh.pa.us 701 : 4 : ControlFile.checkPointCopy.nextOid = FirstGenbkiObjectId;
7136 bruce@momjian.us 702 : 4 : ControlFile.checkPointCopy.nextMulti = FirstMultiXactId;
703 : 4 : ControlFile.checkPointCopy.nextMultiOffset = 0;
5951 tgl@sss.pgh.pa.us 704 : 4 : ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId;
705 : 4 : ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
4710 alvherre@alvh.no-ip. 706 : 4 : ControlFile.checkPointCopy.oldestMulti = FirstMultiXactId;
707 : 4 : ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
6512 tgl@sss.pgh.pa.us 708 : 4 : ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
5711 709 : 4 : ControlFile.checkPointCopy.oldestActiveXid = InvalidTransactionId;
710 : :
7136 bruce@momjian.us 711 : 4 : ControlFile.state = DB_SHUTDOWNED;
6512 tgl@sss.pgh.pa.us 712 : 4 : ControlFile.time = (pg_time_t) time(NULL);
7136 bruce@momjian.us 713 : 4 : ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
2242 michael@paquier.xyz 714 : 4 : ControlFile.unloggedLSN = FirstNormalUnloggedLSN;
715 : :
716 : : /* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */
717 : :
5711 tgl@sss.pgh.pa.us 718 : 4 : ControlFile.wal_level = WAL_LEVEL_MINIMAL;
4378 fujii@postgresql.org 719 : 4 : ControlFile.wal_log_hints = false;
4031 alvherre@alvh.no-ip. 720 : 4 : ControlFile.track_commit_timestamp = false;
5711 tgl@sss.pgh.pa.us 721 : 4 : ControlFile.MaxConnections = 100;
2499 michael@paquier.xyz 722 : 4 : ControlFile.max_wal_senders = 10;
3298 rhaas@postgresql.org 723 : 4 : ControlFile.max_worker_processes = 8;
5711 tgl@sss.pgh.pa.us 724 : 4 : ControlFile.max_prepared_xacts = 0;
725 : 4 : ControlFile.max_locks_per_xact = 64;
726 : :
7379 727 : 4 : ControlFile.maxAlign = MAXIMUM_ALIGNOF;
728 : 4 : ControlFile.floatFormat = FLOATFORMAT_VALUE;
8522 bruce@momjian.us 729 : 4 : ControlFile.blcksz = BLCKSZ;
730 : 4 : ControlFile.relseg_size = RELSEG_SIZE;
35 heikki.linnakangas@i 731 :GNC 4 : ControlFile.slru_pages_per_segment = SLRU_PAGES_PER_SEGMENT;
2823 peter_e@gmx.net 732 :CBC 4 : ControlFile.xlog_blcksz = XLOG_BLCKSZ;
733 : 4 : ControlFile.xlog_seg_size = DEFAULT_XLOG_SEG_SIZE;
8476 tgl@sss.pgh.pa.us 734 : 4 : ControlFile.nameDataLen = NAMEDATALEN;
7567 735 : 4 : ControlFile.indexMaxKeys = INDEX_MAX_KEYS;
6832 736 : 4 : ControlFile.toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE;
4212 737 : 4 : ControlFile.loblksize = LOBLKSIZE;
125 tgl@sss.pgh.pa.us 738 :GNC 4 : ControlFile.float8ByVal = true; /* vestigial */
739 : :
740 : : /*
741 : : * XXX eventually, should try to grovel through old XLOG to develop more
742 : : * accurate values for TimeLineID, nextXID, etc.
743 : : */
8522 bruce@momjian.us 744 :CBC 4 : }
745 : :
746 : :
747 : : /*
748 : : * Print the guessed pg_control values when we had to guess.
749 : : *
750 : : * NB: this display should be just those fields that will not be
751 : : * reset by RewriteControlFile().
752 : : */
753 : : static void
7136 754 : 42 : PrintControlValues(bool guessed)
755 : : {
756 [ + + ]: 42 : if (guessed)
757 : 3 : printf(_("Guessed pg_control values:\n\n"));
758 : : else
4387 heikki.linnakangas@i 759 : 39 : printf(_("Current pg_control values:\n\n"));
760 : :
7057 tgl@sss.pgh.pa.us 761 : 42 : printf(_("pg_control version number: %u\n"),
762 : : ControlFile.pg_control_version);
763 : 42 : printf(_("Catalog version number: %u\n"),
764 : : ControlFile.catalog_version_no);
262 peter@eisentraut.org 765 : 42 : printf(_("Database system identifier: %" PRIu64 "\n"),
766 : : ControlFile.system_identifier);
7057 tgl@sss.pgh.pa.us 767 : 42 : printf(_("Latest checkpoint's TimeLineID: %u\n"),
768 : : ControlFile.checkPointCopy.ThisTimeLineID);
4940 peter_e@gmx.net 769 [ + + ]: 42 : printf(_("Latest checkpoint's full_page_writes: %s\n"),
770 : : ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
3595 mail@joeconway.com 771 : 42 : printf(_("Latest checkpoint's NextXID: %u:%u\n"),
772 : : EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid),
773 : : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
7057 tgl@sss.pgh.pa.us 774 : 42 : printf(_("Latest checkpoint's NextOID: %u\n"),
775 : : ControlFile.checkPointCopy.nextOid);
776 : 42 : printf(_("Latest checkpoint's NextMultiXactId: %u\n"),
777 : : ControlFile.checkPointCopy.nextMulti);
7 heikki.linnakangas@i 778 :GNC 42 : printf(_("Latest checkpoint's NextMultiOffset: %" PRIu64 "\n"),
779 : : ControlFile.checkPointCopy.nextMultiOffset);
5951 tgl@sss.pgh.pa.us 780 :CBC 42 : printf(_("Latest checkpoint's oldestXID: %u\n"),
781 : : ControlFile.checkPointCopy.oldestXid);
782 : 42 : printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
783 : : ControlFile.checkPointCopy.oldestXidDB);
5711 784 : 42 : printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
785 : : ControlFile.checkPointCopy.oldestActiveXid);
4710 alvherre@alvh.no-ip. 786 : 42 : printf(_("Latest checkpoint's oldestMultiXid: %u\n"),
787 : : ControlFile.checkPointCopy.oldestMulti);
788 : 42 : printf(_("Latest checkpoint's oldestMulti's DB: %u\n"),
789 : : ControlFile.checkPointCopy.oldestMultiDB);
3641 mail@joeconway.com 790 : 42 : printf(_("Latest checkpoint's oldestCommitTsXid:%u\n"),
791 : : ControlFile.checkPointCopy.oldestCommitTsXid);
792 : 42 : printf(_("Latest checkpoint's newestCommitTsXid:%u\n"),
793 : : ControlFile.checkPointCopy.newestCommitTsXid);
7057 tgl@sss.pgh.pa.us 794 : 42 : printf(_("Maximum data alignment: %u\n"),
795 : : ControlFile.maxAlign);
796 : : /* we don't print floatFormat since can't say much useful about it */
797 : 42 : printf(_("Database block size: %u\n"),
798 : : ControlFile.blcksz);
799 : 42 : printf(_("Blocks per segment of large relation: %u\n"),
800 : : ControlFile.relseg_size);
35 heikki.linnakangas@i 801 :GNC 42 : printf(_("Pages per SLRU segment: %u\n"),
802 : : ControlFile.slru_pages_per_segment);
7057 tgl@sss.pgh.pa.us 803 :CBC 42 : printf(_("WAL block size: %u\n"),
804 : : ControlFile.xlog_blcksz);
805 : 42 : printf(_("Bytes per WAL segment: %u\n"),
806 : : ControlFile.xlog_seg_size);
807 : 42 : printf(_("Maximum length of identifiers: %u\n"),
808 : : ControlFile.nameDataLen);
809 : 42 : printf(_("Maximum columns in an index: %u\n"),
810 : : ControlFile.indexMaxKeys);
6832 811 : 42 : printf(_("Maximum size of a TOAST chunk: %u\n"),
812 : : ControlFile.toast_max_chunk_size);
4212 813 : 42 : printf(_("Size of a large-object chunk: %u\n"),
814 : : ControlFile.loblksize);
815 : : /* This is no longer configurable, but users may still expect to see it: */
8476 816 : 42 : printf(_("Date/time type storage: %s\n"),
817 : : _("64-bit integers"));
6448 818 [ + - ]: 42 : printf(_("Float8 argument passing: %s\n"),
819 : : (ControlFile.float8ByVal ? _("by value") : _("by reference")));
4613 simon@2ndQuadrant.co 820 : 42 : printf(_("Data page checksum version: %u\n"),
821 : : ControlFile.data_checksum_version);
298 msawada@postgresql.o 822 [ + + ]: 42 : printf(_("Default char data signedness: %s\n"),
823 : : (ControlFile.default_char_signedness ? _("signed") : _("unsigned")));
8522 bruce@momjian.us 824 : 42 : }
825 : :
826 : :
827 : : /*
828 : : * Print the values to be changed.
829 : : */
830 : : static void
3776 andres@anarazel.de 831 : 42 : PrintNewControlValues(void)
832 : : {
833 : : char fname[MAXFNAMELEN];
834 : :
835 : : /* This will be always printed in order to keep format same. */
4387 heikki.linnakangas@i 836 : 42 : printf(_("\n\nValues to be changed:\n\n"));
837 : :
3010 andres@anarazel.de 838 : 42 : XLogFileName(fname, ControlFile.checkPointCopy.ThisTimeLineID,
839 : : newXlogSegNo, WalSegSz);
1188 tgl@sss.pgh.pa.us 840 : 42 : printf(_("First log segment after reset: %s\n"), fname);
841 : :
8 heikki.linnakangas@i 842 [ + + ]:GNC 42 : if (mxids_given)
843 : : {
4387 heikki.linnakangas@i 844 :CBC 1 : printf(_("NextMultiXactId: %u\n"),
845 : : ControlFile.checkPointCopy.nextMulti);
846 : 1 : printf(_("OldestMultiXid: %u\n"),
847 : : ControlFile.checkPointCopy.oldestMulti);
848 : 1 : printf(_("OldestMulti's DB: %u\n"),
849 : : ControlFile.checkPointCopy.oldestMultiDB);
850 : : }
851 : :
8 heikki.linnakangas@i 852 [ + + ]:GNC 42 : if (next_mxoff_given)
853 : : {
7 854 : 1 : printf(_("NextMultiOffset: %" PRIu64 "\n"),
855 : : ControlFile.checkPointCopy.nextMultiOffset);
856 : : }
857 : :
8 858 [ + + ]: 42 : if (next_oid_given)
859 : : {
4387 heikki.linnakangas@i 860 :CBC 1 : printf(_("NextOID: %u\n"),
861 : : ControlFile.checkPointCopy.nextOid);
862 : : }
863 : :
8 heikki.linnakangas@i 864 [ + + ]:GNC 42 : if (next_xid_given)
865 : : {
4387 heikki.linnakangas@i 866 :CBC 1 : printf(_("NextXID: %u\n"),
867 : : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
868 : : }
869 : :
8 heikki.linnakangas@i 870 [ + + ]:GNC 42 : if (oldest_xid_given)
871 : : {
4387 heikki.linnakangas@i 872 :CBC 1 : printf(_("OldestXID: %u\n"),
873 : : ControlFile.checkPointCopy.oldestXid);
874 : 1 : printf(_("OldestXID's DB: %u\n"),
875 : : ControlFile.checkPointCopy.oldestXidDB);
876 : : }
877 : :
8 heikki.linnakangas@i 878 [ + + ]:GNC 42 : if (next_xid_epoch_given)
879 : : {
4147 peter_e@gmx.net 880 :CBC 1 : printf(_("NextXID epoch: %u\n"),
881 : : EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
882 : : }
883 : :
8 heikki.linnakangas@i 884 [ + + ]:GNC 42 : if (commit_ts_xids_given)
885 : : {
3641 mail@joeconway.com 886 :CBC 1 : printf(_("oldestCommitTsXid: %u\n"),
887 : : ControlFile.checkPointCopy.oldestCommitTsXid);
3641 mail@joeconway.com 888 :GBC 1 : printf(_("newestCommitTsXid: %u\n"),
889 : : ControlFile.checkPointCopy.newestCommitTsXid);
890 : : }
891 : :
8 heikki.linnakangas@i 892 [ + + ]:GNC 42 : if (wal_segsize_given)
893 : : {
2823 peter_e@gmx.net 894 :CBC 1 : printf(_("Bytes per WAL segment: %u\n"),
895 : : ControlFile.xlog_seg_size);
896 : : }
4387 heikki.linnakangas@i 897 : 42 : }
898 : :
899 : :
900 : : /*
901 : : * Write out the new pg_control file.
902 : : */
903 : : static void
7136 bruce@momjian.us 904 : 72 : RewriteControlFile(void)
905 : : {
906 : : /*
907 : : * Adjust fields as needed to force an empty XLOG starting at
908 : : * newXlogSegNo.
909 : : */
2717 alvherre@alvh.no-ip. 910 : 72 : XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD, WalSegSz,
911 : : ControlFile.checkPointCopy.redo);
6512 tgl@sss.pgh.pa.us 912 : 72 : ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
913 : :
8522 bruce@momjian.us 914 : 72 : ControlFile.state = DB_SHUTDOWNED;
915 : 72 : ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
4923 heikki.linnakangas@i 916 : 72 : ControlFile.minRecoveryPoint = 0;
4760 917 : 72 : ControlFile.minRecoveryPointTLI = 0;
4923 918 : 72 : ControlFile.backupStartPoint = 0;
919 : 72 : ControlFile.backupEndPoint = 0;
5235 920 : 72 : ControlFile.backupEndRequired = false;
921 : :
922 : : /*
923 : : * Force the defaults for max_* settings. The values don't really matter
924 : : * as long as wal_level='minimal'; the postmaster will reset these fields
925 : : * anyway at startup.
926 : : */
5711 tgl@sss.pgh.pa.us 927 : 72 : ControlFile.wal_level = WAL_LEVEL_MINIMAL;
4378 fujii@postgresql.org 928 : 72 : ControlFile.wal_log_hints = false;
4031 alvherre@alvh.no-ip. 929 : 72 : ControlFile.track_commit_timestamp = false;
5711 heikki.linnakangas@i 930 : 72 : ControlFile.MaxConnections = 100;
2499 michael@paquier.xyz 931 : 72 : ControlFile.max_wal_senders = 10;
3298 rhaas@postgresql.org 932 : 72 : ControlFile.max_worker_processes = 8;
5711 heikki.linnakangas@i 933 : 72 : ControlFile.max_prepared_xacts = 0;
934 : 72 : ControlFile.max_locks_per_xact = 64;
935 : :
936 : : /* The control file gets flushed here. */
2451 peter@eisentraut.org 937 : 72 : update_controlfile(".", &ControlFile, true);
8522 bruce@momjian.us 938 : 72 : }
939 : :
940 : :
941 : : /*
942 : : * Scan existing XLOG files and determine the highest existing WAL address
943 : : *
944 : : * On entry, ControlFile.checkPointCopy.redo and ControlFile.xlog_seg_size
945 : : * are assumed valid (note that we allow the old xlog seg size to differ
946 : : * from what we're using). On exit, newXlogSegNo is set to suitable
947 : : * value for the beginning of replacement WAL (in our seg size).
948 : : */
949 : : static void
6948 tgl@sss.pgh.pa.us 950 : 115 : FindEndOfXLOG(void)
951 : : {
952 : : DIR *xldir;
953 : : struct dirent *xlde;
954 : : uint64 xlogbytepos;
955 : :
956 : : /*
957 : : * Initialize the max() computation using the last checkpoint address from
958 : : * old pg_control. Note that for the moment we are working with segment
959 : : * numbering according to the old xlog seg size.
960 : : */
1168 michael@paquier.xyz 961 : 115 : XLByteToSeg(ControlFile.checkPointCopy.redo, newXlogSegNo,
962 : : ControlFile.xlog_seg_size);
963 : :
964 : : /*
965 : : * Scan the pg_wal directory to find existing WAL segment files. We assume
966 : : * any present have been used; in most scenarios this should be
967 : : * conservative, because of xlog.c's attempts to pre-create files.
968 : : */
6948 tgl@sss.pgh.pa.us 969 : 115 : xldir = opendir(XLOGDIR);
970 [ - + ]: 115 : if (xldir == NULL)
1348 tgl@sss.pgh.pa.us 971 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
972 : :
4288 bruce@momjian.us 973 [ + + ]:CBC 866 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
974 : : {
3819 fujii@postgresql.org 975 [ + + - + ]: 1212 : if (IsXLogFileName(xlde->d_name) ||
976 : 461 : IsPartialXLogFileName(xlde->d_name))
977 : : {
978 : : TimeLineID tli;
979 : : XLogSegNo segno;
980 : :
981 : : /* Use the segment size from the control file */
1168 michael@paquier.xyz 982 : 290 : XLogFromFileName(xlde->d_name, &tli, &segno,
983 : 290 : ControlFile.xlog_seg_size);
984 : :
985 : : /*
986 : : * Note: we take the max of all files found, regardless of their
987 : : * timelines. Another possibility would be to ignore files of
988 : : * timelines other than the target TLI, but this seems safer.
989 : : * Better too large a result than too small...
990 : : */
4923 heikki.linnakangas@i 991 [ + + ]: 290 : if (segno > newXlogSegNo)
992 : 36 : newXlogSegNo = segno;
993 : : }
994 : : }
995 : :
6948 tgl@sss.pgh.pa.us 996 [ - + ]: 115 : if (errno)
1348 tgl@sss.pgh.pa.us 997 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
998 : :
4288 bruce@momjian.us 999 [ - + ]:CBC 115 : if (closedir(xldir))
1348 tgl@sss.pgh.pa.us 1000 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
1001 : :
1002 : : /*
1003 : : * Finally, convert to new xlog seg size, and advance by one to ensure we
1004 : : * are in virgin territory.
1005 : : */
4923 heikki.linnakangas@i 1006 :CBC 115 : xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
2823 peter_e@gmx.net 1007 : 115 : newXlogSegNo = (xlogbytepos + ControlFile.xlog_seg_size - 1) / WalSegSz;
4923 heikki.linnakangas@i 1008 : 115 : newXlogSegNo++;
6948 tgl@sss.pgh.pa.us 1009 : 115 : }
1010 : :
1011 : :
1012 : : /*
1013 : : * Remove existing XLOG files
1014 : : */
1015 : : static void
8522 bruce@momjian.us 1016 : 72 : KillExistingXLOG(void)
1017 : : {
1018 : : DIR *xldir;
1019 : : struct dirent *xlde;
1020 : : char path[MAXPGPATH + sizeof(XLOGDIR)];
1021 : :
7470 tgl@sss.pgh.pa.us 1022 : 72 : xldir = opendir(XLOGDIR);
8522 bruce@momjian.us 1023 [ - + ]: 72 : if (xldir == NULL)
1348 tgl@sss.pgh.pa.us 1024 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
1025 : :
4288 bruce@momjian.us 1026 [ + + ]:CBC 454 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1027 : : {
3819 fujii@postgresql.org 1028 [ + + - + ]: 671 : if (IsXLogFileName(xlde->d_name) ||
1029 : 289 : IsPartialXLogFileName(xlde->d_name))
1030 : : {
3171 peter_e@gmx.net 1031 : 93 : snprintf(path, sizeof(path), "%s/%s", XLOGDIR, xlde->d_name);
8522 bruce@momjian.us 1032 [ - + ]: 93 : if (unlink(path) < 0)
1348 tgl@sss.pgh.pa.us 1033 :UBC 0 : pg_fatal("could not delete file \"%s\": %m", path);
1034 : : }
1035 : : }
1036 : :
8522 bruce@momjian.us 1037 [ - + ]:CBC 72 : if (errno)
1348 tgl@sss.pgh.pa.us 1038 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
1039 : :
4288 bruce@momjian.us 1040 [ - + ]:CBC 72 : if (closedir(xldir))
1348 tgl@sss.pgh.pa.us 1041 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
8522 bruce@momjian.us 1042 :CBC 72 : }
1043 : :
1044 : :
1045 : : /*
1046 : : * Remove existing archive status files
1047 : : */
1048 : : static void
6071 tgl@sss.pgh.pa.us 1049 : 72 : KillExistingArchiveStatus(void)
1050 : : {
1051 : : #define ARCHSTATDIR XLOGDIR "/archive_status"
1052 : :
1053 : : DIR *xldir;
1054 : : struct dirent *xlde;
1055 : : char path[MAXPGPATH + sizeof(ARCHSTATDIR)];
1056 : :
1057 : 72 : xldir = opendir(ARCHSTATDIR);
1058 [ - + ]: 72 : if (xldir == NULL)
1348 tgl@sss.pgh.pa.us 1059 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", ARCHSTATDIR);
1060 : :
4288 bruce@momjian.us 1061 [ + + ]:CBC 216 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1062 : : {
3820 fujii@postgresql.org 1063 [ - + ]: 144 : if (strspn(xlde->d_name, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
3820 fujii@postgresql.org 1064 [ # # ]:UBC 0 : (strcmp(xlde->d_name + XLOG_FNAME_LEN, ".ready") == 0 ||
3819 1065 [ # # ]: 0 : strcmp(xlde->d_name + XLOG_FNAME_LEN, ".done") == 0 ||
1066 [ # # ]: 0 : strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.ready") == 0 ||
1067 [ # # ]: 0 : strcmp(xlde->d_name + XLOG_FNAME_LEN, ".partial.done") == 0))
1068 : : {
3171 peter_e@gmx.net 1069 : 0 : snprintf(path, sizeof(path), "%s/%s", ARCHSTATDIR, xlde->d_name);
6071 tgl@sss.pgh.pa.us 1070 [ # # ]: 0 : if (unlink(path) < 0)
1348 1071 : 0 : pg_fatal("could not delete file \"%s\": %m", path);
1072 : : }
1073 : : }
1074 : :
6071 tgl@sss.pgh.pa.us 1075 [ - + ]:CBC 72 : if (errno)
1348 tgl@sss.pgh.pa.us 1076 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", ARCHSTATDIR);
1077 : :
4288 bruce@momjian.us 1078 [ - + ]:CBC 72 : if (closedir(xldir))
1348 tgl@sss.pgh.pa.us 1079 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
6071 tgl@sss.pgh.pa.us 1080 :CBC 72 : }
1081 : :
1082 : : /*
1083 : : * Remove existing WAL summary files
1084 : : */
1085 : : static void
727 rhaas@postgresql.org 1086 : 72 : KillExistingWALSummaries(void)
1087 : : {
1088 : : #define WALSUMMARYDIR XLOGDIR "/summaries"
1089 : : #define WALSUMMARY_NHEXCHARS 40
1090 : :
1091 : : DIR *xldir;
1092 : : struct dirent *xlde;
1093 : : char path[MAXPGPATH + sizeof(WALSUMMARYDIR)];
1094 : :
1095 : 72 : xldir = opendir(WALSUMMARYDIR);
1096 [ - + ]: 72 : if (xldir == NULL)
727 rhaas@postgresql.org 1097 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", WALSUMMARYDIR);
1098 : :
727 rhaas@postgresql.org 1099 [ + + ]:CBC 216 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1100 : : {
1101 [ - + ]: 144 : if (strspn(xlde->d_name, "0123456789ABCDEF") == WALSUMMARY_NHEXCHARS &&
727 rhaas@postgresql.org 1102 [ # # ]:UBC 0 : strcmp(xlde->d_name + WALSUMMARY_NHEXCHARS, ".summary") == 0)
1103 : : {
1104 : 0 : snprintf(path, sizeof(path), "%s/%s", WALSUMMARYDIR, xlde->d_name);
1105 [ # # ]: 0 : if (unlink(path) < 0)
1106 : 0 : pg_fatal("could not delete file \"%s\": %m", path);
1107 : : }
1108 : : }
1109 : :
727 rhaas@postgresql.org 1110 [ - + ]:CBC 72 : if (errno)
727 rhaas@postgresql.org 1111 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", WALSUMMARYDIR);
1112 : :
727 rhaas@postgresql.org 1113 [ - + ]:CBC 72 : if (closedir(xldir))
727 rhaas@postgresql.org 1114 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
727 rhaas@postgresql.org 1115 :CBC 72 : }
1116 : :
1117 : : /*
1118 : : * Write an empty XLOG file, containing only the checkpoint record
1119 : : * already set up in ControlFile.
1120 : : */
1121 : : static void
8522 bruce@momjian.us 1122 : 72 : WriteEmptyXLOG(void)
1123 : : {
1124 : : PGAlignedXLogBlock buffer;
1125 : : XLogPageHeader page;
1126 : : XLogLongPageHeader longpage;
1127 : : XLogRecord *record;
1128 : : pg_crc32c crc;
1129 : : char path[MAXPGPATH];
1130 : : int fd;
1131 : : int nbytes;
1132 : : char *recptr;
1133 : :
2663 tgl@sss.pgh.pa.us 1134 : 72 : memset(buffer.data, 0, XLOG_BLCKSZ);
1135 : :
1136 : : /* Set up the XLOG page header */
1137 : 72 : page = (XLogPageHeader) buffer.data;
8522 bruce@momjian.us 1138 : 72 : page->xlp_magic = XLOG_PAGE_MAGIC;
7818 tgl@sss.pgh.pa.us 1139 : 72 : page->xlp_info = XLP_LONG_HEADER;
1140 : 72 : page->xlp_tli = ControlFile.checkPointCopy.ThisTimeLineID;
4923 heikki.linnakangas@i 1141 : 72 : page->xlp_pageaddr = ControlFile.checkPointCopy.redo - SizeOfXLogLongPHD;
7818 tgl@sss.pgh.pa.us 1142 : 72 : longpage = (XLogLongPageHeader) page;
1143 : 72 : longpage->xlp_sysid = ControlFile.system_identifier;
3010 andres@anarazel.de 1144 : 72 : longpage->xlp_seg_size = WalSegSz;
7195 tgl@sss.pgh.pa.us 1145 : 72 : longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
1146 : :
1147 : : /* Insert the initial checkpoint record */
4044 heikki.linnakangas@i 1148 : 72 : recptr = (char *) page + SizeOfXLogLongPHD;
1149 : 72 : record = (XLogRecord *) recptr;
4923 1150 : 72 : record->xl_prev = 0;
7979 tgl@sss.pgh.pa.us 1151 : 72 : record->xl_xid = InvalidTransactionId;
4044 heikki.linnakangas@i 1152 : 72 : record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
8522 bruce@momjian.us 1153 : 72 : record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
1154 : 72 : record->xl_rmid = RM_XLOG_ID;
1155 : :
4044 heikki.linnakangas@i 1156 : 72 : recptr += SizeOfXLogRecord;
3185 tgl@sss.pgh.pa.us 1157 : 72 : *(recptr++) = (char) XLR_BLOCK_ID_DATA_SHORT;
4044 heikki.linnakangas@i 1158 : 72 : *(recptr++) = sizeof(CheckPoint);
1159 : 72 : memcpy(recptr, &ControlFile.checkPointCopy,
1160 : : sizeof(CheckPoint));
1161 : :
4060 1162 : 72 : INIT_CRC32C(crc);
4044 1163 : 72 : COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
4060 1164 : 72 : COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
1165 : 72 : FIN_CRC32C(crc);
8522 bruce@momjian.us 1166 : 72 : record->xl_crc = crc;
1167 : :
1168 : : /* Write the first page */
3010 andres@anarazel.de 1169 : 72 : XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID,
1170 : : newXlogSegNo, WalSegSz);
1171 : :
8522 bruce@momjian.us 1172 : 72 : unlink(path);
1173 : :
1174 : 72 : fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
1175 : : pg_file_create_mode);
1176 [ - + ]: 72 : if (fd < 0)
1348 tgl@sss.pgh.pa.us 1177 :UBC 0 : pg_fatal("could not open file \"%s\": %m", path);
1178 : :
8522 bruce@momjian.us 1179 :CBC 72 : errno = 0;
2663 tgl@sss.pgh.pa.us 1180 [ - + ]: 72 : if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1181 : : {
1182 : : /* if write didn't set errno, assume problem is no disk space */
8522 bruce@momjian.us 1183 [ # # ]:UBC 0 : if (errno == 0)
1184 : 0 : errno = ENOSPC;
1348 tgl@sss.pgh.pa.us 1185 : 0 : pg_fatal("could not write file \"%s\": %m", path);
1186 : : }
1187 : :
1188 : : /* Fill the rest of the file with zeroes */
2663 tgl@sss.pgh.pa.us 1189 :CBC 72 : memset(buffer.data, 0, XLOG_BLCKSZ);
3010 andres@anarazel.de 1190 [ + + ]: 132096 : for (nbytes = XLOG_BLCKSZ; nbytes < WalSegSz; nbytes += XLOG_BLCKSZ)
1191 : : {
8522 bruce@momjian.us 1192 : 132024 : errno = 0;
2663 tgl@sss.pgh.pa.us 1193 [ - + ]: 132024 : if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1194 : : {
8522 bruce@momjian.us 1195 [ # # ]:UBC 0 : if (errno == 0)
1196 : 0 : errno = ENOSPC;
1348 tgl@sss.pgh.pa.us 1197 : 0 : pg_fatal("could not write file \"%s\": %m", path);
1198 : : }
1199 : : }
1200 : :
8522 bruce@momjian.us 1201 [ - + ]:CBC 72 : if (fsync(fd) != 0)
1348 tgl@sss.pgh.pa.us 1202 :UBC 0 : pg_fatal("fsync error: %m");
1203 : :
8522 bruce@momjian.us 1204 :CBC 72 : close(fd);
1205 : 72 : }
1206 : :
1207 : :
1208 : : static void
1209 : 1 : usage(void)
1210 : : {
3140 peter_e@gmx.net 1211 : 1 : printf(_("%s resets the PostgreSQL write-ahead log.\n\n"), progname);
810 peter@eisentraut.org 1212 : 1 : printf(_("Usage:\n"));
1213 : 1 : printf(_(" %s [OPTION]... DATADIR\n"), progname);
1214 : :
1215 : 1 : printf(_("\nOptions:\n"));
1216 : 1 : printf(_(" [-D, --pgdata=]DATADIR data directory\n"));
1217 : 1 : printf(_(" -f, --force force update to be done even after unclean shutdown or\n"
1218 : : " if pg_control values had to be guessed\n"));
1219 : 1 : printf(_(" -n, --dry-run no update, just show what would be done\n"));
1220 : 1 : printf(_(" -V, --version output version information, then exit\n"));
1221 : 1 : printf(_(" -?, --help show this help, then exit\n"));
1222 : :
1223 : 1 : printf(_("\nOptions to override control file values:\n"));
2824 peter_e@gmx.net 1224 : 1 : printf(_(" -c, --commit-timestamp-ids=XID,XID\n"
1225 : : " set oldest and newest transactions bearing\n"
1226 : : " commit timestamp (zero means no change)\n"));
1604 bruce@momjian.us 1227 : 1 : printf(_(" -e, --epoch=XIDEPOCH set next transaction ID epoch\n"));
1228 : 1 : printf(_(" -l, --next-wal-file=WALFILE set minimum starting location for new WAL\n"));
1229 : 1 : printf(_(" -m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID\n"));
1230 : 1 : printf(_(" -o, --next-oid=OID set next OID\n"));
1231 : 1 : printf(_(" -O, --multixact-offset=OFFSET set next multitransaction offset\n"));
1232 : 1 : printf(_(" -u, --oldest-transaction-id=XID set oldest transaction ID\n"));
1233 : 1 : printf(_(" -x, --next-transaction-id=XID set next transaction ID\n"));
231 peter@eisentraut.org 1234 : 1 : printf(_(" --char-signedness=OPTION set char signedness to \"signed\" or \"unsigned\"\n"));
1604 bruce@momjian.us 1235 : 1 : printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n"));
1236 : :
2118 peter@eisentraut.org 1237 : 1 : printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1238 : 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
8522 bruce@momjian.us 1239 : 1 : }
1240 : :
1241 : : /*
1242 : : * strtouint32_strict -- like strtoul(), but returns uint32 and doesn't accept
1243 : : * negative values
1244 : : */
1245 : : static uint32
8 heikki.linnakangas@i 1246 :GNC 102 : strtouint32_strict(const char *restrict s, char **restrict endptr, int base)
1247 : : {
1248 : : unsigned long val;
1249 : : bool is_neg;
1250 : :
1251 : : /* skip leading whitespace */
tgl@sss.pgh.pa.us 1252 [ - + ]: 102 : while (isspace((unsigned char) *s))
8 heikki.linnakangas@i 1253 :UNC 0 : s++;
1254 : :
1255 : : /*
1256 : : * Is it negative? We still call strtoul() if it was, to set 'endptr'.
1257 : : * (The current callers don't care though.)
1258 : : */
8 heikki.linnakangas@i 1259 :GNC 102 : is_neg = (*s == '-');
1260 : :
1261 : 102 : val = strtoul(s, endptr, base);
1262 : :
1263 : : /* reject if it was negative */
1264 [ + - + + ]: 102 : if (errno == 0 && is_neg)
1265 : : {
1266 : 3 : errno = ERANGE;
1267 : 3 : val = 0;
1268 : : }
1269 : :
1270 : : /*
1271 : : * reject values larger than UINT32_MAX on platforms where long is 64 bits
1272 : : * wide.
1273 : : */
1274 [ + + + + ]: 102 : if (errno == 0 && val != (uint32) val)
1275 : : {
1276 : 1 : errno = ERANGE;
1277 : 1 : val = UINT32_MAX;
1278 : : }
1279 : :
1280 : 102 : return (uint32) val;
1281 : : }
1282 : :
1283 : : /*
1284 : : * strtouint64_strict -- like strtou64(), but doesn't accept negative values
1285 : : */
1286 : : static uint64
7 1287 : 13 : strtouint64_strict(const char *restrict s, char **restrict endptr, int base)
1288 : : {
1289 : : uint64 val;
1290 : : bool is_neg;
1291 : :
1292 : : /* skip leading whitespace */
1293 [ - + ]: 13 : while (isspace((unsigned char) *s))
7 heikki.linnakangas@i 1294 :UNC 0 : s++;
1295 : :
1296 : : /*
1297 : : * Is it negative? We still call strtou64() if it was, to set 'endptr'.
1298 : : * (The current callers don't care though.)
1299 : : */
7 heikki.linnakangas@i 1300 :GNC 13 : is_neg = (*s == '-');
1301 : :
1302 : 13 : val = strtou64(s, endptr, base);
1303 : :
1304 : : /* reject if it was negative */
1305 [ + - + + ]: 13 : if (errno == 0 && is_neg)
1306 : : {
1307 : 1 : errno = ERANGE;
1308 : 1 : val = 0;
1309 : : }
1310 : :
1311 : 13 : return val;
1312 : : }
|