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