LCOV - code coverage report
Current view: top level - src/bin/initdb - initdb.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 796 1044 76.2 %
Date: 2019-09-22 08:06:49 Functions: 54 56 96.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * initdb --- initialize a PostgreSQL installation
       4             :  *
       5             :  * initdb creates (initializes) a PostgreSQL database cluster (site,
       6             :  * instance, installation, whatever).  A database cluster is a
       7             :  * collection of PostgreSQL databases all managed by the same server.
       8             :  *
       9             :  * To create the database cluster, we create the directory that contains
      10             :  * all its data, create the files that hold the global tables, create
      11             :  * a few other control files for it, and create three databases: the
      12             :  * template databases "template0" and "template1", and a default user
      13             :  * database "postgres".
      14             :  *
      15             :  * The template databases are ordinary PostgreSQL databases.  template0
      16             :  * is never supposed to change after initdb, whereas template1 can be
      17             :  * changed to add site-local standard data.  Either one can be copied
      18             :  * to produce a new database.
      19             :  *
      20             :  * For largely-historical reasons, the template1 database is the one built
      21             :  * by the basic bootstrap process.  After it is complete, template0 and
      22             :  * the default database, postgres, are made just by copying template1.
      23             :  *
      24             :  * To create template1, we run the postgres (backend) program in bootstrap
      25             :  * mode and feed it data from the postgres.bki library file.  After this
      26             :  * initial bootstrap phase, some additional stuff is created by normal
      27             :  * SQL commands fed to a standalone backend.  Some of those commands are
      28             :  * just embedded into this program (yeah, it's ugly), but larger chunks
      29             :  * are taken from script files.
      30             :  *
      31             :  *
      32             :  * Note:
      33             :  *   The program has some memory leakage - it isn't worth cleaning it up.
      34             :  *
      35             :  * This is a C implementation of the previous shell script for setting up a
      36             :  * PostgreSQL cluster location, and should be highly compatible with it.
      37             :  * author of C translation: Andrew Dunstan     mailto:andrew@dunslane.net
      38             :  *
      39             :  * This code is released under the terms of the PostgreSQL License.
      40             :  *
      41             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
      42             :  * Portions Copyright (c) 1994, Regents of the University of California
      43             :  *
      44             :  * src/bin/initdb/initdb.c
      45             :  *
      46             :  *-------------------------------------------------------------------------
      47             :  */
      48             : 
      49             : #include "postgres_fe.h"
      50             : 
      51             : #include <dirent.h>
      52             : #include <fcntl.h>
      53             : #include <sys/stat.h>
      54             : #include <unistd.h>
      55             : #include <signal.h>
      56             : #include <time.h>
      57             : 
      58             : #ifdef HAVE_SHM_OPEN
      59             : #include "sys/mman.h"
      60             : #endif
      61             : 
      62             : #include "access/xlog_internal.h"
      63             : #include "catalog/pg_authid_d.h"
      64             : #include "catalog/pg_class_d.h" /* pgrminclude ignore */
      65             : #include "catalog/pg_collation_d.h"
      66             : #include "common/file_perm.h"
      67             : #include "common/file_utils.h"
      68             : #include "common/logging.h"
      69             : #include "common/restricted_token.h"
      70             : #include "common/username.h"
      71             : #include "fe_utils/string_utils.h"
      72             : #include "getaddrinfo.h"
      73             : #include "getopt_long.h"
      74             : #include "mb/pg_wchar.h"
      75             : #include "miscadmin.h"
      76             : 
      77             : 
      78             : /* Ideally this would be in a .h file, but it hardly seems worth the trouble */
      79             : extern const char *select_default_timezone(const char *share_path);
      80             : 
      81             : static const char *const auth_methods_host[] = {
      82             :     "trust", "reject", "scram-sha-256", "md5", "password", "ident", "radius",
      83             : #ifdef ENABLE_GSS
      84             :     "gss",
      85             : #endif
      86             : #ifdef ENABLE_SSPI
      87             :     "sspi",
      88             : #endif
      89             : #ifdef USE_PAM
      90             :     "pam", "pam ",
      91             : #endif
      92             : #ifdef USE_BSD_AUTH
      93             :     "bsd",
      94             : #endif
      95             : #ifdef USE_LDAP
      96             :     "ldap",
      97             : #endif
      98             : #ifdef USE_SSL
      99             :     "cert",
     100             : #endif
     101             :     NULL
     102             : };
     103             : static const char *const auth_methods_local[] = {
     104             :     "trust", "reject", "scram-sha-256", "md5", "password", "peer", "radius",
     105             : #ifdef USE_PAM
     106             :     "pam", "pam ",
     107             : #endif
     108             : #ifdef USE_BSD_AUTH
     109             :     "bsd",
     110             : #endif
     111             : #ifdef USE_LDAP
     112             :     "ldap",
     113             : #endif
     114             :     NULL
     115             : };
     116             : 
     117             : /*
     118             :  * these values are passed in by makefile defines
     119             :  */
     120             : static char *share_path = NULL;
     121             : 
     122             : /* values to be obtained from arguments */
     123             : static char *pg_data = NULL;
     124             : static char *encoding = NULL;
     125             : static char *locale = NULL;
     126             : static char *lc_collate = NULL;
     127             : static char *lc_ctype = NULL;
     128             : static char *lc_monetary = NULL;
     129             : static char *lc_numeric = NULL;
     130             : static char *lc_time = NULL;
     131             : static char *lc_messages = NULL;
     132             : static const char *default_text_search_config = NULL;
     133             : static char *username = NULL;
     134             : static bool pwprompt = false;
     135             : static char *pwfilename = NULL;
     136             : static char *superuser_password = NULL;
     137             : static const char *authmethodhost = NULL;
     138             : static const char *authmethodlocal = NULL;
     139             : static bool debug = false;
     140             : static bool noclean = false;
     141             : static bool do_sync = true;
     142             : static bool sync_only = false;
     143             : static bool show_setting = false;
     144             : static bool data_checksums = false;
     145             : static char *xlog_dir = NULL;
     146             : static char *str_wal_segment_size_mb = NULL;
     147             : static int  wal_segment_size_mb;
     148             : 
     149             : 
     150             : /* internal vars */
     151             : static const char *progname;
     152             : static int  encodingid;
     153             : static char *bki_file;
     154             : static char *desc_file;
     155             : static char *shdesc_file;
     156             : static char *hba_file;
     157             : static char *ident_file;
     158             : static char *conf_file;
     159             : static char *dictionary_file;
     160             : static char *info_schema_file;
     161             : static char *features_file;
     162             : static char *system_views_file;
     163             : static bool success = false;
     164             : static bool made_new_pgdata = false;
     165             : static bool found_existing_pgdata = false;
     166             : static bool made_new_xlogdir = false;
     167             : static bool found_existing_xlogdir = false;
     168             : static char infoversion[100];
     169             : static bool caught_signal = false;
     170             : static bool output_failed = false;
     171             : static int  output_errno = 0;
     172             : static char *pgdata_native;
     173             : 
     174             : /* defaults */
     175             : static int  n_connections = 10;
     176             : static int  n_buffers = 50;
     177             : static const char *dynamic_shared_memory_type = NULL;
     178             : static const char *default_timezone = NULL;
     179             : 
     180             : /*
     181             :  * Warning messages for authentication methods
     182             :  */
     183             : #define AUTHTRUST_WARNING \
     184             : "# CAUTION: Configuring the system for local \"trust\" authentication\n" \
     185             : "# allows any local user to connect as any PostgreSQL user, including\n" \
     186             : "# the database superuser.  If you do not trust all your local users,\n" \
     187             : "# use another authentication method.\n"
     188             : static bool authwarning = false;
     189             : 
     190             : /*
     191             :  * Centralized knowledge of switches to pass to backend
     192             :  *
     193             :  * Note: we run the backend with -F (fsync disabled) and then do a single
     194             :  * pass of fsync'ing at the end.  This is faster than fsync'ing each step.
     195             :  *
     196             :  * Note: in the shell-script version, we also passed PGDATA as a -D switch,
     197             :  * but here it is more convenient to pass it as an environment variable
     198             :  * (no quoting to worry about).
     199             :  */
     200             : static const char *boot_options = "-F";
     201             : static const char *backend_options = "--single -F -O -j -c search_path=pg_catalog -c exit_on_error=true";
     202             : 
     203             : static const char *const subdirs[] = {
     204             :     "global",
     205             :     "pg_wal/archive_status",
     206             :     "pg_commit_ts",
     207             :     "pg_dynshmem",
     208             :     "pg_notify",
     209             :     "pg_serial",
     210             :     "pg_snapshots",
     211             :     "pg_subtrans",
     212             :     "pg_twophase",
     213             :     "pg_multixact",
     214             :     "pg_multixact/members",
     215             :     "pg_multixact/offsets",
     216             :     "base",
     217             :     "base/1",
     218             :     "pg_replslot",
     219             :     "pg_tblspc",
     220             :     "pg_stat",
     221             :     "pg_stat_tmp",
     222             :     "pg_xact",
     223             :     "pg_logical",
     224             :     "pg_logical/snapshots",
     225             :     "pg_logical/mappings"
     226             : };
     227             : 
     228             : 
     229             : /* path to 'initdb' binary directory */
     230             : static char bin_path[MAXPGPATH];
     231             : static char backend_exec[MAXPGPATH];
     232             : 
     233             : static char **replace_token(char **lines,
     234             :                             const char *token, const char *replacement);
     235             : 
     236             : #ifndef HAVE_UNIX_SOCKETS
     237             : static char **filter_lines_with_token(char **lines, const char *token);
     238             : #endif
     239             : static char **readfile(const char *path);
     240             : static void writefile(char *path, char **lines);
     241             : static FILE *popen_check(const char *command, const char *mode);
     242             : static char *get_id(void);
     243             : static int  get_encoding_id(const char *encoding_name);
     244             : static void set_input(char **dest, const char *filename);
     245             : static void check_input(char *path);
     246             : static void write_version_file(const char *extrapath);
     247             : static void set_null_conf(void);
     248             : static void test_config_settings(void);
     249             : static void setup_config(void);
     250             : static void bootstrap_template1(void);
     251             : static void setup_auth(FILE *cmdfd);
     252             : static void get_su_pwd(void);
     253             : static void setup_depend(FILE *cmdfd);
     254             : static void setup_sysviews(FILE *cmdfd);
     255             : static void setup_description(FILE *cmdfd);
     256             : static void setup_collation(FILE *cmdfd);
     257             : static void setup_dictionary(FILE *cmdfd);
     258             : static void setup_privileges(FILE *cmdfd);
     259             : static void set_info_version(void);
     260             : static void setup_schema(FILE *cmdfd);
     261             : static void load_plpgsql(FILE *cmdfd);
     262             : static void vacuum_db(FILE *cmdfd);
     263             : static void make_template0(FILE *cmdfd);
     264             : static void make_postgres(FILE *cmdfd);
     265             : static void trapsig(int signum);
     266             : static void check_ok(void);
     267             : static char *escape_quotes(const char *src);
     268             : static char *escape_quotes_bki(const char *src);
     269             : static int  locale_date_order(const char *locale);
     270             : static void check_locale_name(int category, const char *locale,
     271             :                               char **canonname);
     272             : static bool check_locale_encoding(const char *locale, int encoding);
     273             : static void setlocales(void);
     274             : static void usage(const char *progname);
     275             : void        setup_pgdata(void);
     276             : void        setup_bin_paths(const char *argv0);
     277             : void        setup_data_file_paths(void);
     278             : void        setup_locale_encoding(void);
     279             : void        setup_signals(void);
     280             : void        setup_text_search(void);
     281             : void        create_data_directory(void);
     282             : void        create_xlog_or_symlink(void);
     283             : void        warn_on_mount_point(int error);
     284             : void        initialize_data_directory(void);
     285             : 
     286             : /*
     287             :  * macros for running pipes to postgres
     288             :  */
     289             : #define PG_CMD_DECL     char cmd[MAXPGPATH]; FILE *cmdfd
     290             : 
     291             : #define PG_CMD_OPEN \
     292             : do { \
     293             :     cmdfd = popen_check(cmd, "w"); \
     294             :     if (cmdfd == NULL) \
     295             :         exit(1); /* message already printed by popen_check */ \
     296             : } while (0)
     297             : 
     298             : #define PG_CMD_CLOSE \
     299             : do { \
     300             :     if (pclose_check(cmdfd)) \
     301             :         exit(1); /* message already printed by pclose_check */ \
     302             : } while (0)
     303             : 
     304             : #define PG_CMD_PUTS(line) \
     305             : do { \
     306             :     if (fputs(line, cmdfd) < 0 || fflush(cmdfd) < 0) \
     307             :         output_failed = true, output_errno = errno; \
     308             : } while (0)
     309             : 
     310             : #define PG_CMD_PRINTF(fmt, ...) \
     311             : do { \
     312             :     if (fprintf(cmdfd, fmt, __VA_ARGS__) < 0 || fflush(cmdfd) < 0) \
     313             :         output_failed = true, output_errno = errno; \
     314             : } while (0)
     315             : 
     316             : /*
     317             :  * Escape single quotes and backslashes, suitably for insertions into
     318             :  * configuration files or SQL E'' strings.
     319             :  */
     320             : static char *
     321        4480 : escape_quotes(const char *src)
     322             : {
     323        4480 :     char       *result = escape_single_quotes_ascii(src);
     324             : 
     325        4480 :     if (!result)
     326             :     {
     327           0 :         pg_log_error("out of memory");
     328           0 :         exit(1);
     329             :     }
     330        4480 :     return result;
     331             : }
     332             : 
     333             : /*
     334             :  * Escape a field value to be inserted into the BKI data.
     335             :  * Here, we first run the value through escape_quotes (which
     336             :  * will be inverted by the backend's scanstr() function) and
     337             :  * then overlay special processing of double quotes, which
     338             :  * bootscanner.l will only accept as data if converted to octal
     339             :  * representation ("\042").  We always wrap the value in double
     340             :  * quotes, even if that isn't strictly necessary.
     341             :  */
     342             : static char *
     343         960 : escape_quotes_bki(const char *src)
     344             : {
     345             :     char       *result;
     346         960 :     char       *data = escape_quotes(src);
     347             :     char       *resultp;
     348             :     char       *datap;
     349         960 :     int         nquotes = 0;
     350             : 
     351             :     /* count double quotes in data */
     352         960 :     datap = data;
     353        1920 :     while ((datap = strchr(datap, '"')) != NULL)
     354             :     {
     355           0 :         nquotes++;
     356           0 :         datap++;
     357             :     }
     358             : 
     359         960 :     result = (char *) pg_malloc(strlen(data) + 3 + nquotes * 3);
     360         960 :     resultp = result;
     361         960 :     *resultp++ = '"';
     362       10240 :     for (datap = data; *datap; datap++)
     363             :     {
     364        9280 :         if (*datap == '"')
     365             :         {
     366           0 :             strcpy(resultp, "\\042");
     367           0 :             resultp += 4;
     368             :         }
     369             :         else
     370        9280 :             *resultp++ = *datap;
     371             :     }
     372         960 :     *resultp++ = '"';
     373         960 :     *resultp = '\0';
     374             : 
     375         960 :     free(data);
     376         960 :     return result;
     377             : }
     378             : 
     379             : /*
     380             :  * make a copy of the array of lines, with token replaced by replacement
     381             :  * the first time it occurs on each line.
     382             :  *
     383             :  * This does most of what sed was used for in the shell script, but
     384             :  * doesn't need any regexp stuff.
     385             :  */
     386             : static char **
     387        9610 : replace_token(char **lines, const char *token, const char *replacement)
     388             : {
     389        9610 :     int         numlines = 1;
     390             :     int         i;
     391             :     char      **result;
     392             :     int         toklen,
     393             :                 replen,
     394             :                 diff;
     395             : 
     396    24210070 :     for (i = 0; lines[i]; i++)
     397    24200460 :         numlines++;
     398             : 
     399        9610 :     result = (char **) pg_malloc(numlines * sizeof(char *));
     400             : 
     401        9610 :     toklen = strlen(token);
     402        9610 :     replen = strlen(replacement);
     403        9610 :     diff = replen - toklen;
     404             : 
     405    24219680 :     for (i = 0; i < numlines; i++)
     406             :     {
     407             :         char       *where;
     408             :         char       *newline;
     409             :         int         pre;
     410             : 
     411             :         /* just copy pointer if NULL or no change needed */
     412    24210070 :         if (lines[i] == NULL || (where = strstr(lines[i], token)) == NULL)
     413             :         {
     414    24193740 :             result[i] = lines[i];
     415    24193740 :             continue;
     416             :         }
     417             : 
     418             :         /* if we get here a change is needed - set up new line */
     419             : 
     420       16330 :         newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1);
     421             : 
     422       16330 :         pre = where - lines[i];
     423             : 
     424       16330 :         memcpy(newline, lines[i], pre);
     425             : 
     426       16330 :         memcpy(newline + pre, replacement, replen);
     427             : 
     428       16330 :         strcpy(newline + pre + replen, lines[i] + pre + toklen);
     429             : 
     430       16330 :         result[i] = newline;
     431             :     }
     432             : 
     433        9610 :     return result;
     434             : }
     435             : 
     436             : /*
     437             :  * make a copy of lines without any that contain the token
     438             :  *
     439             :  * a sort of poor man's grep -v
     440             :  */
     441             : #ifndef HAVE_UNIX_SOCKETS
     442             : static char **
     443             : filter_lines_with_token(char **lines, const char *token)
     444             : {
     445             :     int         numlines = 1;
     446             :     int         i,
     447             :                 src,
     448             :                 dst;
     449             :     char      **result;
     450             : 
     451             :     for (i = 0; lines[i]; i++)
     452             :         numlines++;
     453             : 
     454             :     result = (char **) pg_malloc(numlines * sizeof(char *));
     455             : 
     456             :     for (src = 0, dst = 0; src < numlines; src++)
     457             :     {
     458             :         if (lines[src] == NULL || strstr(lines[src], token) == NULL)
     459             :             result[dst++] = lines[src];
     460             :     }
     461             : 
     462             :     return result;
     463             : }
     464             : #endif
     465             : 
     466             : /*
     467             :  * get the lines from a text file
     468             :  */
     469             : static char **
     470        2240 : readfile(const char *path)
     471             : {
     472             :     FILE       *infile;
     473        2240 :     int         maxlength = 1,
     474        2240 :                 linelen = 0;
     475        2240 :     int         nlines = 0;
     476             :     int         n;
     477             :     char      **result;
     478             :     char       *buffer;
     479             :     int         c;
     480             : 
     481        2240 :     if ((infile = fopen(path, "r")) == NULL)
     482             :     {
     483           0 :         pg_log_error("could not open file \"%s\" for reading: %m", path);
     484           0 :         exit(1);
     485             :     }
     486             : 
     487             :     /* pass over the file twice - the first time to size the result */
     488             : 
     489   281995840 :     while ((c = fgetc(infile)) != EOF)
     490             :     {
     491   281991360 :         linelen++;
     492   281991360 :         if (c == '\n')
     493             :         {
     494     4229120 :             nlines++;
     495     4229120 :             if (linelen > maxlength)
     496       21760 :                 maxlength = linelen;
     497     4229120 :             linelen = 0;
     498             :         }
     499             :     }
     500             : 
     501             :     /* handle last line without a terminating newline (yuck) */
     502        2240 :     if (linelen)
     503           0 :         nlines++;
     504        2240 :     if (linelen > maxlength)
     505           0 :         maxlength = linelen;
     506             : 
     507             :     /* set up the result and the line buffer */
     508        2240 :     result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
     509        2240 :     buffer = (char *) pg_malloc(maxlength + 1);
     510             : 
     511             :     /* now reprocess the file and store the lines */
     512        2240 :     rewind(infile);
     513        2240 :     n = 0;
     514     4233600 :     while (fgets(buffer, maxlength + 1, infile) != NULL && n < nlines)
     515     4229120 :         result[n++] = pg_strdup(buffer);
     516             : 
     517        2240 :     fclose(infile);
     518        2240 :     free(buffer);
     519        2240 :     result[n] = NULL;
     520             : 
     521        2240 :     return result;
     522             : }
     523             : 
     524             : /*
     525             :  * write an array of lines to a file
     526             :  *
     527             :  * This is only used to write text files.  Use fopen "w" not PG_BINARY_W
     528             :  * so that the resulting configuration files are nicely editable on Windows.
     529             :  */
     530             : static void
     531        1280 : writefile(char *path, char **lines)
     532             : {
     533             :     FILE       *out_file;
     534             :     char      **line;
     535             : 
     536        1280 :     if ((out_file = fopen(path, "w")) == NULL)
     537             :     {
     538           0 :         pg_log_error("could not open file \"%s\" for writing: %m", path);
     539           0 :         exit(1);
     540             :     }
     541      283840 :     for (line = lines; *line != NULL; line++)
     542             :     {
     543      282560 :         if (fputs(*line, out_file) < 0)
     544             :         {
     545           0 :             pg_log_error("could not write file \"%s\": %m", path);
     546           0 :             exit(1);
     547             :         }
     548      282560 :         free(*line);
     549             :     }
     550        1280 :     if (fclose(out_file))
     551             :     {
     552           0 :         pg_log_error("could not write file \"%s\": %m", path);
     553           0 :         exit(1);
     554             :     }
     555        1280 : }
     556             : 
     557             : /*
     558             :  * Open a subcommand with suitable error messaging
     559             :  */
     560             : static FILE *
     561         640 : popen_check(const char *command, const char *mode)
     562             : {
     563             :     FILE       *cmdfd;
     564             : 
     565         640 :     fflush(stdout);
     566         640 :     fflush(stderr);
     567         640 :     errno = 0;
     568         640 :     cmdfd = popen(command, mode);
     569         640 :     if (cmdfd == NULL)
     570           0 :         pg_log_error("could not execute command \"%s\": %m", command);
     571         640 :     return cmdfd;
     572             : }
     573             : 
     574             : /*
     575             :  * clean up any files we created on failure
     576             :  * if we created the data directory remove it too
     577             :  */
     578             : static void
     579         334 : cleanup_directories_atexit(void)
     580             : {
     581         334 :     if (success)
     582         320 :         return;
     583             : 
     584          14 :     if (!noclean)
     585             :     {
     586          14 :         if (made_new_pgdata)
     587             :         {
     588           4 :             pg_log_info("removing data directory \"%s\"", pg_data);
     589           4 :             if (!rmtree(pg_data, true))
     590           0 :                 pg_log_error("failed to remove data directory");
     591             :         }
     592          10 :         else if (found_existing_pgdata)
     593             :         {
     594           0 :             pg_log_info("removing contents of data directory \"%s\"",
     595             :                         pg_data);
     596           0 :             if (!rmtree(pg_data, false))
     597           0 :                 pg_log_error("failed to remove contents of data directory");
     598             :         }
     599             : 
     600          14 :         if (made_new_xlogdir)
     601             :         {
     602           0 :             pg_log_info("removing WAL directory \"%s\"", xlog_dir);
     603           0 :             if (!rmtree(xlog_dir, true))
     604           0 :                 pg_log_error("failed to remove WAL directory");
     605             :         }
     606          14 :         else if (found_existing_xlogdir)
     607             :         {
     608           0 :             pg_log_info("removing contents of WAL directory \"%s\"", xlog_dir);
     609           0 :             if (!rmtree(xlog_dir, false))
     610           0 :                 pg_log_error("failed to remove contents of WAL directory");
     611             :         }
     612             :         /* otherwise died during startup, do nothing! */
     613             :     }
     614             :     else
     615             :     {
     616           0 :         if (made_new_pgdata || found_existing_pgdata)
     617           0 :             pg_log_info("data directory \"%s\" not removed at user's request",
     618             :                         pg_data);
     619             : 
     620           0 :         if (made_new_xlogdir || found_existing_xlogdir)
     621           0 :             pg_log_info("WAL directory \"%s\" not removed at user's request",
     622             :                         xlog_dir);
     623             :     }
     624             : }
     625             : 
     626             : /*
     627             :  * find the current user
     628             :  *
     629             :  * on unix make sure it isn't root
     630             :  */
     631             : static char *
     632         328 : get_id(void)
     633             : {
     634             :     const char *username;
     635             : 
     636             : #ifndef WIN32
     637         328 :     if (geteuid() == 0)         /* 0 is root's uid */
     638             :     {
     639           0 :         pg_log_error("cannot be run as root");
     640           0 :         fprintf(stderr,
     641           0 :                 _("Please log in (using, e.g., \"su\") as the (unprivileged) user that will\n"
     642             :                   "own the server process.\n"));
     643           0 :         exit(1);
     644             :     }
     645             : #endif
     646             : 
     647         328 :     username = get_user_name_or_exit(progname);
     648             : 
     649         328 :     return pg_strdup(username);
     650             : }
     651             : 
     652             : static char *
     653         320 : encodingid_to_string(int enc)
     654             : {
     655             :     char        result[20];
     656             : 
     657         320 :     sprintf(result, "%d", enc);
     658         320 :     return pg_strdup(result);
     659             : }
     660             : 
     661             : /*
     662             :  * get the encoding id for a given encoding name
     663             :  */
     664             : static int
     665          14 : get_encoding_id(const char *encoding_name)
     666             : {
     667             :     int         enc;
     668             : 
     669          14 :     if (encoding_name && *encoding_name)
     670             :     {
     671          14 :         if ((enc = pg_valid_server_encoding(encoding_name)) >= 0)
     672          28 :             return enc;
     673             :     }
     674           0 :     pg_log_error("\"%s\" is not a valid server encoding name",
     675             :                  encoding_name ? encoding_name : "(null)");
     676           0 :     exit(1);
     677             : }
     678             : 
     679             : /*
     680             :  * Support for determining the best default text search configuration.
     681             :  * We key this off the first part of LC_CTYPE (ie, the language name).
     682             :  */
     683             : struct tsearch_config_match
     684             : {
     685             :     const char *tsconfname;
     686             :     const char *langname;
     687             : };
     688             : 
     689             : static const struct tsearch_config_match tsearch_config_languages[] =
     690             : {
     691             :     {"arabic", "ar"},
     692             :     {"arabic", "Arabic"},
     693             :     {"danish", "da"},
     694             :     {"danish", "Danish"},
     695             :     {"dutch", "nl"},
     696             :     {"dutch", "Dutch"},
     697             :     {"english", "C"},
     698             :     {"english", "POSIX"},
     699             :     {"english", "en"},
     700             :     {"english", "English"},
     701             :     {"finnish", "fi"},
     702             :     {"finnish", "Finnish"},
     703             :     {"french", "fr"},
     704             :     {"french", "French"},
     705             :     {"german", "de"},
     706             :     {"german", "German"},
     707             :     {"greek", "el"},
     708             :     {"greek", "Greek"},
     709             :     {"hungarian", "hu"},
     710             :     {"hungarian", "Hungarian"},
     711             :     {"indonesian", "id"},
     712             :     {"indonesian", "Indonesian"},
     713             :     {"irish", "ga"},
     714             :     {"irish", "Irish"},
     715             :     {"italian", "it"},
     716             :     {"italian", "Italian"},
     717             :     {"lithuanian", "lt"},
     718             :     {"lithuanian", "Lithuanian"},
     719             :     {"nepali", "ne"},
     720             :     {"nepali", "Nepali"},
     721             :     {"norwegian", "no"},
     722             :     {"norwegian", "Norwegian"},
     723             :     {"portuguese", "pt"},
     724             :     {"portuguese", "Portuguese"},
     725             :     {"romanian", "ro"},
     726             :     {"russian", "ru"},
     727             :     {"russian", "Russian"},
     728             :     {"spanish", "es"},
     729             :     {"spanish", "Spanish"},
     730             :     {"swedish", "sv"},
     731             :     {"swedish", "Swedish"},
     732             :     {"tamil", "ta"},
     733             :     {"tamil", "Tamil"},
     734             :     {"turkish", "tr"},
     735             :     {"turkish", "Turkish"},
     736             :     {NULL, NULL}                /* end marker */
     737             : };
     738             : 
     739             : /*
     740             :  * Look for a text search configuration matching lc_ctype, and return its
     741             :  * name; return NULL if no match.
     742             :  */
     743             : static const char *
     744         326 : find_matching_ts_config(const char *lc_type)
     745             : {
     746             :     int         i;
     747             :     char       *langname,
     748             :                *ptr;
     749             : 
     750             :     /*
     751             :      * Convert lc_ctype to a language name by stripping everything after an
     752             :      * underscore (usual case) or a hyphen (Windows "locale name"; see
     753             :      * comments at IsoLocaleName()).
     754             :      *
     755             :      * XXX Should ' ' be a stop character?  This would select "norwegian" for
     756             :      * the Windows locale "Norwegian (Nynorsk)_Norway.1252".  If we do so, we
     757             :      * should also accept the "nn" and "nb" Unix locales.
     758             :      *
     759             :      * Just for paranoia, we also stop at '.' or '@'.
     760             :      */
     761         326 :     if (lc_type == NULL)
     762           0 :         langname = pg_strdup("");
     763             :     else
     764             :     {
     765         326 :         ptr = langname = pg_strdup(lc_type);
     766        2234 :         while (*ptr &&
     767        1582 :                *ptr != '_' && *ptr != '-' && *ptr != '.' && *ptr != '@')
     768         636 :             ptr++;
     769         326 :         *ptr = '\0';
     770             :     }
     771             : 
     772        2902 :     for (i = 0; tsearch_config_languages[i].tsconfname; i++)
     773             :     {
     774        2902 :         if (pg_strcasecmp(tsearch_config_languages[i].langname, langname) == 0)
     775             :         {
     776         326 :             free(langname);
     777         326 :             return tsearch_config_languages[i].tsconfname;
     778             :         }
     779             :     }
     780             : 
     781           0 :     free(langname);
     782           0 :     return NULL;
     783             : }
     784             : 
     785             : 
     786             : /*
     787             :  * set name of given input file variable under data directory
     788             :  */
     789             : static void
     790        3260 : set_input(char **dest, const char *filename)
     791             : {
     792        3260 :     *dest = psprintf("%s/%s", share_path, filename);
     793        3260 : }
     794             : 
     795             : /*
     796             :  * check that given input file exists
     797             :  */
     798             : static void
     799        3260 : check_input(char *path)
     800             : {
     801             :     struct stat statbuf;
     802             : 
     803        3260 :     if (stat(path, &statbuf) != 0)
     804             :     {
     805           0 :         if (errno == ENOENT)
     806             :         {
     807           0 :             pg_log_error("file \"%s\" does not exist", path);
     808           0 :             fprintf(stderr,
     809           0 :                     _("This might mean you have a corrupted installation or identified\n"
     810             :                       "the wrong directory with the invocation option -L.\n"));
     811             :         }
     812             :         else
     813             :         {
     814           0 :             pg_log_error("could not access file \"%s\": %m", path);
     815           0 :             fprintf(stderr,
     816           0 :                     _("This might mean you have a corrupted installation or identified\n"
     817             :                       "the wrong directory with the invocation option -L.\n"));
     818             :         }
     819           0 :         exit(1);
     820             :     }
     821        3260 :     if (!S_ISREG(statbuf.st_mode))
     822             :     {
     823           0 :         pg_log_error("file \"%s\" is not a regular file", path);
     824           0 :         fprintf(stderr,
     825           0 :                 _("This might mean you have a corrupted installation or identified\n"
     826             :                   "the wrong directory with the invocation option -L.\n"));
     827           0 :         exit(1);
     828             :     }
     829        3260 : }
     830             : 
     831             : /*
     832             :  * write out the PG_VERSION file in the data dir, or its subdirectory
     833             :  * if extrapath is not NULL
     834             :  */
     835             : static void
     836         640 : write_version_file(const char *extrapath)
     837             : {
     838             :     FILE       *version_file;
     839             :     char       *path;
     840             : 
     841         640 :     if (extrapath == NULL)
     842         320 :         path = psprintf("%s/PG_VERSION", pg_data);
     843             :     else
     844         320 :         path = psprintf("%s/%s/PG_VERSION", pg_data, extrapath);
     845             : 
     846         640 :     if ((version_file = fopen(path, PG_BINARY_W)) == NULL)
     847             :     {
     848           0 :         pg_log_error("could not open file \"%s\" for writing: %m", path);
     849           0 :         exit(1);
     850             :     }
     851        1280 :     if (fprintf(version_file, "%s\n", PG_MAJORVERSION) < 0 ||
     852         640 :         fclose(version_file))
     853             :     {
     854           0 :         pg_log_error("could not write file \"%s\": %m", path);
     855           0 :         exit(1);
     856             :     }
     857         640 :     free(path);
     858         640 : }
     859             : 
     860             : /*
     861             :  * set up an empty config file so we can check config settings by launching
     862             :  * a test backend
     863             :  */
     864             : static void
     865         320 : set_null_conf(void)
     866             : {
     867             :     FILE       *conf_file;
     868             :     char       *path;
     869             : 
     870         320 :     path = psprintf("%s/postgresql.conf", pg_data);
     871         320 :     conf_file = fopen(path, PG_BINARY_W);
     872         320 :     if (conf_file == NULL)
     873             :     {
     874           0 :         pg_log_error("could not open file \"%s\" for writing: %m", path);
     875           0 :         exit(1);
     876             :     }
     877         320 :     if (fclose(conf_file))
     878             :     {
     879           0 :         pg_log_error("could not write file \"%s\": %m", path);
     880           0 :         exit(1);
     881             :     }
     882         320 :     free(path);
     883         320 : }
     884             : 
     885             : /*
     886             :  * Determine which dynamic shared memory implementation should be used on
     887             :  * this platform.  POSIX shared memory is preferable because the default
     888             :  * allocation limits are much higher than the limits for System V on most
     889             :  * systems that support both, but the fact that a platform has shm_open
     890             :  * doesn't guarantee that that call will succeed when attempted.  So, we
     891             :  * attempt to reproduce what the postmaster will do when allocating a POSIX
     892             :  * segment in dsm_impl.c; if it doesn't work, we assume it won't work for
     893             :  * the postmaster either, and configure the cluster for System V shared
     894             :  * memory instead.
     895             :  */
     896             : static const char *
     897         320 : choose_dsm_implementation(void)
     898             : {
     899             : #ifdef HAVE_SHM_OPEN
     900         320 :     int         ntries = 10;
     901             : 
     902             :     /* Initialize random(); this function is its only user in this program. */
     903         320 :     srandom((unsigned int) (getpid() ^ time(NULL)));
     904             : 
     905         640 :     while (ntries > 0)
     906             :     {
     907             :         uint32      handle;
     908             :         char        name[64];
     909             :         int         fd;
     910             : 
     911         320 :         handle = random();
     912         320 :         snprintf(name, 64, "/PostgreSQL.%u", handle);
     913         320 :         if ((fd = shm_open(name, O_CREAT | O_RDWR | O_EXCL, 0600)) != -1)
     914             :         {
     915         320 :             close(fd);
     916         320 :             shm_unlink(name);
     917         320 :             return "posix";
     918             :         }
     919           0 :         if (errno != EEXIST)
     920           0 :             break;
     921           0 :         --ntries;
     922             :     }
     923             : #endif
     924             : 
     925             : #ifdef WIN32
     926             :     return "windows";
     927             : #else
     928           0 :     return "sysv";
     929             : #endif
     930             : }
     931             : 
     932             : /*
     933             :  * Determine platform-specific config settings
     934             :  *
     935             :  * Use reasonable values if kernel will let us, else scale back.
     936             :  */
     937             : static void
     938         320 : test_config_settings(void)
     939             : {
     940             :     /*
     941             :      * This macro defines the minimum shared_buffers we want for a given
     942             :      * max_connections value. The arrays show the settings to try.
     943             :      */
     944             : #define MIN_BUFS_FOR_CONNS(nconns)  ((nconns) * 10)
     945             : 
     946             :     static const int trial_conns[] = {
     947             :         100, 50, 40, 30, 20
     948             :     };
     949             :     static const int trial_bufs[] = {
     950             :         16384, 8192, 4096, 3584, 3072, 2560, 2048, 1536,
     951             :         1000, 900, 800, 700, 600, 500,
     952             :         400, 300, 200, 100, 50
     953             :     };
     954             : 
     955             :     char        cmd[MAXPGPATH];
     956         320 :     const int   connslen = sizeof(trial_conns) / sizeof(int);
     957         320 :     const int   bufslen = sizeof(trial_bufs) / sizeof(int);
     958             :     int         i,
     959             :                 status,
     960             :                 test_conns,
     961             :                 test_buffs,
     962         320 :                 ok_buffers = 0;
     963             : 
     964             :     /*
     965             :      * Need to determine working DSM implementation first so that subsequent
     966             :      * tests don't fail because DSM setting doesn't work.
     967             :      */
     968         320 :     printf(_("selecting dynamic shared memory implementation ... "));
     969         320 :     fflush(stdout);
     970         320 :     dynamic_shared_memory_type = choose_dsm_implementation();
     971         320 :     printf("%s\n", dynamic_shared_memory_type);
     972             : 
     973             :     /*
     974             :      * Probe for max_connections before shared_buffers, since it is subject to
     975             :      * more constraints than shared_buffers.
     976             :      */
     977         320 :     printf(_("selecting default max_connections ... "));
     978         320 :     fflush(stdout);
     979             : 
     980         320 :     for (i = 0; i < connslen; i++)
     981             :     {
     982         320 :         test_conns = trial_conns[i];
     983         320 :         test_buffs = MIN_BUFS_FOR_CONNS(test_conns);
     984             : 
     985         320 :         snprintf(cmd, sizeof(cmd),
     986             :                  "\"%s\" --boot -x0 %s "
     987             :                  "-c max_connections=%d "
     988             :                  "-c shared_buffers=%d "
     989             :                  "-c dynamic_shared_memory_type=%s "
     990             :                  "< \"%s\" > \"%s\" 2>&1",
     991             :                  backend_exec, boot_options,
     992             :                  test_conns, test_buffs,
     993             :                  dynamic_shared_memory_type,
     994             :                  DEVNULL, DEVNULL);
     995         320 :         status = system(cmd);
     996         320 :         if (status == 0)
     997             :         {
     998         320 :             ok_buffers = test_buffs;
     999         320 :             break;
    1000             :         }
    1001             :     }
    1002         320 :     if (i >= connslen)
    1003           0 :         i = connslen - 1;
    1004         320 :     n_connections = trial_conns[i];
    1005             : 
    1006         320 :     printf("%d\n", n_connections);
    1007             : 
    1008         320 :     printf(_("selecting default shared_buffers ... "));
    1009         320 :     fflush(stdout);
    1010             : 
    1011         320 :     for (i = 0; i < bufslen; i++)
    1012             :     {
    1013             :         /* Use same amount of memory, independent of BLCKSZ */
    1014         320 :         test_buffs = (trial_bufs[i] * 8192) / BLCKSZ;
    1015         320 :         if (test_buffs <= ok_buffers)
    1016             :         {
    1017           0 :             test_buffs = ok_buffers;
    1018           0 :             break;
    1019             :         }
    1020             : 
    1021         320 :         snprintf(cmd, sizeof(cmd),
    1022             :                  "\"%s\" --boot -x0 %s "
    1023             :                  "-c max_connections=%d "
    1024             :                  "-c shared_buffers=%d "
    1025             :                  "-c dynamic_shared_memory_type=%s "
    1026             :                  "< \"%s\" > \"%s\" 2>&1",
    1027             :                  backend_exec, boot_options,
    1028             :                  n_connections, test_buffs,
    1029             :                  dynamic_shared_memory_type,
    1030             :                  DEVNULL, DEVNULL);
    1031         320 :         status = system(cmd);
    1032         320 :         if (status == 0)
    1033         320 :             break;
    1034             :     }
    1035         320 :     n_buffers = test_buffs;
    1036             : 
    1037         320 :     if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
    1038         320 :         printf("%dMB\n", (n_buffers * (BLCKSZ / 1024)) / 1024);
    1039             :     else
    1040           0 :         printf("%dkB\n", n_buffers * (BLCKSZ / 1024));
    1041             : 
    1042         320 :     printf(_("selecting default time zone ... "));
    1043         320 :     fflush(stdout);
    1044         320 :     default_timezone = select_default_timezone(share_path);
    1045         320 :     printf("%s\n", default_timezone ? default_timezone : "GMT");
    1046         320 : }
    1047             : 
    1048             : /*
    1049             :  * Calculate the default wal_size with a "pretty" unit.
    1050             :  */
    1051             : static char *
    1052         640 : pretty_wal_size(int segment_count)
    1053             : {
    1054         640 :     int         sz = wal_segment_size_mb * segment_count;
    1055         640 :     char       *result = pg_malloc(14);
    1056             : 
    1057         640 :     if ((sz % 1024) == 0)
    1058         316 :         snprintf(result, 14, "%dGB", sz / 1024);
    1059             :     else
    1060         324 :         snprintf(result, 14, "%dMB", sz);
    1061             : 
    1062         640 :     return result;
    1063             : }
    1064             : 
    1065             : /*
    1066             :  * set up all the config files
    1067             :  */
    1068             : static void
    1069         320 : setup_config(void)
    1070             : {
    1071             :     char      **conflines;
    1072             :     char        repltok[MAXPGPATH];
    1073             :     char        path[MAXPGPATH];
    1074             :     char       *autoconflines[3];
    1075             : 
    1076         320 :     fputs(_("creating configuration files ... "), stdout);
    1077         320 :     fflush(stdout);
    1078             : 
    1079             :     /* postgresql.conf */
    1080             : 
    1081         320 :     conflines = readfile(conf_file);
    1082             : 
    1083         320 :     snprintf(repltok, sizeof(repltok), "max_connections = %d", n_connections);
    1084         320 :     conflines = replace_token(conflines, "#max_connections = 100", repltok);
    1085             : 
    1086         320 :     if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
    1087         320 :         snprintf(repltok, sizeof(repltok), "shared_buffers = %dMB",
    1088         320 :                  (n_buffers * (BLCKSZ / 1024)) / 1024);
    1089             :     else
    1090           0 :         snprintf(repltok, sizeof(repltok), "shared_buffers = %dkB",
    1091             :                  n_buffers * (BLCKSZ / 1024));
    1092         320 :     conflines = replace_token(conflines, "#shared_buffers = 32MB", repltok);
    1093             : 
    1094             : #ifdef HAVE_UNIX_SOCKETS
    1095         320 :     snprintf(repltok, sizeof(repltok), "#unix_socket_directories = '%s'",
    1096             :              DEFAULT_PGSOCKET_DIR);
    1097             : #else
    1098             :     snprintf(repltok, sizeof(repltok), "#unix_socket_directories = ''");
    1099             : #endif
    1100         320 :     conflines = replace_token(conflines, "#unix_socket_directories = '/tmp'",
    1101             :                               repltok);
    1102             : 
    1103             : #if DEF_PGPORT != 5432
    1104             :     snprintf(repltok, sizeof(repltok), "#port = %d", DEF_PGPORT);
    1105             :     conflines = replace_token(conflines, "#port = 5432", repltok);
    1106             : #endif
    1107             : 
    1108             :     /* set default max_wal_size and min_wal_size */
    1109         320 :     snprintf(repltok, sizeof(repltok), "min_wal_size = %s",
    1110             :              pretty_wal_size(DEFAULT_MIN_WAL_SEGS));
    1111         320 :     conflines = replace_token(conflines, "#min_wal_size = 80MB", repltok);
    1112             : 
    1113         320 :     snprintf(repltok, sizeof(repltok), "max_wal_size = %s",
    1114             :              pretty_wal_size(DEFAULT_MAX_WAL_SEGS));
    1115         320 :     conflines = replace_token(conflines, "#max_wal_size = 1GB", repltok);
    1116             : 
    1117         320 :     snprintf(repltok, sizeof(repltok), "lc_messages = '%s'",
    1118             :              escape_quotes(lc_messages));
    1119         320 :     conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
    1120             : 
    1121         320 :     snprintf(repltok, sizeof(repltok), "lc_monetary = '%s'",
    1122             :              escape_quotes(lc_monetary));
    1123         320 :     conflines = replace_token(conflines, "#lc_monetary = 'C'", repltok);
    1124             : 
    1125         320 :     snprintf(repltok, sizeof(repltok), "lc_numeric = '%s'",
    1126             :              escape_quotes(lc_numeric));
    1127         320 :     conflines = replace_token(conflines, "#lc_numeric = 'C'", repltok);
    1128             : 
    1129         320 :     snprintf(repltok, sizeof(repltok), "lc_time = '%s'",
    1130             :              escape_quotes(lc_time));
    1131         320 :     conflines = replace_token(conflines, "#lc_time = 'C'", repltok);
    1132             : 
    1133         320 :     switch (locale_date_order(lc_time))
    1134             :     {
    1135             :         case DATEORDER_YMD:
    1136           0 :             strcpy(repltok, "datestyle = 'iso, ymd'");
    1137           0 :             break;
    1138             :         case DATEORDER_DMY:
    1139           0 :             strcpy(repltok, "datestyle = 'iso, dmy'");
    1140           0 :             break;
    1141             :         case DATEORDER_MDY:
    1142             :         default:
    1143         320 :             strcpy(repltok, "datestyle = 'iso, mdy'");
    1144         320 :             break;
    1145             :     }
    1146         320 :     conflines = replace_token(conflines, "#datestyle = 'iso, mdy'", repltok);
    1147             : 
    1148         320 :     snprintf(repltok, sizeof(repltok),
    1149             :              "default_text_search_config = 'pg_catalog.%s'",
    1150             :              escape_quotes(default_text_search_config));
    1151         320 :     conflines = replace_token(conflines,
    1152             :                               "#default_text_search_config = 'pg_catalog.simple'",
    1153             :                               repltok);
    1154             : 
    1155         320 :     if (default_timezone)
    1156             :     {
    1157         320 :         snprintf(repltok, sizeof(repltok), "timezone = '%s'",
    1158             :                  escape_quotes(default_timezone));
    1159         320 :         conflines = replace_token(conflines, "#timezone = 'GMT'", repltok);
    1160         320 :         snprintf(repltok, sizeof(repltok), "log_timezone = '%s'",
    1161             :                  escape_quotes(default_timezone));
    1162         320 :         conflines = replace_token(conflines, "#log_timezone = 'GMT'", repltok);
    1163             :     }
    1164             : 
    1165         320 :     snprintf(repltok, sizeof(repltok), "dynamic_shared_memory_type = %s",
    1166             :              dynamic_shared_memory_type);
    1167         320 :     conflines = replace_token(conflines, "#dynamic_shared_memory_type = posix",
    1168             :                               repltok);
    1169             : 
    1170             : #if DEFAULT_BACKEND_FLUSH_AFTER > 0
    1171             :     snprintf(repltok, sizeof(repltok), "#backend_flush_after = %dkB",
    1172             :              DEFAULT_BACKEND_FLUSH_AFTER * (BLCKSZ / 1024));
    1173             :     conflines = replace_token(conflines, "#backend_flush_after = 0",
    1174             :                               repltok);
    1175             : #endif
    1176             : 
    1177             : #if DEFAULT_BGWRITER_FLUSH_AFTER > 0
    1178         320 :     snprintf(repltok, sizeof(repltok), "#bgwriter_flush_after = %dkB",
    1179             :              DEFAULT_BGWRITER_FLUSH_AFTER * (BLCKSZ / 1024));
    1180         320 :     conflines = replace_token(conflines, "#bgwriter_flush_after = 0",
    1181             :                               repltok);
    1182             : #endif
    1183             : 
    1184             : #if DEFAULT_CHECKPOINT_FLUSH_AFTER > 0
    1185         320 :     snprintf(repltok, sizeof(repltok), "#checkpoint_flush_after = %dkB",
    1186             :              DEFAULT_CHECKPOINT_FLUSH_AFTER * (BLCKSZ / 1024));
    1187         320 :     conflines = replace_token(conflines, "#checkpoint_flush_after = 0",
    1188             :                               repltok);
    1189             : #endif
    1190             : 
    1191             : #ifndef USE_PREFETCH
    1192             :     conflines = replace_token(conflines,
    1193             :                               "#effective_io_concurrency = 1",
    1194             :                               "#effective_io_concurrency = 0");
    1195             : #endif
    1196             : 
    1197             : #ifdef WIN32
    1198             :     conflines = replace_token(conflines,
    1199             :                               "#update_process_title = on",
    1200             :                               "#update_process_title = off");
    1201             : #endif
    1202             : 
    1203         640 :     if (strcmp(authmethodlocal, "scram-sha-256") == 0 ||
    1204         320 :         strcmp(authmethodhost, "scram-sha-256") == 0)
    1205             :     {
    1206           0 :         conflines = replace_token(conflines,
    1207             :                                   "#password_encryption = md5",
    1208             :                                   "password_encryption = scram-sha-256");
    1209             :     }
    1210             : 
    1211             :     /*
    1212             :      * If group access has been enabled for the cluster then it makes sense to
    1213             :      * ensure that the log files also allow group access.  Otherwise a backup
    1214             :      * from a user in the group would fail if the log files were not
    1215             :      * relocated.
    1216             :      */
    1217         320 :     if (pg_dir_create_mode == PG_DIR_MODE_GROUP)
    1218             :     {
    1219          10 :         conflines = replace_token(conflines,
    1220             :                                   "#log_file_mode = 0600",
    1221             :                                   "log_file_mode = 0640");
    1222             :     }
    1223             : 
    1224         320 :     snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
    1225             : 
    1226         320 :     writefile(path, conflines);
    1227         320 :     if (chmod(path, pg_file_create_mode) != 0)
    1228             :     {
    1229           0 :         pg_log_error("could not change permissions of \"%s\": %m", path);
    1230           0 :         exit(1);
    1231             :     }
    1232             : 
    1233             :     /*
    1234             :      * create the automatic configuration file to store the configuration
    1235             :      * parameters set by ALTER SYSTEM command. The parameters present in this
    1236             :      * file will override the value of parameters that exists before parse of
    1237             :      * this file.
    1238             :      */
    1239         320 :     autoconflines[0] = pg_strdup("# Do not edit this file manually!\n");
    1240         320 :     autoconflines[1] = pg_strdup("# It will be overwritten by the ALTER SYSTEM command.\n");
    1241         320 :     autoconflines[2] = NULL;
    1242             : 
    1243         320 :     sprintf(path, "%s/postgresql.auto.conf", pg_data);
    1244             : 
    1245         320 :     writefile(path, autoconflines);
    1246         320 :     if (chmod(path, pg_file_create_mode) != 0)
    1247             :     {
    1248           0 :         pg_log_error("could not change permissions of \"%s\": %m", path);
    1249           0 :         exit(1);
    1250             :     }
    1251             : 
    1252         320 :     free(conflines);
    1253             : 
    1254             : 
    1255             :     /* pg_hba.conf */
    1256             : 
    1257         320 :     conflines = readfile(hba_file);
    1258             : 
    1259             : #ifndef HAVE_UNIX_SOCKETS
    1260             :     conflines = filter_lines_with_token(conflines, "@remove-line-for-nolocal@");
    1261             : #else
    1262         320 :     conflines = replace_token(conflines, "@remove-line-for-nolocal@", "");
    1263             : #endif
    1264             : 
    1265             : #ifdef HAVE_IPV6
    1266             : 
    1267             :     /*
    1268             :      * Probe to see if there is really any platform support for IPv6, and
    1269             :      * comment out the relevant pg_hba line if not.  This avoids runtime
    1270             :      * warnings if getaddrinfo doesn't actually cope with IPv6.  Particularly
    1271             :      * useful on Windows, where executables built on a machine with IPv6 may
    1272             :      * have to run on a machine without.
    1273             :      */
    1274             :     {
    1275             :         struct addrinfo *gai_result;
    1276             :         struct addrinfo hints;
    1277         320 :         int         err = 0;
    1278             : 
    1279             : #ifdef WIN32
    1280             :         /* need to call WSAStartup before calling getaddrinfo */
    1281             :         WSADATA     wsaData;
    1282             : 
    1283             :         err = WSAStartup(MAKEWORD(2, 2), &wsaData);
    1284             : #endif
    1285             : 
    1286             :         /* for best results, this code should match parse_hba_line() */
    1287         320 :         hints.ai_flags = AI_NUMERICHOST;
    1288         320 :         hints.ai_family = AF_UNSPEC;
    1289         320 :         hints.ai_socktype = 0;
    1290         320 :         hints.ai_protocol = 0;
    1291         320 :         hints.ai_addrlen = 0;
    1292         320 :         hints.ai_canonname = NULL;
    1293         320 :         hints.ai_addr = NULL;
    1294         320 :         hints.ai_next = NULL;
    1295             : 
    1296         640 :         if (err != 0 ||
    1297         320 :             getaddrinfo("::1", NULL, &hints, &gai_result) != 0)
    1298             :         {
    1299           0 :             conflines = replace_token(conflines,
    1300             :                                       "host    all             all             ::1",
    1301             :                                       "#host    all             all             ::1");
    1302           0 :             conflines = replace_token(conflines,
    1303             :                                       "host    replication     all             ::1",
    1304             :                                       "#host    replication     all             ::1");
    1305             :         }
    1306             :     }
    1307             : #else                           /* !HAVE_IPV6 */
    1308             :     /* If we didn't compile IPV6 support at all, always comment it out */
    1309             :     conflines = replace_token(conflines,
    1310             :                               "host    all             all             ::1",
    1311             :                               "#host    all             all             ::1");
    1312             :     conflines = replace_token(conflines,
    1313             :                               "host    replication     all             ::1",
    1314             :                               "#host    replication     all             ::1");
    1315             : #endif                          /* HAVE_IPV6 */
    1316             : 
    1317             :     /* Replace default authentication methods */
    1318         320 :     conflines = replace_token(conflines,
    1319             :                               "@authmethodhost@",
    1320             :                               authmethodhost);
    1321         320 :     conflines = replace_token(conflines,
    1322             :                               "@authmethodlocal@",
    1323             :                               authmethodlocal);
    1324             : 
    1325         640 :     conflines = replace_token(conflines,
    1326             :                               "@authcomment@",
    1327         320 :                               (strcmp(authmethodlocal, "trust") == 0 || strcmp(authmethodhost, "trust") == 0) ? AUTHTRUST_WARNING : "");
    1328             : 
    1329         320 :     snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data);
    1330             : 
    1331         320 :     writefile(path, conflines);
    1332         320 :     if (chmod(path, pg_file_create_mode) != 0)
    1333             :     {
    1334           0 :         pg_log_error("could not change permissions of \"%s\": %m", path);
    1335           0 :         exit(1);
    1336             :     }
    1337             : 
    1338         320 :     free(conflines);
    1339             : 
    1340             :     /* pg_ident.conf */
    1341             : 
    1342         320 :     conflines = readfile(ident_file);
    1343             : 
    1344         320 :     snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data);
    1345             : 
    1346         320 :     writefile(path, conflines);
    1347         320 :     if (chmod(path, pg_file_create_mode) != 0)
    1348             :     {
    1349           0 :         pg_log_error("could not change permissions of \"%s\": %m", path);
    1350           0 :         exit(1);
    1351             :     }
    1352             : 
    1353         320 :     free(conflines);
    1354             : 
    1355         320 :     check_ok();
    1356         320 : }
    1357             : 
    1358             : 
    1359             : /*
    1360             :  * run the BKI script in bootstrap mode to create template1
    1361             :  */
    1362             : static void
    1363         320 : bootstrap_template1(void)
    1364             : {
    1365             :     PG_CMD_DECL;
    1366             :     char      **line;
    1367             :     char      **bki_lines;
    1368             :     char        headerline[MAXPGPATH];
    1369             :     char        buf[64];
    1370             : 
    1371         320 :     printf(_("running bootstrap script ... "));
    1372         320 :     fflush(stdout);
    1373             : 
    1374         320 :     bki_lines = readfile(bki_file);
    1375             : 
    1376             :     /* Check that bki file appears to be of the right version */
    1377             : 
    1378         320 :     snprintf(headerline, sizeof(headerline), "# PostgreSQL %s\n",
    1379             :              PG_MAJORVERSION);
    1380             : 
    1381         320 :     if (strcmp(headerline, *bki_lines) != 0)
    1382             :     {
    1383           0 :         pg_log_error("input file \"%s\" does not belong to PostgreSQL %s",
    1384             :                      bki_file, PG_VERSION);
    1385           0 :         fprintf(stderr,
    1386           0 :                 _("Check your installation or specify the correct path "
    1387             :                   "using the option -L.\n"));
    1388           0 :         exit(1);
    1389             :     }
    1390             : 
    1391             :     /* Substitute for various symbols used in the BKI file */
    1392             : 
    1393         320 :     sprintf(buf, "%d", NAMEDATALEN);
    1394         320 :     bki_lines = replace_token(bki_lines, "NAMEDATALEN", buf);
    1395             : 
    1396         320 :     sprintf(buf, "%d", (int) sizeof(Pointer));
    1397         320 :     bki_lines = replace_token(bki_lines, "SIZEOF_POINTER", buf);
    1398             : 
    1399         320 :     bki_lines = replace_token(bki_lines, "ALIGNOF_POINTER",
    1400             :                               (sizeof(Pointer) == 4) ? "i" : "d");
    1401             : 
    1402         320 :     bki_lines = replace_token(bki_lines, "FLOAT4PASSBYVAL",
    1403             :                               FLOAT4PASSBYVAL ? "true" : "false");
    1404             : 
    1405         320 :     bki_lines = replace_token(bki_lines, "FLOAT8PASSBYVAL",
    1406             :                               FLOAT8PASSBYVAL ? "true" : "false");
    1407             : 
    1408         320 :     bki_lines = replace_token(bki_lines, "POSTGRES",
    1409         320 :                               escape_quotes_bki(username));
    1410             : 
    1411         640 :     bki_lines = replace_token(bki_lines, "ENCODING",
    1412         320 :                               encodingid_to_string(encodingid));
    1413             : 
    1414         320 :     bki_lines = replace_token(bki_lines, "LC_COLLATE",
    1415         320 :                               escape_quotes_bki(lc_collate));
    1416             : 
    1417         320 :     bki_lines = replace_token(bki_lines, "LC_CTYPE",
    1418         320 :                               escape_quotes_bki(lc_ctype));
    1419             : 
    1420             :     /* Also ensure backend isn't confused by this environment var: */
    1421         320 :     unsetenv("PGCLIENTENCODING");
    1422             : 
    1423         640 :     snprintf(cmd, sizeof(cmd),
    1424             :              "\"%s\" --boot -x1 -X %u %s %s %s",
    1425             :              backend_exec,
    1426             :              wal_segment_size_mb * (1024 * 1024),
    1427         320 :              data_checksums ? "-k" : "",
    1428             :              boot_options,
    1429         320 :              debug ? "-d 5" : "");
    1430             : 
    1431             : 
    1432         320 :     PG_CMD_OPEN;
    1433             : 
    1434     2248640 :     for (line = bki_lines; *line != NULL; line++)
    1435             :     {
    1436     2248320 :         PG_CMD_PUTS(*line);
    1437     2248320 :         free(*line);
    1438             :     }
    1439             : 
    1440         320 :     PG_CMD_CLOSE;
    1441             : 
    1442         320 :     free(bki_lines);
    1443             : 
    1444         320 :     check_ok();
    1445         320 : }
    1446             : 
    1447             : /*
    1448             :  * set up the shadow password table
    1449             :  */
    1450             : static void
    1451         320 : setup_auth(FILE *cmdfd)
    1452             : {
    1453             :     const char *const *line;
    1454             :     static const char *const pg_authid_setup[] = {
    1455             :         /*
    1456             :          * The authid table shouldn't be readable except through views, to
    1457             :          * ensure passwords are not publicly visible.
    1458             :          */
    1459             :         "REVOKE ALL on pg_authid FROM public;\n\n",
    1460             :         NULL
    1461             :     };
    1462             : 
    1463         640 :     for (line = pg_authid_setup; *line != NULL; line++)
    1464         320 :         PG_CMD_PUTS(*line);
    1465             : 
    1466         320 :     if (superuser_password)
    1467           0 :         PG_CMD_PRINTF("ALTER USER \"%s\" WITH PASSWORD E'%s';\n\n",
    1468             :                        username, escape_quotes(superuser_password));
    1469         320 : }
    1470             : 
    1471             : /*
    1472             :  * get the superuser password if required
    1473             :  */
    1474             : static void
    1475           0 : get_su_pwd(void)
    1476             : {
    1477             :     char        pwd1[100];
    1478             :     char        pwd2[100];
    1479             : 
    1480           0 :     if (pwprompt)
    1481             :     {
    1482             :         /*
    1483             :          * Read password from terminal
    1484             :          */
    1485           0 :         printf("\n");
    1486           0 :         fflush(stdout);
    1487           0 :         simple_prompt("Enter new superuser password: ", pwd1, sizeof(pwd1), false);
    1488           0 :         simple_prompt("Enter it again: ", pwd2, sizeof(pwd2), false);
    1489           0 :         if (strcmp(pwd1, pwd2) != 0)
    1490             :         {
    1491           0 :             fprintf(stderr, _("Passwords didn't match.\n"));
    1492           0 :             exit(1);
    1493             :         }
    1494             :     }
    1495             :     else
    1496             :     {
    1497             :         /*
    1498             :          * Read password from file
    1499             :          *
    1500             :          * Ideally this should insist that the file not be world-readable.
    1501             :          * However, this option is mainly intended for use on Windows where
    1502             :          * file permissions may not exist at all, so we'll skip the paranoia
    1503             :          * for now.
    1504             :          */
    1505           0 :         FILE       *pwf = fopen(pwfilename, "r");
    1506             :         int         i;
    1507             : 
    1508           0 :         if (!pwf)
    1509             :         {
    1510           0 :             pg_log_error("could not open file \"%s\" for reading: %m",
    1511             :                          pwfilename);
    1512           0 :             exit(1);
    1513             :         }
    1514           0 :         if (!fgets(pwd1, sizeof(pwd1), pwf))
    1515             :         {
    1516           0 :             if (ferror(pwf))
    1517           0 :                 pg_log_error("could not read password from file \"%s\": %m",
    1518             :                              pwfilename);
    1519             :             else
    1520           0 :                 pg_log_error("password file \"%s\" is empty",
    1521             :                              pwfilename);
    1522           0 :             exit(1);
    1523             :         }
    1524           0 :         fclose(pwf);
    1525             : 
    1526           0 :         i = strlen(pwd1);
    1527           0 :         while (i > 0 && (pwd1[i - 1] == '\r' || pwd1[i - 1] == '\n'))
    1528           0 :             pwd1[--i] = '\0';
    1529             :     }
    1530             : 
    1531           0 :     superuser_password = pg_strdup(pwd1);
    1532           0 : }
    1533             : 
    1534             : /*
    1535             :  * set up pg_depend
    1536             :  */
    1537             : static void
    1538         320 : setup_depend(FILE *cmdfd)
    1539             : {
    1540             :     const char *const *line;
    1541             :     static const char *const pg_depend_setup[] = {
    1542             :         /*
    1543             :          * Make PIN entries in pg_depend for all objects made so far in the
    1544             :          * tables that the dependency code handles.  This is overkill (the
    1545             :          * system doesn't really depend on having every last weird datatype,
    1546             :          * for instance) but generating only the minimum required set of
    1547             :          * dependencies seems hard.
    1548             :          *
    1549             :          * Catalogs that are intentionally not scanned here are:
    1550             :          *
    1551             :          * pg_database: it's a feature, not a bug, that template1 is not
    1552             :          * pinned.
    1553             :          *
    1554             :          * pg_extension: a pinned extension isn't really an extension, hmm?
    1555             :          *
    1556             :          * pg_tablespace: tablespaces don't participate in the dependency
    1557             :          * code, and DropTableSpace() explicitly protects the built-in
    1558             :          * tablespaces.
    1559             :          *
    1560             :          * First delete any already-made entries; PINs override all else, and
    1561             :          * must be the only entries for their objects.
    1562             :          */
    1563             :         "DELETE FROM pg_depend;\n\n",
    1564             :         "VACUUM pg_depend;\n\n",
    1565             :         "DELETE FROM pg_shdepend;\n\n",
    1566             :         "VACUUM pg_shdepend;\n\n",
    1567             : 
    1568             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1569             :         " FROM pg_class;\n\n",
    1570             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1571             :         " FROM pg_proc;\n\n",
    1572             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1573             :         " FROM pg_type;\n\n",
    1574             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1575             :         " FROM pg_cast;\n\n",
    1576             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1577             :         " FROM pg_constraint;\n\n",
    1578             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1579             :         " FROM pg_conversion;\n\n",
    1580             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1581             :         " FROM pg_attrdef;\n\n",
    1582             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1583             :         " FROM pg_language;\n\n",
    1584             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1585             :         " FROM pg_operator;\n\n",
    1586             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1587             :         " FROM pg_opclass;\n\n",
    1588             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1589             :         " FROM pg_opfamily;\n\n",
    1590             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1591             :         " FROM pg_am;\n\n",
    1592             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1593             :         " FROM pg_amop;\n\n",
    1594             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1595             :         " FROM pg_amproc;\n\n",
    1596             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1597             :         " FROM pg_rewrite;\n\n",
    1598             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1599             :         " FROM pg_trigger;\n\n",
    1600             : 
    1601             :         /*
    1602             :          * restriction here to avoid pinning the public namespace
    1603             :          */
    1604             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1605             :         " FROM pg_namespace "
    1606             :         "    WHERE nspname LIKE 'pg%';\n\n",
    1607             : 
    1608             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1609             :         " FROM pg_ts_parser;\n\n",
    1610             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1611             :         " FROM pg_ts_dict;\n\n",
    1612             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1613             :         " FROM pg_ts_template;\n\n",
    1614             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1615             :         " FROM pg_ts_config;\n\n",
    1616             :         "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
    1617             :         " FROM pg_collation;\n\n",
    1618             :         "INSERT INTO pg_shdepend SELECT 0,0,0,0, tableoid,oid, 'p' "
    1619             :         " FROM pg_authid;\n\n",
    1620             :         NULL
    1621             :     };
    1622             : 
    1623        8960 :     for (line = pg_depend_setup; *line != NULL; line++)
    1624        8640 :         PG_CMD_PUTS(*line);
    1625         320 : }
    1626             : 
    1627             : /*
    1628             :  * set up system views
    1629             :  */
    1630             : static void
    1631         320 : setup_sysviews(FILE *cmdfd)
    1632             : {
    1633             :     char      **line;
    1634             :     char      **sysviews_setup;
    1635             : 
    1636         320 :     sysviews_setup = readfile(system_views_file);
    1637             : 
    1638      432640 :     for (line = sysviews_setup; *line != NULL; line++)
    1639             :     {
    1640      432320 :         PG_CMD_PUTS(*line);
    1641      432320 :         free(*line);
    1642             :     }
    1643             : 
    1644         320 :     PG_CMD_PUTS("\n\n");
    1645             : 
    1646         320 :     free(sysviews_setup);
    1647         320 : }
    1648             : 
    1649             : /*
    1650             :  * load description data
    1651             :  */
    1652             : static void
    1653         320 : setup_description(FILE *cmdfd)
    1654             : {
    1655         320 :     PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_description ( "
    1656             :                 "  objoid oid, "
    1657             :                 "  classname name, "
    1658             :                 "  objsubid int4, "
    1659             :                 "  description text);\n\n");
    1660             : 
    1661         320 :     PG_CMD_PRINTF("COPY tmp_pg_description FROM E'%s';\n\n",
    1662             :                    escape_quotes(desc_file));
    1663             : 
    1664         320 :     PG_CMD_PUTS("INSERT INTO pg_description "
    1665             :                 " SELECT t.objoid, c.oid, t.objsubid, t.description "
    1666             :                 "  FROM tmp_pg_description t, pg_class c "
    1667             :                 "    WHERE c.relname = t.classname;\n\n");
    1668             : 
    1669         320 :     PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_shdescription ( "
    1670             :                 " objoid oid, "
    1671             :                 " classname name, "
    1672             :                 " description text);\n\n");
    1673             : 
    1674         320 :     PG_CMD_PRINTF("COPY tmp_pg_shdescription FROM E'%s';\n\n",
    1675             :                    escape_quotes(shdesc_file));
    1676             : 
    1677         320 :     PG_CMD_PUTS("INSERT INTO pg_shdescription "
    1678             :                 " SELECT t.objoid, c.oid, t.description "
    1679             :                 "  FROM tmp_pg_shdescription t, pg_class c "
    1680             :                 "   WHERE c.relname = t.classname;\n\n");
    1681             : 
    1682             :     /* Create default descriptions for operator implementation functions */
    1683         320 :     PG_CMD_PUTS("WITH funcdescs AS ( "
    1684             :                 "SELECT p.oid as p_oid, o.oid as o_oid, oprname "
    1685             :                 "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) "
    1686             :                 "INSERT INTO pg_description "
    1687             :                 "  SELECT p_oid, 'pg_proc'::regclass, 0, "
    1688             :                 "    'implementation of ' || oprname || ' operator' "
    1689             :                 "  FROM funcdescs "
    1690             :                 "  WHERE NOT EXISTS (SELECT 1 FROM pg_description "
    1691             :                 "   WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) "
    1692             :                 "  AND NOT EXISTS (SELECT 1 FROM pg_description "
    1693             :                 "   WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass"
    1694             :                 "         AND description LIKE 'deprecated%');\n\n");
    1695             : 
    1696             :     /*
    1697             :      * Even though the tables are temp, drop them explicitly so they don't get
    1698             :      * copied into template0/postgres databases.
    1699             :      */
    1700         320 :     PG_CMD_PUTS("DROP TABLE tmp_pg_description;\n\n");
    1701         320 :     PG_CMD_PUTS("DROP TABLE tmp_pg_shdescription;\n\n");
    1702         320 : }
    1703             : 
    1704             : /*
    1705             :  * populate pg_collation
    1706             :  */
    1707             : static void
    1708         320 : setup_collation(FILE *cmdfd)
    1709             : {
    1710             :     /*
    1711             :      * Add an SQL-standard name.  We don't want to pin this, so it doesn't go
    1712             :      * in pg_collation.h.  But add it before reading system collations, so
    1713             :      * that it wins if libc defines a locale named ucs_basic.
    1714             :      */
    1715         320 :     PG_CMD_PRINTF("INSERT INTO pg_collation (oid, collname, collnamespace, collowner, collprovider, collisdeterministic, collencoding, collcollate, collctype)"
    1716             :                    "VALUES (pg_nextoid('pg_catalog.pg_collation', 'oid', 'pg_catalog.pg_collation_oid_index'), 'ucs_basic', 'pg_catalog'::regnamespace, %u, '%c', true, %d, 'C', 'C');\n\n",
    1717             :                    BOOTSTRAP_SUPERUSERID, COLLPROVIDER_LIBC, PG_UTF8);
    1718             : 
    1719             :     /* Now import all collations we can find in the operating system */
    1720         320 :     PG_CMD_PUTS("SELECT pg_import_system_collations('pg_catalog');\n\n");
    1721         320 : }
    1722             : 
    1723             : /*
    1724             :  * load extra dictionaries (Snowball stemmers)
    1725             :  */
    1726             : static void
    1727         320 : setup_dictionary(FILE *cmdfd)
    1728             : {
    1729             :     char      **line;
    1730             :     char      **conv_lines;
    1731             : 
    1732         320 :     conv_lines = readfile(dictionary_file);
    1733      307200 :     for (line = conv_lines; *line != NULL; line++)
    1734             :     {
    1735      306880 :         PG_CMD_PUTS(*line);
    1736      306880 :         free(*line);
    1737             :     }
    1738             : 
    1739         320 :     PG_CMD_PUTS("\n\n");
    1740             : 
    1741         320 :     free(conv_lines);
    1742         320 : }
    1743             : 
    1744             : /*
    1745             :  * Set up privileges
    1746             :  *
    1747             :  * We mark most system catalogs as world-readable.  We don't currently have
    1748             :  * to touch functions, languages, or databases, because their default
    1749             :  * permissions are OK.
    1750             :  *
    1751             :  * Some objects may require different permissions by default, so we
    1752             :  * make sure we don't overwrite privilege sets that have already been
    1753             :  * set (NOT NULL).
    1754             :  *
    1755             :  * Also populate pg_init_privs to save what the privileges are at init
    1756             :  * time.  This is used by pg_dump to allow users to change privileges
    1757             :  * on catalog objects and to have those privilege changes preserved
    1758             :  * across dump/reload and pg_upgrade.
    1759             :  *
    1760             :  * Note that pg_init_privs is only for per-database objects and therefore
    1761             :  * we don't include databases or tablespaces.
    1762             :  */
    1763             : static void
    1764         320 : setup_privileges(FILE *cmdfd)
    1765             : {
    1766             :     char      **line;
    1767             :     char      **priv_lines;
    1768             :     static char *privileges_setup[] = {
    1769             :         "UPDATE pg_class "
    1770             :         "  SET relacl = (SELECT array_agg(a.acl) FROM "
    1771             :         " (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl "
    1772             :         "  UNION SELECT unnest(pg_catalog.acldefault("
    1773             :         "    CASE WHEN relkind = " CppAsString2(RELKIND_SEQUENCE) " THEN 's' "
    1774             :         "         ELSE 'r' END::\"char\"," CppAsString2(BOOTSTRAP_SUPERUSERID) "::oid))"
    1775             :         " ) as a) "
    1776             :         "  WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ", "
    1777             :         CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
    1778             :         CppAsString2(RELKIND_SEQUENCE) ")"
    1779             :         "  AND relacl IS NULL;\n\n",
    1780             :         "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
    1781             :         "GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
    1782             :         "REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n",
    1783             :         "INSERT INTO pg_init_privs "
    1784             :         "  (objoid, classoid, objsubid, initprivs, privtype)"
    1785             :         "    SELECT"
    1786             :         "        oid,"
    1787             :         "        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
    1788             :         "        0,"
    1789             :         "        relacl,"
    1790             :         "        'i'"
    1791             :         "    FROM"
    1792             :         "        pg_class"
    1793             :         "    WHERE"
    1794             :         "        relacl IS NOT NULL"
    1795             :         "        AND relkind IN (" CppAsString2(RELKIND_RELATION) ", "
    1796             :         CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
    1797             :         CppAsString2(RELKIND_SEQUENCE) ");\n\n",
    1798             :         "INSERT INTO pg_init_privs "
    1799             :         "  (objoid, classoid, objsubid, initprivs, privtype)"
    1800             :         "    SELECT"
    1801             :         "        pg_class.oid,"
    1802             :         "        (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
    1803             :         "        pg_attribute.attnum,"
    1804             :         "        pg_attribute.attacl,"
    1805             :         "        'i'"
    1806             :         "    FROM"
    1807             :         "        pg_class"
    1808             :         "        JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)"
    1809             :         "    WHERE"
    1810             :         "        pg_attribute.attacl IS NOT NULL"
    1811             :         "        AND pg_class.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
    1812             :         CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
    1813             :         CppAsString2(RELKIND_SEQUENCE) ");\n\n",
    1814             :         "INSERT INTO pg_init_privs "
    1815             :         "  (objoid, classoid, objsubid, initprivs, privtype)"
    1816             :         "    SELECT"
    1817             :         "        oid,"
    1818             :         "        (SELECT oid FROM pg_class WHERE relname = 'pg_proc'),"
    1819             :         "        0,"
    1820             :         "        proacl,"
    1821             :         "        'i'"
    1822             :         "    FROM"
    1823             :         "        pg_proc"
    1824             :         "    WHERE"
    1825             :         "        proacl IS NOT NULL;\n\n",
    1826             :         "INSERT INTO pg_init_privs "
    1827             :         "  (objoid, classoid, objsubid, initprivs, privtype)"
    1828             :         "    SELECT"
    1829             :         "        oid,"
    1830             :         "        (SELECT oid FROM pg_class WHERE relname = 'pg_type'),"
    1831             :         "        0,"
    1832             :         "        typacl,"
    1833             :         "        'i'"
    1834             :         "    FROM"
    1835             :         "        pg_type"
    1836             :         "    WHERE"
    1837             :         "        typacl IS NOT NULL;\n\n",
    1838             :         "INSERT INTO pg_init_privs "
    1839             :         "  (objoid, classoid, objsubid, initprivs, privtype)"
    1840             :         "    SELECT"
    1841             :         "        oid,"
    1842             :         "        (SELECT oid FROM pg_class WHERE relname = 'pg_language'),"
    1843             :         "        0,"
    1844             :         "        lanacl,"
    1845             :         "        'i'"
    1846             :         "    FROM"
    1847             :         "        pg_language"
    1848             :         "    WHERE"
    1849             :         "        lanacl IS NOT NULL;\n\n",
    1850             :         "INSERT INTO pg_init_privs "
    1851             :         "  (objoid, classoid, objsubid, initprivs, privtype)"
    1852             :         "    SELECT"
    1853             :         "        oid,"
    1854             :         "        (SELECT oid FROM pg_class WHERE "
    1855             :         "        relname = 'pg_largeobject_metadata'),"
    1856             :         "        0,"
    1857             :         "        lomacl,"
    1858             :         "        'i'"
    1859             :         "    FROM"
    1860             :         "        pg_largeobject_metadata"
    1861             :         "    WHERE"
    1862             :         "        lomacl IS NOT NULL;\n\n",
    1863             :         "INSERT INTO pg_init_privs "
    1864             :         "  (objoid, classoid, objsubid, initprivs, privtype)"
    1865             :         "    SELECT"
    1866             :         "        oid,"
    1867             :         "        (SELECT oid FROM pg_class WHERE relname = 'pg_namespace'),"
    1868             :         "        0,"
    1869             :         "        nspacl,"
    1870             :         "        'i'"
    1871             :         "    FROM"
    1872             :         "        pg_namespace"
    1873             :         "    WHERE"
    1874             :         "        nspacl IS NOT NULL;\n\n",
    1875             :         "INSERT INTO pg_init_privs "
    1876             :         "  (objoid, classoid, objsubid, initprivs, privtype)"
    1877             :         "    SELECT"
    1878             :         "        oid,"
    1879             :         "        (SELECT oid FROM pg_class WHERE "
    1880             :         "        relname = 'pg_foreign_data_wrapper'),"
    1881             :         "        0,"
    1882             :         "        fdwacl,"
    1883             :         "        'i'"
    1884             :         "    FROM"
    1885             :         "        pg_foreign_data_wrapper"
    1886             :         "    WHERE"
    1887             :         "        fdwacl IS NOT NULL;\n\n",
    1888             :         "INSERT INTO pg_init_privs "
    1889             :         "  (objoid, classoid, objsubid, initprivs, privtype)"
    1890             :         "    SELECT"
    1891             :         "        oid,"
    1892             :         "        (SELECT oid FROM pg_class "
    1893             :         "        WHERE relname = 'pg_foreign_server'),"
    1894             :         "        0,"
    1895             :         "        srvacl,"
    1896             :         "        'i'"
    1897             :         "    FROM"
    1898             :         "        pg_foreign_server"
    1899             :         "    WHERE"
    1900             :         "        srvacl IS NOT NULL;\n\n",
    1901             :         NULL
    1902             :     };
    1903             : 
    1904         320 :     priv_lines = replace_token(privileges_setup, "$POSTGRES_SUPERUSERNAME",
    1905         320 :                                escape_quotes(username));
    1906        4480 :     for (line = priv_lines; *line != NULL; line++)
    1907        4160 :         PG_CMD_PUTS(*line);
    1908         320 : }
    1909             : 
    1910             : /*
    1911             :  * extract the strange version of version required for information schema
    1912             :  * (09.08.0007abc)
    1913             :  */
    1914             : static void
    1915         326 : set_info_version(void)
    1916             : {
    1917             :     char       *letterversion;
    1918         326 :     long        major = 0,
    1919         326 :                 minor = 0,
    1920         326 :                 micro = 0;
    1921             :     char       *endptr;
    1922         326 :     char       *vstr = pg_strdup(PG_VERSION);
    1923             :     char       *ptr;
    1924             : 
    1925         326 :     ptr = vstr + (strlen(vstr) - 1);
    1926        2282 :     while (ptr != vstr && (*ptr < '0' || *ptr > '9'))
    1927        1630 :         ptr--;
    1928         326 :     letterversion = ptr + 1;
    1929         326 :     major = strtol(vstr, &endptr, 10);
    1930         326 :     if (*endptr)
    1931         326 :         minor = strtol(endptr + 1, &endptr, 10);
    1932         326 :     if (*endptr)
    1933         326 :         micro = strtol(endptr + 1, &endptr, 10);
    1934         326 :     snprintf(infoversion, sizeof(infoversion), "%02ld.%02ld.%04ld%s",
    1935             :              major, minor, micro, letterversion);
    1936         326 : }
    1937             : 
    1938             : /*
    1939             :  * load info schema and populate from features file
    1940             :  */
    1941             : static void
    1942         320 : setup_schema(FILE *cmdfd)
    1943             : {
    1944             :     char      **line;
    1945             :     char      **lines;
    1946             : 
    1947         320 :     lines = readfile(info_schema_file);
    1948             : 
    1949      960000 :     for (line = lines; *line != NULL; line++)
    1950             :     {
    1951      959680 :         PG_CMD_PUTS(*line);
    1952      959680 :         free(*line);
    1953             :     }
    1954             : 
    1955         320 :     PG_CMD_PUTS("\n\n");
    1956             : 
    1957         320 :     free(lines);
    1958             : 
    1959         320 :     PG_CMD_PRINTF("UPDATE information_schema.sql_implementation_info "
    1960             :                    "  SET character_value = '%s' "
    1961             :                    "  WHERE implementation_info_name = 'DBMS VERSION';\n\n",
    1962             :                    infoversion);
    1963             : 
    1964         320 :     PG_CMD_PRINTF("COPY information_schema.sql_features "
    1965             :                    "  (feature_id, feature_name, sub_feature_id, "
    1966             :                    "  sub_feature_name, is_supported, comments) "
    1967             :                    " FROM E'%s';\n\n",
    1968             :                    escape_quotes(features_file));
    1969         320 : }
    1970             : 
    1971             : /*
    1972             :  * load PL/pgSQL server-side language
    1973             :  */
    1974             : static void
    1975         320 : load_plpgsql(FILE *cmdfd)
    1976             : {
    1977         320 :     PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n\n");
    1978         320 : }
    1979             : 
    1980             : /*
    1981             :  * clean everything up in template1
    1982             :  */
    1983             : static void
    1984         320 : vacuum_db(FILE *cmdfd)
    1985             : {
    1986             :     /* Run analyze before VACUUM so the statistics are frozen. */
    1987         320 :     PG_CMD_PUTS("ANALYZE;\n\nVACUUM FREEZE;\n\n");
    1988         320 : }
    1989             : 
    1990             : /*
    1991             :  * copy template1 to template0
    1992             :  */
    1993             : static void
    1994         320 : make_template0(FILE *cmdfd)
    1995             : {
    1996             :     const char *const *line;
    1997             :     static const char *const template0_setup[] = {
    1998             :         "CREATE DATABASE template0 IS_TEMPLATE = true ALLOW_CONNECTIONS = false;\n\n",
    1999             : 
    2000             :         /*
    2001             :          * We use the OID of template0 to determine datlastsysoid
    2002             :          */
    2003             :         "UPDATE pg_database SET datlastsysoid = "
    2004             :         "    (SELECT oid FROM pg_database "
    2005             :         "    WHERE datname = 'template0');\n\n",
    2006             : 
    2007             :         /*
    2008             :          * Explicitly revoke public create-schema and create-temp-table
    2009             :          * privileges in template1 and template0; else the latter would be on
    2010             :          * by default
    2011             :          */
    2012             :         "REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n\n",
    2013             :         "REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n\n",
    2014             : 
    2015             :         "COMMENT ON DATABASE template0 IS 'unmodifiable empty database';\n\n",
    2016             : 
    2017             :         /*
    2018             :          * Finally vacuum to clean up dead rows in pg_database
    2019             :          */
    2020             :         "VACUUM pg_database;\n\n",
    2021             :         NULL
    2022             :     };
    2023             : 
    2024        2240 :     for (line = template0_setup; *line; line++)
    2025        1920 :         PG_CMD_PUTS(*line);
    2026         320 : }
    2027             : 
    2028             : /*
    2029             :  * copy template1 to postgres
    2030             :  */
    2031             : static void
    2032         320 : make_postgres(FILE *cmdfd)
    2033             : {
    2034             :     const char *const *line;
    2035             :     static const char *const postgres_setup[] = {
    2036             :         "CREATE DATABASE postgres;\n\n",
    2037             :         "COMMENT ON DATABASE postgres IS 'default administrative connection database';\n\n",
    2038             :         NULL
    2039             :     };
    2040             : 
    2041         960 :     for (line = postgres_setup; *line; line++)
    2042         640 :         PG_CMD_PUTS(*line);
    2043         320 : }
    2044             : 
    2045             : /*
    2046             :  * signal handler in case we are interrupted.
    2047             :  *
    2048             :  * The Windows runtime docs at
    2049             :  * http://msdn.microsoft.com/library/en-us/vclib/html/_crt_signal.asp
    2050             :  * specifically forbid a number of things being done from a signal handler,
    2051             :  * including IO, memory allocation and system calls, and only allow jmpbuf
    2052             :  * if you are handling SIGFPE.
    2053             :  *
    2054             :  * I avoided doing the forbidden things by setting a flag instead of calling
    2055             :  * exit() directly.
    2056             :  *
    2057             :  * Also note the behaviour of Windows with SIGINT, which says this:
    2058             :  *   Note   SIGINT is not supported for any Win32 application, including
    2059             :  *   Windows 98/Me and Windows NT/2000/XP. When a CTRL+C interrupt occurs,
    2060             :  *   Win32 operating systems generate a new thread to specifically handle
    2061             :  *   that interrupt. This can cause a single-thread application such as UNIX,
    2062             :  *   to become multithreaded, resulting in unexpected behavior.
    2063             :  *
    2064             :  * I have no idea how to handle this. (Strange they call UNIX an application!)
    2065             :  * So this will need some testing on Windows.
    2066             :  */
    2067             : static void
    2068           0 : trapsig(int signum)
    2069             : {
    2070             :     /* handle systems that reset the handler, like Windows (grr) */
    2071           0 :     pqsignal(signum, trapsig);
    2072           0 :     caught_signal = true;
    2073           0 : }
    2074             : 
    2075             : /*
    2076             :  * call exit() if we got a signal, or else output "ok".
    2077             :  */
    2078             : static void
    2079        1612 : check_ok(void)
    2080             : {
    2081        1612 :     if (caught_signal)
    2082             :     {
    2083           0 :         printf(_("caught signal\n"));
    2084           0 :         fflush(stdout);
    2085           0 :         exit(1);
    2086             :     }
    2087        1612 :     else if (output_failed)
    2088             :     {
    2089           0 :         printf(_("could not write to child process: %s\n"),
    2090             :                strerror(output_errno));
    2091           0 :         fflush(stdout);
    2092           0 :         exit(1);
    2093             :     }
    2094             :     else
    2095             :     {
    2096             :         /* all seems well */
    2097        1612 :         printf(_("ok\n"));
    2098        1612 :         fflush(stdout);
    2099             :     }
    2100        1612 : }
    2101             : 
    2102             : /* Hack to suppress a warning about %x from some versions of gcc */
    2103             : static inline size_t
    2104         320 : my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
    2105             : {
    2106         320 :     return strftime(s, max, fmt, tm);
    2107             : }
    2108             : 
    2109             : /*
    2110             :  * Determine likely date order from locale
    2111             :  */
    2112             : static int
    2113         320 : locale_date_order(const char *locale)
    2114             : {
    2115             :     struct tm   testtime;
    2116             :     char        buf[128];
    2117             :     char       *posD;
    2118             :     char       *posM;
    2119             :     char       *posY;
    2120             :     char       *save;
    2121             :     size_t      res;
    2122             :     int         result;
    2123             : 
    2124         320 :     result = DATEORDER_MDY;     /* default */
    2125             : 
    2126         320 :     save = setlocale(LC_TIME, NULL);
    2127         320 :     if (!save)
    2128           0 :         return result;
    2129         320 :     save = pg_strdup(save);
    2130             : 
    2131         320 :     setlocale(LC_TIME, locale);
    2132             : 
    2133         320 :     memset(&testtime, 0, sizeof(testtime));
    2134         320 :     testtime.tm_mday = 22;
    2135         320 :     testtime.tm_mon = 10;       /* November, should come out as "11" */
    2136         320 :     testtime.tm_year = 133;     /* 2033 */
    2137             : 
    2138         320 :     res = my_strftime(buf, sizeof(buf), "%x", &testtime);
    2139             : 
    2140         320 :     setlocale(LC_TIME, save);
    2141         320 :     free(save);
    2142             : 
    2143         320 :     if (res == 0)
    2144           0 :         return result;
    2145             : 
    2146         320 :     posM = strstr(buf, "11");
    2147         320 :     posD = strstr(buf, "22");
    2148         320 :     posY = strstr(buf, "33");
    2149             : 
    2150         320 :     if (!posM || !posD || !posY)
    2151           0 :         return result;
    2152             : 
    2153         320 :     if (posY < posM && posM < posD)
    2154           0 :         result = DATEORDER_YMD;
    2155         320 :     else if (posD < posM)
    2156           0 :         result = DATEORDER_DMY;
    2157             :     else
    2158         320 :         result = DATEORDER_MDY;
    2159             : 
    2160         320 :     return result;
    2161             : }
    2162             : 
    2163             : /*
    2164             :  * Verify that locale name is valid for the locale category.
    2165             :  *
    2166             :  * If successful, and canonname isn't NULL, a malloc'd copy of the locale's
    2167             :  * canonical name is stored there.  This is especially useful for figuring out
    2168             :  * what locale name "" means (ie, the environment value).  (Actually,
    2169             :  * it seems that on most implementations that's the only thing it's good for;
    2170             :  * we could wish that setlocale gave back a canonically spelled version of
    2171             :  * the locale name, but typically it doesn't.)
    2172             :  *
    2173             :  * this should match the backend's check_locale() function
    2174             :  */
    2175             : static void
    2176        1956 : check_locale_name(int category, const char *locale, char **canonname)
    2177             : {
    2178             :     char       *save;
    2179             :     char       *res;
    2180             : 
    2181        1956 :     if (canonname)
    2182        1956 :         *canonname = NULL;      /* in case of failure */
    2183             : 
    2184        1956 :     save = setlocale(category, NULL);
    2185        1956 :     if (!save)
    2186             :     {
    2187           0 :         pg_log_error("setlocale() failed");
    2188           0 :         exit(1);
    2189             :     }
    2190             : 
    2191             :     /* save may be pointing at a modifiable scratch variable, so copy it. */
    2192        1956 :     save = pg_strdup(save);
    2193             : 
    2194             :     /* for setlocale() call */
    2195        1956 :     if (!locale)
    2196        1860 :         locale = "";
    2197             : 
    2198             :     /* set the locale with setlocale, to see if it accepts it. */
    2199        1956 :     res = setlocale(category, locale);
    2200             : 
    2201             :     /* save canonical name if requested. */
    2202        1956 :     if (res && canonname)
    2203        1956 :         *canonname = pg_strdup(res);
    2204             : 
    2205             :     /* restore old value. */
    2206        1956 :     if (!setlocale(category, save))
    2207             :     {
    2208           0 :         pg_log_error("failed to restore old locale \"%s\"", save);
    2209           0 :         exit(1);
    2210             :     }
    2211        1956 :     free(save);
    2212             : 
    2213             :     /* complain if locale wasn't valid */
    2214        1956 :     if (res == NULL)
    2215             :     {
    2216           0 :         if (*locale)
    2217           0 :             pg_log_error("invalid locale name \"%s\"", locale);
    2218             :         else
    2219             :         {
    2220             :             /*
    2221             :              * If no relevant switch was given on command line, locale is an
    2222             :              * empty string, which is not too helpful to report.  Presumably
    2223             :              * setlocale() found something it did not like in the environment.
    2224             :              * Ideally we'd report the bad environment variable, but since
    2225             :              * setlocale's behavior is implementation-specific, it's hard to
    2226             :              * be sure what it didn't like.  Print a safe generic message.
    2227             :              */
    2228           0 :             pg_log_error("invalid locale settings; check LANG and LC_* environment variables");
    2229             :         }
    2230           0 :         exit(1);
    2231             :     }
    2232        1956 : }
    2233             : 
    2234             : /*
    2235             :  * check if the chosen encoding matches the encoding required by the locale
    2236             :  *
    2237             :  * this should match the similar check in the backend createdb() function
    2238             :  */
    2239             : static bool
    2240         652 : check_locale_encoding(const char *locale, int user_enc)
    2241             : {
    2242             :     int         locale_enc;
    2243             : 
    2244         652 :     locale_enc = pg_get_encoding_from_locale(locale, true);
    2245             : 
    2246             :     /* See notes in createdb() to understand these tests */
    2247         652 :     if (!(locale_enc == user_enc ||
    2248           0 :           locale_enc == PG_SQL_ASCII ||
    2249             :           locale_enc == -1 ||
    2250             : #ifdef WIN32
    2251             :           user_enc == PG_UTF8 ||
    2252             : #endif
    2253             :           user_enc == PG_SQL_ASCII))
    2254             :     {
    2255           0 :         pg_log_error("encoding mismatch");
    2256           0 :         fprintf(stderr,
    2257           0 :                 _("The encoding you selected (%s) and the encoding that the\n"
    2258             :                   "selected locale uses (%s) do not match.  This would lead to\n"
    2259             :                   "misbehavior in various character string processing functions.\n"
    2260             :                   "Rerun %s and either do not specify an encoding explicitly,\n"
    2261             :                   "or choose a matching combination.\n"),
    2262             :                 pg_encoding_to_char(user_enc),
    2263             :                 pg_encoding_to_char(locale_enc),
    2264             :                 progname);
    2265           0 :         return false;
    2266             :     }
    2267         652 :     return true;
    2268             : }
    2269             : 
    2270             : /*
    2271             :  * set up the locale variables
    2272             :  *
    2273             :  * assumes we have called setlocale(LC_ALL, "") -- see set_pglocale_pgservice
    2274             :  */
    2275             : static void
    2276         326 : setlocales(void)
    2277             : {
    2278             :     char       *canonname;
    2279             : 
    2280             :     /* set empty lc_* values to locale config if set */
    2281             : 
    2282         326 :     if (locale)
    2283             :     {
    2284          16 :         if (!lc_ctype)
    2285          16 :             lc_ctype = locale;
    2286          16 :         if (!lc_collate)
    2287          16 :             lc_collate = locale;
    2288          16 :         if (!lc_numeric)
    2289          16 :             lc_numeric = locale;
    2290          16 :         if (!lc_time)
    2291          16 :             lc_time = locale;
    2292          16 :         if (!lc_monetary)
    2293          16 :             lc_monetary = locale;
    2294          16 :         if (!lc_messages)
    2295          16 :             lc_messages = locale;
    2296             :     }
    2297             : 
    2298             :     /*
    2299             :      * canonicalize locale names, and obtain any missing values from our
    2300             :      * current environment
    2301             :      */
    2302             : 
    2303         326 :     check_locale_name(LC_CTYPE, lc_ctype, &canonname);
    2304         326 :     lc_ctype = canonname;
    2305         326 :     check_locale_name(LC_COLLATE, lc_collate, &canonname);
    2306         326 :     lc_collate = canonname;
    2307         326 :     check_locale_name(LC_NUMERIC, lc_numeric, &canonname);
    2308         326 :     lc_numeric = canonname;
    2309         326 :     check_locale_name(LC_TIME, lc_time, &canonname);
    2310         326 :     lc_time = canonname;
    2311         326 :     check_locale_name(LC_MONETARY, lc_monetary, &canonname);
    2312         326 :     lc_monetary = canonname;
    2313             : #if defined(LC_MESSAGES) && !defined(WIN32)
    2314         326 :     check_locale_name(LC_MESSAGES, lc_messages, &canonname);
    2315         326 :     lc_messages = canonname;
    2316             : #else
    2317             :     /* when LC_MESSAGES is not available, use the LC_CTYPE setting */
    2318             :     check_locale_name(LC_CTYPE, lc_messages, &canonname);
    2319             :     lc_messages = canonname;
    2320             : #endif
    2321         326 : }
    2322             : 
    2323             : /*
    2324             :  * print help text
    2325             :  */
    2326             : static void
    2327           2 : usage(const char *progname)
    2328             : {
    2329           2 :     printf(_("%s initializes a PostgreSQL database cluster.\n\n"), progname);
    2330           2 :     printf(_("Usage:\n"));
    2331           2 :     printf(_("  %s [OPTION]... [DATADIR]\n"), progname);
    2332           2 :     printf(_("\nOptions:\n"));
    2333           2 :     printf(_("  -A, --auth=METHOD         default authentication method for local connections\n"));
    2334           2 :     printf(_("      --auth-host=METHOD    default authentication method for local TCP/IP connections\n"));
    2335           2 :     printf(_("      --auth-local=METHOD   default authentication method for local-socket connections\n"));
    2336           2 :     printf(_(" [-D, --pgdata=]DATADIR     location for this database cluster\n"));
    2337           2 :     printf(_("  -E, --encoding=ENCODING   set default encoding for new databases\n"));
    2338           2 :     printf(_("  -g, --allow-group-access  allow group read/execute on data directory\n"));
    2339           2 :     printf(_("      --locale=LOCALE       set default locale for new databases\n"));
    2340           2 :     printf(_("      --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n"
    2341             :              "      --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n"
    2342             :              "                            set default locale in the respective category for\n"
    2343             :              "                            new databases (default taken from environment)\n"));
    2344           2 :     printf(_("      --no-locale           equivalent to --locale=C\n"));
    2345           2 :     printf(_("      --pwfile=FILE         read password for the new superuser from file\n"));
    2346           2 :     printf(_("  -T, --text-search-config=CFG\n"
    2347             :              "                            default text search configuration\n"));
    2348           2 :     printf(_("  -U, --username=NAME       database superuser name\n"));
    2349           2 :     printf(_("  -W, --pwprompt            prompt for a password for the new superuser\n"));
    2350           2 :     printf(_("  -X, --waldir=WALDIR       location for the write-ahead log directory\n"));
    2351           2 :     printf(_("      --wal-segsize=SIZE    size of WAL segments, in megabytes\n"));
    2352           2 :     printf(_("\nLess commonly used options:\n"));
    2353           2 :     printf(_("  -d, --debug               generate lots of debugging output\n"));
    2354           2 :     printf(_("  -k, --data-checksums      use data page checksums\n"));
    2355           2 :     printf(_("  -L DIRECTORY              where to find the input files\n"));
    2356           2 :     printf(_("  -n, --no-clean            do not clean up after errors\n"));
    2357           2 :     printf(_("  -N, --no-sync             do not wait for changes to be written safely to disk\n"));
    2358           2 :     printf(_("  -s, --show                show internal settings\n"));
    2359           2 :     printf(_("  -S, --sync-only           only sync data directory\n"));
    2360           2 :     printf(_("\nOther options:\n"));
    2361           2 :     printf(_("  -V, --version             output version information, then exit\n"));
    2362           2 :     printf(_("  -?, --help                show this help, then exit\n"));
    2363           2 :     printf(_("\nIf the data directory is not specified, the environment variable PGDATA\n"
    2364             :              "is used.\n"));
    2365           2 :     printf(_("\nReport bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
    2366           2 : }
    2367             : 
    2368             : static void
    2369         656 : check_authmethod_unspecified(const char **authmethod)
    2370             : {
    2371         656 :     if (*authmethod == NULL)
    2372             :     {
    2373         284 :         authwarning = true;
    2374         284 :         *authmethod = "trust";
    2375             :     }
    2376         656 : }
    2377             : 
    2378             : static void
    2379         656 : check_authmethod_valid(const char *authmethod, const char *const *valid_methods, const char *conntype)
    2380             : {
    2381             :     const char *const *p;
    2382             : 
    2383         656 :     for (p = valid_methods; *p; p++)
    2384             :     {
    2385         656 :         if (strcmp(authmethod, *p) == 0)
    2386         656 :             return;
    2387             :         /* with space = param */
    2388           0 :         if (strchr(authmethod, ' '))
    2389           0 :             if (strncmp(authmethod, *p, (authmethod - strchr(authmethod, ' '))) == 0)
    2390           0 :                 return;
    2391             :     }
    2392             : 
    2393           0 :     pg_log_error("invalid authentication method \"%s\" for \"%s\" connections",
    2394             :                  authmethod, conntype);
    2395           0 :     exit(1);
    2396             : }
    2397             : 
    2398             : static void
    2399         328 : check_need_password(const char *authmethodlocal, const char *authmethodhost)
    2400             : {
    2401         656 :     if ((strcmp(authmethodlocal, "md5") == 0 ||
    2402         656 :          strcmp(authmethodlocal, "password") == 0 ||
    2403         328 :          strcmp(authmethodlocal, "scram-sha-256") == 0) &&
    2404           0 :         (strcmp(authmethodhost, "md5") == 0 ||
    2405           0 :          strcmp(authmethodhost, "password") == 0 ||
    2406           0 :          strcmp(authmethodhost, "scram-sha-256") == 0) &&
    2407           0 :         !(pwprompt || pwfilename))
    2408             :     {
    2409           0 :         pg_log_error("must specify a password for the superuser to enable %s authentication",
    2410             :                      (strcmp(authmethodlocal, "md5") == 0 ||
    2411             :                       strcmp(authmethodlocal, "password") == 0 ||
    2412             :                       strcmp(authmethodlocal, "scram-sha-256") == 0)
    2413             :                      ? authmethodlocal
    2414             :                      : authmethodhost);
    2415           0 :         exit(1);
    2416             :     }
    2417         328 : }
    2418             : 
    2419             : 
    2420             : void
    2421         334 : setup_pgdata(void)
    2422             : {
    2423             :     char       *pgdata_get_env,
    2424             :                *pgdata_set_env;
    2425             : 
    2426         334 :     if (!pg_data)
    2427             :     {
    2428           4 :         pgdata_get_env = getenv("PGDATA");
    2429           4 :         if (pgdata_get_env && strlen(pgdata_get_env))
    2430             :         {
    2431             :             /* PGDATA found */
    2432           4 :             pg_data = pg_strdup(pgdata_get_env);
    2433             :         }
    2434             :         else
    2435             :         {
    2436           0 :             pg_log_error("no data directory specified");
    2437           0 :             fprintf(stderr,
    2438           0 :                     _("You must identify the directory where the data for this database system\n"
    2439             :                       "will reside.  Do this with either the invocation option -D or the\n"
    2440             :                       "environment variable PGDATA.\n"));
    2441           0 :             exit(1);
    2442             :         }
    2443             :     }
    2444             : 
    2445         334 :     pgdata_native = pg_strdup(pg_data);
    2446         334 :     canonicalize_path(pg_data);
    2447             : 
    2448             :     /*
    2449             :      * we have to set PGDATA for postgres rather than pass it on the command
    2450             :      * line to avoid dumb quoting problems on Windows, and we would especially
    2451             :      * need quotes otherwise on Windows because paths there are most likely to
    2452             :      * have embedded spaces.
    2453             :      */
    2454         334 :     pgdata_set_env = psprintf("PGDATA=%s", pg_data);
    2455         334 :     putenv(pgdata_set_env);
    2456         334 : }
    2457             : 
    2458             : 
    2459             : void
    2460         328 : setup_bin_paths(const char *argv0)
    2461             : {
    2462             :     int         ret;
    2463             : 
    2464         328 :     if ((ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
    2465             :                                backend_exec)) < 0)
    2466             :     {
    2467             :         char        full_path[MAXPGPATH];
    2468             : 
    2469           0 :         if (find_my_exec(argv0, full_path) < 0)
    2470           0 :             strlcpy(full_path, progname, sizeof(full_path));
    2471             : 
    2472           0 :         if (ret == -1)
    2473           0 :             pg_log_error("The program \"postgres\" is needed by %s but was not found in the\n"
    2474             :                          "same directory as \"%s\".\n"
    2475             :                          "Check your installation.",
    2476             :                          progname, full_path);
    2477             :         else
    2478           0 :             pg_log_error("The program \"postgres\" was found by \"%s\"\n"
    2479             :                          "but was not the same version as %s.\n"
    2480             :                          "Check your installation.",
    2481             :                          full_path, progname);
    2482           0 :         exit(1);
    2483             :     }
    2484             : 
    2485             :     /* store binary directory */
    2486         328 :     strcpy(bin_path, backend_exec);
    2487         328 :     *last_dir_separator(bin_path) = '\0';
    2488         328 :     canonicalize_path(bin_path);
    2489             : 
    2490         328 :     if (!share_path)
    2491             :     {
    2492         328 :         share_path = pg_malloc(MAXPGPATH);
    2493         328 :         get_share_path(backend_exec, share_path);
    2494             :     }
    2495           0 :     else if (!is_absolute_path(share_path))
    2496             :     {
    2497           0 :         pg_log_error("input file location must be an absolute path");
    2498           0 :         exit(1);
    2499             :     }
    2500             : 
    2501         328 :     canonicalize_path(share_path);
    2502         328 : }
    2503             : 
    2504             : void
    2505         326 : setup_locale_encoding(void)
    2506             : {
    2507         326 :     setlocales();
    2508             : 
    2509         652 :     if (strcmp(lc_ctype, lc_collate) == 0 &&
    2510         652 :         strcmp(lc_ctype, lc_time) == 0 &&
    2511         652 :         strcmp(lc_ctype, lc_numeric) == 0 &&
    2512         652 :         strcmp(lc_ctype, lc_monetary) == 0 &&
    2513         326 :         strcmp(lc_ctype, lc_messages) == 0)
    2514          20 :         printf(_("The database cluster will be initialized with locale \"%s\".\n"), lc_ctype);
    2515             :     else
    2516             :     {
    2517         306 :         printf(_("The database cluster will be initialized with locales\n"
    2518             :                  "  COLLATE:  %s\n"
    2519             :                  "  CTYPE:    %s\n"
    2520             :                  "  MESSAGES: %s\n"
    2521             :                  "  MONETARY: %s\n"
    2522             :                  "  NUMERIC:  %s\n"
    2523             :                  "  TIME:     %s\n"),
    2524             :                lc_collate,
    2525             :                lc_ctype,
    2526             :                lc_messages,
    2527             :                lc_monetary,
    2528             :                lc_numeric,
    2529             :                lc_time);
    2530             :     }
    2531             : 
    2532         326 :     if (!encoding)
    2533             :     {
    2534             :         int         ctype_enc;
    2535             : 
    2536         312 :         ctype_enc = pg_get_encoding_from_locale(lc_ctype, true);
    2537             : 
    2538         312 :         if (ctype_enc == -1)
    2539             :         {
    2540             :             /* Couldn't recognize the locale's codeset */
    2541           0 :             pg_log_error("could not find suitable encoding for locale \"%s\"",
    2542             :                          lc_ctype);
    2543           0 :             fprintf(stderr, _("Rerun %s with the -E option.\n"), progname);
    2544           0 :             fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    2545             :                     progname);
    2546           0 :             exit(1);
    2547             :         }
    2548         312 :         else if (!pg_valid_server_encoding_id(ctype_enc))
    2549             :         {
    2550             :             /*
    2551             :              * We recognized it, but it's not a legal server encoding. On
    2552             :              * Windows, UTF-8 works with any locale, so we can fall back to
    2553             :              * UTF-8.
    2554             :              */
    2555             : #ifdef WIN32
    2556             :             encodingid = PG_UTF8;
    2557             :             printf(_("Encoding \"%s\" implied by locale is not allowed as a server-side encoding.\n"
    2558             :                      "The default database encoding will be set to \"%s\" instead.\n"),
    2559             :                    pg_encoding_to_char(ctype_enc),
    2560             :                    pg_encoding_to_char(encodingid));
    2561             : #else
    2562           0 :             pg_log_error("locale \"%s\" requires unsupported encoding \"%s\"",
    2563             :                          lc_ctype, pg_encoding_to_char(ctype_enc));
    2564           0 :             fprintf(stderr,
    2565           0 :                     _("Encoding \"%s\" is not allowed as a server-side encoding.\n"
    2566             :                       "Rerun %s with a different locale selection.\n"),
    2567             :                     pg_encoding_to_char(ctype_enc), progname);
    2568           0 :             exit(1);
    2569             : #endif
    2570             :         }
    2571             :         else
    2572             :         {
    2573         312 :             encodingid = ctype_enc;
    2574         312 :             printf(_("The default database encoding has accordingly been set to \"%s\".\n"),
    2575             :                    pg_encoding_to_char(encodingid));
    2576             :         }
    2577             :     }
    2578             :     else
    2579          14 :         encodingid = get_encoding_id(encoding);
    2580             : 
    2581         652 :     if (!check_locale_encoding(lc_ctype, encodingid) ||
    2582         326 :         !check_locale_encoding(lc_collate, encodingid))
    2583           0 :         exit(1);                /* check_locale_encoding printed the error */
    2584             : 
    2585         326 : }
    2586             : 
    2587             : 
    2588             : void
    2589         326 : setup_data_file_paths(void)
    2590             : {
    2591         326 :     set_input(&bki_file, "postgres.bki");
    2592         326 :     set_input(&desc_file, "postgres.description");
    2593         326 :     set_input(&shdesc_file, "postgres.shdescription");
    2594         326 :     set_input(&hba_file, "pg_hba.conf.sample");
    2595         326 :     set_input(&ident_file, "pg_ident.conf.sample");
    2596         326 :     set_input(&conf_file, "postgresql.conf.sample");
    2597         326 :     set_input(&dictionary_file, "snowball_create.sql");
    2598         326 :     set_input(&info_schema_file, "information_schema.sql");
    2599         326 :     set_input(&features_file, "sql_features.txt");
    2600         326 :     set_input(&system_views_file, "system_views.sql");
    2601             : 
    2602         326 :     if (show_setting || debug)
    2603             :     {
    2604           0 :         fprintf(stderr,
    2605             :                 "VERSION=%s\n"
    2606             :                 "PGDATA=%s\nshare_path=%s\nPGPATH=%s\n"
    2607             :                 "POSTGRES_SUPERUSERNAME=%s\nPOSTGRES_BKI=%s\n"
    2608             :                 "POSTGRES_DESCR=%s\nPOSTGRES_SHDESCR=%s\n"
    2609             :                 "POSTGRESQL_CONF_SAMPLE=%s\n"
    2610             :                 "PG_HBA_SAMPLE=%s\nPG_IDENT_SAMPLE=%s\n",
    2611             :                 PG_VERSION,
    2612             :                 pg_data, share_path, bin_path,
    2613             :                 username, bki_file,
    2614             :                 desc_file, shdesc_file,
    2615             :                 conf_file,
    2616             :                 hba_file, ident_file);
    2617           0 :         if (show_setting)
    2618           0 :             exit(0);
    2619             :     }
    2620             : 
    2621         326 :     check_input(bki_file);
    2622         326 :     check_input(desc_file);
    2623         326 :     check_input(shdesc_file);
    2624         326 :     check_input(hba_file);
    2625         326 :     check_input(ident_file);
    2626         326 :     check_input(conf_file);
    2627         326 :     check_input(dictionary_file);
    2628         326 :     check_input(info_schema_file);
    2629         326 :     check_input(features_file);
    2630         326 :     check_input(system_views_file);
    2631         326 : }
    2632             : 
    2633             : 
    2634             : void
    2635         326 : setup_text_search(void)
    2636             : {
    2637         326 :     if (!default_text_search_config)
    2638             :     {
    2639         324 :         default_text_search_config = find_matching_ts_config(lc_ctype);
    2640         324 :         if (!default_text_search_config)
    2641             :         {
    2642           0 :             pg_log_info("could not find suitable text search configuration for locale \"%s\"",
    2643             :                         lc_ctype);
    2644           0 :             default_text_search_config = "simple";
    2645             :         }
    2646             :     }
    2647             :     else
    2648             :     {
    2649           2 :         const char *checkmatch = find_matching_ts_config(lc_ctype);
    2650             : 
    2651           2 :         if (checkmatch == NULL)
    2652             :         {
    2653           0 :             pg_log_warning("suitable text search configuration for locale \"%s\" is unknown",
    2654             :                            lc_ctype);
    2655             :         }
    2656           2 :         else if (strcmp(checkmatch, default_text_search_config) != 0)
    2657             :         {
    2658           2 :             pg_log_warning("specified text search configuration \"%s\" might not match locale \"%s\"",
    2659             :                            default_text_search_config, lc_ctype);
    2660             :         }
    2661             :     }
    2662             : 
    2663         326 :     printf(_("The default text search configuration will be set to \"%s\".\n"),
    2664             :            default_text_search_config);
    2665             : 
    2666         326 : }
    2667             : 
    2668             : 
    2669             : void
    2670         326 : setup_signals(void)
    2671             : {
    2672             :     /* some of these are not valid on Windows */
    2673             : #ifdef SIGHUP
    2674         326 :     pqsignal(SIGHUP, trapsig);
    2675             : #endif
    2676             : #ifdef SIGINT
    2677         326 :     pqsignal(SIGINT, trapsig);
    2678             : #endif
    2679             : #ifdef SIGQUIT
    2680         326 :     pqsignal(SIGQUIT, trapsig);
    2681             : #endif
    2682             : #ifdef SIGTERM
    2683         326 :     pqsignal(SIGTERM, trapsig);
    2684             : #endif
    2685             : 
    2686             :     /* Ignore SIGPIPE when writing to backend, so we can clean up */
    2687             : #ifdef SIGPIPE
    2688         326 :     pqsignal(SIGPIPE, SIG_IGN);
    2689             : #endif
    2690             : 
    2691             :     /* Prevent SIGSYS so we can probe for kernel calls that might not work */
    2692             : #ifdef SIGSYS
    2693         326 :     pqsignal(SIGSYS, SIG_IGN);
    2694             : #endif
    2695         326 : }
    2696             : 
    2697             : 
    2698             : void
    2699         326 : create_data_directory(void)
    2700             : {
    2701             :     int         ret;
    2702             : 
    2703         326 :     switch ((ret = pg_check_dir(pg_data)))
    2704             :     {
    2705             :         case 0:
    2706             :             /* PGDATA not there, must create it */
    2707         322 :             printf(_("creating directory %s ... "),
    2708             :                    pg_data);
    2709         322 :             fflush(stdout);
    2710             : 
    2711         322 :             if (pg_mkdir_p(pg_data, pg_dir_create_mode) != 0)
    2712             :             {
    2713           0 :                 pg_log_error("could not create directory \"%s\": %m", pg_data);
    2714           0 :                 exit(1);
    2715             :             }
    2716             :             else
    2717         322 :                 check_ok();
    2718             : 
    2719         322 :             made_new_pgdata = true;
    2720         322 :             break;
    2721             : 
    2722             :         case 1:
    2723             :             /* Present but empty, fix permissions and use it */
    2724           2 :             printf(_("fixing permissions on existing directory %s ... "),
    2725             :                    pg_data);
    2726           2 :             fflush(stdout);
    2727             : 
    2728           2 :             if (chmod(pg_data, pg_dir_create_mode) != 0)
    2729             :             {
    2730           0 :                 pg_log_error("could not change permissions of directory \"%s\": %m",
    2731             :                              pg_data);
    2732           0 :                 exit(1);
    2733             :             }
    2734             :             else
    2735           2 :                 check_ok();
    2736             : 
    2737           2 :             found_existing_pgdata = true;
    2738           2 :             break;
    2739             : 
    2740             :         case 2:
    2741             :         case 3:
    2742             :         case 4:
    2743             :             /* Present and not empty */
    2744           2 :             pg_log_error("directory \"%s\" exists but is not empty", pg_data);
    2745           2 :             if (ret != 4)
    2746           0 :                 warn_on_mount_point(ret);
    2747             :             else
    2748           4 :                 fprintf(stderr,
    2749           2 :                         _("If you want to create a new database system, either remove or empty\n"
    2750             :                           "the directory \"%s\" or run %s\n"
    2751             :                           "with an argument other than \"%s\".\n"),
    2752             :                         pg_data, progname, pg_data);
    2753           2 :             exit(1);            /* no further message needed */
    2754             : 
    2755             :         default:
    2756             :             /* Trouble accessing directory */
    2757           0 :             pg_log_error("could not access directory \"%s\": %m", pg_data);
    2758           0 :             exit(1);
    2759             :     }
    2760         324 : }
    2761             : 
    2762             : 
    2763             : /* Create WAL directory, and symlink if required */
    2764             : void
    2765         324 : create_xlog_or_symlink(void)
    2766             : {
    2767             :     char       *subdirloc;
    2768             : 
    2769             :     /* form name of the place for the subdirectory or symlink */
    2770         324 :     subdirloc = psprintf("%s/pg_wal", pg_data);
    2771             : 
    2772         324 :     if (xlog_dir)
    2773             :     {
    2774             :         int         ret;
    2775             : 
    2776             :         /* clean up xlog directory name, check it's absolute */
    2777           6 :         canonicalize_path(xlog_dir);
    2778           6 :         if (!is_absolute_path(xlog_dir))
    2779             :         {
    2780           2 :             pg_log_error("WAL directory location must be an absolute path");
    2781           2 :             exit(1);
    2782             :         }
    2783             : 
    2784             :         /* check if the specified xlog directory exists/is empty */
    2785           4 :         switch ((ret = pg_check_dir(xlog_dir)))
    2786             :         {
    2787             :             case 0:
    2788             :                 /* xlog directory not there, must create it */
    2789           0 :                 printf(_("creating directory %s ... "),
    2790             :                        xlog_dir);
    2791           0 :                 fflush(stdout);
    2792             : 
    2793           0 :                 if (pg_mkdir_p(xlog_dir, pg_dir_create_mode) != 0)
    2794             :                 {
    2795           0 :                     pg_log_error("could not create directory \"%s\": %m",
    2796             :                                  xlog_dir);
    2797           0 :                     exit(1);
    2798             :                 }
    2799             :                 else
    2800           0 :                     check_ok();
    2801             : 
    2802           0 :                 made_new_xlogdir = true;
    2803           0 :                 break;
    2804             : 
    2805             :             case 1:
    2806             :                 /* Present but empty, fix permissions and use it */
    2807           2 :                 printf(_("fixing permissions on existing directory %s ... "),
    2808             :                        xlog_dir);
    2809           2 :                 fflush(stdout);
    2810             : 
    2811           2 :                 if (chmod(xlog_dir, pg_dir_create_mode) != 0)
    2812             :                 {
    2813           0 :                     pg_log_error("could not change permissions of directory \"%s\": %m",
    2814             :                                  xlog_dir);
    2815           0 :                     exit(1);
    2816             :                 }
    2817             :                 else
    2818           2 :                     check_ok();
    2819             : 
    2820           2 :                 found_existing_xlogdir = true;
    2821           2 :                 break;
    2822             : 
    2823             :             case 2:
    2824             :             case 3:
    2825             :             case 4:
    2826             :                 /* Present and not empty */
    2827           2 :                 pg_log_error("directory \"%s\" exists but is not empty", xlog_dir);
    2828           2 :                 if (ret != 4)
    2829           2 :                     warn_on_mount_point(ret);
    2830             :                 else
    2831           0 :                     fprintf(stderr,
    2832           0 :                             _("If you want to store the WAL there, either remove or empty the directory\n"
    2833             :                               "\"%s\".\n"),
    2834             :                             xlog_dir);
    2835           2 :                 exit(1);
    2836             : 
    2837             :             default:
    2838             :                 /* Trouble accessing directory */
    2839           0 :                 pg_log_error("could not access directory \"%s\": %m", xlog_dir);
    2840           0 :                 exit(1);
    2841             :         }
    2842             : 
    2843             : #ifdef HAVE_SYMLINK
    2844           2 :         if (symlink(xlog_dir, subdirloc) != 0)
    2845             :         {
    2846           0 :             pg_log_error("could not create symbolic link \"%s\": %m",
    2847             :                          subdirloc);
    2848           0 :             exit(1);
    2849             :         }
    2850             : #else
    2851             :         pg_log_error("symlinks are not supported on this platform");
    2852             :         exit(1);
    2853             : #endif
    2854             :     }
    2855             :     else
    2856             :     {
    2857             :         /* Without -X option, just make the subdirectory normally */
    2858         318 :         if (mkdir(subdirloc, pg_dir_create_mode) < 0)
    2859             :         {
    2860           0 :             pg_log_error("could not create directory \"%s\": %m",
    2861             :                          subdirloc);
    2862           0 :             exit(1);
    2863             :         }
    2864             :     }
    2865             : 
    2866         320 :     free(subdirloc);
    2867         320 : }
    2868             : 
    2869             : 
    2870             : void
    2871           2 : warn_on_mount_point(int error)
    2872             : {
    2873           2 :     if (error == 2)
    2874           0 :         fprintf(stderr,
    2875           0 :                 _("It contains a dot-prefixed/invisible file, perhaps due to it being a mount point.\n"));
    2876           2 :     else if (error == 3)
    2877           2 :         fprintf(stderr,
    2878           2 :                 _("It contains a lost+found directory, perhaps due to it being a mount point.\n"));
    2879             : 
    2880           2 :     fprintf(stderr,
    2881           2 :             _("Using a mount point directly as the data directory is not recommended.\n"
    2882             :               "Create a subdirectory under the mount point.\n"));
    2883           2 : }
    2884             : 
    2885             : 
    2886             : void
    2887         326 : initialize_data_directory(void)
    2888             : {
    2889             :     PG_CMD_DECL;
    2890             :     int         i;
    2891             : 
    2892         326 :     setup_signals();
    2893             : 
    2894             :     /*
    2895             :      * Set mask based on requested PGDATA permissions.  pg_mode_mask, and
    2896             :      * friends like pg_dir_create_mode, are set to owner-only by default and
    2897             :      * then updated if -g is passed in by calling SetDataDirectoryCreatePerm()
    2898             :      * when parsing our options (see above).
    2899             :      */
    2900         326 :     umask(pg_mode_mask);
    2901             : 
    2902         326 :     create_data_directory();
    2903             : 
    2904         324 :     create_xlog_or_symlink();
    2905             : 
    2906             :     /* Create required subdirectories (other than pg_wal) */
    2907         320 :     printf(_("creating subdirectories ... "));
    2908         320 :     fflush(stdout);
    2909             : 
    2910        7360 :     for (i = 0; i < lengthof(subdirs); i++)
    2911             :     {
    2912             :         char       *path;
    2913             : 
    2914        7040 :         path = psprintf("%s/%s", pg_data, subdirs[i]);
    2915             : 
    2916             :         /*
    2917             :          * The parent directory already exists, so we only need mkdir() not
    2918             :          * pg_mkdir_p() here, which avoids some failure modes; cf bug #13853.
    2919             :          */
    2920        7040 :         if (mkdir(path, pg_dir_create_mode) < 0)
    2921             :         {
    2922           0 :             pg_log_error("could not create directory \"%s\": %m", path);
    2923           0 :             exit(1);
    2924             :         }
    2925             : 
    2926        7040 :         free(path);
    2927             :     }
    2928             : 
    2929         320 :     check_ok();
    2930             : 
    2931             :     /* Top level PG_VERSION is checked by bootstrapper, so make it first */
    2932         320 :     write_version_file(NULL);
    2933             : 
    2934             :     /* Select suitable configuration settings */
    2935         320 :     set_null_conf();
    2936         320 :     test_config_settings();
    2937             : 
    2938             :     /* Now create all the text config files */
    2939         320 :     setup_config();
    2940             : 
    2941             :     /* Bootstrap template1 */
    2942         320 :     bootstrap_template1();
    2943             : 
    2944             :     /*
    2945             :      * Make the per-database PG_VERSION for template1 only after init'ing it
    2946             :      */
    2947         320 :     write_version_file("base/1");
    2948             : 
    2949             :     /*
    2950             :      * Create the stuff we don't need to use bootstrap mode for, using a
    2951             :      * backend running in simple standalone mode.
    2952             :      */
    2953         320 :     fputs(_("performing post-bootstrap initialization ... "), stdout);
    2954         320 :     fflush(stdout);
    2955             : 
    2956         320 :     snprintf(cmd, sizeof(cmd),
    2957             :              "\"%s\" %s template1 >%s",
    2958             :              backend_exec, backend_options,
    2959             :              DEVNULL);
    2960             : 
    2961         320 :     PG_CMD_OPEN;
    2962             : 
    2963         320 :     setup_auth(cmdfd);
    2964             : 
    2965         320 :     setup_depend(cmdfd);
    2966             : 
    2967             :     /*
    2968             :      * Note that no objects created after setup_depend() will be "pinned".
    2969             :      * They are all droppable at the whim of the DBA.
    2970             :      */
    2971             : 
    2972         320 :     setup_sysviews(cmdfd);
    2973             : 
    2974         320 :     setup_description(cmdfd);
    2975             : 
    2976         320 :     setup_collation(cmdfd);
    2977             : 
    2978         320 :     setup_dictionary(cmdfd);
    2979             : 
    2980         320 :     setup_privileges(cmdfd);
    2981             : 
    2982         320 :     setup_schema(cmdfd);
    2983             : 
    2984         320 :     load_plpgsql(cmdfd);
    2985             : 
    2986         320 :     vacuum_db(cmdfd);
    2987             : 
    2988         320 :     make_template0(cmdfd);
    2989             : 
    2990         320 :     make_postgres(cmdfd);
    2991             : 
    2992         320 :     PG_CMD_CLOSE;
    2993             : 
    2994         320 :     check_ok();
    2995         320 : }
    2996             : 
    2997             : 
    2998             : int
    2999         342 : main(int argc, char *argv[])
    3000             : {
    3001             :     static struct option long_options[] = {
    3002             :         {"pgdata", required_argument, NULL, 'D'},
    3003             :         {"encoding", required_argument, NULL, 'E'},
    3004             :         {"locale", required_argument, NULL, 1},
    3005             :         {"lc-collate", required_argument, NULL, 2},
    3006             :         {"lc-ctype", required_argument, NULL, 3},
    3007             :         {"lc-monetary", required_argument, NULL, 4},
    3008             :         {"lc-numeric", required_argument, NULL, 5},
    3009             :         {"lc-time", required_argument, NULL, 6},
    3010             :         {"lc-messages", required_argument, NULL, 7},
    3011             :         {"no-locale", no_argument, NULL, 8},
    3012             :         {"text-search-config", required_argument, NULL, 'T'},
    3013             :         {"auth", required_argument, NULL, 'A'},
    3014             :         {"auth-local", required_argument, NULL, 10},
    3015             :         {"auth-host", required_argument, NULL, 11},
    3016             :         {"pwprompt", no_argument, NULL, 'W'},
    3017             :         {"pwfile", required_argument, NULL, 9},
    3018             :         {"username", required_argument, NULL, 'U'},
    3019             :         {"help", no_argument, NULL, '?'},
    3020             :         {"version", no_argument, NULL, 'V'},
    3021             :         {"debug", no_argument, NULL, 'd'},
    3022             :         {"show", no_argument, NULL, 's'},
    3023             :         {"noclean", no_argument, NULL, 'n'},  /* for backwards compatibility */
    3024             :         {"no-clean", no_argument, NULL, 'n'},
    3025             :         {"nosync", no_argument, NULL, 'N'}, /* for backwards compatibility */
    3026             :         {"no-sync", no_argument, NULL, 'N'},
    3027             :         {"sync-only", no_argument, NULL, 'S'},
    3028             :         {"waldir", required_argument, NULL, 'X'},
    3029             :         {"wal-segsize", required_argument, NULL, 12},
    3030             :         {"data-checksums", no_argument, NULL, 'k'},
    3031             :         {"allow-group-access", no_argument, NULL, 'g'},
    3032             :         {NULL, 0, NULL, 0}
    3033             :     };
    3034             : 
    3035             :     /*
    3036             :      * options with no short version return a low integer, the rest return
    3037             :      * their short version value
    3038             :      */
    3039             :     int         c;
    3040             :     int         option_index;
    3041             :     char       *effective_user;
    3042             :     PQExpBuffer start_db_cmd;
    3043             :     char        pg_ctl_path[MAXPGPATH];
    3044             : 
    3045             :     /*
    3046             :      * Ensure that buffering behavior of stdout matches what it is in
    3047             :      * interactive usage (at least on most platforms).  This prevents
    3048             :      * unexpected output ordering when, eg, output is redirected to a file.
    3049             :      * POSIX says we must do this before any other usage of these files.
    3050             :      */
    3051         342 :     setvbuf(stdout, NULL, PG_IOLBF, 0);
    3052             : 
    3053         342 :     pg_logging_init(argv[0]);
    3054         342 :     progname = get_progname(argv[0]);
    3055         342 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("initdb"));
    3056             : 
    3057         342 :     if (argc > 1)
    3058             :     {
    3059         342 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
    3060             :         {
    3061           2 :             usage(progname);
    3062           2 :             exit(0);
    3063             :         }
    3064         340 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
    3065             :         {
    3066           4 :             puts("initdb (PostgreSQL) " PG_VERSION);
    3067           4 :             exit(0);
    3068             :         }
    3069             :     }
    3070             : 
    3071             :     /* process command-line options */
    3072             : 
    3073        1684 :     while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:g", long_options, &option_index)) != -1)
    3074             :     {
    3075        1014 :         switch (c)
    3076             :         {
    3077             :             case 'A':
    3078         186 :                 authmethodlocal = authmethodhost = pg_strdup(optarg);
    3079             : 
    3080             :                 /*
    3081             :                  * When ident is specified, use peer for local connections.
    3082             :                  * Mirrored, when peer is specified, use ident for TCP/IP
    3083             :                  * connections.
    3084             :                  */
    3085         186 :                 if (strcmp(authmethodhost, "ident") == 0)
    3086           0 :                     authmethodlocal = "peer";
    3087         186 :                 else if (strcmp(authmethodlocal, "peer") == 0)
    3088           0 :                     authmethodhost = "ident";
    3089         186 :                 break;
    3090             :             case 10:
    3091           0 :                 authmethodlocal = pg_strdup(optarg);
    3092           0 :                 break;
    3093             :             case 11:
    3094           0 :                 authmethodhost = pg_strdup(optarg);
    3095           0 :                 break;
    3096             :             case 'D':
    3097         312 :                 pg_data = pg_strdup(optarg);
    3098         312 :                 break;
    3099             :             case 'E':
    3100          14 :                 encoding = pg_strdup(optarg);
    3101          14 :                 break;
    3102             :             case 'W':
    3103           0 :                 pwprompt = true;
    3104           0 :                 break;
    3105             :             case 'U':
    3106           8 :                 username = pg_strdup(optarg);
    3107           8 :                 break;
    3108             :             case 'd':
    3109           0 :                 debug = true;
    3110           0 :                 printf(_("Running in debug mode.\n"));
    3111           0 :                 break;
    3112             :             case 'n':
    3113         128 :                 noclean = true;
    3114         128 :                 printf(_("Running in no-clean mode.  Mistakes will not be cleaned up.\n"));
    3115         128 :                 break;
    3116             :             case 'N':
    3117         318 :                 do_sync = false;
    3118         318 :                 break;
    3119             :             case 'S':
    3120           6 :                 sync_only = true;
    3121           6 :                 break;
    3122             :             case 'k':
    3123           2 :                 data_checksums = true;
    3124           2 :                 break;
    3125             :             case 'L':
    3126           0 :                 share_path = pg_strdup(optarg);
    3127           0 :                 break;
    3128             :             case 1:
    3129          14 :                 locale = pg_strdup(optarg);
    3130          14 :                 break;
    3131             :             case 2:
    3132           0 :                 lc_collate = pg_strdup(optarg);
    3133           0 :                 break;
    3134             :             case 3:
    3135           0 :                 lc_ctype = pg_strdup(optarg);
    3136           0 :                 break;
    3137             :             case 4:
    3138           0 :                 lc_monetary = pg_strdup(optarg);
    3139           0 :                 break;
    3140             :             case 5:
    3141           0 :                 lc_numeric = pg_strdup(optarg);
    3142           0 :                 break;
    3143             :             case 6:
    3144           0 :                 lc_time = pg_strdup(optarg);
    3145           0 :                 break;
    3146             :             case 7:
    3147           0 :                 lc_messages = pg_strdup(optarg);
    3148           0 :                 break;
    3149             :             case 8:
    3150           2 :                 locale = "C";
    3151           2 :                 break;
    3152             :             case 9:
    3153           0 :                 pwfilename = pg_strdup(optarg);
    3154           0 :                 break;
    3155             :             case 's':
    3156           0 :                 show_setting = true;
    3157           0 :                 break;
    3158             :             case 'T':
    3159           2 :                 default_text_search_config = pg_strdup(optarg);
    3160           2 :                 break;
    3161             :             case 'X':
    3162           6 :                 xlog_dir = pg_strdup(optarg);
    3163           6 :                 break;
    3164             :             case 12:
    3165           4 :                 str_wal_segment_size_mb = pg_strdup(optarg);
    3166           4 :                 break;
    3167             :             case 'g':
    3168          10 :                 SetDataDirectoryCreatePerm(PG_DIR_MODE_GROUP);
    3169          10 :                 break;
    3170             :             default:
    3171             :                 /* getopt_long already emitted a complaint */
    3172           2 :                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    3173             :                         progname);
    3174           2 :                 exit(1);
    3175             :         }
    3176             :     }
    3177             : 
    3178             : 
    3179             :     /*
    3180             :      * Non-option argument specifies data directory as long as it wasn't
    3181             :      * already specified with -D / --pgdata
    3182             :      */
    3183         334 :     if (optind < argc && !pg_data)
    3184             :     {
    3185          18 :         pg_data = pg_strdup(argv[optind]);
    3186          18 :         optind++;
    3187             :     }
    3188             : 
    3189         334 :     if (optind < argc)
    3190             :     {
    3191           0 :         pg_log_error("too many command-line arguments (first is \"%s\")",
    3192             :                      argv[optind]);
    3193           0 :         fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
    3194             :                 progname);
    3195           0 :         exit(1);
    3196             :     }
    3197             : 
    3198         334 :     atexit(cleanup_directories_atexit);
    3199             : 
    3200             :     /* If we only need to fsync, just do it and exit */
    3201         334 :     if (sync_only)
    3202             :     {
    3203           6 :         setup_pgdata();
    3204             : 
    3205             :         /* must check that directory is readable */
    3206           6 :         if (pg_check_dir(pg_data) <= 0)
    3207             :         {
    3208           2 :             pg_log_error("could not access directory \"%s\": %m", pg_data);
    3209           2 :             exit(1);
    3210             :         }
    3211             : 
    3212           4 :         fputs(_("syncing data to disk ... "), stdout);
    3213           4 :         fflush(stdout);
    3214           4 :         fsync_pgdata(pg_data, PG_VERSION_NUM);
    3215           4 :         check_ok();
    3216           4 :         return 0;
    3217             :     }
    3218             : 
    3219         328 :     if (pwprompt && pwfilename)
    3220             :     {
    3221           0 :         pg_log_error("password prompt and password file cannot be specified together");
    3222           0 :         exit(1);
    3223             :     }
    3224             : 
    3225         328 :     check_authmethod_unspecified(&authmethodlocal);
    3226         328 :     check_authmethod_unspecified(&authmethodhost);
    3227             : 
    3228         328 :     check_authmethod_valid(authmethodlocal, auth_methods_local, "local");
    3229         328 :     check_authmethod_valid(authmethodhost, auth_methods_host, "host");
    3230             : 
    3231         328 :     check_need_password(authmethodlocal, authmethodhost);
    3232             : 
    3233             :     /* set wal segment size */
    3234         328 :     if (str_wal_segment_size_mb == NULL)
    3235         324 :         wal_segment_size_mb = (DEFAULT_XLOG_SEG_SIZE) / (1024 * 1024);
    3236             :     else
    3237             :     {
    3238             :         char       *endptr;
    3239             : 
    3240             :         /* check that the argument is a number */
    3241           4 :         wal_segment_size_mb = strtol(str_wal_segment_size_mb, &endptr, 10);
    3242             : 
    3243             :         /* verify that wal segment size is valid */
    3244           4 :         if (endptr == str_wal_segment_size_mb || *endptr != '\0')
    3245             :         {
    3246           0 :             pg_log_error("argument of --wal-segsize must be a number");
    3247           0 :             exit(1);
    3248             :         }
    3249           4 :         if (!IsValidWalSegSize(wal_segment_size_mb * 1024 * 1024))
    3250             :         {
    3251           0 :             pg_log_error("argument of --wal-segsize must be a power of 2 between 1 and 1024");
    3252           0 :             exit(1);
    3253             :         }
    3254             :     }
    3255             : 
    3256         328 :     get_restricted_token();
    3257             : 
    3258         328 :     setup_pgdata();
    3259             : 
    3260         328 :     setup_bin_paths(argv[0]);
    3261             : 
    3262         328 :     effective_user = get_id();
    3263         328 :     if (!username)
    3264         320 :         username = effective_user;
    3265             : 
    3266         328 :     if (strncmp(username, "pg_", 3) == 0)
    3267             :     {
    3268           2 :         pg_log_error("superuser name \"%s\" is disallowed; role names cannot begin with \"pg_\"", username);
    3269           2 :         exit(1);
    3270             :     }
    3271             : 
    3272         326 :     printf(_("The files belonging to this database system will be owned "
    3273             :              "by user \"%s\".\n"
    3274             :              "This user must also own the server process.\n\n"),
    3275             :            effective_user);
    3276             : 
    3277         326 :     set_info_version();
    3278             : 
    3279         326 :     setup_data_file_paths();
    3280             : 
    3281         326 :     setup_locale_encoding();
    3282             : 
    3283         326 :     setup_text_search();
    3284             : 
    3285         326 :     printf("\n");
    3286             : 
    3287         326 :     if (data_checksums)
    3288           2 :         printf(_("Data page checksums are enabled.\n"));
    3289             :     else
    3290         324 :         printf(_("Data page checksums are disabled.\n"));
    3291             : 
    3292         326 :     if (pwprompt || pwfilename)
    3293           0 :         get_su_pwd();
    3294             : 
    3295         326 :     printf("\n");
    3296             : 
    3297         326 :     initialize_data_directory();
    3298             : 
    3299         320 :     if (do_sync)
    3300             :     {
    3301           2 :         fputs(_("syncing data to disk ... "), stdout);
    3302           2 :         fflush(stdout);
    3303           2 :         fsync_pgdata(pg_data, PG_VERSION_NUM);
    3304           2 :         check_ok();
    3305             :     }
    3306             :     else
    3307         318 :         printf(_("\nSync to disk skipped.\nThe data directory might become corrupt if the operating system crashes.\n"));
    3308             : 
    3309         320 :     if (authwarning)
    3310             :     {
    3311         134 :         printf("\n");
    3312         134 :         pg_log_warning("enabling \"trust\" authentication for local connections");
    3313         134 :         fprintf(stderr, _("You can change this by editing pg_hba.conf or using the option -A, or\n"
    3314             :                           "--auth-local and --auth-host, the next time you run initdb.\n"));
    3315             :     }
    3316             : 
    3317             :     /*
    3318             :      * Build up a shell command to tell the user how to start the server
    3319             :      */
    3320         320 :     start_db_cmd = createPQExpBuffer();
    3321             : 
    3322             :     /* Get directory specification used to start initdb ... */
    3323         320 :     strlcpy(pg_ctl_path, argv[0], sizeof(pg_ctl_path));
    3324         320 :     canonicalize_path(pg_ctl_path);
    3325         320 :     get_parent_directory(pg_ctl_path);
    3326             :     /* ... and tag on pg_ctl instead */
    3327         320 :     join_path_components(pg_ctl_path, pg_ctl_path, "pg_ctl");
    3328             : 
    3329             :     /* path to pg_ctl, properly quoted */
    3330         320 :     appendShellString(start_db_cmd, pg_ctl_path);
    3331             : 
    3332             :     /* add -D switch, with properly quoted data directory */
    3333         320 :     appendPQExpBufferStr(start_db_cmd, " -D ");
    3334         320 :     appendShellString(start_db_cmd, pgdata_native);
    3335             : 
    3336             :     /* add suggested -l switch and "start" command */
    3337             :     /* translator: This is a placeholder in a shell command. */
    3338         320 :     appendPQExpBuffer(start_db_cmd, " -l %s start", _("logfile"));
    3339             : 
    3340         320 :     printf(_("\nSuccess. You can now start the database server using:\n\n"
    3341             :              "    %s\n\n"),
    3342             :            start_db_cmd->data);
    3343             : 
    3344         320 :     destroyPQExpBuffer(start_db_cmd);
    3345             : 
    3346         320 :     success = true;
    3347         320 :     return 0;
    3348             : }

Generated by: LCOV version 1.13