PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
initdb.c
Go to the documentation of this file.
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 server.
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 three databases: the
12  * template databases "template0" and "template1", and a default user
13  * database "postgres".
14  *
15  * The template databases are ordinary PostgreSQL databases. template0
16  * is never supposed to change after initdb, whereas template1 can be
17  * changed to add site-local standard data. Either one can be copied
18  * to produce a new database.
19  *
20  * For largely-historical reasons, the template1 database is the one built
21  * by the basic bootstrap process. After it is complete, template0 and
22  * the default database, postgres, are made just by copying template1.
23  *
24  * To create template1, we run the postgres (backend) program in bootstrap
25  * mode and feed it data from the postgres.bki library file. After this
26  * initial bootstrap phase, some additional stuff is created by normal
27  * SQL commands fed to a standalone backend. Some of those commands are
28  * just embedded into this program (yeah, it's ugly), but larger chunks
29  * are taken from script files.
30  *
31  *
32  * Note:
33  * The program has some memory leakage - it isn't worth cleaning it up.
34  *
35  * This is a C implementation of the previous shell script for setting up a
36  * PostgreSQL cluster location, and should be highly compatible with it.
37  * author of C translation: Andrew Dunstan mailto:andrew@dunslane.net
38  *
39  * This code is released under the terms of the PostgreSQL License.
40  *
41  * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
42  * Portions Copyright (c) 1994, Regents of the University of California
43  *
44  * src/bin/initdb/initdb.c
45  *
46  *-------------------------------------------------------------------------
47  */
48 
49 #include "postgres_fe.h"
50 
51 #include <dirent.h>
52 #include <fcntl.h>
53 #include <sys/stat.h>
54 #include <unistd.h>
55 #include <locale.h>
56 #include <signal.h>
57 #include <time.h>
58 
59 #ifdef HAVE_SHM_OPEN
60 #include "sys/mman.h"
61 #endif
62 
63 #include "catalog/catalog.h"
64 #include "common/username.h"
65 #include "mb/pg_wchar.h"
66 #include "getaddrinfo.h"
67 #include "getopt_long.h"
68 #include "miscadmin.h"
69 
70 /* Ideally this would be in a .h file, but it hardly seems worth the trouble */
71 extern const char *select_default_timezone(const char *share_path);
72 
73 static const char *auth_methods_host[] = {"trust", "reject", "md5", "password", "ident", "radius",
74 #ifdef ENABLE_GSS
75  "gss",
76 #endif
77 #ifdef ENABLE_SSPI
78  "sspi",
79 #endif
80 #ifdef USE_PAM
81  "pam", "pam ",
82 #endif
83 #ifdef USE_LDAP
84  "ldap",
85 #endif
86 #ifdef USE_SSL
87  "cert",
88 #endif
89 NULL};
90 static const char *auth_methods_local[] = {"trust", "reject", "md5", "password", "peer", "radius",
91 #ifdef USE_PAM
92  "pam", "pam ",
93 #endif
94 #ifdef USE_LDAP
95  "ldap",
96 #endif
97 NULL};
98 
99 /*
100  * these values are passed in by makefile defines
101  */
102 static char *share_path = NULL;
103 
104 /* values to be obtained from arguments */
105 static char *pg_data = "";
106 static char *encoding = "";
107 static char *locale = "";
108 static char *lc_collate = "";
109 static char *lc_ctype = "";
110 static char *lc_monetary = "";
111 static char *lc_numeric = "";
112 static char *lc_time = "";
113 static char *lc_messages = "";
114 static const char *default_text_search_config = "";
115 static char *username = "";
116 static bool pwprompt = false;
117 static char *pwfilename = NULL;
118 static const char *authmethodhost = "";
119 static const char *authmethodlocal = "";
120 static bool debug = false;
121 static bool noclean = false;
122 static bool do_sync = true;
123 static bool sync_only = false;
124 static bool show_setting = false;
125 static bool data_checksums = false;
126 static char *xlog_dir = "";
127 
128 
129 /* internal vars */
130 static const char *progname;
131 static char *encodingid = "0";
132 static char *bki_file;
133 static char *desc_file;
134 static char *shdesc_file;
135 static char *hba_file;
136 static char *ident_file;
137 static char *conf_file;
138 static char *conversion_file;
139 static char *dictionary_file;
140 static char *info_schema_file;
141 static char *features_file;
142 static char *system_views_file;
143 static bool made_new_pgdata = false;
144 static bool found_existing_pgdata = false;
145 static bool made_new_xlogdir = false;
146 static bool found_existing_xlogdir = false;
147 static char infoversion[100];
148 static bool caught_signal = false;
149 static bool output_failed = false;
150 static int output_errno = 0;
151 static char *pgdata_native;
152 
153 /* defaults */
154 static int n_connections = 10;
155 static int n_buffers = 50;
157 
158 /*
159  * Warning messages for authentication methods
160  */
161 #define AUTHTRUST_WARNING \
162 "# CAUTION: Configuring the system for local \"trust\" authentication\n" \
163 "# allows any local user to connect as any PostgreSQL user, including\n" \
164 "# the database superuser. If you do not trust all your local users,\n" \
165 "# use another authentication method.\n"
166 static char *authwarning = NULL;
167 
168 /*
169  * Centralized knowledge of switches to pass to backend
170  *
171  * Note: we run the backend with -F (fsync disabled) and then do a single
172  * pass of fsync'ing at the end. This is faster than fsync'ing each step.
173  *
174  * Note: in the shell-script version, we also passed PGDATA as a -D switch,
175  * but here it is more convenient to pass it as an environment variable
176  * (no quoting to worry about).
177  */
178 static const char *boot_options = "-F";
179 static const char *backend_options = "--single -F -O -c search_path=pg_catalog -c exit_on_error=true";
180 
181 #ifdef WIN32
182 char *restrict_env;
183 #endif
184 static const char *subdirs[] = {
185  "global",
186  "pg_xlog",
187  "pg_xlog/archive_status",
188  "pg_clog",
189  "pg_commit_ts",
190  "pg_dynshmem",
191  "pg_notify",
192  "pg_serial",
193  "pg_snapshots",
194  "pg_subtrans",
195  "pg_twophase",
196  "pg_multixact/members",
197  "pg_multixact/offsets",
198  "base",
199  "base/1",
200  "pg_replslot",
201  "pg_tblspc",
202  "pg_stat",
203  "pg_stat_tmp",
204  "pg_logical",
205  "pg_logical/snapshots",
206  "pg_logical/mappings"
207 };
208 
209 
210 /* path to 'initdb' binary directory */
211 static char bin_path[MAXPGPATH];
212 static char backend_exec[MAXPGPATH];
213 
214 static char **replace_token(char **lines,
215  const char *token, const char *replacement);
216 
217 #ifndef HAVE_UNIX_SOCKETS
218 static char **filter_lines_with_token(char **lines, const char *token);
219 #endif
220 static char **readfile(const char *path);
221 static void writefile(char *path, char **lines);
222 static void walkdir(char *path, void (*action) (char *fname, bool isdir));
223 static void walktblspc_links(char *path, void (*action) (char *fname, bool isdir));
224 static void pre_sync_fname(char *fname, bool isdir);
225 static void fsync_fname(char *fname, bool isdir);
226 static FILE *popen_check(const char *command, const char *mode);
227 static void exit_nicely(void);
228 static char *get_id(void);
229 static char *get_encoding_id(char *encoding_name);
230 static bool mkdatadir(const char *subdir);
231 static void set_input(char **dest, char *filename);
232 static void check_input(char *path);
233 static void write_version_file(char *extrapath);
234 static void set_null_conf(void);
235 static void test_config_settings(void);
236 static void setup_config(void);
237 static void bootstrap_template1(void);
238 static void setup_auth(void);
239 static void get_set_pwd(void);
240 static void setup_depend(void);
241 static void setup_sysviews(void);
242 static void setup_description(void);
243 static void setup_collation(void);
244 static void setup_conversion(void);
245 static void setup_dictionary(void);
246 static void setup_privileges(void);
247 static void set_info_version(void);
248 static void setup_schema(void);
249 static void load_plpgsql(void);
250 static void vacuum_db(void);
251 static void make_template0(void);
252 static void make_postgres(void);
253 static void perform_fsync(void);
254 static void trapsig(int signum);
255 static void check_ok(void);
256 static char *escape_quotes(const char *src);
257 static int locale_date_order(const char *locale);
258 static void check_locale_name(int category, const char *locale,
259  char **canonname);
260 static bool check_locale_encoding(const char *locale, int encoding);
261 static void setlocales(void);
262 static void usage(const char *progname);
263 void get_restricted_token(void);
264 void setup_pgdata(void);
265 void setup_bin_paths(const char *argv0);
266 void setup_data_file_paths(void);
267 void setup_locale_encoding(void);
268 void setup_signals(void);
269 void setup_text_search(void);
270 void create_data_directory(void);
271 void create_xlog_symlink(void);
272 void warn_on_mount_point(int error);
273 void initialize_data_directory(void);
274 
275 
276 #ifdef WIN32
277 static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo);
278 #endif
279 
280 
281 /*
282  * macros for running pipes to postgres
283  */
284 #define PG_CMD_DECL char cmd[MAXPGPATH]; FILE *cmdfd
285 
286 #define PG_CMD_OPEN \
287 do { \
288  cmdfd = popen_check(cmd, "w"); \
289  if (cmdfd == NULL) \
290  exit_nicely(); /* message already printed by popen_check */ \
291 } while (0)
292 
293 #define PG_CMD_CLOSE \
294 do { \
295  if (pclose_check(cmdfd)) \
296  exit_nicely(); /* message already printed by pclose_check */ \
297 } while (0)
298 
299 #define PG_CMD_PUTS(line) \
300 do { \
301  if (fputs(line, cmdfd) < 0 || fflush(cmdfd) < 0) \
302  output_failed = true, output_errno = errno; \
303 } while (0)
304 
305 #define PG_CMD_PRINTF1(fmt, arg1) \
306 do { \
307  if (fprintf(cmdfd, fmt, arg1) < 0 || fflush(cmdfd) < 0) \
308  output_failed = true, output_errno = errno; \
309 } while (0)
310 
311 #define PG_CMD_PRINTF2(fmt, arg1, arg2) \
312 do { \
313  if (fprintf(cmdfd, fmt, arg1, arg2) < 0 || fflush(cmdfd) < 0) \
314  output_failed = true, output_errno = errno; \
315 } while (0)
316 
317 #define PG_CMD_PRINTF3(fmt, arg1, arg2, arg3) \
318 do { \
319  if (fprintf(cmdfd, fmt, arg1, arg2, arg3) < 0 || fflush(cmdfd) < 0) \
320  output_failed = true, output_errno = errno; \
321 } while (0)
322 
323 #ifndef WIN32
324 #define QUOTE_PATH ""
325 #define DIR_SEP "/"
326 #else
327 #define QUOTE_PATH "\""
328 #define DIR_SEP "\\"
329 #endif
330 
331 static char *
332 escape_quotes(const char *src)
333 {
334  char *result = escape_single_quotes_ascii(src);
335 
336  if (!result)
337  {
338  fprintf(stderr, _("%s: out of memory\n"), progname);
339  exit(1);
340  }
341  return result;
342 }
343 
344 /*
345  * make a copy of the array of lines, with token replaced by replacement
346  * the first time it occurs on each line.
347  *
348  * This does most of what sed was used for in the shell script, but
349  * doesn't need any regexp stuff.
350  */
351 static char **
352 replace_token(char **lines, const char *token, const char *replacement)
353 {
354  int numlines = 1;
355  int i;
356  char **result;
357  int toklen,
358  replen,
359  diff;
360 
361  for (i = 0; lines[i]; i++)
362  numlines++;
363 
364  result = (char **) pg_malloc(numlines * sizeof(char *));
365 
366  toklen = strlen(token);
367  replen = strlen(replacement);
368  diff = replen - toklen;
369 
370  for (i = 0; i < numlines; i++)
371  {
372  char *where;
373  char *newline;
374  int pre;
375 
376  /* just copy pointer if NULL or no change needed */
377  if (lines[i] == NULL || (where = strstr(lines[i], token)) == NULL)
378  {
379  result[i] = lines[i];
380  continue;
381  }
382 
383  /* if we get here a change is needed - set up new line */
384 
385  newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1);
386 
387  pre = where - lines[i];
388 
389  strncpy(newline, lines[i], pre);
390 
391  strcpy(newline + pre, replacement);
392 
393  strcpy(newline + pre + replen, lines[i] + pre + toklen);
394 
395  result[i] = newline;
396  }
397 
398  return result;
399 }
400 
401 /*
402  * make a copy of lines without any that contain the token
403  *
404  * a sort of poor man's grep -v
405  */
406 #ifndef HAVE_UNIX_SOCKETS
407 static char **
408 filter_lines_with_token(char **lines, const char *token)
409 {
410  int numlines = 1;
411  int i,
412  src,
413  dst;
414  char **result;
415 
416  for (i = 0; lines[i]; i++)
417  numlines++;
418 
419  result = (char **) pg_malloc(numlines * sizeof(char *));
420 
421  for (src = 0, dst = 0; src < numlines; src++)
422  {
423  if (lines[src] == NULL || strstr(lines[src], token) == NULL)
424  result[dst++] = lines[src];
425  }
426 
427  return result;
428 }
429 #endif
430 
431 /*
432  * get the lines from a text file
433  */
434 static char **
435 readfile(const char *path)
436 {
437  FILE *infile;
438  int maxlength = 1,
439  linelen = 0;
440  int nlines = 0;
441  int n;
442  char **result;
443  char *buffer;
444  int c;
445 
446  if ((infile = fopen(path, "r")) == NULL)
447  {
448  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
449  progname, path, strerror(errno));
450  exit_nicely();
451  }
452 
453  /* pass over the file twice - the first time to size the result */
454 
455  while ((c = fgetc(infile)) != EOF)
456  {
457  linelen++;
458  if (c == '\n')
459  {
460  nlines++;
461  if (linelen > maxlength)
462  maxlength = linelen;
463  linelen = 0;
464  }
465  }
466 
467  /* handle last line without a terminating newline (yuck) */
468  if (linelen)
469  nlines++;
470  if (linelen > maxlength)
471  maxlength = linelen;
472 
473  /* set up the result and the line buffer */
474  result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
475  buffer = (char *) pg_malloc(maxlength + 1);
476 
477  /* now reprocess the file and store the lines */
478  rewind(infile);
479  n = 0;
480  while (fgets(buffer, maxlength + 1, infile) != NULL && n < nlines)
481  result[n++] = pg_strdup(buffer);
482 
483  fclose(infile);
484  free(buffer);
485  result[n] = NULL;
486 
487  return result;
488 }
489 
490 /*
491  * write an array of lines to a file
492  *
493  * This is only used to write text files. Use fopen "w" not PG_BINARY_W
494  * so that the resulting configuration files are nicely editable on Windows.
495  */
496 static void
497 writefile(char *path, char **lines)
498 {
499  FILE *out_file;
500  char **line;
501 
502  if ((out_file = fopen(path, "w")) == NULL)
503  {
504  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
505  progname, path, strerror(errno));
506  exit_nicely();
507  }
508  for (line = lines; *line != NULL; line++)
509  {
510  if (fputs(*line, out_file) < 0)
511  {
512  fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
513  progname, path, strerror(errno));
514  exit_nicely();
515  }
516  free(*line);
517  }
518  if (fclose(out_file))
519  {
520  fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
521  progname, path, strerror(errno));
522  exit_nicely();
523  }
524 }
525 
526 /*
527  * walkdir: recursively walk a directory, applying the action to each
528  * regular file and directory (including the named directory itself).
529  *
530  * Adapted from copydir() in copydir.c.
531  */
532 static void
533 walkdir(char *path, void (*action) (char *fname, bool isdir))
534 {
535  DIR *dir;
536  struct dirent *direntry;
537  char subpath[MAXPGPATH];
538 
539  dir = opendir(path);
540  if (dir == NULL)
541  {
542  fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
543  progname, path, strerror(errno));
544  exit_nicely();
545  }
546 
547  while (errno = 0, (direntry = readdir(dir)) != NULL)
548  {
549  struct stat fst;
550 
551  if (strcmp(direntry->d_name, ".") == 0 ||
552  strcmp(direntry->d_name, "..") == 0)
553  continue;
554 
555  snprintf(subpath, MAXPGPATH, "%s/%s", path, direntry->d_name);
556 
557  if (lstat(subpath, &fst) < 0)
558  {
559  fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"),
560  progname, subpath, strerror(errno));
561  exit_nicely();
562  }
563 
564  if (S_ISDIR(fst.st_mode))
565  walkdir(subpath, action);
566  else if (S_ISREG(fst.st_mode))
567  (*action) (subpath, false);
568  }
569 
570  if (errno)
571  {
572  fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
573  progname, path, strerror(errno));
574  exit_nicely();
575  }
576 
577  if (closedir(dir))
578  {
579  fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
580  progname, path, strerror(errno));
581  exit_nicely();
582  }
583 
584  /*
585  * It's important to fsync the destination directory itself as individual
586  * file fsyncs don't guarantee that the directory entry for the file is
587  * synced. Recent versions of ext4 have made the window much wider but
588  * it's been an issue for ext3 and other filesystems in the past.
589  */
590  (*action) (path, true);
591 }
592 
593 /*
594  * walktblspc_links: call walkdir on each entry under the given
595  * pg_tblspc directory, or do nothing if pg_tblspc doesn't exist.
596  */
597 static void
598 walktblspc_links(char *path, void (*action) (char *fname, bool isdir))
599 {
600  DIR *dir;
601  struct dirent *direntry;
602  char subpath[MAXPGPATH];
603 
604  dir = opendir(path);
605  if (dir == NULL)
606  {
607  if (errno == ENOENT)
608  return;
609  fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
610  progname, path, strerror(errno));
611  exit_nicely();
612  }
613 
614  while (errno = 0, (direntry = readdir(dir)) != NULL)
615  {
616  if (strcmp(direntry->d_name, ".") == 0 ||
617  strcmp(direntry->d_name, "..") == 0)
618  continue;
619 
620  /* fsync the version specific tablespace subdirectory */
621  snprintf(subpath, sizeof(subpath), "%s/%s/%s",
622  path, direntry->d_name, TABLESPACE_VERSION_DIRECTORY);
623 
624  walkdir(subpath, action);
625  }
626 
627  if (errno)
628  {
629  fprintf(stderr, _("%s: could not read directory \"%s\": %s\n"),
630  progname, path, strerror(errno));
631  exit_nicely();
632  }
633 
634  if (closedir(dir))
635  {
636  fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
637  progname, path, strerror(errno));
638  exit_nicely();
639  }
640 }
641 
642 /*
643  * Hint to the OS that it should get ready to fsync() this file.
644  */
645 static void
646 pre_sync_fname(char *fname, bool isdir)
647 {
648 #if defined(HAVE_SYNC_FILE_RANGE) || \
649  (defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED))
650  int fd;
651 
652  fd = open(fname, O_RDONLY | PG_BINARY);
653 
654  /*
655  * Some OSs don't allow us to open directories at all (Windows returns
656  * EACCES)
657  */
658  if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES))
659  return;
660 
661  if (fd < 0)
662  {
663  fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
664  progname, fname, strerror(errno));
665  exit_nicely();
666  }
667 
668  /*
669  * Prefer sync_file_range, else use posix_fadvise. We ignore any error
670  * here since this operation is only a hint anyway.
671  */
672 #if defined(HAVE_SYNC_FILE_RANGE)
673  sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WRITE);
674 #elif defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
675  posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
676 #endif
677 
678  close(fd);
679 #endif
680 }
681 
682 /*
683  * fsync a file or directory
684  *
685  * Try to fsync directories but ignore errors that indicate the OS
686  * just doesn't allow/require fsyncing directories.
687  *
688  * Adapted from fsync_fname() in copydir.c.
689  */
690 static void
691 fsync_fname(char *fname, bool isdir)
692 {
693  int fd;
694  int returncode;
695 
696  /*
697  * Some OSs require directories to be opened read-only whereas other
698  * systems don't allow us to fsync files opened read-only; so we need both
699  * cases here
700  */
701  if (!isdir)
702  fd = open(fname, O_RDWR | PG_BINARY);
703  else
704  fd = open(fname, O_RDONLY | PG_BINARY);
705 
706  /*
707  * Some OSs don't allow us to open directories at all (Windows returns
708  * EACCES)
709  */
710  if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES))
711  return;
712 
713  else if (fd < 0)
714  {
715  fprintf(stderr, _("%s: could not open file \"%s\": %s\n"),
716  progname, fname, strerror(errno));
717  exit_nicely();
718  }
719 
720  returncode = fsync(fd);
721 
722  /* Some OSs don't allow us to fsync directories at all */
723  if (returncode != 0 && isdir && errno == EBADF)
724  {
725  close(fd);
726  return;
727  }
728 
729  if (returncode != 0)
730  {
731  fprintf(stderr, _("%s: could not fsync file \"%s\": %s\n"),
732  progname, fname, strerror(errno));
733  exit_nicely();
734  }
735 
736  close(fd);
737 }
738 
739 /*
740  * Open a subcommand with suitable error messaging
741  */
742 static FILE *
743 popen_check(const char *command, const char *mode)
744 {
745  FILE *cmdfd;
746 
747  fflush(stdout);
748  fflush(stderr);
749  errno = 0;
750  cmdfd = popen(command, mode);
751  if (cmdfd == NULL)
752  fprintf(stderr, _("%s: could not execute command \"%s\": %s\n"),
753  progname, command, strerror(errno));
754  return cmdfd;
755 }
756 
757 /*
758  * clean up any files we created on failure
759  * if we created the data directory remove it too
760  */
761 static void
763 {
764  if (!noclean)
765  {
766  if (made_new_pgdata)
767  {
768  fprintf(stderr, _("%s: removing data directory \"%s\"\n"),
769  progname, pg_data);
770  if (!rmtree(pg_data, true))
771  fprintf(stderr, _("%s: failed to remove data directory\n"),
772  progname);
773  }
774  else if (found_existing_pgdata)
775  {
776  fprintf(stderr,
777  _("%s: removing contents of data directory \"%s\"\n"),
778  progname, pg_data);
779  if (!rmtree(pg_data, false))
780  fprintf(stderr, _("%s: failed to remove contents of data directory\n"),
781  progname);
782  }
783 
784  if (made_new_xlogdir)
785  {
786  fprintf(stderr, _("%s: removing transaction log directory \"%s\"\n"),
787  progname, xlog_dir);
788  if (!rmtree(xlog_dir, true))
789  fprintf(stderr, _("%s: failed to remove transaction log directory\n"),
790  progname);
791  }
792  else if (found_existing_xlogdir)
793  {
794  fprintf(stderr,
795  _("%s: removing contents of transaction log directory \"%s\"\n"),
796  progname, xlog_dir);
797  if (!rmtree(xlog_dir, false))
798  fprintf(stderr, _("%s: failed to remove contents of transaction log directory\n"),
799  progname);
800  }
801  /* otherwise died during startup, do nothing! */
802  }
803  else
804  {
806  fprintf(stderr,
807  _("%s: data directory \"%s\" not removed at user's request\n"),
808  progname, pg_data);
809 
811  fprintf(stderr,
812  _("%s: transaction log directory \"%s\" not removed at user's request\n"),
813  progname, xlog_dir);
814  }
815 
816  exit(1);
817 }
818 
819 /*
820  * find the current user
821  *
822  * on unix make sure it isn't root
823  */
824 static char *
825 get_id(void)
826 {
827  const char *username;
828 
829 #ifndef WIN32
830  if (geteuid() == 0) /* 0 is root's uid */
831  {
832  fprintf(stderr,
833  _("%s: cannot be run as root\n"
834  "Please log in (using, e.g., \"su\") as the "
835  "(unprivileged) user that will\n"
836  "own the server process.\n"),
837  progname);
838  exit(1);
839  }
840 #endif
841 
842  username = get_user_name_or_exit(progname);
843 
844  return pg_strdup(username);
845 }
846 
847 static char *
849 {
850  char result[20];
851 
852  sprintf(result, "%d", enc);
853  return pg_strdup(result);
854 }
855 
856 /*
857  * get the encoding id for a given encoding name
858  */
859 static char *
860 get_encoding_id(char *encoding_name)
861 {
862  int enc;
863 
864  if (encoding_name && *encoding_name)
865  {
866  if ((enc = pg_valid_server_encoding(encoding_name)) >= 0)
867  return encodingid_to_string(enc);
868  }
869  fprintf(stderr, _("%s: \"%s\" is not a valid server encoding name\n"),
870  progname, encoding_name ? encoding_name : "(null)");
871  exit(1);
872 }
873 
874 /*
875  * Support for determining the best default text search configuration.
876  * We key this off the first part of LC_CTYPE (ie, the language name).
877  */
879 {
880  const char *tsconfname;
881  const char *langname;
882 };
883 
885 {
886  {"danish", "da"},
887  {"danish", "Danish"},
888  {"dutch", "nl"},
889  {"dutch", "Dutch"},
890  {"english", "C"},
891  {"english", "POSIX"},
892  {"english", "en"},
893  {"english", "English"},
894  {"finnish", "fi"},
895  {"finnish", "Finnish"},
896  {"french", "fr"},
897  {"french", "French"},
898  {"german", "de"},
899  {"german", "German"},
900  {"hungarian", "hu"},
901  {"hungarian", "Hungarian"},
902  {"italian", "it"},
903  {"italian", "Italian"},
904  {"norwegian", "no"},
905  {"norwegian", "Norwegian"},
906  {"portuguese", "pt"},
907  {"portuguese", "Portuguese"},
908  {"romanian", "ro"},
909  {"russian", "ru"},
910  {"russian", "Russian"},
911  {"spanish", "es"},
912  {"spanish", "Spanish"},
913  {"swedish", "sv"},
914  {"swedish", "Swedish"},
915  {"turkish", "tr"},
916  {"turkish", "Turkish"},
917  {NULL, NULL} /* end marker */
918 };
919 
920 /*
921  * Look for a text search configuration matching lc_ctype, and return its
922  * name; return NULL if no match.
923  */
924 static const char *
925 find_matching_ts_config(const char *lc_type)
926 {
927  int i;
928  char *langname,
929  *ptr;
930 
931  /*
932  * Convert lc_ctype to a language name by stripping everything after an
933  * underscore (usual case) or a hyphen (Windows "locale name"; see
934  * comments at IsoLocaleName()).
935  *
936  * XXX Should ' ' be a stop character? This would select "norwegian" for
937  * the Windows locale "Norwegian (Nynorsk)_Norway.1252". If we do so, we
938  * should also accept the "nn" and "nb" Unix locales.
939  *
940  * Just for paranoia, we also stop at '.' or '@'.
941  */
942  if (lc_type == NULL)
943  langname = pg_strdup("");
944  else
945  {
946  ptr = langname = pg_strdup(lc_type);
947  while (*ptr &&
948  *ptr != '_' && *ptr != '-' && *ptr != '.' && *ptr != '@')
949  ptr++;
950  *ptr = '\0';
951  }
952 
953  for (i = 0; tsearch_config_languages[i].tsconfname; i++)
954  {
955  if (pg_strcasecmp(tsearch_config_languages[i].langname, langname) == 0)
956  {
957  free(langname);
958  return tsearch_config_languages[i].tsconfname;
959  }
960  }
961 
962  free(langname);
963  return NULL;
964 }
965 
966 
967 /*
968  * make the data directory (or one of its subdirectories if subdir is not NULL)
969  */
970 static bool
971 mkdatadir(const char *subdir)
972 {
973  char *path;
974 
975  if (subdir)
976  path = psprintf("%s/%s", pg_data, subdir);
977  else
978  path = pg_strdup(pg_data);
979 
980  if (pg_mkdir_p(path, S_IRWXU) == 0)
981  return true;
982 
983  fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
984  progname, path, strerror(errno));
985 
986  return false;
987 }
988 
989 
990 /*
991  * set name of given input file variable under data directory
992  */
993 static void
994 set_input(char **dest, char *filename)
995 {
996  *dest = psprintf("%s/%s", share_path, filename);
997 }
998 
999 /*
1000  * check that given input file exists
1001  */
1002 static void
1003 check_input(char *path)
1004 {
1005  struct stat statbuf;
1006 
1007  if (stat(path, &statbuf) != 0)
1008  {
1009  if (errno == ENOENT)
1010  {
1011  fprintf(stderr,
1012  _("%s: file \"%s\" does not exist\n"), progname, path);
1013  fprintf(stderr,
1014  _("This might mean you have a corrupted installation or identified\n"
1015  "the wrong directory with the invocation option -L.\n"));
1016  }
1017  else
1018  {
1019  fprintf(stderr,
1020  _("%s: could not access file \"%s\": %s\n"), progname, path,
1021  strerror(errno));
1022  fprintf(stderr,
1023  _("This might mean you have a corrupted installation or identified\n"
1024  "the wrong directory with the invocation option -L.\n"));
1025  }
1026  exit(1);
1027  }
1028  if (!S_ISREG(statbuf.st_mode))
1029  {
1030  fprintf(stderr,
1031  _("%s: file \"%s\" is not a regular file\n"), progname, path);
1032  fprintf(stderr,
1033  _("This might mean you have a corrupted installation or identified\n"
1034  "the wrong directory with the invocation option -L.\n"));
1035  exit(1);
1036  }
1037 }
1038 
1039 /*
1040  * write out the PG_VERSION file in the data dir, or its subdirectory
1041  * if extrapath is not NULL
1042  */
1043 static void
1044 write_version_file(char *extrapath)
1045 {
1046  FILE *version_file;
1047  char *path;
1048 
1049  if (extrapath == NULL)
1050  path = psprintf("%s/PG_VERSION", pg_data);
1051  else
1052  path = psprintf("%s/%s/PG_VERSION", pg_data, extrapath);
1053 
1054  if ((version_file = fopen(path, PG_BINARY_W)) == NULL)
1055  {
1056  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1057  progname, path, strerror(errno));
1058  exit_nicely();
1059  }
1060  if (fprintf(version_file, "%s\n", PG_MAJORVERSION) < 0 ||
1061  fclose(version_file))
1062  {
1063  fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
1064  progname, path, strerror(errno));
1065  exit_nicely();
1066  }
1067  free(path);
1068 }
1069 
1070 /*
1071  * set up an empty config file so we can check config settings by launching
1072  * a test backend
1073  */
1074 static void
1076 {
1077  FILE *conf_file;
1078  char *path;
1079 
1080  path = psprintf("%s/postgresql.conf", pg_data);
1081  conf_file = fopen(path, PG_BINARY_W);
1082  if (conf_file == NULL)
1083  {
1084  fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
1085  progname, path, strerror(errno));
1086  exit_nicely();
1087  }
1088  if (fclose(conf_file))
1089  {
1090  fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
1091  progname, path, strerror(errno));
1092  exit_nicely();
1093  }
1094  free(path);
1095 }
1096 
1097 /*
1098  * Determine which dynamic shared memory implementation should be used on
1099  * this platform. POSIX shared memory is preferable because the default
1100  * allocation limits are much higher than the limits for System V on most
1101  * systems that support both, but the fact that a platform has shm_open
1102  * doesn't guarantee that that call will succeed when attempted. So, we
1103  * attempt to reproduce what the postmaster will do when allocating a POSIX
1104  * segment in dsm_impl.c; if it doesn't work, we assume it won't work for
1105  * the postmaster either, and configure the cluster for System V shared
1106  * memory instead.
1107  */
1108 static char *
1110 {
1111 #ifdef HAVE_SHM_OPEN
1112  int ntries = 10;
1113 
1114  while (ntries > 0)
1115  {
1116  uint32 handle;
1117  char name[64];
1118  int fd;
1119 
1120  handle = random();
1121  snprintf(name, 64, "/PostgreSQL.%u", handle);
1122  if ((fd = shm_open(name, O_CREAT | O_RDWR | O_EXCL, 0600)) != -1)
1123  {
1124  close(fd);
1125  shm_unlink(name);
1126  return "posix";
1127  }
1128  if (errno != EEXIST)
1129  break;
1130  --ntries;
1131  }
1132 #endif
1133 
1134 #ifdef WIN32
1135  return "windows";
1136 #else
1137  return "sysv";
1138 #endif
1139 }
1140 
1141 /*
1142  * Determine platform-specific config settings
1143  *
1144  * Use reasonable values if kernel will let us, else scale back. Probe
1145  * for max_connections first since it is subject to more constraints than
1146  * shared_buffers.
1147  */
1148 static void
1150 {
1151  /*
1152  * This macro defines the minimum shared_buffers we want for a given
1153  * max_connections value. The arrays show the settings to try.
1154  */
1155 #define MIN_BUFS_FOR_CONNS(nconns) ((nconns) * 10)
1156 
1157  static const int trial_conns[] = {
1158  100, 50, 40, 30, 20, 10
1159  };
1160  static const int trial_bufs[] = {
1161  16384, 8192, 4096, 3584, 3072, 2560, 2048, 1536,
1162  1000, 900, 800, 700, 600, 500,
1163  400, 300, 200, 100, 50
1164  };
1165 
1166  char cmd[MAXPGPATH];
1167  const int connslen = sizeof(trial_conns) / sizeof(int);
1168  const int bufslen = sizeof(trial_bufs) / sizeof(int);
1169  int i,
1170  status,
1171  test_conns,
1172  test_buffs,
1173  ok_buffers = 0;
1174 
1175 
1176  printf(_("selecting default max_connections ... "));
1177  fflush(stdout);
1178 
1179  for (i = 0; i < connslen; i++)
1180  {
1181  test_conns = trial_conns[i];
1182  test_buffs = MIN_BUFS_FOR_CONNS(test_conns);
1183 
1184  snprintf(cmd, sizeof(cmd),
1185  "\"%s\" --boot -x0 %s "
1186  "-c max_connections=%d "
1187  "-c shared_buffers=%d "
1188  "-c dynamic_shared_memory_type=none "
1189  "< \"%s\" > \"%s\" 2>&1",
1191  test_conns, test_buffs,
1192  DEVNULL, DEVNULL);
1193  status = system(cmd);
1194  if (status == 0)
1195  {
1196  ok_buffers = test_buffs;
1197  break;
1198  }
1199  }
1200  if (i >= connslen)
1201  i = connslen - 1;
1202  n_connections = trial_conns[i];
1203 
1204  printf("%d\n", n_connections);
1205 
1206  printf(_("selecting default shared_buffers ... "));
1207  fflush(stdout);
1208 
1209  for (i = 0; i < bufslen; i++)
1210  {
1211  /* Use same amount of memory, independent of BLCKSZ */
1212  test_buffs = (trial_bufs[i] * 8192) / BLCKSZ;
1213  if (test_buffs <= ok_buffers)
1214  {
1215  test_buffs = ok_buffers;
1216  break;
1217  }
1218 
1219  snprintf(cmd, sizeof(cmd),
1220  "\"%s\" --boot -x0 %s "
1221  "-c max_connections=%d "
1222  "-c shared_buffers=%d "
1223  "-c dynamic_shared_memory_type=none "
1224  "< \"%s\" > \"%s\" 2>&1",
1226  n_connections, test_buffs,
1227  DEVNULL, DEVNULL);
1228  status = system(cmd);
1229  if (status == 0)
1230  break;
1231  }
1232  n_buffers = test_buffs;
1233 
1234  if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
1235  printf("%dMB\n", (n_buffers * (BLCKSZ / 1024)) / 1024);
1236  else
1237  printf("%dkB\n", n_buffers * (BLCKSZ / 1024));
1238 
1239  printf(_("selecting dynamic shared memory implementation ... "));
1240  fflush(stdout);
1242  printf("%s\n", dynamic_shared_memory_type);
1243 }
1244 
1245 /*
1246  * set up all the config files
1247  */
1248 static void
1250 {
1251  char **conflines;
1252  char repltok[MAXPGPATH];
1253  char path[MAXPGPATH];
1254  const char *default_timezone;
1255  char *autoconflines[3];
1256 
1257  fputs(_("creating configuration files ... "), stdout);
1258  fflush(stdout);
1259 
1260  /* postgresql.conf */
1261 
1262  conflines = readfile(conf_file);
1263 
1264  snprintf(repltok, sizeof(repltok), "max_connections = %d", n_connections);
1265  conflines = replace_token(conflines, "#max_connections = 100", repltok);
1266 
1267  if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
1268  snprintf(repltok, sizeof(repltok), "shared_buffers = %dMB",
1269  (n_buffers * (BLCKSZ / 1024)) / 1024);
1270  else
1271  snprintf(repltok, sizeof(repltok), "shared_buffers = %dkB",
1272  n_buffers * (BLCKSZ / 1024));
1273  conflines = replace_token(conflines, "#shared_buffers = 32MB", repltok);
1274 
1275 #ifdef HAVE_UNIX_SOCKETS
1276  snprintf(repltok, sizeof(repltok), "#unix_socket_directories = '%s'",
1278 #else
1279  snprintf(repltok, sizeof(repltok), "#unix_socket_directories = ''");
1280 #endif
1281  conflines = replace_token(conflines, "#unix_socket_directories = '/tmp'",
1282  repltok);
1283 
1284 #if DEF_PGPORT != 5432
1285  snprintf(repltok, sizeof(repltok), "#port = %d", DEF_PGPORT);
1286  conflines = replace_token(conflines, "#port = 5432", repltok);
1287 #endif
1288 
1289  snprintf(repltok, sizeof(repltok), "lc_messages = '%s'",
1291  conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
1292 
1293  snprintf(repltok, sizeof(repltok), "lc_monetary = '%s'",
1295  conflines = replace_token(conflines, "#lc_monetary = 'C'", repltok);
1296 
1297  snprintf(repltok, sizeof(repltok), "lc_numeric = '%s'",
1299  conflines = replace_token(conflines, "#lc_numeric = 'C'", repltok);
1300 
1301  snprintf(repltok, sizeof(repltok), "lc_time = '%s'",
1303  conflines = replace_token(conflines, "#lc_time = 'C'", repltok);
1304 
1305  switch (locale_date_order(lc_time))
1306  {
1307  case DATEORDER_YMD:
1308  strcpy(repltok, "datestyle = 'iso, ymd'");
1309  break;
1310  case DATEORDER_DMY:
1311  strcpy(repltok, "datestyle = 'iso, dmy'");
1312  break;
1313  case DATEORDER_MDY:
1314  default:
1315  strcpy(repltok, "datestyle = 'iso, mdy'");
1316  break;
1317  }
1318  conflines = replace_token(conflines, "#datestyle = 'iso, mdy'", repltok);
1319 
1320  snprintf(repltok, sizeof(repltok),
1321  "default_text_search_config = 'pg_catalog.%s'",
1323  conflines = replace_token(conflines,
1324  "#default_text_search_config = 'pg_catalog.simple'",
1325  repltok);
1326 
1327  default_timezone = select_default_timezone(share_path);
1328  if (default_timezone)
1329  {
1330  snprintf(repltok, sizeof(repltok), "timezone = '%s'",
1331  escape_quotes(default_timezone));
1332  conflines = replace_token(conflines, "#timezone = 'GMT'", repltok);
1333  snprintf(repltok, sizeof(repltok), "log_timezone = '%s'",
1334  escape_quotes(default_timezone));
1335  conflines = replace_token(conflines, "#log_timezone = 'GMT'", repltok);
1336  }
1337 
1338  snprintf(repltok, sizeof(repltok), "dynamic_shared_memory_type = %s",
1340  conflines = replace_token(conflines, "#dynamic_shared_memory_type = posix",
1341  repltok);
1342 
1343 #ifndef USE_PREFETCH
1344  conflines = replace_token(conflines,
1345  "#effective_io_concurrency = 1",
1346  "#effective_io_concurrency = 0");
1347 #endif
1348 
1349  snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
1350 
1351  writefile(path, conflines);
1352  if (chmod(path, S_IRUSR | S_IWUSR) != 0)
1353  {
1354  fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"),
1355  progname, path, strerror(errno));
1356  exit_nicely();
1357  }
1358 
1359  /*
1360  * create the automatic configuration file to store the configuration
1361  * parameters set by ALTER SYSTEM command. The parameters present in this
1362  * file will override the value of parameters that exists before parse of
1363  * this file.
1364  */
1365  autoconflines[0] = pg_strdup("# Do not edit this file manually!\n");
1366  autoconflines[1] = pg_strdup("# It will be overwritten by the ALTER SYSTEM command.\n");
1367  autoconflines[2] = NULL;
1368 
1369  sprintf(path, "%s/postgresql.auto.conf", pg_data);
1370 
1371  writefile(path, autoconflines);
1372  if (chmod(path, S_IRUSR | S_IWUSR) != 0)
1373  {
1374  fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"),
1375  progname, path, strerror(errno));
1376  exit_nicely();
1377  }
1378 
1379  free(conflines);
1380 
1381 
1382  /* pg_hba.conf */
1383 
1384  conflines = readfile(hba_file);
1385 
1386 #ifndef HAVE_UNIX_SOCKETS
1387  conflines = filter_lines_with_token(conflines, "@remove-line-for-nolocal@");
1388 #else
1389  conflines = replace_token(conflines, "@remove-line-for-nolocal@", "");
1390 #endif
1391 
1392 #ifdef HAVE_IPV6
1393 
1394  /*
1395  * Probe to see if there is really any platform support for IPv6, and
1396  * comment out the relevant pg_hba line if not. This avoids runtime
1397  * warnings if getaddrinfo doesn't actually cope with IPv6. Particularly
1398  * useful on Windows, where executables built on a machine with IPv6 may
1399  * have to run on a machine without.
1400  */
1401  {
1402  struct addrinfo *gai_result;
1403  struct addrinfo hints;
1404  int err = 0;
1405 
1406 #ifdef WIN32
1407  /* need to call WSAStartup before calling getaddrinfo */
1408  WSADATA wsaData;
1409 
1410  err = WSAStartup(MAKEWORD(2, 2), &wsaData);
1411 #endif
1412 
1413  /* for best results, this code should match parse_hba() */
1414  hints.ai_flags = AI_NUMERICHOST;
1415  hints.ai_family = AF_UNSPEC;
1416  hints.ai_socktype = 0;
1417  hints.ai_protocol = 0;
1418  hints.ai_addrlen = 0;
1419  hints.ai_canonname = NULL;
1420  hints.ai_addr = NULL;
1421  hints.ai_next = NULL;
1422 
1423  if (err != 0 ||
1424  getaddrinfo("::1", NULL, &hints, &gai_result) != 0)
1425  conflines = replace_token(conflines,
1426  "host all all ::1",
1427  "#host all all ::1");
1428  }
1429 #else /* !HAVE_IPV6 */
1430  /* If we didn't compile IPV6 support at all, always comment it out */
1431  conflines = replace_token(conflines,
1432  "host all all ::1",
1433  "#host all all ::1");
1434 #endif /* HAVE_IPV6 */
1435 
1436  /* Replace default authentication methods */
1437  conflines = replace_token(conflines,
1438  "@authmethodhost@",
1439  authmethodhost);
1440  conflines = replace_token(conflines,
1441  "@authmethodlocal@",
1442  authmethodlocal);
1443 
1444  conflines = replace_token(conflines,
1445  "@authcomment@",
1446  (strcmp(authmethodlocal, "trust") == 0 || strcmp(authmethodhost, "trust") == 0) ? AUTHTRUST_WARNING : "");
1447 
1448  /* Replace username for replication */
1449  conflines = replace_token(conflines,
1450  "@default_username@",
1451  username);
1452 
1453  snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data);
1454 
1455  writefile(path, conflines);
1456  if (chmod(path, S_IRUSR | S_IWUSR) != 0)
1457  {
1458  fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"),
1459  progname, path, strerror(errno));
1460  exit_nicely();
1461  }
1462 
1463  free(conflines);
1464 
1465  /* pg_ident.conf */
1466 
1467  conflines = readfile(ident_file);
1468 
1469  snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data);
1470 
1471  writefile(path, conflines);
1472  if (chmod(path, S_IRUSR | S_IWUSR) != 0)
1473  {
1474  fprintf(stderr, _("%s: could not change permissions of \"%s\": %s\n"),
1475  progname, path, strerror(errno));
1476  exit_nicely();
1477  }
1478 
1479  free(conflines);
1480 
1481  check_ok();
1482 }
1483 
1484 
1485 /*
1486  * run the BKI script in bootstrap mode to create template1
1487  */
1488 static void
1490 {
1491  PG_CMD_DECL;
1492  char **line;
1493  char *talkargs = "";
1494  char **bki_lines;
1495  char headerline[MAXPGPATH];
1496  char buf[64];
1497 
1498  printf(_("creating template1 database in %s/base/1 ... "), pg_data);
1499  fflush(stdout);
1500 
1501  if (debug)
1502  talkargs = "-d 5";
1503 
1504  bki_lines = readfile(bki_file);
1505 
1506  /* Check that bki file appears to be of the right version */
1507 
1508  snprintf(headerline, sizeof(headerline), "# PostgreSQL %s\n",
1509  PG_MAJORVERSION);
1510 
1511  if (strcmp(headerline, *bki_lines) != 0)
1512  {
1513  fprintf(stderr,
1514  _("%s: input file \"%s\" does not belong to PostgreSQL %s\n"
1515  "Check your installation or specify the correct path "
1516  "using the option -L.\n"),
1517  progname, bki_file, PG_VERSION);
1518  exit_nicely();
1519  }
1520 
1521  /* Substitute for various symbols used in the BKI file */
1522 
1523  sprintf(buf, "%d", NAMEDATALEN);
1524  bki_lines = replace_token(bki_lines, "NAMEDATALEN", buf);
1525 
1526  sprintf(buf, "%d", (int) sizeof(Pointer));
1527  bki_lines = replace_token(bki_lines, "SIZEOF_POINTER", buf);
1528 
1529  bki_lines = replace_token(bki_lines, "ALIGNOF_POINTER",
1530  (sizeof(Pointer) == 4) ? "i" : "d");
1531 
1532  bki_lines = replace_token(bki_lines, "FLOAT4PASSBYVAL",
1533  FLOAT4PASSBYVAL ? "true" : "false");
1534 
1535  bki_lines = replace_token(bki_lines, "FLOAT8PASSBYVAL",
1536  FLOAT8PASSBYVAL ? "true" : "false");
1537 
1538  bki_lines = replace_token(bki_lines, "POSTGRES", escape_quotes(username));
1539 
1540  bki_lines = replace_token(bki_lines, "ENCODING", encodingid);
1541 
1542  bki_lines = replace_token(bki_lines, "LC_COLLATE", escape_quotes(lc_collate));
1543 
1544  bki_lines = replace_token(bki_lines, "LC_CTYPE", escape_quotes(lc_ctype));
1545 
1546  /*
1547  * Pass correct LC_xxx environment to bootstrap.
1548  *
1549  * The shell script arranged to restore the LC settings afterwards, but
1550  * there doesn't seem to be any compelling reason to do that.
1551  */
1552  snprintf(cmd, sizeof(cmd), "LC_COLLATE=%s", lc_collate);
1553  putenv(pg_strdup(cmd));
1554 
1555  snprintf(cmd, sizeof(cmd), "LC_CTYPE=%s", lc_ctype);
1556  putenv(pg_strdup(cmd));
1557 
1558  unsetenv("LC_ALL");
1559 
1560  /* Also ensure backend isn't confused by this environment var: */
1561  unsetenv("PGCLIENTENCODING");
1562 
1563  snprintf(cmd, sizeof(cmd),
1564  "\"%s\" --boot -x1 %s %s %s",
1565  backend_exec,
1566  data_checksums ? "-k" : "",
1567  boot_options, talkargs);
1568 
1569  PG_CMD_OPEN;
1570 
1571  for (line = bki_lines; *line != NULL; line++)
1572  {
1573  PG_CMD_PUTS(*line);
1574  free(*line);
1575  }
1576 
1577  PG_CMD_CLOSE;
1578 
1579  free(bki_lines);
1580 
1581  check_ok();
1582 }
1583 
1584 /*
1585  * set up the shadow password table
1586  */
1587 static void
1589 {
1590  PG_CMD_DECL;
1591  const char **line;
1592  static const char *pg_authid_setup[] = {
1593  /*
1594  * The authid table shouldn't be readable except through views, to
1595  * ensure passwords are not publicly visible.
1596  */
1597  "REVOKE ALL on pg_authid FROM public;\n",
1598  NULL
1599  };
1600 
1601  fputs(_("initializing pg_authid ... "), stdout);
1602  fflush(stdout);
1603 
1604  snprintf(cmd, sizeof(cmd),
1605  "\"%s\" %s template1 >%s",
1607  DEVNULL);
1608 
1609  PG_CMD_OPEN;
1610 
1611  for (line = pg_authid_setup; *line != NULL; line++)
1612  PG_CMD_PUTS(*line);
1613 
1614  PG_CMD_CLOSE;
1615 
1616  check_ok();
1617 }
1618 
1619 /*
1620  * get the superuser password if required, and call postgres to set it
1621  */
1622 static void
1624 {
1625  PG_CMD_DECL;
1626 
1627  char *pwd1,
1628  *pwd2;
1629 
1630  if (pwprompt)
1631  {
1632  /*
1633  * Read password from terminal
1634  */
1635  pwd1 = simple_prompt("Enter new superuser password: ", 100, false);
1636  pwd2 = simple_prompt("Enter it again: ", 100, false);
1637  if (strcmp(pwd1, pwd2) != 0)
1638  {
1639  fprintf(stderr, _("Passwords didn't match.\n"));
1640  exit_nicely();
1641  }
1642  free(pwd2);
1643  }
1644  else
1645  {
1646  /*
1647  * Read password from file
1648  *
1649  * Ideally this should insist that the file not be world-readable.
1650  * However, this option is mainly intended for use on Windows where
1651  * file permissions may not exist at all, so we'll skip the paranoia
1652  * for now.
1653  */
1654  FILE *pwf = fopen(pwfilename, "r");
1655  char pwdbuf[MAXPGPATH];
1656  int i;
1657 
1658  if (!pwf)
1659  {
1660  fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
1661  progname, pwfilename, strerror(errno));
1662  exit_nicely();
1663  }
1664  if (!fgets(pwdbuf, sizeof(pwdbuf), pwf))
1665  {
1666  if (ferror(pwf))
1667  fprintf(stderr, _("%s: could not read password from file \"%s\": %s\n"),
1668  progname, pwfilename, strerror(errno));
1669  else
1670  fprintf(stderr, _("%s: password file \"%s\" is empty\n"),
1671  progname, pwfilename);
1672  exit_nicely();
1673  }
1674  fclose(pwf);
1675 
1676  i = strlen(pwdbuf);
1677  while (i > 0 && (pwdbuf[i - 1] == '\r' || pwdbuf[i - 1] == '\n'))
1678  pwdbuf[--i] = '\0';
1679 
1680  pwd1 = pg_strdup(pwdbuf);
1681 
1682  }
1683  printf(_("setting password ... "));
1684  fflush(stdout);
1685 
1686  snprintf(cmd, sizeof(cmd),
1687  "\"%s\" %s template1 >%s",
1689  DEVNULL);
1690 
1691  PG_CMD_OPEN;
1692 
1693  PG_CMD_PRINTF2("ALTER USER \"%s\" WITH PASSWORD E'%s';\n",
1694  username, escape_quotes(pwd1));
1695 
1696  /* MM: pwd1 is no longer needed, freeing it */
1697  free(pwd1);
1698 
1699  PG_CMD_CLOSE;
1700 
1701  check_ok();
1702 }
1703 
1704 /*
1705  * set up pg_depend
1706  */
1707 static void
1709 {
1710  PG_CMD_DECL;
1711  const char **line;
1712  static const char *pg_depend_setup[] = {
1713  /*
1714  * Make PIN entries in pg_depend for all objects made so far in the
1715  * tables that the dependency code handles. This is overkill (the
1716  * system doesn't really depend on having every last weird datatype,
1717  * for instance) but generating only the minimum required set of
1718  * dependencies seems hard.
1719  *
1720  * Note that we deliberately do not pin the system views, which
1721  * haven't been created yet. Also, no conversions, databases, or
1722  * tablespaces are pinned.
1723  *
1724  * First delete any already-made entries; PINs override all else, and
1725  * must be the only entries for their objects.
1726  */
1727  "DELETE FROM pg_depend;\n",
1728  "VACUUM pg_depend;\n",
1729  "DELETE FROM pg_shdepend;\n",
1730  "VACUUM pg_shdepend;\n",
1731 
1732  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1733  " FROM pg_class;\n",
1734  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1735  " FROM pg_proc;\n",
1736  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1737  " FROM pg_type;\n",
1738  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1739  " FROM pg_cast;\n",
1740  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1741  " FROM pg_constraint;\n",
1742  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1743  " FROM pg_attrdef;\n",
1744  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1745  " FROM pg_language;\n",
1746  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1747  " FROM pg_operator;\n",
1748  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1749  " FROM pg_opclass;\n",
1750  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1751  " FROM pg_opfamily;\n",
1752  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1753  " FROM pg_amop;\n",
1754  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1755  " FROM pg_amproc;\n",
1756  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1757  " FROM pg_rewrite;\n",
1758  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1759  " FROM pg_trigger;\n",
1760 
1761  /*
1762  * restriction here to avoid pinning the public namespace
1763  */
1764  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1765  " FROM pg_namespace "
1766  " WHERE nspname LIKE 'pg%';\n",
1767 
1768  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1769  " FROM pg_ts_parser;\n",
1770  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1771  " FROM pg_ts_dict;\n",
1772  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1773  " FROM pg_ts_template;\n",
1774  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1775  " FROM pg_ts_config;\n",
1776  "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
1777  " FROM pg_collation;\n",
1778  "INSERT INTO pg_shdepend SELECT 0,0,0,0, tableoid,oid, 'p' "
1779  " FROM pg_authid;\n",
1780  NULL
1781  };
1782 
1783  fputs(_("initializing dependencies ... "), stdout);
1784  fflush(stdout);
1785 
1786  snprintf(cmd, sizeof(cmd),
1787  "\"%s\" %s template1 >%s",
1789  DEVNULL);
1790 
1791  PG_CMD_OPEN;
1792 
1793  for (line = pg_depend_setup; *line != NULL; line++)
1794  PG_CMD_PUTS(*line);
1795 
1796  PG_CMD_CLOSE;
1797 
1798  check_ok();
1799 }
1800 
1801 /*
1802  * set up system views
1803  */
1804 static void
1806 {
1807  PG_CMD_DECL;
1808  char **line;
1809  char **sysviews_setup;
1810 
1811  fputs(_("creating system views ... "), stdout);
1812  fflush(stdout);
1813 
1814  sysviews_setup = readfile(system_views_file);
1815 
1816  /*
1817  * We use -j here to avoid backslashing stuff in system_views.sql
1818  */
1819  snprintf(cmd, sizeof(cmd),
1820  "\"%s\" %s -j template1 >%s",
1822  DEVNULL);
1823 
1824  PG_CMD_OPEN;
1825 
1826  for (line = sysviews_setup; *line != NULL; line++)
1827  {
1828  PG_CMD_PUTS(*line);
1829  free(*line);
1830  }
1831 
1832  PG_CMD_CLOSE;
1833 
1834  free(sysviews_setup);
1835 
1836  check_ok();
1837 }
1838 
1839 /*
1840  * load description data
1841  */
1842 static void
1844 {
1845  PG_CMD_DECL;
1846 
1847  fputs(_("loading system objects' descriptions ... "), stdout);
1848  fflush(stdout);
1849 
1850  snprintf(cmd, sizeof(cmd),
1851  "\"%s\" %s template1 >%s",
1853  DEVNULL);
1854 
1855  PG_CMD_OPEN;
1856 
1857  PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_description ( "
1858  " objoid oid, "
1859  " classname name, "
1860  " objsubid int4, "
1861  " description text) WITHOUT OIDS;\n");
1862 
1863  PG_CMD_PRINTF1("COPY tmp_pg_description FROM E'%s';\n",
1865 
1866  PG_CMD_PUTS("INSERT INTO pg_description "
1867  " SELECT t.objoid, c.oid, t.objsubid, t.description "
1868  " FROM tmp_pg_description t, pg_class c "
1869  " WHERE c.relname = t.classname;\n");
1870 
1871  PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_shdescription ( "
1872  " objoid oid, "
1873  " classname name, "
1874  " description text) WITHOUT OIDS;\n");
1875 
1876  PG_CMD_PRINTF1("COPY tmp_pg_shdescription FROM E'%s';\n",
1878 
1879  PG_CMD_PUTS("INSERT INTO pg_shdescription "
1880  " SELECT t.objoid, c.oid, t.description "
1881  " FROM tmp_pg_shdescription t, pg_class c "
1882  " WHERE c.relname = t.classname;\n");
1883 
1884  /* Create default descriptions for operator implementation functions */
1885  PG_CMD_PUTS("WITH funcdescs AS ( "
1886  "SELECT p.oid as p_oid, oprname, "
1887  "coalesce(obj_description(o.oid, 'pg_operator'),'') as opdesc "
1888  "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) "
1889  "INSERT INTO pg_description "
1890  " SELECT p_oid, 'pg_proc'::regclass, 0, "
1891  " 'implementation of ' || oprname || ' operator' "
1892  " FROM funcdescs "
1893  " WHERE opdesc NOT LIKE 'deprecated%' AND "
1894  " NOT EXISTS (SELECT 1 FROM pg_description "
1895  " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass);\n");
1896 
1897  PG_CMD_CLOSE;
1898 
1899  check_ok();
1900 }
1901 
1902 #ifdef HAVE_LOCALE_T
1903 /*
1904  * "Normalize" a locale name, stripping off encoding tags such as
1905  * ".utf8" (e.g., "en_US.utf8" -> "en_US", but "br_FR.iso885915@euro"
1906  * -> "br_FR@euro"). Return true if a new, different name was
1907  * generated.
1908  */
1909 static bool
1910 normalize_locale_name(char *new, const char *old)
1911 {
1912  char *n = new;
1913  const char *o = old;
1914  bool changed = false;
1915 
1916  while (*o)
1917  {
1918  if (*o == '.')
1919  {
1920  /* skip over encoding tag such as ".utf8" or ".UTF-8" */
1921  o++;
1922  while ((*o >= 'A' && *o <= 'Z')
1923  || (*o >= 'a' && *o <= 'z')
1924  || (*o >= '0' && *o <= '9')
1925  || (*o == '-'))
1926  o++;
1927  changed = true;
1928  }
1929  else
1930  *n++ = *o++;
1931  }
1932  *n = '\0';
1933 
1934  return changed;
1935 }
1936 #endif /* HAVE_LOCALE_T */
1937 
1938 /*
1939  * populate pg_collation
1940  */
1941 static void
1943 {
1944 #if defined(HAVE_LOCALE_T) && !defined(WIN32)
1945  int i;
1946  FILE *locale_a_handle;
1947  char localebuf[NAMEDATALEN]; /* we assume ASCII so this is fine */
1948  int count = 0;
1949 
1950  PG_CMD_DECL;
1951 #endif
1952 
1953  fputs(_("creating collations ... "), stdout);
1954  fflush(stdout);
1955 
1956 #if defined(HAVE_LOCALE_T) && !defined(WIN32)
1957  snprintf(cmd, sizeof(cmd),
1958  "\"%s\" %s template1 >%s",
1960  DEVNULL);
1961 
1962  locale_a_handle = popen_check("locale -a", "r");
1963  if (!locale_a_handle)
1964  return; /* complaint already printed */
1965 
1966  PG_CMD_OPEN;
1967 
1968  PG_CMD_PUTS("CREATE TEMP TABLE tmp_pg_collation ( "
1969  " collname name, "
1970  " locale name, "
1971  " encoding int) WITHOUT OIDS;\n");
1972 
1973  while (fgets(localebuf, sizeof(localebuf), locale_a_handle))
1974  {
1975  size_t len;
1976  int enc;
1977  bool skip;
1978  char *quoted_locale;
1979  char alias[NAMEDATALEN];
1980 
1981  len = strlen(localebuf);
1982 
1983  if (len == 0 || localebuf[len - 1] != '\n')
1984  {
1985  if (debug)
1986  fprintf(stderr, _("%s: locale name too long, skipped: \"%s\"\n"),
1987  progname, localebuf);
1988  continue;
1989  }
1990  localebuf[len - 1] = '\0';
1991 
1992  /*
1993  * Some systems have locale names that don't consist entirely of ASCII
1994  * letters (such as "bokm&aring;l" or "fran&ccedil;ais"). This is
1995  * pretty silly, since we need the locale itself to interpret the
1996  * non-ASCII characters. We can't do much with those, so we filter
1997  * them out.
1998  */
1999  skip = false;
2000  for (i = 0; i < len; i++)
2001  {
2002  if (IS_HIGHBIT_SET(localebuf[i]))
2003  {
2004  skip = true;
2005  break;
2006  }
2007  }
2008  if (skip)
2009  {
2010  if (debug)
2011  fprintf(stderr, _("%s: locale name has non-ASCII characters, skipped: \"%s\"\n"),
2012  progname, localebuf);
2013  continue;
2014  }
2015 
2016  enc = pg_get_encoding_from_locale(localebuf, debug);
2017  if (enc < 0)
2018  {
2019  /* error message printed by pg_get_encoding_from_locale() */
2020  continue;
2021  }
2022  if (!PG_VALID_BE_ENCODING(enc))
2023  continue; /* ignore locales for client-only encodings */
2024  if (enc == PG_SQL_ASCII)
2025  continue; /* C/POSIX are already in the catalog */
2026 
2027  count++;
2028 
2029  quoted_locale = escape_quotes(localebuf);
2030 
2031  PG_CMD_PRINTF3("INSERT INTO tmp_pg_collation VALUES (E'%s', E'%s', %d);\n",
2032  quoted_locale, quoted_locale, enc);
2033 
2034  /*
2035  * Generate aliases such as "en_US" in addition to "en_US.utf8" for
2036  * ease of use. Note that collation names are unique per encoding
2037  * only, so this doesn't clash with "en_US" for LATIN1, say.
2038  */
2039  if (normalize_locale_name(alias, localebuf))
2040  {
2041  char *quoted_alias = escape_quotes(alias);
2042 
2043  PG_CMD_PRINTF3("INSERT INTO tmp_pg_collation VALUES (E'%s', E'%s', %d);\n",
2044  quoted_alias, quoted_locale, enc);
2045  free(quoted_alias);
2046  }
2047  free(quoted_locale);
2048  }
2049 
2050  /* Add an SQL-standard name */
2051  PG_CMD_PRINTF1("INSERT INTO tmp_pg_collation VALUES ('ucs_basic', 'C', %d);\n", PG_UTF8);
2052 
2053  /*
2054  * When copying collations to the final location, eliminate aliases that
2055  * conflict with an existing locale name for the same encoding. For
2056  * example, "br_FR.iso88591" is normalized to "br_FR", both for encoding
2057  * LATIN1. But the unnormalized locale "br_FR" already exists for LATIN1.
2058  * Prefer the alias that matches the OS locale name, else the first locale
2059  * name by sort order (arbitrary choice to be deterministic).
2060  *
2061  * Also, eliminate any aliases that conflict with pg_collation's
2062  * hard-wired entries for "C" etc.
2063  */
2064  PG_CMD_PUTS("INSERT INTO pg_collation (collname, collnamespace, collowner, collencoding, collcollate, collctype) "
2065  " SELECT DISTINCT ON (collname, encoding)"
2066  " collname, "
2067  " (SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog') AS collnamespace, "
2068  " (SELECT relowner FROM pg_class WHERE relname = 'pg_collation') AS collowner, "
2069  " encoding, locale, locale "
2070  " FROM tmp_pg_collation"
2071  " WHERE NOT EXISTS (SELECT 1 FROM pg_collation WHERE collname = tmp_pg_collation.collname)"
2072  " ORDER BY collname, encoding, (collname = locale) DESC, locale;\n");
2073 
2074  pclose(locale_a_handle);
2075  PG_CMD_CLOSE;
2076 
2077  check_ok();
2078  if (count == 0 && !debug)
2079  {
2080  printf(_("No usable system locales were found.\n"));
2081  printf(_("Use the option \"--debug\" to see details.\n"));
2082  }
2083 #else /* not HAVE_LOCALE_T && not WIN32 */
2084  printf(_("not supported on this platform\n"));
2085  fflush(stdout);
2086 #endif /* not HAVE_LOCALE_T && not WIN32 */
2087 }
2088 
2089 /*
2090  * load conversion functions
2091  */
2092 static void
2094 {
2095  PG_CMD_DECL;
2096  char **line;
2097  char **conv_lines;
2098 
2099  fputs(_("creating conversions ... "), stdout);
2100  fflush(stdout);
2101 
2102  snprintf(cmd, sizeof(cmd),
2103  "\"%s\" %s template1 >%s",
2105  DEVNULL);
2106 
2107  PG_CMD_OPEN;
2108 
2109  conv_lines = readfile(conversion_file);
2110  for (line = conv_lines; *line != NULL; line++)
2111  {
2112  if (strstr(*line, "DROP CONVERSION") != *line)
2113  PG_CMD_PUTS(*line);
2114  free(*line);
2115  }
2116 
2117  free(conv_lines);
2118 
2119  PG_CMD_CLOSE;
2120 
2121  check_ok();
2122 }
2123 
2124 /*
2125  * load extra dictionaries (Snowball stemmers)
2126  */
2127 static void
2129 {
2130  PG_CMD_DECL;
2131  char **line;
2132  char **conv_lines;
2133 
2134  fputs(_("creating dictionaries ... "), stdout);
2135  fflush(stdout);
2136 
2137  /*
2138  * We use -j here to avoid backslashing stuff
2139  */
2140  snprintf(cmd, sizeof(cmd),
2141  "\"%s\" %s -j template1 >%s",
2143  DEVNULL);
2144 
2145  PG_CMD_OPEN;
2146 
2147  conv_lines = readfile(dictionary_file);
2148  for (line = conv_lines; *line != NULL; line++)
2149  {
2150  PG_CMD_PUTS(*line);
2151  free(*line);
2152  }
2153 
2154  free(conv_lines);
2155 
2156  PG_CMD_CLOSE;
2157 
2158  check_ok();
2159 }
2160 
2161 /*
2162  * Set up privileges
2163  *
2164  * We mark most system catalogs as world-readable. We don't currently have
2165  * to touch functions, languages, or databases, because their default
2166  * permissions are OK.
2167  *
2168  * Some objects may require different permissions by default, so we
2169  * make sure we don't overwrite privilege sets that have already been
2170  * set (NOT NULL).
2171  */
2172 static void
2174 {
2175  PG_CMD_DECL;
2176  char **line;
2177  char **priv_lines;
2178  static char *privileges_setup[] = {
2179  "UPDATE pg_class "
2180  " SET relacl = E'{\"=r/\\\\\"$POSTGRES_SUPERUSERNAME\\\\\"\"}' "
2181  " WHERE relkind IN ('r', 'v', 'm', 'S') AND relacl IS NULL;\n",
2182  "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n",
2183  "GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n",
2184  "REVOKE ALL ON pg_largeobject FROM PUBLIC;\n",
2185  NULL
2186  };
2187 
2188  fputs(_("setting privileges on built-in objects ... "), stdout);
2189  fflush(stdout);
2190 
2191  snprintf(cmd, sizeof(cmd),
2192  "\"%s\" %s template1 >%s",
2194  DEVNULL);
2195 
2196  PG_CMD_OPEN;
2197 
2198  priv_lines = replace_token(privileges_setup, "$POSTGRES_SUPERUSERNAME",
2200  for (line = priv_lines; *line != NULL; line++)
2201  PG_CMD_PUTS(*line);
2202 
2203  PG_CMD_CLOSE;
2204 
2205  check_ok();
2206 }
2207 
2208 /*
2209  * extract the strange version of version required for information schema
2210  * (09.08.0007abc)
2211  */
2212 static void
2214 {
2215  char *letterversion;
2216  long major = 0,
2217  minor = 0,
2218  micro = 0;
2219  char *endptr;
2220  char *vstr = pg_strdup(PG_VERSION);
2221  char *ptr;
2222 
2223  ptr = vstr + (strlen(vstr) - 1);
2224  while (ptr != vstr && (*ptr < '0' || *ptr > '9'))
2225  ptr--;
2226  letterversion = ptr + 1;
2227  major = strtol(vstr, &endptr, 10);
2228  if (*endptr)
2229  minor = strtol(endptr + 1, &endptr, 10);
2230  if (*endptr)
2231  micro = strtol(endptr + 1, &endptr, 10);
2232  snprintf(infoversion, sizeof(infoversion), "%02ld.%02ld.%04ld%s",
2233  major, minor, micro, letterversion);
2234 }
2235 
2236 /*
2237  * load info schema and populate from features file
2238  */
2239 static void
2241 {
2242  PG_CMD_DECL;
2243  char **line;
2244  char **lines;
2245 
2246  fputs(_("creating information schema ... "), stdout);
2247  fflush(stdout);
2248 
2249  lines = readfile(info_schema_file);
2250 
2251  /*
2252  * We use -j here to avoid backslashing stuff in information_schema.sql
2253  */
2254  snprintf(cmd, sizeof(cmd),
2255  "\"%s\" %s -j template1 >%s",
2257  DEVNULL);
2258 
2259  PG_CMD_OPEN;
2260 
2261  for (line = lines; *line != NULL; line++)
2262  {
2263  PG_CMD_PUTS(*line);
2264  free(*line);
2265  }
2266 
2267  free(lines);
2268 
2269  PG_CMD_CLOSE;
2270 
2271  snprintf(cmd, sizeof(cmd),
2272  "\"%s\" %s template1 >%s",
2274  DEVNULL);
2275 
2276  PG_CMD_OPEN;
2277 
2278  PG_CMD_PRINTF1("UPDATE information_schema.sql_implementation_info "
2279  " SET character_value = '%s' "
2280  " WHERE implementation_info_name = 'DBMS VERSION';\n",
2281  infoversion);
2282 
2283  PG_CMD_PRINTF1("COPY information_schema.sql_features "
2284  " (feature_id, feature_name, sub_feature_id, "
2285  " sub_feature_name, is_supported, comments) "
2286  " FROM E'%s';\n",
2288 
2289  PG_CMD_CLOSE;
2290 
2291  check_ok();
2292 }
2293 
2294 /*
2295  * load PL/pgsql server-side language
2296  */
2297 static void
2299 {
2300  PG_CMD_DECL;
2301 
2302  fputs(_("loading PL/pgSQL server-side language ... "), stdout);
2303  fflush(stdout);
2304 
2305  snprintf(cmd, sizeof(cmd),
2306  "\"%s\" %s template1 >%s",
2308  DEVNULL);
2309 
2310  PG_CMD_OPEN;
2311 
2312  PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n");
2313 
2314  PG_CMD_CLOSE;
2315 
2316  check_ok();
2317 }
2318 
2319 /*
2320  * clean everything up in template1
2321  */
2322 static void
2324 {
2325  PG_CMD_DECL;
2326 
2327  fputs(_("vacuuming database template1 ... "), stdout);
2328  fflush(stdout);
2329 
2330  snprintf(cmd, sizeof(cmd),
2331  "\"%s\" %s template1 >%s",
2333  DEVNULL);
2334 
2335  PG_CMD_OPEN;
2336 
2337  PG_CMD_PUTS("ANALYZE;\nVACUUM FULL;\nVACUUM FREEZE;\n");
2338 
2339  PG_CMD_CLOSE;
2340 
2341  check_ok();
2342 }
2343 
2344 /*
2345  * copy template1 to template0
2346  */
2347 static void
2349 {
2350  PG_CMD_DECL;
2351  const char **line;
2352  static const char *template0_setup[] = {
2353  "CREATE DATABASE template0 IS_TEMPLATE = true ALLOW_CONNECTIONS = false;\n",
2354 
2355  /*
2356  * We use the OID of template0 to determine lastsysoid
2357  */
2358  "UPDATE pg_database SET datlastsysoid = "
2359  " (SELECT oid FROM pg_database "
2360  " WHERE datname = 'template0');\n",
2361 
2362  /*
2363  * Explicitly revoke public create-schema and create-temp-table
2364  * privileges in template1 and template0; else the latter would be on
2365  * by default
2366  */
2367  "REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n",
2368  "REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n",
2369 
2370  "COMMENT ON DATABASE template0 IS 'unmodifiable empty database';\n",
2371 
2372  /*
2373  * Finally vacuum to clean up dead rows in pg_database
2374  */
2375  "VACUUM FULL pg_database;\n",
2376  NULL
2377  };
2378 
2379  fputs(_("copying template1 to template0 ... "), stdout);
2380  fflush(stdout);
2381 
2382  snprintf(cmd, sizeof(cmd),
2383  "\"%s\" %s template1 >%s",
2385  DEVNULL);
2386 
2387  PG_CMD_OPEN;
2388 
2389  for (line = template0_setup; *line; line++)
2390  PG_CMD_PUTS(*line);
2391 
2392  PG_CMD_CLOSE;
2393 
2394  check_ok();
2395 }
2396 
2397 /*
2398  * copy template1 to postgres
2399  */
2400 static void
2402 {
2403  PG_CMD_DECL;
2404  const char **line;
2405  static const char *postgres_setup[] = {
2406  "CREATE DATABASE postgres;\n",
2407  "COMMENT ON DATABASE postgres IS 'default administrative connection database';\n",
2408  NULL
2409  };
2410 
2411  fputs(_("copying template1 to postgres ... "), stdout);
2412  fflush(stdout);
2413 
2414  snprintf(cmd, sizeof(cmd),
2415  "\"%s\" %s template1 >%s",
2417  DEVNULL);
2418 
2419  PG_CMD_OPEN;
2420 
2421  for (line = postgres_setup; *line; line++)
2422  PG_CMD_PUTS(*line);
2423 
2424  PG_CMD_CLOSE;
2425 
2426  check_ok();
2427 }
2428 
2429 /*
2430  * fsync everything down to disk
2431  */
2432 static void
2434 {
2435  char pdir[MAXPGPATH];
2436  char pg_tblspc[MAXPGPATH];
2437 
2438  fputs(_("syncing data to disk ... "), stdout);
2439  fflush(stdout);
2440 
2441  /*
2442  * We need to name the parent of PGDATA. get_parent_directory() isn't
2443  * enough here, because it can result in an empty string.
2444  */
2445  snprintf(pdir, MAXPGPATH, "%s/..", pg_data);
2446  canonicalize_path(pdir);
2447 
2448  /*
2449  * Hint to the OS so that we're going to fsync each of these files soon.
2450  */
2451 
2452  /* first the parent of the PGDATA directory */
2453  pre_sync_fname(pdir, true);
2454 
2455  /* then recursively through the data directory */
2457 
2458  /* now do the same thing for everything under pg_tblspc */
2459  snprintf(pg_tblspc, MAXPGPATH, "%s/pg_tblspc", pg_data);
2460  walktblspc_links(pg_tblspc, pre_sync_fname);
2461 
2462  /*
2463  * Now, do the fsync()s in the same order.
2464  */
2465 
2466  /* first the parent of the PGDATA directory */
2467  fsync_fname(pdir, true);
2468 
2469  /* then recursively through the data directory */
2471 
2472  /* and now the same for all tablespaces */
2473  walktblspc_links(pg_tblspc, fsync_fname);
2474 
2475  check_ok();
2476 }
2477 
2478 
2479 /*
2480  * signal handler in case we are interrupted.
2481  *
2482  * The Windows runtime docs at
2483  * http://msdn.microsoft.com/library/en-us/vclib/html/_crt_signal.asp
2484  * specifically forbid a number of things being done from a signal handler,
2485  * including IO, memory allocation and system calls, and only allow jmpbuf
2486  * if you are handling SIGFPE.
2487  *
2488  * I avoided doing the forbidden things by setting a flag instead of calling
2489  * exit_nicely() directly.
2490  *
2491  * Also note the behaviour of Windows with SIGINT, which says this:
2492  * Note SIGINT is not supported for any Win32 application, including
2493  * Windows 98/Me and Windows NT/2000/XP. When a CTRL+C interrupt occurs,
2494  * Win32 operating systems generate a new thread to specifically handle
2495  * that interrupt. This can cause a single-thread application such as UNIX,
2496  * to become multithreaded, resulting in unexpected behavior.
2497  *
2498  * I have no idea how to handle this. (Strange they call UNIX an application!)
2499  * So this will need some testing on Windows.
2500  */
2501 static void
2502 trapsig(int signum)
2503 {
2504  /* handle systems that reset the handler, like Windows (grr) */
2505  pqsignal(signum, trapsig);
2506  caught_signal = true;
2507 }
2508 
2509 /*
2510  * call exit_nicely() if we got a signal, or else output "ok".
2511  */
2512 static void
2514 {
2515  if (caught_signal)
2516  {
2517  printf(_("caught signal\n"));
2518  fflush(stdout);
2519  exit_nicely();
2520  }
2521  else if (output_failed)
2522  {
2523  printf(_("could not write to child process: %s\n"),
2525  fflush(stdout);
2526  exit_nicely();
2527  }
2528  else
2529  {
2530  /* all seems well */
2531  printf(_("ok\n"));
2532  fflush(stdout);
2533  }
2534 }
2535 
2536 /* Hack to suppress a warning about %x from some versions of gcc */
2537 static inline size_t
2538 my_strftime(char *s, size_t max, const char *fmt, const struct tm * tm)
2539 {
2540  return strftime(s, max, fmt, tm);
2541 }
2542 
2543 /*
2544  * Determine likely date order from locale
2545  */
2546 static int
2548 {
2549  struct tm testtime;
2550  char buf[128];
2551  char *posD;
2552  char *posM;
2553  char *posY;
2554  char *save;
2555  size_t res;
2556  int result;
2557 
2558  result = DATEORDER_MDY; /* default */
2559 
2560  save = setlocale(LC_TIME, NULL);
2561  if (!save)
2562  return result;
2563  save = pg_strdup(save);
2564 
2565  setlocale(LC_TIME, locale);
2566 
2567  memset(&testtime, 0, sizeof(testtime));
2568  testtime.tm_mday = 22;
2569  testtime.tm_mon = 10; /* November, should come out as "11" */
2570  testtime.tm_year = 133; /* 2033 */
2571 
2572  res = my_strftime(buf, sizeof(buf), "%x", &testtime);
2573 
2574  setlocale(LC_TIME, save);
2575  free(save);
2576 
2577  if (res == 0)
2578  return result;
2579 
2580  posM = strstr(buf, "11");
2581  posD = strstr(buf, "22");
2582  posY = strstr(buf, "33");
2583 
2584  if (!posM || !posD || !posY)
2585  return result;
2586 
2587  if (posY < posM && posM < posD)
2588  result = DATEORDER_YMD;
2589  else if (posD < posM)
2590  result = DATEORDER_DMY;
2591  else
2592  result = DATEORDER_MDY;
2593 
2594  return result;
2595 }
2596 
2597 /*
2598  * Verify that locale name is valid for the locale category.
2599  *
2600  * If successful, and canonname isn't NULL, a malloc'd copy of the locale's
2601  * canonical name is stored there. This is especially useful for figuring out
2602  * what locale name "" means (ie, the environment value). (Actually,
2603  * it seems that on most implementations that's the only thing it's good for;
2604  * we could wish that setlocale gave back a canonically spelled version of
2605  * the locale name, but typically it doesn't.)
2606  *
2607  * this should match the backend's check_locale() function
2608  */
2609 static void
2610 check_locale_name(int category, const char *locale, char **canonname)
2611 {
2612  char *save;
2613  char *res;
2614 
2615  if (canonname)
2616  *canonname = NULL; /* in case of failure */
2617 
2618  save = setlocale(category, NULL);
2619  if (!save)
2620  {
2621  fprintf(stderr, _("%s: setlocale() failed\n"),
2622  progname);
2623  exit(1);
2624  }
2625 
2626  /* save may be pointing at a modifiable scratch variable, so copy it. */
2627  save = pg_strdup(save);
2628 
2629  /* set the locale with setlocale, to see if it accepts it. */
2630  res = setlocale(category, locale);
2631 
2632  /* save canonical name if requested. */
2633  if (res && canonname)
2634  *canonname = pg_strdup(res);
2635 
2636  /* restore old value. */
2637  if (!setlocale(category, save))
2638  {
2639  fprintf(stderr, _("%s: failed to restore old locale \"%s\"\n"),
2640  progname, save);
2641  exit(1);
2642  }
2643  free(save);
2644 
2645  /* complain if locale wasn't valid */
2646  if (res == NULL)
2647  {
2648  if (*locale)
2649  fprintf(stderr, _("%s: invalid locale name \"%s\"\n"),
2650  progname, locale);
2651  else
2652  {
2653  /*
2654  * If no relevant switch was given on command line, locale is an
2655  * empty string, which is not too helpful to report. Presumably
2656  * setlocale() found something it did not like in the environment.
2657  * Ideally we'd report the bad environment variable, but since
2658  * setlocale's behavior is implementation-specific, it's hard to
2659  * be sure what it didn't like. Print a safe generic message.
2660  */
2661  fprintf(stderr, _("%s: invalid locale settings; check LANG and LC_* environment variables\n"),
2662  progname);
2663  }
2664  exit(1);
2665  }
2666 }
2667 
2668 /*
2669  * check if the chosen encoding matches the encoding required by the locale
2670  *
2671  * this should match the similar check in the backend createdb() function
2672  */
2673 static bool
2674 check_locale_encoding(const char *locale, int user_enc)
2675 {
2676  int locale_enc;
2677 
2678  locale_enc = pg_get_encoding_from_locale(locale, true);
2679 
2680  /* See notes in createdb() to understand these tests */
2681  if (!(locale_enc == user_enc ||
2682  locale_enc == PG_SQL_ASCII ||
2683  locale_enc == -1 ||
2684 #ifdef WIN32
2685  user_enc == PG_UTF8 ||
2686 #endif
2687  user_enc == PG_SQL_ASCII))
2688  {
2689  fprintf(stderr, _("%s: encoding mismatch\n"), progname);
2690  fprintf(stderr,
2691  _("The encoding you selected (%s) and the encoding that the\n"
2692  "selected locale uses (%s) do not match. This would lead to\n"
2693  "misbehavior in various character string processing functions.\n"
2694  "Rerun %s and either do not specify an encoding explicitly,\n"
2695  "or choose a matching combination.\n"),
2696  pg_encoding_to_char(user_enc),
2697  pg_encoding_to_char(locale_enc),
2698  progname);
2699  return false;
2700  }
2701  return true;
2702 }
2703 
2704 /*
2705  * set up the locale variables
2706  *
2707  * assumes we have called setlocale(LC_ALL, "") -- see set_pglocale_pgservice
2708  */
2709 static void
2711 {
2712  char *canonname;
2713 
2714  /* set empty lc_* values to locale config if set */
2715 
2716  if (strlen(locale) > 0)
2717  {
2718  if (strlen(lc_ctype) == 0)
2719  lc_ctype = locale;
2720  if (strlen(lc_collate) == 0)
2721  lc_collate = locale;
2722  if (strlen(lc_numeric) == 0)
2723  lc_numeric = locale;
2724  if (strlen(lc_time) == 0)
2725  lc_time = locale;
2726  if (strlen(lc_monetary) == 0)
2727  lc_monetary = locale;
2728  if (strlen(lc_messages) == 0)
2729  lc_messages = locale;
2730  }
2731 
2732  /*
2733  * canonicalize locale names, and obtain any missing values from our
2734  * current environment
2735  */
2736 
2737  check_locale_name(LC_CTYPE, lc_ctype, &canonname);
2738  lc_ctype = canonname;
2739  check_locale_name(LC_COLLATE, lc_collate, &canonname);
2740  lc_collate = canonname;
2741  check_locale_name(LC_NUMERIC, lc_numeric, &canonname);
2742  lc_numeric = canonname;
2743  check_locale_name(LC_TIME, lc_time, &canonname);
2744  lc_time = canonname;
2745  check_locale_name(LC_MONETARY, lc_monetary, &canonname);
2746  lc_monetary = canonname;
2747 #if defined(LC_MESSAGES) && !defined(WIN32)
2748  check_locale_name(LC_MESSAGES, lc_messages, &canonname);
2749  lc_messages = canonname;
2750 #else
2751  /* when LC_MESSAGES is not available, use the LC_CTYPE setting */
2752  check_locale_name(LC_CTYPE, lc_messages, &canonname);
2753  lc_messages = canonname;
2754 #endif
2755 }
2756 
2757 #ifdef WIN32
2758 typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
2759 
2760 /* Windows API define missing from some versions of MingW headers */
2761 #ifndef DISABLE_MAX_PRIVILEGE
2762 #define DISABLE_MAX_PRIVILEGE 0x1
2763 #endif
2764 
2765 /*
2766  * Create a restricted token and execute the specified process with it.
2767  *
2768  * Returns 0 on failure, non-zero on success, same as CreateProcess().
2769  *
2770  * On NT4, or any other system not containing the required functions, will
2771  * NOT execute anything.
2772  */
2773 static int
2774 CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo)
2775 {
2776  BOOL b;
2777  STARTUPINFO si;
2778  HANDLE origToken;
2779  HANDLE restrictedToken;
2780  SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
2781  SID_AND_ATTRIBUTES dropSids[2];
2782  __CreateRestrictedToken _CreateRestrictedToken = NULL;
2783  HANDLE Advapi32Handle;
2784 
2785  ZeroMemory(&si, sizeof(si));
2786  si.cb = sizeof(si);
2787 
2788  Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
2789  if (Advapi32Handle != NULL)
2790  {
2791  _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
2792  }
2793 
2794  if (_CreateRestrictedToken == NULL)
2795  {
2796  fprintf(stderr, _("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
2797  if (Advapi32Handle != NULL)
2798  FreeLibrary(Advapi32Handle);
2799  return 0;
2800  }
2801 
2802  /* Open the current token to use as a base for the restricted one */
2803  if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
2804  {
2805  fprintf(stderr, _("%s: could not open process token: error code %lu\n"), progname, GetLastError());
2806  return 0;
2807  }
2808 
2809  /* Allocate list of SIDs to remove */
2810  ZeroMemory(&dropSids, sizeof(dropSids));
2811  if (!AllocateAndInitializeSid(&NtAuthority, 2,
2812  SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
2813  0, &dropSids[0].Sid) ||
2814  !AllocateAndInitializeSid(&NtAuthority, 2,
2815  SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
2816  0, &dropSids[1].Sid))
2817  {
2818  fprintf(stderr, _("%s: could not allocate SIDs: error code %lu\n"),
2819  progname, GetLastError());
2820  return 0;
2821  }
2822 
2823  b = _CreateRestrictedToken(origToken,
2824  DISABLE_MAX_PRIVILEGE,
2825  sizeof(dropSids) / sizeof(dropSids[0]),
2826  dropSids,
2827  0, NULL,
2828  0, NULL,
2829  &restrictedToken);
2830 
2831  FreeSid(dropSids[1].Sid);
2832  FreeSid(dropSids[0].Sid);
2833  CloseHandle(origToken);
2834  FreeLibrary(Advapi32Handle);
2835 
2836  if (!b)
2837  {
2838  fprintf(stderr, _("%s: could not create restricted token: error code %lu\n"), progname, GetLastError());
2839  return 0;
2840  }
2841 
2842 #ifndef __CYGWIN__
2843  AddUserToTokenDacl(restrictedToken);
2844 #endif
2845 
2846  if (!CreateProcessAsUser(restrictedToken,
2847  NULL,
2848  cmd,
2849  NULL,
2850  NULL,
2851  TRUE,
2852  CREATE_SUSPENDED,
2853  NULL,
2854  NULL,
2855  &si,
2856  processInfo))
2857 
2858  {
2859  fprintf(stderr, _("%s: could not start process for command \"%s\": error code %lu\n"), progname, cmd, GetLastError());
2860  return 0;
2861  }
2862 
2863  return ResumeThread(processInfo->hThread);
2864 }
2865 #endif
2866 
2867 /*
2868  * print help text
2869  */
2870 static void
2871 usage(const char *progname)
2872 {
2873  printf(_("%s initializes a PostgreSQL database cluster.\n\n"), progname);
2874  printf(_("Usage:\n"));
2875  printf(_(" %s [OPTION]... [DATADIR]\n"), progname);
2876  printf(_("\nOptions:\n"));
2877  printf(_(" -A, --auth=METHOD default authentication method for local connections\n"));
2878  printf(_(" --auth-host=METHOD default authentication method for local TCP/IP connections\n"));
2879  printf(_(" --auth-local=METHOD default authentication method for local-socket connections\n"));
2880  printf(_(" [-D, --pgdata=]DATADIR location for this database cluster\n"));
2881  printf(_(" -E, --encoding=ENCODING set default encoding for new databases\n"));
2882  printf(_(" --locale=LOCALE set default locale for new databases\n"));
2883  printf(_(" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n"
2884  " --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n"
2885  " set default locale in the respective category for\n"
2886  " new databases (default taken from environment)\n"));
2887  printf(_(" --no-locale equivalent to --locale=C\n"));
2888  printf(_(" --pwfile=FILE read password for the new superuser from file\n"));
2889  printf(_(" -T, --text-search-config=CFG\n"
2890  " default text search configuration\n"));
2891  printf(_(" -U, --username=NAME database superuser name\n"));
2892  printf(_(" -W, --pwprompt prompt for a password for the new superuser\n"));
2893  printf(_(" -X, --xlogdir=XLOGDIR location for the transaction log directory\n"));
2894  printf(_("\nLess commonly used options:\n"));
2895  printf(_(" -d, --debug generate lots of debugging output\n"));
2896  printf(_(" -k, --data-checksums use data page checksums\n"));
2897  printf(_(" -L DIRECTORY where to find the input files\n"));
2898  printf(_(" -n, --noclean do not clean up after errors\n"));
2899  printf(_(" -N, --nosync do not wait for changes to be written safely to disk\n"));
2900  printf(_(" -s, --show show internal settings\n"));
2901  printf(_(" -S, --sync-only only sync data directory\n"));
2902  printf(_("\nOther options:\n"));
2903  printf(_(" -V, --version output version information, then exit\n"));
2904  printf(_(" -?, --help show this help, then exit\n"));
2905  printf(_("\nIf the data directory is not specified, the environment variable PGDATA\n"
2906  "is used.\n"));
2907  printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
2908 }
2909 
2910 static void
2911 check_authmethod_unspecified(const char **authmethod)
2912 {
2913  if (*authmethod == NULL || strlen(*authmethod) == 0)
2914  {
2915  authwarning = _("\nWARNING: enabling \"trust\" authentication for local connections\n"
2916  "You can change this by editing pg_hba.conf or using the option -A, or\n"
2917  "--auth-local and --auth-host, the next time you run initdb.\n");
2918  *authmethod = "trust";
2919  }
2920 }
2921 
2922 static void
2923 check_authmethod_valid(const char *authmethod, const char **valid_methods, const char *conntype)
2924 {
2925  const char **p;
2926 
2927  for (p = valid_methods; *p; p++)
2928  {
2929  if (strcmp(authmethod, *p) == 0)
2930  return;
2931  /* with space = param */
2932  if (strchr(authmethod, ' '))
2933  if (strncmp(authmethod, *p, (authmethod - strchr(authmethod, ' '))) == 0)
2934  return;
2935  }
2936 
2937  fprintf(stderr, _("%s: invalid authentication method \"%s\" for \"%s\" connections\n"),
2938  progname, authmethod, conntype);
2939  exit(1);
2940 }
2941 
2942 static void
2944 {
2945  if ((strcmp(authmethodlocal, "md5") == 0 ||
2946  strcmp(authmethodlocal, "password") == 0) &&
2947  (strcmp(authmethodhost, "md5") == 0 ||
2948  strcmp(authmethodhost, "password") == 0) &&
2949  !(pwprompt || pwfilename))
2950  {
2951  fprintf(stderr, _("%s: must specify a password for the superuser to enable %s authentication\n"), progname,
2952  (strcmp(authmethodlocal, "md5") == 0 ||
2953  strcmp(authmethodlocal, "password") == 0)
2954  ? authmethodlocal
2955  : authmethodhost);
2956  exit(1);
2957  }
2958 }
2959 
2960 void
2962 {
2963 #ifdef WIN32
2964 
2965  /*
2966  * Before we execute another program, make sure that we are running with a
2967  * restricted token. If not, re-execute ourselves with one.
2968  */
2969 
2970  if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
2971  || strcmp(restrict_env, "1") != 0)
2972  {
2973  PROCESS_INFORMATION pi;
2974  char *cmdline;
2975 
2976  ZeroMemory(&pi, sizeof(pi));
2977 
2978  cmdline = pg_strdup(GetCommandLine());
2979 
2980  putenv("PG_RESTRICT_EXEC=1");
2981 
2982  if (!CreateRestrictedProcess(cmdline, &pi))
2983  {
2984  fprintf(stderr, _("%s: could not re-execute with restricted token: error code %lu\n"), progname, GetLastError());
2985  }
2986  else
2987  {
2988  /*
2989  * Successfully re-execed. Now wait for child process to capture
2990  * exitcode.
2991  */
2992  DWORD x;
2993 
2994  CloseHandle(pi.hThread);
2995  WaitForSingleObject(pi.hProcess, INFINITE);
2996 
2997  if (!GetExitCodeProcess(pi.hProcess, &x))
2998  {
2999  fprintf(stderr, _("%s: could not get exit code from subprocess: error code %lu\n"), progname, GetLastError());
3000  exit(1);
3001  }
3002  exit(x);
3003  }
3004  }
3005 #endif
3006 }
3007 
3008 void
3010 {
3011  char *pgdata_get_env,
3012  *pgdata_set_env;
3013 
3014  if (strlen(pg_data) == 0)
3015  {
3016  pgdata_get_env = getenv("PGDATA");
3017  if (pgdata_get_env && strlen(pgdata_get_env))
3018  {
3019  /* PGDATA found */
3020  pg_data = pg_strdup(pgdata_get_env);
3021  }
3022  else
3023  {
3024  fprintf(stderr,
3025  _("%s: no data directory specified\n"
3026  "You must identify the directory where the data for this database system\n"
3027  "will reside. Do this with either the invocation option -D or the\n"
3028  "environment variable PGDATA.\n"),
3029  progname);
3030  exit(1);
3031  }
3032  }
3033 
3036 
3037  /*
3038  * we have to set PGDATA for postgres rather than pass it on the command
3039  * line to avoid dumb quoting problems on Windows, and we would especially
3040  * need quotes otherwise on Windows because paths there are most likely to
3041  * have embedded spaces.
3042  */
3043  pgdata_set_env = psprintf("PGDATA=%s", pg_data);
3044  putenv(pgdata_set_env);
3045 }
3046 
3047 
3048 void
3050 {
3051  int ret;
3052 
3053  if ((ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
3054  backend_exec)) < 0)
3055  {
3056  char full_path[MAXPGPATH];
3057 
3058  if (find_my_exec(argv0, full_path) < 0)
3059  strlcpy(full_path, progname, sizeof(full_path));
3060 
3061  if (ret == -1)
3062  fprintf(stderr,
3063  _("The program \"postgres\" is needed by %s "
3064  "but was not found in the\n"
3065  "same directory as \"%s\".\n"
3066  "Check your installation.\n"),
3067  progname, full_path);
3068  else
3069  fprintf(stderr,
3070  _("The program \"postgres\" was found by \"%s\"\n"
3071  "but was not the same version as %s.\n"
3072  "Check your installation.\n"),
3073  full_path, progname);
3074  exit(1);
3075  }
3076 
3077  /* store binary directory */
3078  strcpy(bin_path, backend_exec);
3079  *last_dir_separator(bin_path) = '\0';
3081 
3082  if (!share_path)
3083  {
3086  }
3087  else if (!is_absolute_path(share_path))
3088  {
3089  fprintf(stderr, _("%s: input file location must be an absolute path\n"), progname);
3090  exit(1);
3091  }
3092 
3094 }
3095 
3096 void
3098 {
3099  int user_enc;
3100 
3101  setlocales();
3102 
3103  if (strcmp(lc_ctype, lc_collate) == 0 &&
3104  strcmp(lc_ctype, lc_time) == 0 &&
3105  strcmp(lc_ctype, lc_numeric) == 0 &&
3106  strcmp(lc_ctype, lc_monetary) == 0 &&
3107  strcmp(lc_ctype, lc_messages) == 0)
3108  printf(_("The database cluster will be initialized with locale \"%s\".\n"), lc_ctype);
3109  else
3110  {
3111  printf(_("The database cluster will be initialized with locales\n"
3112  " COLLATE: %s\n"
3113  " CTYPE: %s\n"
3114  " MESSAGES: %s\n"
3115  " MONETARY: %s\n"
3116  " NUMERIC: %s\n"
3117  " TIME: %s\n"),
3118  lc_collate,
3119  lc_ctype,
3120  lc_messages,
3121  lc_monetary,
3122  lc_numeric,
3123  lc_time);
3124  }
3125 
3126  if (strlen(encoding) == 0)
3127  {
3128  int ctype_enc;
3129 
3130  ctype_enc = pg_get_encoding_from_locale(lc_ctype, true);
3131 
3132  if (ctype_enc == -1)
3133  {
3134  /* Couldn't recognize the locale's codeset */
3135  fprintf(stderr, _("%s: could not find suitable encoding for locale \"%s\"\n"),
3136  progname, lc_ctype);
3137  fprintf(stderr, _("Rerun %s with the -E option.\n"), progname);
3138  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
3139  progname);
3140  exit(1);
3141  }
3142  else if (!pg_valid_server_encoding_id(ctype_enc))
3143  {
3144  /*
3145  * We recognized it, but it's not a legal server encoding. On
3146  * Windows, UTF-8 works with any locale, so we can fall back to
3147  * UTF-8.
3148  */
3149 #ifdef WIN32
3150  printf(_("Encoding \"%s\" implied by locale is not allowed as a server-side encoding.\n"
3151  "The default database encoding will be set to \"%s\" instead.\n"),
3152  pg_encoding_to_char(ctype_enc),
3154  ctype_enc = PG_UTF8;
3155  encodingid = encodingid_to_string(ctype_enc);
3156 #else
3157  fprintf(stderr,
3158  _("%s: locale \"%s\" requires unsupported encoding \"%s\"\n"),
3159  progname, lc_ctype, pg_encoding_to_char(ctype_enc));
3160  fprintf(stderr,
3161  _("Encoding \"%s\" is not allowed as a server-side encoding.\n"
3162  "Rerun %s with a different locale selection.\n"),
3163  pg_encoding_to_char(ctype_enc), progname);
3164  exit(1);
3165 #endif
3166  }
3167  else
3168  {
3169  encodingid = encodingid_to_string(ctype_enc);
3170  printf(_("The default database encoding has accordingly been set to \"%s\".\n"),
3171  pg_encoding_to_char(ctype_enc));
3172  }
3173  }
3174  else
3176 
3177  user_enc = atoi(encodingid);
3178  if (!check_locale_encoding(lc_ctype, user_enc) ||
3179  !check_locale_encoding(lc_collate, user_enc))
3180  exit(1); /* check_locale_encoding printed the error */
3181 
3182 }
3183 
3184 
3185 void
3187 {
3188  set_input(&bki_file, "postgres.bki");
3189  set_input(&desc_file, "postgres.description");
3190  set_input(&shdesc_file, "postgres.shdescription");
3191  set_input(&hba_file, "pg_hba.conf.sample");
3192  set_input(&ident_file, "pg_ident.conf.sample");
3193  set_input(&conf_file, "postgresql.conf.sample");
3194  set_input(&conversion_file, "conversion_create.sql");
3195  set_input(&dictionary_file, "snowball_create.sql");
3196  set_input(&info_schema_file, "information_schema.sql");
3197  set_input(&features_file, "sql_features.txt");
3198  set_input(&system_views_file, "system_views.sql");
3199 
3200  if (show_setting || debug)
3201  {
3202  fprintf(stderr,
3203  "VERSION=%s\n"
3204  "PGDATA=%s\nshare_path=%s\nPGPATH=%s\n"
3205  "POSTGRES_SUPERUSERNAME=%s\nPOSTGRES_BKI=%s\n"
3206  "POSTGRES_DESCR=%s\nPOSTGRES_SHDESCR=%s\n"
3207  "POSTGRESQL_CONF_SAMPLE=%s\n"
3208  "PG_HBA_SAMPLE=%s\nPG_IDENT_SAMPLE=%s\n",
3209  PG_VERSION,
3211  username, bki_file,
3213  conf_file,
3214  hba_file, ident_file);
3215  if (show_setting)
3216  exit(0);
3217  }
3218 
3230 }
3231 
3232 
3233 void
3235 {
3236  if (strlen(default_text_search_config) == 0)
3237  {
3240  {
3241  printf(_("%s: could not find suitable text search configuration for locale \"%s\"\n"),
3242  progname, lc_ctype);
3243  default_text_search_config = "simple";
3244  }
3245  }
3246  else
3247  {
3248  const char *checkmatch = find_matching_ts_config(lc_ctype);
3249 
3250  if (checkmatch == NULL)
3251  {
3252  printf(_("%s: warning: suitable text search configuration for locale \"%s\" is unknown\n"),
3253  progname, lc_ctype);
3254  }
3255  else if (strcmp(checkmatch, default_text_search_config) != 0)
3256  {
3257  printf(_("%s: warning: specified text search configuration \"%s\" might not match locale \"%s\"\n"),
3259  }
3260  }
3261 
3262  printf(_("The default text search configuration will be set to \"%s\".\n"),
3264 
3265 }
3266 
3267 
3268 void
3270 {
3271  /* some of these are not valid on Windows */
3272 #ifdef SIGHUP
3274 #endif
3275 #ifdef SIGINT
3276  pqsignal(SIGINT, trapsig);
3277 #endif
3278 #ifdef SIGQUIT
3280 #endif
3281 #ifdef SIGTERM
3282  pqsignal(SIGTERM, trapsig);
3283 #endif
3284 
3285  /* Ignore SIGPIPE when writing to backend, so we can clean up */
3286 #ifdef SIGPIPE
3288 #endif
3289 
3290  /* Prevent SIGSYS so we can probe for kernel calls that might not work */
3291 #ifdef SIGSYS
3292  pqsignal(SIGSYS, SIG_IGN);
3293 #endif
3294 }
3295 
3296 
3297 void
3299 {
3300  int ret;
3301 
3302  switch ((ret = pg_check_dir(pg_data)))
3303  {
3304  case 0:
3305  /* PGDATA not there, must create it */
3306  printf(_("creating directory %s ... "),
3307  pg_data);
3308  fflush(stdout);
3309 
3310  if (!mkdatadir(NULL))
3311  exit_nicely();
3312  else
3313  check_ok();
3314 
3315  made_new_pgdata = true;
3316  break;
3317 
3318  case 1:
3319  /* Present but empty, fix permissions and use it */
3320  printf(_("fixing permissions on existing directory %s ... "),
3321  pg_data);
3322  fflush(stdout);
3323 
3324  if (chmod(pg_data, S_IRWXU) != 0)
3325  {
3326  fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
3327  progname, pg_data, strerror(errno));
3328  exit_nicely();
3329  }
3330  else
3331  check_ok();
3332 
3333  found_existing_pgdata = true;
3334  break;
3335 
3336  case 2:
3337  case 3:
3338  case 4:
3339  /* Present and not empty */
3340  fprintf(stderr,
3341  _("%s: directory \"%s\" exists but is not empty\n"),
3342  progname, pg_data);
3343  if (ret != 4)
3344  warn_on_mount_point(ret);
3345  else
3346  fprintf(stderr,
3347  _("If you want to create a new database system, either remove or empty\n"
3348  "the directory \"%s\" or run %s\n"
3349  "with an argument other than \"%s\".\n"),
3351  exit(1); /* no further message needed */
3352 
3353  default:
3354  /* Trouble accessing directory */
3355  fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
3356  progname, pg_data, strerror(errno));
3357  exit_nicely();
3358  }
3359 }
3360 
3361 
3362 void
3364 {
3365  /* Create transaction log symlink, if required */
3366  if (strcmp(xlog_dir, "") != 0)
3367  {
3368  char *linkloc;
3369  int ret;
3370 
3371  /* clean up xlog directory name, check it's absolute */
3373  if (!is_absolute_path(xlog_dir))
3374  {
3375  fprintf(stderr, _("%s: transaction log directory location must be an absolute path\n"), progname);
3376  exit_nicely();
3377  }
3378 
3379  /* check if the specified xlog directory exists/is empty */
3380  switch ((ret = pg_check_dir(xlog_dir)))
3381  {
3382  case 0:
3383  /* xlog directory not there, must create it */
3384  printf(_("creating directory %s ... "),
3385  xlog_dir);
3386  fflush(stdout);
3387 
3388  if (pg_mkdir_p(xlog_dir, S_IRWXU) != 0)
3389  {
3390  fprintf(stderr, _("%s: could not create directory \"%s\": %s\n"),
3391  progname, xlog_dir, strerror(errno));
3392  exit_nicely();
3393  }
3394  else
3395  check_ok();
3396 
3397  made_new_xlogdir = true;
3398  break;
3399 
3400  case 1:
3401  /* Present but empty, fix permissions and use it */
3402  printf(_("fixing permissions on existing directory %s ... "),
3403  xlog_dir);
3404  fflush(stdout);
3405 
3406  if (chmod(xlog_dir, S_IRWXU) != 0)
3407  {
3408  fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"),
3409  progname, xlog_dir, strerror(errno));
3410  exit_nicely();
3411  }
3412  else
3413  check_ok();
3414 
3415  found_existing_xlogdir = true;
3416  break;
3417 
3418  case 2:
3419  case 3:
3420  case 4:
3421  /* Present and not empty */
3422  fprintf(stderr,
3423  _("%s: directory \"%s\" exists but is not empty\n"),
3424  progname, xlog_dir);
3425  if (ret != 4)
3426  warn_on_mount_point(ret);
3427  else
3428  fprintf(stderr,
3429  _("If you want to store the transaction log there, either\n"
3430  "remove or empty the directory \"%s\".\n"),
3431  xlog_dir);
3432  exit_nicely();
3433 
3434  default:
3435  /* Trouble accessing directory */
3436  fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"),
3437  progname, xlog_dir, strerror(errno));
3438  exit_nicely();
3439  }
3440 
3441  /* form name of the place where the symlink must go */
3442  linkloc = psprintf("%s/pg_xlog", pg_data);
3443 
3444 #ifdef HAVE_SYMLINK
3445  if (symlink(xlog_dir, linkloc) != 0)
3446  {
3447  fprintf(stderr, _("%s: could not create symbolic link \"%s\": %s\n"),
3448  progname, linkloc, strerror(errno));
3449  exit_nicely();
3450  }
3451 #else
3452  fprintf(stderr, _("%s: symlinks are not supported on this platform"));
3453  exit_nicely();
3454 #endif
3455  free(linkloc);
3456  }
3457 }
3458 
3459 
3460 void
3462 {
3463  if (error == 2)
3464  fprintf(stderr,
3465  _("It contains a dot-prefixed/invisible file, perhaps due to it being a mount point.\n"));
3466  else if (error == 3)
3467  fprintf(stderr,
3468  _("It contains a lost+found directory, perhaps due to it being a mount point.\n"));
3469 
3470  fprintf(stderr,
3471  _("Using a mount point directly as the data directory is not recommended.\n"
3472  "Create a subdirectory under the mount point.\n"));
3473 }
3474 
3475 
3476 void
3478 {
3479  int i;
3480 
3481  setup_signals();
3482 
3483  umask(S_IRWXG | S_IRWXO);
3484 
3486 
3488 
3489  /* Create required subdirectories */
3490  printf(_("creating subdirectories ... "));
3491  fflush(stdout);
3492 
3493  for (i = 0; i < (sizeof(subdirs) / sizeof(char *)); i++)
3494  {
3495  if (!mkdatadir(subdirs[i]))
3496  exit_nicely();
3497  }
3498 
3499  check_ok();
3500 
3501  /* Top level PG_VERSION is checked by bootstrapper, so make it first */
3503 
3504  /* Select suitable configuration settings */
3505  set_null_conf();
3507 
3508  /* Now create all the text config files */
3509  setup_config();
3510 
3511  /* Bootstrap template1 */
3513 
3514  /*
3515  * Make the per-database PG_VERSION for template1 only after init'ing it
3516  */
3517  write_version_file("base/1");
3518 
3519  /* Create the stuff we don't need to use bootstrap mode for */
3520 
3521  setup_auth();
3522  if (pwprompt || pwfilename)
3523  get_set_pwd();
3524 
3525  setup_depend();
3526 
3527  setup_sysviews();
3528 
3530 
3531  setup_collation();
3532 
3533  setup_conversion();
3534 
3535  setup_dictionary();
3536 
3537  setup_privileges();
3538 
3539  setup_schema();
3540 
3541  load_plpgsql();
3542 
3543  vacuum_db();
3544 
3545  make_template0();
3546 
3547  make_postgres();
3548 }
3549 
3550 
3551 int
3552 main(int argc, char *argv[])
3553 {
3554  static struct option long_options[] = {
3555  {"pgdata", required_argument, NULL, 'D'},
3556  {"encoding", required_argument, NULL, 'E'},
3557  {"locale", required_argument, NULL, 1},
3558  {"lc-collate", required_argument, NULL, 2},
3559  {"lc-ctype", required_argument, NULL, 3},
3560  {"lc-monetary", required_argument, NULL, 4},
3561  {"lc-numeric", required_argument, NULL, 5},
3562  {"lc-time", required_argument, NULL, 6},
3563  {"lc-messages", required_argument, NULL, 7},
3564  {"no-locale", no_argument, NULL, 8},
3565  {"text-search-config", required_argument, NULL, 'T'},
3566  {"auth", required_argument, NULL, 'A'},
3567  {"auth-local", required_argument, NULL, 10},
3568  {"auth-host", required_argument, NULL, 11},
3569  {"pwprompt", no_argument, NULL, 'W'},
3570  {"pwfile", required_argument, NULL, 9},
3571  {"username", required_argument, NULL, 'U'},
3572  {"help", no_argument, NULL, '?'},
3573  {"version", no_argument, NULL, 'V'},
3574  {"debug", no_argument, NULL, 'd'},
3575  {"show", no_argument, NULL, 's'},
3576  {"noclean", no_argument, NULL, 'n'},
3577  {"nosync", no_argument, NULL, 'N'},
3578  {"sync-only", no_argument, NULL, 'S'},
3579  {"xlogdir", required_argument, NULL, 'X'},
3580  {"data-checksums", no_argument, NULL, 'k'},
3581  {NULL, 0, NULL, 0}
3582  };
3583 
3584  /*
3585  * options with no short version return a low integer, the rest return
3586  * their short version value
3587  */
3588  int c;
3589  int option_index;
3590  char *effective_user;
3591  char bin_dir[MAXPGPATH];
3592 
3593  /*
3594  * Ensure that buffering behavior of stdout and stderr matches what it is
3595  * in interactive usage (at least on most platforms). This prevents
3596  * unexpected output ordering when, eg, output is redirected to a file.
3597  * POSIX says we must do this before any other usage of these files.
3598  */
3599  setvbuf(stdout, NULL, PG_IOLBF, 0);
3600  setvbuf(stderr, NULL, _IONBF, 0);
3601 
3602  progname = get_progname(argv[0]);
3603  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("initdb"));
3604 
3605  if (argc > 1)
3606  {
3607  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
3608  {
3609  usage(progname);
3610  exit(0);
3611  }
3612  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
3613  {
3614  puts("initdb (PostgreSQL) " PG_VERSION);
3615  exit(0);
3616  }
3617  }
3618 
3619  /* process command-line options */
3620 
3621  while ((c = getopt_long(argc, argv, "dD:E:kL:nNU:WA:sST:X:", long_options, &option_index)) != -1)
3622  {
3623  switch (c)
3624  {
3625  case 'A':
3627 
3628  /*
3629  * When ident is specified, use peer for local connections.
3630  * Mirrored, when peer is specified, use ident for TCP/IP
3631  * connections.
3632  */
3633  if (strcmp(authmethodhost, "ident") == 0)
3634  authmethodlocal = "peer";
3635  else if (strcmp(authmethodlocal, "peer") == 0)
3636  authmethodhost = "ident";
3637  break;
3638  case 10:
3640  break;
3641  case 11:
3643  break;
3644  case 'D':
3646  break;
3647  case 'E':
3649  break;
3650  case 'W':
3651  pwprompt = true;
3652  break;
3653  case 'U':
3655  break;
3656  case 'd':
3657  debug = true;
3658  printf(_("Running in debug mode.\n"));
3659  break;
3660  case 'n':
3661  noclean = true;
3662  printf(_("Running in noclean mode. Mistakes will not be cleaned up.\n"));
3663  break;
3664  case 'N':
3665  do_sync = false;
3666  break;
3667  case 'S':
3668  sync_only = true;
3669  break;
3670  case 'k':
3671  data_checksums = true;
3672  break;
3673  case 'L':
3675  break;
3676  case 1:
3677  locale = pg_strdup(optarg);
3678  break;
3679  case 2:
3681  break;
3682  case 3:
3684  break;
3685  case 4:
3687  break;
3688  case 5:
3690  break;
3691  case 6:
3693  break;
3694  case 7:
3696  break;
3697  case 8:
3698  locale = "C";
3699  break;
3700  case 9:
3702  break;
3703  case 's':
3704  show_setting = true;
3705  break;
3706  case 'T':
3708  break;
3709  case 'X':
3711  break;
3712  default:
3713  /* getopt_long already emitted a complaint */
3714  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
3715  progname);
3716  exit(1);
3717  }
3718  }
3719 
3720 
3721  /*
3722  * Non-option argument specifies data directory as long as it wasn't
3723  * already specified with -D / --pgdata
3724  */
3725  if (optind < argc && strlen(pg_data) == 0)
3726  {
3727  pg_data = pg_strdup(argv[optind]);
3728  optind++;
3729  }
3730 
3731  if (optind < argc)
3732  {
3733  fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
3734  progname, argv[optind]);
3735  fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
3736  progname);
3737  exit(1);
3738  }
3739 
3740  /* If we only need to fsync, just to it and exit */
3741  if (sync_only)
3742  {
3743  setup_pgdata();
3744  perform_fsync();
3745  return 0;
3746  }
3747 
3748  if (pwprompt && pwfilename)
3749  {
3750  fprintf(stderr, _("%s: password prompt and password file cannot be specified together\n"), progname);
3751  exit(1);
3752  }
3753 
3756 
3759 
3761 
3763 
3764  setup_pgdata();
3765 
3766  setup_bin_paths(argv[0]);
3767 
3768  effective_user = get_id();
3769  if (strlen(username) == 0)
3770  username = effective_user;
3771 
3772  printf(_("The files belonging to this database system will be owned "
3773  "by user \"%s\".\n"
3774  "This user must also own the server process.\n\n"),
3775  effective_user);
3776 
3777  set_info_version();
3778 
3780 
3782 
3784 
3785  printf("\n");
3786 
3787  if (data_checksums)
3788  printf(_("Data page checksums are enabled.\n"));
3789  else
3790  printf(_("Data page checksums are disabled.\n"));
3791 
3792  printf("\n");
3793 
3795 
3796  if (do_sync)
3797  perform_fsync();
3798  else
3799  printf(_("\nSync to disk skipped.\nThe data directory might become corrupt if the operating system crashes.\n"));
3800 
3801  if (authwarning != NULL)
3802  fprintf(stderr, "%s", authwarning);
3803 
3804  /* Get directory specification used to start this executable */
3805  strlcpy(bin_dir, argv[0], sizeof(bin_dir));
3806  get_parent_directory(bin_dir);
3807 
3808  printf(_("\nSuccess. You can now start the database server using:\n\n"
3809  " %s%s%spostgres%s -D %s%s%s\n"
3810  "or\n"
3811  " %s%s%spg_ctl%s -D %s%s%s -l logfile start\n\n"),
3812  QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
3814  QUOTE_PATH, bin_dir, (strlen(bin_dir) > 0) ? DIR_SEP : "", QUOTE_PATH,
3816 
3817  return 0;
3818 }