OSDN Git Service

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