pg_controldata: Prevent division-by-zero errors
If the control file is corrupted and specifies the WAL segment size to be 0 bytes, calculating the latest checkpoint's REDO WAL file will fail with a division-by-zero error. Show it as "???" instead. Also reword the warning message a bit and send it to stdout, like the other pre-existing warning messages. Add some tests for dealing with a corrupted pg_control file. Author: Nathan Bossart <bossartn@amazon.com>, tests by me
This commit is contained in:
parent
56163004b8
commit
4731d848f2
@ -95,7 +95,6 @@ main(int argc, char *argv[])
|
|||||||
char mock_auth_nonce_str[MOCK_AUTH_NONCE_LEN * 2 + 1];
|
char mock_auth_nonce_str[MOCK_AUTH_NONCE_LEN * 2 + 1];
|
||||||
const char *strftime_fmt = "%c";
|
const char *strftime_fmt = "%c";
|
||||||
const char *progname;
|
const char *progname;
|
||||||
XLogSegNo segno;
|
|
||||||
char xlogfilename[MAXFNAMELEN];
|
char xlogfilename[MAXFNAMELEN];
|
||||||
int c;
|
int c;
|
||||||
int i;
|
int i;
|
||||||
@ -169,10 +168,11 @@ main(int argc, char *argv[])
|
|||||||
WalSegSz = ControlFile->xlog_seg_size;
|
WalSegSz = ControlFile->xlog_seg_size;
|
||||||
|
|
||||||
if (!IsValidWalSegSize(WalSegSz))
|
if (!IsValidWalSegSize(WalSegSz))
|
||||||
fprintf(stderr,
|
printf(_("WARNING: invalid WAL segment size\n"
|
||||||
_("WARNING: WAL segment size specified, %d bytes, is not a power of two between 1MB and 1GB.\n"
|
"The WAL segment size stored in the file, %d bytes, is not a power of two\n"
|
||||||
"The file is corrupt and the results below are untrustworthy.\n"),
|
"between 1 MB and 1 GB. The file is corrupt and the results below are\n"
|
||||||
WalSegSz);
|
"untrustworthy.\n\n"),
|
||||||
|
WalSegSz);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This slightly-chintzy coding will work as long as the control file
|
* This slightly-chintzy coding will work as long as the control file
|
||||||
@ -193,10 +193,20 @@ main(int argc, char *argv[])
|
|||||||
/*
|
/*
|
||||||
* Calculate name of the WAL file containing the latest checkpoint's REDO
|
* Calculate name of the WAL file containing the latest checkpoint's REDO
|
||||||
* start point.
|
* start point.
|
||||||
|
*
|
||||||
|
* A corrupted control file could report a WAL segment size of 0, and to
|
||||||
|
* guard against division by zero, we need to treat that specially.
|
||||||
*/
|
*/
|
||||||
XLByteToSeg(ControlFile->checkPointCopy.redo, segno, WalSegSz);
|
if (WalSegSz != 0)
|
||||||
XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
|
{
|
||||||
segno, WalSegSz);
|
XLogSegNo segno;
|
||||||
|
|
||||||
|
XLByteToSeg(ControlFile->checkPointCopy.redo, segno, WalSegSz);
|
||||||
|
XLogFileName(xlogfilename, ControlFile->checkPointCopy.ThisTimeLineID,
|
||||||
|
segno, WalSegSz);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strcpy(xlogfilename, _("???"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Format system_identifier and mock_authentication_nonce separately to
|
* Format system_identifier and mock_authentication_nonce separately to
|
||||||
|
@ -2,7 +2,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 13;
|
use Test::More tests => 17;
|
||||||
|
|
||||||
program_help_ok('pg_controldata');
|
program_help_ok('pg_controldata');
|
||||||
program_version_ok('pg_controldata');
|
program_version_ok('pg_controldata');
|
||||||
@ -16,3 +16,22 @@ $node->init;
|
|||||||
|
|
||||||
command_like([ 'pg_controldata', $node->data_dir ],
|
command_like([ 'pg_controldata', $node->data_dir ],
|
||||||
qr/checkpoint/, 'pg_controldata produces output');
|
qr/checkpoint/, 'pg_controldata produces output');
|
||||||
|
|
||||||
|
|
||||||
|
# check with a corrupted pg_control
|
||||||
|
|
||||||
|
my $pg_control = $node->data_dir . '/global/pg_control';
|
||||||
|
my $size = (stat($pg_control))[7];
|
||||||
|
|
||||||
|
open my $fh, '>', $pg_control or BAIL_OUT($!);
|
||||||
|
binmode $fh;
|
||||||
|
# fill file with zeros
|
||||||
|
print $fh pack("x[$size]");
|
||||||
|
close $fh;
|
||||||
|
|
||||||
|
command_checks_all([ 'pg_controldata', $node->data_dir ],
|
||||||
|
0,
|
||||||
|
[ qr/WARNING: Calculated CRC checksum does not match value stored in file/,
|
||||||
|
qr/WARNING: invalid WAL segment size/ ],
|
||||||
|
[ qr/^$/ ],
|
||||||
|
'pg_controldata with corrupted pg_control');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user