Code review for pg_verify_checksums.c.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 31 Aug 2018 17:42:18 +0000 (13:42 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 31 Aug 2018 17:42:28 +0000 (13:42 -0400)
Use postgres_fe.h, since this is frontend code.  Pretend that we've heard
of project style guidelines for, eg, #include order.  Use BlockNumber not
int arithmetic for block numbers, to avoid misbehavior with relations
exceeding 2^31 blocks.  Avoid an unnecessary strict-aliasing warning
(per report from Michael Banck).  Const-ify assorted stuff.  Avoid
scribbling on the output of readdir() -- perhaps that's safe in practice,
but POSIX forbids it, and this code has so far earned exactly zero
credibility portability-wise.  Editorialize on an ambiguously-worded
message.

I did not touch the problem of the "buf" local variable being possibly
insufficiently aligned; that's not specific to this code, and seems like
it should be fixed as part of a different, larger patch.

Discussion: https://postgr.es/m/1535618100.1286.3.camel@credativ.de

src/bin/pg_verify_checksums/pg_verify_checksums.c

index d7b6f4a5280daae7bc02e275cbfd927a8db54dec..bf7feedf3462240e6d0f2c761e0a5c8d9319b62c 100644 (file)
@@ -7,23 +7,20 @@
  *
  *     src/bin/pg_verify_checksums/pg_verify_checksums.c
  */
+#include "postgres_fe.h"
 
-#define FRONTEND 1
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
-#include "postgres.h"
 #include "catalog/pg_control.h"
 #include "common/controldata_utils.h"
 #include "getopt_long.h"
+#include "pg_getopt.h"
 #include "storage/bufpage.h"
 #include "storage/checksum.h"
 #include "storage/checksum_impl.h"
 
-#include <sys/stat.h>
-#include <dirent.h>
-#include <unistd.h>
-
-#include "pg_getopt.h"
-
 
 static int64 files = 0;
 static int64 blocks = 0;
@@ -36,7 +33,7 @@ static bool verbose = false;
 static const char *progname;
 
 static void
-usage()
+usage(void)
 {
        printf(_("%s verifies data checksums in a PostgreSQL database cluster.\n\n"), progname);
        printf(_("Usage:\n"));
@@ -52,7 +49,7 @@ usage()
        printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
 }
 
-static const char *skip[] = {
+static const char *const skip[] = {
        "pg_control",
        "pg_filenode.map",
        "pg_internal.init",
@@ -61,9 +58,9 @@ static const char *skip[] = {
 };
 
 static bool
-skipfile(char *fn)
+skipfile(const char *fn)
 {
-       const char **f;
+       const char *const *f;
 
        if (strcmp(fn, ".") == 0 ||
                strcmp(fn, "..") == 0)
@@ -76,12 +73,12 @@ skipfile(char *fn)
 }
 
 static void
-scan_file(char *fn, int segmentno)
+scan_file(const char *fn, BlockNumber segmentno)
 {
        char            buf[BLCKSZ];
        PageHeader      header = (PageHeader) buf;
        int                     f;
-       int                     blockno;
+       BlockNumber blockno;
 
        f = open(fn, O_RDONLY | PG_BINARY);
        if (f < 0)
@@ -102,21 +99,21 @@ scan_file(char *fn, int segmentno)
                        break;
                if (r != BLCKSZ)
                {
-                       fprintf(stderr, _("%s: short read of block %d in file \"%s\", got only %d bytes\n"),
+                       fprintf(stderr, _("%s: short read of block %u in file \"%s\", got only %d bytes\n"),
                                        progname, blockno, fn, r);
                        exit(1);
                }
                blocks++;
 
                /* New pages have no checksum yet */
-               if (PageIsNew(buf))
+               if (PageIsNew(header))
                        continue;
 
                csum = pg_checksum_page(buf, blockno + segmentno * RELSEG_SIZE);
                if (csum != header->pd_checksum)
                {
                        if (ControlFile->data_checksum_version == PG_DATA_CHECKSUM_VERSION)
-                               fprintf(stderr, _("%s: checksum verification failed in file \"%s\", block %d: calculated checksum %X but expected %X\n"),
+                               fprintf(stderr, _("%s: checksum verification failed in file \"%s\", block %u: calculated checksum %X but block contains %X\n"),
                                                progname, fn, blockno, csum, header->pd_checksum);
                        badblocks++;
                }
@@ -130,7 +127,7 @@ scan_file(char *fn, int segmentno)
 }
 
 static void
-scan_directory(char *basedir, char *subdir)
+scan_directory(const char *basedir, const char *subdir)
 {
        char            path[MAXPGPATH];
        DIR                *dir;
@@ -146,7 +143,7 @@ scan_directory(char *basedir, char *subdir)
        }
        while ((de = readdir(dir)) != NULL)
        {
-               char            fn[MAXPGPATH + 1];
+               char            fn[MAXPGPATH];
                struct stat st;
 
                if (skipfile(de->d_name))
@@ -161,9 +158,10 @@ scan_directory(char *basedir, char *subdir)
                }
                if (S_ISREG(st.st_mode))
                {
+                       char            fnonly[MAXPGPATH];
                        char       *forkpath,
                                           *segmentpath;
-                       int                     segmentno = 0;
+                       BlockNumber segmentno = 0;
 
                        /*
                         * Cut off at the segment boundary (".") to get the segment number
@@ -171,7 +169,8 @@ scan_directory(char *basedir, char *subdir)
                         * fork boundary, to get the relfilenode the file belongs to for
                         * filtering.
                         */
-                       segmentpath = strchr(de->d_name, '.');
+                       strlcpy(fnonly, de->d_name, sizeof(fnonly));
+                       segmentpath = strchr(fnonly, '.');
                        if (segmentpath != NULL)
                        {
                                *segmentpath++ = '\0';
@@ -184,11 +183,11 @@ scan_directory(char *basedir, char *subdir)
                                }
                        }
 
-                       forkpath = strchr(de->d_name, '_');
+                       forkpath = strchr(fnonly, '_');
                        if (forkpath != NULL)
                                *forkpath++ = '\0';
 
-                       if (only_relfilenode && strcmp(only_relfilenode, de->d_name) != 0)
+                       if (only_relfilenode && strcmp(only_relfilenode, fnonly) != 0)
                                /* Relfilenode not to be included */
                                continue;
 
@@ -247,7 +246,7 @@ main(int argc, char *argv[])
                                DataDir = optarg;
                                break;
                        case 'r':
-                               if (atoi(optarg) <= 0)
+                               if (atoi(optarg) == 0)
                                {
                                        fprintf(stderr, _("%s: invalid relfilenode specification, must be numeric: %s\n"), progname, optarg);
                                        exit(1);