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