5 Commits

Author SHA1 Message Date
67f438986f Bump version to 9.6.0 2016-09-29 13:24:49 +02:00
1c9dd6b728 Set exit status if something goes wrong.
Aleksander Alekseev
2016-09-23 15:43:11 +03:00
052ed01129 Fix checksum validation for relations that have more than one segment.
A blkno argument passed to pg_checksum_page procedure should be not a
relative block number in a given segment but an absolute block number
in the entire relation. It's the same for the segment number 0, but for
segment number N the difference is RELSEG_SIZE * N.

Aleksander Alekseev
2016-09-07 19:27:02 +03:00
b163cdaa53 Use LDFLAGS to link 2016-03-24 18:59:57 +01:00
42257f58af Use pg_config --libdir 2016-03-24 18:58:53 +01:00
4 changed files with 199 additions and 9 deletions

View File

@ -1,7 +1,7 @@
# View README.pg_filedump first
# note this must match version macros in pg_filedump.h
FD_VERSION=9.5.0
FD_VERSION=9.6.0
CC=gcc
CFLAGS=-g -O -Wall -Wmissing-prototypes -Wmissing-declarations
@ -11,6 +11,7 @@ CFLAGS=-g -O -Wall -Wmissing-prototypes -Wmissing-declarations
# the server include subdirectory, eg /usr/local/include/postgresql/server
PG_CONFIG=pg_config
PGSQL_INCLUDE_DIR=$(shell $(PG_CONFIG) --includedir-server)
PGSQL_LIB_DIR=$(shell $(PG_CONFIG) --libdir)
DISTFILES= README.pg_filedump Makefile Makefile.contrib \
@ -19,7 +20,7 @@ DISTFILES= README.pg_filedump Makefile Makefile.contrib \
all: pg_filedump
pg_filedump: pg_filedump.o
${CC} ${CFLAGS} -o pg_filedump pg_filedump.o -lpgport
${CC} ${LDFLAGS} -o pg_filedump pg_filedump.o -L${PGSQL_LIB_DIR} -lpgport
pg_filedump.o: pg_filedump.c
${CC} ${CFLAGS} -I${PGSQL_INCLUDE_DIR} pg_filedump.c -c

View File

@ -59,7 +59,7 @@ not require any manual adjustments of the Makefile.
------------------------------------------------------------------------
Invocation:
pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] file
pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] [-s segsize] [-n segnumber] file
Defaults are: relative addressing, range of the entire file, block size
as listed on block 0 in the file
@ -80,6 +80,8 @@ The following options are valid for heap and index files:
[startblock]: block to start at
[endblock]: block to end at
A startblock without an endblock will format the single block
-s Force segment size to [segsize]
-n Force segment number to [segnumber]
-S Force block size to [blocksize]
-x Force interpreted formatting of block items as index items
-y Force interpreted formatting of block items as heap items

View File

@ -52,6 +52,12 @@ static unsigned int blockSize = 0;
/* Current block in file */
static unsigned int currentBlock = 0;
/* Segment size in bytes */
static unsigned int segmentSize = RELSEG_SIZE * BLCKSZ;
/* Number of current segment */
static unsigned int segmentNumber = 0;
/* Offset of current block */
static unsigned int pageOffset = 0;
@ -61,6 +67,9 @@ static unsigned int bytesToFormat = 0;
/* Block version number */
static unsigned int blockVersion = 0;
/* Program exit code */
static int exitCode = 0;
/***
* Function Prototypes
*/
@ -95,7 +104,7 @@ DisplayOptions(unsigned int validOptions)
FD_VERSION, FD_PG_VERSION);
printf
("\nUsage: pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] file\n\n"
("\nUsage: pg_filedump [-abcdfhikxy] [-R startblock [endblock]] [-S blocksize] [-s segsize] [-n segnumber] file\n\n"
"Display formatted contents of a PostgreSQL heap/index/control file\n"
"Defaults are: relative addressing, range of the entire file, block\n"
" size as listed on block 0 in the file\n\n"
@ -114,6 +123,8 @@ DisplayOptions(unsigned int validOptions)
" indexed from 0)\n" " [startblock]: block to start at\n"
" [endblock]: block to end at\n"
" A startblock without an endblock will format the single block\n"
" -s Force segment size to [segsize]\n"
" -n Force segment number to [segnumber]\n"
" -S Force block size to [blocksize]\n"
" -x Force interpreted formatting of block items as index items\n"
" -y Force interpreted formatting of block items as heap items\n\n"
@ -124,6 +135,31 @@ DisplayOptions(unsigned int validOptions)
"\nReport bugs to <pgsql-bugs@postgresql.org>\n");
}
/*
* Determine segment number by segment file name. For instance, if file
* name is /path/to/xxxx.7 procedure returns 7. Default return value is 0.
*/
static unsigned int
GetSegmentNumberFromFileName(const char* fileName)
{
int segnumOffset = strlen(fileName) - 1;
if(segnumOffset < 0)
return 0;
while(isdigit(fileName[segnumOffset]))
{
segnumOffset--;
if(segnumOffset < 0)
return 0;
}
if(fileName[segnumOffset] != '.')
return 0;
return atoi(&fileName[segnumOffset+1]);
}
/* Iterate through the provided options and set the option flags. */
/* An error will result in a positive rc and will force a display */
/* of the usage information. This routine returns enum */
@ -158,6 +194,7 @@ ConsumeOptions(int numOptions, char **options)
{
rc = OPT_RC_INVALID;
printf("Error: Missing range start identifier.\n");
exitCode = 1;
break;
}
@ -172,6 +209,7 @@ ConsumeOptions(int numOptions, char **options)
rc = OPT_RC_INVALID;
printf("Error: Invalid range start identifier <%s>.\n",
optionString);
exitCode = 1;
break;
}
@ -197,6 +235,7 @@ ConsumeOptions(int numOptions, char **options)
rc = OPT_RC_INVALID;
printf("Error: Requested block range start <%d> is "
"greater than end <%d>.\n", blockStart, range);
exitCode = 1;
break;
}
}
@ -232,6 +271,74 @@ ConsumeOptions(int numOptions, char **options)
rc = OPT_RC_INVALID;
printf("Error: Invalid block size requested <%s>.\n",
optionString);
exitCode = 1;
break;
}
}
/* Check for the special case where the user forces a segment size. */
else if ((optionStringLength == 2)
&& (strcmp(optionString, "-s") == 0))
{
int localSegmentSize;
SET_OPTION(segmentOptions, SEGMENT_SIZE_FORCED, 's');
/* Only accept the forced size option once */
if (rc == OPT_RC_DUPLICATE)
break;
/* The token immediately following -s is the segment size */
if (x >= (numOptions - 2))
{
rc = OPT_RC_INVALID;
printf("Error: Missing segment size identifier.\n");
exitCode = 1;
break;
}
/* Next option encountered must be forced segment size */
optionString = options[++x];
if ((localSegmentSize = GetOptionValue(optionString)) > 0)
segmentSize = (unsigned int) localSegmentSize;
else
{
rc = OPT_RC_INVALID;
printf("Error: Invalid segment size requested <%s>.\n",
optionString);
exitCode = 1;
break;
}
}
/* Check for the special case where the user forces a segment number */
/* instead of having the tool determine it by file name. */
else if ((optionStringLength == 2)
&& (strcmp(optionString, "-n") == 0))
{
int localSegmentNumber;
SET_OPTION(segmentOptions, SEGMENT_NUMBER_FORCED, 'n');
/* Only accept the forced segment number option once */
if (rc == OPT_RC_DUPLICATE)
break;
/* The token immediately following -n is the segment number */
if (x >= (numOptions - 2))
{
rc = OPT_RC_INVALID;
printf("Error: Missing segment number identifier.\n");
exitCode = 1;
break;
}
/* Next option encountered must be forced segment number */
optionString = options[++x];
if ((localSegmentNumber = GetOptionValue(optionString)) > 0)
segmentNumber = (unsigned int) localSegmentNumber;
else
{
rc = OPT_RC_INVALID;
printf("Error: Invalid segment number requested <%s>.\n",
optionString);
exitCode = 1;
break;
}
}
@ -243,11 +350,16 @@ ConsumeOptions(int numOptions, char **options)
{
fp = fopen(optionString, "rb");
if (fp)
{
fileName = options[x];
if(!(segmentOptions & SEGMENT_NUMBER_FORCED))
segmentNumber = GetSegmentNumberFromFileName(fileName);
}
else
{
rc = OPT_RC_FILE;
printf("Error: Could not open file <%s>.\n", optionString);
exitCode = 1;
break;
}
}
@ -261,6 +373,7 @@ ConsumeOptions(int numOptions, char **options)
{
rc = OPT_RC_FILE;
printf("Error: Missing file name to dump.\n");
exitCode = 1;
}
break;
}
@ -274,6 +387,7 @@ ConsumeOptions(int numOptions, char **options)
{
rc = OPT_RC_INVALID;
printf("Error: Invalid option string <%s>.\n", optionString);
exitCode = 1;
break;
}
@ -335,6 +449,7 @@ ConsumeOptions(int numOptions, char **options)
rc = OPT_RC_INVALID;
printf("Error: Options <y> and <x> are "
"mutually exclusive.\n");
exitCode = 1;
}
break;
@ -346,12 +461,14 @@ ConsumeOptions(int numOptions, char **options)
rc = OPT_RC_INVALID;
printf("Error: Options <x> and <y> are "
"mutually exclusive.\n");
exitCode = 1;
}
break;
default:
rc = OPT_RC_INVALID;
printf("Error: Unknown option <%c>.\n", optionString[y]);
exitCode = 1;
break;
}
@ -362,7 +479,10 @@ ConsumeOptions(int numOptions, char **options)
}
if (rc == OPT_RC_DUPLICATE)
{
printf("Error: Duplicate option listed <%c>.\n", duplicateSwitch);
exitCode = 1;
}
/* If the user requested a control file dump, a pure binary */
/* block dump or a non-interpreted formatted dump, mask off */
@ -379,6 +499,7 @@ ConsumeOptions(int numOptions, char **options)
rc = OPT_RC_INVALID;
printf("Error: Invalid options used for Control File dump.\n"
" Only options <Sf> may be used with <c>.\n");
exitCode = 1;
}
else
{
@ -446,8 +567,12 @@ GetBlockSize()
if (bytesRead == pageHeaderSize)
localSize = (unsigned int) PageGetPageSize(&localCache);
else
{
printf("Error: Unable to read full page header from block 0.\n"
" ===> Read %u bytes", bytesRead);
" ===> Read %u bytes\n", bytesRead);
exitCode = 1;
}
return (localSize);
}
@ -687,24 +812,34 @@ FormatHeader(Page page, BlockNumber blkno)
|| (pageHeader->pd_lower > blockSize)
|| (pageHeader->pd_upper < pageHeader->pd_lower)
|| (pageHeader->pd_special > blockSize))
{
printf(" Error: Invalid header information.\n\n");
exitCode = 1;
}
if (blockOptions & BLOCK_CHECKSUMS)
{
uint16 calc_checksum = pg_checksum_page(page, blkno);
uint32 delta = (segmentSize/blockSize)*segmentNumber;
uint16 calc_checksum = pg_checksum_page(page, delta + blkno);
if (calc_checksum != pageHeader->pd_checksum)
{
printf(" Error: checksum failure: calculated 0x%04x.\n\n",
calc_checksum);
exitCode = 1;
}
}
}
/* If we have reached the end of file while interpreting the header, let */
/* the user know about it */
if (rc == EOF_ENCOUNTERED)
{
printf
(" Error: End of block encountered within the header."
" Bytes read: %4u.\n\n", bytesToFormat);
exitCode = 1;
}
/* A request to dump the formatted binary of the block (header, */
/* items and special section). It's best to dump even on an error */
@ -739,8 +874,11 @@ FormatItemBlock(Page page)
if (maxOffset == 0)
printf(" Empty block - no items listed \n\n");
else if ((maxOffset < 0) || (maxOffset > blockSize))
{
printf(" Error: Item index corrupt on block. Offset: <%d>.\n\n",
maxOffset);
exitCode = 1;
}
else
{
int formatAs;
@ -813,9 +951,12 @@ FormatItemBlock(Page page)
/* formatting */
if ((itemOffset + itemSize > blockSize) ||
(itemOffset + itemSize > bytesToFormat))
{
printf(" Error: Item contents extend beyond block.\n"
" BlockSize<%d> Bytes Read<%d> Item Start<%d>.\n",
blockSize, bytesToFormat, itemOffset + itemSize);
exitCode = 1;
}
else
{
/* If the user requests that the items be interpreted as */
@ -853,7 +994,10 @@ FormatItem(unsigned int numBytes, unsigned int startIndex,
if (numBytes < SizeOfIptrData)
{
if (numBytes)
{
printf(" Error: This item does not look like an index item.\n");
exitCode = 1;
}
}
else
{
@ -869,8 +1013,11 @@ FormatItem(unsigned int numBytes, unsigned int startIndex,
IndexTupleHasVarwidths(itup) ? 1 : 0);
if (numBytes != IndexTupleSize(itup))
{
printf(" Error: Item size difference. Given <%u>, "
"Internal <%d>.\n", numBytes, (int) IndexTupleSize(itup));
exitCode = 1;
}
}
}
else if (formatAs == ITEM_SPG_INNER)
@ -879,7 +1026,10 @@ FormatItem(unsigned int numBytes, unsigned int startIndex,
if (numBytes < SGITHDRSZ)
{
if (numBytes)
{
printf(" Error: This item does not look like an SPGiST item.\n");
exitCode = 1;
}
}
else
{
@ -892,8 +1042,11 @@ FormatItem(unsigned int numBytes, unsigned int startIndex,
itup->prefixSize);
if (numBytes != itup->size)
{
printf(" Error: Item size difference. Given <%u>, "
"Internal <%d>.\n", numBytes, (int) itup->size);
exitCode = 1;
}
else if (itup->prefixSize == MAXALIGN(itup->prefixSize))
{
int i;
@ -935,7 +1088,10 @@ FormatItem(unsigned int numBytes, unsigned int startIndex,
if (numBytes < SGLTHDRSZ)
{
if (numBytes)
{
printf(" Error: This item does not look like an SPGiST item.\n");
exitCode = 1;
}
}
else
{
@ -949,8 +1105,11 @@ FormatItem(unsigned int numBytes, unsigned int startIndex,
itup->heapPtr.ip_posid);
if (numBytes != itup->size)
{
printf(" Error: Item size difference. Given <%u>, "
"Internal <%d>.\n", numBytes, (int) itup->size);
exitCode = 1;
}
}
}
else
@ -961,7 +1120,10 @@ FormatItem(unsigned int numBytes, unsigned int startIndex,
if (numBytes < alignedSize)
{
if (numBytes)
{
printf(" Error: This item does not look like a heap item.\n");
exitCode = 1;
}
}
else
{
@ -1068,10 +1230,14 @@ FormatItem(unsigned int numBytes, unsigned int startIndex,
* array
*/
if (computedLength != localHoff)
{
printf
(" Error: Computed header length not equal to header size.\n"
" Computed <%u> Header: <%d>\n", computedLength,
localHoff);
exitCode = 1;
}
else if ((infoMask & HEAP_HASNULL) && bitmapLength)
{
printf(" t_bits: ");
@ -1107,6 +1273,7 @@ FormatSpecial()
case SPEC_SECT_ERROR_UNKNOWN:
case SPEC_SECT_ERROR_BOUNDARY:
printf(" Error: Invalid special section encountered.\n");
exitCode = 1;
break;
case SPEC_SECT_SEQUENCE:
@ -1261,6 +1428,7 @@ FormatSpecial()
/* No idea what type of special section this is */
default:
printf(" Unknown special section type. Type: <%u>.\n", specialType);
exitCode = 1;
break;
}
@ -1268,8 +1436,12 @@ FormatSpecial()
if (blockOptions & BLOCK_FORMAT)
{
if (specialType == SPEC_SECT_ERROR_BOUNDARY)
{
printf(" Error: Special section points off page."
" Unable to dump contents.\n");
exitCode = 1;
}
else
FormatBinary(specialSize, specialOffset);
}
@ -1450,6 +1622,8 @@ FormatControl()
/* If we have an error, force a formatted dump so we can see */
/* where things are going wrong */
controlOptions |= CONTROL_FORMAT;
exitCode = 1;
}
/* Dump hex and ascii representation of data */
@ -1539,6 +1713,7 @@ DumpFileContents()
printf("Error: Seek error encountered before requested "
"start block <%d>.\n", blockStart);
contentsToDump = 0;
exitCode = 1;
}
else
currentBlock = blockStart;
@ -1633,8 +1808,11 @@ main(int argv, char **argc)
if (buffer)
DumpFileContents();
else
{
printf("\nError: Unable to create buffer of size <%d>.\n",
blockSize);
exitCode = 1;
}
}
}
@ -1645,5 +1823,5 @@ main(int argv, char **argc)
if (buffer)
free(buffer);
exit(0);
exit(exitCode);
}

View File

@ -22,8 +22,8 @@
* Original Author: Patrick Macdonald <patrickm@redhat.com>
*/
#define FD_VERSION "9.5.0" /* version ID of pg_filedump */
#define FD_PG_VERSION "PostgreSQL 9.5.x" /* PG version it works with */
#define FD_VERSION "9.6.0" /* version ID of pg_filedump */
#define FD_PG_VERSION "PostgreSQL 9.6.x" /* PG version it works with */
#include "postgres.h"
@ -55,6 +55,15 @@ typedef enum blockSwitches
BLOCK_CHECKSUMS = 0x00000040 /* -k: verify block checksums */
} blockSwitches;
/* Segment-related options */
static unsigned int segmentOptions = 0;
typedef enum segmentSwitches
{
SEGMENT_SIZE_FORCED = 0x00000001, /* -s: Segment size forced */
SEGMENT_NUMBER_FORCED = 0x00000002, /* -n: Segment number forced */
} segmentSwitches;
/* -R[start]:Block range start */
static int blockStart = -1;