0001-Formerly-pg_checksums-recursively-dived-into-pg_tbls.patch

text/x-patch

Filename: 0001-Formerly-pg_checksums-recursively-dived-into-pg_tbls.patch
Type: text/x-patch
Part: 0
Message: Re: [Patch] Make pg_checksums skip foreign tablespace directories

Patch

Format: format-patch
Series: patch 0001
Subject: Formerly pg_checksums recursively dived into pg_tblspc, scanning any tablespace location found there without taking into account, that tablespace locations might be used by other PostgreSQL instances at the same time. This could likely happen for example by using pg_upgrade to upgrade clusters with tablespaces.
File+
src/bin/pg_checksums/pg_checksums.c 42 1
From 15bd3a6457f59f3ba4bf72c645499132e90127cd Mon Sep 17 00:00:00 2001
From: Bernd Helmle <mailings@oopsware.de>
Date: Wed, 26 Feb 2020 16:49:03 +0100
Subject: [PATCH 1/2] Formerly pg_checksums recursively dived into pg_tblspc,
 scanning any tablespace location found there without taking into account,
 that tablespace locations might be used by other PostgreSQL instances at the
 same time. This could likely happen for example by using pg_upgrade to
 upgrade clusters with tablespaces.

Fix this by resolving tablespace locations explicitly by looking
up their TABLESPACE_VERSION_DIRECTORY subdirectory if called on
the pg_tblspc directory, and, if found, recursively diving into
them directly. If we can't resolve the tablespace location link, we
throw an error to indicate a probably orphaned or missing tablespace
location.
---
 src/bin/pg_checksums/pg_checksums.c | 43 ++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
index 9bd0bf947f..1367f53bbf 100644
--- a/src/bin/pg_checksums/pg_checksums.c
+++ b/src/bin/pg_checksums/pg_checksums.c
@@ -385,7 +385,48 @@ scan_directory(const char *basedir, const char *subdir, bool sizeonly)
 #else
 		else if (S_ISDIR(st.st_mode) || pgwin32_is_junction(fn))
 #endif
-			dirsize += scan_directory(path, de->d_name, sizeonly);
+		{
+			/*
+			 * If we are called with subdir pg_tblspc, we assume to
+			 * operate on tablespace locations. We're just interested
+			 * in TABLESPACE_VERSION_DIRECTORY only, so we're resolving
+			 * the linked locations here explicitely 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 a TABLESPACE_VERSION_DIRECTORY exists. Not finding
+				 * a valid location is an unexpected condition, since there
+				 * shouldn't be orphaned links. Tell the user something
+				 * is wrong.
+				 */
+				snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s/%s",
+						 path, de->d_name, TABLESPACE_VERSION_DIRECTORY);
+
+				if (lstat(tblspc_path, &tblspc_st) < 0)
+				{
+					pg_log_error("invalid tablespace location \"%s/%s\"",
+								 subdir, de->d_name);
+					exit(1);
+				}
+
+				snprintf(tblspc_path, sizeof(tblspc_path), "%s/%s",
+						 path, de->d_name);
+
+				/* Looks like a valid tablespace location */
+				dirsize += scan_directory(tblspc_path, TABLESPACE_VERSION_DIRECTORY,
+										  sizeonly);
+			}
+			else
+			{
+				dirsize += scan_directory(path, de->d_name, sizeonly);
+			}
+		}
 	}
 	closedir(dir);
 	return dirsize;
-- 
2.24.1