]> granicus.if.org Git - postgresql/blobdiff - src/bin/initdb/initdb.c
>I got a new idea on this. I think we should add an initdb option that
[postgresql] / src / bin / initdb / initdb.c
index cd2df3acb238b603420bb55d2a552c7a6909212b..cd830ecda7a6215baf255e72e363c63b77d54b2e 100644 (file)
  *
  * template0 is made just by copying the completed template1.
  *
- *
- * TODO:
- *      - clean up find_postgres code and return values
- *
  * Note:
  *      The program has some memory leakage - it isn't worth cleaning it up.
  *
@@ -43,7 +39,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  * Portions taken from FreeBSD.
  *
- * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.18 2003/12/23 21:50:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.45 2004/08/01 05:59:13 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include <dirent.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 #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"
@@ -74,12 +72,8 @@ int                  optreset;
 
 /*
  * these values are passed in by makefile defines
- *
- * Note that "datadir" is not the directory we're going to initialize,
- * it's merely how Autoconf names PREFIX/share.
  */
-char      *bindir = PGBINDIR;
-char      *datadir = PGDATADIR;
+char           *share_path = NULL;
 
 /* values to be obtained from arguments */
 char      *pg_data = "";
@@ -93,14 +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_setting = false;
 
 
 /* internal vars */
-char      *progname;
-char      *self_path;
+const char *progname;
 char      *postgres;
 char      *encodingid = "0";
 char      *bki_file;
@@ -124,6 +119,16 @@ bool               output_failed = false;
 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"
+       "# authenication method.\n";
+char *authwarning = NULL;
+
 /*
  * Centralized knowledge of switches to pass to backend
  *
@@ -135,55 +140,31 @@ static const char *boot_options = "-F";
 static const char *backend_options = "-F -O -c search_path=pg_catalog -c exit_on_error=true";
 
 
-/* platform specific path stuff */
-#if defined(__CYGWIN__) || defined(WIN32)
-#define EXE ".exe"
-#define DEVNULL "nul"
-#else
-#define EXE ""
-#define DEVNULL "/dev/null"
-#endif
+/* path to 'initdb' binary directory */
+char      bin_path[MAXPGPATH];
+char      backend_exec[MAXPGPATH];
 
-#ifdef WIN32
-#define PATHSEP ';'
-#else
-#define PATHSEP ':'
-#endif
-
-/* detected path to postgres and (we assume) friends */
-char      *pgpath;
-
-/* forward declare all our functions */
-static bool rmtree(char *, bool);
+static void *xmalloc(size_t size);
+static char *xstrdup(const char *s);
+static bool rmtree(char *path, bool rmtopdir);
+static char **replace_token(char **lines, char *token, char *replacement);
+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 void canonicalize_path(char *);
-#ifdef WIN32
-static char *expanded_path(char *);
-#else
-#define expanded_path(x) (x)
-#endif
-static char **readfile(char *);
-static void writefile(char *, char **);
-static void pclose_check(FILE *stream);
 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 int     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);
@@ -196,12 +177,12 @@ static void set_info_version(void);
 static void setup_schema(void);
 static void vacuum_db(void);
 static void make_template0(void);
-static void usage(const char *);
-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 void init_nls(void);
+static bool chklocale(const char *locale);
+static void setlocales(void);
+static void usage(const char *progname);
+
 
 /*
  * macros for running pipes to postgres
@@ -220,7 +201,8 @@ do { \
 
 #define PG_CMD_CLOSE \
 do { \
-       pclose_check(pg); \
+       if (pclose_check(pg)) \
+               exit_nicely(); \
 } while (0)
 
 #define PG_CMD_PUTLINE \
@@ -293,31 +275,6 @@ rmtree(char *path, bool rmtopdir)
 }
 
 
-/*
- * 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.  Don't remove a leading slash, though.
- */
-static void
-canonicalize_path(char *path)
-{
-       char       *p;
-
-       for (p = path; *p; p++)
-       {
-#ifdef WIN32
-               if (*p == '\\')
-                       *p = '/';
-#endif
-       }
-       if (p > path+1 && *--p == '/')
-               *p = '\0';
-}
-
 /*
  * make a copy of the array of lines, with token replaced by replacement
  * the first time it occurs on each line.
@@ -450,7 +407,6 @@ writefile(char *path, char **lines)
        FILE       *out_file;
        char      **line;
 
-       ;
        if ((out_file = fopen(path, PG_BINARY_W)) == NULL)
        {
                fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
@@ -467,41 +423,6 @@ writefile(char *path, char **lines)
                exit_nicely();
 }
 
-/* pclose() plus useful error reporting */
-static void
-pclose_check(FILE *stream)
-{
-       int             exitstatus;
-
-       exitstatus = pclose(stream);
-
-       if (exitstatus == 0)
-               return;                                 /* all is well */
-
-       if (exitstatus == -1)
-       {
-               /* pclose() itself failed, and hopefully set errno */
-               perror("pclose failed");
-       }
-       else if (WIFEXITED(exitstatus))
-       {
-               fprintf(stderr, _("%s: child process exited with exit code %d\n"),
-                               progname, WEXITSTATUS(exitstatus));
-       }
-       else if (WIFSIGNALED(exitstatus))
-       {
-               fprintf(stderr, _("%s: child process was terminated by signal %d\n"),
-                               progname, WTERMSIG(exitstatus));
-       }
-       else
-       {
-               fprintf(stderr, _("%s: child process exited with unrecognized status %d\n"),
-                               progname, exitstatus);
-       }
-
-       exit_nicely();
-}
-
 /* source stolen from FreeBSD /src/bin/mkdir/mkdir.c and adapted */
 
 /*
@@ -554,7 +475,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)
                {
@@ -693,6 +614,15 @@ 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
  */
@@ -700,15 +630,13 @@ 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"),
@@ -716,6 +644,191 @@ get_encoding_id(char *encoding_name)
        exit(1);
 }
 
+#ifdef HAVE_LANGINFO_H
+/*
+ * 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 */
+
 /*
  * get short version of VERSION
  */
@@ -798,7 +911,7 @@ check_data_dir(void)
  * 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;
 
@@ -820,8 +933,8 @@ mkdatadir(char *subdir)
 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);
 }
 
 /*
@@ -844,193 +957,6 @@ check_input(char *path)
 
 }
 
-/*
- * 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 (plen > 0 && path[plen - 1] != '/')
-               snprintf(fn, sizeof(fn), "%s/postgres%s", path, EXE);
-       else
-               snprintf(fn, sizeof(fn), "%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, sizeof(cmd), "\"%s/postgres\" -V 2>%s", path, DEVNULL);
-
-       /* flush output buffers in case popen does not... */
-       fflush(stdout);
-       fflush(stderr);
-
-       if ((pgver = popen(cmd, "r")) == NULL)
-               return FIND_EXEC_ERR;
-
-       if (fgets(line, sizeof(line), pgver) == NULL)
-               perror("fgets failure");
-
-       pclose_check(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, sizeof(abspath)) == 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.
- * We do it in this order because during upgrades users might move
- * their trees to backup places, so the hard-wired bindir might be inaccurate.
- *
- * XXX this needs work, as its error handling is vastly inferior to the
- * shell-script version, in particular the case where a postgres executable
- * is failing
- */
-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, sizeof(buf), "%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
@@ -1052,8 +978,11 @@ 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();
 }
 
 /*
@@ -1068,7 +997,8 @@ 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();
 }
 
 /*
@@ -1089,12 +1019,12 @@ test_connections(void)
        for (i = 0; i < len; i++)
        {
                snprintf(cmd, sizeof(cmd),
-                                "\"%s/postgres\" -boot -x0 %s "
+                                "%s\"%s\" -boot -x0 %s "
                                 "-c shared_buffers=%d -c max_connections=%d template1 "
-                                "<%s >%s 2>&1",
-                                pgpath, boot_options,
+                                "< \"%s\" > \"%s\" 2>&1%s",
+                                SYSTEMQUOTE, backend_exec, boot_options,
                                 conns[i] * 5, conns[i],
-                                DEVNULL, DEVNULL);
+                                DEVNULL, DEVNULL, SYSTEMQUOTE);
                status = system(cmd);
                if (status == 0)
                        break;
@@ -1125,12 +1055,12 @@ test_buffers(void)
        for (i = 0; i < len; i++)
        {
                snprintf(cmd, sizeof(cmd),
-                                "\"%s/postgres\" -boot -x0 %s "
+                                "%s\"%s\" -boot -x0 %s "
                                 "-c shared_buffers=%d -c max_connections=%d template1 "
-                                "<%s >%s 2>&1",
-                                pgpath, boot_options,
+                                "< \"%s\" > \"%s\" 2>&1%s",
+                                SYSTEMQUOTE, backend_exec, boot_options,
                                 bufs[i], n_connections,
-                                DEVNULL, DEVNULL);
+                                DEVNULL, DEVNULL, SYSTEMQUOTE);
                status = system(cmd);
                if (status == 0)
                        break;
@@ -1195,7 +1125,16 @@ setup_config(void)
                                                          "host    all         all         ::1",
                                                          "#host    all         all         ::1");
 #endif
-
+       
+       /* 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);
@@ -1270,11 +1209,14 @@ bootstrap_template1(char *short_version)
        snprintf(cmd, sizeof(cmd), "LC_CTYPE=%s", lc_ctype);
        putenv(xstrdup(cmd));
 
-       putenv("LC_ALL");
+       unsetenv("LC_ALL");
+
+       /* Also ensure backend isn't confused by this environment var: */
+       unsetenv("PGCLIENTENCODING");
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" -boot -x1 %s %s template1",
-                        pgpath, boot_options, talkargs);
+                        "\"%s\" -boot -x1 %s %s template1",
+                        backend_exec, boot_options, talkargs);
 
        PG_CMD_OPEN;
 
@@ -1323,8 +1265,8 @@ setup_shadow(void)
        fflush(stdout);
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s template1 >%s",
-                        pgpath, backend_options,
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
                         DEVNULL);
 
        PG_CMD_OPEN;
@@ -1350,27 +1292,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';
+               
+               pwd1 = xstrdup(pwdbuf);
+               
+       }
        printf(_("setting password ... "));
        fflush(stdout);
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s template1 >%s",
-                        pgpath, backend_options,
+                        "\"%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)
+                 "ALTER USER \"%s\" WITH PASSWORD '%s';\n", effective_user, pwd1) < 0)
        {
                /* write failure */
                exit_nicely();
@@ -1417,8 +1399,8 @@ unlimit_systables(void)
        fflush(stdout);
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s template1 >%s",
-                        pgpath, backend_options,
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
                         DEVNULL);
 
        PG_CMD_OPEN;
@@ -1490,8 +1472,8 @@ setup_depend(void)
        fflush(stdout);
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s template1 >%s",
-                        pgpath, backend_options,
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
                         DEVNULL);
 
        PG_CMD_OPEN;
@@ -1523,8 +1505,8 @@ setup_sysviews(void)
         * We use -N here to avoid backslashing stuff in system_views.sql
         */
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s -N template1 >%s",
-                        pgpath, backend_options,
+                        "\"%s\" %s -N template1 >%s",
+                        backend_exec, backend_options,
                         DEVNULL);
 
        PG_CMD_OPEN;
@@ -1555,8 +1537,8 @@ setup_description(void)
        fflush(stdout);
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s template1 >%s",
-                        pgpath, backend_options,
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
                         DEVNULL);
 
        PG_CMD_OPEN;
@@ -1603,8 +1585,8 @@ setup_conversion(void)
        fflush(stdout);
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s template1 >%s",
-                        pgpath, backend_options,
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
                         DEVNULL);
 
        PG_CMD_OPEN;
@@ -1659,14 +1641,14 @@ setup_privileges(void)
        fflush(stdout);
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s template1 >%s",
-                        pgpath, backend_options,
+                        "\"%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;
 
@@ -1722,8 +1704,8 @@ setup_schema(void)
         * We use -N here to avoid backslashing stuff in information_schema.sql
         */
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s -N template1 >%s",
-                        pgpath, backend_options,
+                        "\"%s\" %s -N template1 >%s",
+                        backend_exec, backend_options,
                         DEVNULL);
 
        PG_CMD_OPEN;
@@ -1739,8 +1721,8 @@ setup_schema(void)
        PG_CMD_CLOSE;
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s template1 >%s",
-                        pgpath, backend_options,
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
                         DEVNULL);
 
        PG_CMD_OPEN;
@@ -1779,8 +1761,8 @@ vacuum_db(void)
        fflush(stdout);
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s template1 >%s",
-                        pgpath, backend_options,
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
                         DEVNULL);
 
        PG_CMD_OPEN;
@@ -1835,8 +1817,8 @@ make_template0(void)
        fflush(stdout);
 
        snprintf(cmd, sizeof(cmd),
-                        "\"%s/postgres\" %s template1 >%s",
-                        pgpath, backend_options,
+                        "\"%s\" %s template1 >%s",
+                        backend_exec, backend_options,
                         DEVNULL);
 
        PG_CMD_OPEN;
@@ -2009,8 +1991,10 @@ usage(const char *progname)
                         "                            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=filename         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"));
@@ -2023,20 +2007,6 @@ usage(const char *progname)
        printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
 }
 
-/*
- * Initialized NLS if enabled.
- */
-static void
-init_nls(void)
-{
-#ifdef ENABLE_NLS
-        setlocale(LC_ALL, "");
-        bindtextdomain("initdb", LOCALEDIR);
-        textdomain("initdb");
-#endif
-}
-
-
 int
 main(int argc, char *argv[])
 {
@@ -2055,7 +2025,9 @@ 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'},
@@ -2066,48 +2038,25 @@ main(int argc, char *argv[])
        };
 
        int                     c,
-                               i;
+                               i,
+                               ret;
        int                     option_index;
        char       *short_version;
        char       *pgdenv;                     /* PGDATA value got from sent to
                                                                 * environment */
-       char       *subdirs[] =
-       {"global", "pg_xlog", "pg_clog", "base", "base/1"};
-       char       *lastsep;
-       char       *carg0;
-#if defined(__CYGWIN__) || defined(WIN32)
-       char       *exe;                        /* location of exe suffix in progname */
-#endif
-
-       init_nls();
-
-       /* parse argv[0] - detect explicit path if there was one */
-       carg0 = xstrdup(argv[0]);
-       canonicalize_path(carg0);
-
-       lastsep = strrchr(carg0, '/');
-       progname = lastsep ? xstrdup(lastsep + 1) : carg0;
-
-#if defined(__CYGWIN__) || defined(WIN32)
-       if (strlen(progname) > 4 &&
-               (exe = progname + (strlen(progname) - 4)) &&
-               stricmp(exe, EXE) == 0)
-       {
-               /* strip .exe suffix, regardless of case */
-               *exe = '\0';
-       }
-#endif
+       static const char *subdirs[] = {
+               "global",
+               "pg_xlog",
+               "pg_xlog/archive_status",
+               "pg_clog",
+               "pg_subtrans",
+               "base",
+               "base/1",
+               "pg_tblspc"
+       };
 
-       if (lastsep)
-       {
-               self_path = carg0;
-               *lastsep = '\0';
-       }
-       else
-       {
-               /* no path known to ourselves from argv[0] */
-               self_path = NULL;
-       }
+       progname = get_progname(argv[0]);
+       set_pglocale_pgservice(argv[0], "initdb");
 
     if (argc > 1)
     {
@@ -2125,10 +2074,13 @@ main(int argc, char *argv[])
 
        /* process command-line options */
 
-       while ((c = getopt_long(argc, argv, "dD:E:L:nU:W", long_options, &option_index)) != -1)
+       while ((c = getopt_long(argc, argv, "dD:E:L:nU:WA:", long_options, &option_index)) != -1)
        {
                switch (c)
                {
+                       case 'A':
+                               authmethod = xstrdup(optarg);
+                               break;
                        case 'D':
                                pg_data = xstrdup(optarg);
                                break;
@@ -2150,7 +2102,7 @@ main(int argc, char *argv[])
                                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);
@@ -2176,6 +2128,9 @@ main(int argc, char *argv[])
                        case 8:
                                locale = "C";
                                break;
+                       case 9:
+                               pwfilename = xstrdup(optarg);
+                               break;
                        case 's':
                                show_setting = true;
                                break;
@@ -2201,6 +2156,49 @@ main(int argc, char *argv[])
                                progname);
        }
 
+       if (pwprompt && pwfilename)
+       {
+               fprintf(stderr, _("%s: you cannot specify both password prompt and password file\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 flag 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: unknown authentication method \"%s\".\n"), progname, authmethod);
+               exit(1);
+       }
+
+       if ((!strcmp(authmethod,"md5") ||
+                !strcmp(authmethod,"crypt") ||
+                !strcmp(authmethod,"password")) &&
+                !(pwprompt || pwfilename))
+       {
+               fprintf(stderr, _("%s: you need to specify a password for the superuser to enable %s authentication.\n"), progname, authmethod);
+               exit(1);
+       }
+
        if (strlen(pg_data) == 0)
        {
                pgdenv = getenv("PGDATA");
@@ -2233,25 +2231,46 @@ main(int argc, char *argv[])
        sprintf(pgdenv, "PGDATA=%s", pg_data);
        putenv(pgdenv);
 
-       if (set_paths() != 0)
+       if ((ret = find_other_exec(argv[0], "postgres", PG_VERSIONSTR,
+                                                          backend_exec)) < 0)
        {
-               fprintf(stderr,
-                               _("The program \"postgres\" is needed by %s "
-                               "but was not found in \n"
-                               "the directory \"%s\". Check your installation.\n"),
-                               progname, bindir);
+               if (ret == -1)
+                       fprintf(stderr,
+                                               _("The program \"postgres\" is needed by %s "
+                                               "but was not found in the same directory as \"%s\".\n"
+                                               "Check your installation.\n"),
+                                               progname, progname);
+               else
+                       fprintf(stderr,
+                                               _("The program \"postgres\" was found by %s "
+                                               "but was not the same version as \"%s\".\n"
+                                               "Check your installation.\n"),
+                                               progname, progname);
                exit(1);
        }
 
+       /* store binary directory */
+       strcpy(bin_path, backend_exec);
+       *last_dir_separator(bin_path) = '\0';
+
+       if (!share_path)
+       {
+               share_path = xmalloc(MAXPGPATH);
+               get_share_path(backend_exec, share_path);
+       }
+
+       canonicalize_path(share_path);
+
        if ((short_version = get_short_version()) == NULL)
        {
                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);
@@ -2272,15 +2291,13 @@ main(int argc, char *argv[])
        {
                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)
@@ -2297,21 +2314,20 @@ main(int argc, char *argv[])
        check_input(features_file);
        check_input(system_views_file);
 
+       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);
 
-       setlocales();
-
        if (strcmp(lc_ctype, lc_collate) == 0 &&
                strcmp(lc_ctype, lc_time) == 0 &&
                strcmp(lc_ctype, lc_numeric) == 0 &&
                strcmp(lc_ctype, lc_monetary) == 0 &&
                strcmp(lc_ctype, lc_messages) == 0)
        {
-               printf(_("The database cluster will be initialized with locale %s.\n\n"),
-                          lc_ctype);
+               printf(_("The database cluster will be initialized with locale %s.\n"), lc_ctype);
        }
        else
        {
@@ -2321,7 +2337,7 @@ main(int argc, char *argv[])
                           "  MESSAGES: %s\n"
                           "  MONETARY: %s\n"
                           "  NUMERIC:  %s\n"
-                          "  TIME:     %s\n\n"),
+                          "  TIME:     %s\n"),
                           lc_collate,
                           lc_ctype,
                           lc_messages,
@@ -2330,6 +2346,34 @@ main(int argc, char *argv[])
                           lc_time);
        }
 
+#ifdef HAVE_LANGINFO_H
+       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 */
+
+       printf("\n");
+
        umask(077);
 
        /*
@@ -2440,13 +2484,13 @@ main(int argc, char *argv[])
        /* Bootstrap template1 */
        bootstrap_template1(short_version);
 
-       /* Make the per-database PGVERSION for template1 only after init'ing it */
+       /* 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();
@@ -2467,12 +2511,15 @@ main(int argc, char *argv[])
 
        make_template0();
 
+       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, pgpath, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH,
-               QUOTE_PATH, pgpath, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH);
+                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;
 }