]> granicus.if.org Git - postgresql/blobdiff - src/bin/initdb/initdb.c
Fix HAVE_OPTRESET to be HAVE_INT_OPTRESET. Typos spotted by Lorne Sunley.
[postgresql] / src / bin / initdb / initdb.c
index e5bd3e3bd8e0171662c0fa81e79432031c6b116b..a0b2f3357eb8358d5d9f25de3598dfce25ee5faa 100644 (file)
@@ -1,29 +1,45 @@
 /*-------------------------------------------------------------------------
  *
- * initdb
+ * initdb --- initialize a PostgreSQL installation
  *
- * author: Andrew Dunstan         mailto:andrew@dunslane.net
+ * 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.
  *
- * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
+ * 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.  Some of those commands are
+ * just embedded into this program (yeah, it's ugly), but larger chunks
+ * are taken from script files.
+ *
+ * template0 is made just by copying the completed template1.
+ *
+ * Note:
+ *      The program has some memory leakage - it isn't worth cleaning it up.
  *
- * 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.
+ * author of C translation: Andrew Dunstan        mailto:andrew@dunslane.net
  *
- * $Header: /cvsroot/pgsql/src/bin/initdb/initdb.c,v 1.3 2003/11/13 01:09:24 tgl Exp $
+ * This code is released under the terms of the PostgreSQL License.
  *
- * TODO:
- *      - clean up find_postgres code and return values
+ * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ * Portions taken from FreeBSD.
  *
- * 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?
+ * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.68 2004/11/27 18:51:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include <unistd.h>
 #include <locale.h>
 #include <signal.h>
+#include <errno.h>
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
 
 #include "libpq/pqsignal.h"
 #include "mb/pg_wchar.h"
 #include "getopt_long.h"
 
-#ifndef HAVE_OPTRESET
+#ifndef HAVE_INT_OPTRESET
 int                    optreset;
 #endif
 
 
+#define _(x) gettext((x))
+
 /* 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;
+/*
+ * these values are passed in by makefile defines
+ */
+char      *share_path = NULL;
 
 /* values to be obtained from arguments */
 char      *pg_data = "";
@@ -65,16 +87,15 @@ char           *lc_time = "";
 char      *lc_messages = "";
 char      *username = "";
 bool           pwprompt = false;
+char      *pwfilename = NULL;
+char      *authmethod = "";
 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;
+const char *progname;
 char      *postgres;
 char      *encodingid = "0";
 char      *bki_file;
@@ -89,64 +110,63 @@ char          *system_views_file;
 char      *effective_user;
 bool           testpath = true;
 bool           made_new_pgdata = false;
+bool           found_existing_pgdata = false;
 char           infoversion[100];
-bool           not_ok = false;
+bool           caught_signal = false;
+bool           output_failed = false;
 
 /* defaults */
 int                    n_connections = 10;
 int                    n_buffers = 50;
 
+/*
+ * Warning messages for authentication methods
+ */
+char      *authtrust_warning = \
+"# CAUTION: Configuring the system for local \"trust\" authentication allows\n"
+"# any local user to connect as any PostgreSQL user, including the database\n"
+"# superuser. If you do not trust all your local users, use another\n"
+"# authentication method.\n";
+char      *authwarning = NULL;
 
-/* platform specific path stuff */
-#if defined(__CYGWIN__) || defined(WIN32)
-#define EXE ".exe"
-#define DEVNULL "nul"
-#else
-#define EXE ""
-#define DEVNULL "/dev/null"
-#endif
-
-#ifdef WIN32
-#define PATHSEP ';'
-#else
-#define PATHSEP ':'
-#endif
+/*
+ * Centralized knowledge of switches to pass to backend
+ *
+ * Note: in the shell-script version, we also passed PGDATA as a -D switch,
+ * but here it is more convenient to pass it as an environment variable
+ * (no quoting to worry about).
+ */
+static const char *boot_options = "-F";
+static const char *backend_options = "-F -O -c search_path=pg_catalog -c exit_on_error=true";
 
-/* 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 canonicalize_path(char *);
+/* path to 'initdb' binary directory */
+char           bin_path[MAXPGPATH];
+char           backend_exec[MAXPGPATH];
 
-#ifdef WIN32
-static char *expanded_path(char *);
-#else
-#define expanded_path(x) (x)
+static void *xmalloc(size_t size);
+static char *xstrdup(const char *s);
+static char **replace_token(char **lines, char *token, char *replacement);
+#ifndef HAVE_UNIX_SOCKETS
+static char **filter_lines_with_token(char **lines, char *token);
 #endif
-
-static char **readfile(char *);
-static void writefile(char *, char **);
+static char **readfile(char *path);
+static void writefile(char *path, char **lines);
+static int     mkdir_p(char *path, mode_t omode);
+static void exit_nicely(void);
 static char *get_id(void);
-static char *get_encoding_id(char *);
+static char *get_encoding_id(char *encoding_name);
 static char *get_short_version(void);
-static int     mkdir_p(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 int     check_data_dir(void);
+static bool mkdatadir(const char *subdir);
+static void set_input(char **dest, char *filename);
 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_short_version(char *short_version, char *extrapath);
 static void set_null_conf(void);
-static void test_buffers(void);
 static void test_connections(void);
+static void test_buffers(void);
 static void setup_config(void);
-static void bootstrap_template1(char *);
+static void bootstrap_template1(char *short_version);
 static void setup_shadow(void);
 static void get_set_pwd(void);
 static void unlimit_systables(void);
@@ -159,11 +179,13 @@ 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 trapsig(int signum);
 static void check_ok(void);
-static char *xstrdup(const char *);
-static void *xmalloc(size_t);
+static char *escape_quotes(const char *src);
+static bool chklocale(const char *locale);
+static void setlocales(void);
+static void usage(const char *progname);
+
 
 /*
  * macros for running pipes to postgres
@@ -173,22 +195,23 @@ static void *xmalloc(size_t);
 
 #define PG_CMD_OPEN \
 do { \
-                 pg = popen(cmd,PG_BINARY_W); \
-                 if (pg == NULL)  \
-                       exit_nicely(); \
+       fflush(stdout); \
+       fflush(stderr); \
+       pg = popen(cmd, "w"); \
+       if (pg == NULL) \
+               exit_nicely(); \
 } while (0)
 
 #define PG_CMD_CLOSE \
 do { \
-                if(pclose(pg) >> 8 & 0xff) \
-                       exit_nicely(); \
+       if (pclose_check(pg)) \
+               exit_nicely(); \
 } while (0)
 
 #define PG_CMD_PUTLINE \
 do { \
-                if (fputs(*line, pg) < 0) \
-                  exit_nicely(); \
-                fflush(pg); \
+       if (fputs(*line, pg) < 0 || fflush(pg) < 0) \
+               output_failed = true; \
 } while (0)
 
 #ifndef WIN32
@@ -199,9 +222,9 @@ do { \
 
 /*
  * 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)
@@ -211,7 +234,7 @@ xmalloc(size_t size)
        result = malloc(size);
        if (!result)
        {
-               fputs("malloc failure - bailing out\n", stderr);
+               fprintf(stderr, _("%s: out of memory\n"), progname);
                exit(1);
        }
        return result;
@@ -225,64 +248,16 @@ xstrdup(const char *s)
        result = strdup(s);
        if (!result)
        {
-               fputs("strdup failure - bailing out\n", stderr);
+               fprintf(stderr, _("%s: out of memory\n"), progname);
                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            buf[MAXPGPATH + 64];
-
-#ifndef WIN32
-       /* doesn't handle .* files */
-       snprintf(buf, sizeof(buf), "rm -rf '%s%s'", path,
-               rmtopdir ? "" : "/*");
-#else
-       snprintf(buf, sizeof(buf), "%s /s /q \"%s\"",
-               rmtopdir ? "rmdir" : "del", path);
-#endif
-
-       return !system(buf);
-}
-
-
-/*
- * make all paths look like unix, with forward slashes
- * also strip any trailing slash.
- * The Windows command processor will accept suitably quoted paths
- * with forward slashes, but barfs badly with mixed forward and back
- * slashes. Removing the trailing slash on a path means we never get
- * ugly double slashes.
- */
-static void
-canonicalize_path(char *path)
-{
-       char       *p;
-
-       for (p = path; *p; p++)
-       {
-#ifdef WIN32
-               if (*p == '\\')
-                       *p = '/';
-#endif
-       }
-       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.
  */
@@ -340,9 +315,36 @@ replace_token(char **lines, char *token, char *replacement)
 }
 
 /*
- * get the lines from a text file
+ * make a copy of lines without any that contain the token
+ * a sort of poor man's grep -v
  *
  */
+#ifndef HAVE_UNIX_SOCKETS
+static char **
+filter_lines_with_token(char **lines, char *token)
+{
+       int                     numlines = 1;
+       int                     i, src, dst;
+       char      **result;
+
+       for (i = 0; lines[i]; i++)
+               numlines++;
+
+       result = (char **) xmalloc(numlines * sizeof(char *));
+
+       for (src = 0, dst = 0; src < numlines; src++)
+       {
+               if (lines[src] == NULL || strstr(lines[src], token) == NULL)
+                       result[dst++] = lines[src];
+       }
+
+       return result;
+}
+#endif
+
+/*
+ * get the lines from a text file
+ */
 static char **
 readfile(char *path)
 {
@@ -356,7 +358,8 @@ readfile(char *path)
 
        if ((infile = fopen(path, "r")) == NULL)
        {
-               fprintf(stderr, "could not read %s ... ", path);
+               fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
+                               progname, path, strerror(errno));
                exit_nicely();
        }
 
@@ -405,6 +408,8 @@ readfile(char *path)
 /*
  * write an array of lines to a file
  *
+ * This is only used to write text files.  Use fopen "w" not PG_BINARY_W
+ * so that the resulting configuration files are nicely editable on Windows.
  */
 static void
 writefile(char *path, char **lines)
@@ -412,10 +417,10 @@ writefile(char *path, char **lines)
        FILE       *out_file;
        char      **line;
 
-       ;
-       if ((out_file = fopen(path, PG_BINARY_W)) == NULL)
+       if ((out_file = fopen(path, "w")) == NULL)
        {
-               fprintf(stderr, "could not write %s ... ", path);
+               fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
+                               progname, path, strerror(errno));
                exit_nicely();
        }
        for (line = lines; *line != NULL; line++)
@@ -434,7 +439,6 @@ writefile(char *path, char **lines)
  * 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
 mkdir_p(char *path, mode_t omode)
@@ -481,7 +485,7 @@ mkdir_p(char *path, mode_t omode)
                else if (p[0] != '/')
                        continue;
                *p = '\0';
-               if (p[1] == '\0')
+               if (!last && p[1] == '\0')
                        last = 1;
                if (first)
                {
@@ -539,38 +543,46 @@ mkdir_p(char *path, mode_t omode)
 /*
  * 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);
+       fprintf(stderr, _("%s: failed\n"), progname);
 
        if (!noclean)
        {
                if (made_new_pgdata)
                {
-                       fprintf(stderr, "%s: removing data directory \"%s\"\n",
+                       fprintf(stderr, _("%s: removing data directory \"%s\"\n"),
                                        progname, pg_data);
                        if (!rmtree(pg_data, true))
-                               fprintf(stderr, "%s: failed\n", progname);
+                               fprintf(stderr, _("%s: failed\n"), progname);
                }
-               else
+               else if (found_existing_pgdata)
                {
                        fprintf(stderr,
-                                       "%s: removing contents of data directory \"%s\"\n",
+                                       _("%s: removing contents of data directory \"%s\"\n"),
                                        progname, pg_data);
                        if (!rmtree(pg_data, false))
-                               fprintf(stderr, "%s: failed\n", progname);
+                               fprintf(stderr, _("%s: failed\n"), progname);
                }
+               /* otherwise died during startup, do nothing! */
        }
+       else
+       {
+               if (made_new_pgdata || found_existing_pgdata)
+                       fprintf(stderr,
+                                       _("%s: data directory \"%s\" not removed at user's request\n"),
+                                       progname, pg_data);
+       }
+
        exit(1);
 }
 
 /*
- * find the current user using code lifted from pg_id.c
- * on unix make sure it isn't really root
+ * find the current user
  *
+ * on unix make sure it isn't really root
  */
 static char *
 get_id(void)
@@ -586,9 +598,10 @@ get_id(void)
        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",
+                               _("%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);
        }
@@ -611,33 +624,221 @@ get_id(void)
        return xstrdup(pw->pw_name);
 }
 
+static char *
+encodingid_to_string(int enc)
+{
+       char            result[20];
+
+       sprintf(result, "%d", enc);
+       return xstrdup(result);
+}
+
 /*
  * 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);
-               }
+                       return encodingid_to_string(enc);
        }
-       fprintf(stderr, "%s: \"%s\" is not a valid server encoding name\n",
+       fprintf(stderr, _("%s: \"%s\" is not a valid server encoding name\n"),
                        progname, encoding_name ? encoding_name : "(null)");
        exit(1);
 }
 
+#if defined(HAVE_LANGINFO_H) && defined(CODESET)
+/*
+ * Checks whether the encoding selected for PostgreSQL and the
+ * encoding used by the system locale match.
+ */
+
+struct encoding_match
+{
+       enum pg_enc pg_enc_code;
+       char       *system_enc_name;
+};
+
+struct encoding_match encoding_match_list[] = {
+       {PG_EUC_JP, "EUC-JP"},
+       {PG_EUC_JP, "eucJP"},
+       {PG_EUC_JP, "IBM-eucJP"},
+       {PG_EUC_JP, "sdeckanji"},
+
+       {PG_EUC_CN, "EUC-CN"},
+       {PG_EUC_CN, "eucCN"},
+       {PG_EUC_CN, "IBM-eucCN"},
+       {PG_EUC_CN, "GB2312"},
+       {PG_EUC_CN, "dechanzi"},
+
+       {PG_EUC_KR, "EUC-KR"},
+       {PG_EUC_KR, "eucKR"},
+       {PG_EUC_KR, "IBM-eucKR"},
+       {PG_EUC_KR, "deckorean"},
+       {PG_EUC_KR, "5601"},
+
+       {PG_EUC_TW, "EUC-TW"},
+       {PG_EUC_TW, "eucTW"},
+       {PG_EUC_TW, "IBM-eucTW"},
+       {PG_EUC_TW, "cns11643"},
+
+#ifdef NOT_VERIFIED
+       {PG_JOHAB, "???"},
+#endif
+
+       {PG_UTF8, "UTF-8"},
+       {PG_UTF8, "utf8"},
+
+       {PG_LATIN1, "ISO-8859-1"},
+       {PG_LATIN1, "ISO8859-1"},
+       {PG_LATIN1, "iso88591"},
+
+       {PG_LATIN2, "ISO-8859-2"},
+       {PG_LATIN2, "ISO8859-2"},
+       {PG_LATIN2, "iso88592"},
+
+       {PG_LATIN3, "ISO-8859-3"},
+       {PG_LATIN3, "ISO8859-3"},
+       {PG_LATIN3, "iso88593"},
+
+       {PG_LATIN4, "ISO-8859-4"},
+       {PG_LATIN4, "ISO8859-4"},
+       {PG_LATIN4, "iso88594"},
+
+       {PG_LATIN5, "ISO-8859-9"},
+       {PG_LATIN5, "ISO8859-9"},
+       {PG_LATIN5, "iso88599"},
+
+       {PG_LATIN6, "ISO-8859-10"},
+       {PG_LATIN6, "ISO8859-10"},
+       {PG_LATIN6, "iso885910"},
+
+       {PG_LATIN7, "ISO-8859-13"},
+       {PG_LATIN7, "ISO8859-13"},
+       {PG_LATIN7, "iso885913"},
+
+       {PG_LATIN8, "ISO-8859-14"},
+       {PG_LATIN8, "ISO8859-14"},
+       {PG_LATIN8, "iso885914"},
+
+       {PG_LATIN9, "ISO-8859-15"},
+       {PG_LATIN9, "ISO8859-15"},
+       {PG_LATIN9, "iso885915"},
+
+       {PG_LATIN10, "ISO-8859-16"},
+       {PG_LATIN10, "ISO8859-16"},
+       {PG_LATIN10, "iso885916"},
+
+       {PG_WIN1256, "CP1256"},
+       {PG_TCVN, "CP1258"},
+#ifdef NOT_VERIFIED
+       {PG_WIN874, "???"},
+#endif
+       {PG_KOI8R, "KOI8-R"},
+       {PG_WIN1251, "CP1251"},
+       {PG_ALT, "CP866"},
+
+       {PG_ISO_8859_5, "ISO-8859-5"},
+       {PG_ISO_8859_5, "ISO8859-5"},
+       {PG_ISO_8859_5, "iso88595"},
+
+       {PG_ISO_8859_6, "ISO-8859-6"},
+       {PG_ISO_8859_6, "ISO8859-6"},
+       {PG_ISO_8859_6, "iso88596"},
+
+       {PG_ISO_8859_7, "ISO-8859-7"},
+       {PG_ISO_8859_7, "ISO8859-7"},
+       {PG_ISO_8859_7, "iso88597"},
+
+       {PG_ISO_8859_8, "ISO-8859-8"},
+       {PG_ISO_8859_8, "ISO8859-8"},
+       {PG_ISO_8859_8, "iso88598"},
+
+       {PG_SQL_ASCII, NULL}            /* end marker */
+};
+
+static char *
+get_encoding_from_locale(const char *ctype)
+{
+       char       *save;
+       char       *sys;
+
+       save = setlocale(LC_CTYPE, NULL);
+       if (!save)
+               return NULL;
+       save = xstrdup(save);
+
+       setlocale(LC_CTYPE, ctype);
+       sys = nl_langinfo(CODESET);
+       sys = xstrdup(sys);
+
+       setlocale(LC_CTYPE, save);
+       free(save);
+
+       return sys;
+}
+
+static void
+check_encodings_match(int pg_enc, const char *ctype)
+{
+       char       *sys;
+       int                     i;
+
+       sys = get_encoding_from_locale(ctype);
+
+       for (i = 0; encoding_match_list[i].system_enc_name; i++)
+       {
+               if (pg_enc == encoding_match_list[i].pg_enc_code
+                && strcasecmp(sys, encoding_match_list[i].system_enc_name) == 0)
+               {
+                       free(sys);
+                       return;
+               }
+       }
+
+       fprintf(stderr,
+                       _("%s: warning: encoding mismatch\n"), progname);
+       fprintf(stderr,
+                       _("The encoding you selected (%s) and the encoding that the selected\n"
+                  "locale uses (%s) are not known to match.  This may lead to\n"
+                         "misbehavior in various character string processing functions.  To fix\n"
+          "this situation, rerun %s and either do not specify an encoding\n"
+                         "explicitly, or choose a matching combination.\n"),
+                       pg_encoding_to_char(pg_enc), sys, progname);
+
+       free(sys);
+       return;
+}
+
+static int
+find_matching_encoding(const char *ctype)
+{
+       char       *sys;
+       int                     i;
+
+       sys = get_encoding_from_locale(ctype);
+
+       for (i = 0; encoding_match_list[i].system_enc_name; i++)
+       {
+               if (strcasecmp(sys, encoding_match_list[i].system_enc_name) == 0)
+               {
+                       free(sys);
+                       return encoding_match_list[i].pg_enc_code;
+               }
+       }
+
+       free(sys);
+       return -1;
+}
+#endif   /* HAVE_LANGINFO_H && CODESET */
+
 /*
  * get short version of VERSION
- *
  */
 static char *
 get_short_version(void)
@@ -675,18 +876,22 @@ get_short_version(void)
 /*
  * make sure the data directory either doesn't exist or is empty
  *
+ * Returns 0 if nonexistent, 1 if exists and empty, 2 if not empty,
+ * or -1 if trouble accessing directory
  */
-static bool
+static int
 check_data_dir(void)
 {
        DIR                *chkdir;
        struct dirent *file;
-       bool            empty = true;
+       int                     result = 1;
+
+       errno = 0;
 
        chkdir = opendir(pg_data);
 
        if (!chkdir)
-               return (errno == ENOENT);
+               return (errno == ENOENT) ? 0 : -1;
 
        while ((file = readdir(chkdir)) != NULL)
        {
@@ -697,25 +902,26 @@ check_data_dir(void)
                }
                else
                {
-                       empty = false;
+                       result = 2;                     /* not empty */
                        break;
                }
        }
 
        closedir(chkdir);
 
-       return empty;
+       if (errno != 0)
+               result = -1;                    /* some kind of I/O error? */
+
+       return result;
 }
 
 /*
  * make the data directory (or one of its subdirectories if subdir is not NULL)
- *
  */
 static bool
-mkdatadir(char *subdir)
+mkdatadir(const char *subdir)
 {
        char       *path;
-       int                     res;
 
        path = xmalloc(strlen(pg_data) + 2 +
                                   (subdir == NULL ? 0 : strlen(subdir)));
@@ -725,30 +931,22 @@ mkdatadir(char *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 !mkdir_p(path, 0700);
+       return (mkdir_p(path, 0700) == 0);
 }
 
 
 /*
  * 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);
+       *dest = xmalloc(strlen(share_path) + strlen(filename) + 2);
+       sprintf(*dest, "%s/%s", share_path, filename);
 }
 
 /*
  * check that given input file exists
- *
  */
 static void
 check_input(char *path)
@@ -758,199 +956,18 @@ check_input(char *path)
        if (stat(path, &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
        {
                fprintf(stderr,
-                               "%s: file \"%s\" not found\n"
+                               _("%s: file \"%s\" does not exist\n"
                   "This means you have a corrupted installation or identified\n"
-                               "the wrong directory with the invocation option -L.\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
-       /*
-        * Only unix requires this test, on WIN32 an .exe file should be
-        * executable
-        */
-       if ((statbuf.st_mode & permmask) != permmask)
-               return FIND_BAD_PERM;
-#endif
-
-       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;
-}
-
-/*
- * Windows doesn't like relative paths to executables (other things work fine)
- * so we call its builtin function to expand them. Elsewhere this is a NOOP
- *
- */
-#ifdef WIN32
-static char *
-expanded_path(char *path)
-{
-       char            abspath[MAXPGPATH];
-
-       if (_fullpath(abspath, path, MAXPGPATH) == NULL)
-       {
-               perror("expanded path");
-               return path;
-       }
-       canonicalize_path(abspath);
-       return xstrdup(abspath);
-}
-#endif 
-
-/*
- * 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
-                               {
-                                       canonicalize_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);
-               canonicalize_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)
@@ -969,13 +986,15 @@ set_short_version(char *short_version, char *extrapath)
                sprintf(path, "%s/%s/PG_VERSION", pg_data, extrapath);
        }
        version_file = fopen(path, PG_BINARY_W);
+       if (version_file == NULL)
+               exit_nicely();
        fprintf(version_file, "%s\n", short_version);
-       fclose(version_file);
+       if (fclose(version_file))
+               exit_nicely();
 }
 
 /*
  * set up an empty config file so we can check buffers and connections
- *
  */
 static void
 set_null_conf(void)
@@ -986,29 +1005,34 @@ set_null_conf(void)
        path = xmalloc(strlen(pg_data) + 17);
        sprintf(path, "%s/postgresql.conf", pg_data);
        conf_file = fopen(path, PG_BINARY_W);
-       fclose(conf_file);
+       if (conf_file == NULL || fclose(conf_file))
+               exit_nicely();
 }
 
 /*
  * 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);
+       static const int conns[] = {100, 50, 40, 30, 20, 10};
+       static const int len = sizeof(conns) / sizeof(int);
        int                     i,
                                status;
 
+       printf(_("selecting default max_connections ... "));
+       fflush(stdout);
+
        for (i = 0; i < len; i++)
        {
-               snprintf(cmd, sizeof(cmd), format,
-                                pgpath, conns[i] * 5, conns[i], DEVNULL, DEVNULL);
+               snprintf(cmd, sizeof(cmd),
+                                "%s\"%s\" -boot -x0 %s "
+                                "-c shared_buffers=%d -c max_connections=%d template1 "
+                                "< \"%s\" > \"%s\" 2>&1%s",
+                                SYSTEMQUOTE, backend_exec, boot_options,
+                                conns[i] * 5, conns[i],
+                                DEVNULL, DEVNULL, SYSTEMQUOTE);
                status = system(cmd);
                if (status == 0)
                        break;
@@ -1016,29 +1040,35 @@ test_connections(void)
        if (i >= len)
                i = len - 1;
        n_connections = conns[i];
-       printf("connections set to %d\n", n_connections);
+
+       printf("%d\n", n_connections);
 }
 
 /*
  * 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=%d template1 <%s >%s 2>&1";
        char            cmd[MAXPGPATH];
-       int                     bufs[] = {1000, 900, 800, 700, 600, 500, 400, 300, 200, 100, 50};
-       int                     len = sizeof(bufs) / sizeof(int);
+       static const int bufs[] = {1000, 900, 800, 700, 600, 500,
+       400, 300, 200, 100, 50};
+       static const int len = sizeof(bufs) / sizeof(int);
        int                     i,
                                status;
 
+       printf(_("selecting default shared_buffers ... "));
+       fflush(stdout);
+
        for (i = 0; i < len; i++)
        {
-               snprintf(cmd, sizeof(cmd), format, pgpath, bufs[i], n_connections,
-                       DEVNULL, DEVNULL);
+               snprintf(cmd, sizeof(cmd),
+                                "%s\"%s\" -boot -x0 %s "
+                                "-c shared_buffers=%d -c max_connections=%d template1 "
+                                "< \"%s\" > \"%s\" 2>&1%s",
+                                SYSTEMQUOTE, backend_exec, boot_options,
+                                bufs[i], n_connections,
+                                DEVNULL, DEVNULL, SYSTEMQUOTE);
                status = system(cmd);
                if (status == 0)
                        break;
@@ -1046,22 +1076,22 @@ test_buffers(void)
        if (i >= len)
                i = len - 1;
        n_buffers = bufs[i];
-       printf("buffers set to %d\n", n_buffers);
+
+       printf("%d\n", n_buffers);
 }
 
 /*
  * set up all the config files
- *
  */
 static void
 setup_config(void)
 {
-
        char      **conflines;
        char            repltok[100];
        char            path[MAXPGPATH];
 
-       fputs("creating configuration files ... ", stdout);
+       fputs(_("creating configuration files ... "), stdout);
+       fflush(stdout);
 
        /* postgresql.conf */
 
@@ -1073,20 +1103,23 @@ setup_config(void)
        snprintf(repltok, sizeof(repltok), "shared_buffers = %d", n_buffers);
        conflines = replace_token(conflines, "#shared_buffers = 1000", repltok);
 
+       lc_messages = escape_quotes(lc_messages);
        snprintf(repltok, sizeof(repltok), "lc_messages = '%s'", lc_messages);
        conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
 
+       lc_monetary = escape_quotes(lc_monetary);
        snprintf(repltok, sizeof(repltok), "lc_monetary = '%s'", lc_monetary);
        conflines = replace_token(conflines, "#lc_monetary = 'C'", repltok);
 
+       lc_numeric = escape_quotes(lc_numeric);
        snprintf(repltok, sizeof(repltok), "lc_numeric = '%s'", lc_numeric);
-
        conflines = replace_token(conflines, "#lc_numeric = 'C'", repltok);
 
+       lc_time = escape_quotes(lc_time);
        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);
+       snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
 
        writefile(path, conflines);
        chmod(path, 0600);
@@ -1098,13 +1131,28 @@ setup_config(void)
 
        conflines = readfile(hba_file);
 
+#ifndef HAVE_UNIX_SOCKETS
+       conflines = filter_lines_with_token(conflines,"@remove-line-for-nolocal@");
+#else
+       conflines = replace_token(conflines,"@remove-line-for-nolocal@","");
+#endif
+
 #ifndef HAVE_IPV6
        conflines = replace_token(conflines,
                                                          "host    all         all         ::1",
                                                          "#host    all         all         ::1");
 #endif
 
-       snprintf(path, MAXPGPATH, "%s/pg_hba.conf", pg_data);
+       /* Replace default authentication methods */
+       conflines = replace_token(conflines,
+                                                         "@authmethod@",
+                                                         authmethod);
+
+       conflines = replace_token(conflines,
+                                                         "@authcomment@",
+                                  strcmp(authmethod, "trust") ? "" : authtrust_warning);
+
+       snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data);
 
        writefile(path, conflines);
        chmod(path, 0600);
@@ -1115,7 +1163,7 @@ setup_config(void)
 
        conflines = readfile(ident_file);
 
-       snprintf(path, MAXPGPATH, "%s/pg_ident.conf", pg_data);
+       snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data);
 
        writefile(path, conflines);
        chmod(path, 0600);
@@ -1127,8 +1175,7 @@ setup_config(void)
 
 
 /*
- * run the bootstrap code
- *
+ * run the BKI script in bootstrap mode to create template1
  */
 static void
 bootstrap_template1(char *short_version)
@@ -1139,21 +1186,25 @@ bootstrap_template1(char *short_version)
 
        PG_CMD_DECL;
 
-       printf("creating template1 database in %s/base/1 ... ", pg_data);
+       printf(_("creating template1 database in %s/base/1 ... "), pg_data);
+       fflush(stdout);
 
        if (debug)
                talkargs = "-d 5";
 
        bki_lines = readfile(bki_file);
 
-       snprintf(headerline, MAXPGPATH, "# PostgreSQL %s\n", short_version);
+       /* Check that bki file appears to be of the right version */
+
+       snprintf(headerline, sizeof(headerline), "# 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",
+                        _("%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();
 
@@ -1164,21 +1215,25 @@ bootstrap_template1(char *short_version)
        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().
+        * Pass correct LC_xxx environment to bootstrap.
         *
+        * The shell script arranged to restore the LC settings afterwards, but
+        * there doesn't seem to be any compelling reason to do that.
         */
-       snprintf(cmd, MAXPGPATH, "LC_COLLATE=%s", lc_collate);
+       snprintf(cmd, sizeof(cmd), "LC_COLLATE=%s", lc_collate);
        putenv(xstrdup(cmd));
 
-       snprintf(cmd, MAXPGPATH, "LC_CTYPE=%s", lc_ctype);
+       snprintf(cmd, sizeof(cmd), "LC_CTYPE=%s", lc_ctype);
        putenv(xstrdup(cmd));
 
-       putenv("LC_ALL");
+       unsetenv("LC_ALL");
 
-       snprintf(cmd, MAXPGPATH,
-               " \"%s/postgres\"  -boot -x1 -F %s template1", pgpath, talkargs);
+       /* Also ensure backend isn't confused by this environment var: */
+       unsetenv("PGCLIENTENCODING");
+
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" -boot -x1 %s %s template1",
+                        backend_exec, boot_options, talkargs);
 
        PG_CMD_OPEN;
 
@@ -1197,12 +1252,10 @@ bootstrap_template1(char *short_version)
 
 /*
  * 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
@@ -1225,12 +1278,13 @@ setup_shadow(void)
 
        PG_CMD_DECL;
 
-       fputs("initializing pg_shadow ... ", stdout);
+       fputs(_("initializing pg_shadow ... "), stdout);
+       fflush(stdout);
 
-       snprintf(cmd, MAXPGPATH,
-                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
-                        "-c exit_on_error=true template1 >%s",
-                        pgpath, DEVNULL);
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
@@ -1244,7 +1298,6 @@ setup_shadow(void)
 
 /*
  * get the superuser password if required, and call postgres to set it
- *
  */
 static void
 get_set_pwd(void)
@@ -1256,26 +1309,67 @@ get_set_pwd(void)
        char            pwdpath[MAXPGPATH];
        struct stat statbuf;
 
-       pwd1 = simple_prompt("Enter new superuser password: ", 100, false);
-       pwd2 = simple_prompt("Enter it again: ", 100, false);
-       if (strcmp(pwd1, pwd2) != 0)
+       if (pwprompt)
        {
-               fprintf(stderr, "Passwords didn't match.\n");
-               exit_nicely();
+               /*
+                * Read password from terminal
+                */
+               pwd1 = simple_prompt("Enter new superuser password: ", 100, false);
+               pwd2 = simple_prompt("Enter it again: ", 100, false);
+               if (strcmp(pwd1, pwd2) != 0)
+               {
+                       fprintf(stderr, _("Passwords didn't match.\n"));
+                       exit_nicely();
+               }
+               free(pwd2);
        }
-       free(pwd2);
+       else
+       {
+               /*
+                * Read password from file
+                *
+                * Ideally this should insist that the file not be world-readable.
+                * However, this option is mainly intended for use on Windows
+                * where file permissions may not exist at all, so we'll skip the
+                * paranoia for now.
+                */
+               FILE       *pwf = fopen(pwfilename, "r");
+               char            pwdbuf[MAXPGPATH];
+               int                     i;
+
+               if (!pwf)
+               {
+                       fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
+                                       progname, pwfilename, strerror(errno));
+                       exit_nicely();
+               }
+               if (!fgets(pwdbuf, sizeof(pwdbuf), pwf))
+               {
+                       fprintf(stderr, _("%s: could not read password from file \"%s\": %s\n"),
+                                       progname, pwfilename, strerror(errno));
+                       exit_nicely();
+               }
+               fclose(pwf);
+
+               i = strlen(pwdbuf);
+               while (i > 0 && (pwdbuf[i - 1] == '\r' || pwdbuf[i - 1] == '\n'))
+                       pwdbuf[--i] = '\0';
 
-       printf("storing the password ... ");
+               pwd1 = xstrdup(pwdbuf);
 
-       snprintf(cmd, MAXPGPATH,
-                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
-                        "-c exit_on_error=true template1 >%s", pgpath, DEVNULL);
+       }
+       printf(_("setting password ... "));
+       fflush(stdout);
 
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
-       if (fprintf(
-          pg, "ALTER USER \"%s\" WITH PASSWORD '%s';\n", username, pwd1) < 0)
+       if (fprintf(pg,
+       "ALTER USER \"%s\" WITH PASSWORD '%s';\n", effective_user, pwd1) < 0)
        {
                /* write failure */
                exit_nicely();
@@ -1284,12 +1378,12 @@ get_set_pwd(void)
 
        PG_CMD_CLOSE;
 
-       snprintf(pwdpath, MAXPGPATH, "%s/global/pg_pwd", pg_data);
+       snprintf(pwdpath, sizeof(pwdpath), "%s/global/pg_pwd", pg_data);
        if (stat(pwdpath, &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
        {
                fprintf(stderr,
-                               "%s: The password file was not generated - "
-                               "please report this problem\n",
+                               _("%s: The password file was not generated. "
+                                 "Please report this problem.\n"),
                                progname);
                exit_nicely();
        }
@@ -1299,7 +1393,6 @@ get_set_pwd(void)
 
 /*
  * toast sys tables
- *
  */
 static void
 unlimit_systables(void)
@@ -1319,11 +1412,13 @@ unlimit_systables(void)
 
        PG_CMD_DECL;
 
-       fputs("enabling unlimited row size for system tables ... ", stdout);
+       fputs(_("enabling unlimited row size for system tables ... "), stdout);
+       fflush(stdout);
 
-       snprintf(cmd, MAXPGPATH,
-                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
-                        "-c exit_on_error=true template1 >%s", pgpath, DEVNULL);
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
@@ -1337,7 +1432,6 @@ unlimit_systables(void)
 
 /*
  * set up pg_depend
- *
  */
 static void
 setup_depend(void)
@@ -1348,10 +1442,13 @@ setup_depend(void)
                 * 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.
+                * required set of dependencies seems hard.
+                *
+                * Note that we deliberately do not pin the system views, which
+                * haven't been created yet.
+                *
+                * 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' "
@@ -1388,12 +1485,13 @@ setup_depend(void)
 
        PG_CMD_DECL;
 
-       fputs("initializing pg_depend ... ", stdout);
+       fputs(_("initializing pg_depend ... "), stdout);
+       fflush(stdout);
 
-       snprintf(cmd, MAXPGPATH,
-                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
-                        "-c exit_on_error=true template1 >%s",
-                        pgpath, DEVNULL);
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
@@ -1407,7 +1505,6 @@ setup_depend(void)
 
 /*
  * set up system views
- *
  */
 static void
 setup_sysviews(void)
@@ -1416,14 +1513,18 @@ setup_sysviews(void)
 
        char      **sysviews_setup;
 
-       fputs("creating system views ... ", stdout);
+       fputs(_("creating system views ... "), stdout);
+       fflush(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);
+       /*
+        * We use -N here to avoid backslashing stuff in system_views.sql
+        */
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s -N template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
@@ -1442,59 +1543,45 @@ setup_sysviews(void)
 
 /*
  * 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;
+       PG_CMD_DECL_NOLINE;
+       int                     fres;
 
-       fputs("loading pg_description ... ", stdout);
+       fputs(_("loading pg_description ... "), stdout);
+       fflush(stdout);
 
-       snprintf(cmd, MAXPGPATH,
-                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
-                        "-c exit_on_error=true template1 >%s",
-                        pgpath, DEVNULL);
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
+                        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);
+       fres = fprintf(pg,
+                                  "CREATE TEMP TABLE tmp_pg_description ( "
+                                  "    objoid oid, "
+                                  "    classname name, "
+                                  "    objsubid int4, "
+                                  "    description text) WITHOUT OIDS;\n");
+       if (fres < 0)
+               exit_nicely();
 
+       fres = fprintf(pg,
+                                  "COPY tmp_pg_description FROM '%s';\n",
+                                  desc_file);
+       if (fres < 0)
+               exit_nicely();
 
-       for (line = pg_description_setup2; *line != NULL; line++)
-               PG_CMD_PUTLINE;
+       fres = fprintf(pg,
+                                  "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");
+       if (fres < 0)
+               exit_nicely();
 
        PG_CMD_CLOSE;
 
@@ -1503,7 +1590,6 @@ setup_description(void)
 
 /*
  * load conversion functions
- *
  */
 static void
 setup_conversion(void)
@@ -1512,12 +1598,13 @@ setup_conversion(void)
 
        char      **conv_lines;
 
-       fputs("creating conversions ... ", stdout);
+       fputs(_("creating conversions ... "), stdout);
+       fflush(stdout);
 
-       snprintf(cmd, MAXPGPATH,
-                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
-                        "-c exit_on_error=true template1 >%s",
-                        pgpath, DEVNULL);
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
@@ -1538,8 +1625,12 @@ setup_conversion(void)
 }
 
 /*
- * run privileges script
+ * Set up privileges
  *
+ * We 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).
  */
 static void
 setup_privileges(void)
@@ -1563,17 +1654,18 @@ setup_privileges(void)
 
        char      **priv_lines;
 
-       fputs("setting privileges on builtin objects ... ", stdout);
+       fputs(_("setting privileges on built-in objects ... "), stdout);
+       fflush(stdout);
 
-       snprintf(cmd, MAXPGPATH,
-                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
-                        "-c exit_on_error=true template1 >%s",
-                        pgpath, DEVNULL);
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
        priv_lines = replace_token(privileges_setup,
-                                                          "$POSTGRES_SUPERUSERNAME", username);
+                                                          "$POSTGRES_SUPERUSERNAME", effective_user);
        for (line = priv_lines; *line != NULL; line++)
                PG_CMD_PUTLINE;
 
@@ -1583,8 +1675,8 @@ setup_privileges(void)
 }
 
 /*
- * extract the strange version of version required for info schema
- *
+ * extract the strange version of version required for information schema
+ * (09.08.0007abc)
  */
 static void
 set_info_version(void)
@@ -1612,29 +1704,27 @@ set_info_version(void)
 
 /*
  * 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);
+       fputs(_("creating information schema ... "), stdout);
+       fflush(stdout);
 
        lines = readfile(info_schema_file);
 
        /*
-        * note that here we don't run in single line mode, unlike other
-        * places
+        * We use -N here to avoid backslashing stuff in
+        * information_schema.sql
         */
-       snprintf(cmd, MAXPGPATH,
-                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
-                        "-c exit_on_error=true -N template1 >%s",
-                        pgpath, DEVNULL);
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s -N template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
@@ -1648,20 +1738,10 @@ setup_schema(void)
 
        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);
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
@@ -1670,31 +1750,18 @@ setup_schema(void)
                                   "  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);
-
+       fres = fprintf(pg,
+                                  "COPY information_schema.sql_features "
+                                  "  (feature_id, feature_name, sub_feature_id, "
+                                  "  sub_feature_name, is_supported, comments) "
+                                  " FROM '%s';\n",
+                                  features_file);
        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();
@@ -1702,35 +1769,33 @@ setup_schema(void)
 
 /*
  * clean everything up in template1
- *
  */
 static void
 vacuum_db(void)
 {
        PG_CMD_DECL_NOLINE;
 
-       fputs("vacuuming database template1 ... ", stdout);
+       fputs(_("vacuuming database template1 ... "), stdout);
+       fflush(stdout);
 
-       snprintf(cmd, MAXPGPATH,
-                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
-                        "-c exit_on_error=true template1 >%s",
-                        pgpath, DEVNULL);
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
-       if (fputs("ANALYSE;\nVACUUM FULL FREEZE;\n", pg) < 0)
+       if (fputs("ANALYZE;\nVACUUM FULL FREEZE;\n", pg) < 0)
                exit_nicely();
        fflush(pg);
 
        PG_CMD_CLOSE;
 
        check_ok();
-
 }
 
 /*
  * copy template1 to template0
- *
  */
 static void
 make_template0(void)
@@ -1744,7 +1809,6 @@ make_template0(void)
 
                /*
                 * We use the OID of template0 to determine lastsysoid
-                *
                 */
                "UPDATE pg_database SET datlastsysoid = "
                "    (SELECT oid::int4 - 1 FROM pg_database "
@@ -1767,12 +1831,13 @@ make_template0(void)
 
        PG_CMD_DECL;
 
-       fputs("copying template1 to template0 ... ", stdout);
+       fputs(_("copying template1 to template0 ... "), stdout);
+       fflush(stdout);
 
-       snprintf(cmd, MAXPGPATH,
-                        "\"%s/postgres\" -F -O -c search_path=pg_catalog "
-                        "-c exit_on_error=true template1 >%s",
-                        pgpath, DEVNULL);
+       snprintf(cmd, sizeof(cmd),
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
+                        DEVNULL);
 
        PG_CMD_OPEN;
 
@@ -1806,40 +1871,60 @@ make_template0(void)
  *
  * 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;
+       caught_signal = true;
 }
 
 /*
  * call exit_nicely() if we got a signal, or else output "ok".
- *
  */
 static void
-check_ok()
+check_ok(void)
 {
-       if (not_ok)
+       if (caught_signal)
+       {
+               printf(_("caught signal\n"));
+               exit_nicely();
+       }
+       else if (output_failed)
        {
-               puts("Caught Signal.");
+               printf(_("could not write to child process\n"));
                exit_nicely();
        }
        else
        {
-               /* no signal caught */
-               puts("ok");
+               /* all seems well */
+               printf(_("ok\n"));
        }
 }
 
+/*
+ * Escape any single quotes or backslashes in given string
+ */
+static char *
+escape_quotes(const char *src)
+{
+       int                     len = strlen(src),
+                               i, j;
+       char            *result = xmalloc(len * 2 + 1);
+       
+       for (i = 0, j = 0; i < len; i++)
+       {
+               if (src[i] == '\'' || src[i] == '\\')
+                       result[j++] = '\\';
+               result[j++] = src[i];
+       }
+       result[j] = '\0';
+       return result;
+}
 
 /*
- * 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 :-)
+ * check if given string is a valid locale specifier
  */
 static bool
 chklocale(const char *locale)
@@ -1861,15 +1946,15 @@ chklocale(const char *locale)
 
        /* should we exit here? */
        if (!ret)
-               fprintf(stderr, "%s: invalid locale name \"%s\"\n", progname, locale);
+               fprintf(stderr, _("%s: invalid locale name \"%s\"\n"), progname, locale);
 
        return ret;
 }
 
 /*
  * set up the locale variables
- * assumes we have called setlocale(LC_ALL,"")
  *
+ * assumes we have called setlocale(LC_ALL,"")
  */
 static void
 setlocales(void)
@@ -1908,7 +1993,7 @@ setlocales(void)
        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
+#if defined(LC_MESSAGES) && !defined(WIN32)
        {
                /* when available get the current locale setting */
                lc_messages = xstrdup(setlocale(LC_MESSAGES, NULL));
@@ -1922,61 +2007,39 @@ setlocales(void)
 
 }
 
-/*
- * 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)
+usage(const char *progname)
 {
-
-       int                     i;
-       char      **newtext;
-
-       newtext = replace_token(usage_text, "$CMDNAME", progname);
-
-       for (i = 0; newtext[i]; i++)
-               fputs(newtext[i], stdout);              /* faster than printf */
+       printf(_("%s initializes a PostgreSQL database cluster.\n\n"), progname);
+       printf(_("Usage:\n"));
+       printf(_("  %s [OPTION]... [DATADIR]\n"), progname);
+       printf(_("\nOptions:\n"));
+       printf(_(" [-D, --pgdata=]DATADIR     location for this database cluster\n"));
+       printf(_("  -E, --encoding=ENCODING   set default encoding for new databases\n"));
+       printf(_("  --locale=LOCALE           initialize database cluster with given locale\n"));
+       printf(_("  --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"));
+       printf(_("  --no-locale               equivalent to --locale=C\n"));
+       printf(_("  -A, --auth=METHOD         default authentication method for local connections\n"));
+       printf(_("  -U, --username=NAME       database superuser name\n"));
+       printf(_("  -W, --pwprompt            prompt for a password for the new superuser\n"));
+       printf(_("  --pwfile=FILE             read password for the new superuser from file\n"));
+       printf(_("  -?, --help                show this help, then exit\n"));
+       printf(_("  -V, --version             output version information, then exit\n"));
+       printf(_("\nLess commonly used options:\n"));
+       printf(_("  -d, --debug               generate lots of debugging output\n"));
+       printf(_("  -s, --show                show internal settings\n"));
+       printf(_("  -L DIRECTORY              where to find the input files\n"));
+       printf(_("  -n, --noclean             do not clean up after errors\n"));
+       printf(_("\nIf the data directory is not specified, the environment variable PGDATA\n"
+                        "is used.\n"));
+       printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
 }
 
 int
@@ -1985,7 +2048,6 @@ 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'},
@@ -1998,80 +2060,62 @@ main(int argc, char *argv[])
                {"lc-time", required_argument, NULL, 6},
                {"lc-messages", required_argument, NULL, 7},
                {"no-locale", no_argument, NULL, 8},
+               {"auth", required_argument, NULL, 'A'},
                {"pwprompt", no_argument, NULL, 'W'},
+               {"pwfile", required_argument, NULL, 9},
                {"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}
+               {NULL, 0, NULL, 0}
        };
 
        int                     c,
-                               i;
+                               i,
+                               ret;
        int                     option_index;
        char       *short_version;
-       char       *pgdenv;                     /* PGDATA value got from sent to
+       char       *pgdenv;                     /* PGDATA value gotten from and 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
-
-       setlocale(LC_ALL, "");
-
-       carg0 = xstrdup(argv[0]);
-       canonicalize_path(carg0);
-
-       lastsep = strrchr(carg0, '/');
-       progname = lastsep ? xstrdup(lastsep + 1) : carg0;
+       static const char *subdirs[] = {
+               "global",
+               "pg_xlog",
+               "pg_xlog/archive_status",
+               "pg_clog",
+               "pg_subtrans",
+               "base",
+               "base/1",
+               "pg_tblspc"
+       };
 
-#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
+       progname = get_progname(argv[0]);
+       set_pglocale_pgservice(argv[0], "initdb");
 
-       if (lastsep)
-       {
-               self_path = carg0;
-               *lastsep = '\0';
-       }
-       else
+       if (argc > 1)
        {
-               /* no path known to ourselves from argv[0] */
-               self_path = NULL;
+               if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
+               {
+                       usage(progname);
+                       exit(0);
+               }
+               if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
+               {
+                       puts("initdb (PostgreSQL) " PG_VERSION);
+                       exit(0);
+               }
        }
 
-       /* process options */
+       /* process command-line options */
 
-       while (1)
+       while ((c = getopt_long(argc, argv, "dD:E:L:nU:WA:s", long_options, &option_index)) != -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 'A':
+                               authmethod = xstrdup(optarg);
+                               break;
                        case 'D':
                                pg_data = xstrdup(optarg);
                                break;
@@ -2086,12 +2130,14 @@ main(int argc, char *argv[])
                                break;
                        case 'd':
                                debug = true;
+                               printf(_("Running in debug mode.\n"));
                                break;
                        case 'n':
                                noclean = true;
+                               printf(_("Running in noclean mode.  Mistakes will not be cleaned up.\n"));
                                break;
                        case 'L':
-                               datadir = xstrdup(optarg);
+                               share_path = xstrdup(optarg);
                                break;
                        case 1:
                                locale = xstrdup(optarg);
@@ -2117,31 +2163,80 @@ main(int argc, char *argv[])
                        case 8:
                                locale = "C";
                                break;
-                       case '?':
-                               show_help = true;
+                       case 9:
+                               pwfilename = xstrdup(optarg);
                                break;
                        case 's':
                                show_setting = true;
                                break;
-                       case 'V':
-                               show_version = true;
-                               break;
                        default:
-                               show_help = true;
-                               printf("Unrecognized option: %c\n", c);
+                               fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+                                               progname);
+                               exit(1);
                }
-
        }
 
+       /* Non-option argument specifies data directory */
        if (optind < argc)
        {
                pg_data = xstrdup(argv[optind]);
                optind++;
        }
 
-       set_info_version();
+       if (optind < argc)
+       {
+               fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
+                               progname, argv[optind + 1]);
+               fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+                               progname);
+       }
+
+       if (pwprompt && pwfilename)
+       {
+               fprintf(stderr, _("%s: password prompt and password file may not be specified together\n"), progname);
+               exit(1);
+       }
+
+       if (authmethod == NULL || !strlen(authmethod))
+       {
+               authwarning = _("\nWARNING: enabling \"trust\" authentication for local connections\n"
+                                               "You can change this by editing pg_hba.conf or using the -A option the\n"
+                                               "next time you run initdb.\n");
+               authmethod = "trust";
+       }
+
+       if (strcmp(authmethod, "md5") &&
+               strcmp(authmethod, "ident") &&
+               strncmp(authmethod, "ident ", 6) &&             /* ident with space =
+                                                                                                * param */
+               strcmp(authmethod, "trust") &&
+#ifdef USE_PAM
+               strcmp(authmethod, "pam") &&
+               strncmp(authmethod, "pam ", 4) &&               /* pam with space = param */
+#endif
+               strcmp(authmethod, "crypt") &&
+               strcmp(authmethod, "password")
+               )
+
+               /*
+                * Kerberos methods not listed because they are not supported over
+                * local connections and are rejected in hba.c
+                */
+       {
+               fprintf(stderr, _("%s: unrecognized authentication method \"%s\"\n"), progname, authmethod);
+               exit(1);
+       }
+
+       if ((!strcmp(authmethod, "md5") ||
+                !strcmp(authmethod, "crypt") ||
+                !strcmp(authmethod, "password")) &&
+               !(pwprompt || pwfilename))
+       {
+               fprintf(stderr, _("%s: must specify a password for the superuser to enable %s authentication\n"), progname, authmethod);
+               exit(1);
+       }
 
-       if (strlen(pg_data) == 0 && !(show_help || show_setting))
+       if (strlen(pg_data) == 0)
        {
                pgdenv = getenv("PGDATA");
                if (pgdenv && strlen(pgdenv))
@@ -2152,12 +2247,12 @@ main(int argc, char *argv[])
                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",
+                                       _("%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);
+                       exit(1);
                }
        }
 
@@ -2165,52 +2260,66 @@ main(int argc, char *argv[])
 
        /*
         * 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.
-        *
+        * command line to avoid dumb quoting problems on Windows, and we
+        * would especially 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)
+       if ((ret = find_other_exec(argv[0], "postgres", PG_VERSIONSTR,
+                                                          backend_exec)) < 0)
        {
-               /* hard coded name here, in case they rename executable */
-               printf("initdb (PostgreSQL) %s\n", PG_VERSION);
-               exit(0);
+               char full_path[MAXPGPATH];
+
+               if (find_my_exec(argv[0], full_path) < 0)
+                       StrNCpy(full_path, progname, MAXPGPATH);
+
+               if (ret == -1)
+                       fprintf(stderr,
+                                       _("The program \"postgres\" is needed by %s "
+                                         "but was not found in the\n"
+                                         "same directory as \"%s\".\n"
+                                         "Check your installation.\n"),
+                                       progname, full_path);
+               else
+                       fprintf(stderr,
+                                       _("The program \"postgres\" was found by \"%s\"\n"
+                                         "but was not the same version as %s.\n"
+                                         "Check your installation.\n"),
+                                       full_path, progname);
+               exit(1);
        }
 
-       if (show_help)
+       /* store binary directory */
+       strcpy(bin_path, backend_exec);
+       *last_dir_separator(bin_path) = '\0';
+       canonicalize_path(bin_path);
+
+       if (!share_path)
        {
-               usage();
-               exit(0);
+               share_path = xmalloc(MAXPGPATH);
+               get_share_path(backend_exec, share_path);
        }
-
-       if (set_paths() != 0)
+       else if (!is_absolute_path(share_path))
        {
-               fprintf(stderr,
-                               "The program \"postgres\" is needed by %s "
-                               "but was not found in \n"
-                               "the directory \"%s\". Check your installation.\n",
-                               progname, bindir);
+               fprintf(stderr, _("%s: input file location must be an absolute path\n"), progname);
                exit(1);
-
        }
 
+       canonicalize_path(share_path);
 
        if ((short_version = get_short_version()) == NULL)
        {
-               fprintf(stderr, "%s: could not get valid short version\n", progname);
+               fprintf(stderr, _("%s: could not determine valid short version string\n"), progname);
                exit(1);
        }
 
-       effective_user = get_id();
-       if (!strlen(username))
-               username = effective_user;
+       if (strlen(username))
+               effective_user = username;
+       else
+               effective_user = get_id();
 
        if (strlen(encoding))
                encodingid = get_encoding_id(encoding);
@@ -2225,26 +2334,25 @@ main(int argc, char *argv[])
        set_input(&features_file, "sql_features.txt");
        set_input(&system_views_file, "system_views.sql");
 
+       set_info_version();
+
        if (show_setting || debug)
        {
                fprintf(stderr,
                                "VERSION=%s\n"
-                               "PGDATA=%s\ndatadir=%s\nPGPATH=%s\n"
-                               "ENCODING=%s\nENCODINGID=%s\n"
+                               "PGDATA=%s\nshare_path=%s\nPGPATH=%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,
+                               pg_data, share_path, bin_path,
+                               effective_user, bki_file,
                                desc_file, conf_file,
                                hba_file, ident_file);
+               if (show_setting)
+                       exit(0);
        }
 
-       if (show_setting)
-               exit(0);
-
        check_input(bki_file);
        check_input(desc_file);
        check_input(hba_file);
@@ -2257,24 +2365,26 @@ main(int argc, char *argv[])
 
        setlocales();
 
+       printf(_("The files belonging to this database system will be owned "
+                        "by user \"%s\".\n"
+                        "This user must also own the server process.\n\n"),
+                  effective_user);
+
        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);
-       }
+               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",
+               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,
@@ -2283,6 +2393,35 @@ main(int argc, char *argv[])
                           lc_time);
        }
 
+#if defined(HAVE_LANGINFO_H) && defined(CODESET)
+       if (strcmp(lc_ctype, "C") != 0 && strcmp(lc_ctype, "POSIX") != 0)
+       {
+               if (strlen(encoding) == 0)
+               {
+                       int                     tmp;
+
+                       tmp = find_matching_encoding(lc_ctype);
+                       if (tmp == -1)
+                       {
+                               fprintf(stderr, _("%s: could not find suitable encoding for locale \"%s\"\n"), progname, lc_ctype);
+                               fprintf(stderr, _("Rerun %s with the -E option.\n"), progname);
+                               fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
+                               exit(1);
+                       }
+                       else
+                       {
+                               encodingid = encodingid_to_string(tmp);
+                               printf(_("The default database encoding has accordingly been set to %s.\n"),
+                                          pg_encoding_to_char(tmp));
+                       }
+               }
+               else
+                       check_encodings_match(atoi(encodingid), lc_ctype);
+       }
+#endif   /* HAVE_LANGINFO_H && CODESET */
+
+       printf("\n");
+
        umask(077);
 
        /*
@@ -2304,41 +2443,68 @@ main(int argc, char *argv[])
        pqsignal(SIGTERM, trapsig);
 #endif
 
-       /* clear this we'll use it in a few lines */
-       errno = 0;
+       /* Ignore SIGPIPE when writing to backend, so we can clean up */
+#ifdef SIGPIPE
+       pqsignal(SIGPIPE, SIG_IGN);
+#endif
 
-       if (!check_data_dir())
+       switch (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);
-       }
+               case 0:
+                       /* PGDATA not there, must create it */
+                       printf(_("creating directory %s ... "),
+                                  pg_data);
+                       fflush(stdout);
+
+                       if (!mkdatadir(NULL))
+                               exit_nicely();
+                       else
+                               check_ok();
 
-       /*
-        * check_data_dir() called opendir - the errno should still be hanging
-        * around
-        */
-       if (errno == ENOENT)
-       {
-               printf("creating directory \"%s\" ... ", pg_data);
+                       made_new_pgdata = true;
+                       break;
 
-               if (!mkdatadir(NULL))
-                       exit_nicely();
-               else
-                       check_ok();
+               case 1:
+                       /* Present but empty, fix permissions and use it */
+                       printf(_("fixing permissions on existing directory %s ... "),
+                                  pg_data);
+                       fflush(stdout);
+
+                       if (chmod(pg_data, 0700) != 0)
+                       {
+                               fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
+                                               progname, pg_data, strerror(errno));
+                               exit_nicely();
+                       }
+                       else
+                               check_ok();
+
+                       found_existing_pgdata = true;
+                       break;
 
-               made_new_pgdata = true;
+               case 2:
+                       /* Present and not empty */
+                       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 \"%s\" or run %s\n"
+                                         "with an argument other than \"%s\".\n"),
+                                       progname, pg_data, pg_data, progname, pg_data);
+                       exit(1);                        /* no further message needed */
+
+               default:
+                       /* Trouble accessing directory */
+                       fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
+                                       progname, pg_data, strerror(errno));
+                       exit_nicely();
        }
 
+       /* Create required subdirectories */
+
        for (i = 0; i < (sizeof(subdirs) / sizeof(char *)); i++)
        {
-               printf("creating directory %s/%s ... ", pg_data, subdirs[i]);
+               printf(_("creating directory %s/%s ... "), pg_data, subdirs[i]);
+               fflush(stdout);
 
                if (!mkdatadir(subdirs[i]))
                        exit_nicely();
@@ -2346,22 +2512,38 @@ main(int argc, char *argv[])
                        check_ok();
        }
 
+       /* Top level PG_VERSION is checked by bootstrapper, so make it first */
        set_short_version(short_version, NULL);
 
+       /*
+        * 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.
+        */
+
        set_null_conf();
 
-       /* test connections first because it has more constraints */
        test_connections();
        test_buffers();
 
+       /* Now create all the text config files */
        setup_config();
 
+       /* Bootstrap template1 */
        bootstrap_template1(short_version);
 
+       /*
+        * Make the per-database PG_VERSION for template1 only after init'ing
+        * it
+        */
        set_short_version(short_version, "base/1");
 
+       /* Create the stuff we don't need to use bootstrap mode for */
+
        setup_shadow();
-       if (pwprompt)
+       if (pwprompt || pwfilename)
                get_set_pwd();
 
        unlimit_systables();
@@ -2382,12 +2564,15 @@ main(int argc, char *argv[])
 
        make_template0();
 
-       printf("\nSuccess. You can now start the database server using:\n\n"
-                  "    %s%s%s/postmaster -D %s%s%s\n"
-                  "or\n"
-                  "    %s%s%s/pg_ctl -D %s%s%s -l logfile start\n\n",
-                       QUOTE_PATH, pgpath, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH,
-                       QUOTE_PATH, pgpath, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH);
+       if (authwarning != NULL)
+               fprintf(stderr, authwarning);
+
+       printf(_("\nSuccess. You can now start the database server using:\n\n"
+                        "    %s%s%s/postmaster -D %s%s%s\n"
+                        "or\n"
+                        "    %s%s%s/pg_ctl -D %s%s%s -l logfile start\n\n"),
+          QUOTE_PATH, bin_path, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH,
+         QUOTE_PATH, bin_path, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH);
 
        return 0;
 }