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