PageRenderTime 55ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/bin/initdb/initdb.c

http://github.com/postgres/postgres
C | 3303 lines | 2375 code | 413 blank | 515 comment | 325 complexity | 2263fc154151ddf70e80be55d63f1004 MD5 | raw file
Possible License(s): AGPL-3.0

Large files files are truncated, but you can click here to view the full 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-2020, 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. #include "postgres_fe.h"
  49. #include <dirent.h>
  50. #include <fcntl.h>
  51. #include <sys/stat.h>
  52. #include <unistd.h>
  53. #include <signal.h>
  54. #include <time.h>
  55. #ifdef HAVE_SHM_OPEN
  56. #include "sys/mman.h"
  57. #endif
  58. #include "access/xlog_internal.h"
  59. #include "catalog/pg_authid_d.h"
  60. #include "catalog/pg_class_d.h" /* pgrminclude ignore */
  61. #include "catalog/pg_collation_d.h"
  62. #include "common/file_perm.h"
  63. #include "common/file_utils.h"
  64. #include "common/logging.h"
  65. #include "common/restricted_token.h"
  66. #include "common/username.h"
  67. #include "fe_utils/string_utils.h"
  68. #include "getaddrinfo.h"
  69. #include "getopt_long.h"
  70. #include "mb/pg_wchar.h"
  71. #include "miscadmin.h"
  72. /* Ideally this would be in a .h file, but it hardly seems worth the trouble */
  73. extern const char *select_default_timezone(const char *share_path);
  74. static const char *const auth_methods_host[] = {
  75. "trust", "reject", "scram-sha-256", "md5", "password", "ident", "radius",
  76. #ifdef ENABLE_GSS
  77. "gss",
  78. #endif
  79. #ifdef ENABLE_SSPI
  80. "sspi",
  81. #endif
  82. #ifdef USE_PAM
  83. "pam", "pam ",
  84. #endif
  85. #ifdef USE_BSD_AUTH
  86. "bsd",
  87. #endif
  88. #ifdef USE_LDAP
  89. "ldap",
  90. #endif
  91. #ifdef USE_SSL
  92. "cert",
  93. #endif
  94. NULL
  95. };
  96. static const char *const auth_methods_local[] = {
  97. "trust", "reject", "scram-sha-256", "md5", "password", "peer", "radius",
  98. #ifdef USE_PAM
  99. "pam", "pam ",
  100. #endif
  101. #ifdef USE_BSD_AUTH
  102. "bsd",
  103. #endif
  104. #ifdef USE_LDAP
  105. "ldap",
  106. #endif
  107. NULL
  108. };
  109. /*
  110. * these values are passed in by makefile defines
  111. */
  112. static char *share_path = NULL;
  113. /* values to be obtained from arguments */
  114. static char *pg_data = NULL;
  115. static char *encoding = NULL;
  116. static char *locale = NULL;
  117. static char *lc_collate = NULL;
  118. static char *lc_ctype = NULL;
  119. static char *lc_monetary = NULL;
  120. static char *lc_numeric = NULL;
  121. static char *lc_time = NULL;
  122. static char *lc_messages = NULL;
  123. static const char *default_text_search_config = NULL;
  124. static char *username = NULL;
  125. static bool pwprompt = false;
  126. static char *pwfilename = NULL;
  127. static char *superuser_password = NULL;
  128. static const char *authmethodhost = NULL;
  129. static const char *authmethodlocal = NULL;
  130. static bool debug = false;
  131. static bool noclean = false;
  132. static bool do_sync = true;
  133. static bool sync_only = false;
  134. static bool show_setting = false;
  135. static bool data_checksums = false;
  136. static char *xlog_dir = NULL;
  137. static char *str_wal_segment_size_mb = NULL;
  138. static int wal_segment_size_mb;
  139. /* internal vars */
  140. static const char *progname;
  141. static int encodingid;
  142. static char *bki_file;
  143. static char *hba_file;
  144. static char *ident_file;
  145. static char *conf_file;
  146. static char *dictionary_file;
  147. static char *info_schema_file;
  148. static char *features_file;
  149. static char *system_views_file;
  150. static bool success = false;
  151. static bool made_new_pgdata = false;
  152. static bool found_existing_pgdata = false;
  153. static bool made_new_xlogdir = false;
  154. static bool found_existing_xlogdir = false;
  155. static char infoversion[100];
  156. static bool caught_signal = false;
  157. static bool output_failed = false;
  158. static int output_errno = 0;
  159. static char *pgdata_native;
  160. /* defaults */
  161. static int n_connections = 10;
  162. static int n_buffers = 50;
  163. static const char *dynamic_shared_memory_type = NULL;
  164. static const char *default_timezone = NULL;
  165. /*
  166. * Warning messages for authentication methods
  167. */
  168. #define AUTHTRUST_WARNING \
  169. "# CAUTION: Configuring the system for local \"trust\" authentication\n" \
  170. "# allows any local user to connect as any PostgreSQL user, including\n" \
  171. "# the database superuser. If you do not trust all your local users,\n" \
  172. "# use another authentication method.\n"
  173. static bool authwarning = false;
  174. /*
  175. * Centralized knowledge of switches to pass to backend
  176. *
  177. * Note: we run the backend with -F (fsync disabled) and then do a single
  178. * pass of fsync'ing at the end. This is faster than fsync'ing each step.
  179. *
  180. * Note: in the shell-script version, we also passed PGDATA as a -D switch,
  181. * but here it is more convenient to pass it as an environment variable
  182. * (no quoting to worry about).
  183. */
  184. static const char *boot_options = "-F";
  185. static const char *backend_options = "--single -F -O -j -c search_path=pg_catalog -c exit_on_error=true";
  186. static const char *const subdirs[] = {
  187. "global",
  188. "pg_wal/archive_status",
  189. "pg_commit_ts",
  190. "pg_dynshmem",
  191. "pg_notify",
  192. "pg_serial",
  193. "pg_snapshots",
  194. "pg_subtrans",
  195. "pg_twophase",
  196. "pg_multixact",
  197. "pg_multixact/members",
  198. "pg_multixact/offsets",
  199. "base",
  200. "base/1",
  201. "pg_replslot",
  202. "pg_tblspc",
  203. "pg_stat",
  204. "pg_stat_tmp",
  205. "pg_xact",
  206. "pg_logical",
  207. "pg_logical/snapshots",
  208. "pg_logical/mappings"
  209. };
  210. /* path to 'initdb' binary directory */
  211. static char bin_path[MAXPGPATH];
  212. static char backend_exec[MAXPGPATH];
  213. static char **replace_token(char **lines,
  214. const char *token, const char *replacement);
  215. #ifndef HAVE_UNIX_SOCKETS
  216. static char **filter_lines_with_token(char **lines, const char *token);
  217. #endif
  218. static char **readfile(const char *path);
  219. static void writefile(char *path, char **lines);
  220. static FILE *popen_check(const char *command, const char *mode);
  221. static char *get_id(void);
  222. static int get_encoding_id(const char *encoding_name);
  223. static void set_input(char **dest, const char *filename);
  224. static void check_input(char *path);
  225. static void write_version_file(const char *extrapath);
  226. static void set_null_conf(void);
  227. static void test_config_settings(void);
  228. static void setup_config(void);
  229. static void bootstrap_template1(void);
  230. static void setup_auth(FILE *cmdfd);
  231. static void get_su_pwd(void);
  232. static void setup_depend(FILE *cmdfd);
  233. static void setup_sysviews(FILE *cmdfd);
  234. static void setup_description(FILE *cmdfd);
  235. static void setup_collation(FILE *cmdfd);
  236. static void setup_dictionary(FILE *cmdfd);
  237. static void setup_privileges(FILE *cmdfd);
  238. static void set_info_version(void);
  239. static void setup_schema(FILE *cmdfd);
  240. static void load_plpgsql(FILE *cmdfd);
  241. static void vacuum_db(FILE *cmdfd);
  242. static void make_template0(FILE *cmdfd);
  243. static void make_postgres(FILE *cmdfd);
  244. static void trapsig(int signum);
  245. static void check_ok(void);
  246. static char *escape_quotes(const char *src);
  247. static char *escape_quotes_bki(const char *src);
  248. static int locale_date_order(const char *locale);
  249. static void check_locale_name(int category, const char *locale,
  250. char **canonname);
  251. static bool check_locale_encoding(const char *locale, int encoding);
  252. static void setlocales(void);
  253. static void usage(const char *progname);
  254. void setup_pgdata(void);
  255. void setup_bin_paths(const char *argv0);
  256. void setup_data_file_paths(void);
  257. void setup_locale_encoding(void);
  258. void setup_signals(void);
  259. void setup_text_search(void);
  260. void create_data_directory(void);
  261. void create_xlog_or_symlink(void);
  262. void warn_on_mount_point(int error);
  263. void initialize_data_directory(void);
  264. /*
  265. * macros for running pipes to postgres
  266. */
  267. #define PG_CMD_DECL char cmd[MAXPGPATH]; FILE *cmdfd
  268. #define PG_CMD_OPEN \
  269. do { \
  270. cmdfd = popen_check(cmd, "w"); \
  271. if (cmdfd == NULL) \
  272. exit(1); /* message already printed by popen_check */ \
  273. } while (0)
  274. #define PG_CMD_CLOSE \
  275. do { \
  276. if (pclose_check(cmdfd)) \
  277. exit(1); /* message already printed by pclose_check */ \
  278. } while (0)
  279. #define PG_CMD_PUTS(line) \
  280. do { \
  281. if (fputs(line, cmdfd) < 0 || fflush(cmdfd) < 0) \
  282. output_failed = true, output_errno = errno; \
  283. } while (0)
  284. #define PG_CMD_PRINTF(fmt, ...) \
  285. do { \
  286. if (fprintf(cmdfd, fmt, __VA_ARGS__) < 0 || fflush(cmdfd) < 0) \
  287. output_failed = true, output_errno = errno; \
  288. } while (0)
  289. /*
  290. * Escape single quotes and backslashes, suitably for insertions into
  291. * configuration files or SQL E'' strings.
  292. */
  293. static char *
  294. escape_quotes(const char *src)
  295. {
  296. char *result = escape_single_quotes_ascii(src);
  297. if (!result)
  298. {
  299. pg_log_error("out of memory");
  300. exit(1);
  301. }
  302. return result;
  303. }
  304. /*
  305. * Escape a field value to be inserted into the BKI data.
  306. * Here, we first run the value through escape_quotes (which
  307. * will be inverted by the backend's scanstr() function) and
  308. * then overlay special processing of double quotes, which
  309. * bootscanner.l will only accept as data if converted to octal
  310. * representation ("\042"). We always wrap the value in double
  311. * quotes, even if that isn't strictly necessary.
  312. */
  313. static char *
  314. escape_quotes_bki(const char *src)
  315. {
  316. char *result;
  317. char *data = escape_quotes(src);
  318. char *resultp;
  319. char *datap;
  320. int nquotes = 0;
  321. /* count double quotes in data */
  322. datap = data;
  323. while ((datap = strchr(datap, '"')) != NULL)
  324. {
  325. nquotes++;
  326. datap++;
  327. }
  328. result = (char *) pg_malloc(strlen(data) + 3 + nquotes * 3);
  329. resultp = result;
  330. *resultp++ = '"';
  331. for (datap = data; *datap; datap++)
  332. {
  333. if (*datap == '"')
  334. {
  335. strcpy(resultp, "\\042");
  336. resultp += 4;
  337. }
  338. else
  339. *resultp++ = *datap;
  340. }
  341. *resultp++ = '"';
  342. *resultp = '\0';
  343. free(data);
  344. return result;
  345. }
  346. /*
  347. * make a copy of the array of lines, with token replaced by replacement
  348. * the first time it occurs on each line.
  349. *
  350. * This does most of what sed was used for in the shell script, but
  351. * doesn't need any regexp stuff.
  352. */
  353. static char **
  354. replace_token(char **lines, const char *token, const char *replacement)
  355. {
  356. int numlines = 1;
  357. int i;
  358. char **result;
  359. int toklen,
  360. replen,
  361. diff;
  362. for (i = 0; lines[i]; i++)
  363. numlines++;
  364. result = (char **) pg_malloc(numlines * sizeof(char *));
  365. toklen = strlen(token);
  366. replen = strlen(replacement);
  367. diff = replen - toklen;
  368. for (i = 0; i < numlines; i++)
  369. {
  370. char *where;
  371. char *newline;
  372. int pre;
  373. /* just copy pointer if NULL or no change needed */
  374. if (lines[i] == NULL || (where = strstr(lines[i], token)) == NULL)
  375. {
  376. result[i] = lines[i];
  377. continue;
  378. }
  379. /* if we get here a change is needed - set up new line */
  380. newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1);
  381. pre = where - lines[i];
  382. memcpy(newline, lines[i], pre);
  383. memcpy(newline + pre, replacement, replen);
  384. strcpy(newline + pre + replen, lines[i] + pre + toklen);
  385. result[i] = newline;
  386. }
  387. return result;
  388. }
  389. /*
  390. * make a copy of lines without any that contain the token
  391. *
  392. * a sort of poor man's grep -v
  393. */
  394. #ifndef HAVE_UNIX_SOCKETS
  395. static char **
  396. filter_lines_with_token(char **lines, const char *token)
  397. {
  398. int numlines = 1;
  399. int i,
  400. src,
  401. dst;
  402. char **result;
  403. for (i = 0; lines[i]; i++)
  404. numlines++;
  405. result = (char **) pg_malloc(numlines * sizeof(char *));
  406. for (src = 0, dst = 0; src < numlines; src++)
  407. {
  408. if (lines[src] == NULL || strstr(lines[src], token) == NULL)
  409. result[dst++] = lines[src];
  410. }
  411. return result;
  412. }
  413. #endif
  414. /*
  415. * get the lines from a text file
  416. */
  417. static char **
  418. readfile(const char *path)
  419. {
  420. FILE *infile;
  421. int maxlength = 1,
  422. linelen = 0;
  423. int nlines = 0;
  424. int n;
  425. char **result;
  426. char *buffer;
  427. int c;
  428. if ((infile = fopen(path, "r")) == NULL)
  429. {
  430. pg_log_error("could not open file \"%s\" for reading: %m", path);
  431. exit(1);
  432. }
  433. /* pass over the file twice - the first time to size the result */
  434. while ((c = fgetc(infile)) != EOF)
  435. {
  436. linelen++;
  437. if (c == '\n')
  438. {
  439. nlines++;
  440. if (linelen > maxlength)
  441. maxlength = linelen;
  442. linelen = 0;
  443. }
  444. }
  445. /* handle last line without a terminating newline (yuck) */
  446. if (linelen)
  447. nlines++;
  448. if (linelen > maxlength)
  449. maxlength = linelen;
  450. /* set up the result and the line buffer */
  451. result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
  452. buffer = (char *) pg_malloc(maxlength + 1);
  453. /* now reprocess the file and store the lines */
  454. rewind(infile);
  455. n = 0;
  456. while (fgets(buffer, maxlength + 1, infile) != NULL && n < nlines)
  457. result[n++] = pg_strdup(buffer);
  458. fclose(infile);
  459. free(buffer);
  460. result[n] = NULL;
  461. return result;
  462. }
  463. /*
  464. * write an array of lines to a file
  465. *
  466. * This is only used to write text files. Use fopen "w" not PG_BINARY_W
  467. * so that the resulting configuration files are nicely editable on Windows.
  468. */
  469. static void
  470. writefile(char *path, char **lines)
  471. {
  472. FILE *out_file;
  473. char **line;
  474. if ((out_file = fopen(path, "w")) == NULL)
  475. {
  476. pg_log_error("could not open file \"%s\" for writing: %m", path);
  477. exit(1);
  478. }
  479. for (line = lines; *line != NULL; line++)
  480. {
  481. if (fputs(*line, out_file) < 0)
  482. {
  483. pg_log_error("could not write file \"%s\": %m", path);
  484. exit(1);
  485. }
  486. free(*line);
  487. }
  488. if (fclose(out_file))
  489. {
  490. pg_log_error("could not write file \"%s\": %m", path);
  491. exit(1);
  492. }
  493. }
  494. /*
  495. * Open a subcommand with suitable error messaging
  496. */
  497. static FILE *
  498. popen_check(const char *command, const char *mode)
  499. {
  500. FILE *cmdfd;
  501. fflush(stdout);
  502. fflush(stderr);
  503. errno = 0;
  504. cmdfd = popen(command, mode);
  505. if (cmdfd == NULL)
  506. pg_log_error("could not execute command \"%s\": %m", command);
  507. return cmdfd;
  508. }
  509. /*
  510. * clean up any files we created on failure
  511. * if we created the data directory remove it too
  512. */
  513. static void
  514. cleanup_directories_atexit(void)
  515. {
  516. if (success)
  517. return;
  518. if (!noclean)
  519. {
  520. if (made_new_pgdata)
  521. {
  522. pg_log_info("removing data directory \"%s\"", pg_data);
  523. if (!rmtree(pg_data, true))
  524. pg_log_error("failed to remove data directory");
  525. }
  526. else if (found_existing_pgdata)
  527. {
  528. pg_log_info("removing contents of data directory \"%s\"",
  529. pg_data);
  530. if (!rmtree(pg_data, false))
  531. pg_log_error("failed to remove contents of data directory");
  532. }
  533. if (made_new_xlogdir)
  534. {
  535. pg_log_info("removing WAL directory \"%s\"", xlog_dir);
  536. if (!rmtree(xlog_dir, true))
  537. pg_log_error("failed to remove WAL directory");
  538. }
  539. else if (found_existing_xlogdir)
  540. {
  541. pg_log_info("removing contents of WAL directory \"%s\"", xlog_dir);
  542. if (!rmtree(xlog_dir, false))
  543. pg_log_error("failed to remove contents of WAL directory");
  544. }
  545. /* otherwise died during startup, do nothing! */
  546. }
  547. else
  548. {
  549. if (made_new_pgdata || found_existing_pgdata)
  550. pg_log_info("data directory \"%s\" not removed at user's request",
  551. pg_data);
  552. if (made_new_xlogdir || found_existing_xlogdir)
  553. pg_log_info("WAL directory \"%s\" not removed at user's request",
  554. xlog_dir);
  555. }
  556. }
  557. /*
  558. * find the current user
  559. *
  560. * on unix make sure it isn't root
  561. */
  562. static char *
  563. get_id(void)
  564. {
  565. const char *username;
  566. #ifndef WIN32
  567. if (geteuid() == 0) /* 0 is root's uid */
  568. {
  569. pg_log_error("cannot be run as root");
  570. fprintf(stderr,
  571. _("Please log in (using, e.g., \"su\") as the (unprivileged) user that will\n"
  572. "own the server process.\n"));
  573. exit(1);
  574. }
  575. #endif
  576. username = get_user_name_or_exit(progname);
  577. return pg_strdup(username);
  578. }
  579. static char *
  580. encodingid_to_string(int enc)
  581. {
  582. char result[20];
  583. sprintf(result, "%d", enc);
  584. return pg_strdup(result);
  585. }
  586. /*
  587. * get the encoding id for a given encoding name
  588. */
  589. static int
  590. get_encoding_id(const char *encoding_name)
  591. {
  592. int enc;
  593. if (encoding_name && *encoding_name)
  594. {
  595. if ((enc = pg_valid_server_encoding(encoding_name)) >= 0)
  596. return enc;
  597. }
  598. pg_log_error("\"%s\" is not a valid server encoding name",
  599. encoding_name ? encoding_name : "(null)");
  600. exit(1);
  601. }
  602. /*
  603. * Support for determining the best default text search configuration.
  604. * We key this off the first part of LC_CTYPE (ie, the language name).
  605. */
  606. struct tsearch_config_match
  607. {
  608. const char *tsconfname;
  609. const char *langname;
  610. };
  611. static const struct tsearch_config_match tsearch_config_languages[] =
  612. {
  613. {"arabic", "ar"},
  614. {"arabic", "Arabic"},
  615. {"danish", "da"},
  616. {"danish", "Danish"},
  617. {"dutch", "nl"},
  618. {"dutch", "Dutch"},
  619. {"english", "C"},
  620. {"english", "POSIX"},
  621. {"english", "en"},
  622. {"english", "English"},
  623. {"finnish", "fi"},
  624. {"finnish", "Finnish"},
  625. {"french", "fr"},
  626. {"french", "French"},
  627. {"german", "de"},
  628. {"german", "German"},
  629. {"greek", "el"},
  630. {"greek", "Greek"},
  631. {"hungarian", "hu"},
  632. {"hungarian", "Hungarian"},
  633. {"indonesian", "id"},
  634. {"indonesian", "Indonesian"},
  635. {"irish", "ga"},
  636. {"irish", "Irish"},
  637. {"italian", "it"},
  638. {"italian", "Italian"},
  639. {"lithuanian", "lt"},
  640. {"lithuanian", "Lithuanian"},
  641. {"nepali", "ne"},
  642. {"nepali", "Nepali"},
  643. {"norwegian", "no"},
  644. {"norwegian", "Norwegian"},
  645. {"portuguese", "pt"},
  646. {"portuguese", "Portuguese"},
  647. {"romanian", "ro"},
  648. {"russian", "ru"},
  649. {"russian", "Russian"},
  650. {"spanish", "es"},
  651. {"spanish", "Spanish"},
  652. {"swedish", "sv"},
  653. {"swedish", "Swedish"},
  654. {"tamil", "ta"},
  655. {"tamil", "Tamil"},
  656. {"turkish", "tr"},
  657. {"turkish", "Turkish"},
  658. {NULL, NULL} /* end marker */
  659. };
  660. /*
  661. * Look for a text search configuration matching lc_ctype, and return its
  662. * name; return NULL if no match.
  663. */
  664. static const char *
  665. find_matching_ts_config(const char *lc_type)
  666. {
  667. int i;
  668. char *langname,
  669. *ptr;
  670. /*
  671. * Convert lc_ctype to a language name by stripping everything after an
  672. * underscore (usual case) or a hyphen (Windows "locale name"; see
  673. * comments at IsoLocaleName()).
  674. *
  675. * XXX Should ' ' be a stop character? This would select "norwegian" for
  676. * the Windows locale "Norwegian (Nynorsk)_Norway.1252". If we do so, we
  677. * should also accept the "nn" and "nb" Unix locales.
  678. *
  679. * Just for paranoia, we also stop at '.' or '@'.
  680. */
  681. if (lc_type == NULL)
  682. langname = pg_strdup("");
  683. else
  684. {
  685. ptr = langname = pg_strdup(lc_type);
  686. while (*ptr &&
  687. *ptr != '_' && *ptr != '-' && *ptr != '.' && *ptr != '@')
  688. ptr++;
  689. *ptr = '\0';
  690. }
  691. for (i = 0; tsearch_config_languages[i].tsconfname; i++)
  692. {
  693. if (pg_strcasecmp(tsearch_config_languages[i].langname, langname) == 0)
  694. {
  695. free(langname);
  696. return tsearch_config_languages[i].tsconfname;
  697. }
  698. }
  699. free(langname);
  700. return NULL;
  701. }
  702. /*
  703. * set name of given input file variable under data directory
  704. */
  705. static void
  706. set_input(char **dest, const char *filename)
  707. {
  708. *dest = psprintf("%s/%s", share_path, filename);
  709. }
  710. /*
  711. * check that given input file exists
  712. */
  713. static void
  714. check_input(char *path)
  715. {
  716. struct stat statbuf;
  717. if (stat(path, &statbuf) != 0)
  718. {
  719. if (errno == ENOENT)
  720. {
  721. pg_log_error("file \"%s\" does not exist", path);
  722. fprintf(stderr,
  723. _("This might mean you have a corrupted installation or identified\n"
  724. "the wrong directory with the invocation option -L.\n"));
  725. }
  726. else
  727. {
  728. pg_log_error("could not access file \"%s\": %m", path);
  729. fprintf(stderr,
  730. _("This might mean you have a corrupted installation or identified\n"
  731. "the wrong directory with the invocation option -L.\n"));
  732. }
  733. exit(1);
  734. }
  735. if (!S_ISREG(statbuf.st_mode))
  736. {
  737. pg_log_error("file \"%s\" is not a regular file", path);
  738. fprintf(stderr,
  739. _("This might mean you have a corrupted installation or identified\n"
  740. "the wrong directory with the invocation option -L.\n"));
  741. exit(1);
  742. }
  743. }
  744. /*
  745. * write out the PG_VERSION file in the data dir, or its subdirectory
  746. * if extrapath is not NULL
  747. */
  748. static void
  749. write_version_file(const char *extrapath)
  750. {
  751. FILE *version_file;
  752. char *path;
  753. if (extrapath == NULL)
  754. path = psprintf("%s/PG_VERSION", pg_data);
  755. else
  756. path = psprintf("%s/%s/PG_VERSION", pg_data, extrapath);
  757. if ((version_file = fopen(path, PG_BINARY_W)) == NULL)
  758. {
  759. pg_log_error("could not open file \"%s\" for writing: %m", path);
  760. exit(1);
  761. }
  762. if (fprintf(version_file, "%s\n", PG_MAJORVERSION) < 0 ||
  763. fclose(version_file))
  764. {
  765. pg_log_error("could not write file \"%s\": %m", path);
  766. exit(1);
  767. }
  768. free(path);
  769. }
  770. /*
  771. * set up an empty config file so we can check config settings by launching
  772. * a test backend
  773. */
  774. static void
  775. set_null_conf(void)
  776. {
  777. FILE *conf_file;
  778. char *path;
  779. path = psprintf("%s/postgresql.conf", pg_data);
  780. conf_file = fopen(path, PG_BINARY_W);
  781. if (conf_file == NULL)
  782. {
  783. pg_log_error("could not open file \"%s\" for writing: %m", path);
  784. exit(1);
  785. }
  786. if (fclose(conf_file))
  787. {
  788. pg_log_error("could not write file \"%s\": %m", path);
  789. exit(1);
  790. }
  791. free(path);
  792. }
  793. /*
  794. * Determine which dynamic shared memory implementation should be used on
  795. * this platform. POSIX shared memory is preferable because the default
  796. * allocation limits are much higher than the limits for System V on most
  797. * systems that support both, but the fact that a platform has shm_open
  798. * doesn't guarantee that that call will succeed when attempted. So, we
  799. * attempt to reproduce what the postmaster will do when allocating a POSIX
  800. * segment in dsm_impl.c; if it doesn't work, we assume it won't work for
  801. * the postmaster either, and configure the cluster for System V shared
  802. * memory instead.
  803. */
  804. static const char *
  805. choose_dsm_implementation(void)
  806. {
  807. #ifdef HAVE_SHM_OPEN
  808. int ntries = 10;
  809. /* Initialize random(); this function is its only user in this program. */
  810. srandom((unsigned int) (getpid() ^ time(NULL)));
  811. while (ntries > 0)
  812. {
  813. uint32 handle;
  814. char name[64];
  815. int fd;
  816. handle = random();
  817. snprintf(name, 64, "/PostgreSQL.%u", handle);
  818. if ((fd = shm_open(name, O_CREAT | O_RDWR | O_EXCL, 0600)) != -1)
  819. {
  820. close(fd);
  821. shm_unlink(name);
  822. return "posix";
  823. }
  824. if (errno != EEXIST)
  825. break;
  826. --ntries;
  827. }
  828. #endif
  829. #ifdef WIN32
  830. return "windows";
  831. #else
  832. return "sysv";
  833. #endif
  834. }
  835. /*
  836. * Determine platform-specific config settings
  837. *
  838. * Use reasonable values if kernel will let us, else scale back.
  839. */
  840. static void
  841. test_config_settings(void)
  842. {
  843. /*
  844. * This macro defines the minimum shared_buffers we want for a given
  845. * max_connections value. The arrays show the settings to try.
  846. */
  847. #define MIN_BUFS_FOR_CONNS(nconns) ((nconns) * 10)
  848. static const int trial_conns[] = {
  849. 100, 50, 40, 30, 20
  850. };
  851. static const int trial_bufs[] = {
  852. 16384, 8192, 4096, 3584, 3072, 2560, 2048, 1536,
  853. 1000, 900, 800, 700, 600, 500,
  854. 400, 300, 200, 100, 50
  855. };
  856. char cmd[MAXPGPATH];
  857. const int connslen = sizeof(trial_conns) / sizeof(int);
  858. const int bufslen = sizeof(trial_bufs) / sizeof(int);
  859. int i,
  860. status,
  861. test_conns,
  862. test_buffs,
  863. ok_buffers = 0;
  864. /*
  865. * Need to determine working DSM implementation first so that subsequent
  866. * tests don't fail because DSM setting doesn't work.
  867. */
  868. printf(_("selecting dynamic shared memory implementation ... "));
  869. fflush(stdout);
  870. dynamic_shared_memory_type = choose_dsm_implementation();
  871. printf("%s\n", dynamic_shared_memory_type);
  872. /*
  873. * Probe for max_connections before shared_buffers, since it is subject to
  874. * more constraints than shared_buffers.
  875. */
  876. printf(_("selecting default max_connections ... "));
  877. fflush(stdout);
  878. for (i = 0; i < connslen; i++)
  879. {
  880. test_conns = trial_conns[i];
  881. test_buffs = MIN_BUFS_FOR_CONNS(test_conns);
  882. snprintf(cmd, sizeof(cmd),
  883. "\"%s\" --boot -x0 %s "
  884. "-c max_connections=%d "
  885. "-c shared_buffers=%d "
  886. "-c dynamic_shared_memory_type=%s "
  887. "< \"%s\" > \"%s\" 2>&1",
  888. backend_exec, boot_options,
  889. test_conns, test_buffs,
  890. dynamic_shared_memory_type,
  891. DEVNULL, DEVNULL);
  892. status = system(cmd);
  893. if (status == 0)
  894. {
  895. ok_buffers = test_buffs;
  896. break;
  897. }
  898. }
  899. if (i >= connslen)
  900. i = connslen - 1;
  901. n_connections = trial_conns[i];
  902. printf("%d\n", n_connections);
  903. printf(_("selecting default shared_buffers ... "));
  904. fflush(stdout);
  905. for (i = 0; i < bufslen; i++)
  906. {
  907. /* Use same amount of memory, independent of BLCKSZ */
  908. test_buffs = (trial_bufs[i] * 8192) / BLCKSZ;
  909. if (test_buffs <= ok_buffers)
  910. {
  911. test_buffs = ok_buffers;
  912. break;
  913. }
  914. snprintf(cmd, sizeof(cmd),
  915. "\"%s\" --boot -x0 %s "
  916. "-c max_connections=%d "
  917. "-c shared_buffers=%d "
  918. "-c dynamic_shared_memory_type=%s "
  919. "< \"%s\" > \"%s\" 2>&1",
  920. backend_exec, boot_options,
  921. n_connections, test_buffs,
  922. dynamic_shared_memory_type,
  923. DEVNULL, DEVNULL);
  924. status = system(cmd);
  925. if (status == 0)
  926. break;
  927. }
  928. n_buffers = test_buffs;
  929. if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
  930. printf("%dMB\n", (n_buffers * (BLCKSZ / 1024)) / 1024);
  931. else
  932. printf("%dkB\n", n_buffers * (BLCKSZ / 1024));
  933. printf(_("selecting default time zone ... "));
  934. fflush(stdout);
  935. default_timezone = select_default_timezone(share_path);
  936. printf("%s\n", default_timezone ? default_timezone : "GMT");
  937. }
  938. /*
  939. * Calculate the default wal_size with a "pretty" unit.
  940. */
  941. static char *
  942. pretty_wal_size(int segment_count)
  943. {
  944. int sz = wal_segment_size_mb * segment_count;
  945. char *result = pg_malloc(14);
  946. if ((sz % 1024) == 0)
  947. snprintf(result, 14, "%dGB", sz / 1024);
  948. else
  949. snprintf(result, 14, "%dMB", sz);
  950. return result;
  951. }
  952. /*
  953. * set up all the config files
  954. */
  955. static void
  956. setup_config(void)
  957. {
  958. char **conflines;
  959. char repltok[MAXPGPATH];
  960. char path[MAXPGPATH];
  961. char *autoconflines[3];
  962. fputs(_("creating configuration files ... "), stdout);
  963. fflush(stdout);
  964. /* postgresql.conf */
  965. conflines = readfile(conf_file);
  966. snprintf(repltok, sizeof(repltok), "max_connections = %d", n_connections);
  967. conflines = replace_token(conflines, "#max_connections = 100", repltok);
  968. if ((n_buffers * (BLCKSZ / 1024)) % 1024 == 0)
  969. snprintf(repltok, sizeof(repltok), "shared_buffers = %dMB",
  970. (n_buffers * (BLCKSZ / 1024)) / 1024);
  971. else
  972. snprintf(repltok, sizeof(repltok), "shared_buffers = %dkB",
  973. n_buffers * (BLCKSZ / 1024));
  974. conflines = replace_token(conflines, "#shared_buffers = 32MB", repltok);
  975. #ifdef HAVE_UNIX_SOCKETS
  976. snprintf(repltok, sizeof(repltok), "#unix_socket_directories = '%s'",
  977. DEFAULT_PGSOCKET_DIR);
  978. #else
  979. snprintf(repltok, sizeof(repltok), "#unix_socket_directories = ''");
  980. #endif
  981. conflines = replace_token(conflines, "#unix_socket_directories = '/tmp'",
  982. repltok);
  983. #if DEF_PGPORT != 5432
  984. snprintf(repltok, sizeof(repltok), "#port = %d", DEF_PGPORT);
  985. conflines = replace_token(conflines, "#port = 5432", repltok);
  986. #endif
  987. /* set default max_wal_size and min_wal_size */
  988. snprintf(repltok, sizeof(repltok), "min_wal_size = %s",
  989. pretty_wal_size(DEFAULT_MIN_WAL_SEGS));
  990. conflines = replace_token(conflines, "#min_wal_size = 80MB", repltok);
  991. snprintf(repltok, sizeof(repltok), "max_wal_size = %s",
  992. pretty_wal_size(DEFAULT_MAX_WAL_SEGS));
  993. conflines = replace_token(conflines, "#max_wal_size = 1GB", repltok);
  994. snprintf(repltok, sizeof(repltok), "lc_messages = '%s'",
  995. escape_quotes(lc_messages));
  996. conflines = replace_token(conflines, "#lc_messages = 'C'", repltok);
  997. snprintf(repltok, sizeof(repltok), "lc_monetary = '%s'",
  998. escape_quotes(lc_monetary));
  999. conflines = replace_token(conflines, "#lc_monetary = 'C'", repltok);
  1000. snprintf(repltok, sizeof(repltok), "lc_numeric = '%s'",
  1001. escape_quotes(lc_numeric));
  1002. conflines = replace_token(conflines, "#lc_numeric = 'C'", repltok);
  1003. snprintf(repltok, sizeof(repltok), "lc_time = '%s'",
  1004. escape_quotes(lc_time));
  1005. conflines = replace_token(conflines, "#lc_time = 'C'", repltok);
  1006. switch (locale_date_order(lc_time))
  1007. {
  1008. case DATEORDER_YMD:
  1009. strcpy(repltok, "datestyle = 'iso, ymd'");
  1010. break;
  1011. case DATEORDER_DMY:
  1012. strcpy(repltok, "datestyle = 'iso, dmy'");
  1013. break;
  1014. case DATEORDER_MDY:
  1015. default:
  1016. strcpy(repltok, "datestyle = 'iso, mdy'");
  1017. break;
  1018. }
  1019. conflines = replace_token(conflines, "#datestyle = 'iso, mdy'", repltok);
  1020. snprintf(repltok, sizeof(repltok),
  1021. "default_text_search_config = 'pg_catalog.%s'",
  1022. escape_quotes(default_text_search_config));
  1023. conflines = replace_token(conflines,
  1024. "#default_text_search_config = 'pg_catalog.simple'",
  1025. repltok);
  1026. if (default_timezone)
  1027. {
  1028. snprintf(repltok, sizeof(repltok), "timezone = '%s'",
  1029. escape_quotes(default_timezone));
  1030. conflines = replace_token(conflines, "#timezone = 'GMT'", repltok);
  1031. snprintf(repltok, sizeof(repltok), "log_timezone = '%s'",
  1032. escape_quotes(default_timezone));
  1033. conflines = replace_token(conflines, "#log_timezone = 'GMT'", repltok);
  1034. }
  1035. snprintf(repltok, sizeof(repltok), "dynamic_shared_memory_type = %s",
  1036. dynamic_shared_memory_type);
  1037. conflines = replace_token(conflines, "#dynamic_shared_memory_type = posix",
  1038. repltok);
  1039. #if DEFAULT_BACKEND_FLUSH_AFTER > 0
  1040. snprintf(repltok, sizeof(repltok), "#backend_flush_after = %dkB",
  1041. DEFAULT_BACKEND_FLUSH_AFTER * (BLCKSZ / 1024));
  1042. conflines = replace_token(conflines, "#backend_flush_after = 0",
  1043. repltok);
  1044. #endif
  1045. #if DEFAULT_BGWRITER_FLUSH_AFTER > 0
  1046. snprintf(repltok, sizeof(repltok), "#bgwriter_flush_after = %dkB",
  1047. DEFAULT_BGWRITER_FLUSH_AFTER * (BLCKSZ / 1024));
  1048. conflines = replace_token(conflines, "#bgwriter_flush_after = 0",
  1049. repltok);
  1050. #endif
  1051. #if DEFAULT_CHECKPOINT_FLUSH_AFTER > 0
  1052. snprintf(repltok, sizeof(repltok), "#checkpoint_flush_after = %dkB",
  1053. DEFAULT_CHECKPOINT_FLUSH_AFTER * (BLCKSZ / 1024));
  1054. conflines = replace_token(conflines, "#checkpoint_flush_after = 0",
  1055. repltok);
  1056. #endif
  1057. #ifndef USE_PREFETCH
  1058. conflines = replace_token(conflines,
  1059. "#effective_io_concurrency = 1",
  1060. "#effective_io_concurrency = 0");
  1061. #endif
  1062. #ifdef WIN32
  1063. conflines = replace_token(conflines,
  1064. "#update_process_title = on",
  1065. "#update_process_title = off");
  1066. #endif
  1067. if (strcmp(authmethodlocal, "scram-sha-256") == 0 ||
  1068. strcmp(authmethodhost, "scram-sha-256") == 0)
  1069. {
  1070. conflines = replace_token(conflines,
  1071. "#password_encryption = md5",
  1072. "password_encryption = scram-sha-256");
  1073. }
  1074. /*
  1075. * If group access has been enabled for the cluster then it makes sense to
  1076. * ensure that the log files also allow group access. Otherwise a backup
  1077. * from a user in the group would fail if the log files were not
  1078. * relocated.
  1079. */
  1080. if (pg_dir_create_mode == PG_DIR_MODE_GROUP)
  1081. {
  1082. conflines = replace_token(conflines,
  1083. "#log_file_mode = 0600",
  1084. "log_file_mode = 0640");
  1085. }
  1086. snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data);
  1087. writefile(path, conflines);
  1088. if (chmod(path, pg_file_create_mode) != 0)
  1089. {
  1090. pg_log_error("could not change permissions of \"%s\": %m", path);
  1091. exit(1);
  1092. }
  1093. /*
  1094. * create the automatic configuration file to store the configuration
  1095. * parameters set by ALTER SYSTEM command. The parameters present in this
  1096. * file will override the value of parameters that exists before parse of
  1097. * this file.
  1098. */
  1099. autoconflines[0] = pg_strdup("# Do not edit this file manually!\n");
  1100. autoconflines[1] = pg_strdup("# It will be overwritten by the ALTER SYSTEM command.\n");
  1101. autoconflines[2] = NULL;
  1102. sprintf(path, "%s/postgresql.auto.conf", pg_data);
  1103. writefile(path, autoconflines);
  1104. if (chmod(path, pg_file_create_mode) != 0)
  1105. {
  1106. pg_log_error("could not change permissions of \"%s\": %m", path);
  1107. exit(1);
  1108. }
  1109. free(conflines);
  1110. /* pg_hba.conf */
  1111. conflines = readfile(hba_file);
  1112. #ifndef HAVE_UNIX_SOCKETS
  1113. conflines = filter_lines_with_token(conflines, "@remove-line-for-nolocal@");
  1114. #else
  1115. conflines = replace_token(conflines, "@remove-line-for-nolocal@", "");
  1116. #endif
  1117. #ifdef HAVE_IPV6
  1118. /*
  1119. * Probe to see if there is really any platform support for IPv6, and
  1120. * comment out the relevant pg_hba line if not. This avoids runtime
  1121. * warnings if getaddrinfo doesn't actually cope with IPv6. Particularly
  1122. * useful on Windows, where executables built on a machine with IPv6 may
  1123. * have to run on a machine without.
  1124. */
  1125. {
  1126. struct addrinfo *gai_result;
  1127. struct addrinfo hints;
  1128. int err = 0;
  1129. #ifdef WIN32
  1130. /* need to call WSAStartup before calling getaddrinfo */
  1131. WSADATA wsaData;
  1132. err = WSAStartup(MAKEWORD(2, 2), &wsaData);
  1133. #endif
  1134. /* for best results, this code should match parse_hba_line() */
  1135. hints.ai_flags = AI_NUMERICHOST;
  1136. hints.ai_family = AF_UNSPEC;
  1137. hints.ai_socktype = 0;
  1138. hints.ai_protocol = 0;
  1139. hints.ai_addrlen = 0;
  1140. hints.ai_canonname = NULL;
  1141. hints.ai_addr = NULL;
  1142. hints.ai_next = NULL;
  1143. if (err != 0 ||
  1144. getaddrinfo("::1", NULL, &hints, &gai_result) != 0)
  1145. {
  1146. conflines = replace_token(conflines,
  1147. "host all all ::1",
  1148. "#host all all ::1");
  1149. conflines = replace_token(conflines,
  1150. "host replication all ::1",
  1151. "#host replication all ::1");
  1152. }
  1153. }
  1154. #else /* !HAVE_IPV6 */
  1155. /* If we didn't compile IPV6 support at all, always comment it out */
  1156. conflines = replace_token(conflines,
  1157. "host all all ::1",
  1158. "#host all all ::1");
  1159. conflines = replace_token(conflines,
  1160. "host replication all ::1",
  1161. "#host replication all ::1");
  1162. #endif /* HAVE_IPV6 */
  1163. /* Replace default authentication methods */
  1164. conflines = replace_token(conflines,
  1165. "@authmethodhost@",
  1166. authmethodhost);
  1167. conflines = replace_token(conflines,
  1168. "@authmethodlocal@",
  1169. authmethodlocal);
  1170. conflines = replace_token(conflines,
  1171. "@authcomment@",
  1172. (strcmp(authmethodlocal, "trust") == 0 || strcmp(authmethodhost, "trust") == 0) ? AUTHTRUST_WARNING : "");
  1173. snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data);
  1174. writefile(path, conflines);
  1175. if (chmod(path, pg_file_create_mode) != 0)
  1176. {
  1177. pg_log_error("could not change permissions of \"%s\": %m", path);
  1178. exit(1);
  1179. }
  1180. free(conflines);
  1181. /* pg_ident.conf */
  1182. conflines = readfile(ident_file);
  1183. snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data);
  1184. writefile(path, conflines);
  1185. if (chmod(path, pg_file_create_mode) != 0)
  1186. {
  1187. pg_log_error("could not change permissions of \"%s\": %m", path);
  1188. exit(1);
  1189. }
  1190. free(conflines);
  1191. check_ok();
  1192. }
  1193. /*
  1194. * run the BKI script in bootstrap mode to create template1
  1195. */
  1196. static void
  1197. bootstrap_template1(void)
  1198. {
  1199. PG_CMD_DECL;
  1200. char **line;
  1201. char **bki_lines;
  1202. char headerline[MAXPGPATH];
  1203. char buf[64];
  1204. printf(_("running bootstrap script ... "));
  1205. fflush(stdout);
  1206. bki_lines = readfile(bki_file);
  1207. /* Check that bki file appears to be of the right version */
  1208. snprintf(headerline, sizeof(headerline), "# PostgreSQL %s\n",
  1209. PG_MAJORVERSION);
  1210. if (strcmp(headerline, *bki_lines) != 0)
  1211. {
  1212. pg_log_error("input file \"%s\" does not belong to PostgreSQL %s",
  1213. bki_file, PG_VERSION);
  1214. fprintf(stderr,
  1215. _("Check your installation or specify the correct path "
  1216. "using the option -L.\n"));
  1217. exit(1);
  1218. }
  1219. /* Substitute for various symbols used in the BKI file */
  1220. sprintf(buf, "%d", NAMEDATALEN);
  1221. bki_lines = replace_token(bki_lines, "NAMEDATALEN", buf);
  1222. sprintf(buf, "%d", (int) sizeof(Pointer));
  1223. bki_lines = replace_token(bki_lines, "SIZEOF_POINTER", buf);
  1224. bki_lines = replace_token(bki_lines, "ALIGNOF_POINTER",
  1225. (sizeof(Pointer) == 4) ? "i" : "d");
  1226. bki_lines = replace_token(bki_lines, "FLOAT8PASSBYVAL",
  1227. FLOAT8PASSBYVAL ? "true" : "false");
  1228. bki_lines = replace_token(bki_lines, "POSTGRES",
  1229. escape_quotes_bki(username));
  1230. bki_lines = replace_token(bki_lines, "ENCODING",
  1231. encodingid_to_string(encodingid));
  1232. bki_lines = replace_token(bki_lines, "LC_COLLATE",
  1233. escape_quotes_bki(lc_collate));
  1234. bki_lines = replace_token(bki_lines, "LC_CTYPE",
  1235. escape_quotes_bki(lc_ctype));
  1236. /* Also ensure backend isn't confused by this environment var: */
  1237. unsetenv("PGCLIENTENCODING");
  1238. snprintf(cmd, sizeof(cmd),
  1239. "\"%s\" --boot -x1 -X %u %s %s %s",
  1240. backend_exec,
  1241. wal_segment_size_mb * (1024 * 1024),
  1242. data_checksums ? "-k" : "",
  1243. boot_options,
  1244. debug ? "-d 5" : "");
  1245. PG_CMD_OPEN;
  1246. for (line = bki_lines; *line != NULL; line++)
  1247. {
  1248. PG_CMD_PUTS(*line);
  1249. free(*line);
  1250. }
  1251. PG_CMD_CLOSE;
  1252. free(bki_lines);
  1253. check_ok();
  1254. }
  1255. /*
  1256. * set up the shadow password table
  1257. */
  1258. static void
  1259. setup_auth(FILE *cmdfd)
  1260. {
  1261. const char *const *line;
  1262. static const char *const pg_authid_setup[] = {
  1263. /*
  1264. * The authid table shouldn't be readable except through views, to
  1265. * ensure passwords are not publicly visible.
  1266. */
  1267. "REVOKE ALL on pg_authid FROM public;\n\n",
  1268. NULL
  1269. };
  1270. for (line = pg_authid_setup; *line != NULL; line++)
  1271. PG_CMD_PUTS(*line);
  1272. if (superuser_password)
  1273. PG_CMD_PRINTF("ALTER USER \"%s\" WITH PASSWORD E'%s';\n\n",
  1274. username, escape_quotes(superuser_password));
  1275. }
  1276. /*
  1277. * get the superuser password if required
  1278. */
  1279. static void
  1280. get_su_pwd(void)
  1281. {
  1282. char pwd1[100];
  1283. char pwd2[100];
  1284. if (pwprompt)
  1285. {
  1286. /*
  1287. * Read password from terminal
  1288. */
  1289. printf("\n");
  1290. fflush(stdout);
  1291. simple_prompt("Enter new superuser password: ", pwd1, sizeof(pwd1), false);
  1292. simple_prompt("Enter it again: ", pwd2, sizeof(pwd2), false);
  1293. if (strcmp(pwd1, pwd2) != 0)
  1294. {
  1295. fprintf(stderr, _("Passwords didn't match.\n"));
  1296. exit(1);
  1297. }
  1298. }
  1299. else
  1300. {
  1301. /*
  1302. * Read password from file
  1303. *
  1304. * Ideally this should insist that the file not be world-readable.
  1305. * However, this option is mainly intended for use on Windows where
  1306. * file permissions may not exist at all, so we'll skip the paranoia
  1307. * for now.
  1308. */
  1309. FILE *pwf = fopen(pwfilename, "r");
  1310. int i;
  1311. if (!pwf)
  1312. {
  1313. pg_log_error("could not open file \"%s\" for reading: %m",
  1314. pwfilename);
  1315. exit(1);
  1316. }
  1317. if (!fgets(pwd1, sizeof(pwd1), pwf))
  1318. {
  1319. if (ferror(pwf))
  1320. pg_log_error("could not read password from file \"%s\": %m",
  1321. pwfilename);
  1322. else
  1323. pg_log_error("password file \"%s\" is empty",
  1324. pwfilename);
  1325. exit(1);
  1326. }
  1327. fclose(pwf);
  1328. i = strlen(pwd1);
  1329. while (i > 0 && (pwd1[i - 1] == '\r' || pwd1[i - 1] == '\n'))
  1330. pwd1[--i] = '\0';
  1331. }
  1332. superuser_password = pg_strdup(pwd1);
  1333. }
  1334. /*
  1335. * set up pg_depend
  1336. */
  1337. static void
  1338. setup_depend(FILE *cmdfd)
  1339. {
  1340. const char *const *line;
  1341. static const char *const pg_depend_setup[] = {
  1342. /*
  1343. * Make PIN entries in pg_depend for all objects made so far in the
  1344. * tables that the dependency code handles. This is overkill (the
  1345. * system doesn't really depend on having every last weird datatype,
  1346. * for instance) but generating only the minimum required set of
  1347. * dependencies seems hard.
  1348. *
  1349. * Catalogs that are intentionally not scanned here are:
  1350. *
  1351. * pg_database: it's a feature, not a bug, that template1 is not
  1352. * pinned.
  1353. *
  1354. * pg_extension: a pinned extension isn't really an extension, hmm?
  1355. *
  1356. * pg_tablespace: tablespaces don't participate in the dependency
  1357. * code, and DropTableSpace() explicitly protects the built-in
  1358. * tablespaces.
  1359. *
  1360. * First delete any already-made entries; PINs override all else, and
  1361. * must be the only entries for their objects.
  1362. */
  1363. "DELETE FROM pg_depend;\n\n",
  1364. "VACUUM pg_depend;\n\n",
  1365. "DELETE FROM pg_shdepend;\n\n",
  1366. "VACUUM pg_shdepend;\n\n",
  1367. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1368. " FROM pg_class;\n\n",
  1369. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1370. " FROM pg_proc;\n\n",
  1371. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1372. " FROM pg_type;\n\n",
  1373. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1374. " FROM pg_cast;\n\n",
  1375. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1376. " FROM pg_constraint;\n\n",
  1377. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1378. " FROM pg_conversion;\n\n",
  1379. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1380. " FROM pg_attrdef;\n\n",
  1381. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1382. " FROM pg_language;\n\n",
  1383. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1384. " FROM pg_operator;\n\n",
  1385. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1386. " FROM pg_opclass;\n\n",
  1387. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1388. " FROM pg_opfamily;\n\n",
  1389. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1390. " FROM pg_am;\n\n",
  1391. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1392. " FROM pg_amop;\n\n",
  1393. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1394. " FROM pg_amproc;\n\n",
  1395. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1396. " FROM pg_rewrite;\n\n",
  1397. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1398. " FROM pg_trigger;\n\n",
  1399. /*
  1400. * restriction here to avoid pinning the public namespace
  1401. */
  1402. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1403. " FROM pg_namespace "
  1404. " WHERE nspname LIKE 'pg%';\n\n",
  1405. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1406. " FROM pg_ts_parser;\n\n",
  1407. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1408. " FROM pg_ts_dict;\n\n",
  1409. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1410. " FROM pg_ts_template;\n\n",
  1411. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1412. " FROM pg_ts_config;\n\n",
  1413. "INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' "
  1414. " FROM pg_collation;\n\n",
  1415. "INSERT INTO pg_shdepend SELECT 0,0,0,0, tableoid,oid, 'p' "
  1416. " FROM pg_authid;\n\n",
  1417. NULL
  1418. };
  1419. for (line = pg_depend_setup; *line != NULL; line++)
  1420. PG_CMD_PUTS(*line);
  1421. }
  1422. /*
  1423. * set up system views
  1424. */
  1425. static void
  1426. setup_sysviews(FILE *cmdfd)
  1427. {
  1428. char **line;
  1429. char **sysviews_setup;
  1430. sysviews_setup = readfile(system_views_file);
  1431. for (line = sysviews_setup; *line != NULL; line++)
  1432. {
  1433. PG_CMD_PUTS(*line);
  1434. free(*line);
  1435. }
  1436. PG_CMD_PUTS("\n\n");
  1437. free(sysviews_setup);
  1438. }
  1439. /*
  1440. * fill in extra description data
  1441. */
  1442. static void
  1443. setup_description(FILE *cmdfd)
  1444. {
  1445. /* Create default descriptions for operator implementation functions */
  1446. PG_CMD_PUTS("WITH funcdescs AS ( "
  1447. "SELECT p.oid as p_oid, o.oid as o_oid, oprname "
  1448. "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) "
  1449. "INSERT INTO pg_description "
  1450. " SELECT p_oid, 'pg_proc'::regclass, 0, "
  1451. " 'implementation of ' || oprname || ' operator' "
  1452. " FROM funcdescs "
  1453. " WHERE NOT EXISTS (SELECT 1 FROM pg_description "
  1454. " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) "
  1455. " AND NOT EXISTS (SELECT 1 FROM pg_description "
  1456. " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass"
  1457. " AND description LIKE 'deprecated%');\n\n");
  1458. }
  1459. /*
  1460. * populate pg_collation
  1461. */
  1462. static void
  1463. setup_collation(FILE *cmdfd)
  1464. {
  1465. /*
  1466. * Add an SQL-standard name. We don't want to pin this, so it doesn't go
  1467. * in pg_collation.h. But add it before reading system collations, so
  1468. * that it wins if libc defines a locale named ucs_basic.
  1469. */
  1470. PG_CMD_PRINTF("INSERT INTO pg_collation (oid, collname, collnamespace, collowner, collprovider, collisdeterministic, collencoding, collcollate, collctype)"
  1471. "VALUES (pg_nextoid('pg_catalog.pg_collation', 'oid', 'pg_catalog.pg_collation_oid_index'), 'ucs_basic', 'pg_catalog'::regnamespace, %u, '%c', true, %d, 'C', 'C');\n\n",
  1472. BOOTSTRAP_SUPERUSERID, COLLPROVIDER_LIBC, PG_UTF8);
  1473. /* Now import all collations we can find in the operating system */
  1474. PG_CMD_PUTS("SELECT pg_import_system_collations('pg_catalog');\n\n");
  1475. }
  1476. /*
  1477. * load extra dictionaries (Snowball stemmers)
  1478. */
  1479. static void
  1480. setup_dictionary(FILE *cmdfd)
  1481. {
  1482. char **line;
  1483. char **conv_lines;
  1484. conv_lines = readfile(dictionary_file);
  1485. for (line = conv_lines; *line != NULL; line++)
  1486. {
  1487. PG_CMD_PUTS(*line);
  1488. free(*line);
  1489. }
  1490. PG_CMD_PUTS("\n\n");
  1491. free(conv_lines);
  1492. }
  1493. /*
  1494. * Set up privileges
  1495. *
  1496. * We mark most system catalogs as world-readable. We don't currently have
  1497. * to touch functions, languages, or databases, because their default
  1498. * permissions are OK.
  1499. *
  1500. * Some objects may require different permissions by default, so we
  1501. * make sure we don't overwrite privilege sets that have already been
  1502. * set (NOT NULL).
  1503. *
  1504. * Also populate pg_init_privs to save what the privileges are at init
  1505. * time. This is used by pg_dump to allow users to change privileges
  1506. * on catalog objects and to have those privilege changes preserved
  1507. * across dump/reload and pg_upgrade.
  1508. *
  1509. * Note that pg_init_privs is only for per-database objects and therefore
  1510. * we don't include databases or tablespaces.
  1511. */
  1512. static void
  1513. setup_privileges(FILE *cmdfd)
  1514. {
  1515. char **line;
  1516. char **priv_lines;
  1517. static char *privileges_setup[] = {
  1518. "UPDATE pg_class "
  1519. " SET relacl = (SELECT array_agg(a.acl) FROM "
  1520. " (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl "
  1521. " UNION SELECT unnest(pg_catalog.acldefault("
  1522. " CASE WHEN relkind = " CppAsString2(RELKIND_SEQUENCE) " THEN 's' "
  1523. " ELSE 'r' END::\"char\"," CppAsString2(BOOTSTRAP_SUPERUSERID) "::oid))"
  1524. " ) as a) "
  1525. " WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ", "
  1526. CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
  1527. CppAsString2(RELKIND_SEQUENCE) ")"
  1528. " AND relacl IS NULL;\n\n",
  1529. "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
  1530. "GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
  1531. "REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n",
  1532. "INSERT INTO pg_init_privs "
  1533. " (objoid, classoid, objsubid, initprivs, privtype)"
  1534. " SELECT"
  1535. " oid,"
  1536. " (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
  1537. " 0,"
  1538. " relacl,"
  1539. " 'i'"
  1540. " FROM"
  1541. " pg_class"
  1542. " WHERE"
  1543. " relacl IS NOT NULL"
  1544. " AND relkind IN (" CppAsString2(RELKIND_RELATION) ", "
  1545. CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
  1546. CppAsString2(RELKIND_SEQUENCE) ");\n\n",
  1547. "INSERT INTO pg_init_privs "
  1548. " (objoid, classoid, objsubid, initprivs, privtype)"
  1549. " SELECT"
  1550. " pg_class.oid,"
  1551. " (SELECT oid FROM pg_class WHERE relname = 'pg_class'),"
  1552. " pg_attribute.attnum,"
  1553. " pg_attribute.attacl,"
  1554. " 'i'"
  1555. " FROM"
  1556. " pg_class"
  1557. " JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)"
  1558. " WHERE"
  1559. " pg_attribute.attacl IS NOT NULL"
  1560. " AND pg_class.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
  1561. CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
  1562. CppAsString2(RELKIND_SEQUENCE) ");\n\n",
  1563. "INSERT INTO pg_init_privs "
  1564. " (objoid, classoid, objsubid, initprivs, privtype)"
  1565. " SELECT"
  1566. " oid,"
  1567. " (SELECT oid FROM pg_class WHERE relname = 'pg_proc'),"
  1568. " 0,"
  1569. " proacl,"
  1570. " 'i'"
  1571. " FROM"
  1572. " pg_proc"
  1573. " WHERE"
  1574. " proacl IS NOT NULL;\n\n",
  1575. "INSERT INTO pg_init_privs "
  1576. " (objoid, classoid, objsubid, initprivs, privtype)"
  1577. " SELECT"
  1578. " oid,"
  1579. " (SELECT oid FROM pg_class WHERE relname = 'pg_type'),"
  1580. " 0,"
  1581. " typacl,"
  1582. " 'i'"
  1583. " FROM"
  1584. " pg_type"
  1585. " WHERE"
  1586. " typacl IS NOT NULL;\n\n",
  1587. "INSERT INTO pg_init_privs "
  1588. " (objoid, classoid, objsubid, initprivs, privtype)"
  1589. " SELECT"
  1590. " oid,"
  1591. " (SELECT oid FROM pg_class WHERE relname = 'pg_language'),"
  1592. " 0,"
  1593. " lanacl,"
  1594. " 'i'"
  1595. " FROM"
  1596. " pg_language"
  1597. " WHERE"
  1598. " lanacl IS NOT NULL;\n\n",
  1599. "INSERT INTO pg_init_privs "
  1600. " (objoid, classoid, objsubid, initprivs, privtype)"
  1601. " SELECT"
  1602. " oid,"
  1603. " (SELECT oid FROM pg_class WHERE "
  1604. " relname = 'pg_largeobject_metadata'),"
  1605. " 0,"
  1606. " lomacl,"
  1607. " 'i'"
  1608. " FROM"
  1609. " pg_largeobject_metadata"
  1610. " WHERE"
  1611. " lomacl IS NOT NULL;\n\n",
  1612. "INSERT INTO pg_init_privs "
  1613. " (objoid, classoid, objsubid, initprivs, privtype)"
  1614. " SELECT"
  1615. " oid,"
  1616. " (SELECT oid FROM pg_class WHERE relname = 'pg_namespace'),"
  1617. " 0,"
  1618. " nspacl,"
  1619. " 'i'"
  1620. " FROM"
  1621. " pg_namespace"
  1622. " WHERE"
  1623. " nspacl IS NOT NULL;\n\n",
  1624. "INSERT INTO pg_init_privs "
  1625. " (objoid, classoid, objsubid, initprivs, privtype)"
  1626. " SELECT"
  1627. " oid,"
  1628. " (SELECT oid FROM pg_class WHERE "
  1629. " relname = 'pg_foreign_data_wrapper'),"
  1630. " 0,"
  1631. " fdwacl,"
  1632. " 'i'"
  1633. " FROM"
  1634. " pg_foreign_data_wrapper"
  1635. " WHERE"
  1636. " fdwacl IS NOT NULL;\n\n",
  1637. "INSERT INTO pg_init_privs "
  1638. " (objoid, classoid, objsubid, initprivs, privtype)"
  1639. " SELECT"
  1640. " oid,"
  1641. " (SELECT oid FROM pg_class "
  1642. " WHERE relname = 'pg_foreign_server'),"
  1643. " 0,"
  1644. " srvacl,"
  1645. " 'i'"
  1646. " FROM"
  1647. " pg_foreign_server"
  1648. " WHERE"
  1649. " srvacl IS NOT NULL;\n\n",
  1650. NULL
  1651. };
  1652. priv_lines = replace_token(privileges_setup, "$POSTGRES_SUPERUSERNAME",
  1653. escape_quotes(username));
  1654. for (line = priv_lines; *line != NULL; line++)
  1655. PG_CMD_PUTS(*line);
  1656. }
  1657. /*
  1658. * extract the strange version of version required for information schema
  1659. * (09.08.0007abc)
  1660. */
  1661. static void
  1662. set_info_version(void)
  1663. {
  1664. char *letterversion;
  1665. long major = 0

Large files files are truncated, but you can click here to view the full file