From c1275cf74172cd0ed478dbc31e34e2ffffc6e789 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Thu, 17 Apr 2014 11:42:21 -0400
Subject: [PATCH] pg_upgrade:  throw an error for non-existent tablespace
 directories

Non-existent tablespace directory references can occur if user
tablespaces are created inside data directories and the data directory
is renamed in preparation for running pg_upgrade, and the symbolic links
are not updated.

Backpatch to 9.3.
---
 contrib/pg_upgrade/tablespace.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/contrib/pg_upgrade/tablespace.c b/contrib/pg_upgrade/tablespace.c
index 783ee93cfb..94bba087bb 100644
--- a/contrib/pg_upgrade/tablespace.c
+++ b/contrib/pg_upgrade/tablespace.c
@@ -11,6 +11,8 @@
 
 #include "pg_upgrade.h"
 
+#include <sys/types.h>
+
 static void get_tablespace_paths(void);
 static void set_tablespace_directory_suffix(ClusterInfo *cluster);
 
@@ -65,9 +67,39 @@ get_tablespace_paths(void)
 	i_spclocation = PQfnumber(res, "spclocation");
 
 	for (tblnum = 0; tblnum < os_info.num_old_tablespaces; tblnum++)
+	{
+		struct stat statBuf;
+
 		os_info.old_tablespaces[tblnum] = pg_strdup(
 									 PQgetvalue(res, tblnum, i_spclocation));
 
+		/*
+		 * Check that the tablespace path exists and is a directory.
+		 * Effectively, this is checking only for tables/indexes in
+		 * non-existent tablespace directories.  Databases located in
+		 * non-existent tablespaces already throw a backend error.
+		 * Non-existent tablespace directories can occur when a data
+		 * directory that contains user tablespaces is moved as part
+		 * of pg_upgrade preparation and the symbolic links are not
+		 * updated.
+		 */
+		if (stat(os_info.old_tablespaces[tblnum], &statBuf) != 0)
+		{
+			if (errno == ENOENT)
+				report_status(PG_FATAL,
+							  "tablespace directory \"%s\" does not exist\n",
+							  os_info.old_tablespaces[tblnum]);
+			else
+				report_status(PG_FATAL,
+							  "cannot stat() tablespace directory \"%s\": %s\n",
+							  os_info.old_tablespaces[tblnum], getErrorText(errno));
+		}
+		if (!S_ISDIR(statBuf.st_mode))
+				report_status(PG_FATAL,
+							  "tablespace path \"%s\" is not a directory\n",
+							  os_info.old_tablespaces[tblnum]);
+	}
+
 	PQclear(res);
 
 	PQfinish(conn);
-- 
2.40.0