On Tue, Feb  5, 2013 at 08:49:17AM -0500, Peter Eisentraut wrote:
> On 2/5/13 7:32 AM, Kevin Grittner wrote:
> > Sean Chittenden <s...@chittenden.org> wrote:
> > 
> >> > Currently src/port/pgcheckdir.c will reject non-empty
> >> > directories, which is an issue during initdb(1) when PGDATA is
> >> > also the mount point for filesystems that support snapshots (e.g.
> >> > ZFS or UFS2).
> >> > Granted it's not hard to create a subdirectory, initdb there and
> >> > move the contents of the files around, it's extra work that
> >> > shouldn't be required.
> > I feel that it is very bad practice to use the mount point as the
> > PGDATA directory.  It forcloses a lot of reasonable actions that
> > someone managing the database server might want to take. 
> 
> Yes, a variant of this particular patch gets rejected about once every
> 18 months.

Agreed.  The attached patch modifies pg_check_dir() to report about
invisible and lost+found directory entries, and give more helpful
messages to the user.

-- 
  Bruce Momjian  <br...@momjian.us>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + It's impossible for everything to be true. +
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
new file mode 100644
index 2ea3f6e..03eadcd
*** a/src/bin/initdb/initdb.c
--- b/src/bin/initdb/initdb.c
*************** setup_signals(void)
*** 3144,3150 ****
  void
  create_data_directory(void)
  {
! 	switch (pg_check_dir(pg_data))
  	{
  		case 0:
  			/* PGDATA not there, must create it */
--- 3144,3152 ----
  void
  create_data_directory(void)
  {
! 	int ret;
! 
! 	switch ((ret = pg_check_dir(pg_data)))
  	{
  		case 0:
  			/* PGDATA not there, must create it */
*************** create_data_directory(void)
*** 3179,3193 ****
  			break;
  
  		case 2:
  			/* 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);
  			exit(1);			/* no further message needed */
  
  		default:
--- 3181,3205 ----
  			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);
! 			if (ret == 2)
! 				fprintf(stderr,
! 						_("It contains a dot-prefixed/invisible file.\n"));
! 			else if (ret == 3)
! 				fprintf(stderr,
! 						_("It contains a lost+found directory.\n"
! 						"Using the top-level directory of a mount point is not recommended.\n"));
! 			if (ret != 3)
! 				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:
*************** create_xlog_symlink(void)
*** 3206,3211 ****
--- 3218,3224 ----
  	if (strcmp(xlog_dir, "") != 0)
  	{
  		char	   *linkloc;
+ 		int			ret;
  
  		/* clean up xlog directory name, check it's absolute */
  		canonicalize_path(xlog_dir);
*************** create_xlog_symlink(void)
*** 3216,3222 ****
  		}
  
  		/* check if the specified xlog directory exists/is empty */
! 		switch (pg_check_dir(xlog_dir))
  		{
  			case 0:
  				/* xlog directory not there, must create it */
--- 3229,3235 ----
  		}
  
  		/* check if the specified xlog directory exists/is empty */
! 		switch ((ret = pg_check_dir(xlog_dir)))
  		{
  			case 0:
  				/* xlog directory not there, must create it */
*************** create_xlog_symlink(void)
*** 3255,3268 ****
  				break;
  
  			case 2:
  				/* 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);
  				exit_nicely();
  
  			default:
--- 3268,3291 ----
  				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);
! 				if (ret == 2)
! 					fprintf(stderr,
! 							_("It contains a dot-prefixed/invisible file.\n"));
! 				else if (ret == 3)
! 					fprintf(stderr,
! 							_("It contains a lost+found directory.\n"
! 							"Using the top-level directory of a mount point is not recommended.\n"));
! 				if (ret != 3)
! 					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:
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
new file mode 100644
index b6f7744..fb5a1bd
*** a/src/bin/pg_basebackup/pg_basebackup.c
--- b/src/bin/pg_basebackup/pg_basebackup.c
*************** verify_dir_is_empty_or_create(char *dirn
*** 371,376 ****
--- 371,378 ----
  			 */
  			return;
  		case 2:
+ 		case 3:
+ 		case 4:
  
  			/*
  			 * Exists, not empty
diff --git a/src/port/pgcheckdir.c b/src/port/pgcheckdir.c
new file mode 100644
index 3b8258c..9d6f216
*** a/src/port/pgcheckdir.c
--- b/src/port/pgcheckdir.c
*************** pg_check_dir(const char *dir)
*** 47,55 ****
  			/* skip this and parent directory */
  			continue;
  		}
  		else
  		{
! 			result = 2;			/* not empty */
  			break;
  		}
  	}
--- 47,68 ----
  			/* skip this and parent directory */
  			continue;
  		}
+ #ifndef WIN32
+ 		/* file starts with "." */
+ 		else if (file->d_name[0] == '.')
+ 		{
+ 			result = 2;			/* not empty, invisible file */
+ 			break;
+ 		}
+ 		else if (strcmp("lost+found", file->d_name) == 0)
+ 		{
+ 			result = 3;			/* not empty, mount point */
+ 			break;
+ 		}
+ #endif
  		else
  		{
! 			result = 4;			/* not empty */
  			break;
  		}
  	}
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to