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