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