From 8f9aba1874eccae860d5a6ced9b2899b2f7895b4 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 27 Feb 2020 15:31:52 +0900 Subject: [PATCH] Skip foreign tablespaces when running pg_checksums/pg_verify_checksums Attempting to use pg_checksums (pg_verify_checksums in 11) on a data folder which includes tablespace paths used across multiple major versions would cause pg_checksums to scan all directories present in pg_tblspc, and not only marked with TABLESPACE_VERSION_DIRECTORY. This could lead to failures when for example running sanity checks on an upgraded instance with --check. Even worse, it was possible to rewrite on-disk pages with --enable for a cluster potentially online. This commit makes pg_checksums skip any directories not named TABLESPACE_VERSION_DIRECTORY, similarly to what is done for base backups. Reported-by: Michael Banck Author: Michael Banck, Bernd Helmle Discussion: https://postgr.es/m/62031974fd8e941dd8351fbc8c7eff60d59c5338.camel@credativ.de backpatch-through: 11 --- .../pg_verify_checksums/pg_verify_checksums.c | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/bin/pg_verify_checksums/pg_verify_checksums.c b/src/bin/pg_verify_checksums/pg_verify_checksums.c index a33ac6924f8..ba11e8ddf46 100644 --- a/src/bin/pg_verify_checksums/pg_verify_checksums.c +++ b/src/bin/pg_verify_checksums/pg_verify_checksums.c @@ -15,6 +15,7 @@ #include "catalog/pg_control.h" #include "common/controldata_utils.h" +#include "common/relpath.h" #include "getopt_long.h" #include "pg_getopt.h" #include "storage/bufpage.h" @@ -238,7 +239,51 @@ scan_directory(const char *basedir, const char *subdir) #else else if (S_ISDIR(st.st_mode) || pgwin32_is_junction(fn)) #endif - scan_directory(path, de->d_name); + { + /* + * If going through the entries of pg_tblspc, we assume to operate + * on tablespace locations where only TABLESPACE_VERSION_DIRECTORY + * is valid, resolving the linked locations and dive into them + * directly. + */ + if (strncmp("pg_tblspc", subdir, strlen("pg_tblspc")) == 0) + { + char tblspc_path[MAXPGPATH]; + struct stat tblspc_st; + + /* + * Resolve tablespace location path and check whether + * TABLESPACE_VERSION_DIRECTORY exists. Not finding a valid + * location is unexpected, since there should be no orphaned + * links and no links pointing to something else than a + * directory. + */ + snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s/%s", + path, de->d_name, TABLESPACE_VERSION_DIRECTORY); + + if (lstat(tblspc_path, &tblspc_st) < 0) + { + fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"), + progname, tblspc_path, strerror(errno)); + exit(1); + } + + /* + * Move backwards once as the scan needs to happen for the + * contents of TABLESPACE_VERSION_DIRECTORY. + */ + snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s", + path, de->d_name); + + /* Looks like a valid tablespace location */ + scan_directory(tblspc_path, + TABLESPACE_VERSION_DIRECTORY); + } + else + { + scan_directory(path, de->d_name); + } + } } closedir(dir); } -- 2.39.5