OSDN Git Service

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