diff --git a/contrib/amcheck/t/001_verify_heapam.pl b/contrib/amcheck/t/001_verify_heapam.pl index 39e16356d8..64ba64d6b4 100644 --- a/contrib/amcheck/t/001_verify_heapam.pl +++ b/contrib/amcheck/t/001_verify_heapam.pl @@ -7,7 +7,6 @@ use warnings; use PostgresNode; use TestLib; -use Fcntl qw(:seek); use Test::More tests => 80; my ($node, $result); @@ -127,8 +126,8 @@ sub corrupt_first_page # Corrupt some line pointers. The values are chosen to hit the # various line-pointer-corruption checks in verify_heapam.c # on both little-endian and big-endian architectures. - seek($fh, 32, SEEK_SET) - or BAIL_OUT("seek failed: $!"); + sysseek($fh, 32, 0) + or BAIL_OUT("sysseek failed: $!"); syswrite( $fh, pack("L*", diff --git a/src/bin/pg_amcheck/t/003_check.pl b/src/bin/pg_amcheck/t/003_check.pl index cb4c86ad9e..4122d729d4 100644 --- a/src/bin/pg_amcheck/t/003_check.pl +++ b/src/bin/pg_amcheck/t/003_check.pl @@ -7,7 +7,6 @@ use warnings; use PostgresNode; use TestLib; -use Fcntl qw(:seek); use Test::More tests => 63; my ($node, $port, %corrupt_page, %remove_relation); @@ -90,8 +89,8 @@ sub corrupt_first_page # Corrupt some line pointers. The values are chosen to hit the # various line-pointer-corruption checks in verify_heapam.c # on both little-endian and big-endian architectures. - seek($fh, 32, SEEK_SET) - or BAIL_OUT("seek failed: $!"); + sysseek($fh, 32, 0) + or BAIL_OUT("sysseek failed: $!"); syswrite( $fh, pack("L*", diff --git a/src/bin/pg_amcheck/t/004_verify_heapam.pl b/src/bin/pg_amcheck/t/004_verify_heapam.pl index 308fc61868..b603efad92 100644 --- a/src/bin/pg_amcheck/t/004_verify_heapam.pl +++ b/src/bin/pg_amcheck/t/004_verify_heapam.pl @@ -7,7 +7,6 @@ use warnings; use PostgresNode; use TestLib; -use Fcntl qw(:seek); use Test::More; # This regression test demonstrates that the pg_amcheck binary correctly @@ -99,8 +98,8 @@ sub read_tuple { my ($fh, $offset) = @_; my ($buffer, %tup); - seek($fh, $offset, SEEK_SET) - or BAIL_OUT("seek failed: $!"); + sysseek($fh, $offset, 0) + or BAIL_OUT("sysseek failed: $!"); defined(sysread($fh, $buffer, HEAPTUPLE_PACK_LENGTH)) or BAIL_OUT("sysread failed: $!"); @@ -165,8 +164,8 @@ sub write_tuple $tup->{c_va_header}, $tup->{c_va_vartag}, $tup->{c_va_rawsize}, $tup->{c_va_extinfo}, $tup->{c_va_valueid}, $tup->{c_va_toastrelid}); - seek($fh, $offset, SEEK_SET) - or BAIL_OUT("seek failed: $!"); + sysseek($fh, $offset, 0) + or BAIL_OUT("sysseek failed: $!"); defined(syswrite($fh, $buffer, HEAPTUPLE_PACK_LENGTH)) or BAIL_OUT("syswrite failed: $!"); return; diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl index 0db3e0a316..72a2cf8ac8 100644 --- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl +++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl @@ -7,7 +7,6 @@ use Cwd; use Config; use File::Basename qw(basename dirname); use File::Path qw(rmtree); -use Fcntl qw(:seek); use PostgresNode; use TestLib; use Test::More tests => 110; @@ -40,7 +39,7 @@ if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR") } $node->set_replication_conf(); -system_or_bail 'pg_ctl', '-D', $pgdata, 'reload'; +$node->reload; $node->command_fails( [ 'pg_basebackup', '-D', "$tempdir/backup" ], @@ -555,17 +554,13 @@ my $file_corrupt2 = $node->safe_psql('postgres', q{CREATE TABLE corrupt2 AS SELECT b FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')} ); -# set page header and block sizes -my $pageheader_size = 24; +# get block size for corruption steps my $block_size = $node->safe_psql('postgres', 'SHOW block_size;'); # induce corruption -system_or_bail 'pg_ctl', '-D', $pgdata, 'stop'; -open $file, '+<', "$pgdata/$file_corrupt1"; -seek($file, $pageheader_size, SEEK_SET); -syswrite($file, "\0\0\0\0\0\0\0\0\0"); -close $file; -system_or_bail 'pg_ctl', '-D', $pgdata, 'start'; +$node->stop; +$node->corrupt_page_checksum($file_corrupt1, 0); +$node->start; $node->command_checks_all( [ 'pg_basebackup', '-D', "$tempdir/backup_corrupt" ], @@ -576,16 +571,12 @@ $node->command_checks_all( rmtree("$tempdir/backup_corrupt"); # induce further corruption in 5 more blocks -system_or_bail 'pg_ctl', '-D', $pgdata, 'stop'; -open $file, '+<', "$pgdata/$file_corrupt1"; +$node->stop; for my $i (1 .. 5) { - my $offset = $pageheader_size + $i * $block_size; - seek($file, $offset, SEEK_SET); - syswrite($file, "\0\0\0\0\0\0\0\0\0"); + $node->corrupt_page_checksum($file_corrupt1, $i * $block_size); } -close $file; -system_or_bail 'pg_ctl', '-D', $pgdata, 'start'; +$node->start; $node->command_checks_all( [ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2" ], @@ -596,12 +587,9 @@ $node->command_checks_all( rmtree("$tempdir/backup_corrupt2"); # induce corruption in a second file -system_or_bail 'pg_ctl', '-D', $pgdata, 'stop'; -open $file, '+<', "$pgdata/$file_corrupt2"; -seek($file, $pageheader_size, SEEK_SET); -syswrite($file, "\0\0\0\0\0\0\0\0\0"); -close $file; -system_or_bail 'pg_ctl', '-D', $pgdata, 'start'; +$node->stop; +$node->corrupt_page_checksum($file_corrupt2, 0); +$node->start; $node->command_checks_all( [ 'pg_basebackup', '-D', "$tempdir/backup_corrupt3" ], diff --git a/src/bin/pg_checksums/t/002_actions.pl b/src/bin/pg_checksums/t/002_actions.pl index 4cace1542d..761f7ab53b 100644 --- a/src/bin/pg_checksums/t/002_actions.pl +++ b/src/bin/pg_checksums/t/002_actions.pl @@ -9,7 +9,6 @@ use warnings; use PostgresNode; use TestLib; -use Fcntl qw(:seek); use Test::More tests => 63; @@ -24,6 +23,7 @@ sub check_relation_corruption my $tablespace = shift; my $pgdata = $node->data_dir; + # Create table and discover its filesystem location. $node->safe_psql( 'postgres', "CREATE TABLE $table AS SELECT a FROM generate_series(1,10000) AS a; @@ -37,9 +37,6 @@ sub check_relation_corruption my $relfilenode_corrupted = $node->safe_psql('postgres', "SELECT relfilenode FROM pg_class WHERE relname = '$table';"); - # Set page header and block size - my $pageheader_size = 24; - my $block_size = $node->safe_psql('postgres', 'SHOW block_size;'); $node->stop; # Checksums are correct for single relfilenode as the table is not @@ -54,10 +51,7 @@ sub check_relation_corruption ); # Time to create some corruption - open my $file, '+<', "$pgdata/$file_corrupted"; - seek($file, $pageheader_size, SEEK_SET); - syswrite($file, "\0\0\0\0\0\0\0\0\0"); - close $file; + $node->corrupt_page_checksum($file_corrupted, 0); # Checksum checks on single relfilenode fail $node->command_checks_all( diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm index c9016db6f8..92d9303e23 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -2726,6 +2726,37 @@ sub pg_recvlogical_upto =pod +=item $node->corrupt_page_checksum(self, file, page_offset) + +Intentionally corrupt the checksum field of one page in a file. +The server must be stopped for this to work reliably. + +The file name should be specified relative to the cluster datadir. +page_offset had better be a multiple of the cluster's block size. + +=cut + +sub corrupt_page_checksum +{ + my ($self, $file, $page_offset) = @_; + my $pgdata = $self->data_dir; + my $pageheader; + + open my $fh, '+<', "$pgdata/$file" or die "open($file) failed: $!"; + binmode $fh; + sysseek($fh, $page_offset, 0) or die "sysseek failed: $!"; + sysread($fh, $pageheader, 24) or die "sysread failed: $!"; + # This inverts the pd_checksum field (only); see struct PageHeaderData + $pageheader ^= "\0\0\0\0\0\0\0\0\xff\xff"; + sysseek($fh, $page_offset, 0) or die "sysseek failed: $!"; + syswrite($fh, $pageheader) or die "syswrite failed: $!"; + close $fh; + + return; +} + +=pod + =back =cut