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