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