Here's a patch to move src/port/pgcheckdir.c to src/common/checkdir.c
and add the shareable part of postmaster's current checkDataDir code
into it, as pg_check_dir_permissions. This is in the spirit of using it
in pgstat to check the directory defined by stats_temp_directory.
(This is basically the same patch I posted earlier, except the file is
now in src/common instead of src/port.)
Barring objections I intend to push this to 9.3 and HEAD shortly.
--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
***************
*** 95,100 ****
--- 95,101 ----
#include "access/xlog.h"
#include "bootstrap/bootstrap.h"
#include "catalog/pg_control.h"
+ #include "common/checkdir.h"
#include "lib/ilist.h"
#include "libpq/auth.h"
#include "libpq/ip.h"
***************
*** 1313,1385 **** getInstallationPaths(const char *argv0)
static void
checkDataDir(void)
{
char path[MAXPGPATH];
FILE *fp;
- struct stat stat_buf;
Assert(DataDir);
! if (stat(DataDir, &stat_buf) != 0)
{
! if (errno == ENOENT)
ereport(FATAL,
(errcode_for_file_access(),
errmsg("data directory \"%s\" does not exist",
DataDir)));
! else
ereport(FATAL,
(errcode_for_file_access(),
! errmsg("could not read permissions of directory \"%s\": %m",
! DataDir)));
}
- /* eventual chdir would fail anyway, but let's test ... */
- if (!S_ISDIR(stat_buf.st_mode))
- ereport(FATAL,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("specified data directory \"%s\" is not a directory",
- DataDir)));
-
- /*
- * Check that the directory belongs to my userid; if not, reject.
- *
- * This check is an essential part of the interlock that prevents two
- * postmasters from starting in the same directory (see CreateLockFile()).
- * Do not remove or weaken it.
- *
- * XXX can we safely enable this check on Windows?
- */
- #if !defined(WIN32) && !defined(__CYGWIN__)
- if (stat_buf.st_uid != geteuid())
- ereport(FATAL,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("data directory \"%s\" has wrong ownership",
- DataDir),
- errhint("The server must be started by the user that owns the data directory.")));
- #endif
-
- /*
- * Check if the directory has group or world access. If so, reject.
- *
- * It would be possible to allow weaker constraints (for example, allow
- * group access) but we cannot make a general assumption that that is
- * okay; for example there are platforms where nearly all users
- * customarily belong to the same group. Perhaps this test should be
- * configurable.
- *
- * XXX temporarily suppress check when on Windows, because there may not
- * be proper support for Unix-y file permissions. Need to think of a
- * reasonable check to apply on Windows.
- */
- #if !defined(WIN32) && !defined(__CYGWIN__)
- if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
- ereport(FATAL,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("data directory \"%s\" has group or world access",
- DataDir),
- errdetail("Permissions should be u=rwx (0700).")));
- #endif
-
/* Look for PG_VERSION before looking for pg_control */
ValidatePgVersion(DataDir);
--- 1314,1364 ----
static void
checkDataDir(void)
{
+ CheckDirErrcode err;
char path[MAXPGPATH];
FILE *fp;
Assert(DataDir);
! err = pg_check_dir_permissions(DataDir);
! switch (err)
{
! case CKDIR_OK:
! break;
! case CKDIR_NOT_EXISTS:
ereport(FATAL,
(errcode_for_file_access(),
errmsg("data directory \"%s\" does not exist",
DataDir)));
! break;
! case CKDIR_CANT_READ_PERMS:
ereport(FATAL,
(errcode_for_file_access(),
! errmsg("could not read permissions of data directory \"%s\": %m",
! DataDir)));
! break;
! case CKDIR_NOT_DIR:
! ereport(FATAL,
! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("specified data directory \"%s\" is not a directory",
! DataDir)));
! break;
! case CKDIR_WRONG_OWNER:
! ereport(FATAL,
! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("data directory \"%s\" has wrong ownership",
! DataDir),
! errhint("The server must be started by the user that owns the data directory.")));
! break;
! case CKDIR_TOO_ACCESSIBLE:
! ereport(FATAL,
! (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! errmsg("data directory \"%s\" has group or world access",
! DataDir),
! errdetail("Permissions should be u=rwx (0700).")));
! break;
}
/* Look for PG_VERSION before looking for pg_control */
ValidatePgVersion(DataDir);
*** a/src/bin/initdb/initdb.c
--- b/src/bin/initdb/initdb.c
***************
*** 56,61 ****
--- 56,62 ----
#include <signal.h>
#include <time.h>
+ #include "common/checkdir.h"
#include "mb/pg_wchar.h"
#include "getaddrinfo.h"
#include "getopt_long.h"
*** a/src/bin/pg_basebackup/pg_basebackup.c
--- b/src/bin/pg_basebackup/pg_basebackup.c
***************
*** 10,20 ****
* src/bin/pg_basebackup/pg_basebackup.c
*-------------------------------------------------------------------------
*/
-
#include "postgres_fe.h"
- #include "libpq-fe.h"
- #include "pqexpbuffer.h"
- #include "pgtar.h"
#include <unistd.h>
#include <dirent.h>
--- 10,16 ----
***************
*** 27,34 ****
#include <zlib.h>
#endif
#include "getopt_long.h"
!
#include "receivelog.h"
#include "streamutil.h"
--- 23,33 ----
#include <zlib.h>
#endif
+ #include "common/checkdir.h"
#include "getopt_long.h"
! #include "libpq-fe.h"
! #include "pgtar.h"
! #include "pqexpbuffer.h"
#include "receivelog.h"
#include "streamutil.h"
*** a/src/common/Makefile
--- b/src/common/Makefile
***************
*** 23,29 **** include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -DFRONTEND $(CPPFLAGS)
LIBS += $(PTHREAD_LIBS)
! OBJS_COMMON = relpath.o
OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o
--- 23,29 ----
override CPPFLAGS := -DFRONTEND $(CPPFLAGS)
LIBS += $(PTHREAD_LIBS)
! OBJS_COMMON = relpath.o checkdir.o
OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o
*** /dev/null
--- b/src/common/checkdir.c
***************
*** 0 ****
--- 1,148 ----
+ /*-------------------------------------------------------------------------
+ *
+ * src/common/checkdir.c
+ * Subroutines to deal with directory-related checks. Useful in both
+ * initdb and the backend.
+ *
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ #include "c.h"
+
+ #include <dirent.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+
+ #include "common/checkdir.h"
+
+
+ /*
+ * Test to see if a directory exists and is empty or not.
+ *
+ * Returns:
+ * 0 if nonexistent
+ * 1 if exists and empty
+ * 2 if exists and not empty
+ * -1 if trouble accessing directory (errno reflects the error)
+ */
+ int
+ pg_check_dir(const char *dir)
+ {
+ int result = 1;
+ DIR *chkdir;
+ struct dirent *file;
+ bool dot_found = false;
+
+ errno = 0;
+
+ chkdir = opendir(dir);
+
+ if (chkdir == NULL)
+ return (errno == ENOENT) ? 0 : -1;
+
+ while ((file = readdir(chkdir)) != NULL)
+ {
+ if (strcmp(".", file->d_name) == 0 ||
+ strcmp("..", file->d_name) == 0)
+ {
+ /* 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 = 4; /* not empty */
+ break;
+ }
+ }
+
+ #ifdef WIN32
+
+ /*
+ * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
+ * released version
+ */
+ if (GetLastError() == ERROR_NO_MORE_FILES)
+ errno = 0;
+ #endif
+
+ closedir(chkdir);
+
+ 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;
+ }
+
+ /*
+ * Verify permissions of a directory
+ */
+ CheckDirErrcode
+ pg_check_dir_permissions(const char *directory)
+ {
+ struct stat stat_buf;
+
+ if (stat(directory, &stat_buf) != 0)
+ {
+ if (errno == ENOENT)
+ return CKDIR_NOT_EXISTS;
+ else
+ return CKDIR_CANT_READ_PERMS;
+ }
+
+ if (!S_ISDIR(stat_buf.st_mode))
+ return CKDIR_NOT_DIR;
+
+ /*
+ * Check that the directory belongs to my userid; if not, reject.
+ *
+ * This check is an essential part of the interlock that prevents two
+ * postmasters from starting in the same directory (see CreateLockFile()).
+ * Do not remove or weaken it.
+ *
+ * XXX can we safely enable this check on Windows?
+ */
+ #if !defined(WIN32) && !defined(__CYGWIN__)
+ if (stat_buf.st_uid != geteuid())
+ return CKDIR_WRONG_OWNER;
+ #endif
+
+ /*
+ * Check if the directory has group or world access. If so, reject.
+ *
+ * It would be possible to allow weaker constraints (for example, allow
+ * group access) but we cannot make a general assumption that that is
+ * okay; for example there are platforms where nearly all users
+ * customarily belong to the same group. Perhaps this test should be
+ * configurable.
+ *
+ * XXX temporarily suppress check when on Windows, because there may not
+ * be proper support for Unix-y file permissions. Need to think of a
+ * reasonable check to apply on Windows.
+ */
+ #if !defined(WIN32) && !defined(__CYGWIN__)
+ if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
+ return CKDIR_TOO_ACCESSIBLE;
+ #endif
+
+ return CKDIR_OK;
+ }
*** a/src/include/port.h
--- b/src/include/port.h
***************
*** 460,468 **** extern int pg_codepage_to_encoding(UINT cp);
extern char *inet_net_ntop(int af, const void *src, int bits,
char *dst, size_t size);
- /* port/pgcheckdir.c */
- extern int pg_check_dir(const char *dir);
-
/* port/pgmkdirp.c */
extern int pg_mkdir_p(char *path, int omode);
--- 460,465 ----
*** a/src/port/Makefile
--- b/src/port/Makefile
***************
*** 31,37 **** override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS)
LIBS += $(PTHREAD_LIBS)
OBJS = $(LIBOBJS) chklocale.o dirmod.o erand48.o exec.o fls.o inet_net_ntop.o \
! noblock.o path.o pgcheckdir.o pg_crc.o pgmkdirp.o pgsleep.o \
pgstrcasecmp.o pqsignal.o \
qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o \
wait_error.o
--- 31,37 ----
LIBS += $(PTHREAD_LIBS)
OBJS = $(LIBOBJS) chklocale.o dirmod.o erand48.o exec.o fls.o inet_net_ntop.o \
! noblock.o path.o pg_crc.o pgmkdirp.o pgsleep.o \
pgstrcasecmp.o pqsignal.o \
qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o \
wait_error.o
*** a/src/port/pgcheckdir.c
--- /dev/null
***************
*** 1,90 ****
- /*-------------------------------------------------------------------------
- *
- * src/port/pgcheckdir.c
- *
- * A simple subroutine to check whether a directory exists and is empty or not.
- * Useful in both initdb and the backend.
- *
- * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *-------------------------------------------------------------------------
- */
-
- #include "c.h"
-
- #include <dirent.h>
-
-
- /*
- * Test to see if a directory exists and is empty or not.
- *
- * Returns:
- * 0 if nonexistent
- * 1 if exists and empty
- * 2 if exists and not empty
- * -1 if trouble accessing directory (errno reflects the error)
- */
- int
- pg_check_dir(const char *dir)
- {
- int result = 1;
- DIR *chkdir;
- struct dirent *file;
- bool dot_found = false;
-
- errno = 0;
-
- chkdir = opendir(dir);
-
- if (chkdir == NULL)
- return (errno == ENOENT) ? 0 : -1;
-
- while ((file = readdir(chkdir)) != NULL)
- {
- if (strcmp(".", file->d_name) == 0 ||
- strcmp("..", file->d_name) == 0)
- {
- /* 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 = 4; /* not empty */
- break;
- }
- }
-
- #ifdef WIN32
-
- /*
- * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
- * released version
- */
- if (GetLastError() == ERROR_NO_MORE_FILES)
- errno = 0;
- #endif
-
- closedir(chkdir);
-
- 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;
- }
--- 0 ----
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers