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-2026, 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
8599 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;
4189 heikki.linnakangas@i 146 : 193 : char *DataDir = NULL;
3099 andres@anarazel.de 147 : 193 : char *log_fname = NULL;
148 : : int fd;
149 : :
2540 peter@eisentraut.org 150 : 193 : pg_logging_init(argv[0]);
3321 rhaas@postgresql.org 151 : 193 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_resetwal"));
8381 bruce@momjian.us 152 : 193 : progname = get_progname(argv[0]);
153 : :
8599 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 : : {
3321 rhaas@postgresql.org 163 : 47 : puts("pg_resetwal (PostgreSQL) " PG_VERSION);
8599 peter_e@gmx.net 164 : 47 : exit(0);
165 : : }
166 : : }
167 : :
168 : :
1693 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 : : {
8599 peter_e@gmx.net 171 [ + + + + : 204 : switch (c)
+ + + + +
+ + + +
+ ]
172 : : {
4189 heikki.linnakangas@i 173 : 4 : case 'D':
174 : 4 : DataDir = optarg;
175 : 4 : break;
176 : :
8599 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 : :
7146 tgl@sss.pgh.pa.us 185 : 14 : case 'e':
1668 peter@eisentraut.org 186 : 14 : errno = 0;
97 heikki.linnakangas@i 187 :GNC 14 : next_xid_epoch_val = strtouint32_strict(optarg, &endptr, 0);
1668 peter@eisentraut.org 188 [ + + + - :CBC 14 : if (endptr == optarg || *endptr != '\0' || errno != 0)
+ + ]
189 : : {
190 : : /*------
191 : : translator: %s is a command line argument (-e, etc) */
2540 192 : 2 : pg_log_error("invalid argument for option %s", "-e");
1437 tgl@sss.pgh.pa.us 193 : 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7146 194 : 2 : exit(1);
195 : : }
97 heikki.linnakangas@i 196 :GNC 12 : next_xid_epoch_given = true;
7146 tgl@sss.pgh.pa.us 197 :CBC 12 : break;
198 : :
1693 bruce@momjian.us 199 : 13 : case 'u':
1668 peter@eisentraut.org 200 : 13 : errno = 0;
97 heikki.linnakangas@i 201 :GNC 13 : oldest_xid_val = strtouint32_strict(optarg, &endptr, 0);
1668 peter@eisentraut.org 202 [ + + + - :CBC 13 : if (endptr == optarg || *endptr != '\0' || errno != 0)
- + ]
203 : : {
1693 bruce@momjian.us 204 : 1 : pg_log_error("invalid argument for option %s", "-u");
1437 tgl@sss.pgh.pa.us 205 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
1693 bruce@momjian.us 206 : 1 : exit(1);
207 : : }
97 heikki.linnakangas@i 208 [ + + ]:GNC 12 : if (!TransactionIdIsNormal(oldest_xid_val))
1437 tgl@sss.pgh.pa.us 209 :CBC 1 : pg_fatal("oldest transaction ID (-u) must be greater than or equal to %u", FirstNormalTransactionId);
97 heikki.linnakangas@i 210 :GNC 11 : oldest_xid_given = true;
1693 bruce@momjian.us 211 :CBC 11 : break;
212 : :
8599 peter_e@gmx.net 213 : 16 : case 'x':
1668 peter@eisentraut.org 214 : 16 : errno = 0;
97 heikki.linnakangas@i 215 :GNC 16 : next_xid_val = strtouint32_strict(optarg, &endptr, 0);
1668 peter@eisentraut.org 216 [ + + + - :CBC 16 : if (endptr == optarg || *endptr != '\0' || errno != 0)
+ + ]
217 : : {
2540 218 : 4 : pg_log_error("invalid argument for option %s", "-x");
1437 tgl@sss.pgh.pa.us 219 : 4 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8565 220 : 4 : exit(1);
221 : : }
97 heikki.linnakangas@i 222 [ + + ]:GNC 12 : if (!TransactionIdIsNormal(next_xid_val))
1437 tgl@sss.pgh.pa.us 223 :CBC 1 : pg_fatal("transaction ID (-x) must be greater than or equal to %u", FirstNormalTransactionId);
97 heikki.linnakangas@i 224 :GNC 11 : next_xid_given = true;
8599 peter_e@gmx.net 225 :CBC 11 : break;
226 : :
4120 alvherre@alvh.no-ip. 227 : 15 : case 'c':
1668 peter@eisentraut.org 228 : 15 : errno = 0;
97 heikki.linnakangas@i 229 :GNC 15 : oldest_commit_ts_xid_val = strtouint32_strict(optarg, &endptr, 0);
1668 peter@eisentraut.org 230 [ + + + - :CBC 15 : if (endptr == optarg || *endptr != ',' || errno != 0)
- + ]
231 : : {
2540 232 : 1 : pg_log_error("invalid argument for option %s", "-c");
1437 tgl@sss.pgh.pa.us 233 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4120 alvherre@alvh.no-ip. 234 : 1 : exit(1);
235 : : }
97 heikki.linnakangas@i 236 :GNC 14 : newest_commit_ts_xid_val = strtoul(endptr + 1, &endptr2, 0);
1668 peter@eisentraut.org 237 [ + + + - :CBC 14 : if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
- + ]
238 : : {
2540 239 : 1 : pg_log_error("invalid argument for option %s", "-c");
1437 tgl@sss.pgh.pa.us 240 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4120 alvherre@alvh.no-ip. 241 : 1 : exit(1);
242 : : }
243 : :
97 heikki.linnakangas@i 244 [ + + ]:GNC 13 : if (oldest_commit_ts_xid_val < FirstNormalTransactionId &&
245 [ + - ]: 1 : oldest_commit_ts_xid_val != InvalidTransactionId)
887 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 : :
97 heikki.linnakangas@i 248 [ + + ]:GNC 12 : if (newest_commit_ts_xid_val < FirstNormalTransactionId &&
249 [ + + ]: 3 : newest_commit_ts_xid_val != InvalidTransactionId)
887 peter@eisentraut.org 250 :CBC 1 : pg_fatal("transaction ID (-c) must be either %u or greater than or equal to %u", InvalidTransactionId, FirstNormalTransactionId);
97 heikki.linnakangas@i 251 :GNC 11 : commit_ts_xids_given = true;
4120 alvherre@alvh.no-ip. 252 :CBC 11 : break;
253 : :
8565 tgl@sss.pgh.pa.us 254 : 13 : case 'o':
1668 peter@eisentraut.org 255 : 13 : errno = 0;
97 heikki.linnakangas@i 256 :GNC 13 : next_oid_val = strtouint32_strict(optarg, &endptr, 0);
1668 peter@eisentraut.org 257 [ + + + - :CBC 13 : if (endptr == optarg || *endptr != '\0' || errno != 0)
- + ]
258 : : {
2540 259 : 1 : pg_log_error("invalid argument for option %s", "-o");
1437 tgl@sss.pgh.pa.us 260 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8565 261 : 1 : exit(1);
262 : : }
97 heikki.linnakangas@i 263 [ + + ]:GNC 12 : if (next_oid_val == 0)
1437 tgl@sss.pgh.pa.us 264 :CBC 1 : pg_fatal("OID (-o) must not be 0");
97 heikki.linnakangas@i 265 :GNC 11 : next_oid_given = true;
8565 tgl@sss.pgh.pa.us 266 :CBC 11 : break;
267 : :
7626 268 : 16 : case 'm':
1668 peter@eisentraut.org 269 : 16 : errno = 0;
97 heikki.linnakangas@i 270 :GNC 16 : next_mxid_val = strtouint32_strict(optarg, &endptr, 0);
1668 peter@eisentraut.org 271 [ + + + - :CBC 16 : if (endptr == optarg || *endptr != ',' || errno != 0)
- + ]
272 : : {
2540 273 : 1 : pg_log_error("invalid argument for option %s", "-m");
1437 tgl@sss.pgh.pa.us 274 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4799 alvherre@alvh.no-ip. 275 : 1 : exit(1);
276 : : }
277 : :
97 heikki.linnakangas@i 278 :GNC 15 : oldest_mxid_val = strtouint32_strict(endptr + 1, &endptr2, 0);
1668 peter@eisentraut.org 279 [ + + + - :CBC 15 : if (endptr2 == endptr + 1 || *endptr2 != '\0' || errno != 0)
- + ]
280 : : {
2540 281 : 1 : pg_log_error("invalid argument for option %s", "-m");
1437 tgl@sss.pgh.pa.us 282 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7626 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 : : */
93 heikki.linnakangas@i 290 [ + + ]:GNC 14 : if (next_mxid_val == 0)
291 : 1 : pg_fatal("next multitransaction ID (-m) must not be 0");
97 292 [ + + ]: 13 : if (oldest_mxid_val == 0)
1437 tgl@sss.pgh.pa.us 293 :CBC 1 : pg_fatal("oldest multitransaction ID (-m) must not be 0");
97 heikki.linnakangas@i 294 :GNC 12 : mxids_given = true;
7626 tgl@sss.pgh.pa.us 295 :CBC 12 : break;
296 : :
7585 297 : 13 : case 'O':
1668 peter@eisentraut.org 298 : 13 : errno = 0;
96 heikki.linnakangas@i 299 :GNC 13 : next_mxoff_val = strtouint64_strict(optarg, &endptr, 0);
1668 peter@eisentraut.org 300 [ + + + - :CBC 13 : if (endptr == optarg || *endptr != '\0' || errno != 0)
+ + ]
301 : : {
2540 302 : 2 : pg_log_error("invalid argument for option %s", "-O");
1437 tgl@sss.pgh.pa.us 303 : 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7585 304 : 2 : exit(1);
305 : : }
97 heikki.linnakangas@i 306 :GNC 11 : next_mxoff_given = true;
7585 tgl@sss.pgh.pa.us 307 :CBC 11 : break;
308 : :
8599 peter_e@gmx.net 309 : 12 : case 'l':
3909 fujii@postgresql.org 310 [ + + ]: 12 : if (strspn(optarg, "01234567890ABCDEFabcdef") != XLOG_FNAME_LEN)
311 : : {
2540 peter@eisentraut.org 312 : 1 : pg_log_error("invalid argument for option %s", "-l");
1437 tgl@sss.pgh.pa.us 313 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8599 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 : : */
3099 andres@anarazel.de 321 : 11 : log_fname = pg_strdup(optarg);
8599 peter_e@gmx.net 322 : 11 : break;
323 : :
2912 324 : 4 : case 1:
325 : : {
326 : : int wal_segsize_mb;
327 : :
930 peter@eisentraut.org 328 [ + + ]: 4 : if (!option_parse_int(optarg, "--wal-segsize", 1, 1024, &wal_segsize_mb))
329 : 1 : exit(1);
97 heikki.linnakangas@i 330 :GNC 3 : wal_segsize_val = wal_segsize_mb * 1024 * 1024;
331 [ + - + + : 3 : if (!IsValidWalSegSize(wal_segsize_val))
+ - - + ]
929 dgustafsson@postgres 332 :CBC 1 : pg_fatal("argument of %s must be a power of two between 1 and 1024", "--wal-segsize");
97 heikki.linnakangas@i 333 :GNC 2 : wal_segsize_given = true;
930 peter@eisentraut.org 334 :CBC 2 : break;
335 : : }
336 : :
387 msawada@postgresql.o 337 : 3 : case 2:
338 : : {
339 : 3 : errno = 0;
340 : :
341 [ - + ]: 3 : if (pg_strcasecmp(optarg, "signed") == 0)
97 heikki.linnakangas@i 342 :UNC 0 : char_signedness_val = true;
387 msawada@postgresql.o 343 [ + + ]:CBC 3 : else if (pg_strcasecmp(optarg, "unsigned") == 0)
97 heikki.linnakangas@i 344 :GNC 2 : char_signedness_val = false;
345 : : else
346 : : {
387 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 : : }
97 heikki.linnakangas@i 351 :GNC 2 : char_signedness_given = true;
387 msawada@postgresql.o 352 :CBC 2 : break;
353 : : }
354 : :
8599 peter_e@gmx.net 355 : 1 : default:
356 : : /* getopt_long already emitted a complaint */
1437 tgl@sss.pgh.pa.us 357 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8599 peter_e@gmx.net 358 : 1 : exit(1);
359 : : }
360 : : }
361 : :
4160 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 : : {
2540 peter@eisentraut.org 368 : 1 : pg_log_error("too many command-line arguments (first is \"%s\")",
369 : : argv[optind]);
1437 tgl@sss.pgh.pa.us 370 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
4160 heikki.linnakangas@i 371 : 1 : exit(1);
372 : : }
373 : :
374 [ + + ]: 118 : if (DataDir == NULL)
375 : : {
2540 peter@eisentraut.org 376 : 1 : pg_log_error("no data directory specified");
1437 tgl@sss.pgh.pa.us 377 : 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8599 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
7761 neilc@samurai.com 388 [ - + ]: 117 : if (geteuid() == 0)
389 : : {
2540 peter@eisentraut.org 390 :UBC 0 : pg_log_error("cannot be executed by \"root\"");
1437 tgl@sss.pgh.pa.us 391 : 0 : pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
392 : : progname);
7761 neilc@samurai.com 393 : 0 : exit(1);
394 : : }
395 : : #endif
396 : :
2540 peter@eisentraut.org 397 :CBC 117 : get_restricted_token();
398 : :
399 : : /* Set mask based on PGDATA permissions */
2899 sfrost@snowman.net 400 [ + + ]: 117 : if (!GetDataDirectoryCreatePerm(DataDir))
1437 tgl@sss.pgh.pa.us 401 : 1 : pg_fatal("could not read permissions of directory \"%s\": %m",
402 : : DataDir);
403 : :
2899 sfrost@snowman.net 404 : 116 : umask(pg_mode_mask);
405 : :
898 peter@eisentraut.org 406 [ - + ]: 116 : if (chdir(DataDir) < 0)
898 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 */
3212 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 : : */
4861 417 [ + + ]: 116 : if ((fd = open("postmaster.pid", O_RDONLY, 0)) < 0)
418 : : {
8599 peter_e@gmx.net 419 [ - + ]: 115 : if (errno != ENOENT)
1437 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 : : {
2540 peter@eisentraut.org 425 :CBC 1 : pg_log_error("lock file \"%s\" exists", "postmaster.pid");
1437 tgl@sss.pgh.pa.us 426 : 1 : pg_log_error_hint("Is a server running? If not, delete the lock file and try again.");
7225 bruce@momjian.us 427 : 1 : exit(1);
428 : : }
429 : :
430 : : /*
431 : : * Attempt to read the existing pg_control file
432 : : */
2218 peter@eisentraut.org 433 [ + + ]: 115 : if (!read_controlfile())
7225 bruce@momjian.us 434 : 4 : GuessControlValues();
435 : :
436 : : /*
437 : : * If no new WAL segment size was specified, use the control file value.
438 : : */
97 heikki.linnakangas@i 439 [ + + ]:GNC 115 : if (wal_segsize_given)
440 : 2 : WalSegSz = wal_segsize_val;
441 : : else
2912 peter_e@gmx.net 442 :CBC 113 : WalSegSz = ControlFile.xlog_seg_size;
443 : :
3099 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 : : */
7037 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 : : */
4476 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 : : */
97 heikki.linnakangas@i 463 [ + + ]:GNC 115 : if (next_xid_epoch_given)
464 : : ControlFile.checkPointCopy.nextXid =
465 : 12 : FullTransactionIdFromEpochAndXid(next_xid_epoch_val,
2042 andres@anarazel.de 466 :CBC 12 : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
467 : :
97 heikki.linnakangas@i 468 [ + + ]:GNC 115 : if (oldest_xid_given)
469 : : {
470 : 11 : ControlFile.checkPointCopy.oldestXid = oldest_xid_val;
1693 bruce@momjian.us 471 :CBC 11 : ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
472 : : }
473 : :
97 heikki.linnakangas@i 474 [ + + ]:GNC 115 : if (next_xid_given)
475 : : ControlFile.checkPointCopy.nextXid =
2042 andres@anarazel.de 476 :CBC 11 : FullTransactionIdFromEpochAndXid(EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid),
477 : : next_xid_val);
478 : :
97 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;
4799 alvherre@alvh.no-ip. 493 [ - + ]:CBC 12 : if (ControlFile.checkPointCopy.oldestMulti < FirstMultiXactId)
4799 alvherre@alvh.no-ip. 494 :UBC 0 : ControlFile.checkPointCopy.oldestMulti += FirstMultiXactId;
4799 alvherre@alvh.no-ip. 495 :CBC 12 : ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
496 : : }
497 : :
97 heikki.linnakangas@i 498 [ + + ]:GNC 115 : if (next_mxoff_given)
499 : 11 : ControlFile.checkPointCopy.nextMultiOffset = next_mxoff_val;
500 : :
7755 tgl@sss.pgh.pa.us 501 [ - + ]:CBC 115 : if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
502 : : {
7755 tgl@sss.pgh.pa.us 503 :UBC 0 : ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli;
4780 heikki.linnakangas@i 504 : 0 : ControlFile.checkPointCopy.PrevTimeLineID = minXlogTli;
505 : : }
506 : :
97 heikki.linnakangas@i 507 [ + + ]:GNC 115 : if (wal_segsize_given)
2912 peter_e@gmx.net 508 :CBC 2 : ControlFile.xlog_seg_size = WalSegSz;
509 : :
97 heikki.linnakangas@i 510 [ + + ]:GNC 115 : if (char_signedness_given)
511 : 2 : ControlFile.default_char_signedness = char_signedness_val;
512 : :
5012 heikki.linnakangas@i 513 [ + + ]:CBC 115 : if (minXlogSegNo > newXlogSegNo)
514 : 3 : newXlogSegNo = minXlogSegNo;
515 : :
899 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 : : {
4476 heikki.linnakangas@i 528 : 1 : PrintNewControlValues();
899 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 : : */
7225 bruce@momjian.us 537 [ + + + + ]: 73 : if (ControlFile.state != DB_SHUTDOWNED && !force)
538 : : {
899 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.");
8599 peter_e@gmx.net 542 : 1 : exit(1);
543 : : }
544 : :
545 : : /*
546 : : * Else, do the dirty deed.
547 : : */
548 : 72 : RewriteControlFile();
549 : 72 : KillExistingXLOG();
6160 tgl@sss.pgh.pa.us 550 : 72 : KillExistingArchiveStatus();
816 rhaas@postgresql.org 551 : 72 : KillExistingWALSummaries();
8599 peter_e@gmx.net 552 : 72 : WriteEmptyXLOG();
553 : :
3229 554 : 72 : printf(_("Write-ahead log reset\n"));
8599 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
3212 tgl@sss.pgh.pa.us 572 : 116 : CheckDataVersion(void)
573 : : {
574 : : char *version_str;
151 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 : : {
2540 peter@eisentraut.org 579 :UBC 0 : pg_log_error("data directory is of wrong version");
1437 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);
3212 584 : 0 : exit(1);
585 : : }
3212 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
2218 peter@eisentraut.org 596 : 115 : read_controlfile(void)
597 : : {
598 : : int fd;
599 : : int len;
600 : : char *buffer;
601 : : pg_crc32c crc;
602 : :
6381 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 : : */
2540 peter@eisentraut.org 610 :UBC 0 : pg_log_error("could not open file \"%s\" for reading: %m",
611 : : XLOG_CONTROL_FILE);
8611 bruce@momjian.us 612 [ # # ]: 0 : if (errno == ENOENT)
1437 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);
8611 bruce@momjian.us 617 : 0 : exit(1);
618 : : }
619 : :
620 : : /* Use malloc to ensure we have a maxaligned buffer */
3161 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);
8611 bruce@momjian.us 624 [ - + ]: 115 : if (len < 0)
1437 tgl@sss.pgh.pa.us 625 :UBC 0 : pg_fatal("could not read file \"%s\": %m", XLOG_CONTROL_FILE);
8611 bruce@momjian.us 626 :CBC 115 : close(fd);
627 : :
628 [ + - ]: 115 : if (len >= sizeof(ControlFileData) &&
3189 tgl@sss.pgh.pa.us 629 [ + + ]: 115 : ((ControlFileData *) buffer)->pg_control_version == PG_CONTROL_VERSION)
630 : : {
631 : : /* Check the CRC. */
4149 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 : :
3099 andres@anarazel.de 638 [ + + ]: 114 : if (!EQ_CRC32C(crc, ((ControlFileData *) buffer)->crc))
639 : : {
640 : : /* We will use the data but treat it as guessed. */
2540 peter@eisentraut.org 641 : 3 : pg_log_warning("pg_control exists but has invalid CRC; proceed with caution");
3099 andres@anarazel.de 642 : 3 : guessed = true;
643 : : }
644 : :
8611 bruce@momjian.us 645 : 114 : memcpy(&ControlFile, buffer, sizeof(ControlFile));
646 : :
647 : : /* return false if WAL segment size is not valid */
2912 peter_e@gmx.net 648 [ + + + - : 114 : if (!IsValidWalSegSize(ControlFile.xlog_seg_size))
+ - - + ]
649 : : {
2540 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);
2914 peter_e@gmx.net 654 : 3 : return false;
655 : : }
656 : :
8611 bruce@momjian.us 657 : 111 : return true;
658 : : }
659 : :
660 : : /* Looks like it's a mess. */
2540 peter@eisentraut.org 661 : 1 : pg_log_warning("pg_control exists but is broken or wrong version; ignoring it");
8611 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
7225 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;
8611 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 : : */
7225 688 : 4 : gettimeofday(&tv, NULL);
689 : 4 : sysidentifier = ((uint64) tv.tv_sec) << 32;
4310 tgl@sss.pgh.pa.us 690 : 4 : sysidentifier |= ((uint64) tv.tv_usec) << 12;
691 : 4 : sysidentifier |= getpid() & 0xFFF;
692 : :
7225 bruce@momjian.us 693 : 4 : ControlFile.system_identifier = sysidentifier;
694 : :
5012 heikki.linnakangas@i 695 : 4 : ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
7225 bruce@momjian.us 696 : 4 : ControlFile.checkPointCopy.ThisTimeLineID = 1;
4780 heikki.linnakangas@i 697 : 4 : ControlFile.checkPointCopy.PrevTimeLineID = 1;
5163 simon@2ndQuadrant.co 698 : 4 : ControlFile.checkPointCopy.fullPageWrites = false;
699 : : ControlFile.checkPointCopy.nextXid =
2544 tmunro@postgresql.or 700 : 4 : FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId);
1704 tgl@sss.pgh.pa.us 701 : 4 : ControlFile.checkPointCopy.nextOid = FirstGenbkiObjectId;
7225 bruce@momjian.us 702 : 4 : ControlFile.checkPointCopy.nextMulti = FirstMultiXactId;
703 : 4 : ControlFile.checkPointCopy.nextMultiOffset = 0;
6040 tgl@sss.pgh.pa.us 704 : 4 : ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId;
705 : 4 : ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
4799 alvherre@alvh.no-ip. 706 : 4 : ControlFile.checkPointCopy.oldestMulti = FirstMultiXactId;
707 : 4 : ControlFile.checkPointCopy.oldestMultiDB = InvalidOid;
6601 tgl@sss.pgh.pa.us 708 : 4 : ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
5800 709 : 4 : ControlFile.checkPointCopy.oldestActiveXid = InvalidTransactionId;
710 : :
7225 bruce@momjian.us 711 : 4 : ControlFile.state = DB_SHUTDOWNED;
6601 tgl@sss.pgh.pa.us 712 : 4 : ControlFile.time = (pg_time_t) time(NULL);
7225 bruce@momjian.us 713 : 4 : ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
2331 michael@paquier.xyz 714 : 4 : ControlFile.unloggedLSN = FirstNormalUnloggedLSN;
715 : :
716 : : /* minRecoveryPoint, backupStartPoint and backupEndPoint can be left zero */
717 : :
5800 tgl@sss.pgh.pa.us 718 : 4 : ControlFile.wal_level = WAL_LEVEL_MINIMAL;
4467 fujii@postgresql.org 719 : 4 : ControlFile.wal_log_hints = false;
4120 alvherre@alvh.no-ip. 720 : 4 : ControlFile.track_commit_timestamp = false;
5800 tgl@sss.pgh.pa.us 721 : 4 : ControlFile.MaxConnections = 100;
2588 michael@paquier.xyz 722 : 4 : ControlFile.max_wal_senders = 10;
3387 rhaas@postgresql.org 723 : 4 : ControlFile.max_worker_processes = 8;
5800 tgl@sss.pgh.pa.us 724 : 4 : ControlFile.max_prepared_xacts = 0;
725 : 4 : ControlFile.max_locks_per_xact = 64;
726 : :
7468 727 : 4 : ControlFile.maxAlign = MAXIMUM_ALIGNOF;
728 : 4 : ControlFile.floatFormat = FLOATFORMAT_VALUE;
8611 bruce@momjian.us 729 : 4 : ControlFile.blcksz = BLCKSZ;
730 : 4 : ControlFile.relseg_size = RELSEG_SIZE;
124 heikki.linnakangas@i 731 :GNC 4 : ControlFile.slru_pages_per_segment = SLRU_PAGES_PER_SEGMENT;
2912 peter_e@gmx.net 732 :CBC 4 : ControlFile.xlog_blcksz = XLOG_BLCKSZ;
733 : 4 : ControlFile.xlog_seg_size = DEFAULT_XLOG_SEG_SIZE;
8565 tgl@sss.pgh.pa.us 734 : 4 : ControlFile.nameDataLen = NAMEDATALEN;
7656 735 : 4 : ControlFile.indexMaxKeys = INDEX_MAX_KEYS;
6921 736 : 4 : ControlFile.toast_max_chunk_size = TOAST_MAX_CHUNK_SIZE;
4301 737 : 4 : ControlFile.loblksize = LOBLKSIZE;
214 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 : : */
8611 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
7225 754 : 42 : PrintControlValues(bool guessed)
755 : : {
756 [ + + ]: 42 : if (guessed)
757 : 3 : printf(_("Guessed pg_control values:\n\n"));
758 : : else
4476 heikki.linnakangas@i 759 : 39 : printf(_("Current pg_control values:\n\n"));
760 : :
7146 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);
351 peter@eisentraut.org 765 : 42 : printf(_("Database system identifier: %" PRIu64 "\n"),
766 : : ControlFile.system_identifier);
7146 tgl@sss.pgh.pa.us 767 : 42 : printf(_("Latest checkpoint's TimeLineID: %u\n"),
768 : : ControlFile.checkPointCopy.ThisTimeLineID);
5029 peter_e@gmx.net 769 [ + + ]: 42 : printf(_("Latest checkpoint's full_page_writes: %s\n"),
770 : : ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
3684 mail@joeconway.com 771 : 42 : printf(_("Latest checkpoint's NextXID: %u:%u\n"),
772 : : EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid),
773 : : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
7146 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);
96 heikki.linnakangas@i 778 :GNC 42 : printf(_("Latest checkpoint's NextMultiOffset: %" PRIu64 "\n"),
779 : : ControlFile.checkPointCopy.nextMultiOffset);
6040 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);
5800 784 : 42 : printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
785 : : ControlFile.checkPointCopy.oldestActiveXid);
4799 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);
3730 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);
7146 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);
124 heikki.linnakangas@i 801 :GNC 42 : printf(_("Pages per SLRU segment: %u\n"),
802 : : ControlFile.slru_pages_per_segment);
7146 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);
6921 811 : 42 : printf(_("Maximum size of a TOAST chunk: %u\n"),
812 : : ControlFile.toast_max_chunk_size);
4301 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: */
8565 816 : 42 : printf(_("Date/time type storage: %s\n"),
817 : : _("64-bit integers"));
6537 818 [ + - ]: 42 : printf(_("Float8 argument passing: %s\n"),
819 : : (ControlFile.float8ByVal ? _("by value") : _("by reference")));
4702 simon@2ndQuadrant.co 820 : 42 : printf(_("Data page checksum version: %u\n"),
821 : : ControlFile.data_checksum_version);
387 msawada@postgresql.o 822 [ + + ]: 42 : printf(_("Default char data signedness: %s\n"),
823 : : (ControlFile.default_char_signedness ? _("signed") : _("unsigned")));
8611 bruce@momjian.us 824 : 42 : }
825 : :
826 : :
827 : : /*
828 : : * Print the values to be changed.
829 : : */
830 : : static void
3865 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. */
4476 heikki.linnakangas@i 836 : 42 : printf(_("\n\nValues to be changed:\n\n"));
837 : :
3099 andres@anarazel.de 838 : 42 : XLogFileName(fname, ControlFile.checkPointCopy.ThisTimeLineID,
839 : : newXlogSegNo, WalSegSz);
1277 tgl@sss.pgh.pa.us 840 : 42 : printf(_("First log segment after reset: %s\n"), fname);
841 : :
97 heikki.linnakangas@i 842 [ + + ]:GNC 42 : if (mxids_given)
843 : : {
4476 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 : :
97 heikki.linnakangas@i 852 [ + + ]:GNC 42 : if (next_mxoff_given)
853 : : {
96 854 : 1 : printf(_("NextMultiOffset: %" PRIu64 "\n"),
855 : : ControlFile.checkPointCopy.nextMultiOffset);
856 : : }
857 : :
97 858 [ + + ]: 42 : if (next_oid_given)
859 : : {
4476 heikki.linnakangas@i 860 :CBC 1 : printf(_("NextOID: %u\n"),
861 : : ControlFile.checkPointCopy.nextOid);
862 : : }
863 : :
97 heikki.linnakangas@i 864 [ + + ]:GNC 42 : if (next_xid_given)
865 : : {
4476 heikki.linnakangas@i 866 :CBC 1 : printf(_("NextXID: %u\n"),
867 : : XidFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
868 : : }
869 : :
97 heikki.linnakangas@i 870 [ + + ]:GNC 42 : if (oldest_xid_given)
871 : : {
4476 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 : :
97 heikki.linnakangas@i 878 [ + + ]:GNC 42 : if (next_xid_epoch_given)
879 : : {
4236 peter_e@gmx.net 880 :CBC 1 : printf(_("NextXID epoch: %u\n"),
881 : : EpochFromFullTransactionId(ControlFile.checkPointCopy.nextXid));
882 : : }
883 : :
97 heikki.linnakangas@i 884 [ + + ]:GNC 42 : if (commit_ts_xids_given)
885 : : {
3730 mail@joeconway.com 886 :CBC 1 : printf(_("oldestCommitTsXid: %u\n"),
887 : : ControlFile.checkPointCopy.oldestCommitTsXid);
3730 mail@joeconway.com 888 :GBC 1 : printf(_("newestCommitTsXid: %u\n"),
889 : : ControlFile.checkPointCopy.newestCommitTsXid);
890 : : }
891 : :
97 heikki.linnakangas@i 892 [ + + ]:GNC 42 : if (wal_segsize_given)
893 : : {
2912 peter_e@gmx.net 894 :CBC 1 : printf(_("Bytes per WAL segment: %u\n"),
895 : : ControlFile.xlog_seg_size);
896 : : }
4476 heikki.linnakangas@i 897 : 42 : }
898 : :
899 : :
900 : : /*
901 : : * Write out the new pg_control file.
902 : : */
903 : : static void
7225 bruce@momjian.us 904 : 72 : RewriteControlFile(void)
905 : : {
906 : : /*
907 : : * Adjust fields as needed to force an empty XLOG starting at
908 : : * newXlogSegNo.
909 : : */
2806 alvherre@alvh.no-ip. 910 : 72 : XLogSegNoOffsetToRecPtr(newXlogSegNo, SizeOfXLogLongPHD, WalSegSz,
911 : : ControlFile.checkPointCopy.redo);
6601 tgl@sss.pgh.pa.us 912 : 72 : ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
913 : :
8611 bruce@momjian.us 914 : 72 : ControlFile.state = DB_SHUTDOWNED;
915 : 72 : ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
45 alvherre@kurilemu.de 916 :GNC 72 : ControlFile.minRecoveryPoint = InvalidXLogRecPtr;
4849 heikki.linnakangas@i 917 :CBC 72 : ControlFile.minRecoveryPointTLI = 0;
45 alvherre@kurilemu.de 918 :GNC 72 : ControlFile.backupStartPoint = InvalidXLogRecPtr;
919 : 72 : ControlFile.backupEndPoint = InvalidXLogRecPtr;
5324 heikki.linnakangas@i 920 :CBC 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 : : */
5800 tgl@sss.pgh.pa.us 927 : 72 : ControlFile.wal_level = WAL_LEVEL_MINIMAL;
4467 fujii@postgresql.org 928 : 72 : ControlFile.wal_log_hints = false;
4120 alvherre@alvh.no-ip. 929 : 72 : ControlFile.track_commit_timestamp = false;
5800 heikki.linnakangas@i 930 : 72 : ControlFile.MaxConnections = 100;
2588 michael@paquier.xyz 931 : 72 : ControlFile.max_wal_senders = 10;
3387 rhaas@postgresql.org 932 : 72 : ControlFile.max_worker_processes = 8;
5800 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. */
2540 peter@eisentraut.org 937 : 72 : update_controlfile(".", &ControlFile, true);
8611 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
7037 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 : : */
1257 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 : : */
7037 tgl@sss.pgh.pa.us 969 : 115 : xldir = opendir(XLOGDIR);
970 [ - + ]: 115 : if (xldir == NULL)
1437 tgl@sss.pgh.pa.us 971 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
972 : :
4377 bruce@momjian.us 973 [ + + ]:CBC 852 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
974 : : {
3908 fujii@postgresql.org 975 [ + + - + ]: 1198 : 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 */
1257 michael@paquier.xyz 982 : 276 : XLogFromFileName(xlde->d_name, &tli, &segno,
983 : 276 : 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 : : */
5012 heikki.linnakangas@i 991 [ + + ]: 276 : if (segno > newXlogSegNo)
992 : 34 : newXlogSegNo = segno;
993 : : }
994 : : }
995 : :
7037 tgl@sss.pgh.pa.us 996 [ - + ]: 115 : if (errno)
1437 tgl@sss.pgh.pa.us 997 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
998 : :
4377 bruce@momjian.us 999 [ - + ]:CBC 115 : if (closedir(xldir))
1437 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 : : */
5012 heikki.linnakangas@i 1006 :CBC 115 : xlogbytepos = newXlogSegNo * ControlFile.xlog_seg_size;
2912 peter_e@gmx.net 1007 : 115 : newXlogSegNo = (xlogbytepos + ControlFile.xlog_seg_size - 1) / WalSegSz;
5012 heikki.linnakangas@i 1008 : 115 : newXlogSegNo++;
7037 tgl@sss.pgh.pa.us 1009 : 115 : }
1010 : :
1011 : :
1012 : : /*
1013 : : * Remove existing XLOG files
1014 : : */
1015 : : static void
8611 bruce@momjian.us 1016 : 72 : KillExistingXLOG(void)
1017 : : {
1018 : : DIR *xldir;
1019 : : struct dirent *xlde;
1020 : : char path[MAXPGPATH + sizeof(XLOGDIR)];
1021 : :
7559 tgl@sss.pgh.pa.us 1022 : 72 : xldir = opendir(XLOGDIR);
8611 bruce@momjian.us 1023 [ - + ]: 72 : if (xldir == NULL)
1437 tgl@sss.pgh.pa.us 1024 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", XLOGDIR);
1025 : :
4377 bruce@momjian.us 1026 [ + + ]:CBC 454 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1027 : : {
3908 fujii@postgresql.org 1028 [ + + - + ]: 671 : if (IsXLogFileName(xlde->d_name) ||
1029 : 289 : IsPartialXLogFileName(xlde->d_name))
1030 : : {
3260 peter_e@gmx.net 1031 : 93 : snprintf(path, sizeof(path), "%s/%s", XLOGDIR, xlde->d_name);
8611 bruce@momjian.us 1032 [ - + ]: 93 : if (unlink(path) < 0)
1437 tgl@sss.pgh.pa.us 1033 :UBC 0 : pg_fatal("could not delete file \"%s\": %m", path);
1034 : : }
1035 : : }
1036 : :
8611 bruce@momjian.us 1037 [ - + ]:CBC 72 : if (errno)
1437 tgl@sss.pgh.pa.us 1038 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", XLOGDIR);
1039 : :
4377 bruce@momjian.us 1040 [ - + ]:CBC 72 : if (closedir(xldir))
1437 tgl@sss.pgh.pa.us 1041 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
8611 bruce@momjian.us 1042 :CBC 72 : }
1043 : :
1044 : :
1045 : : /*
1046 : : * Remove existing archive status files
1047 : : */
1048 : : static void
6160 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)
1437 tgl@sss.pgh.pa.us 1059 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", ARCHSTATDIR);
1060 : :
4377 bruce@momjian.us 1061 [ + + ]:CBC 216 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1062 : : {
3909 fujii@postgresql.org 1063 [ - + ]: 144 : if (strspn(xlde->d_name, "0123456789ABCDEF") == XLOG_FNAME_LEN &&
3909 fujii@postgresql.org 1064 [ # # ]:UBC 0 : (strcmp(xlde->d_name + XLOG_FNAME_LEN, ".ready") == 0 ||
3908 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 : : {
3260 peter_e@gmx.net 1069 : 0 : snprintf(path, sizeof(path), "%s/%s", ARCHSTATDIR, xlde->d_name);
6160 tgl@sss.pgh.pa.us 1070 [ # # ]: 0 : if (unlink(path) < 0)
1437 1071 : 0 : pg_fatal("could not delete file \"%s\": %m", path);
1072 : : }
1073 : : }
1074 : :
6160 tgl@sss.pgh.pa.us 1075 [ - + ]:CBC 72 : if (errno)
1437 tgl@sss.pgh.pa.us 1076 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", ARCHSTATDIR);
1077 : :
4377 bruce@momjian.us 1078 [ - + ]:CBC 72 : if (closedir(xldir))
1437 tgl@sss.pgh.pa.us 1079 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
1080 : :
1081 : : #undef ARCHSTATDIR
6160 tgl@sss.pgh.pa.us 1082 :CBC 72 : }
1083 : :
1084 : : /*
1085 : : * Remove existing WAL summary files
1086 : : */
1087 : : static void
816 rhaas@postgresql.org 1088 : 72 : KillExistingWALSummaries(void)
1089 : : {
1090 : : #define WALSUMMARYDIR XLOGDIR "/summaries"
1091 : : #define WALSUMMARY_NHEXCHARS 40
1092 : :
1093 : : DIR *xldir;
1094 : : struct dirent *xlde;
1095 : : char path[MAXPGPATH + sizeof(WALSUMMARYDIR)];
1096 : :
1097 : 72 : xldir = opendir(WALSUMMARYDIR);
1098 [ - + ]: 72 : if (xldir == NULL)
816 rhaas@postgresql.org 1099 :UBC 0 : pg_fatal("could not open directory \"%s\": %m", WALSUMMARYDIR);
1100 : :
816 rhaas@postgresql.org 1101 [ + + ]:CBC 216 : while (errno = 0, (xlde = readdir(xldir)) != NULL)
1102 : : {
1103 [ - + ]: 144 : if (strspn(xlde->d_name, "0123456789ABCDEF") == WALSUMMARY_NHEXCHARS &&
816 rhaas@postgresql.org 1104 [ # # ]:UBC 0 : strcmp(xlde->d_name + WALSUMMARY_NHEXCHARS, ".summary") == 0)
1105 : : {
1106 : 0 : snprintf(path, sizeof(path), "%s/%s", WALSUMMARYDIR, xlde->d_name);
1107 [ # # ]: 0 : if (unlink(path) < 0)
1108 : 0 : pg_fatal("could not delete file \"%s\": %m", path);
1109 : : }
1110 : : }
1111 : :
816 rhaas@postgresql.org 1112 [ - + ]:CBC 72 : if (errno)
816 rhaas@postgresql.org 1113 :UBC 0 : pg_fatal("could not read directory \"%s\": %m", WALSUMMARYDIR);
1114 : :
816 rhaas@postgresql.org 1115 [ - + ]:CBC 72 : if (closedir(xldir))
39 michael@paquier.xyz 1116 :UBC 0 : pg_fatal("could not close directory \"%s\": %m", WALSUMMARYDIR);
1117 : :
1118 : : #undef WALSUMMARY_NHEXCHARS
1119 : : #undef WALSUMMARYDIR
816 rhaas@postgresql.org 1120 :CBC 72 : }
1121 : :
1122 : : /*
1123 : : * Write an empty XLOG file, containing only the checkpoint record
1124 : : * already set up in ControlFile.
1125 : : */
1126 : : static void
8611 bruce@momjian.us 1127 : 72 : WriteEmptyXLOG(void)
1128 : : {
1129 : : PGAlignedXLogBlock buffer;
1130 : : XLogPageHeader page;
1131 : : XLogLongPageHeader longpage;
1132 : : XLogRecord *record;
1133 : : pg_crc32c crc;
1134 : : char path[MAXPGPATH];
1135 : : int fd;
1136 : : int nbytes;
1137 : : char *recptr;
1138 : :
2752 tgl@sss.pgh.pa.us 1139 : 72 : memset(buffer.data, 0, XLOG_BLCKSZ);
1140 : :
1141 : : /* Set up the XLOG page header */
1142 : 72 : page = (XLogPageHeader) buffer.data;
8611 bruce@momjian.us 1143 : 72 : page->xlp_magic = XLOG_PAGE_MAGIC;
7907 tgl@sss.pgh.pa.us 1144 : 72 : page->xlp_info = XLP_LONG_HEADER;
1145 : 72 : page->xlp_tli = ControlFile.checkPointCopy.ThisTimeLineID;
5012 heikki.linnakangas@i 1146 : 72 : page->xlp_pageaddr = ControlFile.checkPointCopy.redo - SizeOfXLogLongPHD;
7907 tgl@sss.pgh.pa.us 1147 : 72 : longpage = (XLogLongPageHeader) page;
1148 : 72 : longpage->xlp_sysid = ControlFile.system_identifier;
3099 andres@anarazel.de 1149 : 72 : longpage->xlp_seg_size = WalSegSz;
7284 tgl@sss.pgh.pa.us 1150 : 72 : longpage->xlp_xlog_blcksz = XLOG_BLCKSZ;
1151 : :
1152 : : /* Insert the initial checkpoint record */
4133 heikki.linnakangas@i 1153 : 72 : recptr = (char *) page + SizeOfXLogLongPHD;
1154 : 72 : record = (XLogRecord *) recptr;
45 alvherre@kurilemu.de 1155 :GNC 72 : record->xl_prev = InvalidXLogRecPtr;
8068 tgl@sss.pgh.pa.us 1156 :CBC 72 : record->xl_xid = InvalidTransactionId;
4133 heikki.linnakangas@i 1157 : 72 : record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
8611 bruce@momjian.us 1158 : 72 : record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
1159 : 72 : record->xl_rmid = RM_XLOG_ID;
1160 : :
4133 heikki.linnakangas@i 1161 : 72 : recptr += SizeOfXLogRecord;
3274 tgl@sss.pgh.pa.us 1162 : 72 : *(recptr++) = (char) XLR_BLOCK_ID_DATA_SHORT;
4133 heikki.linnakangas@i 1163 : 72 : *(recptr++) = sizeof(CheckPoint);
1164 : 72 : memcpy(recptr, &ControlFile.checkPointCopy,
1165 : : sizeof(CheckPoint));
1166 : :
4149 1167 : 72 : INIT_CRC32C(crc);
4133 1168 : 72 : COMP_CRC32C(crc, ((char *) record) + SizeOfXLogRecord, record->xl_tot_len - SizeOfXLogRecord);
4149 1169 : 72 : COMP_CRC32C(crc, (char *) record, offsetof(XLogRecord, xl_crc));
1170 : 72 : FIN_CRC32C(crc);
8611 bruce@momjian.us 1171 : 72 : record->xl_crc = crc;
1172 : :
1173 : : /* Write the first page */
3099 andres@anarazel.de 1174 : 72 : XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID,
1175 : : newXlogSegNo, WalSegSz);
1176 : :
8611 bruce@momjian.us 1177 : 72 : unlink(path);
1178 : :
1179 : 72 : fd = open(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
1180 : : pg_file_create_mode);
1181 [ - + ]: 72 : if (fd < 0)
1437 tgl@sss.pgh.pa.us 1182 :UBC 0 : pg_fatal("could not open file \"%s\": %m", path);
1183 : :
8611 bruce@momjian.us 1184 :CBC 72 : errno = 0;
2752 tgl@sss.pgh.pa.us 1185 [ - + ]: 72 : if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1186 : : {
1187 : : /* if write didn't set errno, assume problem is no disk space */
8611 bruce@momjian.us 1188 [ # # ]:UBC 0 : if (errno == 0)
1189 : 0 : errno = ENOSPC;
1437 tgl@sss.pgh.pa.us 1190 : 0 : pg_fatal("could not write file \"%s\": %m", path);
1191 : : }
1192 : :
1193 : : /* Fill the rest of the file with zeroes */
2752 tgl@sss.pgh.pa.us 1194 :CBC 72 : memset(buffer.data, 0, XLOG_BLCKSZ);
3099 andres@anarazel.de 1195 [ + + ]: 132096 : for (nbytes = XLOG_BLCKSZ; nbytes < WalSegSz; nbytes += XLOG_BLCKSZ)
1196 : : {
8611 bruce@momjian.us 1197 : 132024 : errno = 0;
2752 tgl@sss.pgh.pa.us 1198 [ - + ]: 132024 : if (write(fd, buffer.data, XLOG_BLCKSZ) != XLOG_BLCKSZ)
1199 : : {
8611 bruce@momjian.us 1200 [ # # ]:UBC 0 : if (errno == 0)
1201 : 0 : errno = ENOSPC;
1437 tgl@sss.pgh.pa.us 1202 : 0 : pg_fatal("could not write file \"%s\": %m", path);
1203 : : }
1204 : : }
1205 : :
8611 bruce@momjian.us 1206 [ - + ]:CBC 72 : if (fsync(fd) != 0)
1437 tgl@sss.pgh.pa.us 1207 :UBC 0 : pg_fatal("fsync error: %m");
1208 : :
8611 bruce@momjian.us 1209 :CBC 72 : close(fd);
1210 : 72 : }
1211 : :
1212 : :
1213 : : static void
1214 : 1 : usage(void)
1215 : : {
3229 peter_e@gmx.net 1216 : 1 : printf(_("%s resets the PostgreSQL write-ahead log.\n\n"), progname);
899 peter@eisentraut.org 1217 : 1 : printf(_("Usage:\n"));
1218 : 1 : printf(_(" %s [OPTION]... DATADIR\n"), progname);
1219 : :
1220 : 1 : printf(_("\nOptions:\n"));
1221 : 1 : printf(_(" [-D, --pgdata=]DATADIR data directory\n"));
1222 : 1 : printf(_(" -f, --force force update to be done even after unclean shutdown or\n"
1223 : : " if pg_control values had to be guessed\n"));
1224 : 1 : printf(_(" -n, --dry-run no update, just show what would be done\n"));
1225 : 1 : printf(_(" -V, --version output version information, then exit\n"));
1226 : 1 : printf(_(" -?, --help show this help, then exit\n"));
1227 : :
1228 : 1 : printf(_("\nOptions to override control file values:\n"));
2913 peter_e@gmx.net 1229 : 1 : printf(_(" -c, --commit-timestamp-ids=XID,XID\n"
1230 : : " set oldest and newest transactions bearing\n"
1231 : : " commit timestamp (zero means no change)\n"));
1693 bruce@momjian.us 1232 : 1 : printf(_(" -e, --epoch=XIDEPOCH set next transaction ID epoch\n"));
1233 : 1 : printf(_(" -l, --next-wal-file=WALFILE set minimum starting location for new WAL\n"));
1234 : 1 : printf(_(" -m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID\n"));
1235 : 1 : printf(_(" -o, --next-oid=OID set next OID\n"));
1236 : 1 : printf(_(" -O, --multixact-offset=OFFSET set next multitransaction offset\n"));
1237 : 1 : printf(_(" -u, --oldest-transaction-id=XID set oldest transaction ID\n"));
1238 : 1 : printf(_(" -x, --next-transaction-id=XID set next transaction ID\n"));
320 peter@eisentraut.org 1239 : 1 : printf(_(" --char-signedness=OPTION set char signedness to \"signed\" or \"unsigned\"\n"));
1693 bruce@momjian.us 1240 : 1 : printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n"));
1241 : :
2207 peter@eisentraut.org 1242 : 1 : printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
1243 : 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
8611 bruce@momjian.us 1244 : 1 : }
1245 : :
1246 : : /*
1247 : : * strtouint32_strict -- like strtoul(), but returns uint32 and doesn't accept
1248 : : * negative values
1249 : : */
1250 : : static uint32
97 heikki.linnakangas@i 1251 :GNC 102 : strtouint32_strict(const char *restrict s, char **restrict endptr, int base)
1252 : : {
1253 : : unsigned long val;
1254 : : bool is_neg;
1255 : :
1256 : : /* skip leading whitespace */
tgl@sss.pgh.pa.us 1257 [ - + ]: 102 : while (isspace((unsigned char) *s))
97 heikki.linnakangas@i 1258 :UNC 0 : s++;
1259 : :
1260 : : /*
1261 : : * Is it negative? We still call strtoul() if it was, to set 'endptr'.
1262 : : * (The current callers don't care though.)
1263 : : */
97 heikki.linnakangas@i 1264 :GNC 102 : is_neg = (*s == '-');
1265 : :
1266 : 102 : val = strtoul(s, endptr, base);
1267 : :
1268 : : /* reject if it was negative */
1269 [ + - + + ]: 102 : if (errno == 0 && is_neg)
1270 : : {
1271 : 3 : errno = ERANGE;
1272 : 3 : val = 0;
1273 : : }
1274 : :
1275 : : /*
1276 : : * reject values larger than UINT32_MAX on platforms where long is 64 bits
1277 : : * wide.
1278 : : */
1279 [ + + + + ]: 102 : if (errno == 0 && val != (uint32) val)
1280 : : {
1281 : 1 : errno = ERANGE;
1282 : 1 : val = UINT32_MAX;
1283 : : }
1284 : :
1285 : 102 : return (uint32) val;
1286 : : }
1287 : :
1288 : : /*
1289 : : * strtouint64_strict -- like strtou64(), but doesn't accept negative values
1290 : : */
1291 : : static uint64
96 1292 : 13 : strtouint64_strict(const char *restrict s, char **restrict endptr, int base)
1293 : : {
1294 : : uint64 val;
1295 : : bool is_neg;
1296 : :
1297 : : /* skip leading whitespace */
1298 [ - + ]: 13 : while (isspace((unsigned char) *s))
96 heikki.linnakangas@i 1299 :UNC 0 : s++;
1300 : :
1301 : : /*
1302 : : * Is it negative? We still call strtou64() if it was, to set 'endptr'.
1303 : : * (The current callers don't care though.)
1304 : : */
96 heikki.linnakangas@i 1305 :GNC 13 : is_neg = (*s == '-');
1306 : :
1307 : 13 : val = strtou64(s, endptr, base);
1308 : :
1309 : : /* reject if it was negative */
1310 [ + - + + ]: 13 : if (errno == 0 && is_neg)
1311 : : {
1312 : 1 : errno = ERANGE;
1313 : 1 : val = 0;
1314 : : }
1315 : :
1316 : 13 : return val;
1317 : : }
|