-
/*-------------------------------------------------------------------------
*
* initdb
*
* author: Andrew Dunstan mailto:andrew@dunslane.net
*
- * Copyright (C) 2003 Andrew Dunstan
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* This is a C implementation of the previous shell script for setting up a
* PostgreSQL cluster location, and should be highly compatible with it.
*
- * $Header: /cvsroot/pgsql/src/bin/initdb/initdb.c,v 1.1 2003/11/10 22:51:16 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/initdb/initdb.c,v 1.2 2003/11/10 22:52:10 momjian Exp $
*
* TODO:
* - clean up find_postgres code and return values
char *datadir = PGDATADIR;
/* values to be obtained from arguments */
-
char *pg_data = "";
char *encoding = "";
char *locale = "";
bool not_ok = false;
/* defaults */
-int n_buffers = 50;
int n_connections = 10;
+int n_buffers = 50;
/* platform specific path stuff */
#else
#define EXE ""
#define DEVNULL "/dev/null"
-#endif /* defined(__CYGWIN__) || defined(WIN32) */
+#endif
#ifdef WIN32
#define PATHSEP ';'
#else
#define PATHSEP ':'
-#endif /* WIN32 */
+#endif
/* detected path to postgres and (we assume) friends */
char *pgpath;
/* forward declare all our functions */
static bool rmtree(char *, bool);
static void exit_nicely(void);
-static void canonicalise_path(char *);
+static void canonicalize_path(char *);
#ifdef WIN32
static char *expanded_path(char *);
-static int init_unlink(const char *);
-
#else
-#define expanded_path(x) ( x )
-#define init_unlink(x) unlink( (x) )
-#endif /* WIN32 */
+#define expanded_path(x) (x)
+#endif
static char **readfile(char *);
static void writefile(char *, char **);
static char *get_id(void);
static char *get_encoding_id(char *);
static char *get_short_version(void);
-static int build_path(char *, mode_t);
+static int mkdir_p(char *, mode_t);
static bool check_data_dir(void);
static bool mkdatadir(char *);
static bool chklocale(const char *);
static void setup_config(void);
static void bootstrap_template1(char *);
static void setup_shadow(void);
-static void get_set_pw(void);
+static void get_set_pwd(void);
static void unlimit_systables(void);
static void setup_depend(void);
static void setup_sysviews(void);
/*
* macros for running pipes to postgres
*/
-
#define PG_CMD_DECL char cmd[MAXPGPATH]; char ** line ; FILE * pg
#define PG_CMD_DECL_NOLINE char cmd[MAXPGPATH]; FILE * pg
-#define PG_CMD_OPEN \
- do {\
- pg = popen(cmd,PG_BINARY_W);\
- if (pg == NULL) \
- exit_nicely();\
- } while (0)
-#define PG_CMD_CLOSE \
- do {\
- if(pclose(pg)>>8 &0xff)\
- exit_nicely();\
- } while (0)
-#define PG_CMD_PUTLINE \
- do {\
+
+#define PG_CMD_OPEN \
+do { \
+ pg = popen(cmd,PG_BINARY_W); \
+ if (pg == NULL) \
+ exit_nicely(); \
+} while (0)
+
+#define PG_CMD_CLOSE \
+do { \
+ if(pclose(pg) >> 8 & 0xff) \
+ exit_nicely(); \
+} while (0)
+
+#define PG_CMD_PUTLINE \
+do { \
if (fputs(*line, pg) < 0) \
exit_nicely(); \
- fflush(pg);\
- } while (0)
-
-
+ fflush(pg); \
+} while (0)
-
-#ifdef WIN32
-
-/* workaround for win32 unlink bug, not using logging like in port/dirmod.c */
-
-/* make sure we call the real unlink from MSVCRT */
-
-#ifdef unlink
-#undef unlink
+#ifndef WIN32
+#define QUOTE_PATH ""
+#else
+#define QUOTE_PATH "\""
#endif
-static int
-init_unlink(const char *path)
-{
- while (unlink(path))
- {
- if (errno != EACCES)
- return -1;
- Sleep(100); /* ms */
- }
- return 0;
-}
-#endif /* WIN32 */
-
/*
- * routines to check mem allocations and fail noisily
+ * routines to check mem allocations and fail noisily.
* Note that we can't call exit_nicely() on a memory failure, as it calls
* rmtree() which needs memory allocation. So we just exit with a bang.
*
*/
-
static void *
xmalloc(size_t size)
{
static bool
rmtree(char *path, bool rmtopdir)
{
- char filepath[MAXPGPATH];
- DIR *dir;
- struct dirent *file;
- char **filenames;
- char **filename;
- int numnames = 0;
- struct stat statbuf;
+ char buf[MAXPGPATH + 64];
- /*
- * we copy all the names out of the directory before we start
- * modifying it.
- *
- */
-
- dir = opendir(path);
- if (dir == NULL)
- return false;
-
- while ((file = readdir(dir)) != NULL)
- {
- if (strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0)
- numnames++;
- }
-
- rewinddir(dir);
-
- filenames = xmalloc((numnames + 2) * sizeof(char *));
- numnames = 0;
-
- while ((file = readdir(dir)) != NULL)
- {
- if (strcmp(file->d_name, ".") != 0 && strcmp(file->d_name, "..") != 0)
- filenames[numnames++] = xstrdup(file->d_name);
- }
-
- filenames[numnames] = NULL;
-
- closedir(dir);
-
- /* now we have the names we can start removing things */
-
- for (filename = filenames; *filename; filename++)
- {
- snprintf(filepath, MAXPGPATH, "%s/%s", path, *filename);
-
- if (stat(filepath, &statbuf) != 0)
- return false;
-
- if (S_ISDIR(statbuf.st_mode))
- {
- /* call ourselves recursively for a directory */
- if (!rmtree(filepath, true))
- return false;
- }
- else
- {
- if (init_unlink(filepath) != 0)
- return false;
- }
- }
-
- if (rmtopdir)
- {
- if (rmdir(path) != 0)
- return false;
- }
+#ifndef WIN32
+ /* doesn't handle .* files */
+ snprintf(buf, sizeof(buf), "rm -rf '%s%s'", path,
+ rmtopdir ? "" : "/*");
+#else
+ snprintf(buf, sizeof(buf), "%s /s /q \"%s\"",
+ rmtopdir ? "rmdir" : "del", path);
+#endif
- return true;
+ return !system(buf);
}
/*
* make all paths look like unix, with forward slashes
- * also strip any trailing slash
+ * also strip any trailing slash.
+ * The Windows command processor will accept suitably quoted paths
+ * with forward slashes, but barfs badly with mixed forward and back
+ * slashes. Removing the trailing slash on a path means we never get
+ * ugly double slashes.
*/
-
static void
-canonicalise_path(char *path)
+canonicalize_path(char *path)
{
char *p;
#ifdef WIN32
if (*p == '\\')
*p = '/';
-#endif /* WIN32 */
+#endif
}
if (p != path && *--p == '/')
*p = '\0';
* This does most of what sed was used for in the shell script, but
* doesn't need any regexp stuff.
*/
-
static char **
replace_token(char **lines, char *token, char *replacement)
{
replen,
diff;
-
for (i = 0; lines[i]; i++)
numlines++;
char *buffer;
int c;
- infile = fopen(path, "r");
-
- if (!infile)
+ if ((infile = fopen(path, "r")) == NULL)
{
fprintf(stderr, "could not read %s ... ", path);
exit_nicely();
FILE *out_file;
char **line;
- out_file = fopen(path, PG_BINARY_W);
- if (out_file == NULL)
+ ;
+ if ((out_file = fopen(path, PG_BINARY_W)) == NULL)
{
fprintf(stderr, "could not write %s ... ", path);
exit_nicely();
* we also assume it isn't null.
*
*/
-
static int
-build_path(char *path, mode_t omode)
+mkdir_p(char *path, mode_t omode)
{
struct stat sb;
mode_t numask,
retval = 0;
#ifdef WIN32
-
/* skip network and drive specifiers for win32 */
if (strlen(p) >= 2)
{
p += 2;
}
}
-#endif /* WIN32 */
+#endif
if (p[0] == '/') /* Skip leading '/'. */
++p;
}
if (!first && !last)
(void) umask(oumask);
- return (retval);
+ return retval;
}
/*
progname);
exit(1);
}
-#endif /* __BEOS__ */
+#endif
#else /* the windows code */
pw->pw_uid = 1;
GetUserName(pw->pw_name, &pwname_size);
-#endif /* ! WIN32 */
+#endif
return xstrdup(pw->pw_name);
}
closedir(chkdir);
- return (empty);
+ return empty;
}
/*
else if (subdir == NULL || errno != ENOENT)
return false;
else
- return !build_path(path, 0700);
+ return !mkdir_p(path, 0700);
}
* don't overkill
*
*/
-
#define FIND_SUCCESS 0
#define FIND_NOT_FOUND 1
#define FIND_STAT_ERR 2
char line[100];
#ifndef WIN32
-
int permmask = S_IROTH | S_IXOTH;
#endif
-
struct stat statbuf;
FILE *pgver;
int plen = strlen(path);
return FIND_NOT_REGFILE;
#ifndef WIN32
-
- /* on windows a .exe file should be executable - this is the unix test */
-
+ /*
+ * Only unix requires this test, on WIN32 an .exe file should be
+ * executable
+ */
if ((statbuf.st_mode & permmask) != permmask)
return FIND_BAD_PERM;
-#endif /* ! WIN32 */
+#endif
snprintf(cmd, MAXPGPATH, "\"%s/postgres\" -V 2>%s", path, DEVNULL);
return FIND_EXEC_ERR;
if (fgets(line, sizeof(line), pgver) == NULL)
- {
perror("fgets failure");
- }
-
pclose(pgver);
if (strcmp(line, PG_VERSIONSTR) != 0)
return FIND_SUCCESS;
}
-#ifdef WIN32
-
/*
* Windows doesn't like relative paths to executables (other things work fine)
* so we call its builtin function to expand them. Elsewhere this is a NOOP
*
*/
-
+#ifdef WIN32
static char *
expanded_path(char *path)
{
perror("expanded path");
return path;
}
- canonicalise_path(abspath);
+ canonicalize_path(abspath);
return xstrdup(abspath);
}
-#endif /* WIN32 */
+#endif
/*
* set the paths pointing to postgres
}
else
{
- canonicalise_path(cursor);
+ canonicalize_path(cursor);
pathbits[pathsegs] = cursor;
}
pathsegs++;
char *cbindir;
cbindir = xstrdup(bindir);
- canonicalise_path(cbindir);
+ canonicalize_path(cbindir);
res = find_postgres(expanded_path(cbindir));
if (res == 0)
pgpath = expanded_path(cbindir);
}
/*
- * check how many buffers we can run with
+ * check how many connections we can sustain
*
*/
static void
-test_buffers(void)
+test_connections(void)
{
char *format =
- "\"%s/postgres\" -boot -x 0 -F "
- "-c shared_buffers=%d -c max_connections=5 template1 <%s >%s 2>&1";
+ "\"%s/postgres\" -boot -x 0 -F "
+ "-c shared_buffers=%d -c max_connections=%d template1 <%s >%s 2>&1";
char cmd[MAXPGPATH];
- int bufs[] =
- {1000, 900, 800, 700, 600, 500, 400, 300, 200, 100, 50};
- int len = sizeof(bufs) / sizeof(int);
+ int conns[] = {100, 50, 40, 30, 20, 10};
+ int len = sizeof(conns) / sizeof(int);
int i,
status;
for (i = 0; i < len; i++)
{
- snprintf(cmd, sizeof(cmd), format, pgpath, bufs[i], DEVNULL, DEVNULL);
+ snprintf(cmd, sizeof(cmd), format,
+ pgpath, conns[i] * 5, conns[i], DEVNULL, DEVNULL);
status = system(cmd);
if (status == 0)
break;
}
if (i >= len)
i = len - 1;
- n_buffers = bufs[i];
- printf("buffers set to %d\n", n_buffers);
+ n_connections = conns[i];
+ printf("connections set to %d\n", n_connections);
}
/*
- * check how many connections we can sustain
+ * check how many buffers we can run with
*
*/
static void
-test_connections(void)
+test_buffers(void)
{
char *format =
- "\"%s/postgres\" -boot -x 0 -F "
+ "\"%s/postgres\" -boot -x 0 -F "
"-c shared_buffers=%d -c max_connections=%d template1 <%s >%s 2>&1";
char cmd[MAXPGPATH];
- int conns[] = {100, 50, 40, 30, 20, 10};
- int len = sizeof(conns) / sizeof(int);
+ int bufs[] = {1000, 900, 800, 700, 600, 500, 400, 300, 200, 100, 50};
+ int len = sizeof(bufs) / sizeof(int);
int i,
status;
for (i = 0; i < len; i++)
{
- snprintf(cmd, sizeof(cmd), format,
- pgpath, n_buffers, conns[i], DEVNULL, DEVNULL);
+ snprintf(cmd, sizeof(cmd), format, pgpath, bufs[i], n_connections,
+ DEVNULL, DEVNULL);
status = system(cmd);
if (status == 0)
break;
}
if (i >= len)
i = len - 1;
- n_connections = conns[i];
- printf("connections set to %d\n", n_connections);
+ n_buffers = bufs[i];
+ printf("buffers set to %d\n", n_buffers);
}
/*
conflines = readfile(conf_file);
- snprintf(repltok, sizeof(repltok), "shared_buffers = %d", n_buffers);
- conflines = replace_token(conflines, "#shared_buffers = 1000", repltok);
-
snprintf(repltok, sizeof(repltok), "max_connections = %d", n_connections);
conflines = replace_token(conflines, "#max_connections = 100", repltok);
+ snprintf(repltok, sizeof(repltok), "shared_buffers = %d", n_buffers);
+ conflines = replace_token(conflines, "#shared_buffers = 1000", repltok);
+
snprintf(repltok, sizeof(repltok), "lc_messages = '%s'", lc_messages);
conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
conflines = replace_token(conflines,
"host all all ::1",
"#host all all ::1");
-#endif /* ! HAVE_IPV6 */
+#endif
snprintf(path, MAXPGPATH, "%s/pg_hba.conf", pg_data);
free(conflines);
check_ok();
-
}
* already called setlocale().
*
*/
-
snprintf(cmd, MAXPGPATH, "LC_COLLATE=%s", lc_collate);
putenv(xstrdup(cmd));
*
*/
static void
-get_set_pw(void)
+get_set_pwd(void)
{
PG_CMD_DECL_NOLINE;
- char *pw1,
- *pw2;
- char pwpath[MAXPGPATH];
+ char *pwd1,
+ *pwd2;
+ char pwdpath[MAXPGPATH];
struct stat statbuf;
- pw1 = simple_prompt("Enter new superuser password: ", 100, false);
- pw2 = simple_prompt("Enter it again: ", 100, false);
- if (strcmp(pw1, pw2) != 0)
+ pwd1 = simple_prompt("Enter new superuser password: ", 100, false);
+ pwd2 = simple_prompt("Enter it again: ", 100, false);
+ if (strcmp(pwd1, pwd2) != 0)
{
fprintf(stderr, "Passwords didn't match.\n");
exit_nicely();
}
- free(pw2);
+ free(pwd2);
printf("storing the password ... ");
PG_CMD_OPEN;
if (fprintf(
- pg, "ALTER USER \"%s\" WITH PASSWORD '%s';\n", username, pw1) < 0)
+ pg, "ALTER USER \"%s\" WITH PASSWORD '%s';\n", username, pwd1) < 0)
{
/* write failure */
exit_nicely();
PG_CMD_CLOSE;
- snprintf(pwpath, MAXPGPATH, "%s/global/pg_pwd", pg_data);
- if (stat(pwpath, &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
+ snprintf(pwdpath, MAXPGPATH, "%s/global/pg_pwd", pg_data);
+ if (stat(pwdpath, &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
{
fprintf(stderr,
"%s: The password file was not generated - "
* So this will need some testing on Windows.
*
*/
-
static void
trapsig(int signum)
{
/* when not available, get the CTYPE setting */
lc_messages = xstrdup(setlocale(LC_CTYPE, NULL));
}
-#endif /* LC_MESSAGES */
+#endif
}
* help text data
*
*/
-
char *usage_text[] = {
"$CMDNAME initializes a PostgreSQL database cluster.\n",
"\n",
#if defined(__CYGWIN__) || defined(WIN32)
char *exe; /* location of exe suffix in progname */
-#endif /* defined(__CYGWIN__) || defined(WIN32) */
+#endif
setlocale(LC_ALL, "");
carg0 = xstrdup(argv[0]);
- canonicalise_path(carg0);
+ canonicalize_path(carg0);
lastsep = strrchr(carg0, '/');
progname = lastsep ? xstrdup(lastsep + 1) : carg0;
/* strip .exe suffix, regardless of case */
*exe = '\0';
}
-#endif /* defined(__CYGWIN__) || defined(WIN32) */
+#endif
if (lastsep)
{
}
}
- canonicalise_path(pg_data);
+ canonicalize_path(pg_data);
/*
* we have to set PGDATA for postgres rather than pass it on the
set_input(&features_file, "sql_features.txt");
set_input(&system_views_file, "system_views.sql");
-
if (show_setting || debug)
{
fprintf(stderr,
hba_file, ident_file);
}
-
if (show_setting)
exit(0);
-
check_input(bki_file);
check_input(desc_file);
check_input(hba_file);
/* some of these are not valid on Windows */
#ifdef SIGHUP
pqsignal(SIGHUP, trapsig);
-#endif /* SIGHUP */
+#endif
#ifdef SIGINT
pqsignal(SIGINT, trapsig);
-#endif /* SIGINT */
+#endif
#ifdef SIGQUIT
pqsignal(SIGQUIT, trapsig);
-#endif /* SIGQUIT */
+#endif
#ifdef SIGTERM
pqsignal(SIGTERM, trapsig);
-#endif /* SIGTERM */
-
+#endif
/* clear this we'll use it in a few lines */
errno = 0;
* check_data_dir() called opendir - the errno should still be hanging
* around
*/
-
if (errno == ENOENT)
{
printf("creating directory \"%s\" ... ", pg_data);
set_null_conf();
- test_buffers();
-
+ /* test connections first because it has more constraints */
test_connections();
+ test_buffers();
setup_config();
set_short_version(short_version, "base/1");
setup_shadow();
-
if (pwprompt)
- get_set_pw();
+ get_set_pwd();
unlimit_systables();
make_template0();
- printf("\n"
- "Success. You can now start the database server using:\n"
- "\n"
- " \"%s/postmaster\" -D \"%s\"\n"
+ printf("\nSuccess. You can now start the database server using:\n\n"
+ " %s%s%s/postmaster -D %s%s%s\n"
"or\n"
- " \"%s/pg_ctl\" -D \"%s\" -l logfile start\n"
- "\n",
- pgpath, pg_data, pgpath, pg_data);
+ " %s%s%s/pg_ctl -D %s%s%s -l logfile start\n\n",
+ QUOTE_PATH, pgpath, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH,
+ QUOTE_PATH, pgpath, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH);
return 0;
}