]> granicus.if.org Git - postgresql/blob - src/bin/initdb/initdb.c
XLOG file archiving and point-in-time recovery. There are still some
[postgresql] / src / bin / initdb / initdb.c
1 /*-------------------------------------------------------------------------
2  *
3  * initdb --- initialize a PostgreSQL installation
4  *
5  * initdb creates (initializes) a PostgreSQL database cluster (site,
6  * instance, installation, whatever).  A database cluster is a
7  * collection of PostgreSQL databases all managed by the same postmaster.
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 two databases: the
12  * template0 and template1 databases.
13  *
14  * The template databases are ordinary PostgreSQL databases.  template0
15  * is never supposed to change after initdb, whereas template1 can be
16  * changed to add site-local standard data.  Either one can be copied
17  * to produce a new database.
18  *
19  * To create template1, we run the postgres (backend) program in bootstrap
20  * mode and feed it data from the postgres.bki library file.  After this
21  * initial bootstrap phase, some additional stuff is created by normal
22  * SQL commands fed to a standalone backend.  Some of those commands are
23  * just embedded into this program (yeah, it's ugly), but larger chunks
24  * are taken from script files.
25  *
26  * template0 is made just by copying the completed template1.
27  *
28  * Note:
29  *       The program has some memory leakage - it isn't worth cleaning it up.
30  *
31  *
32  * This is a C implementation of the previous shell script for setting up a
33  * PostgreSQL cluster location, and should be highly compatible with it.
34  * author of C translation: Andrew Dunstan         mailto:andrew@dunslane.net
35  *
36  * This code is released under the terms of the PostgreSQL License.
37  *
38  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
39  * Portions Copyright (c) 1994, Regents of the University of California
40  * Portions taken from FreeBSD.
41  *
42  * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.44 2004/07/19 02:47:12 tgl Exp $
43  *
44  *-------------------------------------------------------------------------
45  */
46
47 #include "postgres_fe.h"
48
49 #include <dirent.h>
50 #include <sys/stat.h>
51 #include <unistd.h>
52 #include <locale.h>
53 #include <signal.h>
54 #include <errno.h>
55 #ifdef HAVE_LANGINFO_H
56 # include <langinfo.h>
57 #endif
58
59 #include "libpq/pqsignal.h"
60 #include "mb/pg_wchar.h"
61 #include "getopt_long.h"
62
63 #ifndef HAVE_OPTRESET
64 int                     optreset;
65 #endif
66
67
68 #define _(x) gettext((x))
69
70 /* version string we expect back from postgres */
71 #define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n"
72
73 /*
74  * these values are passed in by makefile defines
75  */
76 char            *share_path = NULL;
77
78 /* values to be obtained from arguments */
79 char       *pg_data = "";
80 char       *encoding = "";
81 char       *locale = "";
82 char       *lc_collate = "";
83 char       *lc_ctype = "";
84 char       *lc_monetary = "";
85 char       *lc_numeric = "";
86 char       *lc_time = "";
87 char       *lc_messages = "";
88 char       *username = "";
89 bool            pwprompt = false;
90 char       *pwfilename = NULL;
91 bool            debug = false;
92 bool            noclean = false;
93 bool            show_setting = false;
94
95
96 /* internal vars */
97 const char *progname;
98 char       *postgres;
99 char       *encodingid = "0";
100 char       *bki_file;
101 char       *desc_file;
102 char       *hba_file;
103 char       *ident_file;
104 char       *conf_file;
105 char       *conversion_file;
106 char       *info_schema_file;
107 char       *features_file;
108 char       *system_views_file;
109 char       *effective_user;
110 bool            testpath = true;
111 bool            made_new_pgdata = false;
112 bool            found_existing_pgdata = false;
113 char            infoversion[100];
114 bool            caught_signal = false;
115 bool            output_failed = false;
116
117 /* defaults */
118 int                     n_connections = 10;
119 int                     n_buffers = 50;
120
121 /*
122  * Centralized knowledge of switches to pass to backend
123  *
124  * Note: in the shell-script version, we also passed PGDATA as a -D switch,
125  * but here it is more convenient to pass it as an environment variable
126  * (no quoting to worry about).
127  */
128 static const char *boot_options = "-F";
129 static const char *backend_options = "-F -O -c search_path=pg_catalog -c exit_on_error=true";
130
131
132 /* path to 'initdb' binary directory */
133 char       bin_path[MAXPGPATH];
134 char       backend_exec[MAXPGPATH];
135
136 static void *xmalloc(size_t size);
137 static char *xstrdup(const char *s);
138 static bool rmtree(char *path, bool rmtopdir);
139 static char **replace_token(char **lines, char *token, char *replacement);
140 static char **readfile(char *path);
141 static void writefile(char *path, char **lines);
142 static int mkdir_p(char *path, mode_t omode);
143 static void exit_nicely(void);
144 static char *get_id(void);
145 static char *get_encoding_id(char *encoding_name);
146 static char *get_short_version(void);
147 static int check_data_dir(void);
148 static bool mkdatadir(const char *subdir);
149 static void set_input(char **dest, char *filename);
150 static void check_input(char *path);
151 static void set_short_version(char *short_version, char *extrapath);
152 static void set_null_conf(void);
153 static void test_connections(void);
154 static void test_buffers(void);
155 static void setup_config(void);
156 static void bootstrap_template1(char *short_version);
157 static void setup_shadow(void);
158 static void get_set_pwd(void);
159 static void unlimit_systables(void);
160 static void setup_depend(void);
161 static void setup_sysviews(void);
162 static void setup_description(void);
163 static void setup_conversion(void);
164 static void setup_privileges(void);
165 static void set_info_version(void);
166 static void setup_schema(void);
167 static void vacuum_db(void);
168 static void make_template0(void);
169 static void trapsig(int signum);
170 static void check_ok(void);
171 static bool chklocale(const char *locale);
172 static void setlocales(void);
173 static void usage(const char *progname);
174
175
176 /*
177  * macros for running pipes to postgres
178  */
179 #define PG_CMD_DECL             char cmd[MAXPGPATH]; char ** line ; FILE * pg
180 #define PG_CMD_DECL_NOLINE                 char cmd[MAXPGPATH]; FILE * pg
181
182 #define PG_CMD_OPEN \
183 do { \
184         fflush(stdout); \
185         fflush(stderr); \
186         pg = popen(cmd, "w"); \
187         if (pg == NULL) \
188                 exit_nicely(); \
189 } while (0)
190
191 #define PG_CMD_CLOSE \
192 do { \
193         if (pclose_check(pg)) \
194                 exit_nicely(); \
195 } while (0)
196
197 #define PG_CMD_PUTLINE \
198 do { \
199         if (fputs(*line, pg) < 0 || fflush(pg) < 0) \
200                 output_failed = true; \
201 } while (0)
202
203 #ifndef WIN32
204 #define QUOTE_PATH      ""
205 #else
206 #define QUOTE_PATH      "\""
207 #endif
208
209 /*
210  * routines to check mem allocations and fail noisily.
211  *
212  * Note that we can't call exit_nicely() on a memory failure, as it calls
213  * rmtree() which needs memory allocation. So we just exit with a bang.
214  */
215 static void *
216 xmalloc(size_t size)
217 {
218         void       *result;
219
220         result = malloc(size);
221         if (!result)
222         {
223                 fprintf(stderr, _("%s: out of memory\n"), progname);
224                 exit(1);
225         }
226         return result;
227 }
228
229 static char *
230 xstrdup(const char *s)
231 {
232         char       *result;
233
234         result = strdup(s);
235         if (!result)
236         {
237                 fprintf(stderr, _("%s: out of memory\n"), progname);
238                 exit(1);
239         }
240         return result;
241 }
242
243 /*
244  * delete a directory tree recursively
245  * assumes path points to a valid directory
246  * deletes everything under path
247  * if rmtopdir is true deletes the directory too
248  */
249 static bool
250 rmtree(char *path, bool rmtopdir)
251 {
252         char            buf[MAXPGPATH + 64];
253
254 #ifndef WIN32
255         /* doesn't handle .* files, but we don't make any... */
256         snprintf(buf, sizeof(buf), "rm -rf \"%s\"%s", path,
257                          rmtopdir ? "" : "/*");
258 #else
259         snprintf(buf, sizeof(buf), "%s /s /q \"%s\"",
260                          rmtopdir ? "rmdir" : "del", path);
261 #endif
262
263         return !system(buf);
264 }
265
266
267 /*
268  * make a copy of the array of lines, with token replaced by replacement
269  * the first time it occurs on each line.
270  *
271  * This does most of what sed was used for in the shell script, but
272  * doesn't need any regexp stuff.
273  */
274 static char **
275 replace_token(char **lines, char *token, char *replacement)
276 {
277         int                     numlines = 1;
278         int                     i;
279         char      **result;
280         int                     toklen,
281                                 replen,
282                                 diff;
283
284         for (i = 0; lines[i]; i++)
285                 numlines++;
286
287         result = (char **) xmalloc(numlines * sizeof(char *));
288
289         toklen = strlen(token);
290         replen = strlen(replacement);
291         diff = replen - toklen;
292
293         for (i = 0; i < numlines; i++)
294         {
295                 char       *where;
296                 char       *newline;
297                 int                     pre;
298
299                 /* just copy pointer if NULL or no change needed */
300
301                 if (lines[i] == NULL || (where = strstr(lines[i], token)) == NULL)
302                 {
303                         result[i] = lines[i];
304                         continue;
305                 }
306
307                 /* if we get here a change is needed - set up new line */
308
309                 newline = (char *) xmalloc(strlen(lines[i]) + diff + 1);
310
311                 pre = where - lines[i];
312
313                 strncpy(newline, lines[i], pre);
314
315                 strcpy(newline + pre, replacement);
316
317                 strcpy(newline + pre + replen, lines[i] + pre + toklen);
318
319                 result[i] = newline;
320
321         }
322
323         return result;
324
325 }
326
327 /*
328  * get the lines from a text file
329  */
330 static char **
331 readfile(char *path)
332 {
333         FILE       *infile;
334         int                     maxlength = 0,
335                                 linelen = 0;
336         int                     nlines = 0;
337         char      **result;
338         char       *buffer;
339         int                     c;
340
341         if ((infile = fopen(path, "r")) == NULL)
342         {
343                 fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
344                                 progname, path, strerror(errno));
345                 exit_nicely();
346         }
347
348         /* pass over the file twice - the first time to size the result */
349
350         while ((c = fgetc(infile)) != EOF)
351         {
352                 linelen++;
353                 if (c == '\n')
354                 {
355                         nlines++;
356                         if (linelen > maxlength)
357                                 maxlength = linelen;
358                         linelen = 0;
359                 }
360         }
361
362         /* handle last line without a terminating newline (yuck) */
363
364         if (linelen)
365                 nlines++;
366         if (linelen > maxlength)
367                 maxlength = linelen;
368
369         /* set up the result and the line buffer */
370
371         result = (char **) xmalloc((nlines + 2) * sizeof(char *));
372         buffer = (char *) xmalloc(maxlength + 2);
373
374         /* now reprocess the file and store the lines */
375
376         rewind(infile);
377         nlines = 0;
378         while (fgets(buffer, maxlength + 1, infile) != NULL)
379         {
380                 result[nlines] = xstrdup(buffer);
381                 nlines++;
382         }
383
384         fclose(infile);
385         result[nlines] = NULL;
386
387         return result;
388 }
389
390 /*
391  * write an array of lines to a file
392  */
393 static void
394 writefile(char *path, char **lines)
395 {
396         FILE       *out_file;
397         char      **line;
398
399         if ((out_file = fopen(path, PG_BINARY_W)) == NULL)
400         {
401                 fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
402                                 progname, path, strerror(errno));
403                 exit_nicely();
404         }
405         for (line = lines; *line != NULL; line++)
406         {
407                 if (fputs(*line, out_file) < 0)
408                         exit_nicely();
409                 free(*line);
410         }
411         if (fclose(out_file))
412                 exit_nicely();
413 }
414
415 /* source stolen from FreeBSD /src/bin/mkdir/mkdir.c and adapted */
416
417 /*
418  * this tries to build all the elements of a path to a directory a la mkdir -p
419  * we assume the path is in canonical form, i.e. uses / as the separator
420  * we also assume it isn't null.
421  */
422 static int
423 mkdir_p(char *path, mode_t omode)
424 {
425         struct stat sb;
426         mode_t          numask,
427                                 oumask;
428         int                     first,
429                                 last,
430                                 retval;
431         char       *p;
432
433         p = path;
434         oumask = 0;
435         retval = 0;
436
437 #ifdef WIN32
438         /* skip network and drive specifiers for win32 */
439         if (strlen(p) >= 2)
440         {
441                 if (p[0] == '/' && p[1] == '/')
442                 {
443                         /* network drive */
444                         p = strstr(p + 2, "/");
445                         if (p == NULL)
446                                 return 1;
447                 }
448                 else if (p[1] == ':' &&
449                                  ((p[0] >= 'a' && p[0] <= 'z') ||
450                                   (p[0] >= 'A' && p[0] <= 'Z')))
451                 {
452                         /* local drive */
453                         p += 2;
454                 }
455         }
456 #endif
457
458         if (p[0] == '/')                        /* Skip leading '/'. */
459                 ++p;
460         for (first = 1, last = 0; !last; ++p)
461         {
462                 if (p[0] == '\0')
463                         last = 1;
464                 else if (p[0] != '/')
465                         continue;
466                 *p = '\0';
467                 if (!last && p[1] == '\0')
468                         last = 1;
469                 if (first)
470                 {
471                         /*
472                          * POSIX 1003.2: For each dir operand that does not name an
473                          * existing directory, effects equivalent to those cased by
474                          * the following command shall occcur:
475                          *
476                          * mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode]
477                          * dir
478                          *
479                          * We change the user's umask and then restore it, instead of
480                          * doing chmod's.
481                          */
482                         oumask = umask(0);
483                         numask = oumask & ~(S_IWUSR | S_IXUSR);
484                         (void) umask(numask);
485                         first = 0;
486                 }
487                 if (last)
488                         (void) umask(oumask);
489                 if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
490                 {
491                         if (errno == EEXIST || errno == EISDIR)
492                         {
493                                 if (stat(path, &sb) < 0)
494                                 {
495                                         retval = 1;
496                                         break;
497                                 }
498                                 else if (!S_ISDIR(sb.st_mode))
499                                 {
500                                         if (last)
501                                                 errno = EEXIST;
502                                         else
503                                                 errno = ENOTDIR;
504                                         retval = 1;
505                                         break;
506                                 }
507                         }
508                         else
509                         {
510                                 retval = 1;
511                                 break;
512                         }
513                 }
514                 if (!last)
515                         *p = '/';
516         }
517         if (!first && !last)
518                 (void) umask(oumask);
519         return retval;
520 }
521
522 /*
523  * clean up any files we created on failure
524  * if we created the data directory remove it too
525  */
526 static void
527 exit_nicely(void)
528 {
529         fprintf(stderr, _("%s: failed\n"), progname);
530
531         if (!noclean)
532         {
533                 if (made_new_pgdata)
534                 {
535                         fprintf(stderr, _("%s: removing data directory \"%s\"\n"),
536                                         progname, pg_data);
537                         if (!rmtree(pg_data, true))
538                                 fprintf(stderr, _("%s: failed\n"), progname);
539                 }
540                 else if (found_existing_pgdata)
541                 {
542                         fprintf(stderr,
543                                         _("%s: removing contents of data directory \"%s\"\n"),
544                                         progname, pg_data);
545                         if (!rmtree(pg_data, false))
546                                 fprintf(stderr, _("%s: failed\n"), progname);
547                 }
548                 /* otherwise died during startup, do nothing! */
549         }
550         else
551         {
552                 if (made_new_pgdata || found_existing_pgdata)
553                         fprintf(stderr,
554                                         _("%s: data directory \"%s\" not removed at user's request\n"),
555                                         progname, pg_data);
556         }
557
558         exit(1);
559 }
560
561 /*
562  * find the current user
563  *
564  * on unix make sure it isn't really root
565  */
566 static char *
567 get_id(void)
568 {
569 #ifndef WIN32
570
571         struct passwd *pw;
572
573         pw = getpwuid(getuid());
574
575 #ifndef __BEOS__                                /* no root check on BEOS */
576
577         if (!geteuid())                         /* 0 is root's uid */
578         {
579                 fprintf(stderr,
580                                 _("%s: cannot be run as root\n"
581                                 "Please log in (using, e.g., \"su\") as the "
582                                 "(unprivileged) user that will\n"
583                                 "own the server process.\n"),
584                                 progname);
585                 exit(1);
586         }
587 #endif
588
589 #else                                                   /* the windows code */
590
591         struct passwd_win32
592         {
593                 int                     pw_uid;
594                 char            pw_name[128];
595         }                       pass_win32;
596         struct passwd_win32 *pw = &pass_win32;
597         DWORD           pwname_size = sizeof(pass_win32.pw_name) - 1;
598
599         pw->pw_uid = 1;
600         GetUserName(pw->pw_name, &pwname_size);
601 #endif
602
603         return xstrdup(pw->pw_name);
604 }
605
606 static char *
607 encodingid_to_string(int enc)
608 {
609         char            result[20];
610
611         sprintf(result, "%d", enc);
612         return xstrdup(result);
613 }
614
615 /*
616  * get the encoding id for a given encoding name
617  */
618 static char *
619 get_encoding_id(char *encoding_name)
620 {
621         int                     enc;
622
623         if (encoding_name && *encoding_name)
624         {
625                 if ((enc = pg_char_to_encoding(encoding_name)) >= 0 &&
626                         pg_valid_server_encoding(encoding_name) >= 0)
627                 {
628                         return encodingid_to_string(enc);
629                 }
630         }
631         fprintf(stderr, _("%s: \"%s\" is not a valid server encoding name\n"),
632                         progname, encoding_name ? encoding_name : "(null)");
633         exit(1);
634 }
635
636 #ifdef HAVE_LANGINFO_H
637 /*
638  * Checks whether the encoding selected for PostgreSQL and the
639  * encoding used by the system locale match.
640  */
641
642 struct encoding_match
643 {
644         enum pg_enc     pg_enc_code;
645         char       *system_enc_name;
646 };
647
648 struct encoding_match encoding_match_list[] = {
649         { PG_EUC_JP, "EUC-JP" },
650         { PG_EUC_JP, "eucJP" },
651         { PG_EUC_JP, "IBM-eucJP" },
652         { PG_EUC_JP, "sdeckanji" },
653
654         { PG_EUC_CN, "EUC-CN" },
655         { PG_EUC_CN, "eucCN" },
656         { PG_EUC_CN, "IBM-eucCN" },
657         { PG_EUC_CN, "GB2312" },
658         { PG_EUC_CN, "dechanzi" },
659
660         { PG_EUC_KR, "EUC-KR" },
661         { PG_EUC_KR, "eucKR" },
662         { PG_EUC_KR, "IBM-eucKR" },
663         { PG_EUC_KR, "deckorean" },
664         { PG_EUC_KR, "5601" },
665
666         { PG_EUC_TW, "EUC-TW" },
667         { PG_EUC_TW, "eucTW" },
668         { PG_EUC_TW, "IBM-eucTW" },
669         { PG_EUC_TW, "cns11643" },
670
671 #ifdef NOT_VERIFIED
672         { PG_JOHAB, "???" },
673 #endif
674
675         { PG_UTF8, "UTF-8" },
676         { PG_UTF8, "utf8" },
677
678         { PG_LATIN1, "ISO-8859-1" },
679         { PG_LATIN1, "ISO8859-1" },
680         { PG_LATIN1, "iso88591" },
681
682         { PG_LATIN2, "ISO-8859-2" },
683         { PG_LATIN2, "ISO8859-2" },
684         { PG_LATIN2, "iso88592" },
685
686         { PG_LATIN3, "ISO-8859-3" },
687         { PG_LATIN3, "ISO8859-3" },
688         { PG_LATIN3, "iso88593" },
689
690         { PG_LATIN4, "ISO-8859-4" },
691         { PG_LATIN4, "ISO8859-4" },
692         { PG_LATIN4, "iso88594" },
693
694         { PG_LATIN5, "ISO-8859-9" },
695         { PG_LATIN5, "ISO8859-9" },
696         { PG_LATIN5, "iso88599" },
697
698         { PG_LATIN6, "ISO-8859-10" },
699         { PG_LATIN6, "ISO8859-10" },
700         { PG_LATIN6, "iso885910" },
701
702         { PG_LATIN7, "ISO-8859-13" },
703         { PG_LATIN7, "ISO8859-13" },
704         { PG_LATIN7, "iso885913" },
705
706         { PG_LATIN8, "ISO-8859-14" },
707         { PG_LATIN8, "ISO8859-14" },
708         { PG_LATIN8, "iso885914" },
709
710         { PG_LATIN9, "ISO-8859-15" },
711         { PG_LATIN9, "ISO8859-15" },
712         { PG_LATIN9, "iso885915" },
713
714         { PG_LATIN10, "ISO-8859-16" },
715         { PG_LATIN10, "ISO8859-16" },
716         { PG_LATIN10, "iso885916" },
717
718         { PG_WIN1256, "CP1256" },
719         { PG_TCVN, "CP1258" },
720 #ifdef NOT_VERIFIED
721         { PG_WIN874, "???" },
722 #endif
723         { PG_KOI8R, "KOI8-R" },
724         { PG_WIN1251, "CP1251" },
725         { PG_ALT, "CP866" },
726
727         { PG_ISO_8859_5, "ISO-8859-5" },
728         { PG_ISO_8859_5, "ISO8859-5" },
729         { PG_ISO_8859_5, "iso88595" },
730
731         { PG_ISO_8859_6, "ISO-8859-6" },
732         { PG_ISO_8859_6, "ISO8859-6" },
733         { PG_ISO_8859_6, "iso88596" },
734
735         { PG_ISO_8859_7, "ISO-8859-7" },
736         { PG_ISO_8859_7, "ISO8859-7" },
737         { PG_ISO_8859_7, "iso88597" },
738
739         { PG_ISO_8859_8, "ISO-8859-8" },
740         { PG_ISO_8859_8, "ISO8859-8" },
741         { PG_ISO_8859_8, "iso88598" },
742
743         { PG_SQL_ASCII, NULL } /* end marker */
744 };
745
746 static char *
747 get_encoding_from_locale(const char *ctype)
748 {
749         char       *save;
750         char       *sys;
751
752         save = setlocale(LC_CTYPE, NULL);
753         if (!save)
754                 return NULL;
755         save = xstrdup(save);
756
757         setlocale(LC_CTYPE, ctype);
758         sys = nl_langinfo(CODESET);
759         sys = xstrdup(sys);
760
761         setlocale(LC_CTYPE, save);
762         free(save);
763
764         return sys;
765 }
766
767 static void
768 check_encodings_match(int pg_enc, const char *ctype)
769 {
770         char *sys;
771         int i;
772
773         sys = get_encoding_from_locale(ctype);
774
775         for (i = 0; encoding_match_list[i].system_enc_name; i++)
776         {
777                 if (pg_enc == encoding_match_list[i].pg_enc_code
778                         && strcasecmp(sys, encoding_match_list[i].system_enc_name) == 0)
779                 {
780                         free(sys);
781                         return;
782                 }
783         }
784
785         fprintf(stderr,
786                         _("%s: warning: encoding mismatch\n"), progname);
787         fprintf(stderr,
788                         _("The encoding you selected (%s) and the encoding that the selected\n"
789                           "locale uses (%s) are not known to match.  This may lead to\n"
790                           "misbehavior in various character string processing functions.  To fix\n"
791                           "this situation, rerun %s and either do not specify an encoding\n"
792                           "explicitly, or choose a matching combination.\n"),
793                         pg_encoding_to_char(pg_enc), sys, progname);
794
795         free(sys);
796         return;
797 }
798
799 static int
800 find_matching_encoding(const char *ctype)
801 {
802         char *sys;
803         int i;
804
805         sys = get_encoding_from_locale(ctype);
806
807         for (i = 0; encoding_match_list[i].system_enc_name; i++)
808         {
809                 if (strcasecmp(sys, encoding_match_list[i].system_enc_name) == 0)
810                 {
811                         free(sys);
812                         return encoding_match_list[i].pg_enc_code;
813                 }
814         }
815
816         free(sys);
817         return -1;
818 }
819 #endif /* HAVE_LANGINFO_H */
820
821 /*
822  * get short version of VERSION
823  */
824 static char *
825 get_short_version(void)
826 {
827         bool            gotdot = false;
828         int                     end;
829         char       *vr;
830
831         vr = xstrdup(PG_VERSION);
832
833         for (end = 0; vr[end] != '\0'; end++)
834         {
835                 if (vr[end] == '.')
836                 {
837                         if (end == 0)
838                                 return NULL;
839                         else if (gotdot)
840                                 break;
841                         else
842                                 gotdot = true;
843                 }
844                 else if (vr[end] < '0' || vr[end] > '9')
845                 {
846                         /* gone past digits and dots */
847                         break;
848                 }
849         }
850         if (end == 0 || vr[end - 1] == '.' || !gotdot)
851                 return NULL;
852
853         vr[end] = '\0';
854         return vr;
855 }
856
857 /*
858  * make sure the data directory either doesn't exist or is empty
859  *
860  * Returns 0 if nonexistent, 1 if exists and empty, 2 if not empty,
861  * or -1 if trouble accessing directory
862  */
863 static int
864 check_data_dir(void)
865 {
866         DIR                *chkdir;
867         struct dirent *file;
868         int                     result = 1;
869
870         errno = 0;
871
872         chkdir = opendir(pg_data);
873
874         if (!chkdir)
875                 return (errno == ENOENT) ? 0 : -1;
876
877         while ((file = readdir(chkdir)) != NULL)
878         {
879                 if (strcmp(".", file->d_name) == 0 || strcmp("..", file->d_name) == 0)
880                 {
881                         /* skip this and parent directory */
882                         continue;
883                 }
884                 else
885                 {
886                         result = 2;                     /* not empty */
887                         break;
888                 }
889         }
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 = xmalloc(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         return (mkdir_p(path, 0700) == 0);
916 }
917
918
919 /*
920  * set name of given input file variable under data directory
921  */
922 static void
923 set_input(char **dest, char *filename)
924 {
925         *dest = xmalloc(strlen(share_path) + strlen(filename) + 2);
926         sprintf(*dest, "%s/%s", share_path, filename);
927 }
928
929 /*
930  * check that given input file exists
931  */
932 static void
933 check_input(char *path)
934 {
935         struct stat statbuf;
936
937         if (stat(path, &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
938         {
939                 fprintf(stderr,
940                                 _("%s: file \"%s\" does not exist\n"
941                                   "This means you have a corrupted installation or identified\n"
942                                   "the wrong directory with the invocation option -L.\n"),
943                                 progname, path);
944                 exit(1);
945         }
946
947 }
948
949 /*
950  * write out the PG_VERSION file in the data dir, or its subdirectory
951  * if extrapath is not NULL
952  */
953 static void
954 set_short_version(char *short_version, char *extrapath)
955 {
956         FILE       *version_file;
957         char       *path;
958
959         if (extrapath == NULL)
960         {
961                 path = xmalloc(strlen(pg_data) + 12);
962                 sprintf(path, "%s/PG_VERSION", pg_data);
963         }
964         else
965         {
966                 path = xmalloc(strlen(pg_data) + strlen(extrapath) + 13);
967                 sprintf(path, "%s/%s/PG_VERSION", pg_data, extrapath);
968         }
969         version_file = fopen(path, PG_BINARY_W);
970         if (version_file == NULL)
971                 exit_nicely();
972         fprintf(version_file, "%s\n", short_version);
973         if (fclose(version_file))
974                 exit_nicely();
975 }
976
977 /*
978  * set up an empty config file so we can check buffers and connections
979  */
980 static void
981 set_null_conf(void)
982 {
983         FILE       *conf_file;
984         char       *path;
985
986         path = xmalloc(strlen(pg_data) + 17);
987         sprintf(path, "%s/postgresql.conf", pg_data);
988         conf_file = fopen(path, PG_BINARY_W);
989         if (conf_file == NULL || fclose(conf_file))
990                 exit_nicely();
991 }
992
993 /*
994  * check how many connections we can sustain
995  */
996 static void
997 test_connections(void)
998 {
999         char            cmd[MAXPGPATH];
1000         static const int conns[] = {100, 50, 40, 30, 20, 10};
1001         static const int len = sizeof(conns) / sizeof(int);
1002         int                     i,
1003                                 status;
1004
1005         printf(_("selecting default max_connections ... "));
1006         fflush(stdout);
1007
1008         for (i = 0; i < len; i++)
1009         {
1010                 snprintf(cmd, sizeof(cmd),
1011                                  "%s\"%s\" -boot -x0 %s "
1012                                  "-c shared_buffers=%d -c max_connections=%d template1 "
1013                                  "< \"%s\" > \"%s\" 2>&1%s",
1014                                  SYSTEMQUOTE, backend_exec, boot_options,
1015                                  conns[i] * 5, conns[i],
1016                                  DEVNULL, DEVNULL, SYSTEMQUOTE);
1017                 status = system(cmd);
1018                 if (status == 0)
1019                         break;
1020         }
1021         if (i >= len)
1022                 i = len - 1;
1023         n_connections = conns[i];
1024
1025         printf("%d\n", n_connections);
1026 }
1027
1028 /*
1029  * check how many buffers we can run with
1030  */
1031 static void
1032 test_buffers(void)
1033 {
1034         char            cmd[MAXPGPATH];
1035         static const int bufs[] = {1000, 900, 800, 700, 600, 500,
1036                                                            400, 300, 200, 100, 50};
1037         static const int len = sizeof(bufs) / sizeof(int);
1038         int                     i,
1039                                 status;
1040
1041         printf(_("selecting default shared_buffers ... "));
1042         fflush(stdout);
1043
1044         for (i = 0; i < len; i++)
1045         {
1046                 snprintf(cmd, sizeof(cmd),
1047                                  "%s\"%s\" -boot -x0 %s "
1048                                  "-c shared_buffers=%d -c max_connections=%d template1 "
1049                                  "< \"%s\" > \"%s\" 2>&1%s",
1050                                  SYSTEMQUOTE, backend_exec, boot_options,
1051                                  bufs[i], n_connections,
1052                                  DEVNULL, DEVNULL, SYSTEMQUOTE);
1053                 status = system(cmd);
1054                 if (status == 0)
1055                         break;
1056         }
1057         if (i >= len)
1058                 i = len - 1;
1059         n_buffers = bufs[i];
1060
1061         printf("%d\n", n_buffers);
1062 }
1063
1064 /*
1065  * set up all the config files
1066  */
1067 static void
1068 setup_config(void)
1069 {
1070         char      **conflines;
1071         char            repltok[100];
1072         char            path[MAXPGPATH];
1073
1074         fputs(_("creating configuration files ... "), stdout);
1075         fflush(stdout);
1076
1077         /* postgresql.conf */
1078
1079         conflines = readfile(conf_file);
1080
1081         snprintf(repltok, sizeof(repltok), "max_connections = %d", n_connections);
1082         conflines = replace_token(conflines, "#max_connections = 100", repltok);
1083
1084         snprintf(repltok, sizeof(repltok), "shared_buffers = %d", n_buffers);
1085         conflines = replace_token(conflines, "#shared_buffers = 1000", repltok);
1086
1087         snprintf(repltok, sizeof(repltok), "lc_messages = '%s'", lc_messages);
1088         conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
1089
1090         snprintf(repltok, sizeof(repltok), "lc_monetary = '%s'", lc_monetary);
1091         conflines = replace_token(conflines, "#lc_monetary = 'C'", repltok);
1092
1093         snprintf(repltok, sizeof(repltok), "lc_numeric = '%s'", lc_numeric);
1094
1095         conflines = replace_token(conflines, "#lc_numeric = 'C'", repltok);
1096
1097         snprintf(repltok, sizeof(repltok), "lc_time = '%s'", lc_time);
1098         conflines = replace_token(conflines, "#lc_time = 'C'", repltok);
1099
1100         snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
1101
1102         writefile(path, conflines);
1103         chmod(path, 0600);
1104
1105         free(conflines);
1106
1107
1108         /* pg_hba.conf */
1109
1110         conflines = readfile(hba_file);
1111
1112 #ifndef HAVE_IPV6
1113         conflines = replace_token(conflines,
1114                                                           "host    all         all         ::1",
1115                                                           "#host    all         all         ::1");
1116 #endif
1117
1118         snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data);
1119
1120         writefile(path, conflines);
1121         chmod(path, 0600);
1122
1123         free(conflines);
1124
1125         /* pg_ident.conf */
1126
1127         conflines = readfile(ident_file);
1128
1129         snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data);
1130
1131         writefile(path, conflines);
1132         chmod(path, 0600);
1133
1134         free(conflines);
1135
1136         check_ok();
1137 }
1138
1139
1140 /*
1141  * run the BKI script in bootstrap mode to create template1
1142  */
1143 static void
1144 bootstrap_template1(char *short_version)
1145 {
1146         char       *talkargs = "";
1147         char      **bki_lines;
1148         char            headerline[MAXPGPATH];
1149
1150         PG_CMD_DECL;
1151
1152         printf(_("creating template1 database in %s/base/1 ... "), pg_data);
1153         fflush(stdout);
1154
1155         if (debug)
1156                 talkargs = "-d 5";
1157
1158         bki_lines = readfile(bki_file);
1159
1160         /* Check that bki file appears to be of the right version */
1161
1162         snprintf(headerline, sizeof(headerline), "# PostgreSQL %s\n",
1163                          short_version);
1164
1165         if (strcmp(headerline, *bki_lines) != 0)
1166         {
1167                 fprintf(stderr,
1168                                 _("%s: input file \"%s\" does not belong to PostgreSQL %s\n"
1169                                 "Check your installation or specify the correct path "
1170                                 "using the option -L.\n"),
1171                                 progname, bki_file, PG_VERSION);
1172                 exit_nicely();
1173
1174         }
1175
1176         bki_lines = replace_token(bki_lines, "POSTGRES", effective_user);
1177
1178         bki_lines = replace_token(bki_lines, "ENCODING", encodingid);
1179
1180         /*
1181          * Pass correct LC_xxx environment to bootstrap.
1182          *
1183          * The shell script arranged to restore the LC settings afterwards,
1184          * but there doesn't seem to be any compelling reason to do that.
1185          */
1186         snprintf(cmd, sizeof(cmd), "LC_COLLATE=%s", lc_collate);
1187         putenv(xstrdup(cmd));
1188
1189         snprintf(cmd, sizeof(cmd), "LC_CTYPE=%s", lc_ctype);
1190         putenv(xstrdup(cmd));
1191
1192         unsetenv("LC_ALL");
1193
1194         /* Also ensure backend isn't confused by this environment var: */
1195         unsetenv("PGCLIENTENCODING");
1196
1197         snprintf(cmd, sizeof(cmd),
1198                          "\"%s\" -boot -x1 %s %s template1",
1199                          backend_exec, boot_options, talkargs);
1200
1201         PG_CMD_OPEN;
1202
1203         for (line = bki_lines; *line != NULL; line++)
1204         {
1205                 PG_CMD_PUTLINE;
1206                 free(*line);
1207         }
1208
1209         PG_CMD_CLOSE;
1210
1211         free(bki_lines);
1212
1213         check_ok();
1214 }
1215
1216 /*
1217  * set up the shadow password table
1218  */
1219 static void
1220 setup_shadow(void)
1221 {
1222         char       *pg_shadow_setup[] = {
1223                 /*
1224                  * Create a trigger so that direct updates to pg_shadow will be
1225                  * written to the flat password/group files pg_pwd and pg_group
1226                  */
1227                 "CREATE TRIGGER pg_sync_pg_pwd "
1228                 "  AFTER INSERT OR UPDATE OR DELETE ON pg_shadow "
1229                 "  FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();\n",
1230                 "CREATE TRIGGER pg_sync_pg_group "
1231                 "  AFTER INSERT OR UPDATE OR DELETE ON pg_group "
1232                 "  FOR EACH ROW EXECUTE PROCEDURE update_pg_pwd_and_pg_group();\n",
1233
1234                 /*
1235                  * needs to be done before alter user, because alter user checks
1236                  * that pg_shadow is secure ...
1237                  */
1238                 "REVOKE ALL on pg_shadow FROM public;\n",
1239                 NULL
1240         };
1241
1242         PG_CMD_DECL;
1243
1244         fputs(_("initializing pg_shadow ... "), stdout);
1245         fflush(stdout);
1246
1247         snprintf(cmd, sizeof(cmd),
1248                          "\"%s\" %s template1 >%s",
1249                          backend_exec, backend_options,
1250                          DEVNULL);
1251
1252         PG_CMD_OPEN;
1253
1254         for (line = pg_shadow_setup; *line != NULL; line++)
1255                 PG_CMD_PUTLINE;
1256
1257         PG_CMD_CLOSE;
1258
1259         check_ok();
1260 }
1261
1262 /*
1263  * get the superuser password if required, and call postgres to set it
1264  */
1265 static void
1266 get_set_pwd(void)
1267 {
1268         PG_CMD_DECL_NOLINE;
1269
1270         char       *pwd1,
1271                            *pwd2;
1272         char            pwdpath[MAXPGPATH];
1273         struct stat statbuf;
1274
1275         if (pwprompt)
1276         {
1277                 /*
1278                  * Read password from terminal
1279                  */
1280                 pwd1 = simple_prompt("Enter new superuser password: ", 100, false);
1281                 pwd2 = simple_prompt("Enter it again: ", 100, false);
1282                 if (strcmp(pwd1, pwd2) != 0)
1283                 {
1284                         fprintf(stderr, _("Passwords didn't match.\n"));
1285                         exit_nicely();
1286                 }
1287                 free(pwd2);
1288         }
1289         else
1290         {
1291                 /*
1292                  * Read password from file
1293                  *
1294                  * Ideally this should insist that the file not be world-readable.
1295                  * However, this option is mainly intended for use on Windows where
1296                  * file permissions may not exist at all, so we'll skip the paranoia
1297                  * for now.
1298                  */
1299                 FILE *pwf = fopen(pwfilename,"r");
1300                 char pwdbuf[MAXPGPATH];
1301                 int  i;
1302
1303                 if (!pwf)
1304                 {
1305                         fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1306                                         progname, pwfilename, strerror(errno));
1307                         exit_nicely();
1308                 }
1309                 if (!fgets(pwdbuf, sizeof(pwdbuf), pwf))
1310                 {
1311                         fprintf(stderr, _("%s: could not read password from file \"%s\": %s\n"),
1312                                         progname, pwfilename, strerror(errno));
1313                         exit_nicely();
1314                 }
1315                 fclose(pwf);
1316
1317                 i = strlen(pwdbuf);
1318                 while (i > 0 && (pwdbuf[i-1] == '\r' || pwdbuf[i-1] == '\n'))
1319                         pwdbuf[--i] = '\0';
1320                 
1321                 pwd1 = xstrdup(pwdbuf);
1322                 
1323         }
1324         printf(_("setting password ... "));
1325         fflush(stdout);
1326
1327         snprintf(cmd, sizeof(cmd),
1328                          "\"%s\" %s template1 >%s",
1329                          backend_exec, backend_options,
1330                          DEVNULL);
1331
1332         PG_CMD_OPEN;
1333
1334         if (fprintf(pg,
1335                   "ALTER USER \"%s\" WITH PASSWORD '%s';\n", effective_user, pwd1) < 0)
1336         {
1337                 /* write failure */
1338                 exit_nicely();
1339         }
1340         fflush(pg);
1341
1342         PG_CMD_CLOSE;
1343
1344         snprintf(pwdpath, sizeof(pwdpath), "%s/global/pg_pwd", pg_data);
1345         if (stat(pwdpath, &statbuf) != 0 || !S_ISREG(statbuf.st_mode))
1346         {
1347                 fprintf(stderr,
1348                                 _("%s: The password file was not generated. "
1349                                 "Please report this problem.\n"),
1350                                 progname);
1351                 exit_nicely();
1352         }
1353
1354         check_ok();
1355 }
1356
1357 /*
1358  * toast sys tables
1359  */
1360 static void
1361 unlimit_systables(void)
1362 {
1363         char       *systables_setup[] = {
1364                 "ALTER TABLE pg_attrdef CREATE TOAST TABLE;\n",
1365                 "ALTER TABLE pg_constraint CREATE TOAST TABLE;\n",
1366                 "ALTER TABLE pg_database CREATE TOAST TABLE;\n",
1367                 "ALTER TABLE pg_description CREATE TOAST TABLE;\n",
1368                 "ALTER TABLE pg_group CREATE TOAST TABLE;\n",
1369                 "ALTER TABLE pg_proc CREATE TOAST TABLE;\n",
1370                 "ALTER TABLE pg_rewrite CREATE TOAST TABLE;\n",
1371                 "ALTER TABLE pg_shadow CREATE TOAST TABLE;\n",
1372                 "ALTER TABLE pg_statistic CREATE TOAST TABLE;\n",
1373                 NULL
1374         };
1375
1376         PG_CMD_DECL;
1377
1378         fputs(_("enabling unlimited row size for system tables ... "), stdout);
1379         fflush(stdout);
1380
1381         snprintf(cmd, sizeof(cmd),
1382                          "\"%s\" %s template1 >%s",
1383                          backend_exec, backend_options,
1384                          DEVNULL);
1385
1386         PG_CMD_OPEN;
1387
1388         for (line = systables_setup; *line != NULL; line++)
1389                 PG_CMD_PUTLINE;
1390
1391         PG_CMD_CLOSE;
1392
1393         check_ok();
1394 }
1395
1396 /*
1397  * set up pg_depend
1398  */
1399 static void
1400 setup_depend(void)
1401 {
1402         char       *pg_depend_setup[] = {
1403                 /*
1404                  * Make PIN entries in pg_depend for all objects made so far in
1405                  * the tables that the dependency code handles.  This is overkill
1406                  * (the system doesn't really depend on having every last weird
1407                  * datatype, for instance) but generating only the minimum
1408                  * required set of dependencies seems hard.
1409                  *
1410                  * Note that we deliberately do not pin the system views, which
1411                  * haven't been created yet.
1412                  *
1413                  * First delete any already-made entries; PINs override all else, and
1414                  * must be the only entries for their objects.
1415                  */
1416                 "DELETE FROM pg_depend;\n",
1417                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1418                 " FROM pg_class;\n",
1419                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1420                 " FROM pg_proc;\n",
1421                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1422                 " FROM pg_type;\n",
1423                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1424                 " FROM pg_cast;\n",
1425                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1426                 " FROM pg_constraint;\n",
1427                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1428                 " FROM pg_attrdef;\n",
1429                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1430                 " FROM pg_language;\n",
1431                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1432                 " FROM pg_operator;\n",
1433                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1434                 " FROM pg_opclass;\n",
1435                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1436                 " FROM pg_rewrite;\n",
1437                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1438                 " FROM pg_trigger;\n",
1439
1440                 /*
1441                  * restriction here to avoid pinning the public namespace
1442                  */
1443                 "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1444                 " FROM pg_namespace "
1445                 "    WHERE nspname LIKE 'pg%';\n",
1446                 NULL
1447         };
1448
1449         PG_CMD_DECL;
1450
1451         fputs(_("initializing pg_depend ... "), stdout);
1452         fflush(stdout);
1453
1454         snprintf(cmd, sizeof(cmd),
1455                          "\"%s\" %s template1 >%s",
1456                          backend_exec, backend_options,
1457                          DEVNULL);
1458
1459         PG_CMD_OPEN;
1460
1461         for (line = pg_depend_setup; *line != NULL; line++)
1462                 PG_CMD_PUTLINE;
1463
1464         PG_CMD_CLOSE;
1465
1466         check_ok();
1467 }
1468
1469 /*
1470  * set up system views
1471  */
1472 static void
1473 setup_sysviews(void)
1474 {
1475         PG_CMD_DECL;
1476
1477         char      **sysviews_setup;
1478
1479         fputs(_("creating system views ... "), stdout);
1480         fflush(stdout);
1481
1482         sysviews_setup = readfile(system_views_file);
1483
1484         /*
1485          * We use -N here to avoid backslashing stuff in system_views.sql
1486          */
1487         snprintf(cmd, sizeof(cmd),
1488                          "\"%s\" %s -N template1 >%s",
1489                          backend_exec, backend_options,
1490                          DEVNULL);
1491
1492         PG_CMD_OPEN;
1493
1494         for (line = sysviews_setup; *line != NULL; line++)
1495         {
1496                 PG_CMD_PUTLINE;
1497                 free(*line);
1498         }
1499
1500         PG_CMD_CLOSE;
1501
1502         free(sysviews_setup);
1503
1504         check_ok();
1505 }
1506
1507 /*
1508  * load description data
1509  */
1510 static void
1511 setup_description(void)
1512 {
1513         PG_CMD_DECL_NOLINE;
1514         int                     fres;
1515
1516         fputs(_("loading pg_description ... "), stdout);
1517         fflush(stdout);
1518
1519         snprintf(cmd, sizeof(cmd),
1520                          "\"%s\" %s template1 >%s",
1521                          backend_exec, backend_options,
1522                          DEVNULL);
1523
1524         PG_CMD_OPEN;
1525
1526         fres = fprintf(pg,
1527                                    "CREATE TEMP TABLE tmp_pg_description ( "
1528                                    "    objoid oid, "
1529                                    "    classname name, "
1530                                    "    objsubid int4, "
1531                                    "    description text) WITHOUT OIDS;\n");
1532         if (fres < 0)
1533                 exit_nicely();
1534
1535         fres = fprintf(pg,
1536                                    "COPY tmp_pg_description FROM '%s';\n",
1537                                    desc_file);
1538         if (fres < 0)
1539                 exit_nicely();
1540
1541         fres = fprintf(pg,
1542                                    "INSERT INTO pg_description "
1543                                    " SELECT t.objoid, c.oid, t.objsubid, t.description "
1544                                    "  FROM tmp_pg_description t, pg_class c "
1545                                    "    WHERE c.relname = t.classname;\n");
1546         if (fres < 0)
1547                 exit_nicely();
1548
1549         PG_CMD_CLOSE;
1550
1551         check_ok();
1552 }
1553
1554 /*
1555  * load conversion functions
1556  */
1557 static void
1558 setup_conversion(void)
1559 {
1560         PG_CMD_DECL;
1561
1562         char      **conv_lines;
1563
1564         fputs(_("creating conversions ... "), stdout);
1565         fflush(stdout);
1566
1567         snprintf(cmd, sizeof(cmd),
1568                          "\"%s\" %s template1 >%s",
1569                          backend_exec, backend_options,
1570                          DEVNULL);
1571
1572         PG_CMD_OPEN;
1573
1574         conv_lines = readfile(conversion_file);
1575         for (line = conv_lines; *line != NULL; line++)
1576         {
1577                 if (strstr(*line, "DROP CONVERSION") != *line)
1578                         PG_CMD_PUTLINE;
1579
1580                 free(*line);
1581         }
1582
1583         free(conv_lines);
1584
1585         PG_CMD_CLOSE;
1586
1587         check_ok();
1588 }
1589
1590 /*
1591  * Set up privileges
1592  *
1593  * We set most system catalogs and built-in functions as world-accessible.
1594  * Some objects may require different permissions by default, so we
1595  * make sure we don't overwrite privilege sets that have already been
1596  * set (NOT NULL).
1597  */
1598 static void
1599 setup_privileges(void)
1600 {
1601         char       *privileges_setup[] = {
1602                 "UPDATE pg_class "
1603                 "  SET relacl = '{\"=r/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
1604                 "  WHERE relkind IN ('r', 'v', 'S') AND relacl IS NULL;\n",
1605                 "UPDATE pg_proc "
1606                 "  SET proacl = '{\"=X/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
1607                 "  WHERE proacl IS NULL;\n",
1608                 "UPDATE pg_language "
1609                 "  SET lanacl = '{\"=U/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
1610                 "  WHERE lanpltrusted;\n",
1611                 "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n",
1612                 "GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n",
1613                 NULL
1614         };
1615
1616         PG_CMD_DECL;
1617
1618         char      **priv_lines;
1619
1620         fputs(_("setting privileges on built-in objects ... "), stdout);
1621         fflush(stdout);
1622
1623         snprintf(cmd, sizeof(cmd),
1624                          "\"%s\" %s template1 >%s",
1625                          backend_exec, backend_options,
1626                          DEVNULL);
1627
1628         PG_CMD_OPEN;
1629
1630         priv_lines = replace_token(privileges_setup,
1631                                                            "$POSTGRES_SUPERUSERNAME", effective_user);
1632         for (line = priv_lines; *line != NULL; line++)
1633                 PG_CMD_PUTLINE;
1634
1635         PG_CMD_CLOSE;
1636
1637         check_ok();
1638 }
1639
1640 /*
1641  * extract the strange version of version required for information schema
1642  * (09.08.0007abc)
1643  */
1644 static void
1645 set_info_version(void)
1646 {
1647         char       *letterversion;
1648         long            major = 0,
1649                                 minor = 0,
1650                                 micro = 0;
1651         char       *endptr;
1652         char       *vstr = xstrdup(PG_VERSION);
1653         char       *ptr;
1654
1655         ptr = vstr + (strlen(vstr) - 1);
1656         while (ptr != vstr && (*ptr < '0' || *ptr > '9'))
1657                 ptr--;
1658         letterversion = ptr + 1;
1659         major = strtol(vstr, &endptr, 10);
1660         if (*endptr)
1661                 minor = strtol(endptr + 1, &endptr, 10);
1662         if (*endptr)
1663                 micro = strtol(endptr + 1, &endptr, 10);
1664         snprintf(infoversion, sizeof(infoversion), "%02ld.%02ld.%04ld%s",
1665                          major, minor, micro, letterversion);
1666 }
1667
1668 /*
1669  * load info schema and populate from features file
1670  */
1671 static void
1672 setup_schema(void)
1673 {
1674         PG_CMD_DECL;
1675         char      **lines;
1676         int                     fres;
1677
1678         fputs(_("creating information schema ... "), stdout);
1679         fflush(stdout);
1680
1681         lines = readfile(info_schema_file);
1682
1683         /*
1684          * We use -N here to avoid backslashing stuff in information_schema.sql
1685          */
1686         snprintf(cmd, sizeof(cmd),
1687                          "\"%s\" %s -N template1 >%s",
1688                          backend_exec, backend_options,
1689                          DEVNULL);
1690
1691         PG_CMD_OPEN;
1692
1693         for (line = lines; *line != NULL; line++)
1694         {
1695                 PG_CMD_PUTLINE;
1696                 free(*line);
1697         }
1698
1699         free(lines);
1700
1701         PG_CMD_CLOSE;
1702
1703         snprintf(cmd, sizeof(cmd),
1704                          "\"%s\" %s template1 >%s",
1705                          backend_exec, backend_options,
1706                          DEVNULL);
1707
1708         PG_CMD_OPEN;
1709
1710         fres = fprintf(pg,
1711                                    "UPDATE information_schema.sql_implementation_info "
1712                                    "  SET character_value = '%s' "
1713                                    "  WHERE implementation_info_name = 'DBMS VERSION';\n",
1714                                    infoversion);
1715         if (fres < 0)
1716                 exit_nicely();
1717
1718         fres = fprintf(pg,
1719                                    "COPY information_schema.sql_features "
1720                                    "  (feature_id, feature_name, sub_feature_id, "
1721                                    "  sub_feature_name, is_supported, comments) "
1722                                    " FROM '%s';\n",
1723                                    features_file);
1724         if (fres < 0)
1725                 exit_nicely();
1726
1727         PG_CMD_CLOSE;
1728
1729         check_ok();
1730 }
1731
1732 /*
1733  * clean everything up in template1
1734  */
1735 static void
1736 vacuum_db(void)
1737 {
1738         PG_CMD_DECL_NOLINE;
1739
1740         fputs(_("vacuuming database template1 ... "), stdout);
1741         fflush(stdout);
1742
1743         snprintf(cmd, sizeof(cmd),
1744                          "\"%s\" %s template1 >%s",
1745                          backend_exec, backend_options,
1746                          DEVNULL);
1747
1748         PG_CMD_OPEN;
1749
1750         if (fputs("ANALYZE;\nVACUUM FULL FREEZE;\n", pg) < 0)
1751                 exit_nicely();
1752         fflush(pg);
1753
1754         PG_CMD_CLOSE;
1755
1756         check_ok();
1757 }
1758
1759 /*
1760  * copy template1 to template0
1761  */
1762 static void
1763 make_template0(void)
1764 {
1765         char       *template0_setup[] = {
1766                 "CREATE DATABASE template0;\n",
1767                 "UPDATE pg_database SET "
1768                 "       datistemplate = 't', "
1769                 "       datallowconn = 'f' "
1770                 "    WHERE datname = 'template0';\n",
1771
1772                 /*
1773                  * We use the OID of template0 to determine lastsysoid
1774                  */
1775                 "UPDATE pg_database SET datlastsysoid = "
1776                 "    (SELECT oid::int4 - 1 FROM pg_database "
1777                 "    WHERE datname = 'template0');\n",
1778
1779                 /*
1780                  * Explicitly revoke public create-schema and create-temp-table
1781                  * privileges in template1 and template0; else the latter would be
1782                  * on by default
1783                  */
1784                 "REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n",
1785                 "REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n",
1786
1787                 /*
1788                  * Finally vacuum to clean up dead rows in pg_database
1789                  */
1790                 "VACUUM FULL pg_database;\n",
1791                 NULL
1792         };
1793
1794         PG_CMD_DECL;
1795
1796         fputs(_("copying template1 to template0 ... "), stdout);
1797         fflush(stdout);
1798
1799         snprintf(cmd, sizeof(cmd),
1800                          "\"%s\" %s template1 >%s",
1801                          backend_exec, backend_options,
1802                          DEVNULL);
1803
1804         PG_CMD_OPEN;
1805
1806         for (line = template0_setup; *line; line++)
1807                 PG_CMD_PUTLINE;
1808
1809         PG_CMD_CLOSE;
1810
1811         check_ok();
1812 }
1813
1814
1815 /*
1816  * signal handler in case we are interrupted.
1817  *
1818  * The Windows runtime docs at
1819  * http://msdn.microsoft.com/library/en-us/vclib/html/_crt_signal.asp
1820  * specifically forbid a number of things being done from a signal handler,
1821  * including IO, memory allocation and system calls, and only allow jmpbuf
1822  * if you are handling SIGFPE.
1823  *
1824  * I avoided doing the forbidden things by setting a flag instead of calling
1825  * exit_nicely() directly.
1826  *
1827  * Also note the behaviour of Windows with SIGINT, which says this:
1828  *       Note   SIGINT is not supported for any Win32 application, including
1829  *       Windows 98/Me and Windows NT/2000/XP. When a CTRL+C interrupt occurs,
1830  *       Win32 operating systems generate a new thread to specifically handle
1831  *       that interrupt. This can cause a single-thread application such as UNIX,
1832  *       to become multithreaded, resulting in unexpected behavior.
1833  *
1834  * I have no idea how to handle this. (Strange they call UNIX an application!)
1835  * So this will need some testing on Windows.
1836  */
1837 static void
1838 trapsig(int signum)
1839 {
1840         /* handle systems that reset the handler, like Windows (grr) */
1841         pqsignal(signum, trapsig);
1842         caught_signal = true;
1843 }
1844
1845 /*
1846  * call exit_nicely() if we got a signal, or else output "ok".
1847  */
1848 static void
1849 check_ok()
1850 {
1851         if (caught_signal)
1852         {
1853                 printf(_("caught signal\n"));
1854                 exit_nicely();
1855         }
1856         else if (output_failed)
1857         {
1858                 printf(_("could not write to child process\n"));
1859                 exit_nicely();
1860         }
1861         else
1862         {
1863                 /* all seems well */
1864                 printf(_("ok\n"));
1865         }
1866 }
1867
1868
1869 /*
1870  * check if given string is a valid locale specifier
1871  * based on some code given to me by Peter Eisentraut
1872  * (but I take responsibility for it :-)
1873  */
1874 static bool
1875 chklocale(const char *locale)
1876 {
1877         bool            ret;
1878         int                     category = LC_CTYPE;
1879         char       *save;
1880
1881         save = setlocale(category, NULL);
1882         if (!save)
1883                 return false;                   /* should not happen; */
1884
1885         save = xstrdup(save);
1886
1887         ret = (setlocale(category, locale) != NULL);
1888
1889         setlocale(category, save);
1890         free(save);
1891
1892         /* should we exit here? */
1893         if (!ret)
1894                 fprintf(stderr, _("%s: invalid locale name \"%s\"\n"), progname, locale);
1895
1896         return ret;
1897 }
1898
1899 /*
1900  * set up the locale variables
1901  *
1902  * assumes we have called setlocale(LC_ALL,"")
1903  */
1904 static void
1905 setlocales(void)
1906 {
1907         /* set empty lc_* values to locale config if set */
1908
1909         if (strlen(locale) > 0)
1910         {
1911                 if (strlen(lc_ctype) == 0)
1912                         lc_ctype = locale;
1913                 if (strlen(lc_collate) == 0)
1914                         lc_collate = locale;
1915                 if (strlen(lc_numeric) == 0)
1916                         lc_numeric = locale;
1917                 if (strlen(lc_time) == 0)
1918                         lc_time = locale;
1919                 if (strlen(lc_monetary) == 0)
1920                         lc_monetary = locale;
1921                 if (strlen(lc_messages) == 0)
1922                         lc_messages = locale;
1923         }
1924
1925         /*
1926          * override absent/invalid config settings from initdb's locale
1927          * settings
1928          */
1929
1930         if (strlen(lc_ctype) == 0 || !chklocale(lc_ctype))
1931                 lc_ctype = xstrdup(setlocale(LC_CTYPE, NULL));
1932         if (strlen(lc_collate) == 0 || !chklocale(lc_collate))
1933                 lc_collate = xstrdup(setlocale(LC_COLLATE, NULL));
1934         if (strlen(lc_numeric) == 0 || !chklocale(lc_numeric))
1935                 lc_numeric = xstrdup(setlocale(LC_NUMERIC, NULL));
1936         if (strlen(lc_time) == 0 || !chklocale(lc_time))
1937                 lc_time = xstrdup(setlocale(LC_TIME, NULL));
1938         if (strlen(lc_monetary) == 0 || !chklocale(lc_monetary))
1939                 lc_monetary = xstrdup(setlocale(LC_MONETARY, NULL));
1940         if (strlen(lc_messages) == 0 || !chklocale(lc_messages))
1941 #ifdef LC_MESSAGES
1942         {
1943                 /* when available get the current locale setting */
1944                 lc_messages = xstrdup(setlocale(LC_MESSAGES, NULL));
1945         }
1946 #else
1947         {
1948                 /* when not available, get the CTYPE setting */
1949                 lc_messages = xstrdup(setlocale(LC_CTYPE, NULL));
1950         }
1951 #endif
1952
1953 }
1954
1955 /*
1956  * print help text
1957  */
1958 static void
1959 usage(const char *progname)
1960 {
1961         printf(_("%s initializes a PostgreSQL database cluster.\n\n"), progname);
1962         printf(_("Usage:\n"));
1963         printf(_("  %s [OPTION]... [DATADIR]\n"), progname);
1964         printf(_("\nOptions:\n"));
1965         printf(_(" [-D, --pgdata=]DATADIR     location for this database cluster\n"));
1966         printf(_("  -E, --encoding=ENCODING   set default encoding for new databases\n"));
1967         printf(_("  --locale=LOCALE           initialize database cluster with given locale\n"));
1968         printf(_("  --lc-collate, --lc-ctype, --lc-messages=LOCALE\n"
1969                          "  --lc-monetary, --lc-numeric, --lc-time=LOCALE\n"
1970                          "                            initialize database cluster with given locale\n"
1971                          "                            in the respective category (default taken from\n"
1972                          "                            environment)\n"));
1973         printf(_("  --no-locale               equivalent to --locale=C\n"));
1974         printf(_("  -U, --username=NAME       database superuser name\n"));
1975         printf(_("  -W, --pwprompt            prompt for a password for the new superuser\n"));
1976         printf(_("  --pwfile=filename         read password for the new superuser from file\n"));
1977         printf(_("  -?, --help                show this help, then exit\n"));
1978         printf(_("  -V, --version             output version information, then exit\n"));
1979         printf(_("\nLess commonly used options:\n"));
1980         printf(_("  -d, --debug               generate lots of debugging output\n"));
1981         printf(_("  -s, --show                show internal settings\n"));
1982         printf(_("  -L DIRECTORY              where to find the input files\n"));
1983         printf(_("  -n, --noclean             do not clean up after errors\n"));
1984         printf(_("\nIf the data directory is not specified, the environment variable PGDATA\n"
1985                          "is used.\n"));
1986         printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
1987 }
1988
1989 int
1990 main(int argc, char *argv[])
1991 {
1992         /*
1993          * options with no short version return a low integer, the rest return
1994          * their short version value
1995          */
1996         static struct option long_options[] = {
1997                 {"pgdata", required_argument, NULL, 'D'},
1998                 {"encoding", required_argument, NULL, 'E'},
1999                 {"locale", required_argument, NULL, 1},
2000                 {"lc-collate", required_argument, NULL, 2},
2001                 {"lc-ctype", required_argument, NULL, 3},
2002                 {"lc-monetary", required_argument, NULL, 4},
2003                 {"lc-numeric", required_argument, NULL, 5},
2004                 {"lc-time", required_argument, NULL, 6},
2005                 {"lc-messages", required_argument, NULL, 7},
2006                 {"no-locale", no_argument, NULL, 8},
2007                 {"pwprompt", no_argument, NULL, 'W'},
2008                 {"pwfile", required_argument, NULL, 9},
2009                 {"username", required_argument, NULL, 'U'},
2010                 {"help", no_argument, NULL, '?'},
2011                 {"version", no_argument, NULL, 'V'},
2012                 {"debug", no_argument, NULL, 'd'},
2013                 {"show", no_argument, NULL, 's'},
2014                 {"noclean", no_argument, NULL, 'n'},
2015                 {0, 0, 0, 0}
2016         };
2017
2018         int                     c,
2019                                 i,
2020                                 ret;
2021         int                     option_index;
2022         char       *short_version;
2023         char       *pgdenv;                     /* PGDATA value got from sent to
2024                                                                  * environment */
2025         static const char *subdirs[] = {
2026                 "global",
2027                 "pg_xlog",
2028                 "pg_xlog/archive_status",
2029                 "pg_clog",
2030                 "pg_subtrans",
2031                 "base",
2032                 "base/1",
2033                 "pg_tblspc"
2034         };
2035
2036         progname = get_progname(argv[0]);
2037         set_pglocale_pgservice(argv[0], "initdb");
2038
2039     if (argc > 1)
2040     {
2041         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
2042         {
2043             usage(progname);
2044             exit(0);
2045         }
2046         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
2047         {
2048             puts("initdb (PostgreSQL) " PG_VERSION);
2049             exit(0);
2050         }
2051     }
2052
2053         /* process command-line options */
2054
2055         while ((c = getopt_long(argc, argv, "dD:E:L:nU:W", long_options, &option_index)) != -1)
2056         {
2057                 switch (c)
2058                 {
2059                         case 'D':
2060                                 pg_data = xstrdup(optarg);
2061                                 break;
2062                         case 'E':
2063                                 encoding = xstrdup(optarg);
2064                                 break;
2065                         case 'W':
2066                                 pwprompt = true;
2067                                 break;
2068                         case 'U':
2069                                 username = xstrdup(optarg);
2070                                 break;
2071                         case 'd':
2072                                 debug = true;
2073                 printf(_("Running in debug mode.\n"));
2074                                 break;
2075                         case 'n':
2076                                 noclean = true;
2077                                 printf(_("Running in noclean mode.  Mistakes will not be cleaned up.\n"));
2078                                 break;
2079                         case 'L':
2080                                 share_path = xstrdup(optarg);
2081                                 break;
2082                         case 1:
2083                                 locale = xstrdup(optarg);
2084                                 break;
2085                         case 2:
2086                                 lc_collate = xstrdup(optarg);
2087                                 break;
2088                         case 3:
2089                                 lc_ctype = xstrdup(optarg);
2090                                 break;
2091                         case 4:
2092                                 lc_monetary = xstrdup(optarg);
2093                                 break;
2094                         case 5:
2095                                 lc_numeric = xstrdup(optarg);
2096                                 break;
2097                         case 6:
2098                                 lc_time = xstrdup(optarg);
2099                                 break;
2100                         case 7:
2101                                 lc_messages = xstrdup(optarg);
2102                                 break;
2103                         case 8:
2104                                 locale = "C";
2105                                 break;
2106                         case 9:
2107                                 pwfilename = xstrdup(optarg);
2108                                 break;
2109                         case 's':
2110                                 show_setting = true;
2111                                 break;
2112                         default:
2113                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2114                         progname);
2115                                 exit(1);
2116                 }
2117         }
2118
2119         /* Non-option argument specifies data directory */
2120         if (optind < argc)
2121         {
2122                 pg_data = xstrdup(argv[optind]);
2123                 optind++;
2124         }
2125
2126         if (optind < argc)
2127         {
2128                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
2129                                                   progname, argv[optind + 1]);
2130                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
2131                                 progname);
2132         }
2133
2134         if (pwprompt && pwfilename)
2135         {
2136                 fprintf(stderr, _("%s: you cannot specify both password prompt and password file\n"), progname);
2137                 exit(1);
2138         }
2139
2140         if (strlen(pg_data) == 0)
2141         {
2142                 pgdenv = getenv("PGDATA");
2143                 if (pgdenv && strlen(pgdenv))
2144                 {
2145                         /* PGDATA found */
2146                         pg_data = xstrdup(pgdenv);
2147                 }
2148                 else
2149                 {
2150                         fprintf(stderr,
2151                                         _("%s: no data directory specified\n"
2152                                           "You must identify the directory where the data for this database system\n"
2153                                           "will reside.  Do this with either the invocation option -D or the\n"
2154                                           "environment variable PGDATA.\n"),
2155                                         progname);
2156                         exit(1);
2157                 }
2158         }
2159
2160         canonicalize_path(pg_data);
2161
2162         /*
2163          * we have to set PGDATA for postgres rather than pass it on the
2164          * commnd line to avoid dumb quoting problems on Windows, and we would
2165          * expecially need quotes otherwise on Windows because paths there are
2166          * most likely to have embedded spaces.
2167          */
2168         pgdenv = xmalloc(8 + strlen(pg_data));
2169         sprintf(pgdenv, "PGDATA=%s", pg_data);
2170         putenv(pgdenv);
2171
2172         if ((ret = find_other_exec(argv[0], "postgres", PG_VERSIONSTR,
2173                                                            backend_exec)) < 0)
2174         {
2175                 if (ret == -1)
2176                         fprintf(stderr,
2177                                                 _("The program \"postgres\" is needed by %s "
2178                                                 "but was not found in the same directory as \"%s\".\n"
2179                                                 "Check your installation.\n"),
2180                                                 progname, progname);
2181                 else
2182                         fprintf(stderr,
2183                                                 _("The program \"postgres\" was found by %s "
2184                                                 "but was not the same version as \"%s\".\n"
2185                                                 "Check your installation.\n"),
2186                                                 progname, progname);
2187                 exit(1);
2188         }
2189
2190         /* store binary directory */
2191         strcpy(bin_path, backend_exec);
2192         *last_dir_separator(bin_path) = '\0';
2193
2194         if (!share_path)
2195         {
2196                 share_path = xmalloc(MAXPGPATH);
2197                 get_share_path(backend_exec, share_path);
2198         }
2199
2200         canonicalize_path(share_path);
2201
2202         if ((short_version = get_short_version()) == NULL)
2203         {
2204                 fprintf(stderr, _("%s: could not determine valid short version string\n"), progname);
2205                 exit(1);
2206         }
2207
2208         if (strlen(username))
2209                 effective_user = username;
2210         else
2211                 effective_user = get_id();
2212
2213         if (strlen(encoding))
2214                 encodingid = get_encoding_id(encoding);
2215
2216         set_input(&bki_file, "postgres.bki");
2217         set_input(&desc_file, "postgres.description");
2218         set_input(&hba_file, "pg_hba.conf.sample");
2219         set_input(&ident_file, "pg_ident.conf.sample");
2220         set_input(&conf_file, "postgresql.conf.sample");
2221         set_input(&conversion_file, "conversion_create.sql");
2222         set_input(&info_schema_file, "information_schema.sql");
2223         set_input(&features_file, "sql_features.txt");
2224         set_input(&system_views_file, "system_views.sql");
2225
2226         set_info_version();
2227
2228         if (show_setting || debug)
2229         {
2230                 fprintf(stderr,
2231                                 "VERSION=%s\n"
2232                                 "PGDATA=%s\nshare_path=%s\nPGPATH=%s\n"
2233                                 "POSTGRES_SUPERUSERNAME=%s\nPOSTGRES_BKI=%s\n"
2234                                 "POSTGRES_DESCR=%s\nPOSTGRESQL_CONF_SAMPLE=%s\n"
2235                                 "PG_HBA_SAMPLE=%s\nPG_IDENT_SAMPLE=%s\n",
2236                                 PG_VERSION,
2237                                 pg_data, share_path, bin_path,
2238                                 effective_user, bki_file,
2239                                 desc_file, conf_file,
2240                                 hba_file, ident_file);
2241                 if (show_setting)
2242                         exit(0);
2243         }
2244
2245         check_input(bki_file);
2246         check_input(desc_file);
2247         check_input(hba_file);
2248         check_input(ident_file);
2249         check_input(conf_file);
2250         check_input(conversion_file);
2251         check_input(info_schema_file);
2252         check_input(features_file);
2253         check_input(system_views_file);
2254
2255         setlocales();
2256
2257         printf(_("The files belonging to this database system will be owned "
2258                    "by user \"%s\".\n"
2259                    "This user must also own the server process.\n\n"),
2260                    effective_user);
2261
2262         if (strcmp(lc_ctype, lc_collate) == 0 &&
2263                 strcmp(lc_ctype, lc_time) == 0 &&
2264                 strcmp(lc_ctype, lc_numeric) == 0 &&
2265                 strcmp(lc_ctype, lc_monetary) == 0 &&
2266                 strcmp(lc_ctype, lc_messages) == 0)
2267         {
2268                 printf(_("The database cluster will be initialized with locale %s.\n"), lc_ctype);
2269         }
2270         else
2271         {
2272                 printf(_("The database cluster will be initialized with locales\n"
2273                            "  COLLATE:  %s\n"
2274                            "  CTYPE:    %s\n"
2275                            "  MESSAGES: %s\n"
2276                            "  MONETARY: %s\n"
2277                            "  NUMERIC:  %s\n"
2278                            "  TIME:     %s\n"),
2279                            lc_collate,
2280                            lc_ctype,
2281                            lc_messages,
2282                            lc_monetary,
2283                            lc_numeric,
2284                            lc_time);
2285         }
2286
2287 #ifdef HAVE_LANGINFO_H
2288         if (strcmp(lc_ctype, "C") != 0 && strcmp(lc_ctype, "POSIX") != 0)
2289         {
2290                 if (strlen(encoding) == 0)
2291                 {
2292                         int tmp;
2293                         tmp = find_matching_encoding(lc_ctype);
2294                         if (tmp == -1)
2295                         {
2296                                 fprintf(stderr, _("%s: could not find suitable encoding for locale \"%s\"\n"), progname, lc_ctype);
2297                                 fprintf(stderr, _("Rerun %s with the -E option.\n"), progname);
2298                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
2299                                 exit(1);
2300                         }
2301                         else
2302                         {
2303                                 encodingid = encodingid_to_string(tmp);
2304                                 printf(_("The default database encoding has accordingly been set to %s.\n"), 
2305                                            pg_encoding_to_char(tmp));
2306                         }
2307                 }
2308                 else
2309                         check_encodings_match(atoi(encodingid), lc_ctype);
2310         }
2311 #endif /* HAVE_LANGINFO_H */
2312
2313         printf("\n");
2314
2315         umask(077);
2316
2317         /*
2318          * now we are starting to do real work, trap signals so we can clean
2319          * up
2320          */
2321
2322         /* some of these are not valid on Windows */
2323 #ifdef SIGHUP
2324         pqsignal(SIGHUP, trapsig);
2325 #endif
2326 #ifdef SIGINT
2327         pqsignal(SIGINT, trapsig);
2328 #endif
2329 #ifdef SIGQUIT
2330         pqsignal(SIGQUIT, trapsig);
2331 #endif
2332 #ifdef SIGTERM
2333         pqsignal(SIGTERM, trapsig);
2334 #endif
2335
2336         /* Ignore SIGPIPE when writing to backend, so we can clean up */
2337 #ifdef SIGPIPE
2338         pqsignal(SIGPIPE, SIG_IGN);
2339 #endif
2340
2341         switch (check_data_dir())
2342         {
2343                 case 0:
2344                         /* PGDATA not there, must create it */
2345                         printf(_("creating directory %s ... "),
2346                                    pg_data);
2347                         fflush(stdout);
2348
2349                         if (!mkdatadir(NULL))
2350                                 exit_nicely();
2351                         else
2352                                 check_ok();
2353
2354                         made_new_pgdata = true;
2355                         break;
2356
2357                 case 1:
2358                         /* Present but empty, fix permissions and use it */
2359                         printf(_("fixing permissions on existing directory %s ... "),
2360                                    pg_data);
2361                         fflush(stdout);
2362
2363                         if (chmod(pg_data, 0700) != 0)
2364                         {
2365                                 perror(pg_data);
2366                                 exit_nicely();
2367                         }
2368                         else
2369                                 check_ok();
2370
2371                         found_existing_pgdata = true;
2372                         break;
2373
2374                 case 2:
2375                         /* Present and not empty */
2376                         fprintf(stderr,
2377                                         _("%s: directory \"%s\" exists but is not empty\n"
2378                                         "If you want to create a new database system, either remove or empty\n"
2379                                         "the directory \"%s\" or run %s\n"
2380                                         "with an argument other than \"%s\".\n"),
2381                                         progname, pg_data, pg_data, progname, pg_data);
2382                         exit(1);                        /* no further message needed */
2383
2384                 default:
2385                         /* Trouble accessing directory */
2386                         perror(pg_data);
2387                         exit_nicely();
2388         }
2389
2390         /* Create required subdirectories */
2391
2392         for (i = 0; i < (sizeof(subdirs) / sizeof(char *)); i++)
2393         {
2394                 printf(_("creating directory %s/%s ... "), pg_data, subdirs[i]);
2395                 fflush(stdout);
2396
2397                 if (!mkdatadir(subdirs[i]))
2398                         exit_nicely();
2399                 else
2400                         check_ok();
2401         }
2402
2403         /* Top level PG_VERSION is checked by bootstrapper, so make it first */
2404         set_short_version(short_version, NULL);
2405
2406         /*
2407          * Determine platform-specific config settings
2408          *
2409          * Use reasonable values if kernel will let us, else scale back.  Probe for
2410          * max_connections first since it is subject to more constraints than
2411          * shared_buffers.
2412          */
2413
2414         set_null_conf();
2415
2416         test_connections();
2417         test_buffers();
2418
2419         /* Now create all the text config files */
2420         setup_config();
2421
2422         /* Bootstrap template1 */
2423         bootstrap_template1(short_version);
2424
2425         /* Make the per-database PG_VERSION for template1 only after init'ing it */
2426         set_short_version(short_version, "base/1");
2427
2428         /* Create the stuff we don't need to use bootstrap mode for */
2429
2430         setup_shadow();
2431         if (pwprompt || pwfilename)
2432                 get_set_pwd();
2433
2434         unlimit_systables();
2435
2436         setup_depend();
2437
2438         setup_sysviews();
2439
2440         setup_description();
2441
2442         setup_conversion();
2443
2444         setup_privileges();
2445
2446         setup_schema();
2447
2448         vacuum_db();
2449
2450         make_template0();
2451
2452         printf(_("\nSuccess. You can now start the database server using:\n\n"
2453                    "    %s%s%s/postmaster -D %s%s%s\n"
2454                    "or\n"
2455                    "    %s%s%s/pg_ctl -D %s%s%s -l logfile start\n\n"),
2456                  QUOTE_PATH, bin_path, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH,
2457                 QUOTE_PATH, bin_path, QUOTE_PATH, QUOTE_PATH, pg_data, QUOTE_PATH);
2458
2459         return 0;
2460 }