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