PostgreSQL Source Code  git master
pg_checksums.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_checksums.c
4  * Checks, enables or disables page level checksums for an offline
5  * cluster
6  *
7  * Copyright (c) 2010-2021, 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 <limits.h>
19 #include <time.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 
23 #include "access/xlog_internal.h"
25 #include "common/file_perm.h"
26 #include "common/file_utils.h"
27 #include "common/logging.h"
28 #include "fe_utils/option_utils.h"
29 #include "getopt_long.h"
30 #include "pg_getopt.h"
31 #include "storage/bufpage.h"
32 #include "storage/checksum.h"
33 #include "storage/checksum_impl.h"
34 
35 
36 static int64 files_scanned = 0;
37 static int64 files_written = 0;
38 static int64 blocks_scanned = 0;
39 static int64 blocks_written = 0;
40 static int64 badblocks = 0;
42 
43 static char *only_filenode = NULL;
44 static bool do_sync = true;
45 static bool verbose = false;
46 static bool showprogress = false;
47 
48 typedef enum
49 {
54 
55 /*
56  * Filename components.
57  *
58  * XXX: fd.h is not declared here as frontend side code is not able to
59  * interact with the backend-side definitions for the various fsync
60  * wrappers.
61  */
62 #define PG_TEMP_FILES_DIR "pgsql_tmp"
63 #define PG_TEMP_FILE_PREFIX "pgsql_tmp"
64 
66 
67 static const char *progname;
68 
69 /*
70  * Progress status information.
71  */
72 int64 total_size = 0;
73 int64 current_size = 0;
75 
76 static void
77 usage(void)
78 {
79  printf(_("%s enables, disables, or verifies data checksums in a PostgreSQL database cluster.\n\n"), progname);
80  printf(_("Usage:\n"));
81  printf(_(" %s [OPTION]... [DATADIR]\n"), progname);
82  printf(_("\nOptions:\n"));
83  printf(_(" [-D, --pgdata=]DATADIR data directory\n"));
84  printf(_(" -c, --check check data checksums (default)\n"));
85  printf(_(" -d, --disable disable data checksums\n"));
86  printf(_(" -e, --enable enable data checksums\n"));
87  printf(_(" -f, --filenode=FILENODE check only relation with specified filenode\n"));
88  printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n"));
89  printf(_(" -P, --progress show progress information\n"));
90  printf(_(" -v, --verbose output verbose messages\n"));
91  printf(_(" -V, --version output version information, then exit\n"));
92  printf(_(" -?, --help show this help, then exit\n"));
93  printf(_("\nIf no data directory (DATADIR) is specified, "
94  "the environment variable PGDATA\nis used.\n\n"));
95  printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
96  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
97 }
98 
99 /*
100  * Definition of one element part of an exclusion list, used for files
101  * to exclude from checksum validation. "name" is the name of the file
102  * or path to check for exclusion. If "match_prefix" is true, any items
103  * matching the name as prefix are excluded.
104  */
105 struct exclude_list_item
106 {
107  const char *name;
108  bool match_prefix;
109 };
110 
111 /*
112  * List of files excluded from checksum validation.
113  *
114  * Note: this list should be kept in sync with what basebackup.c includes.
115  */
116 static const struct exclude_list_item skip[] = {
117  {"pg_control", false},
118  {"pg_filenode.map", false},
119  {"pg_internal.init", true},
120  {"PG_VERSION", false},
121 #ifdef EXEC_BACKEND
122  {"config_exec_params", true},
123 #endif
124  {NULL, false}
125 };
126 
127 /*
128  * Report current progress status. Parts borrowed from
129  * src/bin/pg_basebackup/pg_basebackup.c.
130  */
131 static void
132 progress_report(bool finished)
133 {
134  int percent;
135  char total_size_str[32];
136  char current_size_str[32];
137  pg_time_t now;
138 
140 
141  now = time(NULL);
142  if (now == last_progress_report && !finished)
143  return; /* Max once per second */
144 
145  /* Save current time */
147 
148  /* Adjust total size if current_size is larger */
149  if (current_size > total_size)
151 
152  /* Calculate current percentage of size done */
153  percent = total_size ? (int) ((current_size) * 100 / total_size) : 0;
154 
155  /*
156  * Separate step to keep platform-dependent format code out of
157  * translatable strings. And we only test for INT64_FORMAT availability
158  * in snprintf, not fprintf.
159  */
160  snprintf(total_size_str, sizeof(total_size_str), INT64_FORMAT,
161  total_size / (1024 * 1024));
162  snprintf(current_size_str, sizeof(current_size_str), INT64_FORMAT,
163  current_size / (1024 * 1024));
164 
165  fprintf(stderr, _("%*s/%s MB (%d%%) computed"),
166  (int) strlen(current_size_str), current_size_str, total_size_str,
167  percent);
168 
169  /*
170  * Stay on the same line if reporting to a terminal and we're not done
171  * yet.
172  */
173  fputc((!finished && isatty(fileno(stderr))) ? '\r' : '\n', stderr);
174 }
175 
176 static bool
177 skipfile(const char *fn)
178 {
179  int excludeIdx;
180 
181  for (excludeIdx = 0; skip[excludeIdx].name != NULL; excludeIdx++)
182  {
183  int cmplen = strlen(skip[excludeIdx].name);
184 
185  if (!skip[excludeIdx].match_prefix)
186  cmplen++;
187  if (strncmp(skip[excludeIdx].name, fn, cmplen) == 0)
188  return true;
189  }
190 
191  return false;
192 }
193 
194 static void
195 scan_file(const char *fn, BlockNumber segmentno)
196 {
199  int f;
200  BlockNumber blockno;
201  int flags;
202  int64 blocks_written_in_file = 0;
203 
205  mode == PG_MODE_CHECK);
206 
207  flags = (mode == PG_MODE_ENABLE) ? O_RDWR : O_RDONLY;
208  f = open(fn, PG_BINARY | flags, 0);
209 
210  if (f < 0)
211  {
212  pg_log_error("could not open file \"%s\": %m", fn);
213  exit(1);
214  }
215 
216  files_scanned++;
217 
218  for (blockno = 0;; blockno++)
219  {
220  uint16 csum;
221  int r = read(f, buf.data, BLCKSZ);
222 
223  if (r == 0)
224  break;
225  if (r != BLCKSZ)
226  {
227  if (r < 0)
228  pg_log_error("could not read block %u in file \"%s\": %m",
229  blockno, fn);
230  else
231  pg_log_error("could not read block %u in file \"%s\": read %d of %d",
232  blockno, fn, r, BLCKSZ);
233  exit(1);
234  }
235  blocks_scanned++;
236 
237  /*
238  * Since the file size is counted as total_size for progress status
239  * information, the sizes of all pages including new ones in the file
240  * should be counted as current_size. Otherwise the progress reporting
241  * calculated using those counters may not reach 100%.
242  */
243  current_size += r;
244 
245  /* New pages have no checksum yet */
246  if (PageIsNew(header))
247  continue;
248 
249  csum = pg_checksum_page(buf.data, blockno + segmentno * RELSEG_SIZE);
250  if (mode == PG_MODE_CHECK)
251  {
252  if (csum != header->pd_checksum)
253  {
255  pg_log_error("checksum verification failed in file \"%s\", block %u: calculated checksum %X but block contains %X",
256  fn, blockno, csum, header->pd_checksum);
257  badblocks++;
258  }
259  }
260  else if (mode == PG_MODE_ENABLE)
261  {
262  int w;
263 
264  /*
265  * Do not rewrite if the checksum is already set to the expected
266  * value.
267  */
268  if (header->pd_checksum == csum)
269  continue;
270 
271  blocks_written_in_file++;
272 
273  /* Set checksum in page header */
274  header->pd_checksum = csum;
275 
276  /* Seek back to beginning of block */
277  if (lseek(f, -BLCKSZ, SEEK_CUR) < 0)
278  {
279  pg_log_error("seek failed for block %u in file \"%s\": %m", blockno, fn);
280  exit(1);
281  }
282 
283  /* Write block with checksum */
284  w = write(f, buf.data, BLCKSZ);
285  if (w != BLCKSZ)
286  {
287  if (w < 0)
288  pg_log_error("could not write block %u in file \"%s\": %m",
289  blockno, fn);
290  else
291  pg_log_error("could not write block %u in file \"%s\": wrote %d of %d",
292  blockno, fn, w, BLCKSZ);
293  exit(1);
294  }
295  }
296 
297  if (showprogress)
298  progress_report(false);
299  }
300 
301  if (verbose)
302  {
303  if (mode == PG_MODE_CHECK)
304  pg_log_info("checksums verified in file \"%s\"", fn);
305  if (mode == PG_MODE_ENABLE)
306  pg_log_info("checksums enabled in file \"%s\"", fn);
307  }
308 
309  /* Update write counters if any write activity has happened */
310  if (blocks_written_in_file > 0)
311  {
312  files_written++;
313  blocks_written += blocks_written_in_file;
314  }
315 
316  close(f);
317 }
318 
319 /*
320  * Scan the given directory for items which can be checksummed and
321  * operate on each one of them. If "sizeonly" is true, the size of
322  * all the items which have checksums is computed and returned back
323  * to the caller without operating on the files. This is used to compile
324  * the total size of the data directory for progress reports.
325  */
326 static int64
327 scan_directory(const char *basedir, const char *subdir, bool sizeonly)
328 {
329  int64 dirsize = 0;
330  char path[MAXPGPATH];
331  DIR *dir;
332  struct dirent *de;
333 
334  snprintf(path, sizeof(path), "%s/%s", basedir, subdir);
335  dir = opendir(path);
336  if (!dir)
337  {
338  pg_log_error("could not open directory \"%s\": %m", path);
339  exit(1);
340  }
341  while ((de = readdir(dir)) != NULL)
342  {
343  char fn[MAXPGPATH];
344  struct stat st;
345 
346  if (strcmp(de->d_name, ".") == 0 ||
347  strcmp(de->d_name, "..") == 0)
348  continue;
349 
350  /* Skip temporary files */
351  if (strncmp(de->d_name,
353  strlen(PG_TEMP_FILE_PREFIX)) == 0)
354  continue;
355 
356  /* Skip temporary folders */
357  if (strncmp(de->d_name,
359  strlen(PG_TEMP_FILES_DIR)) == 0)
360  continue;
361 
362  snprintf(fn, sizeof(fn), "%s/%s", path, de->d_name);
363  if (lstat(fn, &st) < 0)
364  {
365  pg_log_error("could not stat file \"%s\": %m", fn);
366  exit(1);
367  }
368  if (S_ISREG(st.st_mode))
369  {
370  char fnonly[MAXPGPATH];
371  char *forkpath,
372  *segmentpath;
373  BlockNumber segmentno = 0;
374 
375  if (skipfile(de->d_name))
376  continue;
377 
378  /*
379  * Cut off at the segment boundary (".") to get the segment number
380  * in order to mix it into the checksum. Then also cut off at the
381  * fork boundary, to get the filenode the file belongs to for
382  * filtering.
383  */
384  strlcpy(fnonly, de->d_name, sizeof(fnonly));
385  segmentpath = strchr(fnonly, '.');
386  if (segmentpath != NULL)
387  {
388  *segmentpath++ = '\0';
389  segmentno = atoi(segmentpath);
390  if (segmentno == 0)
391  {
392  pg_log_error("invalid segment number %d in file name \"%s\"",
393  segmentno, fn);
394  exit(1);
395  }
396  }
397 
398  forkpath = strchr(fnonly, '_');
399  if (forkpath != NULL)
400  *forkpath++ = '\0';
401 
402  if (only_filenode && strcmp(only_filenode, fnonly) != 0)
403  /* filenode not to be included */
404  continue;
405 
406  dirsize += st.st_size;
407 
408  /*
409  * No need to work on the file when calculating only the size of
410  * the items in the data folder.
411  */
412  if (!sizeonly)
413  scan_file(fn, segmentno);
414  }
415 #ifndef WIN32
416  else if (S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
417 #else
418  else if (S_ISDIR(st.st_mode) || pgwin32_is_junction(fn))
419 #endif
420  {
421  /*
422  * If going through the entries of pg_tblspc, we assume to operate
423  * on tablespace locations where only TABLESPACE_VERSION_DIRECTORY
424  * is valid, resolving the linked locations and dive into them
425  * directly.
426  */
427  if (strncmp("pg_tblspc", subdir, strlen("pg_tblspc")) == 0)
428  {
429  char tblspc_path[MAXPGPATH];
430  struct stat tblspc_st;
431 
432  /*
433  * Resolve tablespace location path and check whether
434  * TABLESPACE_VERSION_DIRECTORY exists. Not finding a valid
435  * location is unexpected, since there should be no orphaned
436  * links and no links pointing to something else than a
437  * directory.
438  */
439  snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s/%s",
441 
442  if (lstat(tblspc_path, &tblspc_st) < 0)
443  {
444  pg_log_error("could not stat file \"%s\": %m",
445  tblspc_path);
446  exit(1);
447  }
448 
449  /*
450  * Move backwards once as the scan needs to happen for the
451  * contents of TABLESPACE_VERSION_DIRECTORY.
452  */
453  snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s",
454  path, de->d_name);
455 
456  /* Looks like a valid tablespace location */
457  dirsize += scan_directory(tblspc_path,
459  sizeonly);
460  }
461  else
462  {
463  dirsize += scan_directory(path, de->d_name, sizeonly);
464  }
465  }
466  }
467  closedir(dir);
468  return dirsize;
469 }
470 
471 int
472 main(int argc, char *argv[])
473 {
474  static struct option long_options[] = {
475  {"check", no_argument, NULL, 'c'},
476  {"pgdata", required_argument, NULL, 'D'},
477  {"disable", no_argument, NULL, 'd'},
478  {"enable", no_argument, NULL, 'e'},
479  {"filenode", required_argument, NULL, 'f'},
480  {"no-sync", no_argument, NULL, 'N'},
481  {"progress", no_argument, NULL, 'P'},
482  {"verbose", no_argument, NULL, 'v'},
483  {NULL, 0, NULL, 0}
484  };
485 
486  char *DataDir = NULL;
487  int c;
488  int option_index;
489  bool crc_ok;
490 
491  pg_logging_init(argv[0]);
492  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_checksums"));
493  progname = get_progname(argv[0]);
494 
495  if (argc > 1)
496  {
497  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
498  {
499  usage();
500  exit(0);
501  }
502  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
503  {
504  puts("pg_checksums (PostgreSQL) " PG_VERSION);
505  exit(0);
506  }
507  }
508 
509  while ((c = getopt_long(argc, argv, "cD:deNPf:v", long_options, &option_index)) != -1)
510  {
511  switch (c)
512  {
513  case 'c':
515  break;
516  case 'd':
518  break;
519  case 'e':
521  break;
522  case 'f':
523  if (!option_parse_int(optarg, "-f/--filenode", 0,
524  INT_MAX,
525  NULL))
526  exit(1);
528  break;
529  case 'N':
530  do_sync = false;
531  break;
532  case 'v':
533  verbose = true;
534  break;
535  case 'D':
536  DataDir = optarg;
537  break;
538  case 'P':
539  showprogress = true;
540  break;
541  default:
542  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
543  exit(1);
544  }
545  }
546 
547  if (DataDir == NULL)
548  {
549  if (optind < argc)
550  DataDir = argv[optind++];
551  else
552  DataDir = getenv("PGDATA");
553 
554  /* If no DataDir was specified, and none could be found, error out */
555  if (DataDir == NULL)
556  {
557  pg_log_error("no data directory specified");
558  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
559  exit(1);
560  }
561  }
562 
563  /* Complain if any arguments remain */
564  if (optind < argc)
565  {
566  pg_log_error("too many command-line arguments (first is \"%s\")",
567  argv[optind]);
568  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
569  progname);
570  exit(1);
571  }
572 
573  /* filenode checking only works in --check mode */
574  if (mode != PG_MODE_CHECK && only_filenode)
575  {
576  pg_log_error("option -f/--filenode can only be used with --check");
577  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
578  progname);
579  exit(1);
580  }
581 
582  /* Read the control file and check compatibility */
583  ControlFile = get_controlfile(DataDir, &crc_ok);
584  if (!crc_ok)
585  {
586  pg_log_error("pg_control CRC value is incorrect");
587  exit(1);
588  }
589 
590  if (ControlFile->pg_control_version != PG_CONTROL_VERSION)
591  {
592  pg_log_error("cluster is not compatible with this version of pg_checksums");
593  exit(1);
594  }
595 
596  if (ControlFile->blcksz != BLCKSZ)
597  {
598  pg_log_error("database cluster is not compatible");
599  fprintf(stderr, _("The database cluster was initialized with block size %u, but pg_checksums was compiled with block size %u.\n"),
600  ControlFile->blcksz, BLCKSZ);
601  exit(1);
602  }
603 
604  /*
605  * Check if cluster is running. A clean shutdown is required to avoid
606  * random checksum failures caused by torn pages. Note that this doesn't
607  * guard against someone starting the cluster concurrently.
608  */
609  if (ControlFile->state != DB_SHUTDOWNED &&
610  ControlFile->state != DB_SHUTDOWNED_IN_RECOVERY)
611  {
612  pg_log_error("cluster must be shut down");
613  exit(1);
614  }
615 
616  if (ControlFile->data_checksum_version == 0 &&
617  mode == PG_MODE_CHECK)
618  {
619  pg_log_error("data checksums are not enabled in cluster");
620  exit(1);
621  }
622 
623  if (ControlFile->data_checksum_version == 0 &&
625  {
626  pg_log_error("data checksums are already disabled in cluster");
627  exit(1);
628  }
629 
630  if (ControlFile->data_checksum_version > 0 &&
631  mode == PG_MODE_ENABLE)
632  {
633  pg_log_error("data checksums are already enabled in cluster");
634  exit(1);
635  }
636 
637  /* Operate on all files if checking or enabling checksums */
638  if (mode == PG_MODE_CHECK || mode == PG_MODE_ENABLE)
639  {
640  /*
641  * If progress status information is requested, we need to scan the
642  * directory tree twice: once to know how much total data needs to be
643  * processed and once to do the real work.
644  */
645  if (showprogress)
646  {
647  total_size = scan_directory(DataDir, "global", true);
648  total_size += scan_directory(DataDir, "base", true);
649  total_size += scan_directory(DataDir, "pg_tblspc", true);
650  }
651 
652  (void) scan_directory(DataDir, "global", false);
653  (void) scan_directory(DataDir, "base", false);
654  (void) scan_directory(DataDir, "pg_tblspc", false);
655 
656  if (showprogress)
657  progress_report(true);
658 
659  printf(_("Checksum operation completed\n"));
660  printf(_("Files scanned: %s\n"), psprintf(INT64_FORMAT, files_scanned));
661  printf(_("Blocks scanned: %s\n"), psprintf(INT64_FORMAT, blocks_scanned));
662  if (mode == PG_MODE_CHECK)
663  {
664  printf(_("Bad checksums: %s\n"), psprintf(INT64_FORMAT, badblocks));
665  printf(_("Data checksum version: %u\n"), ControlFile->data_checksum_version);
666 
667  if (badblocks > 0)
668  exit(1);
669  }
670  else if (mode == PG_MODE_ENABLE)
671  {
672  printf(_("Files written: %s\n"), psprintf(INT64_FORMAT, files_written));
673  printf(_("Blocks written: %s\n"), psprintf(INT64_FORMAT, blocks_written));
674  }
675  }
676 
677  /*
678  * Finally make the data durable on disk if enabling or disabling
679  * checksums. Flush first the data directory for safety, and then update
680  * the control file to keep the switch consistent.
681  */
683  {
684  ControlFile->data_checksum_version =
686 
687  if (do_sync)
688  {
689  pg_log_info("syncing data directory");
690  fsync_pgdata(DataDir, PG_VERSION_NUM);
691  }
692 
693  pg_log_info("updating control file");
694  update_controlfile(DataDir, ControlFile, do_sync);
695 
696  if (verbose)
697  printf(_("Data checksum version: %u\n"), ControlFile->data_checksum_version);
698  if (mode == PG_MODE_ENABLE)
699  printf(_("Checksums enabled in cluster\n"));
700  else
701  printf(_("Checksums disabled in cluster\n"));
702  }
703 
704  return 0;
705 }
static PgChecksumMode mode
Definition: pg_checksums.c:65
int64 pg_time_t
Definition: pgtime.h:23
static const char * progname
Definition: pg_checksums.c:67
bool option_parse_int(const char *optarg, const char *optname, int min_range, int max_range, int *result)
Definition: option_utils.c:50
#define write(a, b, c)
Definition: win32.h:14
const char * get_progname(const char *argv0)
Definition: path.c:453
#define pg_log_error(...)
Definition: logging.h:80
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:57
static void usage(void)
Definition: pg_checksums.c:77
char * pstrdup(const char *in)
Definition: mcxt.c:1299
void pg_logging_init(const char *argv0)
Definition: logging.c:81
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static ControlFileData * ControlFile
Definition: pg_checksums.c:41
static const struct exclude_list_item skip[]
Definition: pg_checksums.c:116
static int64 blocks_scanned
Definition: pg_checksums.c:38
int closedir(DIR *)
Definition: dirent.c:123
#define PG_TEMP_FILES_DIR
Definition: pg_checksums.c:62
#define PG_CONTROL_VERSION
Definition: pg_control.h:25
uint32 pg_control_version
Definition: pg_control.h:123
#define printf(...)
Definition: port.h:223
uint32 BlockNumber
Definition: block.h:31
static bool showprogress
Definition: pg_checksums.c:46
#define fprintf
Definition: port.h:221
Definition: dirent.h:9
PgChecksumMode
Definition: pg_checksums.c:48
#define PG_BINARY
Definition: c.h:1271
static char * basedir
int main(int argc, char *argv[])
Definition: pg_checksums.c:472
uint16 pd_checksum
Definition: bufpage.h:156
char data[BLCKSZ]
Definition: c.h:1141
void update_controlfile(const char *DataDir, ControlFileData *ControlFile, bool do_sync)
#define required_argument
Definition: getopt_long.h:25
unsigned short uint16
Definition: c.h:440
int optind
Definition: getopt.c:50
Definition: dirent.c:25
#define PG_TEMP_FILE_PREFIX
Definition: pg_checksums.c:63
#define MAXPGPATH
DIR * opendir(const char *)
Definition: dirent.c:33
uint32 data_checksum_version
Definition: pg_control.h:222
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:26
char * c
static char * buf
Definition: pg_test_fsync.c:68
static int64 files_written
Definition: pg_checksums.c:37
__int64 st_size
Definition: win32_port.h:273
static bool do_sync
Definition: pg_checksums.c:44
static int64 scan_directory(const char *basedir, const char *subdir, bool sizeonly)
Definition: pg_checksums.c:327
static bool verbose
Definition: pg_checksums.c:45
#define S_ISREG(m)
Definition: win32_port.h:327
static int64 files_scanned
Definition: pg_checksums.c:36
#define no_argument
Definition: getopt_long.h:24
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1215
unsigned short st_mode
Definition: win32_port.h:268
int64 total_size
Definition: pg_checksums.c:72
static void * fn(void *arg)
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
PageHeaderData * PageHeader
Definition: bufpage.h:166
#define Assert(condition)
Definition: c.h:804
static pg_time_t last_progress_report
Definition: pg_checksums.c:74
ControlFileData * get_controlfile(const char *DataDir, bool *crc_ok_p)
static void scan_file(const char *fn, BlockNumber segmentno)
Definition: pg_checksums.c:195
struct dirent * readdir(DIR *)
Definition: dirent.c:78
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:212
#define INT64_FORMAT
Definition: c.h:483
static int64 blocks_written
Definition: pg_checksums.c:39
#define S_ISDIR(m)
Definition: win32_port.h:324
#define lstat(path, sb)
Definition: win32_port.h:284
static void progress_report(bool finished)
Definition: pg_checksums.c:132
static char * only_filenode
Definition: pg_checksums.c:43
const char * name
Definition: basebackup.c:141
static int64 badblocks
Definition: pg_checksums.c:40
#define PG_DATA_CHECKSUM_VERSION
Definition: bufpage.h:200
#define PageIsNew(page)
Definition: bufpage.h:229
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:433
char * optarg
Definition: getopt.c:52
char * DataDir
Definition: globals.c:65
int64 current_size
Definition: pg_checksums.c:73
char d_name[MAX_PATH]
Definition: dirent.h:15
#define close(a)
Definition: win32.h:12
#define snprintf
Definition: port.h:217
#define _(x)
Definition: elog.c:89
uint16 pg_checksum_page(char *page, BlockNumber blkno)
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1544
#define read(a, b, c)
Definition: win32.h:13
static bool skipfile(const char *fn)
Definition: pg_checksums.c:177
#define pg_log_info(...)
Definition: logging.h:88
bool pgwin32_is_junction(const char *path)