Fix inconsistent message wording, and split off a couple of duplicated strings.
[PostgreSQL.git] / src / bin / initdb / initdb.c
blob6841612e02b253a12ffcf5e3a576be09ff6d6535
1 /*-------------------------------------------------------------------------
3 * initdb --- initialize a PostgreSQL installation
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.
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".
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.
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.
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.
32 * Note:
33 * The program has some memory leakage - it isn't worth cleaning it up.
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
39 * This code is released under the terms of the PostgreSQL License.
41 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
42 * Portions Copyright (c) 1994, Regents of the University of California
43 * Portions taken from FreeBSD.
45 * $PostgreSQL$
47 *-------------------------------------------------------------------------
50 #include "postgres_fe.h"
52 #include <dirent.h>
53 #include <sys/stat.h>
54 #include <unistd.h>
55 #include <locale.h>
56 #include <signal.h>
57 #include <time.h>
59 #include "libpq/pqsignal.h"
60 #include "mb/pg_wchar.h"
61 #include "getaddrinfo.h"
62 #include "getopt_long.h"
63 #include "miscadmin.h"
65 #ifndef HAVE_INT_OPTRESET
66 int optreset;
67 #endif
70 /* version string we expect back from postgres */
71 #define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n"
74 * these values are passed in by makefile defines
76 static char *share_path = NULL;
78 /* values to be obtained from arguments */
79 static char *pg_data = "";
80 static char *encoding = "";
81 static char *locale = "";
82 static char *lc_collate = "";
83 static char *lc_ctype = "";
84 static char *lc_monetary = "";
85 static char *lc_numeric = "";
86 static char *lc_time = "";
87 static char *lc_messages = "";
88 static const char *default_text_search_config = "";
89 static char *username = "";
90 static bool pwprompt = false;
91 static char *pwfilename = NULL;
92 static char *authmethod = "";
93 static bool debug = false;
94 static bool noclean = false;
95 static bool show_setting = false;
96 static char *xlog_dir = "";
99 /* internal vars */
100 static const char *progname;
101 static char *encodingid = "0";
102 static char *bki_file;
103 static char *desc_file;
104 static char *shdesc_file;
105 static char *hba_file;
106 static char *ident_file;
107 static char *conf_file;
108 static char *conversion_file;
109 static char *dictionary_file;
110 static char *info_schema_file;
111 static char *features_file;
112 static char *system_views_file;
113 static bool made_new_pgdata = false;
114 static bool found_existing_pgdata = false;
115 static bool made_new_xlogdir = false;
116 static bool found_existing_xlogdir = false;
117 static char infoversion[100];
118 static bool caught_signal = false;
119 static bool output_failed = false;
120 static int output_errno = 0;
122 /* defaults */
123 static int n_connections = 10;
124 static int n_buffers = 50;
125 static int n_fsm_pages = 20000;
128 * Warning messages for authentication methods
130 #define AUTHTRUST_WARNING \
131 "# CAUTION: Configuring the system for local \"trust\" authentication allows\n" \
132 "# any local user to connect as any PostgreSQL user, including the database\n" \
133 "# superuser. If you do not trust all your local users, use another\n" \
134 "# authentication method.\n"
135 static char *authwarning = NULL;
138 * Centralized knowledge of switches to pass to backend
140 * Note: in the shell-script version, we also passed PGDATA as a -D switch,
141 * but here it is more convenient to pass it as an environment variable
142 * (no quoting to worry about).
144 static const char *boot_options = "-F";
145 static const char *backend_options = "--single -F -O -c search_path=pg_catalog -c exit_on_error=true";
148 /* path to 'initdb' binary directory */
149 static char bin_path[MAXPGPATH];
150 static char backend_exec[MAXPGPATH];
152 static void *pg_malloc(size_t size);
153 static char *xstrdup(const char *s);
154 static char **replace_token(char **lines,
155 const char *token, const char *replacement);
157 #ifndef HAVE_UNIX_SOCKETS
158 static char **filter_lines_with_token(char **lines, const char *token);
159 #endif
160 static char **readfile(char *path);
161 static void writefile(char *path, char **lines);
162 static FILE *popen_check(const char *command, const char *mode);
163 static int mkdir_p(char *path, mode_t omode);
164 static void exit_nicely(void);
165 static char *get_id(void);
166 static char *get_encoding_id(char *encoding_name);
167 static char *get_short_version(void);
168 static int check_data_dir(char *dir);
169 static bool mkdatadir(const char *subdir);
170 static void set_input(char **dest, char *filename);
171 static void check_input(char *path);
172 static void set_short_version(char *short_version, char *extrapath);
173 static void set_null_conf(void);
174 static void test_config_settings(void);
175 static void setup_config(void);
176 static void bootstrap_template1(char *short_version);
177 static void setup_auth(void);
178 static void get_set_pwd(void);
179 static void setup_depend(void);
180 static void setup_sysviews(void);
181 static void setup_description(void);
182 static void setup_conversion(void);
183 static void setup_dictionary(void);
184 static void setup_privileges(void);
185 static void set_info_version(void);
186 static void setup_schema(void);
187 static void vacuum_db(void);
188 static void make_template0(void);
189 static void make_postgres(void);
190 static void trapsig(int signum);
191 static void check_ok(void);
192 static char *escape_quotes(const char *src);
193 static int locale_date_order(const char *locale);
194 static bool chklocale(const char *locale);
195 static void setlocales(void);
196 static void usage(const char *progname);
198 #ifdef WIN32
199 static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION * processInfo);
200 #endif
204 * macros for running pipes to postgres
206 #define PG_CMD_DECL char cmd[MAXPGPATH]; FILE *cmdfd
208 #define PG_CMD_OPEN \
209 do { \
210 cmdfd = popen_check(cmd, "w"); \
211 if (cmdfd == NULL) \
212 exit_nicely(); /* message already printed by popen_check */ \
213 } while (0)
215 #define PG_CMD_CLOSE \
216 do { \
217 if (pclose_check(cmdfd)) \
218 exit_nicely(); /* message already printed by pclose_check */ \
219 } while (0)
221 #define PG_CMD_PUTS(line) \
222 do { \
223 if (fputs(line, cmdfd) < 0 || fflush(cmdfd) < 0) \
224 output_failed = true, output_errno = errno; \
225 } while (0)
227 #define PG_CMD_PRINTF1(fmt, arg1) \
228 do { \
229 if (fprintf(cmdfd, fmt, arg1) < 0 || fflush(cmdfd) < 0) \
230 output_failed = true, output_errno = errno; \
231 } while (0)
233 #define PG_CMD_PRINTF2(fmt, arg1, arg2) \
234 do { \
235 if (fprintf(cmdfd, fmt, arg1, arg2) < 0 || fflush(cmdfd) < 0) \
236 output_failed = true, output_errno = errno; \
237 } while (0)
239 #ifndef WIN32
240 #define QUOTE_PATH ""
241 #define DIR_SEP "/"
242 #else
243 #define QUOTE_PATH "\""
244 #define DIR_SEP "\\"
245 #endif
248 * routines to check mem allocations and fail noisily.
250 * Note that we can't call exit_nicely() on a memory failure, as it calls
251 * rmtree() which needs memory allocation. So we just exit with a bang.
253 static void *
254 pg_malloc(size_t size)
256 void *result;
258 result = malloc(size);
259 if (!result)
261 fprintf(stderr, _("%s: out of memory\n"), progname);
262 exit(1);
264 return result;
267 static char *
268 xstrdup(const char *s)
270 char *result;
272 result = strdup(s);
273 if (!result)
275 fprintf(stderr, _("%s: out of memory\n"), progname);
276 exit(1);
278 return result;
282 * make a copy of the array of lines, with token replaced by replacement
283 * the first time it occurs on each line.
285 * This does most of what sed was used for in the shell script, but
286 * doesn't need any regexp stuff.
288 static char **
289 replace_token(char **lines, const char *token, const char *replacement)
291 int numlines = 1;
292 int i;
293 char **result;
294 int toklen,
295 replen,
296 diff;
298 for (i = 0; lines[i]; i++)
299 numlines++;
301 result = (char **) pg_malloc(numlines * sizeof(char *));
303 toklen = strlen(token);
304 replen = strlen(replacement);
305 diff = replen - toklen;
307 for (i = 0; i < numlines; i++)
309 char *where;
310 char *newline;
311 int pre;
313 /* just copy pointer if NULL or no change needed */
314 if (lines[i] == NULL || (where = strstr(lines[i], token)) == NULL)
316 result[i] = lines[i];
317 continue;
320 /* if we get here a change is needed - set up new line */
322 newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1);
324 pre = where - lines[i];
326 strncpy(newline, lines[i], pre);
328 strcpy(newline + pre, replacement);
330 strcpy(newline + pre + replen, lines[i] + pre + toklen);
332 result[i] = newline;
335 return result;
339 * make a copy of lines without any that contain the token
341 * a sort of poor man's grep -v
343 #ifndef HAVE_UNIX_SOCKETS
344 static char **
345 filter_lines_with_token(char **lines, const char *token)
347 int numlines = 1;
348 int i,
349 src,
350 dst;
351 char **result;
353 for (i = 0; lines[i]; i++)
354 numlines++;
356 result = (char **) pg_malloc(numlines * sizeof(char *));
358 for (src = 0, dst = 0; src < numlines; src++)
360 if (lines[src] == NULL || strstr(lines[src], token) == NULL)
361 result[dst++] = lines[src];
364 return result;
366 #endif
369 * get the lines from a text file
371 static char **
372 readfile(char *path)
374 FILE *infile;
375 int maxlength = 0,
376 linelen = 0;
377 int nlines = 0;
378 char **result;
379 char *buffer;
380 int c;
382 if ((infile = fopen(path, "r")) == NULL)
384 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
385 progname, path, strerror(errno));
386 exit_nicely();
389 /* pass over the file twice - the first time to size the result */
391 while ((c = fgetc(infile)) != EOF)
393 linelen++;
394 if (c == '\n')
396 nlines++;
397 if (linelen > maxlength)
398 maxlength = linelen;
399 linelen = 0;
403 /* handle last line without a terminating newline (yuck) */
405 if (linelen)
406 nlines++;
407 if (linelen > maxlength)
408 maxlength = linelen;
410 /* set up the result and the line buffer */
412 result = (char **) pg_malloc((nlines + 2) * sizeof(char *));
413 buffer = (char *) pg_malloc(maxlength + 2);
415 /* now reprocess the file and store the lines */
417 rewind(infile);
418 nlines = 0;
419 while (fgets(buffer, maxlength + 1, infile) != NULL)
421 result[nlines] = xstrdup(buffer);
422 nlines++;
425 fclose(infile);
426 free(buffer);
427 result[nlines] = NULL;
429 return result;
433 * write an array of lines to a file
435 * This is only used to write text files. Use fopen "w" not PG_BINARY_W
436 * so that the resulting configuration files are nicely editable on Windows.
438 static void
439 writefile(char *path, char **lines)
441 FILE *out_file;
442 char **line;
444 if ((out_file = fopen(path, "w")) == NULL)
446 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
447 progname, path, strerror(errno));
448 exit_nicely();
450 for (line = lines; *line != NULL; line++)
452 if (fputs(*line, out_file) < 0)
454 fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
455 progname, path, strerror(errno));
456 exit_nicely();
458 free(*line);
460 if (fclose(out_file))
462 fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
463 progname, path, strerror(errno));
464 exit_nicely();
469 * Open a subcommand with suitable error messaging
471 static FILE *
472 popen_check(const char *command, const char *mode)
474 FILE *cmdfd;
476 fflush(stdout);
477 fflush(stderr);
478 errno = 0;
479 cmdfd = popen(command, mode);
480 if (cmdfd == NULL)
481 fprintf(stderr, _("%s: could not execute command \"%s\": %s\n"),
482 progname, command, strerror(errno));
483 return cmdfd;
486 /* source stolen from FreeBSD /src/bin/mkdir/mkdir.c and adapted */
489 * this tries to build all the elements of a path to a directory a la mkdir -p
490 * we assume the path is in canonical form, i.e. uses / as the separator
491 * we also assume it isn't null.
493 * note that on failure, the path arg has been modified to show the particular
494 * directory level we had problems with.
496 static int
497 mkdir_p(char *path, mode_t omode)
499 struct stat sb;
500 mode_t numask,
501 oumask;
502 int first,
503 last,
504 retval;
505 char *p;
507 p = path;
508 oumask = 0;
509 retval = 0;
511 #ifdef WIN32
512 /* skip network and drive specifiers for win32 */
513 if (strlen(p) >= 2)
515 if (p[0] == '/' && p[1] == '/')
517 /* network drive */
518 p = strstr(p + 2, "/");
519 if (p == NULL)
520 return 1;
522 else if (p[1] == ':' &&
523 ((p[0] >= 'a' && p[0] <= 'z') ||
524 (p[0] >= 'A' && p[0] <= 'Z')))
526 /* local drive */
527 p += 2;
530 #endif
532 if (p[0] == '/') /* Skip leading '/'. */
533 ++p;
534 for (first = 1, last = 0; !last; ++p)
536 if (p[0] == '\0')
537 last = 1;
538 else if (p[0] != '/')
539 continue;
540 *p = '\0';
541 if (!last && p[1] == '\0')
542 last = 1;
543 if (first)
546 * POSIX 1003.2: For each dir operand that does not name an
547 * existing directory, effects equivalent to those caused by the
548 * following command shall occcur:
550 * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]
551 * dir
553 * We change the user's umask and then restore it, instead of
554 * doing chmod's.
556 oumask = umask(0);
557 numask = oumask & ~(S_IWUSR | S_IXUSR);
558 (void) umask(numask);
559 first = 0;
561 if (last)
562 (void) umask(oumask);
564 /* check for pre-existing directory; ok if it's a parent */
565 if (stat(path, &sb) == 0)
567 if (!S_ISDIR(sb.st_mode))
569 if (last)
570 errno = EEXIST;
571 else
572 errno = ENOTDIR;
573 retval = 1;
574 break;
577 else if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
579 retval = 1;
580 break;
582 if (!last)
583 *p = '/';
585 if (!first && !last)
586 (void) umask(oumask);
587 return retval;
591 * clean up any files we created on failure
592 * if we created the data directory remove it too
594 static void
595 exit_nicely(void)
597 if (!noclean)
599 if (made_new_pgdata)
601 fprintf(stderr, _("%s: removing data directory \"%s\"\n"),
602 progname, pg_data);
603 if (!rmtree(pg_data, true))
604 fprintf(stderr, _("%s: failed to remove data directory\n"),
605 progname);
607 else if (found_existing_pgdata)
609 fprintf(stderr,
610 _("%s: removing contents of data directory \"%s\"\n"),
611 progname, pg_data);
612 if (!rmtree(pg_data, false))
613 fprintf(stderr, _("%s: failed to remove contents of data directory\n"),
614 progname);
617 if (made_new_xlogdir)
619 fprintf(stderr, _("%s: removing transaction log directory \"%s\"\n"),
620 progname, xlog_dir);
621 if (!rmtree(xlog_dir, true))
622 fprintf(stderr, _("%s: failed to remove transaction log directory\n"),
623 progname);
625 else if (found_existing_xlogdir)
627 fprintf(stderr,
628 _("%s: removing contents of transaction log directory \"%s\"\n"),
629 progname, xlog_dir);
630 if (!rmtree(xlog_dir, false))
631 fprintf(stderr, _("%s: failed to remove contents of transaction log directory\n"),
632 progname);
634 /* otherwise died during startup, do nothing! */
636 else
638 if (made_new_pgdata || found_existing_pgdata)
639 fprintf(stderr,
640 _("%s: data directory \"%s\" not removed at user's request\n"),
641 progname, pg_data);
643 if (made_new_xlogdir || found_existing_xlogdir)
644 fprintf(stderr,
645 _("%s: transaction log directory \"%s\" not removed at user's request\n"),
646 progname, xlog_dir);
649 exit(1);
653 * find the current user
655 * on unix make sure it isn't really root
657 static char *
658 get_id(void)
660 #ifndef WIN32
662 struct passwd *pw;
664 pw = getpwuid(geteuid());
666 if (geteuid() == 0) /* 0 is root's uid */
668 fprintf(stderr,
669 _("%s: cannot be run as root\n"
670 "Please log in (using, e.g., \"su\") as the "
671 "(unprivileged) user that will\n"
672 "own the server process.\n"),
673 progname);
674 exit(1);
676 #else /* the windows code */
678 struct passwd_win32
680 int pw_uid;
681 char pw_name[128];
682 } pass_win32;
683 struct passwd_win32 *pw = &pass_win32;
684 DWORD pwname_size = sizeof(pass_win32.pw_name) - 1;
686 pw->pw_uid = 1;
687 GetUserName(pw->pw_name, &pwname_size);
688 #endif
690 return xstrdup(pw->pw_name);
693 static char *
694 encodingid_to_string(int enc)
696 char result[20];
698 sprintf(result, "%d", enc);
699 return xstrdup(result);
703 * get the encoding id for a given encoding name
705 static char *
706 get_encoding_id(char *encoding_name)
708 int enc;
710 if (encoding_name && *encoding_name)
712 if ((enc = pg_valid_server_encoding(encoding_name)) >= 0)
713 return encodingid_to_string(enc);
715 fprintf(stderr, _("%s: \"%s\" is not a valid server encoding name\n"),
716 progname, encoding_name ? encoding_name : "(null)");
717 exit(1);
721 * Support for determining the best default text search configuration.
722 * We key this off the first part of LC_CTYPE (ie, the language name).
724 struct tsearch_config_match
726 const char *tsconfname;
727 const char *langname;
730 static const struct tsearch_config_match tsearch_config_languages[] =
732 {"danish", "da"},
733 {"danish", "Danish"},
734 {"dutch", "nl"},
735 {"dutch", "Dutch"},
736 {"english", "C"},
737 {"english", "POSIX"},
738 {"english", "en"},
739 {"english", "English"},
740 {"finnish", "fi"},
741 {"finnish", "Finnish"},
742 {"french", "fr"},
743 {"french", "French"},
744 {"german", "de"},
745 {"german", "German"},
746 {"hungarian", "hu"},
747 {"hungarian", "Hungarian"},
748 {"italian", "it"},
749 {"italian", "Italian"},
750 {"norwegian", "no"},
751 {"norwegian", "Norwegian"},
752 {"portuguese", "pt"},
753 {"portuguese", "Portuguese"},
754 {"romanian", "ro"},
755 {"russian", "ru"},
756 {"russian", "Russian"},
757 {"spanish", "es"},
758 {"spanish", "Spanish"},
759 {"swedish", "sv"},
760 {"swedish", "Swedish"},
761 {"turkish", "tr"},
762 {"turkish", "Turkish"},
763 {NULL, NULL} /* end marker */
767 * Look for a text search configuration matching lc_ctype, and return its
768 * name; return NULL if no match.
770 static const char *
771 find_matching_ts_config(const char *lc_type)
773 int i;
774 char *langname,
775 *ptr;
778 * Convert lc_ctype to a language name by stripping everything after an
779 * underscore. Just for paranoia, we also stop at '.' or '@'.
781 if (lc_type == NULL)
782 langname = xstrdup("");
783 else
785 ptr = langname = xstrdup(lc_type);
786 while (*ptr && *ptr != '_' && *ptr != '.' && *ptr != '@')
787 ptr++;
788 *ptr = '\0';
791 for (i = 0; tsearch_config_languages[i].tsconfname; i++)
793 if (pg_strcasecmp(tsearch_config_languages[i].langname, langname) == 0)
795 free(langname);
796 return tsearch_config_languages[i].tsconfname;
800 free(langname);
801 return NULL;
806 * get short version of VERSION
808 static char *
809 get_short_version(void)
811 bool gotdot = false;
812 int end;
813 char *vr;
815 vr = xstrdup(PG_VERSION);
817 for (end = 0; vr[end] != '\0'; end++)
819 if (vr[end] == '.')
821 if (end == 0)
822 return NULL;
823 else if (gotdot)
824 break;
825 else
826 gotdot = true;
828 else if (vr[end] < '0' || vr[end] > '9')
830 /* gone past digits and dots */
831 break;
834 if (end == 0 || vr[end - 1] == '.' || !gotdot)
835 return NULL;
837 vr[end] = '\0';
838 return vr;
842 * make sure the directory either doesn't exist or is empty
844 * Returns 0 if nonexistent, 1 if exists and empty, 2 if not empty,
845 * or -1 if trouble accessing directory
847 static int
848 check_data_dir(char *dir)
850 DIR *chkdir;
851 struct dirent *file;
852 int result = 1;
854 errno = 0;
856 chkdir = opendir(dir);
858 if (!chkdir)
859 return (errno == ENOENT) ? 0 : -1;
861 while ((file = readdir(chkdir)) != NULL)
863 if (strcmp(".", file->d_name) == 0 ||
864 strcmp("..", file->d_name) == 0)
866 /* skip this and parent directory */
867 continue;
869 else
871 result = 2; /* not empty */
872 break;
876 #ifdef WIN32
879 * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
880 * released version
882 if (GetLastError() == ERROR_NO_MORE_FILES)
883 errno = 0;
884 #endif
886 closedir(chkdir);
888 if (errno != 0)
889 result = -1; /* some kind of I/O error? */
891 return result;
895 * make the data directory (or one of its subdirectories if subdir is not NULL)
897 static bool
898 mkdatadir(const char *subdir)
900 char *path;
902 path = pg_malloc(strlen(pg_data) + 2 +
903 (subdir == NULL ? 0 : strlen(subdir)));
905 if (subdir != NULL)
906 sprintf(path, "%s/%s", pg_data, subdir);
907 else
908 strcpy(path, pg_data);
910 if (mkdir_p(path, 0700) == 0)
911 return true;
913 fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
914 progname, path, strerror(errno));
916 return false;
921 * set name of given input file variable under data directory
923 static void
924 set_input(char **dest, char *filename)
926 *dest = pg_malloc(strlen(share_path) + strlen(filename) + 2);
927 sprintf(*dest, "%s/%s", share_path, filename);
931 * check that given input file exists
933 static void
934 check_input(char *path)
936 struct stat statbuf;
938 if (stat(path, &statbuf) != 0)
940 if (errno == ENOENT)
942 fprintf(stderr,
943 _("%s: file \"%s\" does not exist\n"), progname, path);
944 fprintf(stderr,
945 _("This might mean you have a corrupted installation or identified\n"
946 "the wrong directory with the invocation option -L.\n"));
948 else
950 fprintf(stderr,
951 _("%s: could not access file \"%s\": %s\n"), progname, path,
952 strerror(errno));
953 fprintf(stderr,
954 _("This might mean you have a corrupted installation or identified\n"
955 "the wrong directory with the invocation option -L.\n"));
957 exit(1);
959 if (!S_ISREG(statbuf.st_mode))
961 fprintf(stderr,
962 _("%s: file \"%s\" is not a regular file\n"), progname, path);
963 fprintf(stderr,
964 _("This might mean you have a corrupted installation or identified\n"
965 "the wrong directory with the invocation option -L.\n"));
966 exit(1);
971 * write out the PG_VERSION file in the data dir, or its subdirectory
972 * if extrapath is not NULL
974 static void
975 set_short_version(char *short_version, char *extrapath)
977 FILE *version_file;
978 char *path;
980 if (extrapath == NULL)
982 path = pg_malloc(strlen(pg_data) + 12);
983 sprintf(path, "%s/PG_VERSION", pg_data);
985 else
987 path = pg_malloc(strlen(pg_data) + strlen(extrapath) + 13);
988 sprintf(path, "%s/%s/PG_VERSION", pg_data, extrapath);
990 version_file = fopen(path, PG_BINARY_W);
991 if (version_file == NULL)
993 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
994 progname, path, strerror(errno));
995 exit_nicely();
997 if (fprintf(version_file, "%s\n", short_version) < 0 ||
998 fclose(version_file))
1000 fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
1001 progname, path, strerror(errno));
1002 exit_nicely();
1004 free(path);
1008 * set up an empty config file so we can check config settings by launching
1009 * a test backend
1011 static void
1012 set_null_conf(void)
1014 FILE *conf_file;
1015 char *path;
1017 path = pg_malloc(strlen(pg_data) + 17);
1018 sprintf(path, "%s/postgresql.conf", pg_data);
1019 conf_file = fopen(path, PG_BINARY_W);
1020 if (conf_file == NULL)
1022 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1023 progname, path, strerror(errno));
1024 exit_nicely();
1026 if (fclose(conf_file))
1028 fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
1029 progname, path, strerror(errno));
1030 exit_nicely();
1032 free(path);
1036 * Determine platform-specific config settings
1038 * Use reasonable values if kernel will let us, else scale back. Probe
1039 * for max_connections first since it is subject to more constraints than
1040 * shared_buffers.
1042 static void
1043 test_config_settings(void)
1046 * These macros define the minimum shared_buffers we want for a given
1047 * max_connections value, and the max_fsm_pages setting to be used for a
1048 * given shared_buffers value. The arrays show the settings to try.
1051 #define MIN_BUFS_FOR_CONNS(nconns) ((nconns) * 10)
1052 #define FSM_FOR_BUFS(nbuffers) ((nbuffers) > 1000 ? 50 * (nbuffers) : 20000)
1054 static const int trial_conns[] = {
1055 100, 50, 40, 30, 20, 10
1057 static const int trial_bufs[] = {
1058 4096, 3584, 3072, 2560, 2048, 1536,
1059 1000, 900, 800, 700, 600, 500,
1060 400, 300, 200, 100, 50
1063 char cmd[MAXPGPATH];
1064 const int connslen = sizeof(trial_conns) / sizeof(int);
1065 const int bufslen = sizeof(trial_bufs) / sizeof(int);
1066 int i,
1067 status,
1068 test_conns,
1069 test_buffs,
1070 test_max_fsm,
1071 ok_buffers = 0;
1074 printf(_("selecting default max_connections ... "));
1075 fflush(stdout);
1077 for (i = 0; i < connslen; i++)
1079 test_conns = trial_conns[i];
1080 test_buffs = MIN_BUFS_FOR_CONNS(test_conns);
1081 test_max_fsm = FSM_FOR_BUFS(test_buffs);
1083 snprintf(cmd, sizeof(cmd),
1084 "%s\"%s\" --boot -x0 %s "
1085 "-c max_connections=%d "
1086 "-c shared_buffers=%d "
1087 "-c max_fsm_pages=%d "
1088 "< \"%s\" > \"%s\" 2>&1%s",
1089 SYSTEMQUOTE, backend_exec, boot_options,
1090 test_conns, test_buffs, test_max_fsm,
1091 DEVNULL, DEVNULL, SYSTEMQUOTE);
1092 status = system(cmd);
1093 if (status == 0)
1095 ok_buffers = test_buffs;
1096 break;
1099 if (i >= connslen)
1100 i = connslen - 1;
1101 n_connections = trial_conns[i];
1103 printf("%d\n", n_connections);
1105 printf(_("selecting default shared_buffers/max_fsm_pages ... "));
1106 fflush(stdout);
1108 for (i = 0; i < bufslen; i++)
1110 /* Use same amount of memory, independent of BLCKSZ */
1111 test_buffs = (trial_bufs[i] * 8192) / BLCKSZ;
1112 if (test_buffs <= ok_buffers)
1114 test_buffs = ok_buffers;
1115 break;
1117 test_max_fsm = FSM_FOR_BUFS(test_buffs);
1119 snprintf(cmd, sizeof(cmd),
1120 "%s\"%s\" --boot -x0 %s "
1121 "-c max_connections=%d "
1122 "-c shared_buffers=%d "
1123 "-c max_fsm_pages=%d "
1124 "< \"%s\" > \"%s\" 2>&1%s",
1125 SYSTEMQUOTE, backend_exec, boot_options,
1126 n_connections, test_buffs, test_max_fsm,
1127 DEVNULL, DEVNULL, SYSTEMQUOTE);
1128 status = system(cmd);
1129 if (status == 0)
1130 break;
1132 n_buffers = test_buffs;
1133 n_fsm_pages = FSM_FOR_BUFS(n_buffers);
1135 if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
1136 printf("%dMB/%d\n", (n_buffers * (BLCKSZ / 1024)) / 1024, n_fsm_pages);
1137 else
1138 printf("%dkB/%d\n", n_buffers * (BLCKSZ / 1024), n_fsm_pages);
1142 * set up all the config files
1144 static void
1145 setup_config(void)
1147 char **conflines;
1148 char repltok[100];
1149 char path[MAXPGPATH];
1151 fputs(_("creating configuration files ... "), stdout);
1152 fflush(stdout);
1154 /* postgresql.conf */
1156 conflines = readfile(conf_file);
1158 snprintf(repltok, sizeof(repltok), "max_connections = %d", n_connections);
1159 conflines = replace_token(conflines, "#max_connections = 100", repltok);
1161 if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
1162 snprintf(repltok, sizeof(repltok), "shared_buffers = %dMB",
1163 (n_buffers * (BLCKSZ / 1024)) / 1024);
1164 else
1165 snprintf(repltok, sizeof(repltok), "shared_buffers = %dkB",
1166 n_buffers * (BLCKSZ / 1024));
1167 conflines = replace_token(conflines, "#shared_buffers = 32MB", repltok);
1169 snprintf(repltok, sizeof(repltok), "max_fsm_pages = %d", n_fsm_pages);
1170 conflines = replace_token(conflines, "#max_fsm_pages = 204800", repltok);
1172 #if DEF_PGPORT != 5432
1173 snprintf(repltok, sizeof(repltok), "#port = %d", DEF_PGPORT);
1174 conflines = replace_token(conflines, "#port = 5432", repltok);
1175 #endif
1177 snprintf(repltok, sizeof(repltok), "lc_messages = '%s'",
1178 escape_quotes(lc_messages));
1179 conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
1181 snprintf(repltok, sizeof(repltok), "lc_monetary = '%s'",
1182 escape_quotes(lc_monetary));
1183 conflines = replace_token(conflines, "#lc_monetary = 'C'", repltok);
1185 snprintf(repltok, sizeof(repltok), "lc_numeric = '%s'",
1186 escape_quotes(lc_numeric));
1187 conflines = replace_token(conflines, "#lc_numeric = 'C'", repltok);
1189 snprintf(repltok, sizeof(repltok), "lc_time = '%s'",
1190 escape_quotes(lc_time));
1191 conflines = replace_token(conflines, "#lc_time = 'C'", repltok);
1193 switch (locale_date_order(lc_time))
1195 case DATEORDER_YMD:
1196 strcpy(repltok, "datestyle = 'iso, ymd'");
1197 break;
1198 case DATEORDER_DMY:
1199 strcpy(repltok, "datestyle = 'iso, dmy'");
1200 break;
1201 case DATEORDER_MDY:
1202 default:
1203 strcpy(repltok, "datestyle = 'iso, mdy'");
1204 break;
1206 conflines = replace_token(conflines, "#datestyle = 'iso, mdy'", repltok);
1208 snprintf(repltok, sizeof(repltok),
1209 "default_text_search_config = 'pg_catalog.%s'",
1210 escape_quotes(default_text_search_config));
1211 conflines = replace_token(conflines,
1212 "#default_text_search_config = 'pg_catalog.simple'",
1213 repltok);
1215 snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
1217 writefile(path, conflines);
1218 chmod(path, 0600);
1220 free(conflines);
1223 /* pg_hba.conf */
1225 conflines = readfile(hba_file);
1227 #ifndef HAVE_UNIX_SOCKETS
1228 conflines = filter_lines_with_token(conflines, "@remove-line-for-nolocal@");
1229 #else
1230 conflines = replace_token(conflines, "@remove-line-for-nolocal@", "");
1231 #endif
1233 #ifdef HAVE_IPV6
1236 * Probe to see if there is really any platform support for IPv6, and
1237 * comment out the relevant pg_hba line if not. This avoids runtime
1238 * warnings if getaddrinfo doesn't actually cope with IPv6. Particularly
1239 * useful on Windows, where executables built on a machine with IPv6 may
1240 * have to run on a machine without.
1243 struct addrinfo *gai_result;
1244 struct addrinfo hints;
1245 int err = 0;
1247 #ifdef WIN32
1248 /* need to call WSAStartup before calling getaddrinfo */
1249 WSADATA wsaData;
1251 err = WSAStartup(MAKEWORD(2, 2), &wsaData);
1252 #endif
1254 /* for best results, this code should match parse_hba() */
1255 hints.ai_flags = AI_NUMERICHOST;
1256 hints.ai_family = PF_UNSPEC;
1257 hints.ai_socktype = 0;
1258 hints.ai_protocol = 0;
1259 hints.ai_addrlen = 0;
1260 hints.ai_canonname = NULL;
1261 hints.ai_addr = NULL;
1262 hints.ai_next = NULL;
1264 if (err != 0 ||
1265 getaddrinfo("::1", NULL, &hints, &gai_result) != 0)
1266 conflines = replace_token(conflines,
1267 "host all all ::1",
1268 "#host all all ::1");
1270 #else /* !HAVE_IPV6 */
1271 /* If we didn't compile IPV6 support at all, always comment it out */
1272 conflines = replace_token(conflines,
1273 "host all all ::1",
1274 "#host all all ::1");
1275 #endif /* HAVE_IPV6 */
1277 /* Replace default authentication methods */
1278 conflines = replace_token(conflines,
1279 "@authmethod@",
1280 authmethod);
1282 conflines = replace_token(conflines,
1283 "@authcomment@",
1284 strcmp(authmethod, "trust") ? "" : AUTHTRUST_WARNING);
1286 snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data);
1288 writefile(path, conflines);
1289 chmod(path, 0600);
1291 free(conflines);
1293 /* pg_ident.conf */
1295 conflines = readfile(ident_file);
1297 snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data);
1299 writefile(path, conflines);
1300 chmod(path, 0600);
1302 free(conflines);
1304 check_ok();
1309 * run the BKI script in bootstrap mode to create template1
1311 static void
1312 bootstrap_template1(char *short_version)
1314 PG_CMD_DECL;
1315 char **line;
1316 char *talkargs = "";
1317 char **bki_lines;
1318 char headerline[MAXPGPATH];
1320 printf(_("creating template1 database in %s/base/1 ... "), pg_data);
1321 fflush(stdout);
1323 if (debug)
1324 talkargs = "-d 5";
1326 bki_lines = readfile(bki_file);
1328 /* Check that bki file appears to be of the right version */
1330 snprintf(headerline, sizeof(headerline), "# PostgreSQL %s\n",
1331 short_version);
1333 if (strcmp(headerline, *bki_lines) != 0)
1335 fprintf(stderr,
1336 _("%s: input file \"%s\" does not belong to PostgreSQL %s\n"
1337 "Check your installation or specify the correct path "
1338 "using the option -L.\n"),
1339 progname, bki_file, PG_VERSION);
1340 exit_nicely();
1343 bki_lines = replace_token(bki_lines, "POSTGRES", username);
1345 bki_lines = replace_token(bki_lines, "ENCODING", encodingid);
1348 * Pass correct LC_xxx environment to bootstrap.
1350 * The shell script arranged to restore the LC settings afterwards, but
1351 * there doesn't seem to be any compelling reason to do that.
1353 snprintf(cmd, sizeof(cmd), "LC_COLLATE=%s", lc_collate);
1354 putenv(xstrdup(cmd));
1356 snprintf(cmd, sizeof(cmd), "LC_CTYPE=%s", lc_ctype);
1357 putenv(xstrdup(cmd));
1359 unsetenv("LC_ALL");
1361 /* Also ensure backend isn't confused by this environment var: */
1362 unsetenv("PGCLIENTENCODING");
1364 snprintf(cmd, sizeof(cmd),
1365 "\"%s\" --boot -x1 %s %s",
1366 backend_exec, boot_options, talkargs);
1368 PG_CMD_OPEN;
1370 for (line = bki_lines; *line != NULL; line++)
1372 PG_CMD_PUTS(*line);
1373 free(*line);
1376 PG_CMD_CLOSE;
1378 free(bki_lines);
1380 check_ok();
1384 * set up the shadow password table
1386 static void
1387 setup_auth(void)
1389 PG_CMD_DECL;
1390 const char **line;
1391 static const char *pg_authid_setup[] = {
1393 * Create triggers to ensure manual updates to shared catalogs will be
1394 * reflected into their "flat file" copies.
1396 "CREATE TRIGGER pg_sync_pg_database "
1397 " AFTER INSERT OR UPDATE OR DELETE ON pg_database "
1398 " FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
1399 "CREATE TRIGGER pg_sync_pg_authid "
1400 " AFTER INSERT OR UPDATE OR DELETE ON pg_authid "
1401 " FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
1402 "CREATE TRIGGER pg_sync_pg_auth_members "
1403 " AFTER INSERT OR UPDATE OR DELETE ON pg_auth_members "
1404 " FOR EACH STATEMENT EXECUTE PROCEDURE flatfile_update_trigger();\n",
1407 * The authid table shouldn't be readable except through views, to
1408 * ensure passwords are not publicly visible.
1410 "REVOKE ALL on pg_authid FROM public;\n",
1411 NULL
1414 fputs(_("initializing pg_authid ... "), stdout);
1415 fflush(stdout);
1417 snprintf(cmd, sizeof(cmd),
1418 "\"%s\" %s template1 >%s",
1419 backend_exec, backend_options,
1420 DEVNULL);
1422 PG_CMD_OPEN;
1424 for (line = pg_authid_setup; *line != NULL; line++)
1425 PG_CMD_PUTS(*line);
1427 PG_CMD_CLOSE;
1429 check_ok();
1433 * get the superuser password if required, and call postgres to set it
1435 static void
1436 get_set_pwd(void)
1438 PG_CMD_DECL;
1440 char *pwd1,
1441 *pwd2;
1442 char pwdpath[MAXPGPATH];
1443 struct stat statbuf;
1445 if (pwprompt)
1448 * Read password from terminal
1450 pwd1 = simple_prompt("Enter new superuser password: ", 100, false);
1451 pwd2 = simple_prompt("Enter it again: ", 100, false);
1452 if (strcmp(pwd1, pwd2) != 0)
1454 fprintf(stderr, _("Passwords didn't match.\n"));
1455 exit_nicely();
1457 free(pwd2);
1459 else
1462 * Read password from file
1464 * Ideally this should insist that the file not be world-readable.
1465 * However, this option is mainly intended for use on Windows where
1466 * file permissions may not exist at all, so we'll skip the paranoia
1467 * for now.
1469 FILE *pwf = fopen(pwfilename, "r");
1470 char pwdbuf[MAXPGPATH];
1471 int i;
1473 if (!pwf)
1475 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1476 progname, pwfilename, strerror(errno));
1477 exit_nicely();
1479 if (!fgets(pwdbuf, sizeof(pwdbuf), pwf))
1481 fprintf(stderr, _("%s: could not read password from file \"%s\": %s\n"),
1482 progname, pwfilename, strerror(errno));
1483 exit_nicely();
1485 fclose(pwf);
1487 i = strlen(pwdbuf);
1488 while (i > 0 && (pwdbuf[i - 1] == '\r' || pwdbuf[i - 1] == '\n'))
1489 pwdbuf[--i] = '\0';
1491 pwd1 = xstrdup(pwdbuf);
1494 printf(_("setting password ... "));
1495 fflush(stdout);
1497 snprintf(cmd, sizeof(cmd),
1498 "\"%s\" %s template1 >%s",
1499 backend_exec, backend_options,
1500 DEVNULL);
1502 PG_CMD_OPEN;
1504 PG_CMD_PRINTF2("ALTER USER \"%s\" WITH PASSWORD E'%s';\n",
1505 username, escape_quotes(pwd1));
1507 /* MM: pwd1 is no longer needed, freeing it */
1508 free(pwd1);
1510 PG_CMD_CLOSE;
1512 check_ok();
1514 snprintf(pwdpath, sizeof(pwdpath), "%s/global/pg_auth", pg_data);
1515 if (stat(pwdpath, &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
1517 fprintf(stderr,
1518 _("%s: The password file was not generated. "
1519 "Please report this problem.\n"),
1520 progname);
1521 exit_nicely();
1526 * set up pg_depend
1528 static void
1529 setup_depend(void)
1531 PG_CMD_DECL;
1532 const char **line;
1533 static const char *pg_depend_setup[] = {
1535 * Make PIN entries in pg_depend for all objects made so far in the
1536 * tables that the dependency code handles. This is overkill (the
1537 * system doesn't really depend on having every last weird datatype,
1538 * for instance) but generating only the minimum required set of
1539 * dependencies seems hard.
1541 * Note that we deliberately do not pin the system views, which
1542 * haven't been created yet. Also, no conversions, databases, or
1543 * tablespaces are pinned.
1545 * First delete any already-made entries; PINs override all else, and
1546 * must be the only entries for their objects.
1548 "DELETE FROM pg_depend;\n",
1549 "VACUUM pg_depend;\n",
1550 "DELETE FROM pg_shdepend;\n",
1551 "VACUUM pg_shdepend;\n",
1553 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1554 " FROM pg_class;\n",
1555 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1556 " FROM pg_proc;\n",
1557 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1558 " FROM pg_type;\n",
1559 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1560 " FROM pg_cast;\n",
1561 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1562 " FROM pg_constraint;\n",
1563 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1564 " FROM pg_attrdef;\n",
1565 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1566 " FROM pg_language;\n",
1567 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1568 " FROM pg_operator;\n",
1569 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1570 " FROM pg_opclass;\n",
1571 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1572 " FROM pg_opfamily;\n",
1573 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1574 " FROM pg_amop;\n",
1575 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1576 " FROM pg_amproc;\n",
1577 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1578 " FROM pg_rewrite;\n",
1579 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1580 " FROM pg_trigger;\n",
1583 * restriction here to avoid pinning the public namespace
1585 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1586 " FROM pg_namespace "
1587 " WHERE nspname LIKE 'pg%';\n",
1589 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1590 " FROM pg_ts_parser;\n",
1591 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1592 " FROM pg_ts_dict;\n",
1593 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1594 " FROM pg_ts_template;\n",
1595 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1596 " FROM pg_ts_config;\n",
1597 "INSERT INTO pg_shdepend SELECT 0, 0, 0, tableoid, oid, 'p' "
1598 " FROM pg_authid;\n",
1599 NULL
1602 fputs(_("initializing dependencies ... "), stdout);
1603 fflush(stdout);
1605 snprintf(cmd, sizeof(cmd),
1606 "\"%s\" %s template1 >%s",
1607 backend_exec, backend_options,
1608 DEVNULL);
1610 PG_CMD_OPEN;
1612 for (line = pg_depend_setup; *line != NULL; line++)
1613 PG_CMD_PUTS(*line);
1615 PG_CMD_CLOSE;
1617 check_ok();
1621 * set up system views
1623 static void
1624 setup_sysviews(void)
1626 PG_CMD_DECL;
1627 char **line;
1628 char **sysviews_setup;
1630 fputs(_("creating system views ... "), stdout);
1631 fflush(stdout);
1633 sysviews_setup = readfile(system_views_file);
1636 * We use -j here to avoid backslashing stuff in system_views.sql
1638 snprintf(cmd, sizeof(cmd),
1639 "\"%s\" %s -j template1 >%s",
1640 backend_exec, backend_options,
1641 DEVNULL);
1643 PG_CMD_OPEN;
1645 for (line = sysviews_setup; *line != NULL; line++)
1647 PG_CMD_PUTS(*line);
1648 free(*line);
1651 PG_CMD_CLOSE;
1653 free(sysviews_setup);
1655 check_ok();
1659 * load description data
1661 static void
1662 setup_description(void)
1664 PG_CMD_DECL;
1666 fputs(_("loading system objects' descriptions ... "), stdout);
1667 fflush(stdout);
1669 snprintf(cmd, sizeof(cmd),
1670 "\"%s\" %s template1 >%s",
1671 backend_exec, backend_options,
1672 DEVNULL);
1674 PG_CMD_OPEN;
1676 PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_description ( "
1677 " objoid oid, "
1678 " classname name, "
1679 " objsubid int4, "
1680 " description text) WITHOUT OIDS;\n");
1682 PG_CMD_PRINTF1("COPY tmp_pg_description FROM E'%s';\n",
1683 escape_quotes(desc_file));
1685 PG_CMD_PUTS("INSERT INTO pg_description "
1686 " SELECT t.objoid, c.oid, t.objsubid, t.description "
1687 " FROM tmp_pg_description t, pg_class c "
1688 " WHERE c.relname = t.classname;\n");
1690 PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_shdescription ( "
1691 " objoid oid, "
1692 " classname name, "
1693 " description text) WITHOUT OIDS;\n");
1695 PG_CMD_PRINTF1("COPY tmp_pg_shdescription FROM E'%s';\n",
1696 escape_quotes(shdesc_file));
1698 PG_CMD_PUTS("INSERT INTO pg_shdescription "
1699 " SELECT t.objoid, c.oid, t.description "
1700 " FROM tmp_pg_shdescription t, pg_class c "
1701 " WHERE c.relname = t.classname;\n");
1703 PG_CMD_CLOSE;
1705 check_ok();
1709 * load conversion functions
1711 static void
1712 setup_conversion(void)
1714 PG_CMD_DECL;
1715 char **line;
1716 char **conv_lines;
1718 fputs(_("creating conversions ... "), stdout);
1719 fflush(stdout);
1721 snprintf(cmd, sizeof(cmd),
1722 "\"%s\" %s template1 >%s",
1723 backend_exec, backend_options,
1724 DEVNULL);
1726 PG_CMD_OPEN;
1728 conv_lines = readfile(conversion_file);
1729 for (line = conv_lines; *line != NULL; line++)
1731 if (strstr(*line, "DROP CONVERSION") != *line)
1732 PG_CMD_PUTS(*line);
1733 free(*line);
1736 free(conv_lines);
1738 PG_CMD_CLOSE;
1740 check_ok();
1744 * load extra dictionaries (Snowball stemmers)
1746 static void
1747 setup_dictionary(void)
1749 PG_CMD_DECL;
1750 char **line;
1751 char **conv_lines;
1753 fputs(_("creating dictionaries ... "), stdout);
1754 fflush(stdout);
1757 * We use -j here to avoid backslashing stuff
1759 snprintf(cmd, sizeof(cmd),
1760 "\"%s\" %s -j template1 >%s",
1761 backend_exec, backend_options,
1762 DEVNULL);
1764 PG_CMD_OPEN;
1766 conv_lines = readfile(dictionary_file);
1767 for (line = conv_lines; *line != NULL; line++)
1769 PG_CMD_PUTS(*line);
1770 free(*line);
1773 free(conv_lines);
1775 PG_CMD_CLOSE;
1777 check_ok();
1781 * Set up privileges
1783 * We mark most system catalogs as world-readable. We don't currently have
1784 * to touch functions, languages, or databases, because their default
1785 * permissions are OK.
1787 * Some objects may require different permissions by default, so we
1788 * make sure we don't overwrite privilege sets that have already been
1789 * set (NOT NULL).
1791 static void
1792 setup_privileges(void)
1794 PG_CMD_DECL;
1795 char **line;
1796 char **priv_lines;
1797 static char *privileges_setup[] = {
1798 "UPDATE pg_class "
1799 " SET relacl = E'{\"=r/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
1800 " WHERE relkind IN ('r', 'v', 'S') AND relacl IS NULL;\n",
1801 "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n",
1802 "GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n",
1803 NULL
1806 fputs(_("setting privileges on built-in objects ... "), stdout);
1807 fflush(stdout);
1809 snprintf(cmd, sizeof(cmd),
1810 "\"%s\" %s template1 >%s",
1811 backend_exec, backend_options,
1812 DEVNULL);
1814 PG_CMD_OPEN;
1816 priv_lines = replace_token(privileges_setup,
1817 "$POSTGRES_SUPERUSERNAME", username);
1818 for (line = priv_lines; *line != NULL; line++)
1819 PG_CMD_PUTS(*line);
1821 PG_CMD_CLOSE;
1823 check_ok();
1827 * extract the strange version of version required for information schema
1828 * (09.08.0007abc)
1830 static void
1831 set_info_version(void)
1833 char *letterversion;
1834 long major = 0,
1835 minor = 0,
1836 micro = 0;
1837 char *endptr;
1838 char *vstr = xstrdup(PG_VERSION);
1839 char *ptr;
1841 ptr = vstr + (strlen(vstr) - 1);
1842 while (ptr != vstr && (*ptr < '0' || *ptr > '9'))
1843 ptr--;
1844 letterversion = ptr + 1;
1845 major = strtol(vstr, &endptr, 10);
1846 if (*endptr)
1847 minor = strtol(endptr + 1, &endptr, 10);
1848 if (*endptr)
1849 micro = strtol(endptr + 1, &endptr, 10);
1850 snprintf(infoversion, sizeof(infoversion), "%02ld.%02ld.%04ld%s",
1851 major, minor, micro, letterversion);
1855 * load info schema and populate from features file
1857 static void
1858 setup_schema(void)
1860 PG_CMD_DECL;
1861 char **line;
1862 char **lines;
1864 fputs(_("creating information schema ... "), stdout);
1865 fflush(stdout);
1867 lines = readfile(info_schema_file);
1870 * We use -j here to avoid backslashing stuff in information_schema.sql
1872 snprintf(cmd, sizeof(cmd),
1873 "\"%s\" %s -j template1 >%s",
1874 backend_exec, backend_options,
1875 DEVNULL);
1877 PG_CMD_OPEN;
1879 for (line = lines; *line != NULL; line++)
1881 PG_CMD_PUTS(*line);
1882 free(*line);
1885 free(lines);
1887 PG_CMD_CLOSE;
1889 snprintf(cmd, sizeof(cmd),
1890 "\"%s\" %s template1 >%s",
1891 backend_exec, backend_options,
1892 DEVNULL);
1894 PG_CMD_OPEN;
1896 PG_CMD_PRINTF1("UPDATE information_schema.sql_implementation_info "
1897 " SET character_value = '%s' "
1898 " WHERE implementation_info_name = 'DBMS VERSION';\n",
1899 infoversion);
1901 PG_CMD_PRINTF1("COPY information_schema.sql_features "
1902 " (feature_id, feature_name, sub_feature_id, "
1903 " sub_feature_name, is_supported, comments) "
1904 " FROM E'%s';\n",
1905 escape_quotes(features_file));
1907 PG_CMD_CLOSE;
1909 check_ok();
1913 * clean everything up in template1
1915 static void
1916 vacuum_db(void)
1918 PG_CMD_DECL;
1920 fputs(_("vacuuming database template1 ... "), stdout);
1921 fflush(stdout);
1923 snprintf(cmd, sizeof(cmd),
1924 "\"%s\" %s template1 >%s",
1925 backend_exec, backend_options,
1926 DEVNULL);
1928 PG_CMD_OPEN;
1930 PG_CMD_PUTS("ANALYZE;\nVACUUM FULL;\nVACUUM FREEZE;\n");
1932 PG_CMD_CLOSE;
1934 check_ok();
1938 * copy template1 to template0
1940 static void
1941 make_template0(void)
1943 PG_CMD_DECL;
1944 const char **line;
1945 static const char *template0_setup[] = {
1946 "CREATE DATABASE template0;\n",
1947 "UPDATE pg_database SET "
1948 " datistemplate = 't', "
1949 " datallowconn = 'f' "
1950 " WHERE datname = 'template0';\n",
1953 * We use the OID of template0 to determine lastsysoid
1955 "UPDATE pg_database SET datlastsysoid = "
1956 " (SELECT oid FROM pg_database "
1957 " WHERE datname = 'template0');\n",
1960 * Explicitly revoke public create-schema and create-temp-table
1961 * privileges in template1 and template0; else the latter would be on
1962 * by default
1964 "REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n",
1965 "REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n",
1968 * Finally vacuum to clean up dead rows in pg_database
1970 "VACUUM FULL pg_database;\n",
1971 NULL
1974 fputs(_("copying template1 to template0 ... "), stdout);
1975 fflush(stdout);
1977 snprintf(cmd, sizeof(cmd),
1978 "\"%s\" %s template1 >%s",
1979 backend_exec, backend_options,
1980 DEVNULL);
1982 PG_CMD_OPEN;
1984 for (line = template0_setup; *line; line++)
1985 PG_CMD_PUTS(*line);
1987 PG_CMD_CLOSE;
1989 check_ok();
1993 * copy template1 to postgres
1995 static void
1996 make_postgres(void)
1998 PG_CMD_DECL;
1999 const char **line;
2000 static const char *postgres_setup[] = {
2001 "CREATE DATABASE postgres;\n",
2002 NULL
2005 fputs(_("copying template1 to postgres ... "), stdout);
2006 fflush(stdout);
2008 snprintf(cmd, sizeof(cmd),
2009 "\"%s\" %s template1 >%s",
2010 backend_exec, backend_options,
2011 DEVNULL);
2013 PG_CMD_OPEN;
2015 for (line = postgres_setup; *line; line++)
2016 PG_CMD_PUTS(*line);
2018 PG_CMD_CLOSE;
2020 check_ok();
2025 * signal handler in case we are interrupted.
2027 * The Windows runtime docs at
2028 * http://msdn.microsoft.com/library/en-us/vclib/html/_crt_signal.asp
2029 * specifically forbid a number of things being done from a signal handler,
2030 * including IO, memory allocation and system calls, and only allow jmpbuf
2031 * if you are handling SIGFPE.
2033 * I avoided doing the forbidden things by setting a flag instead of calling
2034 * exit_nicely() directly.
2036 * Also note the behaviour of Windows with SIGINT, which says this:
2037 * Note SIGINT is not supported for any Win32 application, including
2038 * Windows 98/Me and Windows NT/2000/XP. When a CTRL+C interrupt occurs,
2039 * Win32 operating systems generate a new thread to specifically handle
2040 * that interrupt. This can cause a single-thread application such as UNIX,
2041 * to become multithreaded, resulting in unexpected behavior.
2043 * I have no idea how to handle this. (Strange they call UNIX an application!)
2044 * So this will need some testing on Windows.
2046 static void
2047 trapsig(int signum)
2049 /* handle systems that reset the handler, like Windows (grr) */
2050 pqsignal(signum, trapsig);
2051 caught_signal = true;
2055 * call exit_nicely() if we got a signal, or else output "ok".
2057 static void
2058 check_ok(void)
2060 if (caught_signal)
2062 printf(_("caught signal\n"));
2063 fflush(stdout);
2064 exit_nicely();
2066 else if (output_failed)
2068 printf(_("could not write to child process: %s\n"),
2069 strerror(output_errno));
2070 fflush(stdout);
2071 exit_nicely();
2073 else
2075 /* all seems well */
2076 printf(_("ok\n"));
2077 fflush(stdout);
2082 * Escape (by doubling) any single quotes or backslashes in given string
2084 * Note: this is used to process both postgresql.conf entries and SQL
2085 * string literals. Since postgresql.conf strings are defined to treat
2086 * backslashes as escapes, we have to double backslashes here. Hence,
2087 * when using this for a SQL string literal, use E'' syntax.
2089 * We do not need to worry about encoding considerations because all
2090 * valid backend encodings are ASCII-safe.
2092 static char *
2093 escape_quotes(const char *src)
2095 int len = strlen(src),
2098 char *result = pg_malloc(len * 2 + 1);
2100 for (i = 0, j = 0; i < len; i++)
2102 if (SQL_STR_DOUBLE(src[i], true))
2103 result[j++] = src[i];
2104 result[j++] = src[i];
2106 result[j] = '\0';
2107 return result;
2110 /* Hack to suppress a warning about %x from some versions of gcc */
2111 static inline size_t
2112 my_strftime(char *s, size_t max, const char *fmt, const struct tm * tm)
2114 return strftime(s, max, fmt, tm);
2118 * Determine likely date order from locale
2120 static int
2121 locale_date_order(const char *locale)
2123 struct tm testtime;
2124 char buf[128];
2125 char *posD;
2126 char *posM;
2127 char *posY;
2128 char *save;
2129 size_t res;
2130 int result;
2132 result = DATEORDER_MDY; /* default */
2134 save = setlocale(LC_TIME, NULL);
2135 if (!save)
2136 return result;
2137 save = xstrdup(save);
2139 setlocale(LC_TIME, locale);
2141 memset(&testtime, 0, sizeof(testtime));
2142 testtime.tm_mday = 22;
2143 testtime.tm_mon = 10; /* November, should come out as "11" */
2144 testtime.tm_year = 133; /* 2033 */
2146 res = my_strftime(buf, sizeof(buf), "%x", &testtime);
2148 setlocale(LC_TIME, save);
2149 free(save);
2151 if (res == 0)
2152 return result;
2154 posM = strstr(buf, "11");
2155 posD = strstr(buf, "22");
2156 posY = strstr(buf, "33");
2158 if (!posM || !posD || !posY)
2159 return result;
2161 if (posY < posM && posM < posD)
2162 result = DATEORDER_YMD;
2163 else if (posD < posM)
2164 result = DATEORDER_DMY;
2165 else
2166 result = DATEORDER_MDY;
2168 return result;
2172 * check if given string is a valid locale specifier
2174 static bool
2175 chklocale(const char *locale)
2177 bool ret;
2178 int category = LC_CTYPE;
2179 char *save;
2181 save = setlocale(category, NULL);
2182 if (!save)
2183 return false; /* should not happen; */
2185 save = xstrdup(save);
2187 ret = (setlocale(category, locale) != NULL);
2189 setlocale(category, save);
2190 free(save);
2192 /* should we exit here? */
2193 if (!ret)
2194 fprintf(stderr, _("%s: invalid locale name \"%s\"\n"), progname, locale);
2196 return ret;
2200 * set up the locale variables
2202 * assumes we have called setlocale(LC_ALL,"")
2204 static void
2205 setlocales(void)
2207 /* set empty lc_* values to locale config if set */
2209 if (strlen(locale) > 0)
2211 if (strlen(lc_ctype) == 0)
2212 lc_ctype = locale;
2213 if (strlen(lc_collate) == 0)
2214 lc_collate = locale;
2215 if (strlen(lc_numeric) == 0)
2216 lc_numeric = locale;
2217 if (strlen(lc_time) == 0)
2218 lc_time = locale;
2219 if (strlen(lc_monetary) == 0)
2220 lc_monetary = locale;
2221 if (strlen(lc_messages) == 0)
2222 lc_messages = locale;
2226 * override absent/invalid config settings from initdb's locale settings
2229 if (strlen(lc_ctype) == 0 || !chklocale(lc_ctype))
2230 lc_ctype = xstrdup(setlocale(LC_CTYPE, NULL));
2231 if (strlen(lc_collate) == 0 || !chklocale(lc_collate))
2232 lc_collate = xstrdup(setlocale(LC_COLLATE, NULL));
2233 if (strlen(lc_numeric) == 0 || !chklocale(lc_numeric))
2234 lc_numeric = xstrdup(setlocale(LC_NUMERIC, NULL));
2235 if (strlen(lc_time) == 0 || !chklocale(lc_time))
2236 lc_time = xstrdup(setlocale(LC_TIME, NULL));
2237 if (strlen(lc_monetary) == 0 || !chklocale(lc_monetary))
2238 lc_monetary = xstrdup(setlocale(LC_MONETARY, NULL));
2239 if (strlen(lc_messages) == 0 || !chklocale(lc_messages))
2240 #if defined(LC_MESSAGES) && !defined(WIN32)
2242 /* when available get the current locale setting */
2243 lc_messages = xstrdup(setlocale(LC_MESSAGES, NULL));
2245 #else
2247 /* when not available, get the CTYPE setting */
2248 lc_messages = xstrdup(setlocale(LC_CTYPE, NULL));
2250 #endif
2254 #ifdef WIN32
2255 typedef BOOL(WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
2257 #define DISABLE_MAX_PRIVILEGE 0x1
2260 * Create a restricted token and execute the specified process with it.
2262 * Returns 0 on failure, non-zero on success, same as CreateProcess().
2264 * On NT4, or any other system not containing the required functions, will
2265 * NOT execute anything.
2267 static int
2268 CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION * processInfo)
2270 BOOL b;
2271 STARTUPINFO si;
2272 HANDLE origToken;
2273 HANDLE restrictedToken;
2274 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
2275 SID_AND_ATTRIBUTES dropSids[2];
2276 __CreateRestrictedToken _CreateRestrictedToken = NULL;
2277 HANDLE Advapi32Handle;
2279 ZeroMemory(&si, sizeof(si));
2280 si.cb = sizeof(si);
2282 Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
2283 if (Advapi32Handle != NULL)
2285 _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
2288 if (_CreateRestrictedToken == NULL)
2290 fprintf(stderr, "WARNING: cannot create restricted tokens on this platform\n");
2291 if (Advapi32Handle != NULL)
2292 FreeLibrary(Advapi32Handle);
2293 return 0;
2296 /* Open the current token to use as a base for the restricted one */
2297 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
2299 fprintf(stderr, "Failed to open process token: %lu\n", GetLastError());
2300 return 0;
2303 /* Allocate list of SIDs to remove */
2304 ZeroMemory(&dropSids, sizeof(dropSids));
2305 if (!AllocateAndInitializeSid(&NtAuthority, 2,
2306 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
2307 0, &dropSids[0].Sid) ||
2308 !AllocateAndInitializeSid(&NtAuthority, 2,
2309 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
2310 0, &dropSids[1].Sid))
2312 fprintf(stderr, "Failed to allocate SIDs: %lu\n", GetLastError());
2313 return 0;
2316 b = _CreateRestrictedToken(origToken,
2317 DISABLE_MAX_PRIVILEGE,
2318 sizeof(dropSids) / sizeof(dropSids[0]),
2319 dropSids,
2320 0, NULL,
2321 0, NULL,
2322 &restrictedToken);
2324 FreeSid(dropSids[1].Sid);
2325 FreeSid(dropSids[0].Sid);
2326 CloseHandle(origToken);
2327 FreeLibrary(Advapi32Handle);
2329 if (!b)
2331 fprintf(stderr, "Failed to create restricted token: %lu\n", GetLastError());
2332 return 0;
2335 return CreateProcessAsUser(restrictedToken, NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, processInfo);
2337 #endif
2340 * print help text
2342 static void
2343 usage(const char *progname)
2345 printf(_("%s initializes a PostgreSQL database cluster.\n\n"), progname);
2346 printf(_("Usage:\n"));
2347 printf(_(" %s [OPTION]... [DATADIR]\n"), progname);
2348 printf(_("\nOptions:\n"));
2349 printf(_(" [-D, --pgdata=]DATADIR location for this database cluster\n"));
2350 printf(_(" -E, --encoding=ENCODING set default encoding for new databases\n"));
2351 printf(_(" --locale=LOCALE initialize database cluster with given locale\n"));
2352 printf(_(" --lc-collate, --lc-ctype, --lc-messages=LOCALE\n"
2353 " --lc-monetary, --lc-numeric, --lc-time=LOCALE\n"
2354 " initialize database cluster with given locale\n"
2355 " in the respective category (default taken from\n"
2356 " environment)\n"));
2357 printf(_(" --no-locale equivalent to --locale=C\n"));
2358 printf(_(" -T, --text-search-config=CFG\n"
2359 " default text search configuration\n"));
2360 printf(_(" -X, --xlogdir=XLOGDIR location for the transaction log directory\n"));
2361 printf(_(" -A, --auth=METHOD default authentication method for local connections\n"));
2362 printf(_(" -U, --username=NAME database superuser name\n"));
2363 printf(_(" -W, --pwprompt prompt for a password for the new superuser\n"));
2364 printf(_(" --pwfile=FILE read password for the new superuser from file\n"));
2365 printf(_(" -?, --help show this help, then exit\n"));
2366 printf(_(" -V, --version output version information, then exit\n"));
2367 printf(_("\nLess commonly used options:\n"));
2368 printf(_(" -d, --debug generate lots of debugging output\n"));
2369 printf(_(" -s, --show show internal settings\n"));
2370 printf(_(" -L DIRECTORY where to find the input files\n"));
2371 printf(_(" -n, --noclean do not clean up after errors\n"));
2372 printf(_("\nIf the data directory is not specified, the environment variable PGDATA\n"
2373 "is used.\n"));
2374 printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
2378 main(int argc, char *argv[])
2381 * options with no short version return a low integer, the rest return
2382 * their short version value
2384 static struct option long_options[] = {
2385 {"pgdata", required_argument, NULL, 'D'},
2386 {"encoding", required_argument, NULL, 'E'},
2387 {"locale", required_argument, NULL, 1},
2388 {"lc-collate", required_argument, NULL, 2},
2389 {"lc-ctype", required_argument, NULL, 3},
2390 {"lc-monetary", required_argument, NULL, 4},
2391 {"lc-numeric", required_argument, NULL, 5},
2392 {"lc-time", required_argument, NULL, 6},
2393 {"lc-messages", required_argument, NULL, 7},
2394 {"no-locale", no_argument, NULL, 8},
2395 {"text-search-config", required_argument, NULL, 'T'},
2396 {"auth", required_argument, NULL, 'A'},
2397 {"pwprompt", no_argument, NULL, 'W'},
2398 {"pwfile", required_argument, NULL, 9},
2399 {"username", required_argument, NULL, 'U'},
2400 {"help", no_argument, NULL, '?'},
2401 {"version", no_argument, NULL, 'V'},
2402 {"debug", no_argument, NULL, 'd'},
2403 {"show", no_argument, NULL, 's'},
2404 {"noclean", no_argument, NULL, 'n'},
2405 {"xlogdir", required_argument, NULL, 'X'},
2406 {NULL, 0, NULL, 0}
2409 int c,
2411 ret;
2412 int option_index;
2413 char *short_version;
2414 char *effective_user;
2415 char *pgdenv; /* PGDATA value gotten from and sent to
2416 * environment */
2417 char bin_dir[MAXPGPATH];
2418 char *pg_data_native;
2420 #ifdef WIN32
2421 char *restrict_env;
2422 #endif
2423 static const char *subdirs[] = {
2424 "global",
2425 "pg_xlog",
2426 "pg_xlog/archive_status",
2427 "pg_clog",
2428 "pg_subtrans",
2429 "pg_twophase",
2430 "pg_multixact/members",
2431 "pg_multixact/offsets",
2432 "base",
2433 "base/1",
2434 "pg_tblspc"
2437 progname = get_progname(argv[0]);
2438 set_pglocale_pgservice(argv[0], "initdb");
2440 if (argc > 1)
2442 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
2444 usage(progname);
2445 exit(0);
2447 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
2449 puts("initdb (PostgreSQL) " PG_VERSION);
2450 exit(0);
2454 /* process command-line options */
2456 while ((c = getopt_long(argc, argv, "dD:E:L:nU:WA:sT:X:", long_options, &option_index)) != -1)
2458 switch (c)
2460 case 'A':
2461 authmethod = xstrdup(optarg);
2462 break;
2463 case 'D':
2464 pg_data = xstrdup(optarg);
2465 break;
2466 case 'E':
2467 encoding = xstrdup(optarg);
2468 break;
2469 case 'W':
2470 pwprompt = true;
2471 break;
2472 case 'U':
2473 username = xstrdup(optarg);
2474 break;
2475 case 'd':
2476 debug = true;
2477 printf(_("Running in debug mode.\n"));
2478 break;
2479 case 'n':
2480 noclean = true;
2481 printf(_("Running in noclean mode. Mistakes will not be cleaned up.\n"));
2482 break;
2483 case 'L':
2484 share_path = xstrdup(optarg);
2485 break;
2486 case 1:
2487 locale = xstrdup(optarg);
2488 break;
2489 case 2:
2490 lc_collate = xstrdup(optarg);
2491 break;
2492 case 3:
2493 lc_ctype = xstrdup(optarg);
2494 break;
2495 case 4:
2496 lc_monetary = xstrdup(optarg);
2497 break;
2498 case 5:
2499 lc_numeric = xstrdup(optarg);
2500 break;
2501 case 6:
2502 lc_time = xstrdup(optarg);
2503 break;
2504 case 7:
2505 lc_messages = xstrdup(optarg);
2506 break;
2507 case 8:
2508 locale = "C";
2509 break;
2510 case 9:
2511 pwfilename = xstrdup(optarg);
2512 break;
2513 case 's':
2514 show_setting = true;
2515 break;
2516 case 'T':
2517 default_text_search_config = xstrdup(optarg);
2518 break;
2519 case 'X':
2520 xlog_dir = xstrdup(optarg);
2521 break;
2522 default:
2523 /* getopt_long already emitted a complaint */
2524 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2525 progname);
2526 exit(1);
2531 /* Non-option argument specifies data directory */
2532 if (optind < argc)
2534 pg_data = xstrdup(argv[optind]);
2535 optind++;
2538 if (optind < argc)
2540 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
2541 progname, argv[optind + 1]);
2542 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2543 progname);
2544 exit(1);
2547 if (pwprompt && pwfilename)
2549 fprintf(stderr, _("%s: password prompt and password file cannot be specified together\n"), progname);
2550 exit(1);
2553 if (authmethod == NULL || !strlen(authmethod))
2555 authwarning = _("\nWARNING: enabling \"trust\" authentication for local connections\n"
2556 "You can change this by editing pg_hba.conf or using the -A option the\n"
2557 "next time you run initdb.\n");
2558 authmethod = "trust";
2561 if (strcmp(authmethod, "md5") &&
2562 strcmp(authmethod, "ident") &&
2563 strncmp(authmethod, "ident ", 6) && /* ident with space = param */
2564 strcmp(authmethod, "trust") &&
2565 #ifdef USE_PAM
2566 strcmp(authmethod, "pam") &&
2567 strncmp(authmethod, "pam ", 4) && /* pam with space = param */
2568 #endif
2569 strcmp(authmethod, "crypt") &&
2570 strcmp(authmethod, "password")
2574 * Kerberos methods not listed because they are not supported over
2575 * local connections and are rejected in hba.c
2578 fprintf(stderr, _("%s: unrecognized authentication method \"%s\"\n"),
2579 progname, authmethod);
2580 exit(1);
2583 if ((!strcmp(authmethod, "md5") ||
2584 !strcmp(authmethod, "crypt") ||
2585 !strcmp(authmethod, "password")) &&
2586 !(pwprompt || pwfilename))
2588 fprintf(stderr, _("%s: must specify a password for the superuser to enable %s authentication\n"), progname, authmethod);
2589 exit(1);
2592 if (strlen(pg_data) == 0)
2594 pgdenv = getenv("PGDATA");
2595 if (pgdenv && strlen(pgdenv))
2597 /* PGDATA found */
2598 pg_data = xstrdup(pgdenv);
2600 else
2602 fprintf(stderr,
2603 _("%s: no data directory specified\n"
2604 "You must identify the directory where the data for this database system\n"
2605 "will reside. Do this with either the invocation option -D or the\n"
2606 "environment variable PGDATA.\n"),
2607 progname);
2608 exit(1);
2612 pg_data_native = pg_data;
2613 canonicalize_path(pg_data);
2615 #ifdef WIN32
2618 * Before we execute another program, make sure that we are running with a
2619 * restricted token. If not, re-execute ourselves with one.
2622 if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
2623 || strcmp(restrict_env, "1") != 0)
2625 PROCESS_INFORMATION pi;
2626 char *cmdline;
2628 ZeroMemory(&pi, sizeof(pi));
2630 cmdline = xstrdup(GetCommandLine());
2632 putenv("PG_RESTRICT_EXEC=1");
2634 if (!CreateRestrictedProcess(cmdline, &pi))
2636 fprintf(stderr, "Failed to re-exec with restricted token: %lu.\n", GetLastError());
2638 else
2641 * Successfully re-execed. Now wait for child process to capture
2642 * exitcode.
2644 DWORD x;
2646 CloseHandle(pi.hThread);
2647 WaitForSingleObject(pi.hProcess, INFINITE);
2649 if (!GetExitCodeProcess(pi.hProcess, &x))
2651 fprintf(stderr, "Failed to get exit code from subprocess: %lu\n", GetLastError());
2652 exit(1);
2654 exit(x);
2657 #endif
2660 * we have to set PGDATA for postgres rather than pass it on the command
2661 * line to avoid dumb quoting problems on Windows, and we would especially
2662 * need quotes otherwise on Windows because paths there are most likely to
2663 * have embedded spaces.
2665 pgdenv = pg_malloc(8 + strlen(pg_data));
2666 sprintf(pgdenv, "PGDATA=%s", pg_data);
2667 putenv(pgdenv);
2669 if ((ret = find_other_exec(argv[0], "postgres", PG_VERSIONSTR,
2670 backend_exec)) < 0)
2672 char full_path[MAXPGPATH];
2674 if (find_my_exec(argv[0], full_path) < 0)
2675 strlcpy(full_path, progname, sizeof(full_path));
2677 if (ret == -1)
2678 fprintf(stderr,
2679 _("The program \"postgres\" is needed by %s "
2680 "but was not found in the\n"
2681 "same directory as \"%s\".\n"
2682 "Check your installation.\n"),
2683 progname, full_path);
2684 else
2685 fprintf(stderr,
2686 _("The program \"postgres\" was found by \"%s\"\n"
2687 "but was not the same version as %s.\n"
2688 "Check your installation.\n"),
2689 full_path, progname);
2690 exit(1);
2693 /* store binary directory */
2694 strcpy(bin_path, backend_exec);
2695 *last_dir_separator(bin_path) = '\0';
2696 canonicalize_path(bin_path);
2698 if (!share_path)
2700 share_path = pg_malloc(MAXPGPATH);
2701 get_share_path(backend_exec, share_path);
2703 else if (!is_absolute_path(share_path))
2705 fprintf(stderr, _("%s: input file location must be an absolute path\n"), progname);
2706 exit(1);
2709 canonicalize_path(share_path);
2711 if ((short_version = get_short_version()) == NULL)
2713 fprintf(stderr, _("%s: could not determine valid short version string\n"), progname);
2714 exit(1);
2717 effective_user = get_id();
2718 if (strlen(username) == 0)
2719 username = effective_user;
2721 set_input(&bki_file, "postgres.bki");
2722 set_input(&desc_file, "postgres.description");
2723 set_input(&shdesc_file, "postgres.shdescription");
2724 set_input(&hba_file, "pg_hba.conf.sample");
2725 set_input(&ident_file, "pg_ident.conf.sample");
2726 set_input(&conf_file, "postgresql.conf.sample");
2727 set_input(&conversion_file, "conversion_create.sql");
2728 set_input(&dictionary_file, "snowball_create.sql");
2729 set_input(&info_schema_file, "information_schema.sql");
2730 set_input(&features_file, "sql_features.txt");
2731 set_input(&system_views_file, "system_views.sql");
2733 set_info_version();
2735 if (show_setting || debug)
2737 fprintf(stderr,
2738 "VERSION=%s\n"
2739 "PGDATA=%s\nshare_path=%s\nPGPATH=%s\n"
2740 "POSTGRES_SUPERUSERNAME=%s\nPOSTGRES_BKI=%s\n"
2741 "POSTGRES_DESCR=%s\nPOSTGRES_SHDESCR=%s\n"
2742 "POSTGRESQL_CONF_SAMPLE=%s\n"
2743 "PG_HBA_SAMPLE=%s\nPG_IDENT_SAMPLE=%s\n",
2744 PG_VERSION,
2745 pg_data, share_path, bin_path,
2746 username, bki_file,
2747 desc_file, shdesc_file,
2748 conf_file,
2749 hba_file, ident_file);
2750 if (show_setting)
2751 exit(0);
2754 check_input(bki_file);
2755 check_input(desc_file);
2756 check_input(shdesc_file);
2757 check_input(hba_file);
2758 check_input(ident_file);
2759 check_input(conf_file);
2760 check_input(conversion_file);
2761 check_input(dictionary_file);
2762 check_input(info_schema_file);
2763 check_input(features_file);
2764 check_input(system_views_file);
2766 setlocales();
2768 printf(_("The files belonging to this database system will be owned "
2769 "by user \"%s\".\n"
2770 "This user must also own the server process.\n\n"),
2771 effective_user);
2773 if (strcmp(lc_ctype, lc_collate) == 0 &&
2774 strcmp(lc_ctype, lc_time) == 0 &&
2775 strcmp(lc_ctype, lc_numeric) == 0 &&
2776 strcmp(lc_ctype, lc_monetary) == 0 &&
2777 strcmp(lc_ctype, lc_messages) == 0)
2778 printf(_("The database cluster will be initialized with locale %s.\n"), lc_ctype);
2779 else
2781 printf(_("The database cluster will be initialized with locales\n"
2782 " COLLATE: %s\n"
2783 " CTYPE: %s\n"
2784 " MESSAGES: %s\n"
2785 " MONETARY: %s\n"
2786 " NUMERIC: %s\n"
2787 " TIME: %s\n"),
2788 lc_collate,
2789 lc_ctype,
2790 lc_messages,
2791 lc_monetary,
2792 lc_numeric,
2793 lc_time);
2796 if (strlen(encoding) == 0)
2798 int ctype_enc;
2800 ctype_enc = pg_get_encoding_from_locale(lc_ctype);
2802 if (ctype_enc == PG_SQL_ASCII &&
2803 !(pg_strcasecmp(lc_ctype, "C") == 0 ||
2804 pg_strcasecmp(lc_ctype, "POSIX") == 0))
2806 /* Hmm, couldn't recognize the locale's codeset */
2807 fprintf(stderr, _("%s: could not find suitable encoding for locale %s\n"),
2808 progname, lc_ctype);
2809 fprintf(stderr, _("Rerun %s with the -E option.\n"), progname);
2810 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2811 progname);
2812 exit(1);
2814 else if (!pg_valid_server_encoding_id(ctype_enc))
2816 /* We recognized it, but it's not a legal server encoding */
2817 fprintf(stderr,
2818 _("%s: locale %s requires unsupported encoding %s\n"),
2819 progname, lc_ctype, pg_encoding_to_char(ctype_enc));
2820 fprintf(stderr,
2821 _("Encoding %s is not allowed as a server-side encoding.\n"
2822 "Rerun %s with a different locale selection.\n"),
2823 pg_encoding_to_char(ctype_enc), progname);
2824 exit(1);
2826 else
2828 encodingid = encodingid_to_string(ctype_enc);
2829 printf(_("The default database encoding has accordingly been set to %s.\n"),
2830 pg_encoding_to_char(ctype_enc));
2833 else
2835 int user_enc;
2836 int ctype_enc;
2838 encodingid = get_encoding_id(encoding);
2839 user_enc = atoi(encodingid);
2841 ctype_enc = pg_get_encoding_from_locale(lc_ctype);
2843 /* We allow selection of SQL_ASCII --- see notes in createdb() */
2844 if (!(ctype_enc == user_enc ||
2845 ctype_enc == PG_SQL_ASCII ||
2846 user_enc == PG_SQL_ASCII
2847 #ifdef WIN32
2850 * On win32, if the encoding chosen is UTF8, all locales are OK
2851 * (assuming the actual locale name passed the checks above). This is
2852 * because UTF8 is a pseudo-codepage, that we convert to UTF16 before
2853 * doing any operations on, and UTF16 supports all locales.
2855 || user_enc == PG_UTF8
2856 #endif
2859 fprintf(stderr, _("%s: encoding mismatch\n"), progname);
2860 fprintf(stderr,
2861 _("The encoding you selected (%s) and the encoding that the\n"
2862 "selected locale uses (%s) do not match. This would lead to\n"
2863 "misbehavior in various character string processing functions.\n"
2864 "Rerun %s and either do not specify an encoding explicitly,\n"
2865 "or choose a matching combination.\n"),
2866 pg_encoding_to_char(user_enc),
2867 pg_encoding_to_char(ctype_enc),
2868 progname);
2869 exit(1);
2873 if (strlen(default_text_search_config) == 0)
2875 default_text_search_config = find_matching_ts_config(lc_ctype);
2876 if (default_text_search_config == NULL)
2878 printf(_("%s: could not find suitable text search configuration for locale %s\n"),
2879 progname, lc_ctype);
2880 default_text_search_config = "simple";
2883 else
2885 const char *checkmatch = find_matching_ts_config(lc_ctype);
2887 if (checkmatch == NULL)
2889 printf(_("%s: warning: suitable text search configuration for locale %s is unknown\n"),
2890 progname, lc_ctype);
2892 else if (strcmp(checkmatch, default_text_search_config) != 0)
2894 printf(_("%s: warning: specified text search configuration \"%s\" might not match locale %s\n"),
2895 progname, default_text_search_config, lc_ctype);
2899 printf(_("The default text search configuration will be set to \"%s\".\n"),
2900 default_text_search_config);
2902 printf("\n");
2904 umask(077);
2907 * now we are starting to do real work, trap signals so we can clean up
2910 /* some of these are not valid on Windows */
2911 #ifdef SIGHUP
2912 pqsignal(SIGHUP, trapsig);
2913 #endif
2914 #ifdef SIGINT
2915 pqsignal(SIGINT, trapsig);
2916 #endif
2917 #ifdef SIGQUIT
2918 pqsignal(SIGQUIT, trapsig);
2919 #endif
2920 #ifdef SIGTERM
2921 pqsignal(SIGTERM, trapsig);
2922 #endif
2924 /* Ignore SIGPIPE when writing to backend, so we can clean up */
2925 #ifdef SIGPIPE
2926 pqsignal(SIGPIPE, SIG_IGN);
2927 #endif
2929 switch (check_data_dir(pg_data))
2931 case 0:
2932 /* PGDATA not there, must create it */
2933 printf(_("creating directory %s ... "),
2934 pg_data);
2935 fflush(stdout);
2937 if (!mkdatadir(NULL))
2938 exit_nicely();
2939 else
2940 check_ok();
2942 made_new_pgdata = true;
2943 break;
2945 case 1:
2946 /* Present but empty, fix permissions and use it */
2947 printf(_("fixing permissions on existing directory %s ... "),
2948 pg_data);
2949 fflush(stdout);
2951 if (chmod(pg_data, 0700) != 0)
2953 fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
2954 progname, pg_data, strerror(errno));
2955 exit_nicely();
2957 else
2958 check_ok();
2960 found_existing_pgdata = true;
2961 break;
2963 case 2:
2964 /* Present and not empty */
2965 fprintf(stderr,
2966 _("%s: directory \"%s\" exists but is not empty\n"),
2967 progname, pg_data);
2968 fprintf(stderr,
2969 _("If you want to create a new database system, either remove or empty\n"
2970 "the directory \"%s\" or run %s\n"
2971 "with an argument other than \"%s\".\n"),
2972 pg_data, progname, pg_data);
2973 exit(1); /* no further message needed */
2975 default:
2976 /* Trouble accessing directory */
2977 fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
2978 progname, pg_data, strerror(errno));
2979 exit_nicely();
2982 /* Create transaction log symlink, if required */
2983 if (strcmp(xlog_dir, "") != 0)
2985 char *linkloc;
2987 linkloc = (char *) pg_malloc(strlen(pg_data) + 8 + 2);
2988 sprintf(linkloc, "%s/pg_xlog", pg_data);
2990 /* check if the specified xlog directory is empty */
2991 switch (check_data_dir(xlog_dir))
2993 case 0:
2994 /* xlog directory not there, must create it */
2995 printf(_("creating directory %s ... "),
2996 xlog_dir);
2997 fflush(stdout);
2999 if (mkdir_p(xlog_dir, 0700) != 0)
3001 fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
3002 progname, xlog_dir, strerror(errno));
3003 exit_nicely();
3005 else
3007 check_ok();
3010 made_new_xlogdir = true;
3011 break;
3012 case 1:
3013 /* Present but empty, fix permissions and use it */
3014 printf(_("fixing permissions on existing directory %s ... "),
3015 xlog_dir);
3016 fflush(stdout);
3018 if (chmod(xlog_dir, 0700) != 0)
3020 fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
3021 progname, xlog_dir, strerror(errno));
3022 exit_nicely();
3024 else
3025 check_ok();
3027 found_existing_xlogdir = true;
3028 break;
3029 case 2:
3030 /* Present and not empty */
3031 fprintf(stderr,
3032 _("%s: directory \"%s\" exists but is not empty\n"),
3033 progname, xlog_dir);
3034 fprintf(stderr,
3035 _("If you want to store the transaction log there, either\n"
3036 "remove or empty the directory \"%s\".\n"),
3037 xlog_dir);
3038 exit(1); /* no further message needed */
3040 default:
3041 /* Trouble accessing directory */
3042 fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
3043 progname, xlog_dir, strerror(errno));
3044 exit_nicely();
3047 #ifdef HAVE_SYMLINK
3048 if (symlink(xlog_dir, linkloc) != 0)
3050 fprintf(stderr, _("%s: could not create symbolic link \"%s\": %s\n"),
3051 progname, linkloc, strerror(errno));
3052 exit_nicely();
3054 #else
3055 fprintf(stderr, _("%s: symlinks are not supported on this platform"));
3056 exit_nicely();
3057 #endif
3060 /* Create required subdirectories */
3061 printf(_("creating subdirectories ... "));
3062 fflush(stdout);
3064 for (i = 0; i < (sizeof(subdirs) / sizeof(char *)); i++)
3066 if (!mkdatadir(subdirs[i]))
3067 exit_nicely();
3070 check_ok();
3072 /* Top level PG_VERSION is checked by bootstrapper, so make it first */
3073 set_short_version(short_version, NULL);
3075 /* Select suitable configuration settings */
3076 set_null_conf();
3077 test_config_settings();
3079 /* Now create all the text config files */
3080 setup_config();
3082 /* Bootstrap template1 */
3083 bootstrap_template1(short_version);
3086 * Make the per-database PG_VERSION for template1 only after init'ing it
3088 set_short_version(short_version, "base/1");
3090 /* Create the stuff we don't need to use bootstrap mode for */
3092 setup_auth();
3093 if (pwprompt || pwfilename)
3094 get_set_pwd();
3096 setup_depend();
3098 setup_sysviews();
3100 setup_description();
3102 setup_conversion();
3104 setup_dictionary();
3106 setup_privileges();
3108 setup_schema();
3110 vacuum_db();
3112 make_template0();
3114 make_postgres();
3116 if (authwarning != NULL)
3117 fprintf(stderr, "%s", authwarning);
3119 /* Get directory specification used to start this executable */
3120 strcpy(bin_dir, argv[0]);
3121 get_parent_directory(bin_dir);
3123 printf(_("\nSuccess. You can now start the database server using:\n\n"
3124 " %s%s%spostgres%s -D %s%s%s\n"
3125 "or\n"
3126 " %s%s%spg_ctl%s -D %s%s%s -l logfile start\n\n"),
3127 QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
3128 QUOTE_PATH, pg_data_native, QUOTE_PATH,
3129 QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
3130 QUOTE_PATH, pg_data_native, QUOTE_PATH);
3132 return 0;