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