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