LCOV - code coverage report
Current view: top level - src/bin/pg_checksums - pg_checksums.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 174 239 72.8 %
Date: 2019-11-15 23:07:02 Functions: 5 6 83.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_checksums.c
       4             :  *    Checks, enables or disables page level checksums for an offline
       5             :  *    cluster
       6             :  *
       7             :  * Copyright (c) 2010-2019, PostgreSQL Global Development Group
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/bin/pg_checksums/pg_checksums.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : 
      15             : #include "postgres_fe.h"
      16             : 
      17             : #include <dirent.h>
      18             : #include <time.h>
      19             : #include <sys/stat.h>
      20             : #include <unistd.h>
      21             : 
      22             : #include "access/xlog_internal.h"
      23             : #include "common/controldata_utils.h"
      24             : #include "common/file_perm.h"
      25             : #include "common/file_utils.h"
      26             : #include "common/logging.h"
      27             : #include "getopt_long.h"
      28             : #include "pg_getopt.h"
      29             : #include "storage/bufpage.h"
      30             : #include "storage/checksum.h"
      31             : #include "storage/checksum_impl.h"
      32             : 
      33             : 
      34             : static int64 files = 0;
      35             : static int64 blocks = 0;
      36             : static int64 badblocks = 0;
      37             : static ControlFileData *ControlFile;
      38             : 
      39             : static char *only_filenode = NULL;
      40             : static bool do_sync = true;
      41             : static bool verbose = false;
      42             : static bool showprogress = false;
      43             : 
      44             : typedef enum
      45             : {
      46             :     PG_MODE_CHECK,
      47             :     PG_MODE_DISABLE,
      48             :     PG_MODE_ENABLE
      49             : } PgChecksumMode;
      50             : 
      51             : /*
      52             :  * Filename components.
      53             :  *
      54             :  * XXX: fd.h is not declared here as frontend side code is not able to
      55             :  * interact with the backend-side definitions for the various fsync
      56             :  * wrappers.
      57             :  */
      58             : #define PG_TEMP_FILES_DIR "pgsql_tmp"
      59             : #define PG_TEMP_FILE_PREFIX "pgsql_tmp"
      60             : 
      61             : static PgChecksumMode mode = PG_MODE_CHECK;
      62             : 
      63             : static const char *progname;
      64             : 
      65             : /*
      66             :  * Progress status information.
      67             :  */
      68             : int64       total_size = 0;
      69             : int64       current_size = 0;
      70             : static pg_time_t last_progress_report = 0;
      71             : 
      72             : static void
      73           2 : usage(void)
      74             : {
      75           2 :     printf(_("%s enables, disables, or verifies data checksums in a PostgreSQL database cluster.\n\n"), progname);
      76           2 :     printf(_("Usage:\n"));
      77           2 :     printf(_("  %s [OPTION]... [DATADIR]\n"), progname);
      78           2 :     printf(_("\nOptions:\n"));
      79           2 :     printf(_(" [-D, --pgdata=]DATADIR    data directory\n"));
      80           2 :     printf(_("  -c, --check              check data checksums (default)\n"));
      81           2 :     printf(_("  -d, --disable            disable data checksums\n"));
      82           2 :     printf(_("  -e, --enable             enable data checksums\n"));
      83           2 :     printf(_("  -f, --filenode=FILENODE  check only relation with specified filenode\n"));
      84           2 :     printf(_("  -N, --no-sync            do not wait for changes to be written safely to disk\n"));
      85           2 :     printf(_("  -P, --progress           show progress information\n"));
      86           2 :     printf(_("  -v, --verbose            output verbose messages\n"));
      87           2 :     printf(_("  -V, --version            output version information, then exit\n"));
      88           2 :     printf(_("  -?, --help               show this help, then exit\n"));
      89           2 :     printf(_("\nIf no data directory (DATADIR) is specified, "
      90             :              "the environment variable PGDATA\nis used.\n\n"));
      91           2 :     printf(_("Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
      92           2 : }
      93             : 
      94             : /*
      95             :  * List of files excluded from checksum validation.
      96             :  *
      97             :  * Note: this list should be kept in sync with what basebackup.c includes.
      98             :  */
      99             : static const char *const skip[] = {
     100             :     "pg_control",
     101             :     "pg_filenode.map",
     102             :     "pg_internal.init",
     103             :     "PG_VERSION",
     104             : #ifdef EXEC_BACKEND
     105             :     "config_exec_params",
     106             :     "config_exec_params.new",
     107             : #endif
     108             :     NULL,
     109             : };
     110             : 
     111             : /*
     112             :  * Report current progress status.  Parts borrowed from
     113             :  * src/bin/pg_basebackup/pg_basebackup.c.
     114             :  */
     115             : static void
     116           0 : progress_report(bool force)
     117             : {
     118             :     int         percent;
     119             :     char        total_size_str[32];
     120             :     char        current_size_str[32];
     121             :     pg_time_t   now;
     122             : 
     123             :     Assert(showprogress);
     124             : 
     125           0 :     now = time(NULL);
     126           0 :     if (now == last_progress_report && !force)
     127           0 :         return;                 /* Max once per second */
     128             : 
     129             :     /* Save current time */
     130           0 :     last_progress_report = now;
     131             : 
     132             :     /* Adjust total size if current_size is larger */
     133           0 :     if (current_size > total_size)
     134           0 :         total_size = current_size;
     135             : 
     136             :     /* Calculate current percentage of size done */
     137           0 :     percent = total_size ? (int) ((current_size) * 100 / total_size) : 0;
     138             : 
     139             :     /*
     140             :      * Separate step to keep platform-dependent format code out of
     141             :      * translatable strings.  And we only test for INT64_FORMAT availability
     142             :      * in snprintf, not fprintf.
     143             :      */
     144           0 :     snprintf(total_size_str, sizeof(total_size_str), INT64_FORMAT,
     145             :              total_size / (1024 * 1024));
     146           0 :     snprintf(current_size_str, sizeof(current_size_str), INT64_FORMAT,
     147             :              current_size / (1024 * 1024));
     148             : 
     149           0 :     fprintf(stderr, _("%*s/%s MB (%d%%) computed"),
     150           0 :             (int) strlen(current_size_str), current_size_str, total_size_str,
     151             :             percent);
     152             : 
     153             :     /* Stay on the same line if reporting to a terminal */
     154           0 :     fprintf(stderr, isatty(fileno(stderr)) ? "\r" : "\n");
     155             : }
     156             : 
     157             : static bool
     158       23074 : skipfile(const char *fn)
     159             : {
     160             :     const char *const *f;
     161             : 
     162      114814 :     for (f = skip; *f; f++)
     163       91974 :         if (strcmp(*f, fn) == 0)
     164         234 :             return true;
     165             : 
     166       22840 :     return false;
     167             : }
     168             : 
     169             : static void
     170       15400 : scan_file(const char *fn, BlockNumber segmentno)
     171             : {
     172             :     PGAlignedBlock buf;
     173       15400 :     PageHeader  header = (PageHeader) buf.data;
     174             :     int         f;
     175             :     BlockNumber blockno;
     176             :     int         flags;
     177             : 
     178             :     Assert(mode == PG_MODE_ENABLE ||
     179             :            mode == PG_MODE_CHECK);
     180             : 
     181       15400 :     flags = (mode == PG_MODE_ENABLE) ? O_RDWR : O_RDONLY;
     182       15400 :     f = open(fn, PG_BINARY | flags, 0);
     183             : 
     184       15400 :     if (f < 0)
     185             :     {
     186           0 :         pg_log_error("could not open file \"%s\": %m", fn);
     187           0 :         exit(1);
     188             :     }
     189             : 
     190       15400 :     files++;
     191             : 
     192       61726 :     for (blockno = 0;; blockno++)
     193       46326 :     {
     194             :         uint16      csum;
     195       61726 :         int         r = read(f, buf.data, BLCKSZ);
     196             : 
     197       61726 :         if (r == 0)
     198       15384 :             break;
     199       46342 :         if (r != BLCKSZ)
     200             :         {
     201          16 :             if (r < 0)
     202           0 :                 pg_log_error("could not read block %u in file \"%s\": %m",
     203             :                              blockno, fn);
     204             :             else
     205          16 :                 pg_log_error("could not read block %u in file \"%s\": read %d of %d",
     206             :                              blockno, fn, r, BLCKSZ);
     207          16 :             exit(1);
     208             :         }
     209       46326 :         blocks++;
     210             : 
     211             :         /* New pages have no checksum yet */
     212       46326 :         if (PageIsNew(header))
     213           0 :             continue;
     214             : 
     215       46326 :         csum = pg_checksum_page(buf.data, blockno + segmentno * RELSEG_SIZE);
     216       46326 :         current_size += r;
     217       46326 :         if (mode == PG_MODE_CHECK)
     218             :         {
     219       35014 :             if (csum != header->pd_checksum)
     220             :             {
     221           8 :                 if (ControlFile->data_checksum_version == PG_DATA_CHECKSUM_VERSION)
     222           8 :                     pg_log_error("checksum verification failed in file \"%s\", block %u: calculated checksum %X but block contains %X",
     223             :                                  fn, blockno, csum, header->pd_checksum);
     224           8 :                 badblocks++;
     225             :             }
     226             :         }
     227       11312 :         else if (mode == PG_MODE_ENABLE)
     228             :         {
     229             :             int     w;
     230             : 
     231             :             /* Set checksum in page header */
     232       11312 :             header->pd_checksum = csum;
     233             : 
     234             :             /* Seek back to beginning of block */
     235       11312 :             if (lseek(f, -BLCKSZ, SEEK_CUR) < 0)
     236             :             {
     237           0 :                 pg_log_error("seek failed for block %u in file \"%s\": %m", blockno, fn);
     238           0 :                 exit(1);
     239             :             }
     240             : 
     241             :             /* Write block with checksum */
     242       11312 :             w = write(f, buf.data, BLCKSZ);
     243       11312 :             if (w != BLCKSZ)
     244             :             {
     245           0 :                 if (w < 0)
     246           0 :                     pg_log_error("could not write block %u in file \"%s\": %m",
     247             :                                  blockno, fn);
     248             :                 else
     249           0 :                     pg_log_error("could not write block %u in file \"%s\": wrote %d of %d",
     250             :                                  blockno, fn, w, BLCKSZ);
     251           0 :                 exit(1);
     252             :             }
     253             :         }
     254             : 
     255       46326 :         if (showprogress)
     256           0 :             progress_report(false);
     257             :     }
     258             : 
     259       15384 :     if (verbose)
     260             :     {
     261           0 :         if (mode == PG_MODE_CHECK)
     262           0 :             pg_log_info("checksums verified in file \"%s\"", fn);
     263           0 :         if (mode == PG_MODE_ENABLE)
     264           0 :             pg_log_info("checksums enabled in file \"%s\"", fn);
     265             :     }
     266             : 
     267       15384 :     close(f);
     268       15384 : }
     269             : 
     270             : /*
     271             :  * Scan the given directory for items which can be checksummed and
     272             :  * operate on each one of them.  If "sizeonly" is true, the size of
     273             :  * all the items which have checksums is computed and returned back
     274             :  * to the caller without operating on the files.  This is used to compile
     275             :  * the total size of the data directory for progress reports.
     276             :  */
     277             : static int64
     278         184 : scan_directory(const char *basedir, const char *subdir, bool sizeonly)
     279             : {
     280         184 :     int64       dirsize = 0;
     281             :     char        path[MAXPGPATH];
     282             :     DIR        *dir;
     283             :     struct dirent *de;
     284             : 
     285         184 :     snprintf(path, sizeof(path), "%s/%s", basedir, subdir);
     286         184 :     dir = opendir(path);
     287         184 :     if (!dir)
     288             :     {
     289           0 :         pg_log_error("could not open directory \"%s\": %m", path);
     290           0 :         exit(1);
     291             :     }
     292       23928 :     while ((de = readdir(dir)) != NULL)
     293             :     {
     294             :         char        fn[MAXPGPATH];
     295             :         struct stat st;
     296             : 
     297       46978 :         if (strcmp(de->d_name, ".") == 0 ||
     298       23402 :             strcmp(de->d_name, "..") == 0)
     299        8428 :             continue;
     300             : 
     301             :         /* Skip temporary files */
     302       23228 :         if (strncmp(de->d_name,
     303             :                     PG_TEMP_FILE_PREFIX,
     304             :                     strlen(PG_TEMP_FILE_PREFIX)) == 0)
     305          58 :             continue;
     306             : 
     307             :         /* Skip temporary folders */
     308       23170 :         if (strncmp(de->d_name,
     309             :                     PG_TEMP_FILES_DIR,
     310             :                     strlen(PG_TEMP_FILES_DIR)) == 0)
     311           0 :             continue;
     312             : 
     313       23170 :         snprintf(fn, sizeof(fn), "%s/%s", path, de->d_name);
     314       23170 :         if (lstat(fn, &st) < 0)
     315             :         {
     316           0 :             pg_log_error("could not stat file \"%s\": %m", fn);
     317           0 :             exit(1);
     318             :         }
     319       23170 :         if (S_ISREG(st.st_mode))
     320             :         {
     321             :             char        fnonly[MAXPGPATH];
     322             :             char       *forkpath,
     323             :                        *segmentpath;
     324       23074 :             BlockNumber segmentno = 0;
     325             : 
     326       23074 :             if (skipfile(de->d_name))
     327        7908 :                 continue;
     328             : 
     329             :             /*
     330             :              * Cut off at the segment boundary (".") to get the segment number
     331             :              * in order to mix it into the checksum. Then also cut off at the
     332             :              * fork boundary, to get the filenode the file belongs to for
     333             :              * filtering.
     334             :              */
     335       22840 :             strlcpy(fnonly, de->d_name, sizeof(fnonly));
     336       22840 :             segmentpath = strchr(fnonly, '.');
     337       22840 :             if (segmentpath != NULL)
     338             :             {
     339         134 :                 *segmentpath++ = '\0';
     340         134 :                 segmentno = atoi(segmentpath);
     341         134 :                 if (segmentno == 0)
     342             :                 {
     343           0 :                     pg_log_error("invalid segment number %d in file name \"%s\"",
     344             :                                  segmentno, fn);
     345           0 :                     exit(1);
     346             :                 }
     347             :             }
     348             : 
     349       22840 :             forkpath = strchr(fnonly, '_');
     350       22840 :             if (forkpath != NULL)
     351        5806 :                 *forkpath++ = '\0';
     352             : 
     353       22840 :             if (only_filenode && strcmp(only_filenode, fnonly) != 0)
     354             :                 /* filenode not to be included */
     355        7440 :                 continue;
     356             : 
     357       15400 :             dirsize += st.st_size;
     358             : 
     359             :             /*
     360             :              * No need to work on the file when calculating only the size of
     361             :              * the items in the data folder.
     362             :              */
     363       15400 :             if (!sizeonly)
     364       15400 :                 scan_file(fn, segmentno);
     365             :         }
     366             : #ifndef WIN32
     367          96 :         else if (S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
     368             : #else
     369             :         else if (S_ISDIR(st.st_mode) || pgwin32_is_junction(fn))
     370             : #endif
     371          96 :             dirsize += scan_directory(path, de->d_name, sizeonly);
     372             :     }
     373         168 :     closedir(dir);
     374         168 :     return dirsize;
     375             : }
     376             : 
     377             : int
     378          60 : main(int argc, char *argv[])
     379             : {
     380             :     static struct option long_options[] = {
     381             :         {"check", no_argument, NULL, 'c'},
     382             :         {"pgdata", required_argument, NULL, 'D'},
     383             :         {"disable", no_argument, NULL, 'd'},
     384             :         {"enable", no_argument, NULL, 'e'},
     385             :         {"filenode", required_argument, NULL, 'f'},
     386             :         {"no-sync", no_argument, NULL, 'N'},
     387             :         {"progress", no_argument, NULL, 'P'},
     388             :         {"verbose", no_argument, NULL, 'v'},
     389             :         {NULL, 0, NULL, 0}
     390             :     };
     391             : 
     392          60 :     char       *DataDir = NULL;
     393             :     int         c;
     394             :     int         option_index;
     395             :     bool        crc_ok;
     396             : 
     397          60 :     pg_logging_init(argv[0]);
     398          60 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_checksums"));
     399          60 :     progname = get_progname(argv[0]);
     400             : 
     401          60 :     if (argc > 1)
     402             :     {
     403          60 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     404             :         {
     405           2 :             usage();
     406           2 :             exit(0);
     407             :         }
     408          58 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     409             :         {
     410           2 :             puts("pg_checksums (PostgreSQL) " PG_VERSION);
     411           2 :             exit(0);
     412             :         }
     413             :     }
     414             : 
     415         236 :     while ((c = getopt_long(argc, argv, "cD:deNPf:v", long_options, &option_index)) != -1)
     416             :     {
     417         126 :         switch (c)
     418             :         {
     419             :             case 'c':
     420          36 :                 mode = PG_MODE_CHECK;
     421          36 :                 break;
     422             :             case 'd':
     423           6 :                 mode = PG_MODE_DISABLE;
     424           6 :                 break;
     425             :             case 'e':
     426           8 :                 mode = PG_MODE_ENABLE;
     427           8 :                 break;
     428             :             case 'f':
     429          12 :                 if (atoi(optarg) == 0)
     430             :                 {
     431           0 :                     pg_log_error("invalid filenode specification, must be numeric: %s", optarg);
     432           0 :                     exit(1);
     433             :                 }
     434          12 :                 only_filenode = pstrdup(optarg);
     435          12 :                 break;
     436             :             case 'N':
     437           8 :                 do_sync = false;
     438           8 :                 break;
     439             :             case 'v':
     440           0 :                 verbose = true;
     441           0 :                 break;
     442             :             case 'D':
     443          54 :                 DataDir = optarg;
     444          54 :                 break;
     445             :             case 'P':
     446           0 :                 showprogress = true;
     447           0 :                 break;
     448             :             default:
     449           2 :                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     450           2 :                 exit(1);
     451             :         }
     452             :     }
     453             : 
     454          54 :     if (DataDir == NULL)
     455             :     {
     456           0 :         if (optind < argc)
     457           0 :             DataDir = argv[optind++];
     458             :         else
     459           0 :             DataDir = getenv("PGDATA");
     460             : 
     461             :         /* If no DataDir was specified, and none could be found, error out */
     462           0 :         if (DataDir == NULL)
     463             :         {
     464           0 :             pg_log_error("no data directory specified");
     465           0 :             fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
     466           0 :             exit(1);
     467             :         }
     468             :     }
     469             : 
     470             :     /* Complain if any arguments remain */
     471          54 :     if (optind < argc)
     472             :     {
     473           0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
     474             :                      argv[optind]);
     475           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
     476             :                 progname);
     477           0 :         exit(1);
     478             :     }
     479             : 
     480             :     /* filenode checking only works in --check mode */
     481          54 :     if (mode != PG_MODE_CHECK && only_filenode)
     482             :     {
     483           4 :         pg_log_error("option -f/--filenode can only be used with --check");
     484           4 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
     485             :                 progname);
     486           4 :         exit(1);
     487             :     }
     488             : 
     489             :     /* Read the control file and check compatibility */
     490          50 :     ControlFile = get_controlfile(DataDir, &crc_ok);
     491          50 :     if (!crc_ok)
     492             :     {
     493           0 :         pg_log_error("pg_control CRC value is incorrect");
     494           0 :         exit(1);
     495             :     }
     496             : 
     497          50 :     if (ControlFile->pg_control_version != PG_CONTROL_VERSION)
     498             :     {
     499           0 :         pg_log_error("cluster is not compatible with this version of pg_checksums");
     500           0 :         exit(1);
     501             :     }
     502             : 
     503          50 :     if (ControlFile->blcksz != BLCKSZ)
     504             :     {
     505           0 :         pg_log_error("database cluster is not compatible");
     506           0 :         fprintf(stderr, _("The database cluster was initialized with block size %u, but pg_checksums was compiled with block size %u.\n"),
     507           0 :                 ControlFile->blcksz, BLCKSZ);
     508           0 :         exit(1);
     509             :     }
     510             : 
     511             :     /*
     512             :      * Check if cluster is running.  A clean shutdown is required to avoid
     513             :      * random checksum failures caused by torn pages.  Note that this doesn't
     514             :      * guard against someone starting the cluster concurrently.
     515             :      */
     516          52 :     if (ControlFile->state != DB_SHUTDOWNED &&
     517           2 :         ControlFile->state != DB_SHUTDOWNED_IN_RECOVERY)
     518             :     {
     519           2 :         pg_log_error("cluster must be shut down");
     520           2 :         exit(1);
     521             :     }
     522             : 
     523          56 :     if (ControlFile->data_checksum_version == 0 &&
     524           8 :         mode == PG_MODE_CHECK)
     525             :     {
     526           2 :         pg_log_error("data checksums are not enabled in cluster");
     527           2 :         exit(1);
     528             :     }
     529             : 
     530          52 :     if (ControlFile->data_checksum_version == 0 &&
     531           6 :         mode == PG_MODE_DISABLE)
     532             :     {
     533           2 :         pg_log_error("data checksums are already disabled in cluster");
     534           2 :         exit(1);
     535             :     }
     536             : 
     537          84 :     if (ControlFile->data_checksum_version > 0 &&
     538          40 :         mode == PG_MODE_ENABLE)
     539             :     {
     540           2 :         pg_log_error("data checksums are already enabled in cluster");
     541           2 :         exit(1);
     542             :     }
     543             : 
     544             :     /* Operate on all files if checking or enabling checksums */
     545          42 :     if (mode == PG_MODE_CHECK || mode == PG_MODE_ENABLE)
     546             :     {
     547             :         /*
     548             :          * If progress status information is requested, we need to scan the
     549             :          * directory tree twice: once to know how much total data needs to be
     550             :          * processed and once to do the real work.
     551             :          */
     552          40 :         if (showprogress)
     553             :         {
     554           0 :             total_size = scan_directory(DataDir, "global", true);
     555           0 :             total_size += scan_directory(DataDir, "base", true);
     556           0 :             total_size += scan_directory(DataDir, "pg_tblspc", true);
     557             :         }
     558             : 
     559          40 :         (void) scan_directory(DataDir, "global", false);
     560          24 :         (void) scan_directory(DataDir, "base", false);
     561          24 :         (void) scan_directory(DataDir, "pg_tblspc", false);
     562             : 
     563          24 :         if (showprogress)
     564             :         {
     565           0 :             progress_report(true);
     566           0 :             fprintf(stderr, "\n");    /* Need to move to next line */
     567             :         }
     568             : 
     569          24 :         printf(_("Checksum operation completed\n"));
     570          24 :         printf(_("Files scanned:  %s\n"), psprintf(INT64_FORMAT, files));
     571          24 :         printf(_("Blocks scanned: %s\n"), psprintf(INT64_FORMAT, blocks));
     572          24 :         if (mode == PG_MODE_CHECK)
     573             :         {
     574          20 :             printf(_("Bad checksums:  %s\n"), psprintf(INT64_FORMAT, badblocks));
     575          20 :             printf(_("Data checksum version: %d\n"), ControlFile->data_checksum_version);
     576             : 
     577          20 :             if (badblocks > 0)
     578           8 :                 exit(1);
     579             :         }
     580             :     }
     581             : 
     582             :     /*
     583             :      * Finally make the data durable on disk if enabling or disabling
     584             :      * checksums.  Flush first the data directory for safety, and then update
     585             :      * the control file to keep the switch consistent.
     586             :      */
     587          18 :     if (mode == PG_MODE_ENABLE || mode == PG_MODE_DISABLE)
     588             :     {
     589          12 :         ControlFile->data_checksum_version =
     590           6 :             (mode == PG_MODE_ENABLE) ? PG_DATA_CHECKSUM_VERSION : 0;
     591             : 
     592           6 :         if (do_sync)
     593             :         {
     594           2 :             pg_log_info("syncing data directory");
     595           2 :             fsync_pgdata(DataDir, PG_VERSION_NUM);
     596             :         }
     597             : 
     598           6 :         pg_log_info("updating control file");
     599           6 :         update_controlfile(DataDir, ControlFile, do_sync);
     600             : 
     601           6 :         if (verbose)
     602           0 :             printf(_("Data checksum version: %d\n"), ControlFile->data_checksum_version);
     603           6 :         if (mode == PG_MODE_ENABLE)
     604           4 :             printf(_("Checksums enabled in cluster\n"));
     605             :         else
     606           2 :             printf(_("Checksums disabled in cluster\n"));
     607             :     }
     608             : 
     609          18 :     return 0;
     610             : }

Generated by: LCOV version 1.13