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