diff --git a/doc/src/sgml/ref/pg_resetxlog.sgml b/doc/src/sgml/ref/pg_resetxlog.sgml index fd9d0be6f44..9758fa652a2 100644 --- a/doc/src/sgml/ref/pg_resetxlog.sgml +++ b/doc/src/sgml/ref/pg_resetxlog.sgml @@ -281,6 +281,11 @@ PostgreSQL documentation pg_resetxlog to run. But before you do so, make doubly certain that there is no server process still alive. + + + pg_resetxlog works only with servers of the same + major version. + diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c index 3ffff22daab..fdd75044de8 100644 --- a/src/bin/pg_resetxlog/pg_resetxlog.c +++ b/src/bin/pg_resetxlog/pg_resetxlog.c @@ -72,6 +72,7 @@ static MultiXactOffset set_mxoff = (MultiXactOffset) -1; static uint32 minXlogTli = 0; static XLogSegNo minXlogSegNo = 0; +static void CheckDataVersion(void); static bool ReadControlFile(void); static void GuessControlValues(void); static void PrintControlValues(bool guessed); @@ -320,6 +321,9 @@ main(int argc, char *argv[]) exit(1); } + /* Check that data directory matches our server version */ + CheckDataVersion(); + /* * Check for a postmaster lock file --- if there is one, refuse to * proceed, on grounds we might be interfering with a live installation. @@ -453,6 +457,70 @@ main(int argc, char *argv[]) } +/* + * Look at the version string stored in PG_VERSION and decide if this utility + * can be run safely or not. + * + * We don't want to inject pg_control and WAL files that are for a different + * major version; that can't do anything good. Note that we don't treat + * mismatching version info in pg_control as a reason to bail out, because + * recovering from a corrupted pg_control is one of the main reasons for this + * program to exist at all. However, PG_VERSION is unlikely to get corrupted, + * and if it were it would be easy to fix by hand. So let's make this check + * to prevent simple user errors. + */ +static void +CheckDataVersion(void) +{ + const char *ver_file = "PG_VERSION"; + FILE *ver_fd; + char rawline[64]; + int len; + + if ((ver_fd = fopen(ver_file, "r")) == NULL) + { + fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"), + progname, ver_file, strerror(errno)); + exit(1); + } + + /* version number has to be the first line read */ + if (!fgets(rawline, sizeof(rawline), ver_fd)) + { + if (!ferror(ver_fd)) + { + fprintf(stderr, _("%s: unexpected empty file \"%s\"\n"), + progname, ver_file); + } + else + { + fprintf(stderr, _("%s: could not read file \"%s\": %s\n"), + progname, ver_file, strerror(errno)); + } + exit(1); + } + + /* remove trailing newline, handling Windows newlines as well */ + len = strlen(rawline); + if (len > 0 && rawline[len - 1] == '\n') + { + rawline[--len] = '\0'; + if (len > 0 && rawline[len - 1] == '\r') + rawline[--len] = '\0'; + } + + if (strcmp(rawline, PG_MAJORVERSION) != 0) + { + fprintf(stderr, _("%s: data directory is of wrong version\n" + "File \"%s\" contains \"%s\", which is not compatible with this program's version \"%s\".\n"), + progname, ver_file, rawline, PG_MAJORVERSION); + exit(1); + } + + fclose(ver_fd); +} + + /* * Try to read the existing pg_control file. * @@ -522,7 +590,7 @@ ReadControlFile(void) } /* Looks like it's a mess. */ - fprintf(stderr, _("%s: pg_control exists but is broken or unknown version; ignoring it\n"), + fprintf(stderr, _("%s: pg_control exists but is broken or wrong version; ignoring it\n"), progname); return false; }