]> granicus.if.org Git - postgresql/commitdiff
Add C version of initdb, from Andrew Dunstan.
authorBruce Momjian <bruce@momjian.us>
Mon, 10 Nov 2003 22:51:16 +0000 (22:51 +0000)
committerBruce Momjian <bruce@momjian.us>
Mon, 10 Nov 2003 22:51:16 +0000 (22:51 +0000)
This is his original version with a binary rmdir() we might need in the
future.

I will commit an update version with cleanups shortly.

src/bin/initdb/Makefile
src/bin/initdb/initdb.c [new file with mode: 0644]
src/bin/initdb/initdb.sh [deleted file]
src/bin/initdb/system_views.sql [new file with mode: 0755]

index cd2cb86c36811c2caf68df663ccb2c684e3dd74b..995a37935549dec0fc9595733bfc4bed7338c23d 100644 (file)
@@ -5,7 +5,7 @@
 # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/initdb/Makefile,v 1.29 2003/09/07 03:36:03 tgl Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Makefile,v 1.30 2003/11/10 22:51:16 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -13,25 +13,30 @@ subdir = src/bin/initdb
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-all: initdb
+override CPPFLAGS := -DPGBINDIR=\"$(bindir)\" -DPGDATADIR=\"$(datadir)\" -DFRONTEND -I$(libpq_srcdir) $(CPPFLAGS)
 
-initdb: initdb.sh $(top_builddir)/src/Makefile.global
-       sed -e 's/@VERSION@/$(VERSION)/g' \
-           -e 's,@SHELL@,$(SHELL),g' \
-           -e 's,@HAVE_IPV6@,$(HAVE_IPV6),g' \
-           -e 's,@bindir@,$(bindir),g' \
-           -e 's,@datadir@,$(datadir),g' \
-         $< >$@
-       chmod a+x $@
+OBJS=  initdb.o sprompt.o
+ifeq ($(PORTNAME), win32)
+OBJS+=dirmod.o
+endif
+
+all: submake-libpq submake-libpgport initdb
+
+initdb: $(OBJS) $(libpq_builddir)/libpq.a
+       $(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@
+
+dirmod.c sprompt.c: % : $(top_srcdir)/src/port/%
+       rm -f $@ && $(LN_S) $< .
 
 install: all installdirs
-       $(INSTALL_SCRIPT) initdb $(DESTDIR)$(bindir)/initdb
+       $(INSTALL_PROGRAM) initdb$(X) $(DESTDIR)$(bindir)/initdb$(X)
+       $(INSTALL_DATA) $(srcdir)/system_views.sql $(DESTDIR)$(datadir)/system_views.sql
 
 installdirs:
        $(mkinstalldirs) $(DESTDIR)$(bindir)
 
 uninstall:
-       rm -f $(DESTDIR)$(bindir)/initdb
+       rm -f $(DESTDIR)$(bindir)/initdb$(X) $(DESTDIR)$(datadir)/system_views.sql
 
-clean distclean maintainer-clean:
-       rm -f initdb
+clean distclean:
+       rm -f initdb$(X) $(OBJS)
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
new file mode 100644 (file)
index 0000000..13522be
--- /dev/null
@@ -0,0 +1,2493 @@
+
+/*-------------------------------------------------------------------------
+ *
+ * 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 code is released under the terms of the PostgreSQL License.
+ *
+ * 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 $
+ *
+ * TODO:
+ *      - clean up find_postgres code and return values
+ *
+ * Note:
+ *      The program has some memory leakage - it isn't worth cleaning it up.
+ *      Even before the code was put in to free most of the dynamic memory
+ *      used it ran around 500Kb used + malloc overhead. It should now use
+ *      far less than that (around 240Kb - the size of the BKI file).
+ *      If we can't load this much data into memory how will we ever run
+ *      postgres anyway?
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+#include "getopt_long.h"
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include <signal.h>
+
+#include "libpq/pqsignal.h"
+#include "mb/pg_wchar.h"
+
+
+/* version string we expect back from postgres */
+#define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n"
+
+/* values passed in by makefile define */
+
+char      *bindir = PGBINDIR;
+char      *datadir = PGDATADIR;
+
+/* values to be obtained from arguments */
+
+char      *pg_data = "";
+char      *encoding = "";
+char      *locale = "";
+char      *lc_collate = "";
+char      *lc_ctype = "";
+char      *lc_monetary = "";
+char      *lc_numeric = "";
+char      *lc_time = "";
+char      *lc_messages = "";
+char      *username = "";
+bool           pwprompt = false;
+bool           debug = false;
+bool           noclean = false;
+bool           show_help = false;
+bool           show_version = false;
+bool           show_setting = false;
+
+
+/* internal vars */
+char      *progname;
+char      *self_path;
+char      *postgres;
+char      *encodingid = "0";
+char      *bki_file;
+char      *desc_file;
+char      *hba_file;
+char      *ident_file;
+char      *conf_file;
+char      *conversion_file;
+char      *info_schema_file;
+char      *features_file;
+char      *system_views_file;
+char      *effective_user;
+bool           testpath = true;
+bool           made_new_pgdata = false;
+char           infoversion[100];
+bool           not_ok = false;
+
+/* defaults */
+int                    n_buffers = 50;
+int                    n_connections = 10;
+
+
+/* platform specific path stuff */
+#if defined(__CYGWIN__) || defined(WIN32)
+#define EXE ".exe"
+#define DEVNULL "nul"
+#else
+#define EXE ""
+#define DEVNULL "/dev/null"
+#endif   /* defined(__CYGWIN__) || defined(WIN32) */
+
+#ifdef WIN32
+#define PATHSEP ';'
+#else
+#define PATHSEP ':'
+#endif   /* WIN32 */
+
+/* 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 *);
+
+#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 */
+
+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 bool check_data_dir(void);
+static bool mkdatadir(char *);
+static bool chklocale(const char *);
+static void setlocales(void);
+static void set_input(char **, char *);
+static void check_input(char *path);
+static int     find_postgres(char *);
+static int     set_paths(void);
+static char **replace_token(char **, char *, char *);
+static void set_short_version(char *, char *);
+static void set_null_conf(void);
+static void test_buffers(void);
+static void test_connections(void);
+static void setup_config(void);
+static void bootstrap_template1(char *);
+static void setup_shadow(void);
+static void get_set_pw(void);
+static void unlimit_systables(void);
+static void setup_depend(void);
+static void setup_sysviews(void);
+static void setup_description(void);
+static void setup_conversion(void);
+static void setup_privileges(void);
+static void set_info_version(void);
+static void setup_schema(void);
+static void vacuum_db(void);
+static void make_template0(void);
+static void usage(void);
+static void trapsig(int);
+static void check_ok(void);
+static char *xstrdup(const char *);
+static void *xmalloc(size_t);
+
+/*
+ * 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 {\
+                if (fputs(*line, pg) < 0) \
+                  exit_nicely(); \
+                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
+#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
+ * 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)
+{
+       void       *result;
+
+       result = malloc(size);
+       if (!result)
+       {
+               fputs("malloc failure - bailing out\n", stderr);
+               exit(1);
+       }
+       return result;
+}
+
+static char *
+xstrdup(const char *s)
+{
+       char       *result;
+
+       result = strdup(s);
+       if (!result)
+       {
+               fputs("strdup failure - bailing out\n", stderr);
+               exit(1);
+       }
+       return result;
+}
+
+/*
+ * delete a directory tree recursively
+ * assumes path points to a valid directory
+ * deletes everything under path
+ * if rmtopdir is true deletes the directory too
+ *
+ */
+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;
+
+       /*
+        * 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;
+       }
+
+       return true;
+}
+
+
+/*
+ * make all paths look like unix, with forward slashes
+ * also strip any trailing slash
+ */
+
+static void
+canonicalise_path(char *path)
+{
+       char       *p;
+
+       for (p = path; *p; p++)
+       {
+#ifdef WIN32
+               if (*p == '\\')
+                       *p = '/';
+#endif   /* WIN32 */
+       }
+       if (p != path && *--p == '/')
+               *p = '\0';
+}
+
+/*
+ * make a copy of the array of lines, with token replaced by replacement
+ * the first time it occurs on each line.
+ * 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)
+{
+       int                     numlines = 1;
+       int                     i;
+       char      **result;
+       int                     toklen,
+                               replen,
+                               diff;
+
+
+       for (i = 0; lines[i]; i++)
+               numlines++;
+
+       result = (char **) xmalloc(numlines * sizeof(char *));
+
+       toklen = strlen(token);
+       replen = strlen(replacement);
+       diff = replen - toklen;
+
+       for (i = 0; i < numlines; i++)
+       {
+               char       *where;
+               char       *newline;
+               int                     pre;
+
+               /* just copy pointer if NULL or no change needed */
+
+               if (lines[i] == NULL || (where = strstr(lines[i], token)) == NULL)
+               {
+                       result[i] = lines[i];
+                       continue;
+               }
+
+               /* if we get here a change is needed - set up new line */
+
+               newline = (char *) xmalloc(strlen(lines[i]) + diff + 1);
+
+               pre = where - lines[i];
+
+               strncpy(newline, lines[i], pre);
+
+               strcpy(newline + pre, replacement);
+
+               strcpy(newline + pre + replen, lines[i] + pre + toklen);
+
+               result[i] = newline;
+
+       }
+
+       return result;
+
+}
+
+/*
+ * get the lines from a text file
+ *
+ */
+static char **
+readfile(char *path)
+{
+       FILE       *infile;
+       int                     maxlength = 0,
+                               linelen = 0;
+       int                     nlines = 0;
+       char      **result;
+       char       *buffer;
+       int                     c;
+
+       infile = fopen(path, "r");
+
+       if (!infile)
+       {
+               fprintf(stderr, "could not read %s ... ", path);
+               exit_nicely();
+       }
+
+       /* pass over the file twice - the first time to size the result */
+
+       while ((c = fgetc(infile)) != EOF)
+       {
+               linelen++;
+               if (c == '\n')
+               {
+                       nlines++;
+                       if (linelen > maxlength)
+                               maxlength = linelen;
+                       linelen = 0;
+               }
+       }
+
+       /* handle last line without a terminating newline (yuck) */
+
+       if (linelen)
+               nlines++;
+       if (linelen > maxlength)
+               maxlength = linelen;
+
+       /* set up the result and the line buffer */
+
+       result = (char **) xmalloc((nlines + 2) * sizeof(char *));
+       buffer = (char *) xmalloc(maxlength + 2);
+
+       /* now reprocess the file and store the lines */
+
+       rewind(infile);
+       nlines = 0;
+       while (fgets(buffer, maxlength + 1, infile) != NULL)
+       {
+               result[nlines] = xstrdup(buffer);
+               nlines++;
+       }
+
+       fclose(infile);
+       result[nlines] = NULL;
+
+       return result;
+}
+
+/*
+ * write an array of lines to a file
+ *
+ */
+static void
+writefile(char *path, char **lines)
+{
+       FILE       *out_file;
+       char      **line;
+
+       out_file = fopen(path, PG_BINARY_W);
+       if (out_file == NULL)
+       {
+               fprintf(stderr, "could not write %s ... ", path);
+               exit_nicely();
+       }
+       for (line = lines; *line != NULL; line++)
+       {
+               if (fputs(*line, out_file) < 0)
+                       exit_nicely();
+               free(*line);
+       }
+       if (fclose(out_file))
+               exit_nicely();
+}
+
+/* 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.
+ *
+ */
+
+static int
+build_path(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   /* WIN32 */
+
+       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 (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 cased 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);
+               if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
+               {
+                       if (errno == EEXIST || errno == EISDIR)
+                       {
+                               if (stat(path, &sb) < 0)
+                               {
+                                       retval = 1;
+                                       break;
+                               }
+                               else if (!S_ISDIR(sb.st_mode))
+                               {
+                                       if (last)
+                                               errno = EEXIST;
+                                       else
+                                               errno = ENOTDIR;
+                                       retval = 1;
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               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
+ *
+ */
+static void
+exit_nicely(void)
+{
+       fprintf(stderr, "%s: failed\n", progname);
+
+       if (!noclean)
+       {
+               if (made_new_pgdata)
+               {
+                       fprintf(stderr, "%s: removing data directory \"%s\"\n",
+                                       progname, pg_data);
+                       if (!rmtree(pg_data, true))
+                               fprintf(stderr, "%s: failed\n", progname);
+               }
+               else
+               {
+                       fprintf(stderr,
+                                       "%s: removing contents of data directory \"%s\"\n",
+                                       progname, pg_data);
+                       if (!rmtree(pg_data, false))
+                               fprintf(stderr, "%s: failed\n", progname);
+               }
+       }
+       exit(1);
+}
+
+/*
+ * find the current user using code lifted from pg_id.c
+ * on unix make sure it isn't really root
+ *
+ */
+static char *
+get_id(void)
+{
+#ifndef WIN32
+
+       struct passwd *pw;
+
+       pw = getpwuid(getuid());
+
+#ifndef __BEOS__                               /* no root check on BEOS */
+
+       if (!geteuid())                         /* 0 is root's uid */
+       {
+               fprintf(stderr,
+                               "%s: cannot be run as root\n"
+                        "Please log in (using, e.g., \"su\") as the (unprivileged) "
+                               "user that will\n" "own the server process.\n",
+                               progname);
+               exit(1);
+       }
+#endif   /* __BEOS__ */
+
+#else                                                  /* the windows code */
+
+       struct passwd_win32
+       {
+               int                     pw_uid;
+               char            pw_name[128];
+       }                       pass_win32;
+       struct passwd_win32 *pw = &pass_win32;
+       DWORD           pwname_size = sizeof(pass_win32.pw_name) - 1;
+
+       pw->pw_uid = 1;
+       GetUserName(pw->pw_name, &pwname_size);
+#endif   /* ! WIN32 */
+
+       return xstrdup(pw->pw_name);
+}
+
+/*
+ * get the encoding id for a given encoding name
+ *
+ */
+static char *
+get_encoding_id(char *encoding_name)
+{
+       int                     enc;
+       char            result[20];
+
+       if (encoding_name && *encoding_name)
+       {
+               if ((enc = pg_char_to_encoding(encoding_name)) >= 0 &&
+                       pg_valid_server_encoding(encoding_name) >= 0)
+               {
+                       sprintf(result, "%d", enc);
+                       return xstrdup(result);
+               }
+       }
+       fprintf(stderr, "%s: \"%s\" is not a valid server encoding name\n",
+                       progname, encoding_name ? encoding_name : "(null)");
+       exit(1);
+}
+
+/*
+ * get short version of VERSION
+ *
+ */
+static char *
+get_short_version(void)
+{
+       bool            gotdot = false;
+       int                     end;
+       char       *vr;
+
+       vr = xstrdup(PG_VERSION);
+
+       for (end = 0; vr[end] != '\0'; end++)
+       {
+               if (vr[end] == '.')
+               {
+                       if (end == 0)
+                               return NULL;
+                       else if (gotdot)
+                               break;
+                       else
+                               gotdot = true;
+               }
+               else if (vr[end] < '0' || vr[end] > '9')
+               {
+                       /* gone past digits and dots */
+                       break;
+               }
+       }
+       if (end == 0 || vr[end - 1] == '.' || !gotdot)
+               return NULL;
+
+       vr[end] = '\0';
+       return vr;
+}
+
+/*
+ * make sure the data directory either doesn't exist or is empty
+ *
+ */
+static bool
+check_data_dir(void)
+{
+       DIR                *chkdir;
+       struct dirent *file;
+       bool            empty = true;
+
+       chkdir = opendir(pg_data);
+
+       if (!chkdir)
+               return (errno == ENOENT);
+
+       while ((file = readdir(chkdir)) != NULL)
+       {
+               if (strcmp(".", file->d_name) == 0 || strcmp("..", file->d_name) == 0)
+               {
+                       /* skip this and parent directory */
+                       continue;
+               }
+               else
+               {
+                       empty = false;
+                       break;
+               }
+       }
+
+       closedir(chkdir);
+
+       return (empty);
+}
+
+/*
+ * make the data directory (or one of its subdirectories if subdir is not NULL)
+ *
+ */
+static bool
+mkdatadir(char *subdir)
+{
+       char       *path;
+       int                     res;
+
+       path = xmalloc(strlen(pg_data) + 2 +
+                                  (subdir == NULL ? 0 : strlen(subdir)));
+
+       if (subdir != NULL)
+               sprintf(path, "%s/%s", pg_data, subdir);
+       else
+               strcpy(path, pg_data);
+
+       res = mkdir(path, 0700);
+       if (res == 0)
+               return true;
+       else if (subdir == NULL || errno != ENOENT)
+               return false;
+       else
+               return !build_path(path, 0700);
+}
+
+
+/*
+ * set name of given input file variable under data directory
+ *
+ */
+static void
+set_input(char **dest, char *filename)
+{
+       *dest = xmalloc(strlen(datadir) + strlen(filename) + 2);
+       sprintf(*dest, "%s/%s", datadir, filename);
+}
+
+/*
+ * check that given input file exists
+ *
+ */
+static void
+check_input(char *path)
+{
+       struct stat statbuf;
+
+       if (stat(path, &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
+       {
+               fprintf(stderr,
+                               "%s: file \"%s\" not found\n"
+                  "This means you have a corrupted installation or identified\n"
+                               "the wrong directory with the invocation option -L.\n",
+                               progname, path);
+               exit(1);
+       }
+
+}
+
+/*
+ * TODO - clean this up and handle the errors properly
+ * don't overkill
+ *
+ */
+
+#define FIND_SUCCESS 0
+#define FIND_NOT_FOUND 1
+#define FIND_STAT_ERR 2
+#define FIND_NOT_REGFILE 3
+#define FIND_BAD_PERM 4
+#define FIND_EXEC_ERR 5
+#define FIND_WRONG_VERSION 6
+
+/*
+ * see if there is a postgres executable in the given path, and giving the
+ * right version number
+ *
+ */
+static int
+find_postgres(char *path)
+{
+       char            fn[MAXPGPATH];
+       char            cmd[MAXPGPATH];
+       char            line[100];
+
+#ifndef WIN32
+
+       int                     permmask = S_IROTH | S_IXOTH;
+#endif
+
+
+       struct stat statbuf;
+       FILE       *pgver;
+       int                     plen = strlen(path);
+
+       if (path[plen - 1] != '/')
+               snprintf(fn, MAXPGPATH, "%s/postgres%s", path, EXE);
+       else
+               snprintf(fn, MAXPGPATH, "%spostgres%s", path, EXE);
+
+       if (stat(fn, &statbuf) != 0)
+       {
+               if (errno == ENOENT)
+                       return FIND_NOT_FOUND;
+               else
+                       return FIND_STAT_ERR;
+       }
+       if (!S_ISREG(statbuf.st_mode))
+               return FIND_NOT_REGFILE;
+
+#ifndef WIN32
+
+       /* on windows a .exe file should be executable - this is the unix test */
+
+       if ((statbuf.st_mode & permmask) != permmask)
+               return FIND_BAD_PERM;
+#endif   /* ! WIN32 */
+
+       snprintf(cmd, MAXPGPATH, "\"%s/postgres\" -V 2>%s", path, DEVNULL);
+
+       if ((pgver = popen(cmd, "r")) == NULL)
+               return FIND_EXEC_ERR;
+
+       if (fgets(line, sizeof(line), pgver) == NULL)
+       {
+               perror("fgets failure");
+
+       }
+
+       pclose(pgver);
+
+       if (strcmp(line, PG_VERSIONSTR) != 0)
+               return FIND_WRONG_VERSION;
+
+       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
+ *
+ */
+
+static char *
+expanded_path(char *path)
+{
+       char            abspath[MAXPGPATH];
+
+       if (_fullpath(abspath, path, MAXPGPATH) == NULL)
+       {
+               perror("expanded path");
+               return path;
+       }
+       canonicalise_path(abspath);
+       return xstrdup(abspath);
+}
+#endif   /* WIN32 */
+
+/*
+ * set the paths pointing to postgres
+ * look for it in the same place we found this program, or in the environment
+ * path, or in the configured bindir.
+ *
+ */
+static int
+set_paths(void)
+{
+       if (testpath && !self_path)
+       {
+
+               char       *path,
+                                  *cursor;
+               int                     pathlen,
+                                       i,
+                                       pathsegs;
+               char      **pathbits;
+               char            buf[MAXPGPATH];
+               struct stat statbuf;
+
+               path = xstrdup(getenv("PATH"));
+               pathlen = strlen(path);
+
+               for (i = 0, pathsegs = 1; i < pathlen; i++)
+               {
+                       if (path[i] == PATHSEP)
+                               pathsegs++;
+               }
+
+               pathbits = (char **) xmalloc(pathsegs * sizeof(char *));
+               for (i = 0, pathsegs = 0, cursor = path; i <= pathlen; i++)
+               {
+                       if (path[i] == PATHSEP || path[i] == 0)
+                       {
+                               path[i] = 0;
+                               if (strlen(cursor) == 0)
+                               {
+                                       /* empty path segment means current directory */
+                                       pathbits[pathsegs] = xstrdup(".");
+                               }
+                               else
+                               {
+                                       canonicalise_path(cursor);
+                                       pathbits[pathsegs] = cursor;
+                               }
+                               pathsegs++;
+                               cursor = path + i + 1;
+                       }
+               }
+
+               for (i = 0; i < pathsegs; i++)
+               {
+                       snprintf(buf, MAXPGPATH, "%s/%s%s", pathbits[i], progname, EXE);
+                       if (stat(buf, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
+                       {
+                               self_path = pathbits[i];
+                               break;
+                       }
+               }
+       }
+
+       if (testpath && self_path &&
+               (find_postgres(expanded_path(self_path)) == 0))
+       {
+               /* we found postgres on out own path */
+               pgpath = expanded_path(self_path);
+       }
+       else
+       {
+               /* look in the hardcoded bindir */
+               int                     res;
+               char       *cbindir;
+
+               cbindir = xstrdup(bindir);
+               canonicalise_path(cbindir);
+               res = find_postgres(expanded_path(cbindir));
+               if (res == 0)
+                       pgpath = expanded_path(cbindir);
+               else
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * write out the PG_VERSION file in the data dir, or its subdirectory
+ * if extrapath is not NULL
+ *
+ */
+static void
+set_short_version(char *short_version, char *extrapath)
+{
+       FILE       *version_file;
+       char       *path;
+
+       if (extrapath == NULL)
+       {
+               path = xmalloc(strlen(pg_data) + 12);
+               sprintf(path, "%s/PG_VERSION", pg_data);
+       }
+       else
+       {
+               path = xmalloc(strlen(pg_data) + strlen(extrapath) + 13);
+               sprintf(path, "%s/%s/PG_VERSION", pg_data, extrapath);
+       }
+       version_file = fopen(path, PG_BINARY_W);
+       fprintf(version_file, "%s\n", short_version);
+       fclose(version_file);
+}
+
+/*
+ * set up an empty config file so we can check buffers and connections
+ *
+ */
+static void
+set_null_conf(void)
+{
+       FILE       *conf_file;
+       char       *path;
+
+       path = xmalloc(strlen(pg_data) + 17);
+       sprintf(path, "%s/postgresql.conf", pg_data);
+       conf_file = fopen(path, PG_BINARY_W);
+       fclose(conf_file);
+}
+
+/*
+ * check how many buffers we can run with
+ *
+ */
+static void
+test_buffers(void)
+{
+       char       *format =
+       "\"%s/postgres\"  -boot -x 0 -F "
+       "-c shared_buffers=%d -c max_connections=5 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                     i,
+                               status;
+
+       for (i = 0; i < len; i++)
+       {
+               snprintf(cmd, sizeof(cmd), format, pgpath, bufs[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);
+}
+
+/*
+ * check how many connections we can sustain
+ *
+ */
+static void
+test_connections(void)
+{
+       char       *format =
+       "\"%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                     i,
+                               status;
+
+       for (i = 0; i < len; i++)
+       {
+               snprintf(cmd, sizeof(cmd), format,
+                                pgpath, n_buffers, conns[i], 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);
+}
+
+/*
+ * set up all the config files
+ *
+ */
+static void
+setup_config(void)
+{
+
+       char      **conflines;
+       char            repltok[100];
+       char            path[MAXPGPATH];
+
+       fputs("creating configuration files ... ", stdout);
+
+       /* postgresql.conf */
+
+       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), "lc_messages = '%s'", lc_messages);
+       conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
+
+       snprintf(repltok, sizeof(repltok), "lc_monetary = '%s'", lc_monetary);
+       conflines = replace_token(conflines, "#lc_monetary = 'C'", repltok);
+
+       snprintf(repltok, sizeof(repltok), "lc_numeric = '%s'", lc_numeric);
+
+       conflines = replace_token(conflines, "#lc_numeric = 'C'", repltok);
+
+       snprintf(repltok, sizeof(repltok), "lc_time = '%s'", lc_time);
+       conflines = replace_token(conflines, "#lc_time = 'C'", repltok);
+
+       snprintf(path, MAXPGPATH, "%s/postgresql.conf", pg_data);
+
+       writefile(path, conflines);
+       chmod(path, 0600);
+
+       free(conflines);
+
+
+       /* pg_hba.conf */
+
+       conflines = readfile(hba_file);
+
+#ifndef HAVE_IPV6
+       conflines = replace_token(conflines,
+                                                         "host    all         all         ::1",
+                                                         "#host    all         all         ::1");
+#endif   /* ! HAVE_IPV6 */
+
+       snprintf(path, MAXPGPATH, "%s/pg_hba.conf", pg_data);
+
+       writefile(path, conflines);
+       chmod(path, 0600);
+
+       free(conflines);
+
+       /* pg_ident.conf */
+
+       conflines = readfile(ident_file);
+
+       snprintf(path, MAXPGPATH, "%s/pg_ident.conf", pg_data);
+
+       writefile(path, conflines);
+       chmod(path, 0600);
+
+       free(conflines);
+
+       check_ok();
+
+}
+
+
+/*
+ * run the bootstrap code
+ *
+ */
+static void
+bootstrap_template1(char *short_version)
+{
+       char       *talkargs = "";
+       char      **bki_lines;
+       char            headerline[MAXPGPATH];
+
+       PG_CMD_DECL;
+
+       printf("creating template1 database in %s/base/1 ... ", pg_data);
+
+       if (debug)
+               talkargs = "-d 5";
+
+       bki_lines = readfile(bki_file);
+
+       snprintf(headerline, MAXPGPATH, "# PostgreSQL %s\n", short_version);
+
+       if (strcmp(headerline, *bki_lines) != 0)
+       {
+               fprintf(stderr,
+                               "%s: input file \"%s\" does not belong to PostgreSQL %s\n"
+                               "Check your installation or specify the correct path "
+                               "using the option -L.\n",
+                               progname, bki_file, PG_VERSION);
+               exit_nicely();
+
+       }
+
+       bki_lines = replace_token(bki_lines, "POSTGRES", effective_user);
+
+       bki_lines = replace_token(bki_lines, "ENCODING", encodingid);
+
+       /*
+        * we could save the old environment here, and restore it afterwards,
+        * but there doesn't seem to be any point, especially as we have
+        * already called setlocale().
+        *
+        */
+
+       snprintf(cmd, MAXPGPATH, "LC_COLLATE=%s", lc_collate);
+       putenv(xstrdup(cmd));
+
+       snprintf(cmd, MAXPGPATH, "LC_CTYPE=%s", lc_ctype);
+       putenv(xstrdup(cmd));
+
+       putenv("LC_ALL");
+
+       snprintf(cmd, MAXPGPATH,
+               " \"%s/postgres\"  -boot -x1 -F %s template1", pgpath, talkargs);
+
+       PG_CMD_OPEN;
+
+       for (line = bki_lines; *line != NULL; line++)
+       {
+               PG_CMD_PUTLINE;
+               free(*line);
+       }
+
+       PG_CMD_CLOSE;
+
+       free(bki_lines);
+
+       check_ok();
+}
+
+/*
+ * set up the shadow password table
+ *
+ */
+static void
+setup_shadow(void)
+{
+
+       char       *pg_shadow_setup[] = {
+               /*
+                * Create a trigger so that direct updates to pg_shadow will be
+                * written to the flat password/group files pg_pwd and pg_group
+                */
+               "CREATE TRIGGER pg_sync_pg_pwd "
+               "  AFTER INSERT OR UPDATE OR DELETE ON pg_shadow "
+               "  FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();\n",
+               "CREATE TRIGGER pg_sync_pg_group "
+               "  AFTER INSERT OR UPDATE OR DELETE ON pg_group "
+               "  FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();\n",
+
+               /*
+                * needs to be done before alter user, because alter user checks
+                * that pg_shadow is secure ...
+                */
+               "REVOKE ALL on pg_shadow FROM public;\n",
+               NULL
+       };
+
+       PG_CMD_DECL;
+
+       fputs("initializing pg_shadow ... ", stdout);
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s",
+                        pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       for (line = pg_shadow_setup; *line != NULL; line++)
+               PG_CMD_PUTLINE;
+
+       PG_CMD_CLOSE;
+
+       check_ok();
+}
+
+/*
+ * get the superuser password if required, and call postgres to set it
+ *
+ */
+static void
+get_set_pw(void)
+{
+       PG_CMD_DECL_NOLINE;
+
+       char       *pw1,
+                          *pw2;
+       char            pwpath[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)
+       {
+               fprintf(stderr, "Passwords didn't match.\n");
+               exit_nicely();
+       }
+       free(pw2);
+
+       printf("storing the password ... ");
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s", pgpath, DEVNULL);
+
+
+       PG_CMD_OPEN;
+
+       if (fprintf(
+          pg, "ALTER USER \"%s\" WITH PASSWORD '%s';\n", username, pw1) < 0)
+       {
+               /* write failure */
+               exit_nicely();
+       }
+       fflush(pg);
+
+       PG_CMD_CLOSE;
+
+       snprintf(pwpath, MAXPGPATH, "%s/global/pg_pwd", pg_data);
+       if (stat(pwpath, &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
+       {
+               fprintf(stderr,
+                               "%s: The password file was not generated - "
+                               "please report this problem\n",
+                               progname);
+               exit_nicely();
+       }
+
+       check_ok();
+}
+
+/*
+ * toast sys tables
+ *
+ */
+static void
+unlimit_systables(void)
+{
+       char       *systables_setup[] = {
+               "ALTER TABLE pg_attrdef CREATE TOAST TABLE;\n",
+               "ALTER TABLE pg_constraint CREATE TOAST TABLE;\n",
+               "ALTER TABLE pg_database CREATE TOAST TABLE;\n",
+               "ALTER TABLE pg_description CREATE TOAST TABLE;\n",
+               "ALTER TABLE pg_group CREATE TOAST TABLE;\n",
+               "ALTER TABLE pg_proc CREATE TOAST TABLE;\n",
+               "ALTER TABLE pg_rewrite CREATE TOAST TABLE;\n",
+               "ALTER TABLE pg_shadow CREATE TOAST TABLE;\n",
+               "ALTER TABLE pg_statistic CREATE TOAST TABLE;\n",
+               NULL
+       };
+
+       PG_CMD_DECL;
+
+       fputs("enabling unlimited row size for system tables ... ", stdout);
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s", pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       for (line = systables_setup; *line != NULL; line++)
+               PG_CMD_PUTLINE;
+
+       PG_CMD_CLOSE;
+
+       check_ok();
+}
+
+/*
+ * set up pg_depend
+ *
+ */
+static void
+setup_depend(void)
+{
+       char       *pg_depend_setup[] = {
+               /*
+                * Make PIN entries in pg_depend for all objects made so far in
+                * the tables that the dependency code handles.  This is overkill
+                * (the system doesn't really depend on having every last weird
+                * datatype, for instance) but generating only the minimum
+                * required set of dependencies seems hard. Note that we
+                * deliberately do not pin the system views. First delete any
+                * already-made entries; PINs override all else, and must be the
+                * only entries for their objects.
+                */
+               "DELETE FROM pg_depend;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_class;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_proc;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_type;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_cast;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_constraint;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_attrdef;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_language;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_operator;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_opclass;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_rewrite;\n",
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_trigger;\n",
+
+               /*
+                * restriction here to avoid pinning the public namespace
+                */
+               "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
+               " FROM pg_namespace "
+               "    WHERE nspname LIKE 'pg%';\n",
+               NULL
+       };
+
+       PG_CMD_DECL;
+
+       fputs("initializing pg_depend ... ", stdout);
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s",
+                        pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       for (line = pg_depend_setup; *line != NULL; line++)
+               PG_CMD_PUTLINE;
+
+       PG_CMD_CLOSE;
+
+       check_ok();
+}
+
+/*
+ * set up system views
+ *
+ */
+static void
+setup_sysviews(void)
+{
+       PG_CMD_DECL;
+
+       char      **sysviews_setup;
+
+       fputs("creating system views ... ", stdout);
+
+       sysviews_setup = readfile(system_views_file);
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -N -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s",
+                        pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       for (line = sysviews_setup; *line != NULL; line++)
+       {
+               PG_CMD_PUTLINE;
+               free(*line);
+       }
+
+       PG_CMD_CLOSE;
+
+       free(sysviews_setup);
+
+       check_ok();
+}
+
+/*
+ * load description data
+ *
+ */
+static void
+setup_description(void)
+{
+       char       *pg_description_setup1[] = {
+               "CREATE TEMP TABLE tmp_pg_description ( "
+               "       objoid oid, "
+               "       classname name, "
+               "       objsubid int4, "
+               "       description text) WITHOUT OIDS;\n",
+               "COPY tmp_pg_description FROM STDIN;\n",
+               NULL
+       };
+
+       char       *pg_description_setup2[] = {
+               "\\.\n",
+               "INSERT INTO pg_description "
+               " SELECT t.objoid, c.oid, t.objsubid, t.description "
+               "  FROM tmp_pg_description t, pg_class c "
+               "    WHERE c.relname = t.classname;\n",
+               NULL
+       };
+
+
+       PG_CMD_DECL;
+
+       char      **desc_lines;
+
+       fputs("loading pg_description ... ", stdout);
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s",
+                        pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       for (line = pg_description_setup1; *line != NULL; line++)
+               PG_CMD_PUTLINE;
+
+       desc_lines = readfile(desc_file);
+       for (line = desc_lines; *line != NULL; line++)
+       {
+               PG_CMD_PUTLINE;
+               free(*line);
+       }
+
+       free(desc_lines);
+
+
+       for (line = pg_description_setup2; *line != NULL; line++)
+               PG_CMD_PUTLINE;
+
+       PG_CMD_CLOSE;
+
+       check_ok();
+}
+
+/*
+ * load conversion functions
+ *
+ */
+static void
+setup_conversion(void)
+{
+       PG_CMD_DECL;
+
+       char      **conv_lines;
+
+       fputs("creating conversions ... ", stdout);
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s",
+                        pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       conv_lines = readfile(conversion_file);
+       for (line = conv_lines; *line != NULL; line++)
+       {
+               if (strstr(*line, "DROP CONVERSION") != *line)
+                       PG_CMD_PUTLINE;
+
+               free(*line);
+       }
+
+       free(conv_lines);
+
+       PG_CMD_CLOSE;
+
+       check_ok();
+}
+
+/*
+ * run privileges script
+ *
+ */
+static void
+setup_privileges(void)
+{
+       char       *privileges_setup[] = {
+               "UPDATE pg_class "
+               "  SET relacl = '{\"=r/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
+               "  WHERE relkind IN ('r', 'v', 'S') AND relacl IS NULL;\n",
+               "UPDATE pg_proc "
+               "  SET proacl = '{\"=X/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
+               "  WHERE proacl IS NULL;\n",
+               "UPDATE pg_language "
+               "  SET lanacl = '{\"=U/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
+               "  WHERE lanpltrusted;\n",
+               "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n",
+               "GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n",
+               NULL
+       };
+
+       PG_CMD_DECL;
+
+       char      **priv_lines;
+
+       fputs("setting privileges on builtin objects ... ", stdout);
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s",
+                        pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       priv_lines = replace_token(privileges_setup,
+                                                          "$POSTGRES_SUPERUSERNAME", username);
+       for (line = priv_lines; *line != NULL; line++)
+               PG_CMD_PUTLINE;
+
+       PG_CMD_CLOSE;
+
+       check_ok();
+}
+
+/*
+ * extract the strange version of version required for info schema
+ *
+ */
+static void
+set_info_version(void)
+{
+       char       *letterversion;
+       long            major = 0,
+                               minor = 0,
+                               micro = 0;
+       char       *endptr;
+       char       *vstr = xstrdup(PG_VERSION);
+       char       *ptr;
+
+       ptr = vstr + (strlen(vstr) - 1);
+       while (ptr != vstr && (*ptr < '0' || *ptr > '9'))
+               ptr--;
+       letterversion = ptr + 1;
+       major = strtol(vstr, &endptr, 10);
+       if (*endptr)
+               minor = strtol(endptr + 1, &endptr, 10);
+       if (*endptr)
+               micro = strtol(endptr + 1, &endptr, 10);
+       snprintf(infoversion, sizeof(infoversion), "%02ld.%02ld.%04ld%s",
+                        major, minor, micro, letterversion);
+}
+
+/*
+ * load info schema and populate from features file
+ *
+ */
+static void
+setup_schema(void)
+{
+
+       PG_CMD_DECL;
+
+       char      **lines;
+       int                     fres;
+
+       fputs("creating information schema ... ", stdout);
+
+       lines = readfile(info_schema_file);
+
+       /*
+        * note that here we don't run in single line mode, unlike other
+        * places
+        */
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true -N template1 >%s",
+                        pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       for (line = lines; *line != NULL; line++)
+       {
+               PG_CMD_PUTLINE;
+               free(*line);
+       }
+
+       free(lines);
+
+       PG_CMD_CLOSE;
+
+       lines = readfile(features_file);
+
+       /*
+        * strip CR before NL this is the only place we do this  (following
+        * the shell script) - we could do it universally in readfile() if
+        * necessary
+        *
+        */
+       lines = replace_token(lines, "\r\n", "\n");
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s",
+                        pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       fres = fprintf(pg,
+                                  "UPDATE information_schema.sql_implementation_info "
+                                  "  SET character_value = '%s' "
+                                  "  WHERE implementation_info_name = 'DBMS VERSION';\n",
+                                  infoversion);
+
+       if (fres < 0)
+               exit_nicely();
+
+       fres = fputs("COPY information_schema.sql_features "
+                                "  (feature_id, feature_name, sub_feature_id, "
+                                "  sub_feature_name, is_supported, comments) "
+                                "FROM STDIN;\n",
+                                pg);
+
+       if (fres < 0)
+               exit_nicely();
+
+       for (line = lines; *line != NULL; line++)
+       {
+               PG_CMD_PUTLINE;
+               free(*line);
+       }
+
+       free(lines);
+
+       if (fputs("\\.\n", pg) < 0)
+               exit_nicely();
+       fflush(pg);
+
+       PG_CMD_CLOSE;
+
+       check_ok();
+}
+
+/*
+ * clean everything up in template1
+ *
+ */
+static void
+vacuum_db(void)
+{
+       PG_CMD_DECL_NOLINE;
+
+       fputs("vacuuming database template1 ... ", stdout);
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s",
+                        pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       if (fputs("ANALYSE;\nVACUUM FULL FREEZE;\n", pg) < 0)
+               exit_nicely();
+       fflush(pg);
+
+       PG_CMD_CLOSE;
+
+       check_ok();
+
+}
+
+/*
+ * copy template1 to template0
+ *
+ */
+static void
+make_template0(void)
+{
+       char       *template0_setup[] = {
+               "CREATE DATABASE template0;\n",
+               "UPDATE pg_database SET "
+               "       datistemplate = 't', "
+               "       datallowconn = 'f' "
+               "    WHERE datname = 'template0';\n",
+
+               /*
+                * We use the OID of template0 to determine lastsysoid
+                *
+                */
+               "UPDATE pg_database SET datlastsysoid = "
+               "    (SELECT oid::int4 - 1 FROM pg_database "
+               "    WHERE datname = 'template0');\n",
+
+               /*
+                * Explicitly revoke public create-schema and create-temp-table
+                * privileges in template1 and template0; else the latter would be
+                * on by default
+                */
+               "REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n",
+               "REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n",
+
+               /*
+                * Finally vacuum to clean up dead rows in pg_database
+                */
+               "VACUUM FULL pg_database;\n",
+               NULL
+       };
+
+       PG_CMD_DECL;
+
+       fputs("copying template1 to template0 ... ", stdout);
+
+       snprintf(cmd, MAXPGPATH,
+                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
+                        "-c exit_on_error=true template1 >%s",
+                        pgpath, DEVNULL);
+
+       PG_CMD_OPEN;
+
+       for (line = template0_setup; *line; line++)
+               PG_CMD_PUTLINE;
+
+       PG_CMD_CLOSE;
+
+       check_ok();
+}
+
+
+/*
+ * signal handler in case we are interrupted.
+ *
+ * The Windows runtime docs at
+ * http://msdn.microsoft.com/library/en-us/vclib/html/_crt_signal.asp
+ * specifically forbid a number of things being done from a signal handler,
+ * including IO, memory allocation and system calls, and only allow jmpbuf
+ * if you are handling SIGFPE.
+ *
+ * I avoided doing the forbidden things by setting a flag instead of calling
+ * exit_nicely() directly.
+ *
+ * Also note the behaviour of Windows with SIGINT, which says this:
+ *      Note   SIGINT is not supported for any Win32 application, including
+ *      Windows 98/Me and Windows NT/2000/XP. When a CTRL+C interrupt occurs,
+ *      Win32 operating systems generate a new thread to specifically handle
+ *      that interrupt. This can cause a single-thread application such as UNIX,
+ *      to become multithreaded, resulting in unexpected behavior.
+ *
+ * I have no idea how to handle this. (Strange they call UNIX an application!)
+ * So this will need some testing on Windows.
+ *
+ */
+
+static void
+trapsig(int signum)
+{
+       /* handle systems that reset the handler, like Windows (grr) */
+       pqsignal(signum, trapsig);
+       not_ok = true;
+}
+
+/*
+ * call exit_nicely() if we got a signal, or else output "ok".
+ *
+ */
+static void
+check_ok()
+{
+       if (not_ok)
+       {
+               puts("Caught Signal.");
+               exit_nicely();
+       }
+       else
+       {
+               /* no signal caught */
+               puts("ok");
+       }
+}
+
+
+/*
+ * check if given string is a valid locle specifier
+ * based on some code given to me by Peter Eisentraut
+ * (but I take responsibility for it :-)
+ */
+static bool
+chklocale(const char *locale)
+{
+       bool            ret;
+       int                     category = LC_CTYPE;
+       char       *save;
+
+       save = setlocale(category, NULL);
+       if (!save)
+               return false;                   /* should not happen; */
+
+       save = xstrdup(save);
+
+       ret = (setlocale(category, locale) != NULL);
+
+       setlocale(category, save);
+       free(save);
+
+       /* should we exit here? */
+       if (!ret)
+               fprintf(stderr, "%s: invalid locale name \"%s\"\n", progname, locale);
+
+       return ret;
+}
+
+/*
+ * set up the locale variables
+ * assumes we have called setlocale(LC_ALL,"")
+ *
+ */
+static void
+setlocales(void)
+{
+       /* set empty lc_* values to locale config if set */
+
+       if (strlen(locale) > 0)
+       {
+               if (strlen(lc_ctype) == 0)
+                       lc_ctype = locale;
+               if (strlen(lc_collate) == 0)
+                       lc_collate = locale;
+               if (strlen(lc_numeric) == 0)
+                       lc_numeric = locale;
+               if (strlen(lc_time) == 0)
+                       lc_time = locale;
+               if (strlen(lc_monetary) == 0)
+                       lc_monetary = locale;
+               if (strlen(lc_messages) == 0)
+                       lc_messages = locale;
+       }
+
+       /*
+        * override absent/invalid config settings from initdb's locale
+        * settings
+        */
+
+       if (strlen(lc_ctype) == 0 || !chklocale(lc_ctype))
+               lc_ctype = xstrdup(setlocale(LC_CTYPE, NULL));
+       if (strlen(lc_collate) == 0 || !chklocale(lc_collate))
+               lc_collate = xstrdup(setlocale(LC_COLLATE, NULL));
+       if (strlen(lc_numeric) == 0 || !chklocale(lc_numeric))
+               lc_numeric = xstrdup(setlocale(LC_NUMERIC, NULL));
+       if (strlen(lc_time) == 0 || !chklocale(lc_time))
+               lc_time = xstrdup(setlocale(LC_TIME, NULL));
+       if (strlen(lc_monetary) == 0 || !chklocale(lc_monetary))
+               lc_monetary = xstrdup(setlocale(LC_MONETARY, NULL));
+       if (strlen(lc_messages) == 0 || !chklocale(lc_messages))
+#ifdef LC_MESSAGES
+       {
+               /* when available get the current locale setting */
+               lc_messages = xstrdup(setlocale(LC_MESSAGES, NULL));
+       }
+#else
+       {
+               /* when not available, get the CTYPE setting */
+               lc_messages = xstrdup(setlocale(LC_CTYPE, NULL));
+       }
+#endif   /* LC_MESSAGES */
+
+}
+
+/*
+ * help text data
+ *
+ */
+
+char      *usage_text[] = {
+       "$CMDNAME initializes a PostgreSQL database cluster.\n",
+       "\n",
+       "Usage:\n",
+       "  $CMDNAME [OPTION]... [DATADIR]\n",
+       "\n",
+       "Options:\n",
+       " [-D, --pgdata=]DATADIR     location for this database cluster\n",
+       "  -E, --encoding=ENCODING   set default encoding for new databases\n",
+       "  --locale=LOCALE           initialize database cluster with given locale\n",
+       "  --lc-collate, --lc-ctype, --lc-messages=LOCALE\n",
+       "  --lc-monetary, --lc-numeric, --lc-time=LOCALE\n",
+       "                            initialize database cluster with given locale\n",
+       "                            in the respective category (default taken from\n",
+       "                            environment)\n",
+       "  --no-locale               equivalent to --locale=C\n",
+       "  -U, --username=NAME       database superuser name\n",
+       "  -W, --pwprompt            prompt for a password for the new superuser\n",
+       "  -?, --help                show this help, then exit\n",
+       "  -V, --version             output version information, then exit\n",
+       "\n",
+       "Less commonly used options: \n",
+       "  -d, --debug               generate lots of debugging output\n",
+       "  -s, --show                show internal settings\n",
+       "  -L DIRECTORY              where to find the input files\n",
+       "  -n, --noclean             do not clean up after errors\n",
+       "\n",
+       "If the data directory is not specified, the environment variable PGDATA\n",
+       "is used.\n",
+       "\n",
+       "Report bugs to <pgsql-bugs@postgresql.org>.\n",
+       NULL
+};
+
+
+
+/*
+ * print help text
+ *
+ */
+static void
+usage(void)
+{
+
+       int                     i;
+       char      **newtext;
+
+       newtext = replace_token(usage_text, "$CMDNAME", progname);
+
+       for (i = 0; newtext[i]; i++)
+               fputs(newtext[i], stdout);              /* faster than printf */
+}
+
+int
+main(int argc, char *argv[])
+{
+       /*
+        * options with no short version return a low integer, the rest return
+        * their short version value
+        *
+        */
+       static struct option long_options[] = {
+               {"pgdata", required_argument, NULL, 'D'},
+               {"encoding", required_argument, NULL, 'E'},
+               {"locale", required_argument, NULL, 1},
+               {"lc-collate", required_argument, NULL, 2},
+               {"lc-ctype", required_argument, NULL, 3},
+               {"lc-monetary", required_argument, NULL, 4},
+               {"lc-numeric", required_argument, NULL, 5},
+               {"lc-time", required_argument, NULL, 6},
+               {"lc-messages", required_argument, NULL, 7},
+               {"no-locale", no_argument, NULL, 8},
+               {"pwprompt", no_argument, NULL, 'W'},
+               {"username", required_argument, NULL, 'U'},
+               {"help", no_argument, NULL, '?'},
+               {"version", no_argument, NULL, 'V'},
+               {"debug", no_argument, NULL, 'd'},
+               {"show", no_argument, NULL, 's'},
+               {"noclean", no_argument, NULL, 'n'},
+               {0, 0, 0, 0}
+       };
+
+       int                     c,
+                               i;
+       int                     option_index;
+       char       *short_version;
+       char       *pgdenv;                     /* PGDATA value got from sent to
+                                                                * environment */
+       char       *subdirs[] =
+       {"global", "pg_xlog", "pg_clog", "base", "base/1"};
+
+       char       *lastsep;
+
+       /* parse argv[0] - detect explicit path if there was one */
+
+       char       *carg0;
+
+#if defined(__CYGWIN__) || defined(WIN32)
+       char       *exe;                        /* location of exe suffix in progname */
+#endif   /* defined(__CYGWIN__) || defined(WIN32) */
+
+       setlocale(LC_ALL, "");
+
+       carg0 = xstrdup(argv[0]);
+       canonicalise_path(carg0);
+
+       lastsep = strrchr(carg0, '/');
+       progname = lastsep ? xstrdup(lastsep + 1) : carg0;
+
+#if defined(__CYGWIN__) || defined(WIN32)
+       if (strlen(progname) > 4 &&
+               (exe = progname + (strlen(progname) - 4)) &&
+               stricmp(exe, EXE) == 0)
+       {
+               /* strip .exe suffix, regardless of case */
+               *exe = '\0';
+       }
+#endif   /* defined(__CYGWIN__) || defined(WIN32) */
+
+       if (lastsep)
+       {
+               self_path = carg0;
+               *lastsep = '\0';
+       }
+       else
+       {
+               /* no path known to ourselves from argv[0] */
+               self_path = NULL;
+       }
+
+       /* process options */
+
+       while (1)
+       {
+               /*
+                * a : as the first option char here lets us use ? as a short
+                * option
+                */
+               c = getopt_long(argc, argv, ":D:E:WU:?sVdnL:",
+                                               long_options, &option_index);
+
+               if (c == -1)
+                       break;
+
+               switch (c)
+               {
+                       case 'D':
+                               pg_data = xstrdup(optarg);
+                               break;
+                       case 'E':
+                               encoding = xstrdup(optarg);
+                               break;
+                       case 'W':
+                               pwprompt = true;
+                               break;
+                       case 'U':
+                               username = xstrdup(optarg);
+                               break;
+                       case 'd':
+                               debug = true;
+                               break;
+                       case 'n':
+                               noclean = true;
+                               break;
+                       case 'L':
+                               datadir = xstrdup(optarg);
+                               break;
+                       case 1:
+                               locale = xstrdup(optarg);
+                               break;
+                       case 2:
+                               lc_collate = xstrdup(optarg);
+                               break;
+                       case 3:
+                               lc_ctype = xstrdup(optarg);
+                               break;
+                       case 4:
+                               lc_monetary = xstrdup(optarg);
+                               break;
+                       case 5:
+                               lc_numeric = xstrdup(optarg);
+                               break;
+                       case 6:
+                               lc_time = xstrdup(optarg);
+                               break;
+                       case 7:
+                               lc_messages = xstrdup(optarg);
+                               break;
+                       case 8:
+                               locale = "C";
+                               break;
+                       case '?':
+                               show_help = true;
+                               break;
+                       case 's':
+                               show_setting = true;
+                               break;
+                       case 'V':
+                               show_version = true;
+                               break;
+                       default:
+                               show_help = true;
+                               printf("Unrecognized option: %c\n", c);
+               }
+
+       }
+
+       if (optind < argc)
+       {
+               pg_data = xstrdup(argv[optind]);
+               optind++;
+       }
+
+       set_info_version();
+
+       if (strlen(pg_data) == 0 && !(show_help || show_setting))
+       {
+               pgdenv = getenv("PGDATA");
+               if (pgdenv && strlen(pgdenv))
+               {
+                       /* PGDATA found */
+                       pg_data = xstrdup(pgdenv);
+               }
+               else
+               {
+                       fprintf(stderr,
+                                       "%s: no data directory specified\n"
+                          "You must identify the directory where the data for this "
+                                       "database system\n"
+                          "will reside.  Do this with either the invocation option "
+                                       "-D or the\n" "environment variable PGDATA.\n",
+                                       progname);
+               }
+       }
+
+       canonicalise_path(pg_data);
+
+       /*
+        * we have to set PGDATA for postgres rather than pass it on the
+        * commnd line to avoid dumb quoting problems on Windows, and we would
+        * expecially need quotes otherwise on Windows because paths there are
+        * most likely to have embedded spaces.
+        *
+        */
+       pgdenv = xmalloc(8 + strlen(pg_data));
+       sprintf(pgdenv, "PGDATA=%s", pg_data);
+       putenv(pgdenv);
+
+       if (optind < argc)
+               show_help = true;
+
+       if (show_version)
+       {
+               /* hard coded name here, in case they rename executable */
+               printf("initdb (PostgreSQL) %s\n", PG_VERSION);
+               exit(0);
+       }
+
+       if (show_help)
+       {
+               usage();
+               exit(0);
+       }
+
+       if (set_paths() != 0)
+       {
+               fprintf(stderr,
+                               "The program \"postgres\" is needed by %s "
+                               "but was not found in \n"
+                               "the directory \"%s\". Check your installation.\n",
+                               progname, bindir);
+               exit(1);
+
+       }
+
+
+       if ((short_version = get_short_version()) == NULL)
+       {
+               fprintf(stderr, "%s: could not get valid short version\n", progname);
+               exit(1);
+       }
+
+       effective_user = get_id();
+       if (!strlen(username))
+               username = effective_user;
+
+       if (strlen(encoding))
+               encodingid = get_encoding_id(encoding);
+
+       set_input(&bki_file, "postgres.bki");
+       set_input(&desc_file, "postgres.description");
+       set_input(&hba_file, "pg_hba.conf.sample");
+       set_input(&ident_file, "pg_ident.conf.sample");
+       set_input(&conf_file, "postgresql.conf.sample");
+       set_input(&conversion_file, "conversion_create.sql");
+       set_input(&info_schema_file, "information_schema.sql");
+       set_input(&features_file, "sql_features.txt");
+       set_input(&system_views_file, "system_views.sql");
+
+
+       if (show_setting || debug)
+       {
+               fprintf(stderr,
+                               "VERSION=%s\n"
+                               "PGDATA=%s\ndatadir=%s\nPGPATH=%s\n"
+                               "ENCODING=%s\nENCODINGID=%s\n"
+                               "POSTGRES_SUPERUSERNAME=%s\nPOSTGRES_BKI=%s\n"
+                               "POSTGRES_DESCR=%s\nPOSTGRESQL_CONF_SAMPLE=%s\n"
+                               "PG_HBA_SAMPLE=%s\nPG_IDENT_SAMPLE=%s\n",
+                               PG_VERSION,
+                               pg_data, datadir, pgpath,
+                               encoding, encodingid,
+                               username, bki_file,
+                               desc_file, conf_file,
+                               hba_file, ident_file);
+       }
+
+
+       if (show_setting)
+               exit(0);
+
+
+       check_input(bki_file);
+       check_input(desc_file);
+       check_input(hba_file);
+       check_input(ident_file);
+       check_input(conf_file);
+       check_input(conversion_file);
+       check_input(info_schema_file);
+       check_input(features_file);
+       check_input(system_views_file);
+
+       setlocales();
+
+       if (strcmp(lc_ctype, lc_collate) == 0 &&
+               strcmp(lc_ctype, lc_time) == 0 &&
+               strcmp(lc_ctype, lc_numeric) == 0 &&
+               strcmp(lc_ctype, lc_monetary) == 0 &&
+               strcmp(lc_ctype, lc_messages) == 0)
+       {
+               printf("The database cluster will be initialized with locale %s\n",
+                          lc_ctype);
+       }
+       else
+       {
+               printf("The database cluster will be initialized with locales\n"
+                          "  COLLATE:  %s\n"
+                          "  CTYPE:    %s\n"
+                          "  MESSAGES: %s\n"
+                          "  MONETARY: %s\n"
+                          "  NUMERIC:  %s\n"
+                          "  TIME:     %s\n",
+                          lc_collate,
+                          lc_ctype,
+                          lc_messages,
+                          lc_monetary,
+                          lc_numeric,
+                          lc_time);
+       }
+
+       umask(077);
+
+       /*
+        * now we are starting to do real work, trap signals so we can clean
+        * up
+        */
+
+       /* some of these are not valid on Windows */
+#ifdef SIGHUP
+       pqsignal(SIGHUP, trapsig);
+#endif   /* SIGHUP */
+#ifdef SIGINT
+       pqsignal(SIGINT, trapsig);
+#endif   /* SIGINT */
+#ifdef SIGQUIT
+       pqsignal(SIGQUIT, trapsig);
+#endif   /* SIGQUIT */
+#ifdef SIGTERM
+       pqsignal(SIGTERM, trapsig);
+#endif   /* SIGTERM */
+
+
+       /* clear this we'll use it in a few lines */
+       errno = 0;
+
+       if (!check_data_dir())
+       {
+               fprintf(stderr,
+                               "%s: directory \"%s\" exists but is not empty\n"
+                               "If you want to create a new database system, either "
+                               "remove or empty\n"
+                               "the directory \"$PGDATA\" or run $CMDNAME with an "
+                               "argument other than\n"
+                               "\"%s\".\n",
+                               progname, pg_data, pg_data);
+               exit(1);
+       }
+
+       /*
+        * check_data_dir() called opendir - the errno should still be hanging
+        * around
+        */
+
+       if (errno == ENOENT)
+       {
+               printf("creating directory \"%s\" ... ", pg_data);
+
+               if (!mkdatadir(NULL))
+                       exit_nicely();
+               else
+                       check_ok();
+
+               made_new_pgdata = true;
+       }
+
+       for (i = 0; i < (sizeof(subdirs) / sizeof(char *)); i++)
+       {
+               printf("creating directory %s/%s ... ", pg_data, subdirs[i]);
+
+               if (!mkdatadir(subdirs[i]))
+                       exit_nicely();
+               else
+                       check_ok();
+       }
+
+       set_short_version(short_version, NULL);
+
+       set_null_conf();
+
+       test_buffers();
+
+       test_connections();
+
+       setup_config();
+
+       bootstrap_template1(short_version);
+
+       set_short_version(short_version, "base/1");
+
+       setup_shadow();
+
+       if (pwprompt)
+               get_set_pw();
+
+       unlimit_systables();
+
+       setup_depend();
+
+       setup_sysviews();
+
+       setup_description();
+
+       setup_conversion();
+
+       setup_privileges();
+
+       setup_schema();
+
+       vacuum_db();
+
+       make_template0();
+
+       printf("\n"
+                  "Success. You can now start the database server using:\n"
+                  "\n"
+                  "    \"%s/postmaster\" -D \"%s\"\n"
+                  "or\n"
+                  "    \"%s/pg_ctl\" -D \"%s\" -l logfile start\n"
+                  "\n",
+                  pgpath, pg_data, pgpath, pg_data);
+
+       return 0;
+}
diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh
deleted file mode 100644 (file)
index ed396c4..0000000
+++ /dev/null
@@ -1,1155 +0,0 @@
-#!@SHELL@
-#-------------------------------------------------------------------------
-#
-# initdb creates (initializes) a PostgreSQL database cluster (site,
-# instance, installation, whatever).  A database cluster is a
-# collection of PostgreSQL databases all managed by the same postmaster.
-#
-# To create the database cluster, we create the directory that contains
-# all its data, create the files that hold the global tables, create
-# a few other control files for it, and create two databases: the
-# template0 and template1 databases.
-#
-# The template databases are ordinary PostgreSQL databases.  template0
-# is never supposed to change after initdb, whereas template1 can be
-# changed to add site-local standard data.  Either one can be copied
-# to produce a new database.
-#
-# To create template1, we run the postgres (backend) program in bootstrap
-# mode and feed it data from the postgres.bki library file.  After this
-# initial bootstrap phase, some additional stuff is created by normal
-# SQL commands fed to a standalone backend.  Those commands are just
-# embedded into this script (yeah, it's ugly).
-#
-# template0 is made just by copying the completed template1.
-#
-#
-# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
-# Portions Copyright (c) 1994, Regents of the University of California
-#
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.204 2003/10/13 21:06:44 tgl Exp $
-#
-#-------------------------------------------------------------------------
-
-
-##########################################################################
-#
-# INITIALIZATION
-
-exit_nicely(){
-    stty echo > /dev/null 2>&1
-    echo 1>&2
-    echo "$CMDNAME: failed" 1>&2
-    if [ "$noclean" != yes ]; then
-        if [ "$made_new_pgdata" = yes ]; then
-            echo "$CMDNAME: removing data directory \"$PGDATA\"" 1>&2
-            rm -rf "$PGDATA" || echo "$CMDNAME: failed" 1>&2
-        fi
-    else
-        echo "$CMDNAME: data directory \"$PGDATA\" not removed at user's request" 1>&2
-    fi
-    exit 1
-}
-
-pg_getlocale(){
-    arg=$1
-    unset ret
-
-    for var in "PGLC_$arg" PGLOCALE LC_ALL "LC_$arg" LANG; do
-        varset=`eval echo '${'"$var"'+set}'`
-        varval=`eval echo '$'"$var"`
-        if test "$varset" = set; then
-            ret=$varval
-            break
-        fi
-    done
-
-    if test "${ret+set}" != set; then
-        ret=C
-    fi
-
-    echo "$ret"
-}
-
-
-CMDNAME=`basename $0`
-
-# Placed here during build
-VERSION='@VERSION@'
-HAVE_IPV6='@HAVE_IPV6@'
-bindir='@bindir@'
-# Note that "datadir" is not the directory we're initializing, it's
-# merely how Autoconf names PREFIX/share.
-datadir='@datadir@'
-
-
-# Check for echo -n vs echo \c
-if echo '\c' | grep -s c >/dev/null 2>&1
-then
-    ECHO_N="echo -n"
-    ECHO_C=""
-else
-    ECHO_N="echo"
-    ECHO_C='\c'
-fi
-
-
-#
-# Find out where we're located
-#
-if echo "$0" | grep '/' > /dev/null 2>&1 
-then
-        # explicit dir name given
-        self_path=`echo $0 | sed 's,/[^/]*$,,'`       # (dirname command is not portable)
-else
-        # look for it in PATH ('which' command is not portable)
-        for dir in `echo "$PATH" | sed 's/:/ /g'`
-       do
-                # empty entry in path means current dir
-                [ -z "$dir" ] && dir='.'
-                if [ -f "$dir/$CMDNAME" ]
-               then
-                        self_path="$dir"
-                        break
-                fi
-        done
-fi
-
-
-# Check for right version of backend.  First we check for an
-# executable in the same directory is this initdb script (presuming
-# the above code worked).  Then we fall back to the hard-wired bindir.
-# We do it in this order because during upgrades users might move
-# their trees to backup places, so $bindir might be inaccurate.
-
-if [ x"$self_path" != x"" ] \
-  && [ -x "$self_path/postgres" ] \
-  && [ x"`$self_path/postgres -V 2>/dev/null`" = x"postgres (PostgreSQL) $VERSION" ]
-then
-    PGPATH=$self_path
-elif [ -x "$bindir/postgres" ]; then
-    if [ x"`$bindir/postgres -V 2>/dev/null`" = x"postgres (PostgreSQL) $VERSION" ]
-    then
-        PGPATH=$bindir
-    else
-        # Maybe there was an error message?
-        errormsg=`$bindir/postgres -V 2>&1 >/dev/null`
-      (
-        echo "The program "
-        echo "    $bindir/postgres"
-        echo "needed by $CMDNAME does not belong to PostgreSQL version $VERSION, or"
-        echo "there may be a configuration problem."
-        if test x"$errormsg" != x""; then
-            echo
-            echo "This was the error message issued by that program:"
-            echo "$errormsg"
-        fi
-      ) 1>&2
-        exit 1
-    fi
-else
-    echo "The program \"postgres\" is needed by $CMDNAME but was not found in" 1>&2
-    echo "the directory \"$bindir\".  Check your installation." 1>&2
-    exit 1
-fi
-
-
-# Now we can assume that 'pg_id' belongs to the same version as the
-# verified 'postgres' in the same directory.
-if [ ! -x "$PGPATH/pg_id" ]; then
-    echo "The program \"pg_id\" is needed by $CMDNAME but was not found in" 1>&2
-    echo "the directory \"$PGPATH\".  Check your installation." 1>&2
-    exit 1
-fi
-
-
-EffectiveUser=`$PGPATH/pg_id -n -u`
-if [ -z "$EffectiveUser" ]; then
-    echo "$CMDNAME: could not determine current user name" 1>&2
-    exit 1
-fi
-
-if [ `$PGPATH/pg_id -u` -eq 0 ]
-then
-    echo "$CMDNAME: cannot be run as root" 1>&2
-    echo "Please log in (using, e.g., \"su\") as the (unprivileged) user that will" 1>&2
-    echo "own the server process." 1>&2
-    exit 1
-fi
-
-
-short_version=`echo $VERSION | sed -e 's!^\([0-9][0-9]*\.[0-9][0-9]*\).*!\1!'`
-if [ x"$short_version" = x"" ] ; then
-  echo "$CMDNAME: bug: version number has wrong format" 1>&2
-  exit 1
-fi
-
-
-##########################################################################
-#
-# COMMAND LINE OPTIONS
-
-# 0 is the default (non-)encoding
-ENCODINGID=0
-
-# Set defaults:
-debug=
-noclean=
-show_setting=
-
-# Note: There is a single compelling reason that the name of the database
-#       superuser be the same as the Unix user owning the server process:
-#       The single user postgres backend will only connect as the database
-#       user with the same name as the Unix user running it. That's
-#       a security measure.
-POSTGRES_SUPERUSERNAME="$EffectiveUser"
-
-while [ "$#" -gt 0 ]
-do
-    case "$1" in
-        --help|-\?)
-                usage=t
-                break
-                ;;
-        --version|-V)
-                echo "initdb (PostgreSQL) $VERSION"
-                exit 0
-                ;;
-        --debug|-d)
-                debug=yes
-                echo "Running in debug mode."
-                ;;
-        --show|-s)
-               show_setting=yes
-               ;;        
-        --noclean|-n)
-                noclean=yes
-                echo "Running in noclean mode.  Mistakes will not be cleaned up."
-                ;;
-# The name of the database superuser. Can be freely changed.
-        --username|-U)
-                POSTGRES_SUPERUSERNAME="$2"
-                shift;;
-        --username=*)
-                POSTGRES_SUPERUSERNAME=`echo $1 | sed 's/^--username=//'`
-                ;;
-        -U*)
-                POSTGRES_SUPERUSERNAME=`echo $1 | sed 's/^-U//'`
-                ;;
-# The default password of the database superuser.
-# Make initdb prompt for the default password of the database superuser.
-        --pwprompt|-W)
-                PwPrompt=1
-                ;;
-# Directory where to install the data. No default, unless the environment
-# variable PGDATA is set.
-        --pgdata|-D)
-                PGDATA="$2"
-                shift;;
-        --pgdata=*)
-                PGDATA=`echo $1 | sed 's/^--pgdata=//'`
-                ;;
-        -D*)
-                PGDATA=`echo $1 | sed 's/^-D//'`
-                ;;
-# The directory where the .bki input files are stored. Normally
-# they are in PREFIX/share and this option should be unnecessary.
-        -L)
-                datadir="$2"
-                shift;;
-        -L*)
-                datadir=`echo $1 | sed 's/^-L//'`
-                ;;
-# The encoding of the template1 database. Defaults to what you chose
-# at configure time. (see above)
-        --encoding|-E)
-                ENCODING="$2"
-                shift;;
-        --encoding=*)
-                ENCODING=`echo $1 | sed 's/^--encoding=//'`
-                ;;
-        -E*)
-                ENCODING=`echo $1 | sed 's/^-E//'`
-                ;;
-# Locale flags
-        --locale)
-                PGLOCALE="$2"
-                shift;;
-        --locale=*)
-                PGLOCALE=`echo $1 | sed 's/^[^=]*=//'`
-                ;;
-        --no-locale)
-                PGLOCALE=C
-                ;;
-
-        --lc-collate)
-                PGLC_COLLATE=$2
-                shift;;
-        --lc-collate=*)
-                PGLC_COLLATE=`echo $1 | sed 's/^[^=]*=//'`
-                ;;
-        --lc-ctype)
-                PGLC_CTYPE=$2
-                shift;;
-        --lc-ctype=*)
-                PGLC_CTYPE=`echo $1 | sed 's/^[^=]*=//'`
-                ;;
-        --lc-messages)
-                PGLC_MESSAGES=$2
-                shift;;
-        --lc-messages=*)
-                PGLC_MESSAGES=`echo $1 | sed 's/^[^=]*=//'`
-                ;;
-        --lc-monetary)
-                PGLC_MONETARY=$2
-                shift;;
-        --lc-monetary=*)
-                PGLC_MONETARY=`echo $1 | sed 's/^[^=]*=//'`
-                ;;
-        --lc-numeric)
-                PGLC_NUMERIC=$2
-                shift;;
-        --lc-numeric=*)
-                PGLC_NUMERIC=`echo $1 | sed 's/^[^=]*=//'`
-                ;;
-        --lc-time)
-                PGLC_TIME=$2
-                shift;;
-        --lc-time=*)
-                PGLC_TIME=`echo $1 | sed 's/^[^=]*=//'`
-                ;;
-
-       -*)
-               echo "$CMDNAME: invalid option: $1"
-               echo "Try \"$CMDNAME --help\" for more information."
-               exit 1
-               ;;
-
-# Non-option argument specifies data directory
-        *)
-                PGDATA=$1
-                ;;
-    esac
-    shift
-done
-
-if [ "$usage" ]; then
-    echo "$CMDNAME initializes a PostgreSQL database cluster."
-    echo
-    echo "Usage:"
-    echo "  $CMDNAME [OPTION]... [DATADIR]"
-    echo
-    echo "Options:"
-    echo " [-D, --pgdata=]DATADIR     location for this database cluster"
-    echo "  -E, --encoding=ENCODING   set default encoding for new databases"
-    echo "  --locale=LOCALE           initialize database cluster with given locale"
-    echo "  --lc-collate, --lc-ctype, --lc-messages=LOCALE"
-    echo "  --lc-monetary, --lc-numeric, --lc-time=LOCALE"
-    echo "                            initialize database cluster with given locale"
-    echo "                            in the respective category (default taken from"
-    echo "                            environment)"
-    echo "  --no-locale               equivalent to --locale=C"
-    echo "  -U, --username=NAME       database superuser name"
-    echo "  -W, --pwprompt            prompt for a password for the new superuser"
-    echo "  --help                    show this help, then exit"
-    echo "  --version                 output version information, then exit"
-    echo
-    echo "Less commonly used options: "
-    echo "  -d, --debug               generate lots of debugging output"
-    echo "  -L DIRECTORY              where to find the input files"
-    echo "  -n, --noclean             do not clean up after errors"
-    echo
-    echo "If the data directory is not specified, the environment variable PGDATA"
-    echo "is used."
-    echo
-    echo "Report bugs to <pgsql-bugs@postgresql.org>."
-    exit 0
-fi
-
-#-------------------------------------------------------------------------
-# Resolve the encoding name
-#-------------------------------------------------------------------------
-
-if [ "$ENCODING" ]
-then
-       ENCODINGID=`$PGPATH/pg_encoding -b $ENCODING`
-       if [ "$?" -ne 0 ]
-       then
-              (
-                echo "$CMDNAME: pg_encoding failed"
-                echo "Make sure the program was installed correctly."
-              ) 1>&2
-                exit 1
-        fi
-       if [ -z "$ENCODINGID" ]
-       then
-               echo "$CMDNAME: \"$ENCODING\" is not a valid server encoding name" 1>&2
-               exit 1
-       fi
-fi
-
-
-#-------------------------------------------------------------------------
-# Make sure he told us where to build the database system
-#-------------------------------------------------------------------------
-
-if [ -z "$PGDATA" ]
-then
-  (
-    echo "$CMDNAME: no data directory specified"
-    echo "You must identify the directory where the data for this database system"
-    echo "will reside.  Do this with either the invocation option -D or the"
-    echo "environment variable PGDATA."
-  ) 1>&2
-    exit 1
-fi
-
-
-#-------------------------------------------------------------------------
-# Find the input files
-#-------------------------------------------------------------------------
-
-POSTGRES_BKI="$datadir"/postgres.bki
-POSTGRES_DESCR="$datadir"/postgres.description
-
-PG_HBA_SAMPLE="$datadir"/pg_hba.conf.sample
-PG_IDENT_SAMPLE="$datadir"/pg_ident.conf.sample
-POSTGRESQL_CONF_SAMPLE="$datadir"/postgresql.conf.sample
-
-if [ "$show_setting" = yes ] || [ "$debug" = yes ]
-then
-  (
-    echo
-    echo "$CMDNAME: internal variables:"
-    for var in PGDATA datadir PGPATH ENCODING ENCODINGID \
-        POSTGRES_SUPERUSERNAME POSTGRES_BKI \
-        POSTGRES_DESCR POSTGRESQL_CONF_SAMPLE \
-       PG_HBA_SAMPLE PG_IDENT_SAMPLE ; do
-        eval "echo '  '$var=\$$var"
-    done
-  ) 1>&2
-fi
-
-if [ "$show_setting" = yes ] ; then
-    exit 0
-fi
-
-for PREREQ_FILE in "$POSTGRES_BKI" "$POSTGRES_DESCR" \
-    "$PG_HBA_SAMPLE" "$PG_IDENT_SAMPLE" "$POSTGRESQL_CONF_SAMPLE"
-do
-    if [ ! -f "$PREREQ_FILE" ] ; then
-      (
-        echo "$CMDNAME: file \"$PREREQ_FILE\" not found"
-        echo "This means you have a corrupted installation or identified the"
-        echo "wrong directory with the invocation option -L."
-      ) 1>&2
-        exit 1
-    fi
-done
-
-for file in "$POSTGRES_BKI"
-do
-     if [ x"`sed 1q $file`" != x"# PostgreSQL $short_version" ]; then
-       (
-         echo "$CMDNAME: input file \"$file\" does not belong to PostgreSQL $VERSION"
-         echo "Check your installation or specify the correct path using the option -L."
-       ) 1>&2
-         exit 1
-     fi
-done
-
-
-trap 'echo "Caught signal." ; exit_nicely' 1 2 3 15
-
-# Let's go
-echo "The files belonging to this database system will be owned by user \"$EffectiveUser\"."
-echo "This user must also own the server process."
-echo
-
-TAB='  '
-
-if test x`pg_getlocale CTYPE` = x`pg_getlocale COLLATE` \
-   && test x`pg_getlocale CTYPE` = x`pg_getlocale TIME` \
-   && test x`pg_getlocale CTYPE` = x`pg_getlocale NUMERIC` \
-   && test x`pg_getlocale CTYPE` = x`pg_getlocale MONETARY` \
-   && test x`pg_getlocale CTYPE` = x`pg_getlocale MESSAGES`
-then
-    echo "The database cluster will be initialized with locale `pg_getlocale CTYPE`."
-else
-    echo "The database cluster will be initialized with locales:"
-    echo "  COLLATE:  `pg_getlocale COLLATE`"
-    echo "  CTYPE:    `pg_getlocale CTYPE`"
-    echo "  MESSAGES: `pg_getlocale MESSAGES`"
-    echo "  MONETARY: `pg_getlocale MONETARY`"
-    echo "  NUMERIC:  `pg_getlocale NUMERIC`"
-    echo "  TIME:     `pg_getlocale TIME`"
-fi
-echo
-
-
-##########################################################################
-#
-# CREATE DATABASE DIRECTORY
-
-# umask must disallow access to group, other for files and dirs
-umask 077
-
-# find out if directory is empty
-pgdata_contents=`ls -A "$PGDATA" 2>/dev/null`
-if [ x"$pgdata_contents" != x ]
-then
-    (
-      echo "$CMDNAME: directory \"$PGDATA\" exists but is not empty"
-      echo "If you want to create a new database system, either remove or empty"
-      echo "the directory \"$PGDATA\" or run $CMDNAME with an argument other than"
-      echo "\"$PGDATA\"."
-    ) 1>&2
-    exit 1
-else
-    if [ ! -d "$PGDATA" ]; then
-        $ECHO_N "creating directory $PGDATA... "$ECHO_C
-        mkdir -p "$PGDATA" >/dev/null 2>&1 || mkdir "$PGDATA" || exit_nicely
-        made_new_pgdata=yes
-    else
-        $ECHO_N "fixing permissions on existing directory $PGDATA... "$ECHO_C
-       chmod go-rwx "$PGDATA" || exit_nicely
-    fi
-    echo "ok"
-
-    if [ ! -d "$PGDATA"/base ]
-       then
-        $ECHO_N "creating directory $PGDATA/base... "$ECHO_C
-        mkdir "$PGDATA"/base || exit_nicely
-       echo "ok"
-    fi
-    if [ ! -d "$PGDATA"/global ]
-    then
-        $ECHO_N "creating directory $PGDATA/global... "$ECHO_C
-        mkdir "$PGDATA"/global || exit_nicely
-       echo "ok"
-    fi
-    if [ ! -d "$PGDATA"/pg_xlog ]
-    then
-        $ECHO_N "creating directory $PGDATA/pg_xlog... "$ECHO_C
-        mkdir "$PGDATA"/pg_xlog || exit_nicely
-       echo "ok"
-    fi
-    if [ ! -d "$PGDATA"/pg_clog ]
-    then
-        $ECHO_N "creating directory $PGDATA/pg_clog... "$ECHO_C
-        mkdir "$PGDATA"/pg_clog || exit_nicely
-       echo "ok"
-    fi
-fi
-
-# Top level PG_VERSION is checked by bootstrapper, so make it first
-echo "$short_version" > "$PGDATA/PG_VERSION"         || exit_nicely
-
-
-##########################################################################
-#
-# DETERMINE PLATFORM-SPECIFIC CONFIG SETTINGS
-#
-# Use reasonable values if kernel will let us, else scale back.  Probe for
-# max_connections first since it is subject to more constraints than
-# shared_buffers.
-
-# common backend options
-PGSQL_OPT="-F -D$PGDATA"
-
-cp /dev/null "$PGDATA"/postgresql.conf               || exit_nicely
-
-$ECHO_N "selecting default max_connections... "$ECHO_C
-
-for nconns in 100 50 40 30 20 10
-do
-    nbuffers=`expr $nconns '*' 5`
-    TEST_OPT="$PGSQL_OPT -c shared_buffers=$nbuffers -c max_connections=$nconns"
-    if "$PGPATH"/postgres -boot -x0 $TEST_OPT template1 </dev/null >/dev/null 2>&1
-    then
-       break
-    fi
-done
-
-echo "$nconns"
-
-$ECHO_N "selecting default shared_buffers... "$ECHO_C
-
-for nbuffers in 1000 900 800 700 600 500 400 300 200 100 50
-do
-    TEST_OPT="$PGSQL_OPT -c shared_buffers=$nbuffers -c max_connections=$nconns"
-    if "$PGPATH"/postgres -boot -x0 $TEST_OPT template1 </dev/null >/dev/null 2>&1
-    then
-       break
-    fi
-done
-
-echo "$nbuffers"
-
-##########################################################################
-#
-# CREATE CONFIG FILES
-
-$ECHO_N "creating configuration files... "$ECHO_C
-
-sed -e "s/^#shared_buffers = 1000/shared_buffers = $nbuffers/" \
-    -e "s/^#max_connections = 100/max_connections = $nconns/" \
-    -e "s/^#lc_messages = 'C'/lc_messages = '`pg_getlocale MESSAGES`'/" \
-    -e "s/^#lc_monetary = 'C'/lc_monetary = '`pg_getlocale MONETARY`'/" \
-    -e "s/^#lc_numeric = 'C'/lc_numeric = '`pg_getlocale NUMERIC`'/" \
-    -e "s/^#lc_time = 'C'/lc_time = '`pg_getlocale TIME`'/" \
-    "$POSTGRESQL_CONF_SAMPLE"  > "$PGDATA"/postgresql.conf || exit_nicely
-if [ "x$HAVE_IPV6" = xyes ]
-then
-    cp "$PG_HBA_SAMPLE" "$PGDATA"/pg_hba.conf          || exit_nicely
-else
-    sed -e "/ ::1 / s/^host/#host/" \
-        "$PG_HBA_SAMPLE" > "$PGDATA"/pg_hba.conf       || exit_nicely
-fi
-cp "$PG_IDENT_SAMPLE" "$PGDATA"/pg_ident.conf          || exit_nicely
-
-chmod 0600 "$PGDATA"/pg_hba.conf "$PGDATA"/pg_ident.conf \
-       "$PGDATA"/postgresql.conf
-
-echo "ok"
-
-##########################################################################
-#
-# RUN BKI SCRIPT IN BOOTSTRAP MODE TO CREATE TEMPLATE1
-
-if [ "$debug" = yes ]
-then
-    BOOTSTRAP_TALK_ARG="-d 5"
-fi
-
-$ECHO_N "creating template1 database in $PGDATA/base/1... "$ECHO_C
-
-rm -rf "$PGDATA"/base/1 || exit_nicely
-mkdir "$PGDATA"/base/1 || exit_nicely
-
-cat "$POSTGRES_BKI" \
-| sed -e "s/POSTGRES/$POSTGRES_SUPERUSERNAME/g" \
-      -e "s/ENCODING/$ENCODINGID/g" \
-| 
-(
-  LC_COLLATE=`pg_getlocale COLLATE`
-  LC_CTYPE=`pg_getlocale CTYPE`
-  export LC_COLLATE
-  export LC_CTYPE
-  unset LC_ALL
-  "$PGPATH"/postgres -boot -x1 $PGSQL_OPT $BOOTSTRAP_TALK_ARG template1
-) \
-|| exit_nicely
-
-# Make the per-database PGVERSION for template1 only after init'ing it
-echo "$short_version" > "$PGDATA/base/1/PG_VERSION" || exit_nicely
-
-echo "ok"
-
-##########################################################################
-#
-# CREATE VIEWS and other things
-#
-# NOTE: because here we are driving a standalone backend (not psql), we must
-# follow the standalone backend's convention that commands end at a newline.
-# To break an SQL command across lines in this script, backslash-escape all
-# internal newlines in the command.
-
-PGSQL_OPT="$PGSQL_OPT -O -c search_path=pg_catalog -c exit_on_error=true"
-
-$ECHO_N "initializing pg_shadow... "$ECHO_C
-
-"$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
--- Create a trigger so that direct updates to pg_shadow will be written
--- to the flat password/group files pg_pwd and pg_group
-CREATE TRIGGER pg_sync_pg_pwd AFTER INSERT OR UPDATE OR DELETE ON pg_shadow \
-FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();
-CREATE TRIGGER pg_sync_pg_group AFTER INSERT OR UPDATE OR DELETE ON pg_group \
-FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();
--- needs to be done before alter user, because alter user checks that
--- pg_shadow is secure ...
-REVOKE ALL on pg_shadow FROM public;
-EOF
-if [ "$?" -ne 0 ]; then
-    exit_nicely
-fi
-echo "ok"
-
-# set up password
-if [ "$PwPrompt" ]; then
-    $ECHO_N "Enter new superuser password: "$ECHO_C
-    stty -echo > /dev/null 2>&1
-    read FirstPw
-    stty echo > /dev/null 2>&1
-    echo
-    $ECHO_N "Enter it again: "$ECHO_C
-    stty -echo > /dev/null 2>&1
-    read SecondPw
-    stty echo > /dev/null 2>&1
-    echo
-    if [ "$FirstPw" != "$SecondPw" ]; then
-        echo "Passwords didn't match." 1>&2
-        exit_nicely
-    fi
-    $ECHO_N "setting password... "$ECHO_C
-    "$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
-       ALTER USER "$POSTGRES_SUPERUSERNAME" WITH PASSWORD '$FirstPw';
-EOF
-    if [ "$?" -ne 0 ]; then
-       exit_nicely
-    fi
-    if [ ! -f "$PGDATA"/global/pg_pwd ]; then
-        echo
-        echo "$CMDNAME: The password file wasn't generated. Please report this problem." 1>&2
-        exit_nicely
-    fi
-    echo "ok"
-fi
-
-$ECHO_N "enabling unlimited row size for system tables... "$ECHO_C
-
-"$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
-ALTER TABLE pg_attrdef CREATE TOAST TABLE;
-ALTER TABLE pg_constraint CREATE TOAST TABLE;
-ALTER TABLE pg_database CREATE TOAST TABLE;
-ALTER TABLE pg_description CREATE TOAST TABLE;
-ALTER TABLE pg_group CREATE TOAST TABLE;
-ALTER TABLE pg_proc CREATE TOAST TABLE;
-ALTER TABLE pg_rewrite CREATE TOAST TABLE;
-ALTER TABLE pg_shadow CREATE TOAST TABLE;
-ALTER TABLE pg_statistic CREATE TOAST TABLE;
-EOF
-if [ "$?" -ne 0 ]; then
-    exit_nicely
-fi
-echo "ok"
-
-
-$ECHO_N "initializing pg_depend... "$ECHO_C
-
-"$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
--- Make PIN entries in pg_depend for all objects made so far in the tables
--- that the dependency code handles.  This is overkill (the system doesn't
--- really depend on having every last weird datatype, for instance)
--- but generating only the minimum required set of dependencies seems hard.
--- Note that we deliberately do not pin the system views.
--- First delete any already-made entries; PINs override all else, and must
--- be the only entries for their objects.
-DELETE FROM pg_depend;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_class;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_proc;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_type;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_cast;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_constraint;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_attrdef;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_language;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_operator;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_opclass;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_rewrite;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_trigger;
--- restriction here to avoid pinning the public namespace
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_namespace \
-    WHERE nspname LIKE 'pg%';
-EOF
-if [ "$?" -ne 0 ]; then
-    exit_nicely
-fi
-echo "ok"
-
-
-$ECHO_N "creating system views... "$ECHO_C
-
-"$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
-
-CREATE VIEW pg_user AS \
-    SELECT \
-        usename, \
-        usesysid, \
-        usecreatedb, \
-        usesuper, \
-        usecatupd, \
-        '********'::text as passwd, \
-        valuntil, \
-        useconfig \
-    FROM pg_shadow;
-
-CREATE VIEW pg_rules AS \
-    SELECT \
-        N.nspname AS schemaname, \
-        C.relname AS tablename, \
-        R.rulename AS rulename, \
-        pg_get_ruledef(R.oid) AS definition \
-    FROM (pg_rewrite R JOIN pg_class C ON (C.oid = R.ev_class)) \
-        LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \
-    WHERE R.rulename != '_RETURN';
-
-CREATE VIEW pg_views AS \
-    SELECT \
-        N.nspname AS schemaname, \
-        C.relname AS viewname, \
-        pg_get_userbyid(C.relowner) AS viewowner, \
-        pg_get_viewdef(C.oid) AS definition \
-    FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \
-    WHERE C.relkind = 'v';
-
-CREATE VIEW pg_tables AS \
-    SELECT \
-        N.nspname AS schemaname, \
-        C.relname AS tablename, \
-        pg_get_userbyid(C.relowner) AS tableowner, \
-        C.relhasindex AS hasindexes, \
-        C.relhasrules AS hasrules, \
-        (C.reltriggers > 0) AS hastriggers \
-    FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \
-    WHERE C.relkind = 'r';
-
-CREATE VIEW pg_indexes AS \
-    SELECT \
-        N.nspname AS schemaname, \
-        C.relname AS tablename, \
-        I.relname AS indexname, \
-        pg_get_indexdef(I.oid) AS indexdef \
-    FROM pg_index X JOIN pg_class C ON (C.oid = X.indrelid) \
-         JOIN pg_class I ON (I.oid = X.indexrelid) \
-         LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \
-    WHERE C.relkind = 'r' AND I.relkind = 'i';
-
-CREATE VIEW pg_stats AS \
-    SELECT \
-        nspname AS schemaname, \
-        relname AS tablename, \
-        attname AS attname, \
-        stanullfrac AS null_frac, \
-        stawidth AS avg_width, \
-        stadistinct AS n_distinct, \
-        CASE 1 \
-            WHEN stakind1 THEN stavalues1 \
-            WHEN stakind2 THEN stavalues2 \
-            WHEN stakind3 THEN stavalues3 \
-            WHEN stakind4 THEN stavalues4 \
-        END AS most_common_vals, \
-        CASE 1 \
-            WHEN stakind1 THEN stanumbers1 \
-            WHEN stakind2 THEN stanumbers2 \
-            WHEN stakind3 THEN stanumbers3 \
-            WHEN stakind4 THEN stanumbers4 \
-        END AS most_common_freqs, \
-        CASE 2 \
-            WHEN stakind1 THEN stavalues1 \
-            WHEN stakind2 THEN stavalues2 \
-            WHEN stakind3 THEN stavalues3 \
-            WHEN stakind4 THEN stavalues4 \
-        END AS histogram_bounds, \
-        CASE 3 \
-            WHEN stakind1 THEN stanumbers1[1] \
-            WHEN stakind2 THEN stanumbers2[1] \
-            WHEN stakind3 THEN stanumbers3[1] \
-            WHEN stakind4 THEN stanumbers4[1] \
-        END AS correlation \
-    FROM pg_statistic s JOIN pg_class c ON (c.oid = s.starelid) \
-         JOIN pg_attribute a ON (c.oid = attrelid AND attnum = s.staattnum) \
-         LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace) \
-    WHERE has_table_privilege(c.oid, 'select');
-
-REVOKE ALL on pg_statistic FROM public;
-
-CREATE VIEW pg_stat_all_tables AS \
-    SELECT \
-            C.oid AS relid, \
-            N.nspname AS schemaname, \
-            C.relname AS relname, \
-            pg_stat_get_numscans(C.oid) AS seq_scan, \
-            pg_stat_get_tuples_returned(C.oid) AS seq_tup_read, \
-            sum(pg_stat_get_numscans(I.indexrelid)) AS idx_scan, \
-            sum(pg_stat_get_tuples_fetched(I.indexrelid)) AS idx_tup_fetch, \
-            pg_stat_get_tuples_inserted(C.oid) AS n_tup_ins, \
-            pg_stat_get_tuples_updated(C.oid) AS n_tup_upd, \
-            pg_stat_get_tuples_deleted(C.oid) AS n_tup_del \
-    FROM pg_class C LEFT JOIN \
-         pg_index I ON C.oid = I.indrelid \
-         LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \
-    WHERE C.relkind = 'r' \
-    GROUP BY C.oid, N.nspname, C.relname;
-
-CREATE VIEW pg_stat_sys_tables AS \
-    SELECT * FROM pg_stat_all_tables \
-    WHERE schemaname IN ('pg_catalog', 'pg_toast');
-
-CREATE VIEW pg_stat_user_tables AS \
-    SELECT * FROM pg_stat_all_tables \
-    WHERE schemaname NOT IN ('pg_catalog', 'pg_toast');
-
-CREATE VIEW pg_statio_all_tables AS \
-    SELECT \
-            C.oid AS relid, \
-            N.nspname AS schemaname, \
-            C.relname AS relname, \
-            pg_stat_get_blocks_fetched(C.oid) - \
-                    pg_stat_get_blocks_hit(C.oid) AS heap_blks_read, \
-            pg_stat_get_blocks_hit(C.oid) AS heap_blks_hit, \
-            sum(pg_stat_get_blocks_fetched(I.indexrelid) - \
-                    pg_stat_get_blocks_hit(I.indexrelid)) AS idx_blks_read, \
-            sum(pg_stat_get_blocks_hit(I.indexrelid)) AS idx_blks_hit, \
-            pg_stat_get_blocks_fetched(T.oid) - \
-                    pg_stat_get_blocks_hit(T.oid) AS toast_blks_read, \
-            pg_stat_get_blocks_hit(T.oid) AS toast_blks_hit, \
-            pg_stat_get_blocks_fetched(X.oid) - \
-                    pg_stat_get_blocks_hit(X.oid) AS tidx_blks_read, \
-            pg_stat_get_blocks_hit(X.oid) AS tidx_blks_hit \
-    FROM pg_class C LEFT JOIN \
-            pg_index I ON C.oid = I.indrelid LEFT JOIN \
-            pg_class T ON C.reltoastrelid = T.oid LEFT JOIN \
-            pg_class X ON T.reltoastidxid = X.oid \
-            LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \
-    WHERE C.relkind = 'r' \
-    GROUP BY C.oid, N.nspname, C.relname, T.oid, X.oid;
-
-CREATE VIEW pg_statio_sys_tables AS \
-    SELECT * FROM pg_statio_all_tables \
-    WHERE schemaname IN ('pg_catalog', 'pg_toast');
-
-CREATE VIEW pg_statio_user_tables AS \
-    SELECT * FROM pg_statio_all_tables \
-    WHERE schemaname NOT IN ('pg_catalog', 'pg_toast');
-
-CREATE VIEW pg_stat_all_indexes AS \
-    SELECT \
-            C.oid AS relid, \
-            I.oid AS indexrelid, \
-            N.nspname AS schemaname, \
-            C.relname AS relname, \
-            I.relname AS indexrelname, \
-            pg_stat_get_numscans(I.oid) AS idx_scan, \
-            pg_stat_get_tuples_returned(I.oid) AS idx_tup_read, \
-            pg_stat_get_tuples_fetched(I.oid) AS idx_tup_fetch \
-    FROM pg_class C JOIN \
-            pg_index X ON C.oid = X.indrelid JOIN \
-            pg_class I ON I.oid = X.indexrelid \
-            LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \
-    WHERE C.relkind = 'r';
-
-CREATE VIEW pg_stat_sys_indexes AS \
-    SELECT * FROM pg_stat_all_indexes \
-    WHERE schemaname IN ('pg_catalog', 'pg_toast');
-
-CREATE VIEW pg_stat_user_indexes AS \
-    SELECT * FROM pg_stat_all_indexes \
-    WHERE schemaname NOT IN ('pg_catalog', 'pg_toast');
-
-CREATE VIEW pg_statio_all_indexes AS \
-    SELECT \
-            C.oid AS relid, \
-            I.oid AS indexrelid, \
-            N.nspname AS schemaname, \
-            C.relname AS relname, \
-            I.relname AS indexrelname, \
-            pg_stat_get_blocks_fetched(I.oid) - \
-                    pg_stat_get_blocks_hit(I.oid) AS idx_blks_read, \
-            pg_stat_get_blocks_hit(I.oid) AS idx_blks_hit \
-    FROM pg_class C JOIN \
-            pg_index X ON C.oid = X.indrelid JOIN \
-            pg_class I ON I.oid = X.indexrelid \
-            LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \
-    WHERE C.relkind = 'r';
-
-CREATE VIEW pg_statio_sys_indexes AS \
-    SELECT * FROM pg_statio_all_indexes \
-    WHERE schemaname IN ('pg_catalog', 'pg_toast');
-
-CREATE VIEW pg_statio_user_indexes AS \
-    SELECT * FROM pg_statio_all_indexes \
-    WHERE schemaname NOT IN ('pg_catalog', 'pg_toast');
-
-CREATE VIEW pg_statio_all_sequences AS \
-    SELECT \
-            C.oid AS relid, \
-            N.nspname AS schemaname, \
-            C.relname AS relname, \
-            pg_stat_get_blocks_fetched(C.oid) - \
-                    pg_stat_get_blocks_hit(C.oid) AS blks_read, \
-            pg_stat_get_blocks_hit(C.oid) AS blks_hit \
-    FROM pg_class C \
-            LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \
-    WHERE C.relkind = 'S';
-
-CREATE VIEW pg_statio_sys_sequences AS \
-    SELECT * FROM pg_statio_all_sequences \
-    WHERE schemaname IN ('pg_catalog', 'pg_toast');
-
-CREATE VIEW pg_statio_user_sequences AS \
-    SELECT * FROM pg_statio_all_sequences \
-    WHERE schemaname NOT IN ('pg_catalog', 'pg_toast');
-
-CREATE VIEW pg_stat_activity AS \
-    SELECT \
-            D.oid AS datid, \
-            D.datname AS datname, \
-            pg_stat_get_backend_pid(S.backendid) AS procpid, \
-            pg_stat_get_backend_userid(S.backendid) AS usesysid, \
-            U.usename AS usename, \
-            pg_stat_get_backend_activity(S.backendid) AS current_query, \
-            pg_stat_get_backend_activity_start(S.backendid) AS query_start \
-    FROM pg_database D, \
-            (SELECT pg_stat_get_backend_idset() AS backendid) AS S, \
-            pg_shadow U \
-    WHERE pg_stat_get_backend_dbid(S.backendid) = D.oid AND \
-            pg_stat_get_backend_userid(S.backendid) = U.usesysid;
-
-CREATE VIEW pg_stat_database AS \
-    SELECT \
-            D.oid AS datid, \
-            D.datname AS datname, \
-            pg_stat_get_db_numbackends(D.oid) AS numbackends, \
-            pg_stat_get_db_xact_commit(D.oid) AS xact_commit, \
-            pg_stat_get_db_xact_rollback(D.oid) AS xact_rollback, \
-            pg_stat_get_db_blocks_fetched(D.oid) - \
-                    pg_stat_get_db_blocks_hit(D.oid) AS blks_read, \
-            pg_stat_get_db_blocks_hit(D.oid) AS blks_hit \
-    FROM pg_database D;
-
-CREATE VIEW pg_locks AS \
-    SELECT * \
-    FROM pg_lock_status() AS L(relation oid, database oid, \
-       transaction xid, pid int4, mode text, granted boolean);
-
-CREATE VIEW pg_settings AS \
-    SELECT * \
-    FROM pg_show_all_settings() AS A \
-    (name text, setting text, context text, vartype text, \
-     source text, min_val text, max_val text);
-
-CREATE RULE pg_settings_u AS \
-    ON UPDATE TO pg_settings \
-    WHERE new.name = old.name DO \
-    SELECT set_config(old.name, new.setting, 'f');
-
-CREATE RULE pg_settings_n AS \
-    ON UPDATE TO pg_settings \
-    DO INSTEAD NOTHING;
-
-EOF
-if [ "$?" -ne 0 ]; then
-    exit_nicely
-fi
-echo "ok"
-
-$ECHO_N "loading pg_description... "$ECHO_C
-(
-  cat <<EOF
-    CREATE TEMP TABLE tmp_pg_description ( \
-       objoid oid, \
-       classname name, \
-       objsubid int4, \
-       description text) WITHOUT OIDS;
-    COPY tmp_pg_description FROM STDIN;
-EOF
-  cat "$POSTGRES_DESCR"
-  cat <<EOF
-\.
-    INSERT INTO pg_description SELECT \
-       t.objoid, c.oid, t.objsubid, t.description \
-    FROM tmp_pg_description t, pg_class c WHERE c.relname = t.classname;
-EOF
-) \
-       | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
-echo "ok"
-
-# Create pg_conversion and support functions
-$ECHO_N "creating conversions... "$ECHO_C
-grep -v '^DROP CONVERSION' $datadir/conversion_create.sql | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
-echo "ok"
-
-# Set most system catalogs and built-in functions as world-accessible.
-# Some objects may require different permissions by default, so we
-# make sure we don't overwrite privilege sets that have already been
-# set (NOT NULL).
-$ECHO_N "setting privileges on built-in objects... "$ECHO_C
-(
-  cat <<EOF
-    UPDATE pg_class SET relacl = '{"=r/\\\\"$POSTGRES_SUPERUSERNAME\\\\""}' \
-        WHERE relkind IN ('r', 'v', 'S') AND relacl IS NULL;
-    UPDATE pg_proc SET proacl = '{"=X/\\\\"$POSTGRES_SUPERUSERNAME\\\\""}' \
-        WHERE proacl IS NULL;
-    UPDATE pg_language SET lanacl = '{"=U/\\\\"$POSTGRES_SUPERUSERNAME\\\\""}' \
-        WHERE lanpltrusted;
-    GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;
-    GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;
-EOF
-) \
-       | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
-echo "ok"
-
-$ECHO_N "creating information schema... "$ECHO_C
-"$PGPATH"/postgres $PGSQL_OPT -N template1 > /dev/null < "$datadir"/information_schema.sql || exit_nicely
-(
-  # Format version number to format required by information schema (09.08.0007abc).
-  major_version=`echo $VERSION | sed 's/^\([0-9]*\).*/00\1/;s/.*\(..\)$/\1/'`
-  minor_version=`echo $VERSION | sed 's/^[0-9]*\.\([0-9]*\).*/00\1/;s/.*\(..\)$/\1/'`
-  micro_version=`echo $VERSION | sed -e 's/^[0-9]*\.[0-9]*\.\([0-9]*\).*/0000\1/' -e 't L' -e 's/.*/0000/;q' -e ': L' -e 's/.*\(....\)$/\1/'`
-  letter_version=`echo $VERSION | sed 's/^.*[0-9]\([^0-9]*\)$/\1/'`
-  combined_version="$major_version.$minor_version.$micro_version$letter_version"
-
-  echo "UPDATE information_schema.sql_implementation_info SET character_value = '$combined_version' WHERE implementation_info_name = 'DBMS VERSION';"
-
-  echo "COPY information_schema.sql_features (feature_id, feature_name, sub_feature_id, sub_feature_name, is_supported, comments) FROM '$datadir/sql_features.txt';"
-) \
-       | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
-echo "ok"
-
-$ECHO_N "vacuuming database template1... "$ECHO_C
-
-"$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
-ANALYZE;
-VACUUM FULL FREEZE;
-EOF
-if [ "$?" -ne 0 ]; then
-    exit_nicely
-fi
-echo "ok"
-
-$ECHO_N "copying template1 to template0... "$ECHO_C
-
-"$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
-CREATE DATABASE template0;
-
-UPDATE pg_database SET \
-       datistemplate = 't', \
-       datallowconn = 'f' \
-    WHERE datname = 'template0';
-
--- We use the OID of template0 to determine lastsysoid
-
-UPDATE pg_database SET datlastsysoid = \
-    (SELECT oid::int4 - 1 FROM pg_database WHERE datname = 'template0');
-
--- Explicitly revoke public create-schema and create-temp-table privileges
--- in template1 and template0; else the latter would be on by default
-
-REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;
-REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;
-
--- Finally vacuum to clean up dead rows in pg_database
-
-VACUUM FULL pg_database;
-EOF
-if [ "$?" -ne 0 ]; then
-    exit_nicely
-fi
-echo "ok"
-
-
-##########################################################################
-#
-# FINISHED
-
-echo
-echo "Success. You can now start the database server using:"
-echo ""
-echo "    $PGPATH/postmaster -D $PGDATA"
-echo "or"
-# (Advertise -l option here, otherwise we have a background
-#  process writing to the terminal.)
-echo "    $PGPATH/pg_ctl -D $PGDATA -l logfile start"
-echo
-
-exit 0
diff --git a/src/bin/initdb/system_views.sql b/src/bin/initdb/system_views.sql
new file mode 100755 (executable)
index 0000000..524468f
--- /dev/null
@@ -0,0 +1,270 @@
+\r
+\r
+\r
+CREATE VIEW pg_user AS \r
+    SELECT \r
+        usename, \r
+        usesysid, \r
+        usecreatedb, \r
+        usesuper, \r
+        usecatupd, \r
+        '********'::text as passwd, \r
+        valuntil, \r
+        useconfig \r
+    FROM pg_shadow;\r
+\r
+CREATE VIEW pg_rules AS \r
+    SELECT \r
+        N.nspname AS schemaname, \r
+        C.relname AS tablename, \r
+        R.rulename AS rulename, \r
+        pg_get_ruledef(R.oid) AS definition \r
+    FROM (pg_rewrite R JOIN pg_class C ON (C.oid = R.ev_class)) \r
+        LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \r
+    WHERE R.rulename != '_RETURN';\r
+\r
+CREATE VIEW pg_views AS \r
+    SELECT \r
+        N.nspname AS schemaname, \r
+        C.relname AS viewname, \r
+        pg_get_userbyid(C.relowner) AS viewowner, \r
+        pg_get_viewdef(C.oid) AS definition \r
+    FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \r
+    WHERE C.relkind = 'v';\r
+\r
+CREATE VIEW pg_tables AS \r
+    SELECT \r
+        N.nspname AS schemaname, \r
+        C.relname AS tablename, \r
+        pg_get_userbyid(C.relowner) AS tableowner, \r
+        C.relhasindex AS hasindexes, \r
+        C.relhasrules AS hasrules, \r
+        (C.reltriggers > 0) AS hastriggers \r
+    FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \r
+    WHERE C.relkind = 'r';\r
+\r
+CREATE VIEW pg_indexes AS \r
+    SELECT \r
+        N.nspname AS schemaname, \r
+        C.relname AS tablename, \r
+        I.relname AS indexname, \r
+        pg_get_indexdef(I.oid) AS indexdef \r
+    FROM pg_index X JOIN pg_class C ON (C.oid = X.indrelid) \r
+         JOIN pg_class I ON (I.oid = X.indexrelid) \r
+         LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \r
+    WHERE C.relkind = 'r' AND I.relkind = 'i';\r
+\r
+CREATE VIEW pg_stats AS \r
+    SELECT \r
+        nspname AS schemaname, \r
+        relname AS tablename, \r
+        attname AS attname, \r
+        stanullfrac AS null_frac, \r
+        stawidth AS avg_width, \r
+        stadistinct AS n_distinct, \r
+        CASE 1 \r
+            WHEN stakind1 THEN stavalues1 \r
+            WHEN stakind2 THEN stavalues2 \r
+            WHEN stakind3 THEN stavalues3 \r
+            WHEN stakind4 THEN stavalues4 \r
+        END AS most_common_vals, \r
+        CASE 1 \r
+            WHEN stakind1 THEN stanumbers1 \r
+            WHEN stakind2 THEN stanumbers2 \r
+            WHEN stakind3 THEN stanumbers3 \r
+            WHEN stakind4 THEN stanumbers4 \r
+        END AS most_common_freqs, \r
+        CASE 2 \r
+            WHEN stakind1 THEN stavalues1 \r
+            WHEN stakind2 THEN stavalues2 \r
+            WHEN stakind3 THEN stavalues3 \r
+            WHEN stakind4 THEN stavalues4 \r
+        END AS histogram_bounds, \r
+        CASE 3 \r
+            WHEN stakind1 THEN stanumbers1[1] \r
+            WHEN stakind2 THEN stanumbers2[1] \r
+            WHEN stakind3 THEN stanumbers3[1] \r
+            WHEN stakind4 THEN stanumbers4[1] \r
+        END AS correlation \r
+    FROM pg_statistic s JOIN pg_class c ON (c.oid = s.starelid) \r
+         JOIN pg_attribute a ON (c.oid = attrelid AND attnum = s.staattnum) \r
+         LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace) \r
+    WHERE has_table_privilege(c.oid, 'select');\r
+\r
+REVOKE ALL on pg_statistic FROM public;\r
+\r
+CREATE VIEW pg_stat_all_tables AS \r
+    SELECT \r
+            C.oid AS relid, \r
+            N.nspname AS schemaname, \r
+            C.relname AS relname, \r
+            pg_stat_get_numscans(C.oid) AS seq_scan, \r
+            pg_stat_get_tuples_returned(C.oid) AS seq_tup_read, \r
+            sum(pg_stat_get_numscans(I.indexrelid)) AS idx_scan, \r
+            sum(pg_stat_get_tuples_fetched(I.indexrelid)) AS idx_tup_fetch, \r
+            pg_stat_get_tuples_inserted(C.oid) AS n_tup_ins, \r
+            pg_stat_get_tuples_updated(C.oid) AS n_tup_upd, \r
+            pg_stat_get_tuples_deleted(C.oid) AS n_tup_del \r
+    FROM pg_class C LEFT JOIN \r
+         pg_index I ON C.oid = I.indrelid \r
+         LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \r
+    WHERE C.relkind = 'r' \r
+    GROUP BY C.oid, N.nspname, C.relname;\r
+\r
+CREATE VIEW pg_stat_sys_tables AS \r
+    SELECT * FROM pg_stat_all_tables \r
+    WHERE schemaname IN ('pg_catalog', 'pg_toast');\r
+\r
+CREATE VIEW pg_stat_user_tables AS \r
+    SELECT * FROM pg_stat_all_tables \r
+    WHERE schemaname NOT IN ('pg_catalog', 'pg_toast');\r
+\r
+CREATE VIEW pg_statio_all_tables AS \r
+    SELECT \r
+            C.oid AS relid, \r
+            N.nspname AS schemaname, \r
+            C.relname AS relname, \r
+            pg_stat_get_blocks_fetched(C.oid) - \r
+                    pg_stat_get_blocks_hit(C.oid) AS heap_blks_read, \r
+            pg_stat_get_blocks_hit(C.oid) AS heap_blks_hit, \r
+            sum(pg_stat_get_blocks_fetched(I.indexrelid) - \r
+                    pg_stat_get_blocks_hit(I.indexrelid)) AS idx_blks_read, \r
+            sum(pg_stat_get_blocks_hit(I.indexrelid)) AS idx_blks_hit, \r
+            pg_stat_get_blocks_fetched(T.oid) - \r
+                    pg_stat_get_blocks_hit(T.oid) AS toast_blks_read, \r
+            pg_stat_get_blocks_hit(T.oid) AS toast_blks_hit, \r
+            pg_stat_get_blocks_fetched(X.oid) - \r
+                    pg_stat_get_blocks_hit(X.oid) AS tidx_blks_read, \r
+            pg_stat_get_blocks_hit(X.oid) AS tidx_blks_hit \r
+    FROM pg_class C LEFT JOIN \r
+            pg_index I ON C.oid = I.indrelid LEFT JOIN \r
+            pg_class T ON C.reltoastrelid = T.oid LEFT JOIN \r
+            pg_class X ON T.reltoastidxid = X.oid \r
+            LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \r
+    WHERE C.relkind = 'r' \r
+    GROUP BY C.oid, N.nspname, C.relname, T.oid, X.oid;\r
+\r
+CREATE VIEW pg_statio_sys_tables AS \r
+    SELECT * FROM pg_statio_all_tables \r
+    WHERE schemaname IN ('pg_catalog', 'pg_toast');\r
+\r
+CREATE VIEW pg_statio_user_tables AS \r
+    SELECT * FROM pg_statio_all_tables \r
+    WHERE schemaname NOT IN ('pg_catalog', 'pg_toast');\r
+\r
+CREATE VIEW pg_stat_all_indexes AS \r
+    SELECT \r
+            C.oid AS relid, \r
+            I.oid AS indexrelid, \r
+            N.nspname AS schemaname, \r
+            C.relname AS relname, \r
+            I.relname AS indexrelname, \r
+            pg_stat_get_numscans(I.oid) AS idx_scan, \r
+            pg_stat_get_tuples_returned(I.oid) AS idx_tup_read, \r
+            pg_stat_get_tuples_fetched(I.oid) AS idx_tup_fetch \r
+    FROM pg_class C JOIN \r
+            pg_index X ON C.oid = X.indrelid JOIN \r
+            pg_class I ON I.oid = X.indexrelid \r
+            LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \r
+    WHERE C.relkind = 'r';\r
+\r
+CREATE VIEW pg_stat_sys_indexes AS \r
+    SELECT * FROM pg_stat_all_indexes \r
+    WHERE schemaname IN ('pg_catalog', 'pg_toast');\r
+\r
+CREATE VIEW pg_stat_user_indexes AS \r
+    SELECT * FROM pg_stat_all_indexes \r
+    WHERE schemaname NOT IN ('pg_catalog', 'pg_toast');\r
+\r
+CREATE VIEW pg_statio_all_indexes AS \r
+    SELECT \r
+            C.oid AS relid, \r
+            I.oid AS indexrelid, \r
+            N.nspname AS schemaname, \r
+            C.relname AS relname, \r
+            I.relname AS indexrelname, \r
+            pg_stat_get_blocks_fetched(I.oid) - \r
+                    pg_stat_get_blocks_hit(I.oid) AS idx_blks_read, \r
+            pg_stat_get_blocks_hit(I.oid) AS idx_blks_hit \r
+    FROM pg_class C JOIN \r
+            pg_index X ON C.oid = X.indrelid JOIN \r
+            pg_class I ON I.oid = X.indexrelid \r
+            LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \r
+    WHERE C.relkind = 'r';\r
+\r
+CREATE VIEW pg_statio_sys_indexes AS \r
+    SELECT * FROM pg_statio_all_indexes \r
+    WHERE schemaname IN ('pg_catalog', 'pg_toast');\r
+\r
+CREATE VIEW pg_statio_user_indexes AS \r
+    SELECT * FROM pg_statio_all_indexes \r
+    WHERE schemaname NOT IN ('pg_catalog', 'pg_toast');\r
+\r
+CREATE VIEW pg_statio_all_sequences AS \r
+    SELECT \r
+            C.oid AS relid, \r
+            N.nspname AS schemaname, \r
+            C.relname AS relname, \r
+            pg_stat_get_blocks_fetched(C.oid) - \r
+                    pg_stat_get_blocks_hit(C.oid) AS blks_read, \r
+            pg_stat_get_blocks_hit(C.oid) AS blks_hit \r
+    FROM pg_class C \r
+            LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) \r
+    WHERE C.relkind = 'S';\r
+\r
+CREATE VIEW pg_statio_sys_sequences AS \r
+    SELECT * FROM pg_statio_all_sequences \r
+    WHERE schemaname IN ('pg_catalog', 'pg_toast');\r
+\r
+CREATE VIEW pg_statio_user_sequences AS \r
+    SELECT * FROM pg_statio_all_sequences \r
+    WHERE schemaname NOT IN ('pg_catalog', 'pg_toast');\r
+\r
+CREATE VIEW pg_stat_activity AS \r
+    SELECT \r
+            D.oid AS datid, \r
+            D.datname AS datname, \r
+            pg_stat_get_backend_pid(S.backendid) AS procpid, \r
+            pg_stat_get_backend_userid(S.backendid) AS usesysid, \r
+            U.usename AS usename, \r
+            pg_stat_get_backend_activity(S.backendid) AS current_query, \r
+            pg_stat_get_backend_activity_start(S.backendid) AS query_start \r
+    FROM pg_database D, \r
+            (SELECT pg_stat_get_backend_idset() AS backendid) AS S, \r
+            pg_shadow U \r
+    WHERE pg_stat_get_backend_dbid(S.backendid) = D.oid AND \r
+            pg_stat_get_backend_userid(S.backendid) = U.usesysid;\r
+\r
+CREATE VIEW pg_stat_database AS \r
+    SELECT \r
+            D.oid AS datid, \r
+            D.datname AS datname, \r
+            pg_stat_get_db_numbackends(D.oid) AS numbackends, \r
+            pg_stat_get_db_xact_commit(D.oid) AS xact_commit, \r
+            pg_stat_get_db_xact_rollback(D.oid) AS xact_rollback, \r
+            pg_stat_get_db_blocks_fetched(D.oid) - \r
+                    pg_stat_get_db_blocks_hit(D.oid) AS blks_read, \r
+            pg_stat_get_db_blocks_hit(D.oid) AS blks_hit \r
+    FROM pg_database D;\r
+\r
+CREATE VIEW pg_locks AS \r
+    SELECT * \r
+    FROM pg_lock_status() AS L(relation oid, database oid, \r
+       transaction xid, pid int4, mode text, granted boolean);\r
+\r
+CREATE VIEW pg_settings AS \r
+    SELECT * \r
+    FROM pg_show_all_settings() AS A \r
+    (name text, setting text, context text, vartype text, \r
+     source text, min_val text, max_val text);\r
+\r
+CREATE RULE pg_settings_u AS \r
+    ON UPDATE TO pg_settings \r
+    WHERE new.name = old.name DO \r
+    SELECT set_config(old.name, new.setting, 'f');\r
+\r
+CREATE RULE pg_settings_n AS \r
+    ON UPDATE TO pg_settings \r
+    DO INSTEAD NOTHING;\r
+\r
+\r