Header And Logo

PostgreSQL
| The world's most advanced open source database.

initdb.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * initdb --- initialize a PostgreSQL installation
00004  *
00005  * initdb creates (initializes) a PostgreSQL database cluster (site,
00006  * instance, installation, whatever).  A database cluster is a
00007  * collection of PostgreSQL databases all managed by the same server.
00008  *
00009  * To create the database cluster, we create the directory that contains
00010  * all its data, create the files that hold the global tables, create
00011  * a few other control files for it, and create three databases: the
00012  * template databases "template0" and "template1", and a default user
00013  * database "postgres".
00014  *
00015  * The template databases are ordinary PostgreSQL databases.  template0
00016  * is never supposed to change after initdb, whereas template1 can be
00017  * changed to add site-local standard data.  Either one can be copied
00018  * to produce a new database.
00019  *
00020  * For largely-historical reasons, the template1 database is the one built
00021  * by the basic bootstrap process.  After it is complete, template0 and
00022  * the default database, postgres, are made just by copying template1.
00023  *
00024  * To create template1, we run the postgres (backend) program in bootstrap
00025  * mode and feed it data from the postgres.bki library file.  After this
00026  * initial bootstrap phase, some additional stuff is created by normal
00027  * SQL commands fed to a standalone backend.  Some of those commands are
00028  * just embedded into this program (yeah, it's ugly), but larger chunks
00029  * are taken from script files.
00030  *
00031  *
00032  * Note:
00033  *   The program has some memory leakage - it isn't worth cleaning it up.
00034  *
00035  * This is a C implementation of the previous shell script for setting up a
00036  * PostgreSQL cluster location, and should be highly compatible with it.
00037  * author of C translation: Andrew Dunstan     mailto:[email protected]
00038  *
00039  * This code is released under the terms of the PostgreSQL License.
00040  *
00041  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00042  * Portions Copyright (c) 1994, Regents of the University of California
00043  *
00044  * src/bin/initdb/initdb.c
00045  *
00046  *-------------------------------------------------------------------------
00047  */
00048 
00049 #include "postgres_fe.h"
00050 
00051 #include <dirent.h>
00052 #include <fcntl.h>
00053 #include <sys/stat.h>
00054 #include <unistd.h>
00055 #include <locale.h>
00056 #include <signal.h>
00057 #include <time.h>
00058 
00059 #include "mb/pg_wchar.h"
00060 #include "getaddrinfo.h"
00061 #include "getopt_long.h"
00062 #include "miscadmin.h"
00063 
00064 /* Ideally this would be in a .h file, but it hardly seems worth the trouble */
00065 extern const char *select_default_timezone(const char *share_path);
00066 
00067 static const char *auth_methods_host[] = {"trust", "reject", "md5", "password", "ident", "radius",
00068 #ifdef ENABLE_GSS
00069     "gss",
00070 #endif
00071 #ifdef ENABLE_SSPI
00072     "sspi",
00073 #endif
00074 #ifdef KRB5
00075     "krb5",
00076 #endif
00077 #ifdef USE_PAM
00078     "pam", "pam ",
00079 #endif
00080 #ifdef USE_LDAP
00081     "ldap",
00082 #endif
00083 #ifdef USE_SSL
00084     "cert",
00085 #endif
00086 NULL};
00087 static const char *auth_methods_local[] = {"trust", "reject", "md5", "password", "peer", "radius",
00088 #ifdef USE_PAM
00089     "pam", "pam ",
00090 #endif
00091 #ifdef USE_LDAP
00092     "ldap",
00093 #endif
00094 NULL};
00095 
00096 /*
00097  * these values are passed in by makefile defines
00098  */
00099 static char *share_path = NULL;
00100 
00101 /* values to be obtained from arguments */
00102 static char *pg_data = "";
00103 static char *encoding = "";
00104 static char *locale = "";
00105 static char *lc_collate = "";
00106 static char *lc_ctype = "";
00107 static char *lc_monetary = "";
00108 static char *lc_numeric = "";
00109 static char *lc_time = "";
00110 static char *lc_messages = "";
00111 static const char *default_text_search_config = "";
00112 static char *username = "";
00113 static bool pwprompt = false;
00114 static char *pwfilename = NULL;
00115 static const char *authmethodhost = "";
00116 static const char *authmethodlocal = "";
00117 static bool debug = false;
00118 static bool noclean = false;
00119 static bool do_sync = true;
00120 static bool sync_only = false;
00121 static bool show_setting = false;
00122 static bool data_checksums = false;
00123 static char *xlog_dir = "";
00124 
00125 
00126 /* internal vars */
00127 static const char *progname;
00128 static char *encodingid = "0";
00129 static char *bki_file;
00130 static char *desc_file;
00131 static char *shdesc_file;
00132 static char *hba_file;
00133 static char *ident_file;
00134 static char *conf_file;
00135 static char *conversion_file;
00136 static char *dictionary_file;
00137 static char *info_schema_file;
00138 static char *features_file;
00139 static char *system_views_file;
00140 static bool made_new_pgdata = false;
00141 static bool found_existing_pgdata = false;
00142 static bool made_new_xlogdir = false;
00143 static bool found_existing_xlogdir = false;
00144 static char infoversion[100];
00145 static bool caught_signal = false;
00146 static bool output_failed = false;
00147 static int  output_errno = 0;
00148 static char *pgdata_native;
00149 
00150 /* defaults */
00151 static int  n_connections = 10;
00152 static int  n_buffers = 50;
00153 
00154 /*
00155  * Warning messages for authentication methods
00156  */
00157 #define AUTHTRUST_WARNING \
00158 "# CAUTION: Configuring the system for local \"trust\" authentication\n" \
00159 "# allows any local user to connect as any PostgreSQL user, including\n" \
00160 "# the database superuser.  If you do not trust all your local users,\n" \
00161 "# use another authentication method.\n"
00162 static char *authwarning = NULL;
00163 
00164 /*
00165  * Centralized knowledge of switches to pass to backend
00166  *
00167  * Note: we run the backend with -F (fsync disabled) and then do a single
00168  * pass of fsync'ing at the end.  This is faster than fsync'ing each step.
00169  *
00170  * Note: in the shell-script version, we also passed PGDATA as a -D switch,
00171  * but here it is more convenient to pass it as an environment variable
00172  * (no quoting to worry about).
00173  */
00174 static const char *boot_options = "-F";
00175 static const char *backend_options = "--single -F -O -c search_path=pg_catalog -c exit_on_error=true";
00176 
00177 #ifdef WIN32
00178 char       *restrict_env;
00179 #endif
00180 const char *subdirs[] = {
00181     "global",
00182     "pg_xlog",
00183     "pg_xlog/archive_status",
00184     "pg_clog",
00185     "pg_notify",
00186     "pg_serial",
00187     "pg_snapshots",
00188     "pg_subtrans",
00189     "pg_twophase",
00190     "pg_multixact/members",
00191     "pg_multixact/offsets",
00192     "base",
00193     "base/1",
00194     "pg_tblspc",
00195     "pg_stat",
00196     "pg_stat_tmp"
00197 };
00198 
00199 
00200 /* path to 'initdb' binary directory */
00201 static char bin_path[MAXPGPATH];
00202 static char backend_exec[MAXPGPATH];
00203 
00204 static char **replace_token(char **lines,
00205               const char *token, const char *replacement);
00206 
00207 #ifndef HAVE_UNIX_SOCKETS
00208 static char **filter_lines_with_token(char **lines, const char *token);
00209 #endif
00210 static char **readfile(const char *path);
00211 static void writefile(char *path, char **lines);
00212 static void walkdir(char *path, void (*action)(char *fname, bool isdir));
00213 static void pre_sync_fname(char *fname, bool isdir);
00214 static void fsync_fname(char *fname, bool isdir);
00215 static FILE *popen_check(const char *command, const char *mode);
00216 static void exit_nicely(void);
00217 static char *get_id(void);
00218 static char *get_encoding_id(char *encoding_name);
00219 static bool mkdatadir(const char *subdir);
00220 static void set_input(char **dest, char *filename);
00221 static void check_input(char *path);
00222 static void write_version_file(char *extrapath);
00223 static void set_null_conf(void);
00224 static void test_config_settings(void);
00225 static void setup_config(void);
00226 static void bootstrap_template1(void);
00227 static void setup_auth(void);
00228 static void get_set_pwd(void);
00229 static void setup_depend(void);
00230 static void setup_sysviews(void);
00231 static void setup_description(void);
00232 static void setup_collation(void);
00233 static void setup_conversion(void);
00234 static void setup_dictionary(void);
00235 static void setup_privileges(void);
00236 static void set_info_version(void);
00237 static void setup_schema(void);
00238 static void load_plpgsql(void);
00239 static void vacuum_db(void);
00240 static void make_template0(void);
00241 static void make_postgres(void);
00242 static void perform_fsync(void);
00243 static void trapsig(int signum);
00244 static void check_ok(void);
00245 static char *escape_quotes(const char *src);
00246 static int  locale_date_order(const char *locale);
00247 static bool check_locale_name(int category, const char *locale,
00248                   char **canonname);
00249 static bool check_locale_encoding(const char *locale, int encoding);
00250 static void setlocales(void);
00251 static void usage(const char *progname);
00252 void get_restricted_token(void);
00253 void setup_pgdata(void);
00254 void setup_bin_paths(const char *argv0);
00255 void setup_data_file_paths(void);
00256 void setup_locale_encoding(void);
00257 void setup_signals(void);
00258 void setup_text_search(void);
00259 void create_data_directory(void);
00260 void create_xlog_symlink(void);
00261 void warn_on_mount_point(int error);
00262 void initialize_data_directory(void);
00263 
00264 
00265 #ifdef WIN32
00266 static int  CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo);
00267 #endif
00268 
00269 
00270 /*
00271  * macros for running pipes to postgres
00272  */
00273 #define PG_CMD_DECL     char cmd[MAXPGPATH]; FILE *cmdfd
00274 
00275 #define PG_CMD_OPEN \
00276 do { \
00277     cmdfd = popen_check(cmd, "w"); \
00278     if (cmdfd == NULL) \
00279         exit_nicely(); /* message already printed by popen_check */ \
00280 } while (0)
00281 
00282 #define PG_CMD_CLOSE \
00283 do { \
00284     if (pclose_check(cmdfd)) \
00285         exit_nicely(); /* message already printed by pclose_check */ \
00286 } while (0)
00287 
00288 #define PG_CMD_PUTS(line) \
00289 do { \
00290     if (fputs(line, cmdfd) < 0 || fflush(cmdfd) < 0) \
00291         output_failed = true, output_errno = errno; \
00292 } while (0)
00293 
00294 #define PG_CMD_PRINTF1(fmt, arg1) \
00295 do { \
00296     if (fprintf(cmdfd, fmt, arg1) < 0 || fflush(cmdfd) < 0) \
00297         output_failed = true, output_errno = errno; \
00298 } while (0)
00299 
00300 #define PG_CMD_PRINTF2(fmt, arg1, arg2) \
00301 do { \
00302     if (fprintf(cmdfd, fmt, arg1, arg2) < 0 || fflush(cmdfd) < 0) \
00303         output_failed = true, output_errno = errno; \
00304 } while (0)
00305 
00306 #define PG_CMD_PRINTF3(fmt, arg1, arg2, arg3)       \
00307 do { \
00308     if (fprintf(cmdfd, fmt, arg1, arg2, arg3) < 0 || fflush(cmdfd) < 0) \
00309         output_failed = true, output_errno = errno; \
00310 } while (0)
00311 
00312 #ifndef WIN32
00313 #define QUOTE_PATH  ""
00314 #define DIR_SEP "/"
00315 #else
00316 #define QUOTE_PATH  "\""
00317 #define DIR_SEP "\\"
00318 #endif
00319 
00320 static char *
00321 escape_quotes(const char *src)
00322 {
00323     char *result = escape_single_quotes_ascii(src);
00324     if (!result)
00325     {
00326         fprintf(stderr, _("%s: out of memory\n"), progname);
00327         exit(1);
00328     }
00329     return result;
00330 }
00331 
00332 /*
00333  * make a copy of the array of lines, with token replaced by replacement
00334  * the first time it occurs on each line.
00335  *
00336  * This does most of what sed was used for in the shell script, but
00337  * doesn't need any regexp stuff.
00338  */
00339 static char **
00340 replace_token(char **lines, const char *token, const char *replacement)
00341 {
00342     int         numlines = 1;
00343     int         i;
00344     char      **result;
00345     int         toklen,
00346                 replen,
00347                 diff;
00348 
00349     for (i = 0; lines[i]; i++)
00350         numlines++;
00351 
00352     result = (char **) pg_malloc(numlines * sizeof(char *));
00353 
00354     toklen = strlen(token);
00355     replen = strlen(replacement);
00356     diff = replen - toklen;
00357 
00358     for (i = 0; i < numlines; i++)
00359     {
00360         char       *where;
00361         char       *newline;
00362         int         pre;
00363 
00364         /* just copy pointer if NULL or no change needed */
00365         if (lines[i] == NULL || (where = strstr(lines[i], token)) == NULL)
00366         {
00367             result[i] = lines[i];
00368             continue;
00369         }
00370 
00371         /* if we get here a change is needed - set up new line */
00372 
00373         newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1);
00374 
00375         pre = where - lines[i];
00376 
00377         strncpy(newline, lines[i], pre);
00378 
00379         strcpy(newline + pre, replacement);
00380 
00381         strcpy(newline + pre + replen, lines[i] + pre + toklen);
00382 
00383         result[i] = newline;
00384     }
00385 
00386     return result;
00387 }
00388 
00389 /*
00390  * make a copy of lines without any that contain the token
00391  *
00392  * a sort of poor man's grep -v
00393  */
00394 #ifndef HAVE_UNIX_SOCKETS
00395 static char **
00396 filter_lines_with_token(char **lines, const char *token)
00397 {
00398     int         numlines = 1;
00399     int         i,
00400                 src,
00401                 dst;
00402     char      **result;
00403 
00404     for (i = 0; lines[i]; i++)
00405         numlines++;
00406 
00407     result = (char **) pg_malloc(numlines * sizeof(char *));
00408 
00409     for (src = 0, dst = 0; src < numlines; src++)
00410     {
00411         if (lines[src] == NULL || strstr(lines[src], token) == NULL)
00412             result[dst++] = lines[src];
00413     }
00414 
00415     return result;
00416 }
00417 #endif
00418 
00419 /*
00420  * get the lines from a text file
00421  */
00422 static char **
00423 readfile(const char *path)
00424 {
00425     FILE       *infile;
00426     int         maxlength = 1,
00427                 linelen = 0;
00428     int         nlines = 0;
00429     int         n;
00430     char      **result;
00431     char       *buffer;
00432     int         c;
00433 
00434     if ((infile = fopen(path, "r")) == NULL)
00435     {
00436         fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
00437                 progname, path, strerror(errno));
00438         exit_nicely();
00439     }
00440 
00441     /* pass over the file twice - the first time to size the result */
00442 
00443     while ((c = fgetc(infile)) != EOF)
00444     {
00445         linelen++;
00446         if (c == '\n')
00447         {
00448             nlines++;
00449             if (linelen > maxlength)
00450                 maxlength = linelen;
00451             linelen = 0;
00452         }
00453     }
00454 
00455     /* handle last line without a terminating newline (yuck) */
00456     if (linelen)
00457         nlines++;
00458     if (linelen > maxlength)
00459         maxlength = linelen;
00460 
00461     /* set up the result and the line buffer */
00462     result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
00463     buffer = (char *) pg_malloc(maxlength + 1);
00464 
00465     /* now reprocess the file and store the lines */
00466     rewind(infile);
00467     n = 0;
00468     while (fgets(buffer, maxlength + 1, infile) != NULL && n < nlines)
00469         result[n++] = pg_strdup(buffer);
00470 
00471     fclose(infile);
00472     free(buffer);
00473     result[n] = NULL;
00474 
00475     return result;
00476 }
00477 
00478 /*
00479  * write an array of lines to a file
00480  *
00481  * This is only used to write text files.  Use fopen "w" not PG_BINARY_W
00482  * so that the resulting configuration files are nicely editable on Windows.
00483  */
00484 static void
00485 writefile(char *path, char **lines)
00486 {
00487     FILE       *out_file;
00488     char      **line;
00489 
00490     if ((out_file = fopen(path, "w")) == NULL)
00491     {
00492         fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
00493                 progname, path, strerror(errno));
00494         exit_nicely();
00495     }
00496     for (line = lines; *line != NULL; line++)
00497     {
00498         if (fputs(*line, out_file) < 0)
00499         {
00500             fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
00501                     progname, path, strerror(errno));
00502             exit_nicely();
00503         }
00504         free(*line);
00505     }
00506     if (fclose(out_file))
00507     {
00508         fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
00509                 progname, path, strerror(errno));
00510         exit_nicely();
00511     }
00512 }
00513 
00514 /*
00515  * walkdir: recursively walk a directory, applying the action to each
00516  * regular file and directory (including the named directory itself).
00517  *
00518  * Adapted from copydir() in copydir.c.
00519  */
00520 static void
00521 walkdir(char *path, void (*action) (char *fname, bool isdir))
00522 {
00523     DIR        *dir;
00524     struct dirent *direntry;
00525     char        subpath[MAXPGPATH];
00526 
00527     dir = opendir(path);
00528     if (dir == NULL)
00529     {
00530         fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
00531                 progname, path, strerror(errno));
00532         exit_nicely();
00533     }
00534 
00535     while (errno = 0, (direntry = readdir(dir)) != NULL)
00536     {
00537         struct stat fst;
00538 
00539         if (strcmp(direntry->d_name, ".") == 0 ||
00540             strcmp(direntry->d_name, "..") == 0)
00541             continue;
00542 
00543         snprintf(subpath, MAXPGPATH, "%s/%s", path, direntry->d_name);
00544 
00545         if (lstat(subpath, &fst) < 0)
00546         {
00547             fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"),
00548                     progname, subpath, strerror(errno));
00549             exit_nicely();
00550         }
00551 
00552         if (S_ISDIR(fst.st_mode))
00553             walkdir(subpath, action);
00554         else if (S_ISREG(fst.st_mode))
00555             (*action) (subpath, false);
00556     }
00557 
00558 #ifdef WIN32
00559     /*
00560      * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
00561      * released version
00562      */
00563     if (GetLastError() == ERROR_NO_MORE_FILES)
00564         errno = 0;
00565 #endif
00566 
00567     if (errno)
00568     {
00569         fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
00570                 progname, path, strerror(errno));
00571         exit_nicely();
00572     }
00573 
00574     closedir(dir);
00575 
00576     /*
00577      * It's important to fsync the destination directory itself as individual
00578      * file fsyncs don't guarantee that the directory entry for the file is
00579      * synced.  Recent versions of ext4 have made the window much wider but
00580      * it's been an issue for ext3 and other filesystems in the past.
00581      */
00582     (*action) (path, true);
00583 }
00584 
00585 /*
00586  * Hint to the OS that it should get ready to fsync() this file.
00587  */
00588 static void
00589 pre_sync_fname(char *fname, bool isdir)
00590 {
00591 #if defined(HAVE_SYNC_FILE_RANGE) || \
00592     (defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED))
00593     int fd;
00594 
00595     fd = open(fname, O_RDONLY | PG_BINARY);
00596 
00597     /*
00598      * Some OSs don't allow us to open directories at all (Windows returns
00599      * EACCES)
00600      */
00601     if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES))
00602         return;
00603 
00604     if (fd < 0)
00605     {
00606         fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
00607                 progname, fname, strerror(errno));
00608         exit_nicely();
00609     }
00610 
00611     /*
00612      * Prefer sync_file_range, else use posix_fadvise.  We ignore any error
00613      * here since this operation is only a hint anyway.
00614      */
00615 #if defined(HAVE_SYNC_FILE_RANGE)
00616     sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WRITE);
00617 #elif defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
00618     posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
00619 #endif
00620 
00621     close(fd);
00622 #endif
00623 }
00624 
00625 /*
00626  * fsync a file or directory
00627  *
00628  * Try to fsync directories but ignore errors that indicate the OS
00629  * just doesn't allow/require fsyncing directories.
00630  *
00631  * Adapted from fsync_fname() in copydir.c.
00632  */
00633 static void
00634 fsync_fname(char *fname, bool isdir)
00635 {
00636     int         fd;
00637     int         returncode;
00638 
00639     /*
00640      * Some OSs require directories to be opened read-only whereas other
00641      * systems don't allow us to fsync files opened read-only; so we need both
00642      * cases here
00643      */
00644     if (!isdir)
00645         fd = open(fname, O_RDWR | PG_BINARY);
00646     else
00647         fd = open(fname, O_RDONLY | PG_BINARY);
00648 
00649     /*
00650      * Some OSs don't allow us to open directories at all (Windows returns
00651      * EACCES)
00652      */
00653     if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES))
00654         return;
00655 
00656     else if (fd < 0)
00657     {
00658         fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
00659                 progname, fname, strerror(errno));
00660         exit_nicely();
00661     }
00662 
00663     returncode = fsync(fd);
00664 
00665     /* Some OSs don't allow us to fsync directories at all */
00666     if (returncode != 0 && isdir && errno == EBADF)
00667     {
00668         close(fd);
00669         return;
00670     }
00671 
00672     if (returncode != 0)
00673     {
00674         fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"),
00675                 progname, fname, strerror(errno));
00676         exit_nicely();
00677     }
00678 
00679     close(fd);
00680 }
00681 
00682 /*
00683  * Open a subcommand with suitable error messaging
00684  */
00685 static FILE *
00686 popen_check(const char *command, const char *mode)
00687 {
00688     FILE       *cmdfd;
00689 
00690     fflush(stdout);
00691     fflush(stderr);
00692     errno = 0;
00693     cmdfd = popen(command, mode);
00694     if (cmdfd == NULL)
00695         fprintf(stderr, _("%s: could not execute command \"%s\": %s\n"),
00696                 progname, command, strerror(errno));
00697     return cmdfd;
00698 }
00699 
00700 /*
00701  * clean up any files we created on failure
00702  * if we created the data directory remove it too
00703  */
00704 static void
00705 exit_nicely(void)
00706 {
00707     if (!noclean)
00708     {
00709         if (made_new_pgdata)
00710         {
00711             fprintf(stderr, _("%s: removing data directory \"%s\"\n"),
00712                     progname, pg_data);
00713             if (!rmtree(pg_data, true))
00714                 fprintf(stderr, _("%s: failed to remove data directory\n"),
00715                         progname);
00716         }
00717         else if (found_existing_pgdata)
00718         {
00719             fprintf(stderr,
00720                     _("%s: removing contents of data directory \"%s\"\n"),
00721                     progname, pg_data);
00722             if (!rmtree(pg_data, false))
00723                 fprintf(stderr, _("%s: failed to remove contents of data directory\n"),
00724                         progname);
00725         }
00726 
00727         if (made_new_xlogdir)
00728         {
00729             fprintf(stderr, _("%s: removing transaction log directory \"%s\"\n"),
00730                     progname, xlog_dir);
00731             if (!rmtree(xlog_dir, true))
00732                 fprintf(stderr, _("%s: failed to remove transaction log directory\n"),
00733                         progname);
00734         }
00735         else if (found_existing_xlogdir)
00736         {
00737             fprintf(stderr,
00738             _("%s: removing contents of transaction log directory \"%s\"\n"),
00739                     progname, xlog_dir);
00740             if (!rmtree(xlog_dir, false))
00741                 fprintf(stderr, _("%s: failed to remove contents of transaction log directory\n"),
00742                         progname);
00743         }
00744         /* otherwise died during startup, do nothing! */
00745     }
00746     else
00747     {
00748         if (made_new_pgdata || found_existing_pgdata)
00749             fprintf(stderr,
00750               _("%s: data directory \"%s\" not removed at user's request\n"),
00751                     progname, pg_data);
00752 
00753         if (made_new_xlogdir || found_existing_xlogdir)
00754             fprintf(stderr,
00755                     _("%s: transaction log directory \"%s\" not removed at user's request\n"),
00756                     progname, xlog_dir);
00757     }
00758 
00759     exit(1);
00760 }
00761 
00762 /*
00763  * find the current user
00764  *
00765  * on unix make sure it isn't really root
00766  */
00767 static char *
00768 get_id(void)
00769 {
00770 #ifndef WIN32
00771 
00772     struct passwd *pw;
00773 
00774     if (geteuid() == 0)         /* 0 is root's uid */
00775     {
00776         fprintf(stderr,
00777                 _("%s: cannot be run as root\n"
00778                   "Please log in (using, e.g., \"su\") as the "
00779                   "(unprivileged) user that will\n"
00780                   "own the server process.\n"),
00781                 progname);
00782         exit(1);
00783     }
00784 
00785     pw = getpwuid(geteuid());
00786     if (!pw)
00787     {
00788         fprintf(stderr,
00789               _("%s: could not obtain information about current user: %s\n"),
00790                 progname, strerror(errno));
00791         exit(1);
00792     }
00793 #else                           /* the windows code */
00794 
00795     struct passwd_win32
00796     {
00797         int         pw_uid;
00798         char        pw_name[128];
00799     }           pass_win32;
00800     struct passwd_win32 *pw = &pass_win32;
00801     DWORD       pwname_size = sizeof(pass_win32.pw_name) - 1;
00802 
00803     pw->pw_uid = 1;
00804     if (!GetUserName(pw->pw_name, &pwname_size))
00805     {
00806         fprintf(stderr, _("%s: could not get current user name: %s\n"),
00807                 progname, strerror(errno));
00808         exit(1);
00809     }
00810 #endif
00811 
00812     return pg_strdup(pw->pw_name);
00813 }
00814 
00815 static char *
00816 encodingid_to_string(int enc)
00817 {
00818     char        result[20];
00819 
00820     sprintf(result, "%d", enc);
00821     return pg_strdup(result);
00822 }
00823 
00824 /*
00825  * get the encoding id for a given encoding name
00826  */
00827 static char *
00828 get_encoding_id(char *encoding_name)
00829 {
00830     int         enc;
00831 
00832     if (encoding_name && *encoding_name)
00833     {
00834         if ((enc = pg_valid_server_encoding(encoding_name)) >= 0)
00835             return encodingid_to_string(enc);
00836     }
00837     fprintf(stderr, _("%s: \"%s\" is not a valid server encoding name\n"),
00838             progname, encoding_name ? encoding_name : "(null)");
00839     exit(1);
00840 }
00841 
00842 /*
00843  * Support for determining the best default text search configuration.
00844  * We key this off the first part of LC_CTYPE (ie, the language name).
00845  */
00846 struct tsearch_config_match
00847 {
00848     const char *tsconfname;
00849     const char *langname;
00850 };
00851 
00852 static const struct tsearch_config_match tsearch_config_languages[] =
00853 {
00854     {"danish", "da"},
00855     {"danish", "Danish"},
00856     {"dutch", "nl"},
00857     {"dutch", "Dutch"},
00858     {"english", "C"},
00859     {"english", "POSIX"},
00860     {"english", "en"},
00861     {"english", "English"},
00862     {"finnish", "fi"},
00863     {"finnish", "Finnish"},
00864     {"french", "fr"},
00865     {"french", "French"},
00866     {"german", "de"},
00867     {"german", "German"},
00868     {"hungarian", "hu"},
00869     {"hungarian", "Hungarian"},
00870     {"italian", "it"},
00871     {"italian", "Italian"},
00872     {"norwegian", "no"},
00873     {"norwegian", "Norwegian"},
00874     {"portuguese", "pt"},
00875     {"portuguese", "Portuguese"},
00876     {"romanian", "ro"},
00877     {"russian", "ru"},
00878     {"russian", "Russian"},
00879     {"spanish", "es"},
00880     {"spanish", "Spanish"},
00881     {"swedish", "sv"},
00882     {"swedish", "Swedish"},
00883     {"turkish", "tr"},
00884     {"turkish", "Turkish"},
00885     {NULL, NULL}                /* end marker */
00886 };
00887 
00888 /*
00889  * Look for a text search configuration matching lc_ctype, and return its
00890  * name; return NULL if no match.
00891  */
00892 static const char *
00893 find_matching_ts_config(const char *lc_type)
00894 {
00895     int         i;
00896     char       *langname,
00897                *ptr;
00898 
00899     /*
00900      * Convert lc_ctype to a language name by stripping everything after an
00901      * underscore (usual case) or a hyphen (Windows "locale name"; see
00902      * comments at IsoLocaleName()).
00903      *
00904      * XXX Should ' ' be a stop character?  This would select "norwegian" for
00905      * the Windows locale "Norwegian (Nynorsk)_Norway.1252".  If we do so, we
00906      * should also accept the "nn" and "nb" Unix locales.
00907      *
00908      * Just for paranoia, we also stop at '.' or '@'.
00909      */
00910     if (lc_type == NULL)
00911         langname = pg_strdup("");
00912     else
00913     {
00914         ptr = langname = pg_strdup(lc_type);
00915         while (*ptr &&
00916                *ptr != '_' && *ptr != '-' && *ptr != '.' && *ptr != '@')
00917             ptr++;
00918         *ptr = '\0';
00919     }
00920 
00921     for (i = 0; tsearch_config_languages[i].tsconfname; i++)
00922     {
00923         if (pg_strcasecmp(tsearch_config_languages[i].langname, langname) == 0)
00924         {
00925             free(langname);
00926             return tsearch_config_languages[i].tsconfname;
00927         }
00928     }
00929 
00930     free(langname);
00931     return NULL;
00932 }
00933 
00934 
00935 /*
00936  * make the data directory (or one of its subdirectories if subdir is not NULL)
00937  */
00938 static bool
00939 mkdatadir(const char *subdir)
00940 {
00941     char       *path;
00942 
00943     path = pg_malloc(strlen(pg_data) + 2 +
00944                      (subdir == NULL ? 0 : strlen(subdir)));
00945 
00946     if (subdir != NULL)
00947         sprintf(path, "%s/%s", pg_data, subdir);
00948     else
00949         strcpy(path, pg_data);
00950 
00951     if (pg_mkdir_p(path, S_IRWXU) == 0)
00952         return true;
00953 
00954     fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
00955             progname, path, strerror(errno));
00956 
00957     return false;
00958 }
00959 
00960 
00961 /*
00962  * set name of given input file variable under data directory
00963  */
00964 static void
00965 set_input(char **dest, char *filename)
00966 {
00967     *dest = pg_malloc(strlen(share_path) + strlen(filename) + 2);
00968     sprintf(*dest, "%s/%s", share_path, filename);
00969 }
00970 
00971 /*
00972  * check that given input file exists
00973  */
00974 static void
00975 check_input(char *path)
00976 {
00977     struct stat statbuf;
00978 
00979     if (stat(path, &statbuf) != 0)
00980     {
00981         if (errno == ENOENT)
00982         {
00983             fprintf(stderr,
00984                     _("%s: file \"%s\" does not exist\n"), progname, path);
00985             fprintf(stderr,
00986                     _("This might mean you have a corrupted installation or identified\n"
00987                     "the wrong directory with the invocation option -L.\n"));
00988         }
00989         else
00990         {
00991             fprintf(stderr,
00992                  _("%s: could not access file \"%s\": %s\n"), progname, path,
00993                     strerror(errno));
00994             fprintf(stderr,
00995                     _("This might mean you have a corrupted installation or identified\n"
00996                     "the wrong directory with the invocation option -L.\n"));
00997         }
00998         exit(1);
00999     }
01000     if (!S_ISREG(statbuf.st_mode))
01001     {
01002         fprintf(stderr,
01003                 _("%s: file \"%s\" is not a regular file\n"), progname, path);
01004         fprintf(stderr,
01005         _("This might mean you have a corrupted installation or identified\n"
01006           "the wrong directory with the invocation option -L.\n"));
01007         exit(1);
01008     }
01009 }
01010 
01011 /*
01012  * write out the PG_VERSION file in the data dir, or its subdirectory
01013  * if extrapath is not NULL
01014  */
01015 static void
01016 write_version_file(char *extrapath)
01017 {
01018     FILE       *version_file;
01019     char       *path;
01020 
01021     if (extrapath == NULL)
01022     {
01023         path = pg_malloc(strlen(pg_data) + 12);
01024         sprintf(path, "%s/PG_VERSION", pg_data);
01025     }
01026     else
01027     {
01028         path = pg_malloc(strlen(pg_data) + strlen(extrapath) + 13);
01029         sprintf(path, "%s/%s/PG_VERSION", pg_data, extrapath);
01030     }
01031 
01032     if ((version_file = fopen(path, PG_BINARY_W)) == NULL)
01033     {
01034         fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
01035                 progname, path, strerror(errno));
01036         exit_nicely();
01037     }
01038     if (fprintf(version_file, "%s\n", PG_MAJORVERSION) < 0 ||
01039         fclose(version_file))
01040     {
01041         fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
01042                 progname, path, strerror(errno));
01043         exit_nicely();
01044     }
01045     free(path);
01046 }
01047 
01048 /*
01049  * set up an empty config file so we can check config settings by launching
01050  * a test backend
01051  */
01052 static void
01053 set_null_conf(void)
01054 {
01055     FILE       *conf_file;
01056     char       *path;
01057 
01058     path = pg_malloc(strlen(pg_data) + 17);
01059     sprintf(path, "%s/postgresql.conf", pg_data);
01060     conf_file = fopen(path, PG_BINARY_W);
01061     if (conf_file == NULL)
01062     {
01063         fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
01064                 progname, path, strerror(errno));
01065         exit_nicely();
01066     }
01067     if (fclose(conf_file))
01068     {
01069         fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
01070                 progname, path, strerror(errno));
01071         exit_nicely();
01072     }
01073     free(path);
01074 }
01075 
01076 /*
01077  * Determine platform-specific config settings
01078  *
01079  * Use reasonable values if kernel will let us, else scale back.  Probe
01080  * for max_connections first since it is subject to more constraints than
01081  * shared_buffers.
01082  */
01083 static void
01084 test_config_settings(void)
01085 {
01086     /*
01087      * This macro defines the minimum shared_buffers we want for a given
01088      * max_connections value. The arrays show the settings to try.
01089      */
01090 #define MIN_BUFS_FOR_CONNS(nconns)  ((nconns) * 10)
01091 
01092     static const int trial_conns[] = {
01093         100, 50, 40, 30, 20, 10
01094     };
01095     static const int trial_bufs[] = {
01096         16384, 8192, 4096, 3584, 3072, 2560, 2048, 1536,
01097         1000, 900, 800, 700, 600, 500,
01098         400, 300, 200, 100, 50
01099     };
01100 
01101     char        cmd[MAXPGPATH];
01102     const int   connslen = sizeof(trial_conns) / sizeof(int);
01103     const int   bufslen = sizeof(trial_bufs) / sizeof(int);
01104     int         i,
01105                 status,
01106                 test_conns,
01107                 test_buffs,
01108                 ok_buffers = 0;
01109 
01110 
01111     printf(_("selecting default max_connections ... "));
01112     fflush(stdout);
01113 
01114     for (i = 0; i < connslen; i++)
01115     {
01116         test_conns = trial_conns[i];
01117         test_buffs = MIN_BUFS_FOR_CONNS(test_conns);
01118 
01119         snprintf(cmd, sizeof(cmd),
01120                  SYSTEMQUOTE "\"%s\" --boot -x0 %s "
01121                  "-c max_connections=%d "
01122                  "-c shared_buffers=%d "
01123                  "< \"%s\" > \"%s\" 2>&1" SYSTEMQUOTE,
01124                  backend_exec, boot_options,
01125                  test_conns, test_buffs,
01126                  DEVNULL, DEVNULL);
01127         status = system(cmd);
01128         if (status == 0)
01129         {
01130             ok_buffers = test_buffs;
01131             break;
01132         }
01133     }
01134     if (i >= connslen)
01135         i = connslen - 1;
01136     n_connections = trial_conns[i];
01137 
01138     printf("%d\n", n_connections);
01139 
01140     printf(_("selecting default shared_buffers ... "));
01141     fflush(stdout);
01142 
01143     for (i = 0; i < bufslen; i++)
01144     {
01145         /* Use same amount of memory, independent of BLCKSZ */
01146         test_buffs = (trial_bufs[i] * 8192) / BLCKSZ;
01147         if (test_buffs <= ok_buffers)
01148         {
01149             test_buffs = ok_buffers;
01150             break;
01151         }
01152 
01153         snprintf(cmd, sizeof(cmd),
01154                  SYSTEMQUOTE "\"%s\" --boot -x0 %s "
01155                  "-c max_connections=%d "
01156                  "-c shared_buffers=%d "
01157                  "< \"%s\" > \"%s\" 2>&1" SYSTEMQUOTE,
01158                  backend_exec, boot_options,
01159                  n_connections, test_buffs,
01160                  DEVNULL, DEVNULL);
01161         status = system(cmd);
01162         if (status == 0)
01163             break;
01164     }
01165     n_buffers = test_buffs;
01166 
01167     if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
01168         printf("%dMB\n", (n_buffers * (BLCKSZ / 1024)) / 1024);
01169     else
01170         printf("%dkB\n", n_buffers * (BLCKSZ / 1024));
01171 }
01172 
01173 /*
01174  * set up all the config files
01175  */
01176 static void
01177 setup_config(void)
01178 {
01179     char      **conflines;
01180     char        repltok[MAXPGPATH];
01181     char        path[MAXPGPATH];
01182     const char *default_timezone;
01183 
01184     fputs(_("creating configuration files ... "), stdout);
01185     fflush(stdout);
01186 
01187     /* postgresql.conf */
01188 
01189     conflines = readfile(conf_file);
01190 
01191     snprintf(repltok, sizeof(repltok), "max_connections = %d", n_connections);
01192     conflines = replace_token(conflines, "#max_connections = 100", repltok);
01193 
01194     if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
01195         snprintf(repltok, sizeof(repltok), "shared_buffers = %dMB",
01196                  (n_buffers * (BLCKSZ / 1024)) / 1024);
01197     else
01198         snprintf(repltok, sizeof(repltok), "shared_buffers = %dkB",
01199                  n_buffers * (BLCKSZ / 1024));
01200     conflines = replace_token(conflines, "#shared_buffers = 32MB", repltok);
01201 
01202 #ifdef HAVE_UNIX_SOCKETS
01203     snprintf(repltok, sizeof(repltok), "#unix_socket_directories = '%s'",
01204              DEFAULT_PGSOCKET_DIR);
01205 #else
01206     snprintf(repltok, sizeof(repltok), "#unix_socket_directories = ''");
01207 #endif
01208     conflines = replace_token(conflines, "#unix_socket_directories = '/tmp'",
01209                               repltok);
01210 
01211 #if DEF_PGPORT != 5432
01212     snprintf(repltok, sizeof(repltok), "#port = %d", DEF_PGPORT);
01213     conflines = replace_token(conflines, "#port = 5432", repltok);
01214 #endif
01215 
01216     snprintf(repltok, sizeof(repltok), "lc_messages = '%s'",
01217              escape_quotes(lc_messages));
01218     conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
01219 
01220     snprintf(repltok, sizeof(repltok), "lc_monetary = '%s'",
01221              escape_quotes(lc_monetary));
01222     conflines = replace_token(conflines, "#lc_monetary = 'C'", repltok);
01223 
01224     snprintf(repltok, sizeof(repltok), "lc_numeric = '%s'",
01225              escape_quotes(lc_numeric));
01226     conflines = replace_token(conflines, "#lc_numeric = 'C'", repltok);
01227 
01228     snprintf(repltok, sizeof(repltok), "lc_time = '%s'",
01229              escape_quotes(lc_time));
01230     conflines = replace_token(conflines, "#lc_time = 'C'", repltok);
01231 
01232     switch (locale_date_order(lc_time))
01233     {
01234         case DATEORDER_YMD:
01235             strcpy(repltok, "datestyle = 'iso, ymd'");
01236             break;
01237         case DATEORDER_DMY:
01238             strcpy(repltok, "datestyle = 'iso, dmy'");
01239             break;
01240         case DATEORDER_MDY:
01241         default:
01242             strcpy(repltok, "datestyle = 'iso, mdy'");
01243             break;
01244     }
01245     conflines = replace_token(conflines, "#datestyle = 'iso, mdy'", repltok);
01246 
01247     snprintf(repltok, sizeof(repltok),
01248              "default_text_search_config = 'pg_catalog.%s'",
01249              escape_quotes(default_text_search_config));
01250     conflines = replace_token(conflines,
01251                          "#default_text_search_config = 'pg_catalog.simple'",
01252                               repltok);
01253 
01254     default_timezone = select_default_timezone(share_path);
01255     if (default_timezone)
01256     {
01257         snprintf(repltok, sizeof(repltok), "timezone = '%s'",
01258                  escape_quotes(default_timezone));
01259         conflines = replace_token(conflines, "#timezone = 'GMT'", repltok);
01260         snprintf(repltok, sizeof(repltok), "log_timezone = '%s'",
01261                  escape_quotes(default_timezone));
01262         conflines = replace_token(conflines, "#log_timezone = 'GMT'", repltok);
01263     }
01264 
01265     snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
01266 
01267     writefile(path, conflines);
01268     chmod(path, S_IRUSR | S_IWUSR);
01269 
01270     free(conflines);
01271 
01272 
01273     /* pg_hba.conf */
01274 
01275     conflines = readfile(hba_file);
01276 
01277 #ifndef HAVE_UNIX_SOCKETS
01278     conflines = filter_lines_with_token(conflines, "@[email protected]");
01279 #else
01280     conflines = replace_token(conflines, "@[email protected]", "");
01281 #endif
01282 
01283 #ifdef HAVE_IPV6
01284 
01285     /*
01286      * Probe to see if there is really any platform support for IPv6, and
01287      * comment out the relevant pg_hba line if not.  This avoids runtime
01288      * warnings if getaddrinfo doesn't actually cope with IPv6.  Particularly
01289      * useful on Windows, where executables built on a machine with IPv6 may
01290      * have to run on a machine without.
01291      */
01292     {
01293         struct addrinfo *gai_result;
01294         struct addrinfo hints;
01295         int         err = 0;
01296 
01297 #ifdef WIN32
01298         /* need to call WSAStartup before calling getaddrinfo */
01299         WSADATA     wsaData;
01300 
01301         err = WSAStartup(MAKEWORD(2, 2), &wsaData);
01302 #endif
01303 
01304         /* for best results, this code should match parse_hba() */
01305         hints.ai_flags = AI_NUMERICHOST;
01306         hints.ai_family = PF_UNSPEC;
01307         hints.ai_socktype = 0;
01308         hints.ai_protocol = 0;
01309         hints.ai_addrlen = 0;
01310         hints.ai_canonname = NULL;
01311         hints.ai_addr = NULL;
01312         hints.ai_next = NULL;
01313 
01314         if (err != 0 ||
01315             getaddrinfo("::1", NULL, &hints, &gai_result) != 0)
01316             conflines = replace_token(conflines,
01317                                "host    all             all             ::1",
01318                              "#host    all             all             ::1");
01319     }
01320 #else                           /* !HAVE_IPV6 */
01321     /* If we didn't compile IPV6 support at all, always comment it out */
01322     conflines = replace_token(conflines,
01323                               "host    all             all             ::1",
01324                               "#host    all             all             ::1");
01325 #endif   /* HAVE_IPV6 */
01326 
01327     /* Replace default authentication methods */
01328     conflines = replace_token(conflines,
01329                               "@[email protected]",
01330                               authmethodhost);
01331     conflines = replace_token(conflines,
01332                               "@[email protected]",
01333                               authmethodlocal);
01334 
01335     conflines = replace_token(conflines,
01336                               "@[email protected]",
01337                               (strcmp(authmethodlocal, "trust") == 0 || strcmp(authmethodhost, "trust") == 0) ? AUTHTRUST_WARNING : "");
01338 
01339     /* Replace username for replication */
01340     conflines = replace_token(conflines,
01341                               "@[email protected]",
01342                               username);
01343 
01344     snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data);
01345 
01346     writefile(path, conflines);
01347     chmod(path, S_IRUSR | S_IWUSR);
01348 
01349     free(conflines);
01350 
01351     /* pg_ident.conf */
01352 
01353     conflines = readfile(ident_file);
01354 
01355     snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data);
01356 
01357     writefile(path, conflines);
01358     chmod(path, S_IRUSR | S_IWUSR);
01359 
01360     free(conflines);
01361 
01362     check_ok();
01363 }
01364 
01365 
01366 /*
01367  * run the BKI script in bootstrap mode to create template1
01368  */
01369 static void
01370 bootstrap_template1(void)
01371 {
01372     PG_CMD_DECL;
01373     char      **line;
01374     char       *talkargs = "";
01375     char      **bki_lines;
01376     char        headerline[MAXPGPATH];
01377     char        buf[64];
01378 
01379     printf(_("creating template1 database in %s/base/1 ... "), pg_data);
01380     fflush(stdout);
01381 
01382     if (debug)
01383         talkargs = "-d 5";
01384 
01385     bki_lines = readfile(bki_file);
01386 
01387     /* Check that bki file appears to be of the right version */
01388 
01389     snprintf(headerline, sizeof(headerline), "# PostgreSQL %s\n",
01390              PG_MAJORVERSION);
01391 
01392     if (strcmp(headerline, *bki_lines) != 0)
01393     {
01394         fprintf(stderr,
01395                 _("%s: input file \"%s\" does not belong to PostgreSQL %s\n"
01396                   "Check your installation or specify the correct path "
01397                   "using the option -L.\n"),
01398                 progname, bki_file, PG_VERSION);
01399         exit_nicely();
01400     }
01401 
01402     /* Substitute for various symbols used in the BKI file */
01403 
01404     sprintf(buf, "%d", NAMEDATALEN);
01405     bki_lines = replace_token(bki_lines, "NAMEDATALEN", buf);
01406 
01407     sprintf(buf, "%d", (int) sizeof(Pointer));
01408     bki_lines = replace_token(bki_lines, "SIZEOF_POINTER", buf);
01409 
01410     bki_lines = replace_token(bki_lines, "ALIGNOF_POINTER",
01411                               (sizeof(Pointer) == 4) ? "i" : "d");
01412 
01413     bki_lines = replace_token(bki_lines, "FLOAT4PASSBYVAL",
01414                               FLOAT4PASSBYVAL ? "true" : "false");
01415 
01416     bki_lines = replace_token(bki_lines, "FLOAT8PASSBYVAL",
01417                               FLOAT8PASSBYVAL ? "true" : "false");
01418 
01419     bki_lines = replace_token(bki_lines, "POSTGRES", escape_quotes(username));
01420 
01421     bki_lines = replace_token(bki_lines, "ENCODING", encodingid);
01422 
01423     bki_lines = replace_token(bki_lines, "LC_COLLATE", escape_quotes(lc_collate));
01424 
01425     bki_lines = replace_token(bki_lines, "LC_CTYPE", escape_quotes(lc_ctype));
01426 
01427     /*
01428      * Pass correct LC_xxx environment to bootstrap.
01429      *
01430      * The shell script arranged to restore the LC settings afterwards, but
01431      * there doesn't seem to be any compelling reason to do that.
01432      */
01433     snprintf(cmd, sizeof(cmd), "LC_COLLATE=%s", lc_collate);
01434     putenv(pg_strdup(cmd));
01435 
01436     snprintf(cmd, sizeof(cmd), "LC_CTYPE=%s", lc_ctype);
01437     putenv(pg_strdup(cmd));
01438 
01439     unsetenv("LC_ALL");
01440 
01441     /* Also ensure backend isn't confused by this environment var: */
01442     unsetenv("PGCLIENTENCODING");
01443 
01444     snprintf(cmd, sizeof(cmd),
01445              "\"%s\" --boot -x1 %s %s %s",
01446              backend_exec,
01447              data_checksums ? "-k" : "",
01448              boot_options, talkargs);
01449 
01450     PG_CMD_OPEN;
01451 
01452     for (line = bki_lines; *line != NULL; line++)
01453     {
01454         PG_CMD_PUTS(*line);
01455         free(*line);
01456     }
01457 
01458     PG_CMD_CLOSE;
01459 
01460     free(bki_lines);
01461 
01462     check_ok();
01463 }
01464 
01465 /*
01466  * set up the shadow password table
01467  */
01468 static void
01469 setup_auth(void)
01470 {
01471     PG_CMD_DECL;
01472     const char **line;
01473     static const char *pg_authid_setup[] = {
01474         /*
01475          * The authid table shouldn't be readable except through views, to
01476          * ensure passwords are not publicly visible.
01477          */
01478         "REVOKE ALL on pg_authid FROM public;\n",
01479         NULL
01480     };
01481 
01482     fputs(_("initializing pg_authid ... "), stdout);
01483     fflush(stdout);
01484 
01485     snprintf(cmd, sizeof(cmd),
01486              "\"%s\" %s template1 >%s",
01487              backend_exec, backend_options,
01488              DEVNULL);
01489 
01490     PG_CMD_OPEN;
01491 
01492     for (line = pg_authid_setup; *line != NULL; line++)
01493         PG_CMD_PUTS(*line);
01494 
01495     PG_CMD_CLOSE;
01496 
01497     check_ok();
01498 }
01499 
01500 /*
01501  * get the superuser password if required, and call postgres to set it
01502  */
01503 static void
01504 get_set_pwd(void)
01505 {
01506     PG_CMD_DECL;
01507 
01508     char       *pwd1,
01509                *pwd2;
01510 
01511     if (pwprompt)
01512     {
01513         /*
01514          * Read password from terminal
01515          */
01516         pwd1 = simple_prompt("Enter new superuser password: ", 100, false);
01517         pwd2 = simple_prompt("Enter it again: ", 100, false);
01518         if (strcmp(pwd1, pwd2) != 0)
01519         {
01520             fprintf(stderr, _("Passwords didn't match.\n"));
01521             exit_nicely();
01522         }
01523         free(pwd2);
01524     }
01525     else
01526     {
01527         /*
01528          * Read password from file
01529          *
01530          * Ideally this should insist that the file not be world-readable.
01531          * However, this option is mainly intended for use on Windows where
01532          * file permissions may not exist at all, so we'll skip the paranoia
01533          * for now.
01534          */
01535         FILE       *pwf = fopen(pwfilename, "r");
01536         char        pwdbuf[MAXPGPATH];
01537         int         i;
01538 
01539         if (!pwf)
01540         {
01541             fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
01542                     progname, pwfilename, strerror(errno));
01543             exit_nicely();
01544         }
01545         if (!fgets(pwdbuf, sizeof(pwdbuf), pwf))
01546         {
01547             fprintf(stderr, _("%s: could not read password from file \"%s\": %s\n"),
01548                     progname, pwfilename, strerror(errno));
01549             exit_nicely();
01550         }
01551         fclose(pwf);
01552 
01553         i = strlen(pwdbuf);
01554         while (i > 0 && (pwdbuf[i - 1] == '\r' || pwdbuf[i - 1] == '\n'))
01555             pwdbuf[--i] = '\0';
01556 
01557         pwd1 = pg_strdup(pwdbuf);
01558 
01559     }
01560     printf(_("setting password ... "));
01561     fflush(stdout);
01562 
01563     snprintf(cmd, sizeof(cmd),
01564              "\"%s\" %s template1 >%s",
01565              backend_exec, backend_options,
01566              DEVNULL);
01567 
01568     PG_CMD_OPEN;
01569 
01570     PG_CMD_PRINTF2("ALTER USER \"%s\" WITH PASSWORD E'%s';\n",
01571                    username, escape_quotes(pwd1));
01572 
01573     /* MM: pwd1 is no longer needed, freeing it */
01574     free(pwd1);
01575 
01576     PG_CMD_CLOSE;
01577 
01578     check_ok();
01579 }
01580 
01581 /*
01582  * set up pg_depend
01583  */
01584 static void
01585 setup_depend(void)
01586 {
01587     PG_CMD_DECL;
01588     const char **line;
01589     static const char *pg_depend_setup[] = {
01590         /*
01591          * Make PIN entries in pg_depend for all objects made so far in the
01592          * tables that the dependency code handles.  This is overkill (the
01593          * system doesn't really depend on having every last weird datatype,
01594          * for instance) but generating only the minimum required set of
01595          * dependencies seems hard.
01596          *
01597          * Note that we deliberately do not pin the system views, which
01598          * haven't been created yet.  Also, no conversions, databases, or
01599          * tablespaces are pinned.
01600          *
01601          * First delete any already-made entries; PINs override all else, and
01602          * must be the only entries for their objects.
01603          */
01604         "DELETE FROM pg_depend;\n",
01605         "VACUUM pg_depend;\n",
01606         "DELETE FROM pg_shdepend;\n",
01607         "VACUUM pg_shdepend;\n",
01608 
01609         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01610         " FROM pg_class;\n",
01611         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01612         " FROM pg_proc;\n",
01613         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01614         " FROM pg_type;\n",
01615         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01616         " FROM pg_cast;\n",
01617         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01618         " FROM pg_constraint;\n",
01619         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01620         " FROM pg_attrdef;\n",
01621         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01622         " FROM pg_language;\n",
01623         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01624         " FROM pg_operator;\n",
01625         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01626         " FROM pg_opclass;\n",
01627         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01628         " FROM pg_opfamily;\n",
01629         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01630         " FROM pg_amop;\n",
01631         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01632         " FROM pg_amproc;\n",
01633         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01634         " FROM pg_rewrite;\n",
01635         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01636         " FROM pg_trigger;\n",
01637 
01638         /*
01639          * restriction here to avoid pinning the public namespace
01640          */
01641         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01642         " FROM pg_namespace "
01643         "    WHERE nspname LIKE 'pg%';\n",
01644 
01645         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01646         " FROM pg_ts_parser;\n",
01647         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01648         " FROM pg_ts_dict;\n",
01649         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01650         " FROM pg_ts_template;\n",
01651         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01652         " FROM pg_ts_config;\n",
01653         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
01654         " FROM pg_collation;\n",
01655         "INSERT INTO pg_shdepend SELECT 0,0,0,0, tableoid,oid, 'p' "
01656         " FROM pg_authid;\n",
01657         NULL
01658     };
01659 
01660     fputs(_("initializing dependencies ... "), stdout);
01661     fflush(stdout);
01662 
01663     snprintf(cmd, sizeof(cmd),
01664              "\"%s\" %s template1 >%s",
01665              backend_exec, backend_options,
01666              DEVNULL);
01667 
01668     PG_CMD_OPEN;
01669 
01670     for (line = pg_depend_setup; *line != NULL; line++)
01671         PG_CMD_PUTS(*line);
01672 
01673     PG_CMD_CLOSE;
01674 
01675     check_ok();
01676 }
01677 
01678 /*
01679  * set up system views
01680  */
01681 static void
01682 setup_sysviews(void)
01683 {
01684     PG_CMD_DECL;
01685     char      **line;
01686     char      **sysviews_setup;
01687 
01688     fputs(_("creating system views ... "), stdout);
01689     fflush(stdout);
01690 
01691     sysviews_setup = readfile(system_views_file);
01692 
01693     /*
01694      * We use -j here to avoid backslashing stuff in system_views.sql
01695      */
01696     snprintf(cmd, sizeof(cmd),
01697              "\"%s\" %s -j template1 >%s",
01698              backend_exec, backend_options,
01699              DEVNULL);
01700 
01701     PG_CMD_OPEN;
01702 
01703     for (line = sysviews_setup; *line != NULL; line++)
01704     {
01705         PG_CMD_PUTS(*line);
01706         free(*line);
01707     }
01708 
01709     PG_CMD_CLOSE;
01710 
01711     free(sysviews_setup);
01712 
01713     check_ok();
01714 }
01715 
01716 /*
01717  * load description data
01718  */
01719 static void
01720 setup_description(void)
01721 {
01722     PG_CMD_DECL;
01723 
01724     fputs(_("loading system objects' descriptions ... "), stdout);
01725     fflush(stdout);
01726 
01727     snprintf(cmd, sizeof(cmd),
01728              "\"%s\" %s template1 >%s",
01729              backend_exec, backend_options,
01730              DEVNULL);
01731 
01732     PG_CMD_OPEN;
01733 
01734     PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_description ( "
01735                 "   objoid oid, "
01736                 "   classname name, "
01737                 "   objsubid int4, "
01738                 "   description text) WITHOUT OIDS;\n");
01739 
01740     PG_CMD_PRINTF1("COPY tmp_pg_description FROM E'%s';\n",
01741                    escape_quotes(desc_file));
01742 
01743     PG_CMD_PUTS("INSERT INTO pg_description "
01744                 " SELECT t.objoid, c.oid, t.objsubid, t.description "
01745                 "  FROM tmp_pg_description t, pg_class c "
01746                 "    WHERE c.relname = t.classname;\n");
01747 
01748     PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_shdescription ( "
01749                 " objoid oid, "
01750                 " classname name, "
01751                 " description text) WITHOUT OIDS;\n");
01752 
01753     PG_CMD_PRINTF1("COPY tmp_pg_shdescription FROM E'%s';\n",
01754                    escape_quotes(shdesc_file));
01755 
01756     PG_CMD_PUTS("INSERT INTO pg_shdescription "
01757                 " SELECT t.objoid, c.oid, t.description "
01758                 "  FROM tmp_pg_shdescription t, pg_class c "
01759                 "   WHERE c.relname = t.classname;\n");
01760 
01761     /* Create default descriptions for operator implementation functions */
01762     PG_CMD_PUTS("WITH funcdescs AS ( "
01763                 "SELECT p.oid as p_oid, oprname, "
01764               "coalesce(obj_description(o.oid, 'pg_operator'),'') as opdesc "
01765                 "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) "
01766                 "INSERT INTO pg_description "
01767                 "  SELECT p_oid, 'pg_proc'::regclass, 0, "
01768                 "    'implementation of ' || oprname || ' operator' "
01769                 "  FROM funcdescs "
01770                 "  WHERE opdesc NOT LIKE 'deprecated%' AND "
01771                 "  NOT EXISTS (SELECT 1 FROM pg_description "
01772           "    WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass);\n");
01773 
01774     PG_CMD_CLOSE;
01775 
01776     check_ok();
01777 }
01778 
01779 #ifdef HAVE_LOCALE_T
01780 /*
01781  * "Normalize" a locale name, stripping off encoding tags such as
01782  * ".utf8" (e.g., "en_US.utf8" -> "en_US", but "[email protected]"
01783  * -> "[email protected]").  Return true if a new, different name was
01784  * generated.
01785  */
01786 static bool
01787 normalize_locale_name(char *new, const char *old)
01788 {
01789     char       *n = new;
01790     const char *o = old;
01791     bool        changed = false;
01792 
01793     while (*o)
01794     {
01795         if (*o == '.')
01796         {
01797             /* skip over encoding tag such as ".utf8" or ".UTF-8" */
01798             o++;
01799             while ((*o >= 'A' && *o <= 'Z')
01800                    || (*o >= 'a' && *o <= 'z')
01801                    || (*o >= '0' && *o <= '9')
01802                    || (*o == '-'))
01803                 o++;
01804             changed = true;
01805         }
01806         else
01807             *n++ = *o++;
01808     }
01809     *n = '\0';
01810 
01811     return changed;
01812 }
01813 #endif   /* HAVE_LOCALE_T */
01814 
01815 /*
01816  * populate pg_collation
01817  */
01818 static void
01819 setup_collation(void)
01820 {
01821 #if defined(HAVE_LOCALE_T) && !defined(WIN32)
01822     int         i;
01823     FILE       *locale_a_handle;
01824     char        localebuf[NAMEDATALEN]; /* we assume ASCII so this is fine */
01825     int         count = 0;
01826 
01827     PG_CMD_DECL;
01828 #endif
01829 
01830     fputs(_("creating collations ... "), stdout);
01831     fflush(stdout);
01832 
01833 #if defined(HAVE_LOCALE_T) && !defined(WIN32)
01834     snprintf(cmd, sizeof(cmd),
01835              "\"%s\" %s template1 >%s",
01836              backend_exec, backend_options,
01837              DEVNULL);
01838 
01839     locale_a_handle = popen_check("locale -a", "r");
01840     if (!locale_a_handle)
01841         return;                 /* complaint already printed */
01842 
01843     PG_CMD_OPEN;
01844 
01845     PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_collation ( "
01846                 "   collname name, "
01847                 "   locale name, "
01848                 "   encoding int) WITHOUT OIDS;\n");
01849 
01850     while (fgets(localebuf, sizeof(localebuf), locale_a_handle))
01851     {
01852         size_t      len;
01853         int         enc;
01854         bool        skip;
01855         char       *quoted_locale;
01856         char        alias[NAMEDATALEN];
01857 
01858         len = strlen(localebuf);
01859 
01860         if (len == 0 || localebuf[len - 1] != '\n')
01861         {
01862             if (debug)
01863                 fprintf(stderr, _("%s: locale name too long, skipped: \"%s\"\n"),
01864                         progname, localebuf);
01865             continue;
01866         }
01867         localebuf[len - 1] = '\0';
01868 
01869         /*
01870          * Some systems have locale names that don't consist entirely of ASCII
01871          * letters (such as "bokm&aring;l" or "fran&ccedil;ais").  This is
01872          * pretty silly, since we need the locale itself to interpret the
01873          * non-ASCII characters. We can't do much with those, so we filter
01874          * them out.
01875          */
01876         skip = false;
01877         for (i = 0; i < len; i++)
01878         {
01879             if (IS_HIGHBIT_SET(localebuf[i]))
01880             {
01881                 skip = true;
01882                 break;
01883             }
01884         }
01885         if (skip)
01886         {
01887             if (debug)
01888                 fprintf(stderr, _("%s: locale name has non-ASCII characters, skipped: \"%s\"\n"),
01889                         progname, localebuf);
01890             continue;
01891         }
01892 
01893         enc = pg_get_encoding_from_locale(localebuf, debug);
01894         if (enc < 0)
01895         {
01896             /* error message printed by pg_get_encoding_from_locale() */
01897             continue;
01898         }
01899         if (!PG_VALID_BE_ENCODING(enc))
01900             continue;           /* ignore locales for client-only encodings */
01901         if (enc == PG_SQL_ASCII)
01902             continue;           /* C/POSIX are already in the catalog */
01903 
01904         count++;
01905 
01906         quoted_locale = escape_quotes(localebuf);
01907 
01908         PG_CMD_PRINTF3("INSERT INTO tmp_pg_collation VALUES (E'%s', E'%s', %d);\n",
01909                        quoted_locale, quoted_locale, enc);
01910 
01911         /*
01912          * Generate aliases such as "en_US" in addition to "en_US.utf8" for
01913          * ease of use.  Note that collation names are unique per encoding
01914          * only, so this doesn't clash with "en_US" for LATIN1, say.
01915          */
01916         if (normalize_locale_name(alias, localebuf))
01917             PG_CMD_PRINTF3("INSERT INTO tmp_pg_collation VALUES (E'%s', E'%s', %d);\n",
01918                            escape_quotes(alias), quoted_locale, enc);
01919     }
01920 
01921     /* Add an SQL-standard name */
01922     PG_CMD_PRINTF1("INSERT INTO tmp_pg_collation VALUES ('ucs_basic', 'C', %d);\n", PG_UTF8);
01923 
01924     /*
01925      * When copying collations to the final location, eliminate aliases that
01926      * conflict with an existing locale name for the same encoding.  For
01927      * example, "br_FR.iso88591" is normalized to "br_FR", both for encoding
01928      * LATIN1.  But the unnormalized locale "br_FR" already exists for LATIN1.
01929      * Prefer the alias that matches the OS locale name, else the first locale
01930      * name by sort order (arbitrary choice to be deterministic).
01931      *
01932      * Also, eliminate any aliases that conflict with pg_collation's
01933      * hard-wired entries for "C" etc.
01934      */
01935     PG_CMD_PUTS("INSERT INTO pg_collation (collname, collnamespace, collowner, collencoding, collcollate, collctype) "
01936                 " SELECT DISTINCT ON (collname, encoding)"
01937                 "   collname, "
01938                 "   (SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog') AS collnamespace, "
01939                 "   (SELECT relowner FROM pg_class WHERE relname = 'pg_collation') AS collowner, "
01940                 "   encoding, locale, locale "
01941                 "  FROM tmp_pg_collation"
01942                 "  WHERE NOT EXISTS (SELECT 1 FROM pg_collation WHERE collname = tmp_pg_collation.collname)"
01943        "  ORDER BY collname, encoding, (collname = locale) DESC, locale;\n");
01944 
01945     pclose(locale_a_handle);
01946     PG_CMD_CLOSE;
01947 
01948     check_ok();
01949     if (count == 0 && !debug)
01950     {
01951         printf(_("No usable system locales were found.\n"));
01952         printf(_("Use the option \"--debug\" to see details.\n"));
01953     }
01954 #else                           /* not HAVE_LOCALE_T && not WIN32 */
01955     printf(_("not supported on this platform\n"));
01956     fflush(stdout);
01957 #endif   /* not HAVE_LOCALE_T  && not WIN32 */
01958 }
01959 
01960 /*
01961  * load conversion functions
01962  */
01963 static void
01964 setup_conversion(void)
01965 {
01966     PG_CMD_DECL;
01967     char      **line;
01968     char      **conv_lines;
01969 
01970     fputs(_("creating conversions ... "), stdout);
01971     fflush(stdout);
01972 
01973     snprintf(cmd, sizeof(cmd),
01974              "\"%s\" %s template1 >%s",
01975              backend_exec, backend_options,
01976              DEVNULL);
01977 
01978     PG_CMD_OPEN;
01979 
01980     conv_lines = readfile(conversion_file);
01981     for (line = conv_lines; *line != NULL; line++)
01982     {
01983         if (strstr(*line, "DROP CONVERSION") != *line)
01984             PG_CMD_PUTS(*line);
01985         free(*line);
01986     }
01987 
01988     free(conv_lines);
01989 
01990     PG_CMD_CLOSE;
01991 
01992     check_ok();
01993 }
01994 
01995 /*
01996  * load extra dictionaries (Snowball stemmers)
01997  */
01998 static void
01999 setup_dictionary(void)
02000 {
02001     PG_CMD_DECL;
02002     char      **line;
02003     char      **conv_lines;
02004 
02005     fputs(_("creating dictionaries ... "), stdout);
02006     fflush(stdout);
02007 
02008     /*
02009      * We use -j here to avoid backslashing stuff
02010      */
02011     snprintf(cmd, sizeof(cmd),
02012              "\"%s\" %s -j template1 >%s",
02013              backend_exec, backend_options,
02014              DEVNULL);
02015 
02016     PG_CMD_OPEN;
02017 
02018     conv_lines = readfile(dictionary_file);
02019     for (line = conv_lines; *line != NULL; line++)
02020     {
02021         PG_CMD_PUTS(*line);
02022         free(*line);
02023     }
02024 
02025     free(conv_lines);
02026 
02027     PG_CMD_CLOSE;
02028 
02029     check_ok();
02030 }
02031 
02032 /*
02033  * Set up privileges
02034  *
02035  * We mark most system catalogs as world-readable.  We don't currently have
02036  * to touch functions, languages, or databases, because their default
02037  * permissions are OK.
02038  *
02039  * Some objects may require different permissions by default, so we
02040  * make sure we don't overwrite privilege sets that have already been
02041  * set (NOT NULL).
02042  */
02043 static void
02044 setup_privileges(void)
02045 {
02046     PG_CMD_DECL;
02047     char      **line;
02048     char      **priv_lines;
02049     static char *privileges_setup[] = {
02050         "UPDATE pg_class "
02051         "  SET relacl = E'{\"=r/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
02052         "  WHERE relkind IN ('r', 'v', 'm', 'S') AND relacl IS NULL;\n",
02053         "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n",
02054         "GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n",
02055         "REVOKE ALL ON pg_largeobject FROM PUBLIC;\n",
02056         NULL
02057     };
02058 
02059     fputs(_("setting privileges on built-in objects ... "), stdout);
02060     fflush(stdout);
02061 
02062     snprintf(cmd, sizeof(cmd),
02063              "\"%s\" %s template1 >%s",
02064              backend_exec, backend_options,
02065              DEVNULL);
02066 
02067     PG_CMD_OPEN;
02068 
02069     priv_lines = replace_token(privileges_setup, "$POSTGRES_SUPERUSERNAME",
02070                                escape_quotes(username));
02071     for (line = priv_lines; *line != NULL; line++)
02072         PG_CMD_PUTS(*line);
02073 
02074     PG_CMD_CLOSE;
02075 
02076     check_ok();
02077 }
02078 
02079 /*
02080  * extract the strange version of version required for information schema
02081  * (09.08.0007abc)
02082  */
02083 static void
02084 set_info_version(void)
02085 {
02086     char       *letterversion;
02087     long        major = 0,
02088                 minor = 0,
02089                 micro = 0;
02090     char       *endptr;
02091     char       *vstr = pg_strdup(PG_VERSION);
02092     char       *ptr;
02093 
02094     ptr = vstr + (strlen(vstr) - 1);
02095     while (ptr != vstr && (*ptr < '0' || *ptr > '9'))
02096         ptr--;
02097     letterversion = ptr + 1;
02098     major = strtol(vstr, &endptr, 10);
02099     if (*endptr)
02100         minor = strtol(endptr + 1, &endptr, 10);
02101     if (*endptr)
02102         micro = strtol(endptr + 1, &endptr, 10);
02103     snprintf(infoversion, sizeof(infoversion), "%02ld.%02ld.%04ld%s",
02104              major, minor, micro, letterversion);
02105 }
02106 
02107 /*
02108  * load info schema and populate from features file
02109  */
02110 static void
02111 setup_schema(void)
02112 {
02113     PG_CMD_DECL;
02114     char      **line;
02115     char      **lines;
02116 
02117     fputs(_("creating information schema ... "), stdout);
02118     fflush(stdout);
02119 
02120     lines = readfile(info_schema_file);
02121 
02122     /*
02123      * We use -j here to avoid backslashing stuff in information_schema.sql
02124      */
02125     snprintf(cmd, sizeof(cmd),
02126              "\"%s\" %s -j template1 >%s",
02127              backend_exec, backend_options,
02128              DEVNULL);
02129 
02130     PG_CMD_OPEN;
02131 
02132     for (line = lines; *line != NULL; line++)
02133     {
02134         PG_CMD_PUTS(*line);
02135         free(*line);
02136     }
02137 
02138     free(lines);
02139 
02140     PG_CMD_CLOSE;
02141 
02142     snprintf(cmd, sizeof(cmd),
02143              "\"%s\" %s template1 >%s",
02144              backend_exec, backend_options,
02145              DEVNULL);
02146 
02147     PG_CMD_OPEN;
02148 
02149     PG_CMD_PRINTF1("UPDATE information_schema.sql_implementation_info "
02150                    "  SET character_value = '%s' "
02151                    "  WHERE implementation_info_name = 'DBMS VERSION';\n",
02152                    infoversion);
02153 
02154     PG_CMD_PRINTF1("COPY information_schema.sql_features "
02155                    "  (feature_id, feature_name, sub_feature_id, "
02156                    "  sub_feature_name, is_supported, comments) "
02157                    " FROM E'%s';\n",
02158                    escape_quotes(features_file));
02159 
02160     PG_CMD_CLOSE;
02161 
02162     check_ok();
02163 }
02164 
02165 /*
02166  * load PL/pgsql server-side language
02167  */
02168 static void
02169 load_plpgsql(void)
02170 {
02171     PG_CMD_DECL;
02172 
02173     fputs(_("loading PL/pgSQL server-side language ... "), stdout);
02174     fflush(stdout);
02175 
02176     snprintf(cmd, sizeof(cmd),
02177              "\"%s\" %s template1 >%s",
02178              backend_exec, backend_options,
02179              DEVNULL);
02180 
02181     PG_CMD_OPEN;
02182 
02183     PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n");
02184 
02185     PG_CMD_CLOSE;
02186 
02187     check_ok();
02188 }
02189 
02190 /*
02191  * clean everything up in template1
02192  */
02193 static void
02194 vacuum_db(void)
02195 {
02196     PG_CMD_DECL;
02197 
02198     fputs(_("vacuuming database template1 ... "), stdout);
02199     fflush(stdout);
02200 
02201     snprintf(cmd, sizeof(cmd),
02202              "\"%s\" %s template1 >%s",
02203              backend_exec, backend_options,
02204              DEVNULL);
02205 
02206     PG_CMD_OPEN;
02207 
02208     PG_CMD_PUTS("ANALYZE;\nVACUUM FULL;\nVACUUM FREEZE;\n");
02209 
02210     PG_CMD_CLOSE;
02211 
02212     check_ok();
02213 }
02214 
02215 /*
02216  * copy template1 to template0
02217  */
02218 static void
02219 make_template0(void)
02220 {
02221     PG_CMD_DECL;
02222     const char **line;
02223     static const char *template0_setup[] = {
02224         "CREATE DATABASE template0;\n",
02225         "UPDATE pg_database SET "
02226         "   datistemplate = 't', "
02227         "   datallowconn = 'f' "
02228         "    WHERE datname = 'template0';\n",
02229 
02230         /*
02231          * We use the OID of template0 to determine lastsysoid
02232          */
02233         "UPDATE pg_database SET datlastsysoid = "
02234         "    (SELECT oid FROM pg_database "
02235         "    WHERE datname = 'template0');\n",
02236 
02237         /*
02238          * Explicitly revoke public create-schema and create-temp-table
02239          * privileges in template1 and template0; else the latter would be on
02240          * by default
02241          */
02242         "REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n",
02243         "REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n",
02244 
02245         "COMMENT ON DATABASE template0 IS 'unmodifiable empty database';\n",
02246 
02247         /*
02248          * Finally vacuum to clean up dead rows in pg_database
02249          */
02250         "VACUUM FULL pg_database;\n",
02251         NULL
02252     };
02253 
02254     fputs(_("copying template1 to template0 ... "), stdout);
02255     fflush(stdout);
02256 
02257     snprintf(cmd, sizeof(cmd),
02258              "\"%s\" %s template1 >%s",
02259              backend_exec, backend_options,
02260              DEVNULL);
02261 
02262     PG_CMD_OPEN;
02263 
02264     for (line = template0_setup; *line; line++)
02265         PG_CMD_PUTS(*line);
02266 
02267     PG_CMD_CLOSE;
02268 
02269     check_ok();
02270 }
02271 
02272 /*
02273  * copy template1 to postgres
02274  */
02275 static void
02276 make_postgres(void)
02277 {
02278     PG_CMD_DECL;
02279     const char **line;
02280     static const char *postgres_setup[] = {
02281         "CREATE DATABASE postgres;\n",
02282         "COMMENT ON DATABASE postgres IS 'default administrative connection database';\n",
02283         NULL
02284     };
02285 
02286     fputs(_("copying template1 to postgres ... "), stdout);
02287     fflush(stdout);
02288 
02289     snprintf(cmd, sizeof(cmd),
02290              "\"%s\" %s template1 >%s",
02291              backend_exec, backend_options,
02292              DEVNULL);
02293 
02294     PG_CMD_OPEN;
02295 
02296     for (line = postgres_setup; *line; line++)
02297         PG_CMD_PUTS(*line);
02298 
02299     PG_CMD_CLOSE;
02300 
02301     check_ok();
02302 }
02303 
02304 /*
02305  * fsync everything down to disk
02306  */
02307 static void
02308 perform_fsync(void)
02309 {
02310     char        pdir[MAXPGPATH];
02311 
02312     fputs(_("syncing data to disk ... "), stdout);
02313     fflush(stdout);
02314 
02315     /*
02316      * We need to name the parent of PGDATA.  get_parent_directory() isn't
02317      * enough here, because it can result in an empty string.
02318      */
02319     snprintf(pdir, MAXPGPATH, "%s/..", pg_data);
02320     canonicalize_path(pdir);
02321 
02322     /*
02323      * Hint to the OS so that we're going to fsync each of these files soon.
02324      */
02325 
02326     /* first the parent of the PGDATA directory */
02327     pre_sync_fname(pdir, true);
02328 
02329     /* then recursively through the directory */
02330     walkdir(pg_data, pre_sync_fname);
02331 
02332     /*
02333      * Now, do the fsync()s in the same order.
02334      */
02335 
02336     /* first the parent of the PGDATA directory */
02337     fsync_fname(pdir, true);
02338 
02339     /* then recursively through the directory */
02340     walkdir(pg_data, fsync_fname);
02341 
02342     check_ok();
02343 }
02344 
02345 
02346 /*
02347  * signal handler in case we are interrupted.
02348  *
02349  * The Windows runtime docs at
02350  * http://msdn.microsoft.com/library/en-us/vclib/html/_crt_signal.asp
02351  * specifically forbid a number of things being done from a signal handler,
02352  * including IO, memory allocation and system calls, and only allow jmpbuf
02353  * if you are handling SIGFPE.
02354  *
02355  * I avoided doing the forbidden things by setting a flag instead of calling
02356  * exit_nicely() directly.
02357  *
02358  * Also note the behaviour of Windows with SIGINT, which says this:
02359  *   Note   SIGINT is not supported for any Win32 application, including
02360  *   Windows 98/Me and Windows NT/2000/XP. When a CTRL+C interrupt occurs,
02361  *   Win32 operating systems generate a new thread to specifically handle
02362  *   that interrupt. This can cause a single-thread application such as UNIX,
02363  *   to become multithreaded, resulting in unexpected behavior.
02364  *
02365  * I have no idea how to handle this. (Strange they call UNIX an application!)
02366  * So this will need some testing on Windows.
02367  */
02368 static void
02369 trapsig(int signum)
02370 {
02371     /* handle systems that reset the handler, like Windows (grr) */
02372     pqsignal(signum, trapsig);
02373     caught_signal = true;
02374 }
02375 
02376 /*
02377  * call exit_nicely() if we got a signal, or else output "ok".
02378  */
02379 static void
02380 check_ok(void)
02381 {
02382     if (caught_signal)
02383     {
02384         printf(_("caught signal\n"));
02385         fflush(stdout);
02386         exit_nicely();
02387     }
02388     else if (output_failed)
02389     {
02390         printf(_("could not write to child process: %s\n"),
02391                strerror(output_errno));
02392         fflush(stdout);
02393         exit_nicely();
02394     }
02395     else
02396     {
02397         /* all seems well */
02398         printf(_("ok\n"));
02399         fflush(stdout);
02400     }
02401 }
02402 
02403 /* Hack to suppress a warning about %x from some versions of gcc */
02404 static inline size_t
02405 my_strftime(char *s, size_t max, const char *fmt, const struct tm * tm)
02406 {
02407     return strftime(s, max, fmt, tm);
02408 }
02409 
02410 /*
02411  * Determine likely date order from locale
02412  */
02413 static int
02414 locale_date_order(const char *locale)
02415 {
02416     struct tm   testtime;
02417     char        buf[128];
02418     char       *posD;
02419     char       *posM;
02420     char       *posY;
02421     char       *save;
02422     size_t      res;
02423     int         result;
02424 
02425     result = DATEORDER_MDY;     /* default */
02426 
02427     save = setlocale(LC_TIME, NULL);
02428     if (!save)
02429         return result;
02430     save = pg_strdup(save);
02431 
02432     setlocale(LC_TIME, locale);
02433 
02434     memset(&testtime, 0, sizeof(testtime));
02435     testtime.tm_mday = 22;
02436     testtime.tm_mon = 10;       /* November, should come out as "11" */
02437     testtime.tm_year = 133;     /* 2033 */
02438 
02439     res = my_strftime(buf, sizeof(buf), "%x", &testtime);
02440 
02441     setlocale(LC_TIME, save);
02442     free(save);
02443 
02444     if (res == 0)
02445         return result;
02446 
02447     posM = strstr(buf, "11");
02448     posD = strstr(buf, "22");
02449     posY = strstr(buf, "33");
02450 
02451     if (!posM || !posD || !posY)
02452         return result;
02453 
02454     if (posY < posM && posM < posD)
02455         result = DATEORDER_YMD;
02456     else if (posD < posM)
02457         result = DATEORDER_DMY;
02458     else
02459         result = DATEORDER_MDY;
02460 
02461     return result;
02462 }
02463 
02464 /*
02465  * Is the locale name valid for the locale category?
02466  *
02467  * If successful, and canonname isn't NULL, a malloc'd copy of the locale's
02468  * canonical name is stored there.  This is especially useful for figuring out
02469  * what locale name "" means (ie, the environment value).  (Actually,
02470  * it seems that on most implementations that's the only thing it's good for;
02471  * we could wish that setlocale gave back a canonically spelled version of
02472  * the locale name, but typically it doesn't.)
02473  *
02474  * this should match the backend's check_locale() function
02475  */
02476 static bool
02477 check_locale_name(int category, const char *locale, char **canonname)
02478 {
02479     char       *save;
02480     char       *res;
02481 
02482     if (canonname)
02483         *canonname = NULL;      /* in case of failure */
02484 
02485     save = setlocale(category, NULL);
02486     if (!save)
02487         return false;           /* won't happen, we hope */
02488 
02489     /* save may be pointing at a modifiable scratch variable, so copy it. */
02490     save = pg_strdup(save);
02491 
02492     /* set the locale with setlocale, to see if it accepts it. */
02493     res = setlocale(category, locale);
02494 
02495     /* save canonical name if requested. */
02496     if (res && canonname)
02497         *canonname = pg_strdup(res);
02498 
02499     /* restore old value. */
02500     if (!setlocale(category, save))
02501         fprintf(stderr, _("%s: failed to restore old locale \"%s\"\n"),
02502                 progname, save);
02503     free(save);
02504 
02505     /* should we exit here? */
02506     if (res == NULL)
02507         fprintf(stderr, _("%s: invalid locale name \"%s\"\n"),
02508                 progname, locale);
02509 
02510     return (res != NULL);
02511 }
02512 
02513 /*
02514  * check if the chosen encoding matches the encoding required by the locale
02515  *
02516  * this should match the similar check in the backend createdb() function
02517  */
02518 static bool
02519 check_locale_encoding(const char *locale, int user_enc)
02520 {
02521     int         locale_enc;
02522 
02523     locale_enc = pg_get_encoding_from_locale(locale, true);
02524 
02525     /* See notes in createdb() to understand these tests */
02526     if (!(locale_enc == user_enc ||
02527           locale_enc == PG_SQL_ASCII ||
02528           locale_enc == -1 ||
02529 #ifdef WIN32
02530           user_enc == PG_UTF8 ||
02531 #endif
02532           user_enc == PG_SQL_ASCII))
02533     {
02534         fprintf(stderr, _("%s: encoding mismatch\n"), progname);
02535         fprintf(stderr,
02536                 _("The encoding you selected (%s) and the encoding that the\n"
02537               "selected locale uses (%s) do not match.  This would lead to\n"
02538             "misbehavior in various character string processing functions.\n"
02539                "Rerun %s and either do not specify an encoding explicitly,\n"
02540                   "or choose a matching combination.\n"),
02541                 pg_encoding_to_char(user_enc),
02542                 pg_encoding_to_char(locale_enc),
02543                 progname);
02544         return false;
02545     }
02546     return true;
02547 }
02548 
02549 /*
02550  * set up the locale variables
02551  *
02552  * assumes we have called setlocale(LC_ALL, "") -- see set_pglocale_pgservice
02553  */
02554 static void
02555 setlocales(void)
02556 {
02557     char       *canonname;
02558 
02559     /* set empty lc_* values to locale config if set */
02560 
02561     if (strlen(locale) > 0)
02562     {
02563         if (strlen(lc_ctype) == 0)
02564             lc_ctype = locale;
02565         if (strlen(lc_collate) == 0)
02566             lc_collate = locale;
02567         if (strlen(lc_numeric) == 0)
02568             lc_numeric = locale;
02569         if (strlen(lc_time) == 0)
02570             lc_time = locale;
02571         if (strlen(lc_monetary) == 0)
02572             lc_monetary = locale;
02573         if (strlen(lc_messages) == 0)
02574             lc_messages = locale;
02575     }
02576 
02577     /*
02578      * canonicalize locale names, and override any missing/invalid values from
02579      * our current environment
02580      */
02581 
02582     if (check_locale_name(LC_CTYPE, lc_ctype, &canonname))
02583         lc_ctype = canonname;
02584     else
02585         lc_ctype = pg_strdup(setlocale(LC_CTYPE, NULL));
02586     if (check_locale_name(LC_COLLATE, lc_collate, &canonname))
02587         lc_collate = canonname;
02588     else
02589         lc_collate = pg_strdup(setlocale(LC_COLLATE, NULL));
02590     if (check_locale_name(LC_NUMERIC, lc_numeric, &canonname))
02591         lc_numeric = canonname;
02592     else
02593         lc_numeric = pg_strdup(setlocale(LC_NUMERIC, NULL));
02594     if (check_locale_name(LC_TIME, lc_time, &canonname))
02595         lc_time = canonname;
02596     else
02597         lc_time = pg_strdup(setlocale(LC_TIME, NULL));
02598     if (check_locale_name(LC_MONETARY, lc_monetary, &canonname))
02599         lc_monetary = canonname;
02600     else
02601         lc_monetary = pg_strdup(setlocale(LC_MONETARY, NULL));
02602 #if defined(LC_MESSAGES) && !defined(WIN32)
02603     if (check_locale_name(LC_MESSAGES, lc_messages, &canonname))
02604         lc_messages = canonname;
02605     else
02606         lc_messages = pg_strdup(setlocale(LC_MESSAGES, NULL));
02607 #else
02608     /* when LC_MESSAGES is not available, use the LC_CTYPE setting */
02609     if (check_locale_name(LC_CTYPE, lc_messages, &canonname))
02610         lc_messages = canonname;
02611     else
02612         lc_messages = pg_strdup(setlocale(LC_CTYPE, NULL));
02613 #endif
02614 }
02615 
02616 #ifdef WIN32
02617 typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
02618 
02619 /* Windows API define missing from some versions of MingW headers */
02620 #ifndef  DISABLE_MAX_PRIVILEGE
02621 #define DISABLE_MAX_PRIVILEGE   0x1
02622 #endif
02623 
02624 /*
02625  * Create a restricted token and execute the specified process with it.
02626  *
02627  * Returns 0 on failure, non-zero on success, same as CreateProcess().
02628  *
02629  * On NT4, or any other system not containing the required functions, will
02630  * NOT execute anything.
02631  */
02632 static int
02633 CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo)
02634 {
02635     BOOL        b;
02636     STARTUPINFO si;
02637     HANDLE      origToken;
02638     HANDLE      restrictedToken;
02639     SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
02640     SID_AND_ATTRIBUTES dropSids[2];
02641     __CreateRestrictedToken _CreateRestrictedToken = NULL;
02642     HANDLE      Advapi32Handle;
02643 
02644     ZeroMemory(&si, sizeof(si));
02645     si.cb = sizeof(si);
02646 
02647     Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
02648     if (Advapi32Handle != NULL)
02649     {
02650         _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
02651     }
02652 
02653     if (_CreateRestrictedToken == NULL)
02654     {
02655         fprintf(stderr, _("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
02656         if (Advapi32Handle != NULL)
02657             FreeLibrary(Advapi32Handle);
02658         return 0;
02659     }
02660 
02661     /* Open the current token to use as a base for the restricted one */
02662     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
02663     {
02664         fprintf(stderr, _("%s: could not open process token: error code %lu\n"), progname, GetLastError());
02665         return 0;
02666     }
02667 
02668     /* Allocate list of SIDs to remove */
02669     ZeroMemory(&dropSids, sizeof(dropSids));
02670     if (!AllocateAndInitializeSid(&NtAuthority, 2,
02671          SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
02672                                   0, &dropSids[0].Sid) ||
02673         !AllocateAndInitializeSid(&NtAuthority, 2,
02674     SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
02675                                   0, &dropSids[1].Sid))
02676     {
02677         fprintf(stderr, _("%s: could not to allocate SIDs: error code %lu\n"), progname, GetLastError());
02678         return 0;
02679     }
02680 
02681     b = _CreateRestrictedToken(origToken,
02682                                DISABLE_MAX_PRIVILEGE,
02683                                sizeof(dropSids) / sizeof(dropSids[0]),
02684                                dropSids,
02685                                0, NULL,
02686                                0, NULL,
02687                                &restrictedToken);
02688 
02689     FreeSid(dropSids[1].Sid);
02690     FreeSid(dropSids[0].Sid);
02691     CloseHandle(origToken);
02692     FreeLibrary(Advapi32Handle);
02693 
02694     if (!b)
02695     {
02696         fprintf(stderr, _("%s: could not create restricted token: error code %lu\n"), progname, GetLastError());
02697         return 0;
02698     }
02699 
02700 #ifndef __CYGWIN__
02701     AddUserToTokenDacl(restrictedToken);
02702 #endif
02703 
02704     if (!CreateProcessAsUser(restrictedToken,
02705                              NULL,
02706                              cmd,
02707                              NULL,
02708                              NULL,
02709                              TRUE,
02710                              CREATE_SUSPENDED,
02711                              NULL,
02712                              NULL,
02713                              &si,
02714                              processInfo))
02715 
02716     {
02717         fprintf(stderr, _("%s: could not start process for command \"%s\": error code %lu\n"), progname, cmd, GetLastError());
02718         return 0;
02719     }
02720 
02721     return ResumeThread(processInfo->hThread);
02722 }
02723 #endif
02724 
02725 /*
02726  * print help text
02727  */
02728 static void
02729 usage(const char *progname)
02730 {
02731     printf(_("%s initializes a PostgreSQL database cluster.\n\n"), progname);
02732     printf(_("Usage:\n"));
02733     printf(_("  %s [OPTION]... [DATADIR]\n"), progname);
02734     printf(_("\nOptions:\n"));
02735     printf(_("  -A, --auth=METHOD         default authentication method for local connections\n"));
02736     printf(_("      --auth-host=METHOD    default authentication method for local TCP/IP connections\n"));
02737     printf(_("      --auth-local=METHOD   default authentication method for local-socket connections\n"));
02738     printf(_(" [-D, --pgdata=]DATADIR     location for this database cluster\n"));
02739     printf(_("  -E, --encoding=ENCODING   set default encoding for new databases\n"));
02740     printf(_("      --locale=LOCALE       set default locale for new databases\n"));
02741     printf(_("      --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n"
02742              "      --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n"
02743              "                            set default locale in the respective category for\n"
02744              "                            new databases (default taken from environment)\n"));
02745     printf(_("      --no-locale           equivalent to --locale=C\n"));
02746     printf(_("      --pwfile=FILE         read password for the new superuser from file\n"));
02747     printf(_("  -T, --text-search-config=CFG\n"
02748          "                            default text search configuration\n"));
02749     printf(_("  -U, --username=NAME       database superuser name\n"));
02750     printf(_("  -W, --pwprompt            prompt for a password for the new superuser\n"));
02751     printf(_("  -X, --xlogdir=XLOGDIR     location for the transaction log directory\n"));
02752     printf(_("\nLess commonly used options:\n"));
02753     printf(_("  -d, --debug               generate lots of debugging output\n"));
02754     printf(_("  -k, --data-checksums      use data page checksums\n"));
02755     printf(_("  -L DIRECTORY              where to find the input files\n"));
02756     printf(_("  -n, --noclean             do not clean up after errors\n"));
02757     printf(_("  -N, --nosync              do not wait for changes to be written safely to disk\n"));
02758     printf(_("  -s, --show                show internal settings\n"));
02759     printf(_("  -S, --sync-only           only sync data directory\n"));
02760     printf(_("\nOther options:\n"));
02761     printf(_("  -V, --version             output version information, then exit\n"));
02762     printf(_("  -?, --help                show this help, then exit\n"));
02763     printf(_("\nIf the data directory is not specified, the environment variable PGDATA\n"
02764              "is used.\n"));
02765     printf(_("\nReport bugs to <[email protected]>.\n"));
02766 }
02767 
02768 static void
02769 check_authmethod_unspecified(const char **authmethod)
02770 {
02771     if (*authmethod == NULL || strlen(*authmethod) == 0)
02772     {
02773         authwarning = _("\nWARNING: enabling \"trust\" authentication for local connections\n"
02774                         "You can change this by editing pg_hba.conf or using the option -A, or\n"
02775             "--auth-local and --auth-host, the next time you run initdb.\n");
02776         *authmethod = "trust";
02777     }
02778 }
02779 
02780 static void
02781 check_authmethod_valid(const char *authmethod, const char **valid_methods, const char *conntype)
02782 {
02783     const char **p;
02784 
02785     for (p = valid_methods; *p; p++)
02786     {
02787         if (strcmp(authmethod, *p) == 0)
02788             return;
02789         /* with space = param */
02790         if (strchr(authmethod, ' '))
02791             if (strncmp(authmethod, *p, (authmethod - strchr(authmethod, ' '))) == 0)
02792                 return;
02793     }
02794 
02795     fprintf(stderr, _("%s: invalid authentication method \"%s\" for \"%s\" connections\n"),
02796             progname, authmethod, conntype);
02797     exit(1);
02798 }
02799 
02800 static void
02801 check_need_password(const char *authmethodlocal, const char *authmethodhost)
02802 {
02803     if ((strcmp(authmethodlocal, "md5") == 0 ||
02804          strcmp(authmethodlocal, "password") == 0) &&
02805         (strcmp(authmethodhost, "md5") == 0 ||
02806          strcmp(authmethodhost, "password") == 0) &&
02807         !(pwprompt || pwfilename))
02808     {
02809         fprintf(stderr, _("%s: must specify a password for the superuser to enable %s authentication\n"), progname,
02810                 (strcmp(authmethodlocal, "md5") == 0 ||
02811                  strcmp(authmethodlocal, "password") == 0)
02812                 ? authmethodlocal
02813                 : authmethodhost);
02814         exit(1);
02815     }
02816 }
02817 
02818 void
02819 get_restricted_token(void)
02820 {
02821 #ifdef WIN32
02822     /*
02823      * Before we execute another program, make sure that we are running with a
02824      * restricted token. If not, re-execute ourselves with one.
02825      */
02826 
02827     if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
02828         || strcmp(restrict_env, "1") != 0)
02829     {
02830         PROCESS_INFORMATION pi;
02831         char       *cmdline;
02832 
02833         ZeroMemory(&pi, sizeof(pi));
02834 
02835         cmdline = pg_strdup(GetCommandLine());
02836 
02837         putenv("PG_RESTRICT_EXEC=1");
02838 
02839         if (!CreateRestrictedProcess(cmdline, &pi))
02840         {
02841             fprintf(stderr, _("%s: could not re-execute with restricted token: error code %lu\n"), progname, GetLastError());
02842         }
02843         else
02844         {
02845             /*
02846              * Successfully re-execed. Now wait for child process to capture
02847              * exitcode.
02848              */
02849             DWORD       x;
02850 
02851             CloseHandle(pi.hThread);
02852             WaitForSingleObject(pi.hProcess, INFINITE);
02853 
02854             if (!GetExitCodeProcess(pi.hProcess, &x))
02855             {
02856                 fprintf(stderr, _("%s: could not get exit code from subprocess: error code %lu\n"), progname, GetLastError());
02857                 exit(1);
02858             }
02859             exit(x);
02860         }
02861     }
02862 #endif
02863 }
02864 
02865 void
02866 setup_pgdata(void)
02867 {
02868     char       *pgdata_get_env, *pgdata_set_env;
02869 
02870     if (strlen(pg_data) == 0)
02871     {
02872         pgdata_get_env = getenv("PGDATA");
02873         if (pgdata_get_env && strlen(pgdata_get_env))
02874         {
02875             /* PGDATA found */
02876             pg_data = pg_strdup(pgdata_get_env);
02877         }
02878         else
02879         {
02880             fprintf(stderr,
02881                     _("%s: no data directory specified\n"
02882                       "You must identify the directory where the data for this database system\n"
02883                       "will reside.  Do this with either the invocation option -D or the\n"
02884                       "environment variable PGDATA.\n"),
02885                     progname);
02886             exit(1);
02887         }
02888     }
02889 
02890     pgdata_native = pg_strdup(pg_data);
02891     canonicalize_path(pg_data);
02892 
02893     /*
02894      * we have to set PGDATA for postgres rather than pass it on the command
02895      * line to avoid dumb quoting problems on Windows, and we would especially
02896      * need quotes otherwise on Windows because paths there are most likely to
02897      * have embedded spaces.
02898      */
02899     pgdata_set_env = pg_malloc(8 + strlen(pg_data));
02900     sprintf(pgdata_set_env, "PGDATA=%s", pg_data);
02901     putenv(pgdata_set_env);
02902 }
02903 
02904 
02905 void
02906 setup_bin_paths(const char *argv0)
02907 {
02908     int ret;
02909 
02910     if ((ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
02911                                backend_exec)) < 0)
02912     {
02913         char        full_path[MAXPGPATH];
02914 
02915         if (find_my_exec(argv0, full_path) < 0)
02916             strlcpy(full_path, progname, sizeof(full_path));
02917 
02918         if (ret == -1)
02919             fprintf(stderr,
02920                     _("The program \"postgres\" is needed by %s "
02921                       "but was not found in the\n"
02922                       "same directory as \"%s\".\n"
02923                       "Check your installation.\n"),
02924                     progname, full_path);
02925         else
02926             fprintf(stderr,
02927                     _("The program \"postgres\" was found by \"%s\"\n"
02928                       "but was not the same version as %s.\n"
02929                       "Check your installation.\n"),
02930                     full_path, progname);
02931         exit(1);
02932     }
02933 
02934     /* store binary directory */
02935     strcpy(bin_path, backend_exec);
02936     *last_dir_separator(bin_path) = '\0';
02937     canonicalize_path(bin_path);
02938 
02939     if (!share_path)
02940     {
02941         share_path = pg_malloc(MAXPGPATH);
02942         get_share_path(backend_exec, share_path);
02943     }
02944     else if (!is_absolute_path(share_path))
02945     {
02946         fprintf(stderr, _("%s: input file location must be an absolute path\n"), progname);
02947         exit(1);
02948     }
02949 
02950     canonicalize_path(share_path);
02951 }
02952 
02953 void
02954 setup_locale_encoding(void)
02955 {
02956     int         user_enc;
02957 
02958     setlocales();
02959 
02960     if (strcmp(lc_ctype, lc_collate) == 0 &&
02961         strcmp(lc_ctype, lc_time) == 0 &&
02962         strcmp(lc_ctype, lc_numeric) == 0 &&
02963         strcmp(lc_ctype, lc_monetary) == 0 &&
02964         strcmp(lc_ctype, lc_messages) == 0)
02965         printf(_("The database cluster will be initialized with locale \"%s\".\n"), lc_ctype);
02966     else
02967     {
02968         printf(_("The database cluster will be initialized with locales\n"
02969                  "  COLLATE:  %s\n"
02970                  "  CTYPE:    %s\n"
02971                  "  MESSAGES: %s\n"
02972                  "  MONETARY: %s\n"
02973                  "  NUMERIC:  %s\n"
02974                  "  TIME:     %s\n"),
02975                lc_collate,
02976                lc_ctype,
02977                lc_messages,
02978                lc_monetary,
02979                lc_numeric,
02980                lc_time);
02981     }
02982 
02983     if (strlen(encoding) == 0)
02984     {
02985         int         ctype_enc;
02986 
02987         ctype_enc = pg_get_encoding_from_locale(lc_ctype, true);
02988 
02989         if (ctype_enc == -1)
02990         {
02991             /* Couldn't recognize the locale's codeset */
02992             fprintf(stderr, _("%s: could not find suitable encoding for locale \"%s\"\n"),
02993                     progname, lc_ctype);
02994             fprintf(stderr, _("Rerun %s with the -E option.\n"), progname);
02995             fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
02996                     progname);
02997             exit(1);
02998         }
02999         else if (!pg_valid_server_encoding_id(ctype_enc))
03000         {
03001             /*
03002              * We recognized it, but it's not a legal server encoding. On
03003              * Windows, UTF-8 works with any locale, so we can fall back to
03004              * UTF-8.
03005              */
03006 #ifdef WIN32
03007             printf(_("Encoding \"%s\" implied by locale is not allowed as a server-side encoding.\n"
03008             "The default database encoding will be set to \"%s\" instead.\n"),
03009                    pg_encoding_to_char(ctype_enc),
03010                    pg_encoding_to_char(PG_UTF8));
03011             ctype_enc = PG_UTF8;
03012             encodingid = encodingid_to_string(ctype_enc);
03013 #else
03014             fprintf(stderr,
03015                _("%s: locale \"%s\" requires unsupported encoding \"%s\"\n"),
03016                     progname, lc_ctype, pg_encoding_to_char(ctype_enc));
03017             fprintf(stderr,
03018               _("Encoding \"%s\" is not allowed as a server-side encoding.\n"
03019                 "Rerun %s with a different locale selection.\n"),
03020                     pg_encoding_to_char(ctype_enc), progname);
03021             exit(1);
03022 #endif
03023         }
03024         else
03025         {
03026             encodingid = encodingid_to_string(ctype_enc);
03027             printf(_("The default database encoding has accordingly been set to \"%s\".\n"),
03028                    pg_encoding_to_char(ctype_enc));
03029         }
03030     }
03031     else
03032         encodingid = get_encoding_id(encoding);
03033 
03034     user_enc = atoi(encodingid);
03035     if (!check_locale_encoding(lc_ctype, user_enc) ||
03036         !check_locale_encoding(lc_collate, user_enc))
03037         exit(1);                /* check_locale_encoding printed the error */
03038 
03039 }
03040 
03041 
03042 void
03043 setup_data_file_paths(void)
03044 {
03045     set_input(&bki_file, "postgres.bki");
03046     set_input(&desc_file, "postgres.description");
03047     set_input(&shdesc_file, "postgres.shdescription");
03048     set_input(&hba_file, "pg_hba.conf.sample");
03049     set_input(&ident_file, "pg_ident.conf.sample");
03050     set_input(&conf_file, "postgresql.conf.sample");
03051     set_input(&conversion_file, "conversion_create.sql");
03052     set_input(&dictionary_file, "snowball_create.sql");
03053     set_input(&info_schema_file, "information_schema.sql");
03054     set_input(&features_file, "sql_features.txt");
03055     set_input(&system_views_file, "system_views.sql");
03056 
03057     if (show_setting || debug)
03058     {
03059         fprintf(stderr,
03060                 "VERSION=%s\n"
03061                 "PGDATA=%s\nshare_path=%s\nPGPATH=%s\n"
03062                 "POSTGRES_SUPERUSERNAME=%s\nPOSTGRES_BKI=%s\n"
03063                 "POSTGRES_DESCR=%s\nPOSTGRES_SHDESCR=%s\n"
03064                 "POSTGRESQL_CONF_SAMPLE=%s\n"
03065                 "PG_HBA_SAMPLE=%s\nPG_IDENT_SAMPLE=%s\n",
03066                 PG_VERSION,
03067                 pg_data, share_path, bin_path,
03068                 username, bki_file,
03069                 desc_file, shdesc_file,
03070                 conf_file,
03071                 hba_file, ident_file);
03072         if (show_setting)
03073             exit(0);
03074     }
03075 
03076     check_input(bki_file);
03077     check_input(desc_file);
03078     check_input(shdesc_file);
03079     check_input(hba_file);
03080     check_input(ident_file);
03081     check_input(conf_file);
03082     check_input(conversion_file);
03083     check_input(dictionary_file);
03084     check_input(info_schema_file);
03085     check_input(features_file);
03086     check_input(system_views_file);
03087 }
03088 
03089 
03090 void
03091 setup_text_search(void)
03092 {
03093     if (strlen(default_text_search_config) == 0)
03094     {
03095         default_text_search_config = find_matching_ts_config(lc_ctype);
03096         if (default_text_search_config == NULL)
03097         {
03098             printf(_("%s: could not find suitable text search configuration for locale \"%s\"\n"),
03099                    progname, lc_ctype);
03100             default_text_search_config = "simple";
03101         }
03102     }
03103     else
03104     {
03105         const char *checkmatch = find_matching_ts_config(lc_ctype);
03106 
03107         if (checkmatch == NULL)
03108         {
03109             printf(_("%s: warning: suitable text search configuration for locale \"%s\" is unknown\n"),
03110                    progname, lc_ctype);
03111         }
03112         else if (strcmp(checkmatch, default_text_search_config) != 0)
03113         {
03114             printf(_("%s: warning: specified text search configuration \"%s\" might not match locale \"%s\"\n"),
03115                    progname, default_text_search_config, lc_ctype);
03116         }
03117     }
03118 
03119     printf(_("The default text search configuration will be set to \"%s\".\n"),
03120            default_text_search_config);
03121 
03122 }
03123 
03124 
03125 void
03126 setup_signals(void)
03127 {
03128     /* some of these are not valid on Windows */
03129 #ifdef SIGHUP
03130     pqsignal(SIGHUP, trapsig);
03131 #endif
03132 #ifdef SIGINT
03133     pqsignal(SIGINT, trapsig);
03134 #endif
03135 #ifdef SIGQUIT
03136     pqsignal(SIGQUIT, trapsig);
03137 #endif
03138 #ifdef SIGTERM
03139     pqsignal(SIGTERM, trapsig);
03140 #endif
03141 
03142     /* Ignore SIGPIPE when writing to backend, so we can clean up */
03143 #ifdef SIGPIPE
03144     pqsignal(SIGPIPE, SIG_IGN);
03145 #endif
03146 }
03147 
03148 
03149 void
03150 create_data_directory(void)
03151 {
03152     int ret;
03153 
03154     switch ((ret = pg_check_dir(pg_data)))
03155     {
03156         case 0:
03157             /* PGDATA not there, must create it */
03158             printf(_("creating directory %s ... "),
03159                    pg_data);
03160             fflush(stdout);
03161 
03162             if (!mkdatadir(NULL))
03163                 exit_nicely();
03164             else
03165                 check_ok();
03166 
03167             made_new_pgdata = true;
03168             break;
03169 
03170         case 1:
03171             /* Present but empty, fix permissions and use it */
03172             printf(_("fixing permissions on existing directory %s ... "),
03173                    pg_data);
03174             fflush(stdout);
03175 
03176             if (chmod(pg_data, S_IRWXU) != 0)
03177             {
03178                 fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
03179                         progname, pg_data, strerror(errno));
03180                 exit_nicely();
03181             }
03182             else
03183                 check_ok();
03184 
03185             found_existing_pgdata = true;
03186             break;
03187 
03188         case 2:
03189         case 3:
03190         case 4:
03191             /* Present and not empty */
03192             fprintf(stderr,
03193                     _("%s: directory \"%s\" exists but is not empty\n"),
03194                     progname, pg_data);
03195             if (ret != 4)
03196                 warn_on_mount_point(ret);
03197             else
03198                 fprintf(stderr,
03199                         _("If you want to create a new database system, either remove or empty\n"
03200                           "the directory \"%s\" or run %s\n"
03201                           "with an argument other than \"%s\".\n"),
03202                         pg_data, progname, pg_data);
03203             exit(1);            /* no further message needed */
03204 
03205         default:
03206             /* Trouble accessing directory */
03207             fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
03208                     progname, pg_data, strerror(errno));
03209             exit_nicely();
03210     }
03211 }
03212 
03213 
03214 void
03215 create_xlog_symlink(void)
03216 {
03217     /* Create transaction log symlink, if required */
03218     if (strcmp(xlog_dir, "") != 0)
03219     {
03220         char       *linkloc;
03221         int         ret;
03222 
03223         /* clean up xlog directory name, check it's absolute */
03224         canonicalize_path(xlog_dir);
03225         if (!is_absolute_path(xlog_dir))
03226         {
03227             fprintf(stderr, _("%s: transaction log directory location must be an absolute path\n"), progname);
03228             exit_nicely();
03229         }
03230 
03231         /* check if the specified xlog directory exists/is empty */
03232         switch ((ret = pg_check_dir(xlog_dir)))
03233         {
03234             case 0:
03235                 /* xlog directory not there, must create it */
03236                 printf(_("creating directory %s ... "),
03237                        xlog_dir);
03238                 fflush(stdout);
03239 
03240                 if (pg_mkdir_p(xlog_dir, S_IRWXU) != 0)
03241                 {
03242                     fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
03243                             progname, xlog_dir, strerror(errno));
03244                     exit_nicely();
03245                 }
03246                 else
03247                     check_ok();
03248 
03249                 made_new_xlogdir = true;
03250                 break;
03251 
03252             case 1:
03253                 /* Present but empty, fix permissions and use it */
03254                 printf(_("fixing permissions on existing directory %s ... "),
03255                        xlog_dir);
03256                 fflush(stdout);
03257 
03258                 if (chmod(xlog_dir, S_IRWXU) != 0)
03259                 {
03260                     fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
03261                             progname, xlog_dir, strerror(errno));
03262                     exit_nicely();
03263                 }
03264                 else
03265                     check_ok();
03266 
03267                 found_existing_xlogdir = true;
03268                 break;
03269 
03270             case 2:
03271             case 3:
03272             case 4:
03273                 /* Present and not empty */
03274                 fprintf(stderr,
03275                         _("%s: directory \"%s\" exists but is not empty\n"),
03276                         progname, xlog_dir);
03277                 if (ret != 4)
03278                     warn_on_mount_point(ret);
03279                 else
03280                     fprintf(stderr,
03281                      _("If you want to store the transaction log there, either\n"
03282                        "remove or empty the directory \"%s\".\n"),
03283                             xlog_dir);
03284                 exit_nicely();
03285 
03286             default:
03287                 /* Trouble accessing directory */
03288                 fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
03289                         progname, xlog_dir, strerror(errno));
03290                 exit_nicely();
03291         }
03292 
03293         /* form name of the place where the symlink must go */
03294         linkloc = (char *) pg_malloc(strlen(pg_data) + 8 + 1);
03295         sprintf(linkloc, "%s/pg_xlog", pg_data);
03296 
03297 #ifdef HAVE_SYMLINK
03298         if (symlink(xlog_dir, linkloc) != 0)
03299         {
03300             fprintf(stderr, _("%s: could not create symbolic link \"%s\": %s\n"),
03301                     progname, linkloc, strerror(errno));
03302             exit_nicely();
03303         }
03304 #else
03305         fprintf(stderr, _("%s: symlinks are not supported on this platform"));
03306         exit_nicely();
03307 #endif
03308     }
03309 }
03310 
03311 
03312 void
03313 warn_on_mount_point(int error)
03314 {
03315     if (error == 2)
03316         fprintf(stderr,
03317                 _("It contains a dot-prefixed/invisible file, perhaps due to it being a mount point.\n"));
03318     else if (error == 3)
03319         fprintf(stderr,
03320                 _("It contains a lost+found directory, perhaps due to it being a mount point.\n"));
03321 
03322     fprintf(stderr,
03323             _("Using a mount point directly as the data directory is not recommended.\n"
03324               "Create a subdirectory under the mount point.\n"));
03325 }
03326 
03327 
03328 void
03329 initialize_data_directory(void)
03330 {
03331     int i;
03332 
03333     setup_signals();
03334 
03335     umask(S_IRWXG | S_IRWXO);
03336  
03337     create_data_directory();
03338 
03339     create_xlog_symlink();
03340 
03341     /* Create required subdirectories */
03342     printf(_("creating subdirectories ... "));
03343     fflush(stdout);
03344 
03345     for (i = 0; i < (sizeof(subdirs) / sizeof(char *)); i++)
03346     {
03347         if (!mkdatadir(subdirs[i]))
03348             exit_nicely();
03349     }
03350 
03351     check_ok();
03352 
03353     /* Top level PG_VERSION is checked by bootstrapper, so make it first */
03354     write_version_file(NULL);
03355 
03356     /* Select suitable configuration settings */
03357     set_null_conf();
03358     test_config_settings();
03359 
03360     /* Now create all the text config files */
03361     setup_config();
03362 
03363     /* Bootstrap template1 */
03364     bootstrap_template1();
03365 
03366     /*
03367      * Make the per-database PG_VERSION for template1 only after init'ing it
03368      */
03369     write_version_file("base/1");
03370 
03371     /* Create the stuff we don't need to use bootstrap mode for */
03372 
03373     setup_auth();
03374     if (pwprompt || pwfilename)
03375         get_set_pwd();
03376 
03377     setup_depend();
03378 
03379     setup_sysviews();
03380 
03381     setup_description();
03382 
03383     setup_collation();
03384 
03385     setup_conversion();
03386 
03387     setup_dictionary();
03388 
03389     setup_privileges();
03390 
03391     setup_schema();
03392 
03393     load_plpgsql();
03394 
03395     vacuum_db();
03396 
03397     make_template0();
03398 
03399     make_postgres();
03400 }
03401 
03402 
03403 int
03404 main(int argc, char *argv[])
03405 {
03406     static struct option long_options[] = {
03407         {"pgdata", required_argument, NULL, 'D'},
03408         {"encoding", required_argument, NULL, 'E'},
03409         {"locale", required_argument, NULL, 1},
03410         {"lc-collate", required_argument, NULL, 2},
03411         {"lc-ctype", required_argument, NULL, 3},
03412         {"lc-monetary", required_argument, NULL, 4},
03413         {"lc-numeric", required_argument, NULL, 5},
03414         {"lc-time", required_argument, NULL, 6},
03415         {"lc-messages", required_argument, NULL, 7},
03416         {"no-locale", no_argument, NULL, 8},
03417         {"text-search-config", required_argument, NULL, 'T'},
03418         {"auth", required_argument, NULL, 'A'},
03419         {"auth-local", required_argument, NULL, 10},
03420         {"auth-host", required_argument, NULL, 11},
03421         {"pwprompt", no_argument, NULL, 'W'},
03422         {"pwfile", required_argument, NULL, 9},
03423         {"username", required_argument, NULL, 'U'},
03424         {"help", no_argument, NULL, '?'},
03425         {"version", no_argument, NULL, 'V'},
03426         {"debug", no_argument, NULL, 'd'},
03427         {"show", no_argument, NULL, 's'},
03428         {"noclean", no_argument, NULL, 'n'},
03429         {"nosync", no_argument, NULL, 'N'},
03430         {"sync-only", no_argument, NULL, 'S'},
03431         {"xlogdir", required_argument, NULL, 'X'},
03432         {"data-checksums", no_argument, NULL, 'k'},
03433         {NULL, 0, NULL, 0}
03434     };
03435 
03436     /*
03437      * options with no short version return a low integer, the rest return
03438      * their short version value
03439      */
03440     int         c;
03441     int         option_index;
03442     char       *effective_user;
03443     char        bin_dir[MAXPGPATH];
03444 
03445     progname = get_progname(argv[0]);
03446     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("initdb"));
03447 
03448     if (argc > 1)
03449     {
03450         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
03451         {
03452             usage(progname);
03453             exit(0);
03454         }
03455         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
03456         {
03457             puts("initdb (PostgreSQL) " PG_VERSION);
03458             exit(0);
03459         }
03460     }
03461 
03462     /* process command-line options */
03463 
03464     while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", long_options, &option_index)) != -1)
03465     {
03466         switch (c)
03467         {
03468             case 'A':
03469                 authmethodlocal = authmethodhost = pg_strdup(optarg);
03470 
03471                 /*
03472                  * When ident is specified, use peer for local connections.
03473                  * Mirrored, when peer is specified, use ident for TCP/IP
03474                  * connections.
03475                  */
03476                 if (strcmp(authmethodhost, "ident") == 0)
03477                     authmethodlocal = "peer";
03478                 else if (strcmp(authmethodlocal, "peer") == 0)
03479                     authmethodhost = "ident";
03480                 break;
03481             case 10:
03482                 authmethodlocal = pg_strdup(optarg);
03483                 break;
03484             case 11:
03485                 authmethodhost = pg_strdup(optarg);
03486                 break;
03487             case 'D':
03488                 pg_data = pg_strdup(optarg);
03489                 break;
03490             case 'E':
03491                 encoding = pg_strdup(optarg);
03492                 break;
03493             case 'W':
03494                 pwprompt = true;
03495                 break;
03496             case 'U':
03497                 username = pg_strdup(optarg);
03498                 break;
03499             case 'd':
03500                 debug = true;
03501                 printf(_("Running in debug mode.\n"));
03502                 break;
03503             case 'n':
03504                 noclean = true;
03505                 printf(_("Running in noclean mode.  Mistakes will not be cleaned up.\n"));
03506                 break;
03507             case 'N':
03508                 do_sync = false;
03509                 break;
03510             case 'S':
03511                 sync_only = true;
03512                 break;
03513             case 'k':
03514                 data_checksums = true;
03515                 break;
03516             case 'L':
03517                 share_path = pg_strdup(optarg);
03518                 break;
03519             case 1:
03520                 locale = pg_strdup(optarg);
03521                 break;
03522             case 2:
03523                 lc_collate = pg_strdup(optarg);
03524                 break;
03525             case 3:
03526                 lc_ctype = pg_strdup(optarg);
03527                 break;
03528             case 4:
03529                 lc_monetary = pg_strdup(optarg);
03530                 break;
03531             case 5:
03532                 lc_numeric = pg_strdup(optarg);
03533                 break;
03534             case 6:
03535                 lc_time = pg_strdup(optarg);
03536                 break;
03537             case 7:
03538                 lc_messages = pg_strdup(optarg);
03539                 break;
03540             case 8:
03541                 locale = "C";
03542                 break;
03543             case 9:
03544                 pwfilename = pg_strdup(optarg);
03545                 break;
03546             case 's':
03547                 show_setting = true;
03548                 break;
03549             case 'T':
03550                 default_text_search_config = pg_strdup(optarg);
03551                 break;
03552             case 'X':
03553                 xlog_dir = pg_strdup(optarg);
03554                 break;
03555             default:
03556                 /* getopt_long already emitted a complaint */
03557                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
03558                         progname);
03559                 exit(1);
03560         }
03561     }
03562 
03563 
03564     /*
03565      * Non-option argument specifies data directory as long as it wasn't
03566      * already specified with -D / --pgdata
03567      */
03568     if (optind < argc && strlen(pg_data) == 0)
03569     {
03570         pg_data = pg_strdup(argv[optind]);
03571         optind++;
03572     }
03573 
03574     if (optind < argc)
03575     {
03576         fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
03577                 progname, argv[optind]);
03578         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
03579                 progname);
03580         exit(1);
03581     }
03582 
03583     /* If we only need to fsync, just to it and exit */
03584     if (sync_only)
03585     {
03586         setup_pgdata();
03587         perform_fsync();
03588         return 0;
03589     }
03590     
03591     if (pwprompt && pwfilename)
03592     {
03593         fprintf(stderr, _("%s: password prompt and password file cannot be specified together\n"), progname);
03594         exit(1);
03595     }
03596 
03597     check_authmethod_unspecified(&authmethodlocal);
03598     check_authmethod_unspecified(&authmethodhost);
03599 
03600     check_authmethod_valid(authmethodlocal, auth_methods_local, "local");
03601     check_authmethod_valid(authmethodhost, auth_methods_host, "host");
03602 
03603     check_need_password(authmethodlocal, authmethodhost);
03604 
03605     get_restricted_token();
03606 
03607     setup_pgdata();
03608 
03609     setup_bin_paths(argv[0]);
03610     
03611     effective_user = get_id();
03612     if (strlen(username) == 0)
03613         username = effective_user;
03614 
03615     printf(_("The files belonging to this database system will be owned "
03616              "by user \"%s\".\n"
03617              "This user must also own the server process.\n\n"),
03618            effective_user);
03619 
03620     set_info_version();
03621 
03622     setup_data_file_paths();
03623 
03624     setup_locale_encoding();
03625 
03626     setup_text_search();
03627 
03628     if (data_checksums)
03629         printf(_("Data page checksums are enabled.\n"));
03630     else
03631         printf(_("Data page checksums are disabled.\n"));
03632     
03633     printf("\n");
03634 
03635     initialize_data_directory();
03636     
03637     if (do_sync)
03638         perform_fsync();
03639     else
03640         printf(_("\nSync to disk skipped.\nThe data directory might become corrupt if the operating system crashes.\n"));
03641 
03642     if (authwarning != NULL)
03643         fprintf(stderr, "%s", authwarning);
03644 
03645     /* Get directory specification used to start this executable */
03646     strlcpy(bin_dir, argv[0], sizeof(bin_dir));
03647     get_parent_directory(bin_dir);
03648 
03649     printf(_("\nSuccess. You can now start the database server using:\n\n"
03650              "    %s%s%spostgres%s -D %s%s%s\n"
03651              "or\n"
03652              "    %s%s%spg_ctl%s -D %s%s%s -l logfile start\n\n"),
03653        QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
03654            QUOTE_PATH, pgdata_native, QUOTE_PATH,
03655        QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
03656            QUOTE_PATH, pgdata_native, QUOTE_PATH);
03657 
03658     return 0;
03659 }