From 17f15239325a88581bb4f9cf91d38005f1f52d69 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Sat, 16 Feb 2013 18:52:50 -0500
Subject: [PATCH] Warn about initdb using mount-points

Add code to detect and warn about trying to initdb or create pg_xlog on
mount points.
---
 src/bin/initdb/initdb.c               | 51 +++++++++++++++++++++------
 src/bin/pg_basebackup/pg_basebackup.c |  2 ++
 src/port/pgcheckdir.c                 | 20 +++++++++--
 3 files changed, 60 insertions(+), 13 deletions(-)

diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 2ea3f6ed02b..b8faf9cba6a 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -257,6 +257,7 @@ void setup_signals(void);
 void setup_text_search(void);
 void create_data_directory(void);
 void create_xlog_symlink(void);
+void warn_on_mount_point(int error);
 void initialize_data_directory(void);
 
 
@@ -3144,7 +3145,9 @@ setup_signals(void)
 void
 create_data_directory(void)
 {
-	switch (pg_check_dir(pg_data))
+	int ret;
+
+	switch ((ret = pg_check_dir(pg_data)))
 	{
 		case 0:
 			/* PGDATA not there, must create it */
@@ -3179,15 +3182,20 @@ create_data_directory(void)
 			break;
 
 		case 2:
+		case 3:
+		case 4:
 			/* Present and not empty */
 			fprintf(stderr,
 					_("%s: directory \"%s\" exists but is not empty\n"),
 					progname, pg_data);
-			fprintf(stderr,
-					_("If you want to create a new database system, either remove or empty\n"
-					  "the directory \"%s\" or run %s\n"
-					  "with an argument other than \"%s\".\n"),
-					pg_data, progname, pg_data);
+			if (ret != 4)
+				warn_on_mount_point(ret);
+			else
+				fprintf(stderr,
+						_("If you want to create a new database system, either remove or empty\n"
+						  "the directory \"%s\" or run %s\n"
+						  "with an argument other than \"%s\".\n"),
+						pg_data, progname, pg_data);
 			exit(1);			/* no further message needed */
 
 		default:
@@ -3206,6 +3214,7 @@ create_xlog_symlink(void)
 	if (strcmp(xlog_dir, "") != 0)
 	{
 		char	   *linkloc;
+		int			ret;
 
 		/* clean up xlog directory name, check it's absolute */
 		canonicalize_path(xlog_dir);
@@ -3216,7 +3225,7 @@ create_xlog_symlink(void)
 		}
 
 		/* check if the specified xlog directory exists/is empty */
-		switch (pg_check_dir(xlog_dir))
+		switch ((ret = pg_check_dir(xlog_dir)))
 		{
 			case 0:
 				/* xlog directory not there, must create it */
@@ -3255,14 +3264,19 @@ create_xlog_symlink(void)
 				break;
 
 			case 2:
+			case 3:
+			case 4:
 				/* Present and not empty */
 				fprintf(stderr,
 						_("%s: directory \"%s\" exists but is not empty\n"),
 						progname, xlog_dir);
-				fprintf(stderr,
-				 _("If you want to store the transaction log there, either\n"
-				   "remove or empty the directory \"%s\".\n"),
-						xlog_dir);
+				if (ret != 4)
+					warn_on_mount_point(ret);
+				else
+					fprintf(stderr,
+					 _("If you want to store the transaction log there, either\n"
+					   "remove or empty the directory \"%s\".\n"),
+							xlog_dir);
 				exit_nicely();
 
 			default:
@@ -3291,6 +3305,21 @@ create_xlog_symlink(void)
 }
 
 
+void
+warn_on_mount_point(int error)
+{
+	if (error == 2)
+		fprintf(stderr,
+				_("It contains a dot-prefixed/invisible file, perhaps due to it being a mount point.\n"));
+	else if (error == 3)
+		fprintf(stderr,
+				_("It contains a lost+found directory, perhaps due to it being a mount point.\n"));
+
+	fprintf(stderr,
+			_("Using the top-level directory of a mount point is not recommended.\n"));
+}
+
+
 void
 initialize_data_directory(void)
 {
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index b6f774469b1..fb5a1bd1c19 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -371,6 +371,8 @@ verify_dir_is_empty_or_create(char *dirname)
 			 */
 			return;
 		case 2:
+		case 3:
+		case 4:
 
 			/*
 			 * Exists, not empty
diff --git a/src/port/pgcheckdir.c b/src/port/pgcheckdir.c
index 3b8258c0353..aee59975afc 100644
--- a/src/port/pgcheckdir.c
+++ b/src/port/pgcheckdir.c
@@ -31,6 +31,7 @@ pg_check_dir(const char *dir)
 	int			result = 1;
 	DIR		   *chkdir;
 	struct dirent *file;
+	bool		dot_found = false;
 
 	errno = 0;
 
@@ -47,15 +48,26 @@ pg_check_dir(const char *dir)
 			/* skip this and parent directory */
 			continue;
 		}
+#ifndef WIN32
+		/* file starts with "." */
+		else if (file->d_name[0] == '.')
+		{
+			dot_found = true;
+		}
+		else if (strcmp("lost+found", file->d_name) == 0)
+		{
+			result = 3;			/* not empty, mount point */
+			break;
+		}
+#endif
 		else
 		{
-			result = 2;			/* not empty */
+			result = 4;			/* not empty */
 			break;
 		}
 	}
 
 #ifdef WIN32
-
 	/*
 	 * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
 	 * released version
@@ -69,5 +81,9 @@ pg_check_dir(const char *dir)
 	if (errno != 0)
 		result = -1;			/* some kind of I/O error? */
 
+	/* We report on dot-files if we _only_ find dot files */
+	if (result == 1 && dot_found)
+		result = 2;
+
 	return result;
 }
-- 
GitLab