*
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
- * Portions taken from FreeBSD.
*
* src/bin/initdb/initdb.c
*
static char **readfile(const char *path);
static void writefile(char *path, char **lines);
static FILE *popen_check(const char *command, const char *mode);
-static int mkdir_p(char *path, mode_t omode);
static void exit_nicely(void);
static char *get_id(void);
static char *get_encoding_id(char *encoding_name);
-static int check_data_dir(char *dir);
static bool mkdatadir(const char *subdir);
static void set_input(char **dest, char *filename);
static void check_input(char *path);
return cmdfd;
}
-/* source stolen from FreeBSD /src/bin/mkdir/mkdir.c and adapted */
-
-/*
- * this tries to build all the elements of a path to a directory a la mkdir -p
- * we assume the path is in canonical form, i.e. uses / as the separator
- * we also assume it isn't null.
- *
- * note that on failure, the path arg has been modified to show the particular
- * directory level we had problems with.
- */
-static int
-mkdir_p(char *path, mode_t omode)
-{
- struct stat sb;
- mode_t numask,
- oumask;
- int first,
- last,
- retval;
- char *p;
-
- p = path;
- oumask = 0;
- retval = 0;
-
-#ifdef WIN32
- /* skip network and drive specifiers for win32 */
- if (strlen(p) >= 2)
- {
- if (p[0] == '/' && p[1] == '/')
- {
- /* network drive */
- p = strstr(p + 2, "/");
- if (p == NULL)
- return 1;
- }
- else if (p[1] == ':' &&
- ((p[0] >= 'a' && p[0] <= 'z') ||
- (p[0] >= 'A' && p[0] <= 'Z')))
- {
- /* local drive */
- p += 2;
- }
- }
-#endif
-
- if (p[0] == '/') /* Skip leading '/'. */
- ++p;
- for (first = 1, last = 0; !last; ++p)
- {
- if (p[0] == '\0')
- last = 1;
- else if (p[0] != '/')
- continue;
- *p = '\0';
- if (!last && p[1] == '\0')
- last = 1;
- if (first)
- {
- /*
- * POSIX 1003.2: For each dir operand that does not name an
- * existing directory, effects equivalent to those caused by the
- * following command shall occcur:
- *
- * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]
- * dir
- *
- * We change the user's umask and then restore it, instead of
- * doing chmod's.
- */
- oumask = umask(0);
- numask = oumask & ~(S_IWUSR | S_IXUSR);
- (void) umask(numask);
- first = 0;
- }
- if (last)
- (void) umask(oumask);
-
- /* check for pre-existing directory; ok if it's a parent */
- if (stat(path, &sb) == 0)
- {
- if (!S_ISDIR(sb.st_mode))
- {
- if (last)
- errno = EEXIST;
- else
- errno = ENOTDIR;
- retval = 1;
- break;
- }
- }
- else if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
- {
- retval = 1;
- break;
- }
- if (!last)
- *p = '/';
- }
- if (!first && !last)
- (void) umask(oumask);
- return retval;
-}
-
/*
* clean up any files we created on failure
* if we created the data directory remove it too
}
-/*
- * make sure the directory either doesn't exist or is empty
- *
- * Returns 0 if nonexistent, 1 if exists and empty, 2 if not empty,
- * or -1 if trouble accessing directory
- */
-static int
-check_data_dir(char *dir)
-{
- DIR *chkdir;
- struct dirent *file;
- int result = 1;
-
- errno = 0;
-
- chkdir = opendir(dir);
-
- if (!chkdir)
- 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;
- }
- else
- {
- result = 2; /* 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? */
-
- return result;
-}
-
/*
* make the data directory (or one of its subdirectories if subdir is not NULL)
*/
else
strcpy(path, pg_data);
- if (mkdir_p(path, S_IRWXU) == 0)
+ if (pg_mkdir_p(path, S_IRWXU) == 0)
return true;
fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
pqsignal(SIGPIPE, SIG_IGN);
#endif
- switch (check_data_dir(pg_data))
+ switch (pg_check_dir(pg_data))
{
case 0:
/* PGDATA not there, must create it */
exit_nicely();
}
- /* check if the specified xlog directory is empty */
- switch (check_data_dir(xlog_dir))
+ /* check if the specified xlog directory exists/is empty */
+ switch (pg_check_dir(xlog_dir))
{
case 0:
/* xlog directory not there, must create it */
xlog_dir);
fflush(stdout);
- if (mkdir_p(xlog_dir, S_IRWXU) != 0)
+ if (pg_mkdir_p(xlog_dir, S_IRWXU) != 0)
{
fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
progname, xlog_dir, strerror(errno));
made_new_xlogdir = true;
break;
+
case 1:
/* Present but empty, fix permissions and use it */
printf(_("fixing permissions on existing directory %s ... "),
found_existing_xlogdir = true;
break;
+
case 2:
/* Present and not empty */
fprintf(stderr,
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);
+
#endif /* PG_PORT_H */
# libpgport_srv.a - contains object files without FRONTEND defined,
# for use only by the backend binaries
#
-# LIBOBJS is set by configure (via Makefile.global) to be the list of
-# object files that are conditionally needed as determined by configure's probing.
+# LIBOBJS is set by configure (via Makefile.global) to be the list of object
+# files that are conditionally needed as determined by configure's probing.
# OBJS adds additional object files that are always compiled.
#
# IDENTIFICATION
override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS)
LIBS += $(PTHREAD_LIBS)
-OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o inet_net_ntop.o noblock.o path.o \
- pgsleep.o pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o
+OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o inet_net_ntop.o noblock.o \
+ path.o pgcheckdir.o pgmkdirp.o pgsleep.o pgstrcasecmp.o \
+ qsort.o qsort_arg.o sprompt.o thread.o
+
ifneq (,$(filter $(PORTNAME),cygwin win32))
OBJS += pipe.o
endif
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * 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-2010, 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;
+
+ 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;
+ }
+ else
+ {
+ result = 2; /* 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? */
+
+ return result;
+}
--- /dev/null
+/*
+ * This is adapted from FreeBSD's src/bin/mkdir/mkdir.c, which bears
+ * the following copyright notice:
+ *
+ * Copyright (c) 1983, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "c.h"
+
+#include <sys/stat.h>
+
+
+/*
+ * pg_mkdir_p --- create a directory and, if necessary, parent directories
+ *
+ * This is equivalent to "mkdir -p" except we don't complain if the target
+ * directory already exists.
+ *
+ * We assume the path is in canonical form, i.e., uses / as the separator.
+ *
+ * omode is the file permissions bits for the target directory. Note that any
+ * parent directories that have to be created get permissions according to the
+ * prevailing umask, but with u+wx forced on to ensure we can create there.
+ * (We declare omode as int, not mode_t, to minimize dependencies for port.h.)
+ *
+ * Returns 0 on success, -1 (with errno set) on failure.
+ *
+ * Note that on failure, the path arg has been modified to show the particular
+ * directory level we had problems with.
+ */
+int
+pg_mkdir_p(char *path, int omode)
+{
+ struct stat sb;
+ mode_t numask,
+ oumask;
+ int last,
+ retval;
+ char *p;
+
+ retval = 0;
+ p = path;
+
+#ifdef WIN32
+ /* skip network and drive specifiers for win32 */
+ if (strlen(p) >= 2)
+ {
+ if (p[0] == '/' && p[1] == '/')
+ {
+ /* network drive */
+ p = strstr(p + 2, "/");
+ if (p == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ else if (p[1] == ':' &&
+ ((p[0] >= 'a' && p[0] <= 'z') ||
+ (p[0] >= 'A' && p[0] <= 'Z')))
+ {
+ /* local drive */
+ p += 2;
+ }
+ }
+#endif
+
+ /*
+ * POSIX 1003.2: For each dir operand that does not name an existing
+ * directory, effects equivalent to those caused by the following command
+ * shall occcur:
+ *
+ * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode] dir
+ *
+ * We change the user's umask and then restore it, instead of doing
+ * chmod's. Note we assume umask() can't change errno.
+ */
+ oumask = umask(0);
+ numask = oumask & ~(S_IWUSR | S_IXUSR);
+ (void) umask(numask);
+
+ if (p[0] == '/') /* Skip leading '/'. */
+ ++p;
+ for (last = 0; !last; ++p)
+ {
+ if (p[0] == '\0')
+ last = 1;
+ else if (p[0] != '/')
+ continue;
+ *p = '\0';
+ if (!last && p[1] == '\0')
+ last = 1;
+
+ if (last)
+ (void) umask(oumask);
+
+ /* check for pre-existing directory */
+ if (stat(path, &sb) == 0)
+ {
+ if (!S_ISDIR(sb.st_mode))
+ {
+ if (last)
+ errno = EEXIST;
+ else
+ errno = ENOTDIR;
+ retval = -1;
+ break;
+ }
+ }
+ else if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
+ {
+ retval = -1;
+ break;
+ }
+ if (!last)
+ *p = '/';
+ }
+
+ /* ensure we restored umask */
+ (void) umask(oumask);
+
+ return retval;
+}