Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 98bff29

Browse files
committed
Prevent running pg_resetwal/pg_resetxlog against wrong-version data dirs.
pg_resetwal (formerly pg_resetxlog) doesn't insist on finding a matching version number in pg_control, and that seems like an important thing to preserve since recovering from corrupt pg_control is a prime reason to need to run it. However, that means you can try to run it against a data directory of a different major version, which is at best useless and at worst disastrous. So as to provide some protection against that type of pilot error, inspect PG_VERSION at startup and refuse to do anything if it doesn't match. PG_VERSION is read-only after initdb, so it's unlikely to get corrupted, and even if it were corrupted it would be easy to fix by hand. This hazard has been there all along, so back-patch to all supported branches. Michael Paquier, with some kibitzing by me Discussion: https://postgr.es/m/f4b8eb91-b934-8a0d-b3cc-68f06e2279d1@enterprisedb.com
1 parent dd1daa0 commit 98bff29

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

doc/src/sgml/ref/pg_resetxlog.sgml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,11 @@ PostgreSQL documentation
281281
<command>pg_resetxlog</command> to run. But before you do
282282
so, make doubly certain that there is no server process still alive.
283283
</para>
284+
285+
<para>
286+
<command>pg_resetxlog</command> works only with servers of the same
287+
major version.
288+
</para>
284289
</refsect1>
285290

286291
<refsect1>

src/bin/pg_resetxlog/pg_resetxlog.c

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ static MultiXactOffset set_mxoff = (MultiXactOffset) -1;
7272
static uint32 minXlogTli = 0;
7373
static XLogSegNo minXlogSegNo = 0;
7474

75+
static void CheckDataVersion(void);
7576
static bool ReadControlFile(void);
7677
static void GuessControlValues(void);
7778
static void PrintControlValues(bool guessed);
@@ -320,6 +321,9 @@ main(int argc, char *argv[])
320321
exit(1);
321322
}
322323

324+
/* Check that data directory matches our server version */
325+
CheckDataVersion();
326+
323327
/*
324328
* Check for a postmaster lock file --- if there is one, refuse to
325329
* proceed, on grounds we might be interfering with a live installation.
@@ -453,6 +457,70 @@ main(int argc, char *argv[])
453457
}
454458

455459

460+
/*
461+
* Look at the version string stored in PG_VERSION and decide if this utility
462+
* can be run safely or not.
463+
*
464+
* We don't want to inject pg_control and WAL files that are for a different
465+
* major version; that can't do anything good. Note that we don't treat
466+
* mismatching version info in pg_control as a reason to bail out, because
467+
* recovering from a corrupted pg_control is one of the main reasons for this
468+
* program to exist at all. However, PG_VERSION is unlikely to get corrupted,
469+
* and if it were it would be easy to fix by hand. So let's make this check
470+
* to prevent simple user errors.
471+
*/
472+
static void
473+
CheckDataVersion(void)
474+
{
475+
const char *ver_file = "PG_VERSION";
476+
FILE *ver_fd;
477+
char rawline[64];
478+
int len;
479+
480+
if ((ver_fd = fopen(ver_file, "r")) == NULL)
481+
{
482+
fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
483+
progname, ver_file, strerror(errno));
484+
exit(1);
485+
}
486+
487+
/* version number has to be the first line read */
488+
if (!fgets(rawline, sizeof(rawline), ver_fd))
489+
{
490+
if (!ferror(ver_fd))
491+
{
492+
fprintf(stderr, _("%s: unexpected empty file \"%s\"\n"),
493+
progname, ver_file);
494+
}
495+
else
496+
{
497+
fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
498+
progname, ver_file, strerror(errno));
499+
}
500+
exit(1);
501+
}
502+
503+
/* remove trailing newline, handling Windows newlines as well */
504+
len = strlen(rawline);
505+
if (len > 0 && rawline[len - 1] == '\n')
506+
{
507+
rawline[--len] = '\0';
508+
if (len > 0 && rawline[len - 1] == '\r')
509+
rawline[--len] = '\0';
510+
}
511+
512+
if (strcmp(rawline, PG_MAJORVERSION) != 0)
513+
{
514+
fprintf(stderr, _("%s: data directory is of wrong version\n"
515+
"File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".\n"),
516+
progname, ver_file, rawline, PG_MAJORVERSION);
517+
exit(1);
518+
}
519+
520+
fclose(ver_fd);
521+
}
522+
523+
456524
/*
457525
* Try to read the existing pg_control file.
458526
*
@@ -522,7 +590,7 @@ ReadControlFile(void)
522590
}
523591

524592
/* Looks like it's a mess. */
525-
fprintf(stderr, _("%s: pg_control exists but is broken or unknown version; ignoring it\n"),
593+
fprintf(stderr, _("%s: pg_control exists but is broken or wrong version; ignoring it\n"),
526594
progname);
527595
return false;
528596
}

0 commit comments

Comments
 (0)