summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeikki Linnakangas2025-11-11 17:00:41 +0000
committerHeikki Linnakangas2025-11-11 17:00:41 +0000
commit6956bca515e2a07a16c6d68b208766e97b275ddc (patch)
tree63c14e2d258c56e9a861cfe35d315bf95e174dd5 /src
parent676cd9ac07430282df71532b8d0a4f3c09831f76 (diff)
Add warning to pg_controldata on PG_CONTROL_VERSION mismatchHEADmaster
If you run pg_controldata on a cluster that has been initialized with different PG_CONTROL_VERSION than what the pg_controldata program has been compiled with, pg_controldata will still try to interpret the control file, but the result is likely to be somewhat nonsensical. How nonsensical it is depends on the differences between the versions. If sizeof(ControlFileData) differs between the versions, the CRC will not match and you get a warning of that, but otherwise you get no warning. Looking back at recent PG_CONTROL_VERSION updates, all changes that would mess up the printed values have also changed sizeof(ControlFileData), but there's no guarantee of that in future versions. Add an explicit check and warning for version number mismatch before the CRC check. That way, you get a more clear warning if you use the pg_controldata binary from wrong version, and if we change the control file in the future in a way that doesn't change sizeof(ControlFileData), this ensures that you get a warning in that case too. Discussion: https://www.postgresql.org/message-id/[email protected]
Diffstat (limited to 'src')
-rw-r--r--src/bin/pg_controldata/pg_controldata.c9
-rw-r--r--src/bin/pg_controldata/t/001_pg_controldata.pl14
2 files changed, 18 insertions, 5 deletions
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index 5c77f40313b..30ad46912e1 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -167,7 +167,14 @@ main(int argc, char *argv[])
/* get a copy of the control file */
ControlFile = get_controlfile(DataDir, &crc_ok);
- if (!crc_ok)
+ if (ControlFile->pg_control_version != PG_CONTROL_VERSION)
+ {
+ pg_log_warning("control file version (%u) does not match the version understood by this program (%u)",
+ ControlFile->pg_control_version, PG_CONTROL_VERSION);
+ pg_log_warning_detail("Either the control file has been created with a different version of PostgreSQL, "
+ "or it is corrupt. The results below are untrustworthy.");
+ }
+ else if (!crc_ok)
{
pg_log_warning("calculated CRC checksum does not match value stored in control file");
pg_log_warning_detail("Either the control file is corrupt, or it has a different layout than this program "
diff --git a/src/bin/pg_controldata/t/001_pg_controldata.pl b/src/bin/pg_controldata/t/001_pg_controldata.pl
index 4aea00d6d5a..6ace61f9314 100644
--- a/src/bin/pg_controldata/t/001_pg_controldata.pl
+++ b/src/bin/pg_controldata/t/001_pg_controldata.pl
@@ -21,16 +21,22 @@ command_like([ 'pg_controldata', $node->data_dir ],
qr/checkpoint/, 'pg_controldata produces output');
-# check with a corrupted pg_control
+# Check with a corrupted pg_control
+#
+# To corrupt it, overwrite most of it with zeros. We leave the
+# beginning portion that contains the pg_control version number (first
+# 16 bytes) unmodified because otherwise you get an error about the
+# version number, instead of checksum mismatch.
my $pg_control = $node->data_dir . '/global/pg_control';
my $size = -s $pg_control;
-open my $fh, '>', $pg_control or BAIL_OUT($!);
+open my $fh, '+<', $pg_control or BAIL_OUT($!);
binmode $fh;
-# fill file with zeros
-print $fh pack("x[$size]");
+my ($overwrite_off, $overwrite_len) = (16, $size - 16);
+seek $fh, $overwrite_off, 0 or BAIL_OUT($!);
+print $fh pack("x[$overwrite_len]");
close $fh;
command_checks_all(