File: | bin/initdb/initdb.c |
Warning: | line 1100, column 14 Potential memory leak |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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-2022, 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 <signal.h> | |||
56 | #include <time.h> | |||
57 | ||||
58 | #ifdef HAVE_SHM_OPEN1 | |||
59 | #include "sys/mman.h" | |||
60 | #endif | |||
61 | ||||
62 | #include "access/transam.h" | |||
63 | #include "access/xlog_internal.h" | |||
64 | #include "catalog/pg_authid_d.h" | |||
65 | #include "catalog/pg_class_d.h" /* pgrminclude ignore */ | |||
66 | #include "catalog/pg_collation_d.h" | |||
67 | #include "common/file_perm.h" | |||
68 | #include "common/file_utils.h" | |||
69 | #include "common/logging.h" | |||
70 | #include "common/pg_prng.h" | |||
71 | #include "common/restricted_token.h" | |||
72 | #include "common/string.h" | |||
73 | #include "common/username.h" | |||
74 | #include "fe_utils/string_utils.h" | |||
75 | #include "getaddrinfo.h" | |||
76 | #include "getopt_long.h" | |||
77 | #include "mb/pg_wchar.h" | |||
78 | #include "miscadmin.h" | |||
79 | ||||
80 | ||||
81 | /* Ideally this would be in a .h file, but it hardly seems worth the trouble */ | |||
82 | extern const char *select_default_timezone(const char *share_path); | |||
83 | ||||
84 | static const char *const auth_methods_host[] = { | |||
85 | "trust", "reject", "scram-sha-256", "md5", "password", "ident", "radius", | |||
86 | #ifdef ENABLE_GSS | |||
87 | "gss", | |||
88 | #endif | |||
89 | #ifdef ENABLE_SSPI | |||
90 | "sspi", | |||
91 | #endif | |||
92 | #ifdef USE_PAM | |||
93 | "pam", "pam ", | |||
94 | #endif | |||
95 | #ifdef USE_BSD_AUTH | |||
96 | "bsd", | |||
97 | #endif | |||
98 | #ifdef USE_LDAP | |||
99 | "ldap", | |||
100 | #endif | |||
101 | #ifdef USE_SSL | |||
102 | "cert", | |||
103 | #endif | |||
104 | NULL((void*)0) | |||
105 | }; | |||
106 | static const char *const auth_methods_local[] = { | |||
107 | "trust", "reject", "scram-sha-256", "md5", "password", "peer", "radius", | |||
108 | #ifdef USE_PAM | |||
109 | "pam", "pam ", | |||
110 | #endif | |||
111 | #ifdef USE_BSD_AUTH | |||
112 | "bsd", | |||
113 | #endif | |||
114 | #ifdef USE_LDAP | |||
115 | "ldap", | |||
116 | #endif | |||
117 | NULL((void*)0) | |||
118 | }; | |||
119 | ||||
120 | /* | |||
121 | * these values are passed in by makefile defines | |||
122 | */ | |||
123 | static char *share_path = NULL((void*)0); | |||
124 | ||||
125 | /* values to be obtained from arguments */ | |||
126 | static char *pg_data = NULL((void*)0); | |||
127 | static char *encoding = NULL((void*)0); | |||
128 | static char *locale = NULL((void*)0); | |||
129 | static char *lc_collate = NULL((void*)0); | |||
130 | static char *lc_ctype = NULL((void*)0); | |||
131 | static char *lc_monetary = NULL((void*)0); | |||
132 | static char *lc_numeric = NULL((void*)0); | |||
133 | static char *lc_time = NULL((void*)0); | |||
134 | static char *lc_messages = NULL((void*)0); | |||
135 | static const char *default_text_search_config = NULL((void*)0); | |||
136 | static char *username = NULL((void*)0); | |||
137 | static bool_Bool pwprompt = false0; | |||
138 | static char *pwfilename = NULL((void*)0); | |||
139 | static char *superuser_password = NULL((void*)0); | |||
140 | static const char *authmethodhost = NULL((void*)0); | |||
141 | static const char *authmethodlocal = NULL((void*)0); | |||
142 | static bool_Bool debug = false0; | |||
143 | static bool_Bool noclean = false0; | |||
144 | static bool_Bool noinstructions = false0; | |||
145 | static bool_Bool do_sync = true1; | |||
146 | static bool_Bool sync_only = false0; | |||
147 | static bool_Bool show_setting = false0; | |||
148 | static bool_Bool data_checksums = false0; | |||
149 | static char *xlog_dir = NULL((void*)0); | |||
150 | static char *str_wal_segment_size_mb = NULL((void*)0); | |||
151 | static int wal_segment_size_mb; | |||
152 | ||||
153 | ||||
154 | /* internal vars */ | |||
155 | static const char *progname; | |||
156 | static int encodingid; | |||
157 | static char *bki_file; | |||
158 | static char *hba_file; | |||
159 | static char *ident_file; | |||
160 | static char *conf_file; | |||
161 | static char *dictionary_file; | |||
162 | static char *info_schema_file; | |||
163 | static char *features_file; | |||
164 | static char *system_constraints_file; | |||
165 | static char *system_functions_file; | |||
166 | static char *system_views_file; | |||
167 | static bool_Bool success = false0; | |||
168 | static bool_Bool made_new_pgdata = false0; | |||
169 | static bool_Bool found_existing_pgdata = false0; | |||
170 | static bool_Bool made_new_xlogdir = false0; | |||
171 | static bool_Bool found_existing_xlogdir = false0; | |||
172 | static char infoversion[100]; | |||
173 | static bool_Bool caught_signal = false0; | |||
174 | static bool_Bool output_failed = false0; | |||
175 | static int output_errno = 0; | |||
176 | static char *pgdata_native; | |||
177 | ||||
178 | /* defaults */ | |||
179 | static int n_connections = 10; | |||
180 | static int n_buffers = 50; | |||
181 | static const char *dynamic_shared_memory_type = NULL((void*)0); | |||
182 | static const char *default_timezone = NULL((void*)0); | |||
183 | ||||
184 | /* | |||
185 | * Warning messages for authentication methods | |||
186 | */ | |||
187 | #define AUTHTRUST_WARNING"# CAUTION: Configuring the system for local \"trust\" authentication\n" "# allows any local user to connect as any PostgreSQL user, including\n" "# the database superuser. If you do not trust all your local users,\n" "# use another authentication method.\n" \ | |||
188 | "# CAUTION: Configuring the system for local \"trust\" authentication\n" \ | |||
189 | "# allows any local user to connect as any PostgreSQL user, including\n" \ | |||
190 | "# the database superuser. If you do not trust all your local users,\n" \ | |||
191 | "# use another authentication method.\n" | |||
192 | static bool_Bool authwarning = false0; | |||
193 | ||||
194 | /* | |||
195 | * Centralized knowledge of switches to pass to backend | |||
196 | * | |||
197 | * Note: we run the backend with -F (fsync disabled) and then do a single | |||
198 | * pass of fsync'ing at the end. This is faster than fsync'ing each step. | |||
199 | * | |||
200 | * Note: in the shell-script version, we also passed PGDATA as a -D switch, | |||
201 | * but here it is more convenient to pass it as an environment variable | |||
202 | * (no quoting to worry about). | |||
203 | */ | |||
204 | static const char *boot_options = "-F -c log_checkpoints=false"; | |||
205 | static const char *backend_options = "--single -F -O -j -c search_path=pg_catalog -c exit_on_error=true -c log_checkpoints=false"; | |||
206 | ||||
207 | /* Additional switches to pass to backend (either boot or standalone) */ | |||
208 | static char *extra_options = ""; | |||
209 | ||||
210 | static const char *const subdirs[] = { | |||
211 | "global", | |||
212 | "pg_wal/archive_status", | |||
213 | "pg_commit_ts", | |||
214 | "pg_dynshmem", | |||
215 | "pg_notify", | |||
216 | "pg_serial", | |||
217 | "pg_snapshots", | |||
218 | "pg_subtrans", | |||
219 | "pg_twophase", | |||
220 | "pg_multixact", | |||
221 | "pg_multixact/members", | |||
222 | "pg_multixact/offsets", | |||
223 | "base", | |||
224 | "base/1", | |||
225 | "pg_replslot", | |||
226 | "pg_tblspc", | |||
227 | "pg_stat", | |||
228 | "pg_stat_tmp", | |||
229 | "pg_xact", | |||
230 | "pg_logical", | |||
231 | "pg_logical/snapshots", | |||
232 | "pg_logical/mappings" | |||
233 | }; | |||
234 | ||||
235 | ||||
236 | /* path to 'initdb' binary directory */ | |||
237 | static char bin_path[MAXPGPATH1024]; | |||
238 | static char backend_exec[MAXPGPATH1024]; | |||
239 | ||||
240 | static char **replace_token(char **lines, | |||
241 | const char *token, const char *replacement); | |||
242 | ||||
243 | #ifndef HAVE_UNIX_SOCKETS1 | |||
244 | static char **filter_lines_with_token(char **lines, const char *token); | |||
245 | #endif | |||
246 | static char **readfile(const char *path); | |||
247 | static void writefile(char *path, char **lines); | |||
248 | static FILE *popen_check(const char *command, const char *mode); | |||
249 | static char *get_id(void); | |||
250 | static int get_encoding_id(const char *encoding_name); | |||
251 | static void set_input(char **dest, const char *filename); | |||
252 | static void check_input(char *path); | |||
253 | static void write_version_file(const char *extrapath); | |||
254 | static void set_null_conf(void); | |||
255 | static void test_config_settings(void); | |||
256 | static void setup_config(void); | |||
257 | static void bootstrap_template1(void); | |||
258 | static void setup_auth(FILE *cmdfd); | |||
259 | static void get_su_pwd(void); | |||
260 | static void setup_depend(FILE *cmdfd); | |||
261 | static void setup_run_file(FILE *cmdfd, const char *filename); | |||
262 | static void setup_description(FILE *cmdfd); | |||
263 | static void setup_collation(FILE *cmdfd); | |||
264 | static void setup_privileges(FILE *cmdfd); | |||
265 | static void set_info_version(void); | |||
266 | static void setup_schema(FILE *cmdfd); | |||
267 | static void load_plpgsql(FILE *cmdfd); | |||
268 | static void vacuum_db(FILE *cmdfd); | |||
269 | static void make_template0(FILE *cmdfd); | |||
270 | static void make_postgres(FILE *cmdfd); | |||
271 | static void trapsig(int signum); | |||
272 | static void check_ok(void); | |||
273 | static char *escape_quotes(const char *src); | |||
274 | static char *escape_quotes_bki(const char *src); | |||
275 | static int locale_date_order(const char *locale); | |||
276 | static void check_locale_name(int category, const char *locale, | |||
277 | char **canonname); | |||
278 | static bool_Bool check_locale_encoding(const char *locale, int encoding); | |||
279 | static void setlocales(void); | |||
280 | static void usage(const char *progname); | |||
281 | void setup_pgdata(void); | |||
282 | void setup_bin_paths(const char *argv0); | |||
283 | void setup_data_file_paths(void); | |||
284 | void setup_locale_encoding(void); | |||
285 | void setup_signals(void); | |||
286 | void setup_text_search(void); | |||
287 | void create_data_directory(void); | |||
288 | void create_xlog_or_symlink(void); | |||
289 | void warn_on_mount_point(int error); | |||
290 | void initialize_data_directory(void); | |||
291 | ||||
292 | /* | |||
293 | * macros for running pipes to postgres | |||
294 | */ | |||
295 | #define PG_CMD_DECLchar cmd[1024]; FILE *cmdfd char cmd[MAXPGPATH1024]; FILE *cmdfd | |||
296 | ||||
297 | #define PG_CMD_OPENdo { cmdfd = popen_check(cmd, "w"); if (cmdfd == ((void*)0)) exit (1); } while (0) \ | |||
298 | do { \ | |||
299 | cmdfd = popen_check(cmd, "w"); \ | |||
300 | if (cmdfd == NULL((void*)0)) \ | |||
301 | exit(1); /* message already printed by popen_check */ \ | |||
302 | } while (0) | |||
303 | ||||
304 | #define PG_CMD_CLOSEdo { if (pclose_check(cmdfd)) exit(1); } while (0) \ | |||
305 | do { \ | |||
306 | if (pclose_check(cmdfd)) \ | |||
307 | exit(1); /* message already printed by pclose_check */ \ | |||
308 | } while (0) | |||
309 | ||||
310 | #define PG_CMD_PUTS(line)do { if (fputs(line, cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) \ | |||
311 | do { \ | |||
312 | if (fputs(line, cmdfd) < 0 || fflush(cmdfd) < 0) \ | |||
313 | output_failed = true1, output_errno = errno(*__errno_location ()); \ | |||
314 | } while (0) | |||
315 | ||||
316 | #define PG_CMD_PRINTF(fmt, ...)do { if (pg_fprintf(cmdfd, fmt, ...) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) \ | |||
317 | do { \ | |||
318 | if (fprintfpg_fprintf(cmdfd, fmt, __VA_ARGS__) < 0 || fflush(cmdfd) < 0) \ | |||
319 | output_failed = true1, output_errno = errno(*__errno_location ()); \ | |||
320 | } while (0) | |||
321 | ||||
322 | /* | |||
323 | * Escape single quotes and backslashes, suitably for insertions into | |||
324 | * configuration files or SQL E'' strings. | |||
325 | */ | |||
326 | static char * | |||
327 | escape_quotes(const char *src) | |||
328 | { | |||
329 | char *result = escape_single_quotes_ascii(src); | |||
330 | ||||
331 | if (!result) | |||
332 | { | |||
333 | pg_log_error("out of memory")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "out of memory"); } while (0); | |||
334 | exit(1); | |||
335 | } | |||
336 | return result; | |||
337 | } | |||
338 | ||||
339 | /* | |||
340 | * Escape a field value to be inserted into the BKI data. | |||
341 | * Run the value through escape_quotes (which will be inverted | |||
342 | * by the backend's DeescapeQuotedString() function), then wrap | |||
343 | * the value in single quotes, even if that isn't strictly necessary. | |||
344 | */ | |||
345 | static char * | |||
346 | escape_quotes_bki(const char *src) | |||
347 | { | |||
348 | char *result; | |||
349 | char *data = escape_quotes(src); | |||
350 | char *resultp; | |||
351 | char *datap; | |||
352 | ||||
353 | result = (char *) pg_malloc(strlen(data) + 3); | |||
354 | resultp = result; | |||
355 | *resultp++ = '\''; | |||
356 | for (datap = data; *datap; datap++) | |||
357 | *resultp++ = *datap; | |||
358 | *resultp++ = '\''; | |||
359 | *resultp = '\0'; | |||
360 | ||||
361 | free(data); | |||
362 | return result; | |||
363 | } | |||
364 | ||||
365 | /* | |||
366 | * make a copy of the array of lines, with token replaced by replacement | |||
367 | * the first time it occurs on each line. | |||
368 | * | |||
369 | * This does most of what sed was used for in the shell script, but | |||
370 | * doesn't need any regexp stuff. | |||
371 | */ | |||
372 | static char ** | |||
373 | replace_token(char **lines, const char *token, const char *replacement) | |||
374 | { | |||
375 | int numlines = 1; | |||
376 | int i; | |||
377 | char **result; | |||
378 | int toklen, | |||
379 | replen, | |||
380 | diff; | |||
381 | ||||
382 | for (i = 0; lines[i]; i++) | |||
383 | numlines++; | |||
384 | ||||
385 | result = (char **) pg_malloc(numlines * sizeof(char *)); | |||
386 | ||||
387 | toklen = strlen(token); | |||
388 | replen = strlen(replacement); | |||
389 | diff = replen - toklen; | |||
390 | ||||
391 | for (i = 0; i < numlines; i++) | |||
392 | { | |||
393 | char *where; | |||
394 | char *newline; | |||
395 | int pre; | |||
396 | ||||
397 | /* just copy pointer if NULL or no change needed */ | |||
398 | if (lines[i] == NULL((void*)0) || (where = strstr(lines[i], token)) == NULL((void*)0)) | |||
399 | { | |||
400 | result[i] = lines[i]; | |||
401 | continue; | |||
402 | } | |||
403 | ||||
404 | /* if we get here a change is needed - set up new line */ | |||
405 | ||||
406 | newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1); | |||
407 | ||||
408 | pre = where - lines[i]; | |||
409 | ||||
410 | memcpy(newline, lines[i], pre); | |||
411 | ||||
412 | memcpy(newline + pre, replacement, replen); | |||
413 | ||||
414 | strcpy(newline + pre + replen, lines[i] + pre + toklen); | |||
415 | ||||
416 | result[i] = newline; | |||
417 | } | |||
418 | ||||
419 | return result; | |||
420 | } | |||
421 | ||||
422 | /* | |||
423 | * make a copy of lines without any that contain the token | |||
424 | * | |||
425 | * a sort of poor man's grep -v | |||
426 | */ | |||
427 | #ifndef HAVE_UNIX_SOCKETS1 | |||
428 | static char ** | |||
429 | filter_lines_with_token(char **lines, const char *token) | |||
430 | { | |||
431 | int numlines = 1; | |||
432 | int i, | |||
433 | src, | |||
434 | dst; | |||
435 | char **result; | |||
436 | ||||
437 | for (i = 0; lines[i]; i++) | |||
438 | numlines++; | |||
439 | ||||
440 | result = (char **) pg_malloc(numlines * sizeof(char *)); | |||
441 | ||||
442 | for (src = 0, dst = 0; src < numlines; src++) | |||
443 | { | |||
444 | if (lines[src] == NULL((void*)0) || strstr(lines[src], token) == NULL((void*)0)) | |||
445 | result[dst++] = lines[src]; | |||
446 | } | |||
447 | ||||
448 | return result; | |||
449 | } | |||
450 | #endif | |||
451 | ||||
452 | /* | |||
453 | * get the lines from a text file | |||
454 | */ | |||
455 | static char ** | |||
456 | readfile(const char *path) | |||
457 | { | |||
458 | char **result; | |||
459 | FILE *infile; | |||
460 | StringInfoData line; | |||
461 | int maxlines; | |||
462 | int n; | |||
463 | ||||
464 | if ((infile = fopen(path, "r")) == NULL((void*)0)) | |||
465 | { | |||
466 | pg_log_error("could not open file \"%s\" for reading: %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not open file \"%s\" for reading: %m" , path); } while(0); | |||
467 | exit(1); | |||
468 | } | |||
469 | ||||
470 | initStringInfo(&line); | |||
471 | ||||
472 | maxlines = 1024; | |||
473 | result = (char **) pg_malloc(maxlines * sizeof(char *)); | |||
474 | ||||
475 | n = 0; | |||
476 | while (pg_get_line_buf(infile, &line)) | |||
477 | { | |||
478 | /* make sure there will be room for a trailing NULL pointer */ | |||
479 | if (n >= maxlines - 1) | |||
480 | { | |||
481 | maxlines *= 2; | |||
482 | result = (char **) pg_realloc(result, maxlines * sizeof(char *)); | |||
483 | } | |||
484 | ||||
485 | result[n++] = pg_strdup(line.data); | |||
486 | } | |||
487 | result[n] = NULL((void*)0); | |||
488 | ||||
489 | pfree(line.data); | |||
490 | ||||
491 | fclose(infile); | |||
492 | ||||
493 | return result; | |||
494 | } | |||
495 | ||||
496 | /* | |||
497 | * write an array of lines to a file | |||
498 | * | |||
499 | * This is only used to write text files. Use fopen "w" not PG_BINARY_W | |||
500 | * so that the resulting configuration files are nicely editable on Windows. | |||
501 | */ | |||
502 | static void | |||
503 | writefile(char *path, char **lines) | |||
504 | { | |||
505 | FILE *out_file; | |||
506 | char **line; | |||
507 | ||||
508 | if ((out_file = fopen(path, "w")) == NULL((void*)0)) | |||
509 | { | |||
510 | pg_log_error("could not open file \"%s\" for writing: %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not open file \"%s\" for writing: %m" , path); } while(0); | |||
511 | exit(1); | |||
512 | } | |||
513 | for (line = lines; *line != NULL((void*)0); line++) | |||
514 | { | |||
515 | if (fputs(*line, out_file) < 0) | |||
516 | { | |||
517 | pg_log_error("could not write file \"%s\": %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not write file \"%s\": %m" , path); } while(0); | |||
518 | exit(1); | |||
519 | } | |||
520 | free(*line); | |||
521 | } | |||
522 | if (fclose(out_file)) | |||
523 | { | |||
524 | pg_log_error("could not write file \"%s\": %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not write file \"%s\": %m" , path); } while(0); | |||
525 | exit(1); | |||
526 | } | |||
527 | } | |||
528 | ||||
529 | /* | |||
530 | * Open a subcommand with suitable error messaging | |||
531 | */ | |||
532 | static FILE * | |||
533 | popen_check(const char *command, const char *mode) | |||
534 | { | |||
535 | FILE *cmdfd; | |||
536 | ||||
537 | fflush(stdoutstdout); | |||
538 | fflush(stderrstderr); | |||
539 | errno(*__errno_location ()) = 0; | |||
540 | cmdfd = popen(command, mode); | |||
541 | if (cmdfd == NULL((void*)0)) | |||
542 | pg_log_error("could not execute command \"%s\": %m", command)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not execute command \"%s\": %m" , command); } while(0); | |||
543 | return cmdfd; | |||
544 | } | |||
545 | ||||
546 | /* | |||
547 | * clean up any files we created on failure | |||
548 | * if we created the data directory remove it too | |||
549 | */ | |||
550 | static void | |||
551 | cleanup_directories_atexit(void) | |||
552 | { | |||
553 | if (success) | |||
554 | return; | |||
555 | ||||
556 | if (!noclean) | |||
557 | { | |||
558 | if (made_new_pgdata) | |||
559 | { | |||
560 | pg_log_info("removing data directory \"%s\"", pg_data)do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "removing data directory \"%s\"" , pg_data); } while(0); | |||
561 | if (!rmtree(pg_data, true1)) | |||
562 | pg_log_error("failed to remove data directory")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "failed to remove data directory" ); } while(0); | |||
563 | } | |||
564 | else if (found_existing_pgdata) | |||
565 | { | |||
566 | pg_log_info("removing contents of data directory \"%s\"",do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "removing contents of data directory \"%s\"" , pg_data); } while(0) | |||
567 | pg_data)do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "removing contents of data directory \"%s\"" , pg_data); } while(0); | |||
568 | if (!rmtree(pg_data, false0)) | |||
569 | pg_log_error("failed to remove contents of data directory")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "failed to remove contents of data directory" ); } while(0); | |||
570 | } | |||
571 | ||||
572 | if (made_new_xlogdir) | |||
573 | { | |||
574 | pg_log_info("removing WAL directory \"%s\"", xlog_dir)do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "removing WAL directory \"%s\"" , xlog_dir); } while(0); | |||
575 | if (!rmtree(xlog_dir, true1)) | |||
576 | pg_log_error("failed to remove WAL directory")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "failed to remove WAL directory" ); } while(0); | |||
577 | } | |||
578 | else if (found_existing_xlogdir) | |||
579 | { | |||
580 | pg_log_info("removing contents of WAL directory \"%s\"", xlog_dir)do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "removing contents of WAL directory \"%s\"" , xlog_dir); } while(0); | |||
581 | if (!rmtree(xlog_dir, false0)) | |||
582 | pg_log_error("failed to remove contents of WAL directory")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "failed to remove contents of WAL directory" ); } while(0); | |||
583 | } | |||
584 | /* otherwise died during startup, do nothing! */ | |||
585 | } | |||
586 | else | |||
587 | { | |||
588 | if (made_new_pgdata || found_existing_pgdata) | |||
589 | pg_log_info("data directory \"%s\" not removed at user's request",do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "data directory \"%s\" not removed at user's request" , pg_data); } while(0) | |||
590 | pg_data)do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "data directory \"%s\" not removed at user's request" , pg_data); } while(0); | |||
591 | ||||
592 | if (made_new_xlogdir || found_existing_xlogdir) | |||
593 | pg_log_info("WAL directory \"%s\" not removed at user's request",do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "WAL directory \"%s\" not removed at user's request" , xlog_dir); } while(0) | |||
594 | xlog_dir)do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "WAL directory \"%s\" not removed at user's request" , xlog_dir); } while(0); | |||
595 | } | |||
596 | } | |||
597 | ||||
598 | /* | |||
599 | * find the current user | |||
600 | * | |||
601 | * on unix make sure it isn't root | |||
602 | */ | |||
603 | static char * | |||
604 | get_id(void) | |||
605 | { | |||
606 | const char *username; | |||
607 | ||||
608 | #ifndef WIN32 | |||
609 | if (geteuid() == 0) /* 0 is root's uid */ | |||
610 | { | |||
611 | pg_log_error("cannot be run as root")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "cannot be run as root" ); } while(0); | |||
612 | fprintfpg_fprintf(stderrstderr, | |||
613 | _("Please log in (using, e.g., \"su\") as the (unprivileged) user that will\n"("Please log in (using, e.g., \"su\") as the (unprivileged) user that will\n" "own the server process.\n") | |||
614 | "own the server process.\n")("Please log in (using, e.g., \"su\") as the (unprivileged) user that will\n" "own the server process.\n")); | |||
615 | exit(1); | |||
616 | } | |||
617 | #endif | |||
618 | ||||
619 | username = get_user_name_or_exit(progname); | |||
620 | ||||
621 | return pg_strdup(username); | |||
622 | } | |||
623 | ||||
624 | static char * | |||
625 | encodingid_to_string(int enc) | |||
626 | { | |||
627 | char result[20]; | |||
628 | ||||
629 | sprintfpg_sprintf(result, "%d", enc); | |||
630 | return pg_strdup(result); | |||
631 | } | |||
632 | ||||
633 | /* | |||
634 | * get the encoding id for a given encoding name | |||
635 | */ | |||
636 | static int | |||
637 | get_encoding_id(const char *encoding_name) | |||
638 | { | |||
639 | int enc; | |||
640 | ||||
641 | if (encoding_name && *encoding_name) | |||
642 | { | |||
643 | if ((enc = pg_valid_server_encoding(encoding_name)) >= 0) | |||
644 | return enc; | |||
645 | } | |||
646 | pg_log_error("\"%s\" is not a valid server encoding name",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "\"%s\" is not a valid server encoding name" , encoding_name ? encoding_name : "(null)"); } while(0) | |||
647 | encoding_name ? encoding_name : "(null)")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "\"%s\" is not a valid server encoding name" , encoding_name ? encoding_name : "(null)"); } while(0); | |||
648 | exit(1); | |||
649 | } | |||
650 | ||||
651 | /* | |||
652 | * Support for determining the best default text search configuration. | |||
653 | * We key this off the first part of LC_CTYPE (ie, the language name). | |||
654 | */ | |||
655 | struct tsearch_config_match | |||
656 | { | |||
657 | const char *tsconfname; | |||
658 | const char *langname; | |||
659 | }; | |||
660 | ||||
661 | static const struct tsearch_config_match tsearch_config_languages[] = | |||
662 | { | |||
663 | {"arabic", "ar"}, | |||
664 | {"arabic", "Arabic"}, | |||
665 | {"armenian", "hy"}, | |||
666 | {"armenian", "Armenian"}, | |||
667 | {"basque", "eu"}, | |||
668 | {"basque", "Basque"}, | |||
669 | {"catalan", "ca"}, | |||
670 | {"catalan", "Catalan"}, | |||
671 | {"danish", "da"}, | |||
672 | {"danish", "Danish"}, | |||
673 | {"dutch", "nl"}, | |||
674 | {"dutch", "Dutch"}, | |||
675 | {"english", "C"}, | |||
676 | {"english", "POSIX"}, | |||
677 | {"english", "en"}, | |||
678 | {"english", "English"}, | |||
679 | {"finnish", "fi"}, | |||
680 | {"finnish", "Finnish"}, | |||
681 | {"french", "fr"}, | |||
682 | {"french", "French"}, | |||
683 | {"german", "de"}, | |||
684 | {"german", "German"}, | |||
685 | {"greek", "el"}, | |||
686 | {"greek", "Greek"}, | |||
687 | {"hindi", "hi"}, | |||
688 | {"hindi", "Hindi"}, | |||
689 | {"hungarian", "hu"}, | |||
690 | {"hungarian", "Hungarian"}, | |||
691 | {"indonesian", "id"}, | |||
692 | {"indonesian", "Indonesian"}, | |||
693 | {"irish", "ga"}, | |||
694 | {"irish", "Irish"}, | |||
695 | {"italian", "it"}, | |||
696 | {"italian", "Italian"}, | |||
697 | {"lithuanian", "lt"}, | |||
698 | {"lithuanian", "Lithuanian"}, | |||
699 | {"nepali", "ne"}, | |||
700 | {"nepali", "Nepali"}, | |||
701 | {"norwegian", "no"}, | |||
702 | {"norwegian", "Norwegian"}, | |||
703 | {"portuguese", "pt"}, | |||
704 | {"portuguese", "Portuguese"}, | |||
705 | {"romanian", "ro"}, | |||
706 | {"russian", "ru"}, | |||
707 | {"russian", "Russian"}, | |||
708 | {"serbian", "sr"}, | |||
709 | {"serbian", "Serbian"}, | |||
710 | {"spanish", "es"}, | |||
711 | {"spanish", "Spanish"}, | |||
712 | {"swedish", "sv"}, | |||
713 | {"swedish", "Swedish"}, | |||
714 | {"tamil", "ta"}, | |||
715 | {"tamil", "Tamil"}, | |||
716 | {"turkish", "tr"}, | |||
717 | {"turkish", "Turkish"}, | |||
718 | {"yiddish", "yi"}, | |||
719 | {"yiddish", "Yiddish"}, | |||
720 | {NULL((void*)0), NULL((void*)0)} /* end marker */ | |||
721 | }; | |||
722 | ||||
723 | /* | |||
724 | * Look for a text search configuration matching lc_ctype, and return its | |||
725 | * name; return NULL if no match. | |||
726 | */ | |||
727 | static const char * | |||
728 | find_matching_ts_config(const char *lc_type) | |||
729 | { | |||
730 | int i; | |||
731 | char *langname, | |||
732 | *ptr; | |||
733 | ||||
734 | /* | |||
735 | * Convert lc_ctype to a language name by stripping everything after an | |||
736 | * underscore (usual case) or a hyphen (Windows "locale name"; see | |||
737 | * comments at IsoLocaleName()). | |||
738 | * | |||
739 | * XXX Should ' ' be a stop character? This would select "norwegian" for | |||
740 | * the Windows locale "Norwegian (Nynorsk)_Norway.1252". If we do so, we | |||
741 | * should also accept the "nn" and "nb" Unix locales. | |||
742 | * | |||
743 | * Just for paranoia, we also stop at '.' or '@'. | |||
744 | */ | |||
745 | if (lc_type == NULL((void*)0)) | |||
746 | langname = pg_strdup(""); | |||
747 | else | |||
748 | { | |||
749 | ptr = langname = pg_strdup(lc_type); | |||
750 | while (*ptr && | |||
751 | *ptr != '_' && *ptr != '-' && *ptr != '.' && *ptr != '@') | |||
752 | ptr++; | |||
753 | *ptr = '\0'; | |||
754 | } | |||
755 | ||||
756 | for (i = 0; tsearch_config_languages[i].tsconfname; i++) | |||
757 | { | |||
758 | if (pg_strcasecmp(tsearch_config_languages[i].langname, langname) == 0) | |||
759 | { | |||
760 | free(langname); | |||
761 | return tsearch_config_languages[i].tsconfname; | |||
762 | } | |||
763 | } | |||
764 | ||||
765 | free(langname); | |||
766 | return NULL((void*)0); | |||
767 | } | |||
768 | ||||
769 | ||||
770 | /* | |||
771 | * set name of given input file variable under data directory | |||
772 | */ | |||
773 | static void | |||
774 | set_input(char **dest, const char *filename) | |||
775 | { | |||
776 | *dest = psprintf("%s/%s", share_path, filename); | |||
777 | } | |||
778 | ||||
779 | /* | |||
780 | * check that given input file exists | |||
781 | */ | |||
782 | static void | |||
783 | check_input(char *path) | |||
784 | { | |||
785 | struct stat statbuf; | |||
786 | ||||
787 | if (stat(path, &statbuf) != 0) | |||
788 | { | |||
789 | if (errno(*__errno_location ()) == ENOENT2) | |||
790 | { | |||
791 | pg_log_error("file \"%s\" does not exist", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "file \"%s\" does not exist" , path); } while(0); | |||
792 | fprintfpg_fprintf(stderrstderr, | |||
793 | _("This might mean you have a corrupted installation or identified\n"("This might mean you have a corrupted installation or identified\n" "the wrong directory with the invocation option -L.\n") | |||
794 | "the wrong directory with the invocation option -L.\n")("This might mean you have a corrupted installation or identified\n" "the wrong directory with the invocation option -L.\n")); | |||
795 | } | |||
796 | else | |||
797 | { | |||
798 | pg_log_error("could not access file \"%s\": %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not access file \"%s\": %m" , path); } while(0); | |||
799 | fprintfpg_fprintf(stderrstderr, | |||
800 | _("This might mean you have a corrupted installation or identified\n"("This might mean you have a corrupted installation or identified\n" "the wrong directory with the invocation option -L.\n") | |||
801 | "the wrong directory with the invocation option -L.\n")("This might mean you have a corrupted installation or identified\n" "the wrong directory with the invocation option -L.\n")); | |||
802 | } | |||
803 | exit(1); | |||
804 | } | |||
805 | if (!S_ISREG(statbuf.st_mode)((((statbuf.st_mode)) & 0170000) == (0100000))) | |||
806 | { | |||
807 | pg_log_error("file \"%s\" is not a regular file", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "file \"%s\" is not a regular file" , path); } while(0); | |||
808 | fprintfpg_fprintf(stderrstderr, | |||
809 | _("This might mean you have a corrupted installation or identified\n"("This might mean you have a corrupted installation or identified\n" "the wrong directory with the invocation option -L.\n") | |||
810 | "the wrong directory with the invocation option -L.\n")("This might mean you have a corrupted installation or identified\n" "the wrong directory with the invocation option -L.\n")); | |||
811 | exit(1); | |||
812 | } | |||
813 | } | |||
814 | ||||
815 | /* | |||
816 | * write out the PG_VERSION file in the data dir, or its subdirectory | |||
817 | * if extrapath is not NULL | |||
818 | */ | |||
819 | static void | |||
820 | write_version_file(const char *extrapath) | |||
821 | { | |||
822 | FILE *version_file; | |||
823 | char *path; | |||
824 | ||||
825 | if (extrapath == NULL((void*)0)) | |||
826 | path = psprintf("%s/PG_VERSION", pg_data); | |||
827 | else | |||
828 | path = psprintf("%s/%s/PG_VERSION", pg_data, extrapath); | |||
829 | ||||
830 | if ((version_file = fopen(path, PG_BINARY_W"w")) == NULL((void*)0)) | |||
831 | { | |||
832 | pg_log_error("could not open file \"%s\" for writing: %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not open file \"%s\" for writing: %m" , path); } while(0); | |||
833 | exit(1); | |||
834 | } | |||
835 | if (fprintfpg_fprintf(version_file, "%s\n", PG_MAJORVERSION"15") < 0 || | |||
836 | fclose(version_file)) | |||
837 | { | |||
838 | pg_log_error("could not write file \"%s\": %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not write file \"%s\": %m" , path); } while(0); | |||
839 | exit(1); | |||
840 | } | |||
841 | free(path); | |||
842 | } | |||
843 | ||||
844 | /* | |||
845 | * set up an empty config file so we can check config settings by launching | |||
846 | * a test backend | |||
847 | */ | |||
848 | static void | |||
849 | set_null_conf(void) | |||
850 | { | |||
851 | FILE *conf_file; | |||
852 | char *path; | |||
853 | ||||
854 | path = psprintf("%s/postgresql.conf", pg_data); | |||
855 | conf_file = fopen(path, PG_BINARY_W"w"); | |||
856 | if (conf_file == NULL((void*)0)) | |||
857 | { | |||
858 | pg_log_error("could not open file \"%s\" for writing: %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not open file \"%s\" for writing: %m" , path); } while(0); | |||
859 | exit(1); | |||
860 | } | |||
861 | if (fclose(conf_file)) | |||
862 | { | |||
863 | pg_log_error("could not write file \"%s\": %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not write file \"%s\": %m" , path); } while(0); | |||
864 | exit(1); | |||
865 | } | |||
866 | free(path); | |||
867 | } | |||
868 | ||||
869 | /* | |||
870 | * Determine which dynamic shared memory implementation should be used on | |||
871 | * this platform. POSIX shared memory is preferable because the default | |||
872 | * allocation limits are much higher than the limits for System V on most | |||
873 | * systems that support both, but the fact that a platform has shm_open | |||
874 | * doesn't guarantee that that call will succeed when attempted. So, we | |||
875 | * attempt to reproduce what the postmaster will do when allocating a POSIX | |||
876 | * segment in dsm_impl.c; if it doesn't work, we assume it won't work for | |||
877 | * the postmaster either, and configure the cluster for System V shared | |||
878 | * memory instead. | |||
879 | */ | |||
880 | static const char * | |||
881 | choose_dsm_implementation(void) | |||
882 | { | |||
883 | #ifdef HAVE_SHM_OPEN1 | |||
884 | int ntries = 10; | |||
885 | pg_prng_state prng_state; | |||
886 | ||||
887 | /* Initialize prng; this function is its only user in this program. */ | |||
888 | pg_prng_seed(&prng_state, (uint64) (getpid() ^ time(NULL((void*)0)))); | |||
889 | ||||
890 | while (ntries > 0) | |||
891 | { | |||
892 | uint32 handle; | |||
893 | char name[64]; | |||
894 | int fd; | |||
895 | ||||
896 | handle = pg_prng_uint32(&prng_state); | |||
897 | snprintfpg_snprintf(name, 64, "/PostgreSQL.%u", handle); | |||
898 | if ((fd = shm_open(name, O_CREAT0100 | O_RDWR02 | O_EXCL0200, 0600)) != -1) | |||
899 | { | |||
900 | close(fd); | |||
901 | shm_unlink(name); | |||
902 | return "posix"; | |||
903 | } | |||
904 | if (errno(*__errno_location ()) != EEXIST17) | |||
905 | break; | |||
906 | --ntries; | |||
907 | } | |||
908 | #endif | |||
909 | ||||
910 | #ifdef WIN32 | |||
911 | return "windows"; | |||
912 | #else | |||
913 | return "sysv"; | |||
914 | #endif | |||
915 | } | |||
916 | ||||
917 | /* | |||
918 | * Determine platform-specific config settings | |||
919 | * | |||
920 | * Use reasonable values if kernel will let us, else scale back. | |||
921 | */ | |||
922 | static void | |||
923 | test_config_settings(void) | |||
924 | { | |||
925 | /* | |||
926 | * This macro defines the minimum shared_buffers we want for a given | |||
927 | * max_connections value. The arrays show the settings to try. | |||
928 | */ | |||
929 | #define MIN_BUFS_FOR_CONNS(nconns)((nconns) * 10) ((nconns) * 10) | |||
930 | ||||
931 | static const int trial_conns[] = { | |||
932 | 100, 50, 40, 30, 20 | |||
933 | }; | |||
934 | static const int trial_bufs[] = { | |||
935 | 16384, 8192, 4096, 3584, 3072, 2560, 2048, 1536, | |||
936 | 1000, 900, 800, 700, 600, 500, | |||
937 | 400, 300, 200, 100, 50 | |||
938 | }; | |||
939 | ||||
940 | char cmd[MAXPGPATH1024]; | |||
941 | const int connslen = sizeof(trial_conns) / sizeof(int); | |||
942 | const int bufslen = sizeof(trial_bufs) / sizeof(int); | |||
943 | int i, | |||
944 | status, | |||
945 | test_conns, | |||
946 | test_buffs, | |||
947 | ok_buffers = 0; | |||
948 | ||||
949 | /* | |||
950 | * Need to determine working DSM implementation first so that subsequent | |||
951 | * tests don't fail because DSM setting doesn't work. | |||
952 | */ | |||
953 | printf(_("selecting dynamic shared memory implementation ... "))pg_printf(("selecting dynamic shared memory implementation ... " )); | |||
954 | fflush(stdoutstdout); | |||
955 | dynamic_shared_memory_type = choose_dsm_implementation(); | |||
956 | printf("%s\n", dynamic_shared_memory_type)pg_printf("%s\n", dynamic_shared_memory_type); | |||
957 | ||||
958 | /* | |||
959 | * Probe for max_connections before shared_buffers, since it is subject to | |||
960 | * more constraints than shared_buffers. | |||
961 | */ | |||
962 | printf(_("selecting default max_connections ... "))pg_printf(("selecting default max_connections ... ")); | |||
963 | fflush(stdoutstdout); | |||
964 | ||||
965 | for (i = 0; i < connslen; i++) | |||
966 | { | |||
967 | test_conns = trial_conns[i]; | |||
968 | test_buffs = MIN_BUFS_FOR_CONNS(test_conns)((test_conns) * 10); | |||
969 | ||||
970 | snprintfpg_snprintf(cmd, sizeof(cmd), | |||
971 | "\"%s\" --check %s %s " | |||
972 | "-c max_connections=%d " | |||
973 | "-c shared_buffers=%d " | |||
974 | "-c dynamic_shared_memory_type=%s " | |||
975 | "< \"%s\" > \"%s\" 2>&1", | |||
976 | backend_exec, boot_options, extra_options, | |||
977 | test_conns, test_buffs, | |||
978 | dynamic_shared_memory_type, | |||
979 | DEVNULL"/dev/null", DEVNULL"/dev/null"); | |||
980 | status = system(cmd); | |||
981 | if (status == 0) | |||
982 | { | |||
983 | ok_buffers = test_buffs; | |||
984 | break; | |||
985 | } | |||
986 | } | |||
987 | if (i >= connslen) | |||
988 | i = connslen - 1; | |||
989 | n_connections = trial_conns[i]; | |||
990 | ||||
991 | printf("%d\n", n_connections)pg_printf("%d\n", n_connections); | |||
992 | ||||
993 | printf(_("selecting default shared_buffers ... "))pg_printf(("selecting default shared_buffers ... ")); | |||
994 | fflush(stdoutstdout); | |||
995 | ||||
996 | for (i = 0; i < bufslen; i++) | |||
997 | { | |||
998 | /* Use same amount of memory, independent of BLCKSZ */ | |||
999 | test_buffs = (trial_bufs[i] * 8192) / BLCKSZ8192; | |||
1000 | if (test_buffs <= ok_buffers) | |||
1001 | { | |||
1002 | test_buffs = ok_buffers; | |||
1003 | break; | |||
1004 | } | |||
1005 | ||||
1006 | snprintfpg_snprintf(cmd, sizeof(cmd), | |||
1007 | "\"%s\" --check %s %s " | |||
1008 | "-c max_connections=%d " | |||
1009 | "-c shared_buffers=%d " | |||
1010 | "-c dynamic_shared_memory_type=%s " | |||
1011 | "< \"%s\" > \"%s\" 2>&1", | |||
1012 | backend_exec, boot_options, extra_options, | |||
1013 | n_connections, test_buffs, | |||
1014 | dynamic_shared_memory_type, | |||
1015 | DEVNULL"/dev/null", DEVNULL"/dev/null"); | |||
1016 | status = system(cmd); | |||
1017 | if (status == 0) | |||
1018 | break; | |||
1019 | } | |||
1020 | n_buffers = test_buffs; | |||
1021 | ||||
1022 | if ((n_buffers * (BLCKSZ8192 / 1024)) % 1024 == 0) | |||
1023 | printf("%dMB\n", (n_buffers * (BLCKSZ / 1024)) / 1024)pg_printf("%dMB\n", (n_buffers * (8192 / 1024)) / 1024); | |||
1024 | else | |||
1025 | printf("%dkB\n", n_buffers * (BLCKSZ / 1024))pg_printf("%dkB\n", n_buffers * (8192 / 1024)); | |||
1026 | ||||
1027 | printf(_("selecting default time zone ... "))pg_printf(("selecting default time zone ... ")); | |||
1028 | fflush(stdoutstdout); | |||
1029 | default_timezone = select_default_timezone(share_path); | |||
1030 | printf("%s\n", default_timezone ? default_timezone : "GMT")pg_printf("%s\n", default_timezone ? default_timezone : "GMT" ); | |||
1031 | } | |||
1032 | ||||
1033 | /* | |||
1034 | * Calculate the default wal_size with a "pretty" unit. | |||
1035 | */ | |||
1036 | static char * | |||
1037 | pretty_wal_size(int segment_count) | |||
1038 | { | |||
1039 | int sz = wal_segment_size_mb * segment_count; | |||
1040 | char *result = pg_malloc(14); | |||
1041 | ||||
1042 | if ((sz % 1024) == 0) | |||
1043 | snprintfpg_snprintf(result, 14, "%dGB", sz / 1024); | |||
1044 | else | |||
1045 | snprintfpg_snprintf(result, 14, "%dMB", sz); | |||
1046 | ||||
1047 | return result; | |||
1048 | } | |||
1049 | ||||
1050 | /* | |||
1051 | * set up all the config files | |||
1052 | */ | |||
1053 | static void | |||
1054 | setup_config(void) | |||
1055 | { | |||
1056 | char **conflines; | |||
1057 | char repltok[MAXPGPATH1024]; | |||
1058 | char path[MAXPGPATH1024]; | |||
1059 | char *autoconflines[3]; | |||
1060 | ||||
1061 | fputs(_("creating configuration files ... ")("creating configuration files ... "), stdoutstdout); | |||
1062 | fflush(stdoutstdout); | |||
1063 | ||||
1064 | /* postgresql.conf */ | |||
1065 | ||||
1066 | conflines = readfile(conf_file); | |||
1067 | ||||
1068 | snprintfpg_snprintf(repltok, sizeof(repltok), "max_connections = %d", n_connections); | |||
1069 | conflines = replace_token(conflines, "#max_connections = 100", repltok); | |||
1070 | ||||
1071 | if ((n_buffers * (BLCKSZ8192 / 1024)) % 1024 == 0) | |||
| ||||
1072 | snprintfpg_snprintf(repltok, sizeof(repltok), "shared_buffers = %dMB", | |||
1073 | (n_buffers * (BLCKSZ8192 / 1024)) / 1024); | |||
1074 | else | |||
1075 | snprintfpg_snprintf(repltok, sizeof(repltok), "shared_buffers = %dkB", | |||
1076 | n_buffers * (BLCKSZ8192 / 1024)); | |||
1077 | conflines = replace_token(conflines, "#shared_buffers = 128MB", repltok); | |||
1078 | ||||
1079 | #ifdef HAVE_UNIX_SOCKETS1 | |||
1080 | snprintfpg_snprintf(repltok, sizeof(repltok), "#unix_socket_directories = '%s'", | |||
1081 | DEFAULT_PGSOCKET_DIR"/tmp"); | |||
1082 | #else | |||
1083 | snprintfpg_snprintf(repltok, sizeof(repltok), "#unix_socket_directories = ''"); | |||
1084 | #endif | |||
1085 | conflines = replace_token(conflines, "#unix_socket_directories = '/tmp'", | |||
1086 | repltok); | |||
1087 | ||||
1088 | #if DEF_PGPORT5432 != 5432 | |||
1089 | snprintfpg_snprintf(repltok, sizeof(repltok), "#port = %d", DEF_PGPORT5432); | |||
1090 | conflines = replace_token(conflines, "#port = 5432", repltok); | |||
1091 | #endif | |||
1092 | ||||
1093 | /* set default max_wal_size and min_wal_size */ | |||
1094 | snprintfpg_snprintf(repltok, sizeof(repltok), "min_wal_size = %s", | |||
1095 | pretty_wal_size(DEFAULT_MIN_WAL_SEGS5)); | |||
1096 | conflines = replace_token(conflines, "#min_wal_size = 80MB", repltok); | |||
1097 | ||||
1098 | snprintfpg_snprintf(repltok, sizeof(repltok), "max_wal_size = %s", | |||
1099 | pretty_wal_size(DEFAULT_MAX_WAL_SEGS64)); | |||
1100 | conflines = replace_token(conflines, "#max_wal_size = 1GB", repltok); | |||
| ||||
1101 | ||||
1102 | snprintfpg_snprintf(repltok, sizeof(repltok), "lc_messages = '%s'", | |||
1103 | escape_quotes(lc_messages)); | |||
1104 | conflines = replace_token(conflines, "#lc_messages = 'C'", repltok); | |||
1105 | ||||
1106 | snprintfpg_snprintf(repltok, sizeof(repltok), "lc_monetary = '%s'", | |||
1107 | escape_quotes(lc_monetary)); | |||
1108 | conflines = replace_token(conflines, "#lc_monetary = 'C'", repltok); | |||
1109 | ||||
1110 | snprintfpg_snprintf(repltok, sizeof(repltok), "lc_numeric = '%s'", | |||
1111 | escape_quotes(lc_numeric)); | |||
1112 | conflines = replace_token(conflines, "#lc_numeric = 'C'", repltok); | |||
1113 | ||||
1114 | snprintfpg_snprintf(repltok, sizeof(repltok), "lc_time = '%s'", | |||
1115 | escape_quotes(lc_time)); | |||
1116 | conflines = replace_token(conflines, "#lc_time = 'C'", repltok); | |||
1117 | ||||
1118 | switch (locale_date_order(lc_time)) | |||
1119 | { | |||
1120 | case DATEORDER_YMD0: | |||
1121 | strcpy(repltok, "datestyle = 'iso, ymd'"); | |||
1122 | break; | |||
1123 | case DATEORDER_DMY1: | |||
1124 | strcpy(repltok, "datestyle = 'iso, dmy'"); | |||
1125 | break; | |||
1126 | case DATEORDER_MDY2: | |||
1127 | default: | |||
1128 | strcpy(repltok, "datestyle = 'iso, mdy'"); | |||
1129 | break; | |||
1130 | } | |||
1131 | conflines = replace_token(conflines, "#datestyle = 'iso, mdy'", repltok); | |||
1132 | ||||
1133 | snprintfpg_snprintf(repltok, sizeof(repltok), | |||
1134 | "default_text_search_config = 'pg_catalog.%s'", | |||
1135 | escape_quotes(default_text_search_config)); | |||
1136 | conflines = replace_token(conflines, | |||
1137 | "#default_text_search_config = 'pg_catalog.simple'", | |||
1138 | repltok); | |||
1139 | ||||
1140 | if (default_timezone) | |||
1141 | { | |||
1142 | snprintfpg_snprintf(repltok, sizeof(repltok), "timezone = '%s'", | |||
1143 | escape_quotes(default_timezone)); | |||
1144 | conflines = replace_token(conflines, "#timezone = 'GMT'", repltok); | |||
1145 | snprintfpg_snprintf(repltok, sizeof(repltok), "log_timezone = '%s'", | |||
1146 | escape_quotes(default_timezone)); | |||
1147 | conflines = replace_token(conflines, "#log_timezone = 'GMT'", repltok); | |||
1148 | } | |||
1149 | ||||
1150 | snprintfpg_snprintf(repltok, sizeof(repltok), "dynamic_shared_memory_type = %s", | |||
1151 | dynamic_shared_memory_type); | |||
1152 | conflines = replace_token(conflines, "#dynamic_shared_memory_type = posix", | |||
1153 | repltok); | |||
1154 | ||||
1155 | #if DEFAULT_BACKEND_FLUSH_AFTER0 > 0 | |||
1156 | snprintfpg_snprintf(repltok, sizeof(repltok), "#backend_flush_after = %dkB", | |||
1157 | DEFAULT_BACKEND_FLUSH_AFTER0 * (BLCKSZ8192 / 1024)); | |||
1158 | conflines = replace_token(conflines, "#backend_flush_after = 0", | |||
1159 | repltok); | |||
1160 | #endif | |||
1161 | ||||
1162 | #if DEFAULT_BGWRITER_FLUSH_AFTER64 > 0 | |||
1163 | snprintfpg_snprintf(repltok, sizeof(repltok), "#bgwriter_flush_after = %dkB", | |||
1164 | DEFAULT_BGWRITER_FLUSH_AFTER64 * (BLCKSZ8192 / 1024)); | |||
1165 | conflines = replace_token(conflines, "#bgwriter_flush_after = 0", | |||
1166 | repltok); | |||
1167 | #endif | |||
1168 | ||||
1169 | #if DEFAULT_CHECKPOINT_FLUSH_AFTER32 > 0 | |||
1170 | snprintfpg_snprintf(repltok, sizeof(repltok), "#checkpoint_flush_after = %dkB", | |||
1171 | DEFAULT_CHECKPOINT_FLUSH_AFTER32 * (BLCKSZ8192 / 1024)); | |||
1172 | conflines = replace_token(conflines, "#checkpoint_flush_after = 0", | |||
1173 | repltok); | |||
1174 | #endif | |||
1175 | ||||
1176 | #ifndef USE_PREFETCH | |||
1177 | conflines = replace_token(conflines, | |||
1178 | "#effective_io_concurrency = 1", | |||
1179 | "#effective_io_concurrency = 0"); | |||
1180 | #endif | |||
1181 | ||||
1182 | #ifdef WIN32 | |||
1183 | conflines = replace_token(conflines, | |||
1184 | "#update_process_title = on", | |||
1185 | "#update_process_title = off"); | |||
1186 | #endif | |||
1187 | ||||
1188 | /* | |||
1189 | * Change password_encryption setting to md5 if md5 was chosen as an | |||
1190 | * authentication method, unless scram-sha-256 was also chosen. | |||
1191 | */ | |||
1192 | if ((strcmp(authmethodlocal, "md5") == 0 && | |||
1193 | strcmp(authmethodhost, "scram-sha-256") != 0) || | |||
1194 | (strcmp(authmethodhost, "md5") == 0 && | |||
1195 | strcmp(authmethodlocal, "scram-sha-256") != 0)) | |||
1196 | { | |||
1197 | conflines = replace_token(conflines, | |||
1198 | "#password_encryption = scram-sha-256", | |||
1199 | "password_encryption = md5"); | |||
1200 | } | |||
1201 | ||||
1202 | /* | |||
1203 | * If group access has been enabled for the cluster then it makes sense to | |||
1204 | * ensure that the log files also allow group access. Otherwise a backup | |||
1205 | * from a user in the group would fail if the log files were not | |||
1206 | * relocated. | |||
1207 | */ | |||
1208 | if (pg_dir_create_mode == PG_DIR_MODE_GROUP((0400|0200|0100) | (0400 >> 3) | (0100 >> 3))) | |||
1209 | { | |||
1210 | conflines = replace_token(conflines, | |||
1211 | "#log_file_mode = 0600", | |||
1212 | "log_file_mode = 0640"); | |||
1213 | } | |||
1214 | ||||
1215 | snprintfpg_snprintf(path, sizeof(path), "%s/postgresql.conf", pg_data); | |||
1216 | ||||
1217 | writefile(path, conflines); | |||
1218 | if (chmod(path, pg_file_create_mode) != 0) | |||
1219 | { | |||
1220 | pg_log_error("could not change permissions of \"%s\": %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not change permissions of \"%s\": %m" , path); } while(0); | |||
1221 | exit(1); | |||
1222 | } | |||
1223 | ||||
1224 | /* | |||
1225 | * create the automatic configuration file to store the configuration | |||
1226 | * parameters set by ALTER SYSTEM command. The parameters present in this | |||
1227 | * file will override the value of parameters that exists before parse of | |||
1228 | * this file. | |||
1229 | */ | |||
1230 | autoconflines[0] = pg_strdup("# Do not edit this file manually!\n"); | |||
1231 | autoconflines[1] = pg_strdup("# It will be overwritten by the ALTER SYSTEM command.\n"); | |||
1232 | autoconflines[2] = NULL((void*)0); | |||
1233 | ||||
1234 | sprintfpg_sprintf(path, "%s/postgresql.auto.conf", pg_data); | |||
1235 | ||||
1236 | writefile(path, autoconflines); | |||
1237 | if (chmod(path, pg_file_create_mode) != 0) | |||
1238 | { | |||
1239 | pg_log_error("could not change permissions of \"%s\": %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not change permissions of \"%s\": %m" , path); } while(0); | |||
1240 | exit(1); | |||
1241 | } | |||
1242 | ||||
1243 | free(conflines); | |||
1244 | ||||
1245 | ||||
1246 | /* pg_hba.conf */ | |||
1247 | ||||
1248 | conflines = readfile(hba_file); | |||
1249 | ||||
1250 | #ifndef HAVE_UNIX_SOCKETS1 | |||
1251 | conflines = filter_lines_with_token(conflines, "@remove-line-for-nolocal@"); | |||
1252 | #else | |||
1253 | conflines = replace_token(conflines, "@remove-line-for-nolocal@", ""); | |||
1254 | #endif | |||
1255 | ||||
1256 | #ifdef HAVE_IPV61 | |||
1257 | ||||
1258 | /* | |||
1259 | * Probe to see if there is really any platform support for IPv6, and | |||
1260 | * comment out the relevant pg_hba line if not. This avoids runtime | |||
1261 | * warnings if getaddrinfo doesn't actually cope with IPv6. Particularly | |||
1262 | * useful on Windows, where executables built on a machine with IPv6 may | |||
1263 | * have to run on a machine without. | |||
1264 | */ | |||
1265 | { | |||
1266 | struct addrinfo *gai_result; | |||
1267 | struct addrinfo hints; | |||
1268 | int err = 0; | |||
1269 | ||||
1270 | #ifdef WIN32 | |||
1271 | /* need to call WSAStartup before calling getaddrinfo */ | |||
1272 | WSADATA wsaData; | |||
1273 | ||||
1274 | err = WSAStartup(MAKEWORD(2, 2), &wsaData); | |||
1275 | #endif | |||
1276 | ||||
1277 | /* for best results, this code should match parse_hba_line() */ | |||
1278 | hints.ai_flags = AI_NUMERICHOST0x0004; | |||
1279 | hints.ai_family = AF_UNSPEC0; | |||
1280 | hints.ai_socktype = 0; | |||
1281 | hints.ai_protocol = 0; | |||
1282 | hints.ai_addrlen = 0; | |||
1283 | hints.ai_canonname = NULL((void*)0); | |||
1284 | hints.ai_addr = NULL((void*)0); | |||
1285 | hints.ai_next = NULL((void*)0); | |||
1286 | ||||
1287 | if (err != 0 || | |||
1288 | getaddrinfo("::1", NULL((void*)0), &hints, &gai_result) != 0) | |||
1289 | { | |||
1290 | conflines = replace_token(conflines, | |||
1291 | "host all all ::1", | |||
1292 | "#host all all ::1"); | |||
1293 | conflines = replace_token(conflines, | |||
1294 | "host replication all ::1", | |||
1295 | "#host replication all ::1"); | |||
1296 | } | |||
1297 | } | |||
1298 | #else /* !HAVE_IPV6 */ | |||
1299 | /* If we didn't compile IPV6 support at all, always comment it out */ | |||
1300 | conflines = replace_token(conflines, | |||
1301 | "host all all ::1", | |||
1302 | "#host all all ::1"); | |||
1303 | conflines = replace_token(conflines, | |||
1304 | "host replication all ::1", | |||
1305 | "#host replication all ::1"); | |||
1306 | #endif /* HAVE_IPV6 */ | |||
1307 | ||||
1308 | /* Replace default authentication methods */ | |||
1309 | conflines = replace_token(conflines, | |||
1310 | "@authmethodhost@", | |||
1311 | authmethodhost); | |||
1312 | conflines = replace_token(conflines, | |||
1313 | "@authmethodlocal@", | |||
1314 | authmethodlocal); | |||
1315 | ||||
1316 | conflines = replace_token(conflines, | |||
1317 | "@authcomment@", | |||
1318 | (strcmp(authmethodlocal, "trust") == 0 || strcmp(authmethodhost, "trust") == 0) ? AUTHTRUST_WARNING"# CAUTION: Configuring the system for local \"trust\" authentication\n" "# allows any local user to connect as any PostgreSQL user, including\n" "# the database superuser. If you do not trust all your local users,\n" "# use another authentication method.\n" : ""); | |||
1319 | ||||
1320 | snprintfpg_snprintf(path, sizeof(path), "%s/pg_hba.conf", pg_data); | |||
1321 | ||||
1322 | writefile(path, conflines); | |||
1323 | if (chmod(path, pg_file_create_mode) != 0) | |||
1324 | { | |||
1325 | pg_log_error("could not change permissions of \"%s\": %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not change permissions of \"%s\": %m" , path); } while(0); | |||
1326 | exit(1); | |||
1327 | } | |||
1328 | ||||
1329 | free(conflines); | |||
1330 | ||||
1331 | /* pg_ident.conf */ | |||
1332 | ||||
1333 | conflines = readfile(ident_file); | |||
1334 | ||||
1335 | snprintfpg_snprintf(path, sizeof(path), "%s/pg_ident.conf", pg_data); | |||
1336 | ||||
1337 | writefile(path, conflines); | |||
1338 | if (chmod(path, pg_file_create_mode) != 0) | |||
1339 | { | |||
1340 | pg_log_error("could not change permissions of \"%s\": %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not change permissions of \"%s\": %m" , path); } while(0); | |||
1341 | exit(1); | |||
1342 | } | |||
1343 | ||||
1344 | free(conflines); | |||
1345 | ||||
1346 | check_ok(); | |||
1347 | } | |||
1348 | ||||
1349 | ||||
1350 | /* | |||
1351 | * run the BKI script in bootstrap mode to create template1 | |||
1352 | */ | |||
1353 | static void | |||
1354 | bootstrap_template1(void) | |||
1355 | { | |||
1356 | PG_CMD_DECLchar cmd[1024]; FILE *cmdfd; | |||
1357 | char **line; | |||
1358 | char **bki_lines; | |||
1359 | char headerline[MAXPGPATH1024]; | |||
1360 | char buf[64]; | |||
1361 | ||||
1362 | printf(_("running bootstrap script ... "))pg_printf(("running bootstrap script ... ")); | |||
1363 | fflush(stdoutstdout); | |||
1364 | ||||
1365 | bki_lines = readfile(bki_file); | |||
1366 | ||||
1367 | /* Check that bki file appears to be of the right version */ | |||
1368 | ||||
1369 | snprintfpg_snprintf(headerline, sizeof(headerline), "# PostgreSQL %s\n", | |||
1370 | PG_MAJORVERSION"15"); | |||
1371 | ||||
1372 | if (strcmp(headerline, *bki_lines) != 0) | |||
1373 | { | |||
1374 | pg_log_error("input file \"%s\" does not belong to PostgreSQL %s",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "input file \"%s\" does not belong to PostgreSQL %s" , bki_file, "15devel"); } while(0) | |||
1375 | bki_file, PG_VERSION)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "input file \"%s\" does not belong to PostgreSQL %s" , bki_file, "15devel"); } while(0); | |||
1376 | fprintfpg_fprintf(stderrstderr, | |||
1377 | _("Check your installation or specify the correct path "("Check your installation or specify the correct path " "using the option -L.\n" ) | |||
1378 | "using the option -L.\n")("Check your installation or specify the correct path " "using the option -L.\n" )); | |||
1379 | exit(1); | |||
1380 | } | |||
1381 | ||||
1382 | /* Substitute for various symbols used in the BKI file */ | |||
1383 | ||||
1384 | sprintfpg_sprintf(buf, "%d", NAMEDATALEN64); | |||
1385 | bki_lines = replace_token(bki_lines, "NAMEDATALEN", buf); | |||
1386 | ||||
1387 | sprintfpg_sprintf(buf, "%d", (int) sizeof(Pointer)); | |||
1388 | bki_lines = replace_token(bki_lines, "SIZEOF_POINTER", buf); | |||
1389 | ||||
1390 | bki_lines = replace_token(bki_lines, "ALIGNOF_POINTER", | |||
1391 | (sizeof(Pointer) == 4) ? "i" : "d"); | |||
1392 | ||||
1393 | bki_lines = replace_token(bki_lines, "FLOAT8PASSBYVAL", | |||
1394 | FLOAT8PASSBYVAL1 ? "true" : "false"); | |||
1395 | ||||
1396 | bki_lines = replace_token(bki_lines, "POSTGRES", | |||
1397 | escape_quotes_bki(username)); | |||
1398 | ||||
1399 | bki_lines = replace_token(bki_lines, "ENCODING", | |||
1400 | encodingid_to_string(encodingid)); | |||
1401 | ||||
1402 | bki_lines = replace_token(bki_lines, "LC_COLLATE", | |||
1403 | escape_quotes_bki(lc_collate)); | |||
1404 | ||||
1405 | bki_lines = replace_token(bki_lines, "LC_CTYPE", | |||
1406 | escape_quotes_bki(lc_ctype)); | |||
1407 | ||||
1408 | /* Also ensure backend isn't confused by this environment var: */ | |||
1409 | unsetenv("PGCLIENTENCODING"); | |||
1410 | ||||
1411 | snprintfpg_snprintf(cmd, sizeof(cmd), | |||
1412 | "\"%s\" --boot -X %d %s %s %s %s", | |||
1413 | backend_exec, | |||
1414 | wal_segment_size_mb * (1024 * 1024), | |||
1415 | data_checksums ? "-k" : "", | |||
1416 | boot_options, extra_options, | |||
1417 | debug ? "-d 5" : ""); | |||
1418 | ||||
1419 | ||||
1420 | PG_CMD_OPENdo { cmdfd = popen_check(cmd, "w"); if (cmdfd == ((void*)0)) exit (1); } while (0); | |||
1421 | ||||
1422 | for (line = bki_lines; *line != NULL((void*)0); line++) | |||
1423 | { | |||
1424 | PG_CMD_PUTS(*line)do { if (fputs(*line, cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1425 | free(*line); | |||
1426 | } | |||
1427 | ||||
1428 | PG_CMD_CLOSEdo { if (pclose_check(cmdfd)) exit(1); } while (0); | |||
1429 | ||||
1430 | free(bki_lines); | |||
1431 | ||||
1432 | check_ok(); | |||
1433 | } | |||
1434 | ||||
1435 | /* | |||
1436 | * set up the shadow password table | |||
1437 | */ | |||
1438 | static void | |||
1439 | setup_auth(FILE *cmdfd) | |||
1440 | { | |||
1441 | const char *const *line; | |||
1442 | static const char *const pg_authid_setup[] = { | |||
1443 | /* | |||
1444 | * The authid table shouldn't be readable except through views, to | |||
1445 | * ensure passwords are not publicly visible. | |||
1446 | */ | |||
1447 | "REVOKE ALL ON pg_authid FROM public;\n\n", | |||
1448 | NULL((void*)0) | |||
1449 | }; | |||
1450 | ||||
1451 | for (line = pg_authid_setup; *line != NULL((void*)0); line++) | |||
1452 | PG_CMD_PUTS(*line)do { if (fputs(*line, cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1453 | ||||
1454 | if (superuser_password) | |||
1455 | PG_CMD_PRINTF("ALTER USER \"%s\" WITH PASSWORD E'%s';\n\n",do { if (pg_fprintf(cmdfd, "ALTER USER \"%s\" WITH PASSWORD E'%s';\n\n" , username, escape_quotes(superuser_password)) < 0 || fflush (cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1456 | username, escape_quotes(superuser_password))do { if (pg_fprintf(cmdfd, "ALTER USER \"%s\" WITH PASSWORD E'%s';\n\n" , username, escape_quotes(superuser_password)) < 0 || fflush (cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1457 | } | |||
1458 | ||||
1459 | /* | |||
1460 | * get the superuser password if required | |||
1461 | */ | |||
1462 | static void | |||
1463 | get_su_pwd(void) | |||
1464 | { | |||
1465 | char *pwd1; | |||
1466 | ||||
1467 | if (pwprompt) | |||
1468 | { | |||
1469 | /* | |||
1470 | * Read password from terminal | |||
1471 | */ | |||
1472 | char *pwd2; | |||
1473 | ||||
1474 | printf("\n")pg_printf("\n"); | |||
1475 | fflush(stdoutstdout); | |||
1476 | pwd1 = simple_prompt("Enter new superuser password: ", false0); | |||
1477 | pwd2 = simple_prompt("Enter it again: ", false0); | |||
1478 | if (strcmp(pwd1, pwd2) != 0) | |||
1479 | { | |||
1480 | fprintfpg_fprintf(stderrstderr, _("Passwords didn't match.\n")("Passwords didn't match.\n")); | |||
1481 | exit(1); | |||
1482 | } | |||
1483 | free(pwd2); | |||
1484 | } | |||
1485 | else | |||
1486 | { | |||
1487 | /* | |||
1488 | * Read password from file | |||
1489 | * | |||
1490 | * Ideally this should insist that the file not be world-readable. | |||
1491 | * However, this option is mainly intended for use on Windows where | |||
1492 | * file permissions may not exist at all, so we'll skip the paranoia | |||
1493 | * for now. | |||
1494 | */ | |||
1495 | FILE *pwf = fopen(pwfilename, "r"); | |||
1496 | ||||
1497 | if (!pwf) | |||
1498 | { | |||
1499 | pg_log_error("could not open file \"%s\" for reading: %m",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not open file \"%s\" for reading: %m" , pwfilename); } while(0) | |||
1500 | pwfilename)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not open file \"%s\" for reading: %m" , pwfilename); } while(0); | |||
1501 | exit(1); | |||
1502 | } | |||
1503 | pwd1 = pg_get_line(pwf, NULL((void*)0)); | |||
1504 | if (!pwd1) | |||
1505 | { | |||
1506 | if (ferror(pwf)) | |||
1507 | pg_log_error("could not read password from file \"%s\": %m",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not read password from file \"%s\": %m" , pwfilename); } while(0) | |||
1508 | pwfilename)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not read password from file \"%s\": %m" , pwfilename); } while(0); | |||
1509 | else | |||
1510 | pg_log_error("password file \"%s\" is empty",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "password file \"%s\" is empty" , pwfilename); } while(0) | |||
1511 | pwfilename)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "password file \"%s\" is empty" , pwfilename); } while(0); | |||
1512 | exit(1); | |||
1513 | } | |||
1514 | fclose(pwf); | |||
1515 | ||||
1516 | (void) pg_strip_crlf(pwd1); | |||
1517 | } | |||
1518 | ||||
1519 | superuser_password = pwd1; | |||
1520 | } | |||
1521 | ||||
1522 | /* | |||
1523 | * set up pg_depend | |||
1524 | */ | |||
1525 | static void | |||
1526 | setup_depend(FILE *cmdfd) | |||
1527 | { | |||
1528 | const char *const *line; | |||
1529 | static const char *const pg_depend_setup[] = { | |||
1530 | /* | |||
1531 | * Advance the OID counter so that subsequently-created objects aren't | |||
1532 | * pinned. | |||
1533 | */ | |||
1534 | "SELECT pg_stop_making_pinned_objects();\n\n", | |||
1535 | NULL((void*)0) | |||
1536 | }; | |||
1537 | ||||
1538 | for (line = pg_depend_setup; *line != NULL((void*)0); line++) | |||
1539 | PG_CMD_PUTS(*line)do { if (fputs(*line, cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1540 | } | |||
1541 | ||||
1542 | /* | |||
1543 | * Run external file | |||
1544 | */ | |||
1545 | static void | |||
1546 | setup_run_file(FILE *cmdfd, const char *filename) | |||
1547 | { | |||
1548 | char **lines; | |||
1549 | ||||
1550 | lines = readfile(filename); | |||
1551 | ||||
1552 | for (char **line = lines; *line != NULL((void*)0); line++) | |||
1553 | { | |||
1554 | PG_CMD_PUTS(*line)do { if (fputs(*line, cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1555 | free(*line); | |||
1556 | } | |||
1557 | ||||
1558 | PG_CMD_PUTS("\n\n")do { if (fputs("\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1559 | ||||
1560 | free(lines); | |||
1561 | } | |||
1562 | ||||
1563 | /* | |||
1564 | * fill in extra description data | |||
1565 | */ | |||
1566 | static void | |||
1567 | setup_description(FILE *cmdfd) | |||
1568 | { | |||
1569 | /* Create default descriptions for operator implementation functions */ | |||
1570 | PG_CMD_PUTS("WITH funcdescs AS ( "do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1571 | "SELECT p.oid as p_oid, o.oid as o_oid, oprname "do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1572 | "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) "do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1573 | "INSERT INTO pg_description "do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1574 | " SELECT p_oid, 'pg_proc'::regclass, 0, "do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1575 | " 'implementation of ' || oprname || ' operator' "do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1576 | " FROM funcdescs "do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1577 | " WHERE NOT EXISTS (SELECT 1 FROM pg_description "do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1578 | " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) "do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1579 | " AND NOT EXISTS (SELECT 1 FROM pg_description "do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1580 | " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass"do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1581 | " AND description LIKE 'deprecated%');\n\n")do { if (fputs("WITH funcdescs AS ( " "SELECT p.oid as p_oid, o.oid as o_oid, oprname " "FROM pg_proc p JOIN pg_operator o ON oprcode = p.oid ) " "INSERT INTO pg_description " " SELECT p_oid, 'pg_proc'::regclass, 0, " " 'implementation of ' || oprname || ' operator' " " FROM funcdescs " " WHERE NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = p_oid AND classoid = 'pg_proc'::regclass) " " AND NOT EXISTS (SELECT 1 FROM pg_description " " WHERE objoid = o_oid AND classoid = 'pg_operator'::regclass" " AND description LIKE 'deprecated%');\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1582 | } | |||
1583 | ||||
1584 | /* | |||
1585 | * populate pg_collation | |||
1586 | */ | |||
1587 | static void | |||
1588 | setup_collation(FILE *cmdfd) | |||
1589 | { | |||
1590 | /* | |||
1591 | * Add an SQL-standard name. We don't want to pin this, so it doesn't go | |||
1592 | * in pg_collation.h. But add it before reading system collations, so | |||
1593 | * that it wins if libc defines a locale named ucs_basic. | |||
1594 | */ | |||
1595 | PG_CMD_PRINTF("INSERT INTO pg_collation (oid, collname, collnamespace, collowner, collprovider, collisdeterministic, collencoding, collcollate, collctype)"do { if (pg_fprintf(cmdfd, "INSERT INTO pg_collation (oid, collname, collnamespace, collowner, collprovider, collisdeterministic, collencoding, collcollate, collctype)" "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" , 10, 'c', PG_UTF8) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1596 | "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",do { if (pg_fprintf(cmdfd, "INSERT INTO pg_collation (oid, collname, collnamespace, collowner, collprovider, collisdeterministic, collencoding, collcollate, collctype)" "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" , 10, 'c', PG_UTF8) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1597 | BOOTSTRAP_SUPERUSERID, COLLPROVIDER_LIBC, PG_UTF8)do { if (pg_fprintf(cmdfd, "INSERT INTO pg_collation (oid, collname, collnamespace, collowner, collprovider, collisdeterministic, collencoding, collcollate, collctype)" "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" , 10, 'c', PG_UTF8) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1598 | ||||
1599 | /* Now import all collations we can find in the operating system */ | |||
1600 | PG_CMD_PUTS("SELECT pg_import_system_collations('pg_catalog');\n\n")do { if (fputs("SELECT pg_import_system_collations('pg_catalog');\n\n" , cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1601 | } | |||
1602 | ||||
1603 | /* | |||
1604 | * Set up privileges | |||
1605 | * | |||
1606 | * We mark most system catalogs as world-readable. We don't currently have | |||
1607 | * to touch functions, languages, or databases, because their default | |||
1608 | * permissions are OK. | |||
1609 | * | |||
1610 | * Some objects may require different permissions by default, so we | |||
1611 | * make sure we don't overwrite privilege sets that have already been | |||
1612 | * set (NOT NULL). | |||
1613 | * | |||
1614 | * Also populate pg_init_privs to save what the privileges are at init | |||
1615 | * time. This is used by pg_dump to allow users to change privileges | |||
1616 | * on catalog objects and to have those privilege changes preserved | |||
1617 | * across dump/reload and pg_upgrade. | |||
1618 | * | |||
1619 | * Note that pg_init_privs is only for per-database objects and therefore | |||
1620 | * we don't include databases or tablespaces. | |||
1621 | */ | |||
1622 | static void | |||
1623 | setup_privileges(FILE *cmdfd) | |||
1624 | { | |||
1625 | char **line; | |||
1626 | char **priv_lines; | |||
1627 | static char *privileges_setup[] = { | |||
1628 | "UPDATE pg_class " | |||
1629 | " SET relacl = (SELECT array_agg(a.acl) FROM " | |||
1630 | " (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl " | |||
1631 | " UNION SELECT unnest(pg_catalog.acldefault(" | |||
1632 | " CASE WHEN relkind = " CppAsString2(RELKIND_SEQUENCE)"'S'" " THEN 's' " | |||
1633 | " ELSE 'r' END::\"char\"," CppAsString2(BOOTSTRAP_SUPERUSERID)"10" "::oid))" | |||
1634 | " ) as a) " | |||
1635 | " WHERE relkind IN (" CppAsString2(RELKIND_RELATION)"'r'" ", " | |||
1636 | CppAsString2(RELKIND_VIEW)"'v'" ", " CppAsString2(RELKIND_MATVIEW)"'m'" ", " | |||
1637 | CppAsString2(RELKIND_SEQUENCE)"'S'" ")" | |||
1638 | " AND relacl IS NULL;\n\n", | |||
1639 | "GRANT USAGE ON SCHEMA pg_catalog, public TO PUBLIC;\n\n", | |||
1640 | "REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n", | |||
1641 | "INSERT INTO pg_init_privs " | |||
1642 | " (objoid, classoid, objsubid, initprivs, privtype)" | |||
1643 | " SELECT" | |||
1644 | " oid," | |||
1645 | " (SELECT oid FROM pg_class WHERE relname = 'pg_class')," | |||
1646 | " 0," | |||
1647 | " relacl," | |||
1648 | " 'i'" | |||
1649 | " FROM" | |||
1650 | " pg_class" | |||
1651 | " WHERE" | |||
1652 | " relacl IS NOT NULL" | |||
1653 | " AND relkind IN (" CppAsString2(RELKIND_RELATION)"'r'" ", " | |||
1654 | CppAsString2(RELKIND_VIEW)"'v'" ", " CppAsString2(RELKIND_MATVIEW)"'m'" ", " | |||
1655 | CppAsString2(RELKIND_SEQUENCE)"'S'" ");\n\n", | |||
1656 | "INSERT INTO pg_init_privs " | |||
1657 | " (objoid, classoid, objsubid, initprivs, privtype)" | |||
1658 | " SELECT" | |||
1659 | " pg_class.oid," | |||
1660 | " (SELECT oid FROM pg_class WHERE relname = 'pg_class')," | |||
1661 | " pg_attribute.attnum," | |||
1662 | " pg_attribute.attacl," | |||
1663 | " 'i'" | |||
1664 | " FROM" | |||
1665 | " pg_class" | |||
1666 | " JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)" | |||
1667 | " WHERE" | |||
1668 | " pg_attribute.attacl IS NOT NULL" | |||
1669 | " AND pg_class.relkind IN (" CppAsString2(RELKIND_RELATION)"'r'" ", " | |||
1670 | CppAsString2(RELKIND_VIEW)"'v'" ", " CppAsString2(RELKIND_MATVIEW)"'m'" ", " | |||
1671 | CppAsString2(RELKIND_SEQUENCE)"'S'" ");\n\n", | |||
1672 | "INSERT INTO pg_init_privs " | |||
1673 | " (objoid, classoid, objsubid, initprivs, privtype)" | |||
1674 | " SELECT" | |||
1675 | " oid," | |||
1676 | " (SELECT oid FROM pg_class WHERE relname = 'pg_proc')," | |||
1677 | " 0," | |||
1678 | " proacl," | |||
1679 | " 'i'" | |||
1680 | " FROM" | |||
1681 | " pg_proc" | |||
1682 | " WHERE" | |||
1683 | " proacl IS NOT NULL;\n\n", | |||
1684 | "INSERT INTO pg_init_privs " | |||
1685 | " (objoid, classoid, objsubid, initprivs, privtype)" | |||
1686 | " SELECT" | |||
1687 | " oid," | |||
1688 | " (SELECT oid FROM pg_class WHERE relname = 'pg_type')," | |||
1689 | " 0," | |||
1690 | " typacl," | |||
1691 | " 'i'" | |||
1692 | " FROM" | |||
1693 | " pg_type" | |||
1694 | " WHERE" | |||
1695 | " typacl IS NOT NULL;\n\n", | |||
1696 | "INSERT INTO pg_init_privs " | |||
1697 | " (objoid, classoid, objsubid, initprivs, privtype)" | |||
1698 | " SELECT" | |||
1699 | " oid," | |||
1700 | " (SELECT oid FROM pg_class WHERE relname = 'pg_language')," | |||
1701 | " 0," | |||
1702 | " lanacl," | |||
1703 | " 'i'" | |||
1704 | " FROM" | |||
1705 | " pg_language" | |||
1706 | " WHERE" | |||
1707 | " lanacl IS NOT NULL;\n\n", | |||
1708 | "INSERT INTO pg_init_privs " | |||
1709 | " (objoid, classoid, objsubid, initprivs, privtype)" | |||
1710 | " SELECT" | |||
1711 | " oid," | |||
1712 | " (SELECT oid FROM pg_class WHERE " | |||
1713 | " relname = 'pg_largeobject_metadata')," | |||
1714 | " 0," | |||
1715 | " lomacl," | |||
1716 | " 'i'" | |||
1717 | " FROM" | |||
1718 | " pg_largeobject_metadata" | |||
1719 | " WHERE" | |||
1720 | " lomacl IS NOT NULL;\n\n", | |||
1721 | "INSERT INTO pg_init_privs " | |||
1722 | " (objoid, classoid, objsubid, initprivs, privtype)" | |||
1723 | " SELECT" | |||
1724 | " oid," | |||
1725 | " (SELECT oid FROM pg_class WHERE relname = 'pg_namespace')," | |||
1726 | " 0," | |||
1727 | " nspacl," | |||
1728 | " 'i'" | |||
1729 | " FROM" | |||
1730 | " pg_namespace" | |||
1731 | " WHERE" | |||
1732 | " nspacl IS NOT NULL;\n\n", | |||
1733 | "INSERT INTO pg_init_privs " | |||
1734 | " (objoid, classoid, objsubid, initprivs, privtype)" | |||
1735 | " SELECT" | |||
1736 | " oid," | |||
1737 | " (SELECT oid FROM pg_class WHERE " | |||
1738 | " relname = 'pg_foreign_data_wrapper')," | |||
1739 | " 0," | |||
1740 | " fdwacl," | |||
1741 | " 'i'" | |||
1742 | " FROM" | |||
1743 | " pg_foreign_data_wrapper" | |||
1744 | " WHERE" | |||
1745 | " fdwacl IS NOT NULL;\n\n", | |||
1746 | "INSERT INTO pg_init_privs " | |||
1747 | " (objoid, classoid, objsubid, initprivs, privtype)" | |||
1748 | " SELECT" | |||
1749 | " oid," | |||
1750 | " (SELECT oid FROM pg_class " | |||
1751 | " WHERE relname = 'pg_foreign_server')," | |||
1752 | " 0," | |||
1753 | " srvacl," | |||
1754 | " 'i'" | |||
1755 | " FROM" | |||
1756 | " pg_foreign_server" | |||
1757 | " WHERE" | |||
1758 | " srvacl IS NOT NULL;\n\n", | |||
1759 | NULL((void*)0) | |||
1760 | }; | |||
1761 | ||||
1762 | priv_lines = replace_token(privileges_setup, "$POSTGRES_SUPERUSERNAME", | |||
1763 | escape_quotes(username)); | |||
1764 | for (line = priv_lines; *line != NULL((void*)0); line++) | |||
1765 | PG_CMD_PUTS(*line)do { if (fputs(*line, cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1766 | } | |||
1767 | ||||
1768 | /* | |||
1769 | * extract the strange version of version required for information schema | |||
1770 | * (09.08.0007abc) | |||
1771 | */ | |||
1772 | static void | |||
1773 | set_info_version(void) | |||
1774 | { | |||
1775 | char *letterversion; | |||
1776 | long major = 0, | |||
1777 | minor = 0, | |||
1778 | micro = 0; | |||
1779 | char *endptr; | |||
1780 | char *vstr = pg_strdup(PG_VERSION"15devel"); | |||
1781 | char *ptr; | |||
1782 | ||||
1783 | ptr = vstr + (strlen(vstr) - 1); | |||
1784 | while (ptr != vstr && (*ptr < '0' || *ptr > '9')) | |||
1785 | ptr--; | |||
1786 | letterversion = ptr + 1; | |||
1787 | major = strtol(vstr, &endptr, 10); | |||
1788 | if (*endptr) | |||
1789 | minor = strtol(endptr + 1, &endptr, 10); | |||
1790 | if (*endptr) | |||
1791 | micro = strtol(endptr + 1, &endptr, 10); | |||
1792 | snprintfpg_snprintf(infoversion, sizeof(infoversion), "%02ld.%02ld.%04ld%s", | |||
1793 | major, minor, micro, letterversion); | |||
1794 | } | |||
1795 | ||||
1796 | /* | |||
1797 | * load info schema and populate from features file | |||
1798 | */ | |||
1799 | static void | |||
1800 | setup_schema(FILE *cmdfd) | |||
1801 | { | |||
1802 | setup_run_file(cmdfd, info_schema_file); | |||
1803 | ||||
1804 | PG_CMD_PRINTF("UPDATE information_schema.sql_implementation_info "do { if (pg_fprintf(cmdfd, "UPDATE information_schema.sql_implementation_info " " SET character_value = '%s' " " WHERE implementation_info_name = 'DBMS VERSION';\n\n" , infoversion) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1805 | " SET character_value = '%s' "do { if (pg_fprintf(cmdfd, "UPDATE information_schema.sql_implementation_info " " SET character_value = '%s' " " WHERE implementation_info_name = 'DBMS VERSION';\n\n" , infoversion) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1806 | " WHERE implementation_info_name = 'DBMS VERSION';\n\n",do { if (pg_fprintf(cmdfd, "UPDATE information_schema.sql_implementation_info " " SET character_value = '%s' " " WHERE implementation_info_name = 'DBMS VERSION';\n\n" , infoversion) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1807 | infoversion)do { if (pg_fprintf(cmdfd, "UPDATE information_schema.sql_implementation_info " " SET character_value = '%s' " " WHERE implementation_info_name = 'DBMS VERSION';\n\n" , infoversion) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1808 | ||||
1809 | PG_CMD_PRINTF("COPY information_schema.sql_features "do { if (pg_fprintf(cmdfd, "COPY information_schema.sql_features " " (feature_id, feature_name, sub_feature_id, " " sub_feature_name, is_supported, comments) " " FROM E'%s';\n\n", escape_quotes(features_file)) < 0 || fflush (cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1810 | " (feature_id, feature_name, sub_feature_id, "do { if (pg_fprintf(cmdfd, "COPY information_schema.sql_features " " (feature_id, feature_name, sub_feature_id, " " sub_feature_name, is_supported, comments) " " FROM E'%s';\n\n", escape_quotes(features_file)) < 0 || fflush (cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1811 | " sub_feature_name, is_supported, comments) "do { if (pg_fprintf(cmdfd, "COPY information_schema.sql_features " " (feature_id, feature_name, sub_feature_id, " " sub_feature_name, is_supported, comments) " " FROM E'%s';\n\n", escape_quotes(features_file)) < 0 || fflush (cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1812 | " FROM E'%s';\n\n",do { if (pg_fprintf(cmdfd, "COPY information_schema.sql_features " " (feature_id, feature_name, sub_feature_id, " " sub_feature_name, is_supported, comments) " " FROM E'%s';\n\n", escape_quotes(features_file)) < 0 || fflush (cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0) | |||
1813 | escape_quotes(features_file))do { if (pg_fprintf(cmdfd, "COPY information_schema.sql_features " " (feature_id, feature_name, sub_feature_id, " " sub_feature_name, is_supported, comments) " " FROM E'%s';\n\n", escape_quotes(features_file)) < 0 || fflush (cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1814 | } | |||
1815 | ||||
1816 | /* | |||
1817 | * load PL/pgSQL server-side language | |||
1818 | */ | |||
1819 | static void | |||
1820 | load_plpgsql(FILE *cmdfd) | |||
1821 | { | |||
1822 | PG_CMD_PUTS("CREATE EXTENSION plpgsql;\n\n")do { if (fputs("CREATE EXTENSION plpgsql;\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = ( *__errno_location ()); } while (0); | |||
1823 | } | |||
1824 | ||||
1825 | /* | |||
1826 | * clean everything up in template1 | |||
1827 | */ | |||
1828 | static void | |||
1829 | vacuum_db(FILE *cmdfd) | |||
1830 | { | |||
1831 | /* Run analyze before VACUUM so the statistics are frozen. */ | |||
1832 | PG_CMD_PUTS("ANALYZE;\n\nVACUUM FREEZE;\n\n")do { if (fputs("ANALYZE;\n\nVACUUM FREEZE;\n\n", cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = ( *__errno_location ()); } while (0); | |||
1833 | } | |||
1834 | ||||
1835 | /* | |||
1836 | * copy template1 to template0 | |||
1837 | */ | |||
1838 | static void | |||
1839 | make_template0(FILE *cmdfd) | |||
1840 | { | |||
1841 | const char *const *line; | |||
1842 | ||||
1843 | /* | |||
1844 | * pg_upgrade tries to preserve database OIDs across upgrades. It's smart | |||
1845 | * enough to drop and recreate a conflicting database with the same name, | |||
1846 | * but if the same OID were used for one system-created database in the | |||
1847 | * old cluster and a different system-created database in the new cluster, | |||
1848 | * it would fail. To avoid that, assign a fixed OID to template0 rather | |||
1849 | * than letting the server choose one. | |||
1850 | * | |||
1851 | * (Note that, while the user could have dropped and recreated these | |||
1852 | * objects in the old cluster, the problem scenario only exists if the OID | |||
1853 | * that is in use in the old cluster is also used in the new cluster - and | |||
1854 | * the new cluster should be the result of a fresh initdb.) | |||
1855 | */ | |||
1856 | static const char *const template0_setup[] = { | |||
1857 | "CREATE DATABASE template0 IS_TEMPLATE = true ALLOW_CONNECTIONS = false OID = " | |||
1858 | CppAsString2(Template0ObjectId)"4" ";\n\n", | |||
1859 | ||||
1860 | /* | |||
1861 | * Explicitly revoke public create-schema and create-temp-table | |||
1862 | * privileges in template1 and template0; else the latter would be on | |||
1863 | * by default | |||
1864 | */ | |||
1865 | "REVOKE CREATE,TEMPORARY ON DATABASE template1 FROM public;\n\n", | |||
1866 | "REVOKE CREATE,TEMPORARY ON DATABASE template0 FROM public;\n\n", | |||
1867 | ||||
1868 | "COMMENT ON DATABASE template0 IS 'unmodifiable empty database';\n\n", | |||
1869 | ||||
1870 | /* | |||
1871 | * Finally vacuum to clean up dead rows in pg_database | |||
1872 | */ | |||
1873 | "VACUUM pg_database;\n\n", | |||
1874 | NULL((void*)0) | |||
1875 | }; | |||
1876 | ||||
1877 | for (line = template0_setup; *line; line++) | |||
1878 | PG_CMD_PUTS(*line)do { if (fputs(*line, cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1879 | } | |||
1880 | ||||
1881 | /* | |||
1882 | * copy template1 to postgres | |||
1883 | */ | |||
1884 | static void | |||
1885 | make_postgres(FILE *cmdfd) | |||
1886 | { | |||
1887 | const char *const *line; | |||
1888 | ||||
1889 | /* Assign a fixed OID to postgres, for the same reasons as template0 */ | |||
1890 | static const char *const postgres_setup[] = { | |||
1891 | "CREATE DATABASE postgres OID = " CppAsString2(PostgresObjectId)"5" ";\n\n", | |||
1892 | "COMMENT ON DATABASE postgres IS 'default administrative connection database';\n\n", | |||
1893 | NULL((void*)0) | |||
1894 | }; | |||
1895 | ||||
1896 | for (line = postgres_setup; *line; line++) | |||
1897 | PG_CMD_PUTS(*line)do { if (fputs(*line, cmdfd) < 0 || fflush(cmdfd) < 0) output_failed = 1, output_errno = (*__errno_location ()); } while (0); | |||
1898 | } | |||
1899 | ||||
1900 | /* | |||
1901 | * signal handler in case we are interrupted. | |||
1902 | * | |||
1903 | * The Windows runtime docs at | |||
1904 | * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/signal | |||
1905 | * specifically forbid a number of things being done from a signal handler, | |||
1906 | * including IO, memory allocation and system calls, and only allow jmpbuf | |||
1907 | * if you are handling SIGFPE. | |||
1908 | * | |||
1909 | * I avoided doing the forbidden things by setting a flag instead of calling | |||
1910 | * exit() directly. | |||
1911 | * | |||
1912 | * Also note the behaviour of Windows with SIGINT, which says this: | |||
1913 | * SIGINT is not supported for any Win32 application. When a CTRL+C interrupt | |||
1914 | * occurs, Win32 operating systems generate a new thread to specifically | |||
1915 | * handle that interrupt. This can cause a single-thread application, such as | |||
1916 | * one in UNIX, to become multithreaded and cause unexpected behavior. | |||
1917 | * | |||
1918 | * I have no idea how to handle this. (Strange they call UNIX an application!) | |||
1919 | * So this will need some testing on Windows. | |||
1920 | */ | |||
1921 | static void | |||
1922 | trapsig(int signum) | |||
1923 | { | |||
1924 | /* handle systems that reset the handler, like Windows (grr) */ | |||
1925 | pqsignal(signum, trapsig); | |||
1926 | caught_signal = true1; | |||
1927 | } | |||
1928 | ||||
1929 | /* | |||
1930 | * call exit() if we got a signal, or else output "ok". | |||
1931 | */ | |||
1932 | static void | |||
1933 | check_ok(void) | |||
1934 | { | |||
1935 | if (caught_signal) | |||
1936 | { | |||
1937 | printf(_("caught signal\n"))pg_printf(("caught signal\n")); | |||
1938 | fflush(stdoutstdout); | |||
1939 | exit(1); | |||
1940 | } | |||
1941 | else if (output_failed) | |||
1942 | { | |||
1943 | printf(_("could not write to child process: %s\n"),pg_printf(("could not write to child process: %s\n"), pg_strerror (output_errno)) | |||
1944 | strerror(output_errno))pg_printf(("could not write to child process: %s\n"), pg_strerror (output_errno)); | |||
1945 | fflush(stdoutstdout); | |||
1946 | exit(1); | |||
1947 | } | |||
1948 | else | |||
1949 | { | |||
1950 | /* all seems well */ | |||
1951 | printf(_("ok\n"))pg_printf(("ok\n")); | |||
1952 | fflush(stdoutstdout); | |||
1953 | } | |||
1954 | } | |||
1955 | ||||
1956 | /* Hack to suppress a warning about %x from some versions of gcc */ | |||
1957 | static inline size_t | |||
1958 | my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm) | |||
1959 | { | |||
1960 | return strftime(s, max, fmt, tm); | |||
1961 | } | |||
1962 | ||||
1963 | /* | |||
1964 | * Determine likely date order from locale | |||
1965 | */ | |||
1966 | static int | |||
1967 | locale_date_order(const char *locale) | |||
1968 | { | |||
1969 | struct tm testtime; | |||
1970 | char buf[128]; | |||
1971 | char *posD; | |||
1972 | char *posM; | |||
1973 | char *posY; | |||
1974 | char *save; | |||
1975 | size_t res; | |||
1976 | int result; | |||
1977 | ||||
1978 | result = DATEORDER_MDY2; /* default */ | |||
1979 | ||||
1980 | save = setlocale(LC_TIME2, NULL((void*)0)); | |||
1981 | if (!save) | |||
1982 | return result; | |||
1983 | save = pg_strdup(save); | |||
1984 | ||||
1985 | setlocale(LC_TIME2, locale); | |||
1986 | ||||
1987 | memset(&testtime, 0, sizeof(testtime)); | |||
1988 | testtime.tm_mday = 22; | |||
1989 | testtime.tm_mon = 10; /* November, should come out as "11" */ | |||
1990 | testtime.tm_year = 133; /* 2033 */ | |||
1991 | ||||
1992 | res = my_strftime(buf, sizeof(buf), "%x", &testtime); | |||
1993 | ||||
1994 | setlocale(LC_TIME2, save); | |||
1995 | free(save); | |||
1996 | ||||
1997 | if (res == 0) | |||
1998 | return result; | |||
1999 | ||||
2000 | posM = strstr(buf, "11"); | |||
2001 | posD = strstr(buf, "22"); | |||
2002 | posY = strstr(buf, "33"); | |||
2003 | ||||
2004 | if (!posM || !posD || !posY) | |||
2005 | return result; | |||
2006 | ||||
2007 | if (posY < posM && posM < posD) | |||
2008 | result = DATEORDER_YMD0; | |||
2009 | else if (posD < posM) | |||
2010 | result = DATEORDER_DMY1; | |||
2011 | else | |||
2012 | result = DATEORDER_MDY2; | |||
2013 | ||||
2014 | return result; | |||
2015 | } | |||
2016 | ||||
2017 | /* | |||
2018 | * Verify that locale name is valid for the locale category. | |||
2019 | * | |||
2020 | * If successful, and canonname isn't NULL, a malloc'd copy of the locale's | |||
2021 | * canonical name is stored there. This is especially useful for figuring out | |||
2022 | * what locale name "" means (ie, the environment value). (Actually, | |||
2023 | * it seems that on most implementations that's the only thing it's good for; | |||
2024 | * we could wish that setlocale gave back a canonically spelled version of | |||
2025 | * the locale name, but typically it doesn't.) | |||
2026 | * | |||
2027 | * this should match the backend's check_locale() function | |||
2028 | */ | |||
2029 | static void | |||
2030 | check_locale_name(int category, const char *locale, char **canonname) | |||
2031 | { | |||
2032 | char *save; | |||
2033 | char *res; | |||
2034 | ||||
2035 | if (canonname) | |||
2036 | *canonname = NULL((void*)0); /* in case of failure */ | |||
2037 | ||||
2038 | save = setlocale(category, NULL((void*)0)); | |||
2039 | if (!save) | |||
2040 | { | |||
2041 | pg_log_error("setlocale() failed")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "setlocale() failed") ; } while(0); | |||
2042 | exit(1); | |||
2043 | } | |||
2044 | ||||
2045 | /* save may be pointing at a modifiable scratch variable, so copy it. */ | |||
2046 | save = pg_strdup(save); | |||
2047 | ||||
2048 | /* for setlocale() call */ | |||
2049 | if (!locale) | |||
2050 | locale = ""; | |||
2051 | ||||
2052 | /* set the locale with setlocale, to see if it accepts it. */ | |||
2053 | res = setlocale(category, locale); | |||
2054 | ||||
2055 | /* save canonical name if requested. */ | |||
2056 | if (res && canonname) | |||
2057 | *canonname = pg_strdup(res); | |||
2058 | ||||
2059 | /* restore old value. */ | |||
2060 | if (!setlocale(category, save)) | |||
2061 | { | |||
2062 | pg_log_error("failed to restore old locale \"%s\"", save)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "failed to restore old locale \"%s\"" , save); } while(0); | |||
2063 | exit(1); | |||
2064 | } | |||
2065 | free(save); | |||
2066 | ||||
2067 | /* complain if locale wasn't valid */ | |||
2068 | if (res == NULL((void*)0)) | |||
2069 | { | |||
2070 | if (*locale) | |||
2071 | pg_log_error("invalid locale name \"%s\"", locale)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "invalid locale name \"%s\"" , locale); } while(0); | |||
2072 | else | |||
2073 | { | |||
2074 | /* | |||
2075 | * If no relevant switch was given on command line, locale is an | |||
2076 | * empty string, which is not too helpful to report. Presumably | |||
2077 | * setlocale() found something it did not like in the environment. | |||
2078 | * Ideally we'd report the bad environment variable, but since | |||
2079 | * setlocale's behavior is implementation-specific, it's hard to | |||
2080 | * be sure what it didn't like. Print a safe generic message. | |||
2081 | */ | |||
2082 | pg_log_error("invalid locale settings; check LANG and LC_* environment variables")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "invalid locale settings; check LANG and LC_* environment variables" ); } while(0); | |||
2083 | } | |||
2084 | exit(1); | |||
2085 | } | |||
2086 | } | |||
2087 | ||||
2088 | /* | |||
2089 | * check if the chosen encoding matches the encoding required by the locale | |||
2090 | * | |||
2091 | * this should match the similar check in the backend createdb() function | |||
2092 | */ | |||
2093 | static bool_Bool | |||
2094 | check_locale_encoding(const char *locale, int user_enc) | |||
2095 | { | |||
2096 | int locale_enc; | |||
2097 | ||||
2098 | locale_enc = pg_get_encoding_from_locale(locale, true1); | |||
2099 | ||||
2100 | /* See notes in createdb() to understand these tests */ | |||
2101 | if (!(locale_enc == user_enc || | |||
2102 | locale_enc == PG_SQL_ASCII || | |||
2103 | locale_enc == -1 || | |||
2104 | #ifdef WIN32 | |||
2105 | user_enc == PG_UTF8 || | |||
2106 | #endif | |||
2107 | user_enc == PG_SQL_ASCII)) | |||
2108 | { | |||
2109 | pg_log_error("encoding mismatch")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "encoding mismatch"); } while(0); | |||
2110 | fprintfpg_fprintf(stderrstderr, | |||
2111 | _("The encoding you selected (%s) and the encoding that the\n"("The encoding you selected (%s) and the encoding that the\n" "selected locale uses (%s) do not match. This would lead to\n" "misbehavior in various character string processing functions.\n" "Rerun %s and either do not specify an encoding explicitly,\n" "or choose a matching combination.\n") | |||
2112 | "selected locale uses (%s) do not match. This would lead to\n"("The encoding you selected (%s) and the encoding that the\n" "selected locale uses (%s) do not match. This would lead to\n" "misbehavior in various character string processing functions.\n" "Rerun %s and either do not specify an encoding explicitly,\n" "or choose a matching combination.\n") | |||
2113 | "misbehavior in various character string processing functions.\n"("The encoding you selected (%s) and the encoding that the\n" "selected locale uses (%s) do not match. This would lead to\n" "misbehavior in various character string processing functions.\n" "Rerun %s and either do not specify an encoding explicitly,\n" "or choose a matching combination.\n") | |||
2114 | "Rerun %s and either do not specify an encoding explicitly,\n"("The encoding you selected (%s) and the encoding that the\n" "selected locale uses (%s) do not match. This would lead to\n" "misbehavior in various character string processing functions.\n" "Rerun %s and either do not specify an encoding explicitly,\n" "or choose a matching combination.\n") | |||
2115 | "or choose a matching combination.\n")("The encoding you selected (%s) and the encoding that the\n" "selected locale uses (%s) do not match. This would lead to\n" "misbehavior in various character string processing functions.\n" "Rerun %s and either do not specify an encoding explicitly,\n" "or choose a matching combination.\n"), | |||
2116 | pg_encoding_to_char(user_enc), | |||
2117 | pg_encoding_to_char(locale_enc), | |||
2118 | progname); | |||
2119 | return false0; | |||
2120 | } | |||
2121 | return true1; | |||
2122 | } | |||
2123 | ||||
2124 | /* | |||
2125 | * set up the locale variables | |||
2126 | * | |||
2127 | * assumes we have called setlocale(LC_ALL, "") -- see set_pglocale_pgservice | |||
2128 | */ | |||
2129 | static void | |||
2130 | setlocales(void) | |||
2131 | { | |||
2132 | char *canonname; | |||
2133 | ||||
2134 | /* set empty lc_* values to locale config if set */ | |||
2135 | ||||
2136 | if (locale) | |||
2137 | { | |||
2138 | if (!lc_ctype) | |||
2139 | lc_ctype = locale; | |||
2140 | if (!lc_collate) | |||
2141 | lc_collate = locale; | |||
2142 | if (!lc_numeric) | |||
2143 | lc_numeric = locale; | |||
2144 | if (!lc_time) | |||
2145 | lc_time = locale; | |||
2146 | if (!lc_monetary) | |||
2147 | lc_monetary = locale; | |||
2148 | if (!lc_messages) | |||
2149 | lc_messages = locale; | |||
2150 | } | |||
2151 | ||||
2152 | /* | |||
2153 | * canonicalize locale names, and obtain any missing values from our | |||
2154 | * current environment | |||
2155 | */ | |||
2156 | ||||
2157 | check_locale_name(LC_CTYPE0, lc_ctype, &canonname); | |||
2158 | lc_ctype = canonname; | |||
2159 | check_locale_name(LC_COLLATE3, lc_collate, &canonname); | |||
2160 | lc_collate = canonname; | |||
2161 | check_locale_name(LC_NUMERIC1, lc_numeric, &canonname); | |||
2162 | lc_numeric = canonname; | |||
2163 | check_locale_name(LC_TIME2, lc_time, &canonname); | |||
2164 | lc_time = canonname; | |||
2165 | check_locale_name(LC_MONETARY4, lc_monetary, &canonname); | |||
2166 | lc_monetary = canonname; | |||
2167 | #if defined(LC_MESSAGES5) && !defined(WIN32) | |||
2168 | check_locale_name(LC_MESSAGES5, lc_messages, &canonname); | |||
2169 | lc_messages = canonname; | |||
2170 | #else | |||
2171 | /* when LC_MESSAGES is not available, use the LC_CTYPE setting */ | |||
2172 | check_locale_name(LC_CTYPE0, lc_messages, &canonname); | |||
2173 | lc_messages = canonname; | |||
2174 | #endif | |||
2175 | } | |||
2176 | ||||
2177 | /* | |||
2178 | * print help text | |||
2179 | */ | |||
2180 | static void | |||
2181 | usage(const char *progname) | |||
2182 | { | |||
2183 | printf(_("%s initializes a PostgreSQL database cluster.\n\n"), progname)pg_printf(("%s initializes a PostgreSQL database cluster.\n\n" ), progname); | |||
2184 | printf(_("Usage:\n"))pg_printf(("Usage:\n")); | |||
2185 | printf(_(" %s [OPTION]... [DATADIR]\n"), progname)pg_printf((" %s [OPTION]... [DATADIR]\n"), progname); | |||
2186 | printf(_("\nOptions:\n"))pg_printf(("\nOptions:\n")); | |||
2187 | printf(_(" -A, --auth=METHOD default authentication method for local connections\n"))pg_printf((" -A, --auth=METHOD default authentication method for local connections\n" )); | |||
2188 | printf(_(" --auth-host=METHOD default authentication method for local TCP/IP connections\n"))pg_printf((" --auth-host=METHOD default authentication method for local TCP/IP connections\n" )); | |||
2189 | printf(_(" --auth-local=METHOD default authentication method for local-socket connections\n"))pg_printf((" --auth-local=METHOD default authentication method for local-socket connections\n" )); | |||
2190 | printf(_(" [-D, --pgdata=]DATADIR location for this database cluster\n"))pg_printf((" [-D, --pgdata=]DATADIR location for this database cluster\n" )); | |||
2191 | printf(_(" -E, --encoding=ENCODING set default encoding for new databases\n"))pg_printf((" -E, --encoding=ENCODING set default encoding for new databases\n" )); | |||
2192 | printf(_(" -g, --allow-group-access allow group read/execute on data directory\n"))pg_printf((" -g, --allow-group-access allow group read/execute on data directory\n" )); | |||
2193 | printf(_(" -k, --data-checksums use data page checksums\n"))pg_printf((" -k, --data-checksums use data page checksums\n" )); | |||
2194 | printf(_(" --locale=LOCALE set default locale for new databases\n"))pg_printf((" --locale=LOCALE set default locale for new databases\n" )); | |||
2195 | printf(_(" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n"pg_printf((" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n" " --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n" " set default locale in the respective category for\n" " new databases (default taken from environment)\n" )) | |||
2196 | " --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n"pg_printf((" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n" " --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n" " set default locale in the respective category for\n" " new databases (default taken from environment)\n" )) | |||
2197 | " set default locale in the respective category for\n"pg_printf((" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n" " --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n" " set default locale in the respective category for\n" " new databases (default taken from environment)\n" )) | |||
2198 | " new databases (default taken from environment)\n"))pg_printf((" --lc-collate=, --lc-ctype=, --lc-messages=LOCALE\n" " --lc-monetary=, --lc-numeric=, --lc-time=LOCALE\n" " set default locale in the respective category for\n" " new databases (default taken from environment)\n" )); | |||
2199 | printf(_(" --no-locale equivalent to --locale=C\n"))pg_printf((" --no-locale equivalent to --locale=C\n" )); | |||
2200 | printf(_(" --pwfile=FILE read password for the new superuser from file\n"))pg_printf((" --pwfile=FILE read password for the new superuser from file\n" )); | |||
2201 | printf(_(" -T, --text-search-config=CFG\n"pg_printf((" -T, --text-search-config=CFG\n" " default text search configuration\n" )) | |||
2202 | " default text search configuration\n"))pg_printf((" -T, --text-search-config=CFG\n" " default text search configuration\n" )); | |||
2203 | printf(_(" -U, --username=NAME database superuser name\n"))pg_printf((" -U, --username=NAME database superuser name\n" )); | |||
2204 | printf(_(" -W, --pwprompt prompt for a password for the new superuser\n"))pg_printf((" -W, --pwprompt prompt for a password for the new superuser\n" )); | |||
2205 | printf(_(" -X, --waldir=WALDIR location for the write-ahead log directory\n"))pg_printf((" -X, --waldir=WALDIR location for the write-ahead log directory\n" )); | |||
2206 | printf(_(" --wal-segsize=SIZE size of WAL segments, in megabytes\n"))pg_printf((" --wal-segsize=SIZE size of WAL segments, in megabytes\n" )); | |||
2207 | printf(_("\nLess commonly used options:\n"))pg_printf(("\nLess commonly used options:\n")); | |||
2208 | printf(_(" -d, --debug generate lots of debugging output\n"))pg_printf((" -d, --debug generate lots of debugging output\n" )); | |||
2209 | printf(_(" --discard-caches set debug_discard_caches=1\n"))pg_printf((" --discard-caches set debug_discard_caches=1\n" )); | |||
2210 | printf(_(" -L DIRECTORY where to find the input files\n"))pg_printf((" -L DIRECTORY where to find the input files\n" )); | |||
2211 | printf(_(" -n, --no-clean do not clean up after errors\n"))pg_printf((" -n, --no-clean do not clean up after errors\n" )); | |||
2212 | printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n"))pg_printf((" -N, --no-sync do not wait for changes to be written safely to disk\n" )); | |||
2213 | printf(_(" --no-instructions do not print instructions for next steps\n"))pg_printf((" --no-instructions do not print instructions for next steps\n" )); | |||
2214 | printf(_(" -s, --show show internal settings\n"))pg_printf((" -s, --show show internal settings\n" )); | |||
2215 | printf(_(" -S, --sync-only only sync database files to disk, then exit\n"))pg_printf((" -S, --sync-only only sync database files to disk, then exit\n" )); | |||
2216 | printf(_("\nOther options:\n"))pg_printf(("\nOther options:\n")); | |||
2217 | printf(_(" -V, --version output version information, then exit\n"))pg_printf((" -V, --version output version information, then exit\n" )); | |||
2218 | printf(_(" -?, --help show this help, then exit\n"))pg_printf((" -?, --help show this help, then exit\n" )); | |||
2219 | printf(_("\nIf the data directory is not specified, the environment variable PGDATA\n"pg_printf(("\nIf the data directory is not specified, the environment variable PGDATA\n" "is used.\n")) | |||
2220 | "is used.\n"))pg_printf(("\nIf the data directory is not specified, the environment variable PGDATA\n" "is used.\n")); | |||
2221 | printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT)pg_printf(("\nReport bugs to <%s>.\n"), "pgsql-bugs@lists.postgresql.org" ); | |||
2222 | printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL)pg_printf(("%s home page: <%s>\n"), "PostgreSQL", "https://www.postgresql.org/" ); | |||
2223 | } | |||
2224 | ||||
2225 | static void | |||
2226 | check_authmethod_unspecified(const char **authmethod) | |||
2227 | { | |||
2228 | if (*authmethod == NULL((void*)0)) | |||
2229 | { | |||
2230 | authwarning = true1; | |||
2231 | *authmethod = "trust"; | |||
2232 | } | |||
2233 | } | |||
2234 | ||||
2235 | static void | |||
2236 | check_authmethod_valid(const char *authmethod, const char *const *valid_methods, const char *conntype) | |||
2237 | { | |||
2238 | const char *const *p; | |||
2239 | ||||
2240 | for (p = valid_methods; *p; p++) | |||
2241 | { | |||
2242 | if (strcmp(authmethod, *p) == 0) | |||
2243 | return; | |||
2244 | /* with space = param */ | |||
2245 | if (strchr(authmethod, ' ')) | |||
2246 | if (strncmp(authmethod, *p, (authmethod - strchr(authmethod, ' '))) == 0) | |||
2247 | return; | |||
2248 | } | |||
2249 | ||||
2250 | pg_log_error("invalid authentication method \"%s\" for \"%s\" connections",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "invalid authentication method \"%s\" for \"%s\" connections" , authmethod, conntype); } while(0) | |||
2251 | authmethod, conntype)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "invalid authentication method \"%s\" for \"%s\" connections" , authmethod, conntype); } while(0); | |||
2252 | exit(1); | |||
2253 | } | |||
2254 | ||||
2255 | static void | |||
2256 | check_need_password(const char *authmethodlocal, const char *authmethodhost) | |||
2257 | { | |||
2258 | if ((strcmp(authmethodlocal, "md5") == 0 || | |||
2259 | strcmp(authmethodlocal, "password") == 0 || | |||
2260 | strcmp(authmethodlocal, "scram-sha-256") == 0) && | |||
2261 | (strcmp(authmethodhost, "md5") == 0 || | |||
2262 | strcmp(authmethodhost, "password") == 0 || | |||
2263 | strcmp(authmethodhost, "scram-sha-256") == 0) && | |||
2264 | !(pwprompt || pwfilename)) | |||
2265 | { | |||
2266 | pg_log_error("must specify a password for the superuser to enable password authentication")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "must specify a password for the superuser to enable password authentication" ); } while(0); | |||
2267 | exit(1); | |||
2268 | } | |||
2269 | } | |||
2270 | ||||
2271 | ||||
2272 | void | |||
2273 | setup_pgdata(void) | |||
2274 | { | |||
2275 | char *pgdata_get_env; | |||
2276 | ||||
2277 | if (!pg_data) | |||
2278 | { | |||
2279 | pgdata_get_env = getenv("PGDATA"); | |||
2280 | if (pgdata_get_env && strlen(pgdata_get_env)) | |||
2281 | { | |||
2282 | /* PGDATA found */ | |||
2283 | pg_data = pg_strdup(pgdata_get_env); | |||
2284 | } | |||
2285 | else | |||
2286 | { | |||
2287 | pg_log_error("no data directory specified")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "no data directory specified" ); } while(0); | |||
2288 | fprintfpg_fprintf(stderrstderr, | |||
2289 | _("You must identify the directory where the data for this database system\n"("You must identify the directory where the data for this database system\n" "will reside. Do this with either the invocation option -D or the\n" "environment variable PGDATA.\n") | |||
2290 | "will reside. Do this with either the invocation option -D or the\n"("You must identify the directory where the data for this database system\n" "will reside. Do this with either the invocation option -D or the\n" "environment variable PGDATA.\n") | |||
2291 | "environment variable PGDATA.\n")("You must identify the directory where the data for this database system\n" "will reside. Do this with either the invocation option -D or the\n" "environment variable PGDATA.\n")); | |||
2292 | exit(1); | |||
2293 | } | |||
2294 | } | |||
2295 | ||||
2296 | pgdata_native = pg_strdup(pg_data); | |||
2297 | canonicalize_path(pg_data); | |||
2298 | ||||
2299 | /* | |||
2300 | * we have to set PGDATA for postgres rather than pass it on the command | |||
2301 | * line to avoid dumb quoting problems on Windows, and we would especially | |||
2302 | * need quotes otherwise on Windows because paths there are most likely to | |||
2303 | * have embedded spaces. | |||
2304 | */ | |||
2305 | if (setenv("PGDATA", pg_data, 1) != 0) | |||
2306 | { | |||
2307 | pg_log_error("could not set environment")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not set environment" ); } while(0); | |||
2308 | exit(1); | |||
2309 | } | |||
2310 | } | |||
2311 | ||||
2312 | ||||
2313 | void | |||
2314 | setup_bin_paths(const char *argv0) | |||
2315 | { | |||
2316 | int ret; | |||
2317 | ||||
2318 | if ((ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR"postgres (PostgreSQL) " "15devel" "\n", | |||
2319 | backend_exec)) < 0) | |||
2320 | { | |||
2321 | char full_path[MAXPGPATH1024]; | |||
2322 | ||||
2323 | if (find_my_exec(argv0, full_path) < 0) | |||
2324 | strlcpy(full_path, progname, sizeof(full_path)); | |||
2325 | ||||
2326 | if (ret == -1) | |||
2327 | pg_log_error("The program \"%s\" is needed by %s but was not found in the\n"do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "The program \"%s\" is needed by %s but was not found in the\n" "same directory as \"%s\".\n" "Check your installation.", "postgres" , progname, full_path); } while(0) | |||
2328 | "same directory as \"%s\".\n"do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "The program \"%s\" is needed by %s but was not found in the\n" "same directory as \"%s\".\n" "Check your installation.", "postgres" , progname, full_path); } while(0) | |||
2329 | "Check your installation.",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "The program \"%s\" is needed by %s but was not found in the\n" "same directory as \"%s\".\n" "Check your installation.", "postgres" , progname, full_path); } while(0) | |||
2330 | "postgres", progname, full_path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "The program \"%s\" is needed by %s but was not found in the\n" "same directory as \"%s\".\n" "Check your installation.", "postgres" , progname, full_path); } while(0); | |||
2331 | else | |||
2332 | pg_log_error("The program \"%s\" was found by \"%s\"\n"do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "The program \"%s\" was found by \"%s\"\n" "but was not the same version as %s.\n" "Check your installation." , "postgres", full_path, progname); } while(0) | |||
2333 | "but was not the same version as %s.\n"do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "The program \"%s\" was found by \"%s\"\n" "but was not the same version as %s.\n" "Check your installation." , "postgres", full_path, progname); } while(0) | |||
2334 | "Check your installation.",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "The program \"%s\" was found by \"%s\"\n" "but was not the same version as %s.\n" "Check your installation." , "postgres", full_path, progname); } while(0) | |||
2335 | "postgres", full_path, progname)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "The program \"%s\" was found by \"%s\"\n" "but was not the same version as %s.\n" "Check your installation." , "postgres", full_path, progname); } while(0); | |||
2336 | exit(1); | |||
2337 | } | |||
2338 | ||||
2339 | /* store binary directory */ | |||
2340 | strcpy(bin_path, backend_exec); | |||
2341 | *last_dir_separator(bin_path) = '\0'; | |||
2342 | canonicalize_path(bin_path); | |||
2343 | ||||
2344 | if (!share_path) | |||
2345 | { | |||
2346 | share_path = pg_malloc(MAXPGPATH1024); | |||
2347 | get_share_path(backend_exec, share_path); | |||
2348 | } | |||
2349 | else if (!is_absolute_path(share_path)( (((share_path)[0]) == '/') )) | |||
2350 | { | |||
2351 | pg_log_error("input file location must be an absolute path")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "input file location must be an absolute path" ); } while(0); | |||
2352 | exit(1); | |||
2353 | } | |||
2354 | ||||
2355 | canonicalize_path(share_path); | |||
2356 | } | |||
2357 | ||||
2358 | void | |||
2359 | setup_locale_encoding(void) | |||
2360 | { | |||
2361 | setlocales(); | |||
2362 | ||||
2363 | if (strcmp(lc_ctype, lc_collate) == 0 && | |||
2364 | strcmp(lc_ctype, lc_time) == 0 && | |||
2365 | strcmp(lc_ctype, lc_numeric) == 0 && | |||
2366 | strcmp(lc_ctype, lc_monetary) == 0 && | |||
2367 | strcmp(lc_ctype, lc_messages) == 0) | |||
2368 | printf(_("The database cluster will be initialized with locale \"%s\".\n"), lc_ctype)pg_printf(("The database cluster will be initialized with locale \"%s\".\n" ), lc_ctype); | |||
2369 | else | |||
2370 | { | |||
2371 | printf(_("The database cluster will be initialized with locales\n"pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2372 | " COLLATE: %s\n"pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2373 | " CTYPE: %s\n"pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2374 | " MESSAGES: %s\n"pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2375 | " MONETARY: %s\n"pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2376 | " NUMERIC: %s\n"pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2377 | " TIME: %s\n"),pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2378 | lc_collate,pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2379 | lc_ctype,pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2380 | lc_messages,pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2381 | lc_monetary,pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2382 | lc_numeric,pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time) | |||
2383 | lc_time)pg_printf(("The database cluster will be initialized with locales\n" " COLLATE: %s\n" " CTYPE: %s\n" " MESSAGES: %s\n" " MONETARY: %s\n" " NUMERIC: %s\n" " TIME: %s\n"), lc_collate, lc_ctype , lc_messages, lc_monetary, lc_numeric, lc_time); | |||
2384 | } | |||
2385 | ||||
2386 | if (!encoding) | |||
2387 | { | |||
2388 | int ctype_enc; | |||
2389 | ||||
2390 | ctype_enc = pg_get_encoding_from_locale(lc_ctype, true1); | |||
2391 | ||||
2392 | if (ctype_enc == -1) | |||
2393 | { | |||
2394 | /* Couldn't recognize the locale's codeset */ | |||
2395 | pg_log_error("could not find suitable encoding for locale \"%s\"",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not find suitable encoding for locale \"%s\"" , lc_ctype); } while(0) | |||
2396 | lc_ctype)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not find suitable encoding for locale \"%s\"" , lc_ctype); } while(0); | |||
2397 | fprintfpg_fprintf(stderrstderr, _("Rerun %s with the -E option.\n")("Rerun %s with the -E option.\n"), progname); | |||
2398 | fprintfpg_fprintf(stderrstderr, _("Try \"%s --help\" for more information.\n")("Try \"%s --help\" for more information.\n"), | |||
2399 | progname); | |||
2400 | exit(1); | |||
2401 | } | |||
2402 | else if (!pg_valid_server_encoding_id(ctype_enc)) | |||
2403 | { | |||
2404 | /* | |||
2405 | * We recognized it, but it's not a legal server encoding. On | |||
2406 | * Windows, UTF-8 works with any locale, so we can fall back to | |||
2407 | * UTF-8. | |||
2408 | */ | |||
2409 | #ifdef WIN32 | |||
2410 | encodingid = PG_UTF8; | |||
2411 | printf(_("Encoding \"%s\" implied by locale is not allowed as a server-side encoding.\n"pg_printf(("Encoding \"%s\" implied by locale is not allowed as a server-side encoding.\n" "The default database encoding will be set to \"%s\" instead.\n" ), pg_encoding_to_char(ctype_enc), pg_encoding_to_char(encodingid )) | |||
2412 | "The default database encoding will be set to \"%s\" instead.\n"),pg_printf(("Encoding \"%s\" implied by locale is not allowed as a server-side encoding.\n" "The default database encoding will be set to \"%s\" instead.\n" ), pg_encoding_to_char(ctype_enc), pg_encoding_to_char(encodingid )) | |||
2413 | pg_encoding_to_char(ctype_enc),pg_printf(("Encoding \"%s\" implied by locale is not allowed as a server-side encoding.\n" "The default database encoding will be set to \"%s\" instead.\n" ), pg_encoding_to_char(ctype_enc), pg_encoding_to_char(encodingid )) | |||
2414 | pg_encoding_to_char(encodingid))pg_printf(("Encoding \"%s\" implied by locale is not allowed as a server-side encoding.\n" "The default database encoding will be set to \"%s\" instead.\n" ), pg_encoding_to_char(ctype_enc), pg_encoding_to_char(encodingid )); | |||
2415 | #else | |||
2416 | pg_log_error("locale \"%s\" requires unsupported encoding \"%s\"",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "locale \"%s\" requires unsupported encoding \"%s\"" , lc_ctype, pg_encoding_to_char(ctype_enc)); } while(0) | |||
2417 | lc_ctype, pg_encoding_to_char(ctype_enc))do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "locale \"%s\" requires unsupported encoding \"%s\"" , lc_ctype, pg_encoding_to_char(ctype_enc)); } while(0); | |||
2418 | fprintfpg_fprintf(stderrstderr, | |||
2419 | _("Encoding \"%s\" is not allowed as a server-side encoding.\n"("Encoding \"%s\" is not allowed as a server-side encoding.\n" "Rerun %s with a different locale selection.\n") | |||
2420 | "Rerun %s with a different locale selection.\n")("Encoding \"%s\" is not allowed as a server-side encoding.\n" "Rerun %s with a different locale selection.\n"), | |||
2421 | pg_encoding_to_char(ctype_enc), progname); | |||
2422 | exit(1); | |||
2423 | #endif | |||
2424 | } | |||
2425 | else | |||
2426 | { | |||
2427 | encodingid = ctype_enc; | |||
2428 | printf(_("The default database encoding has accordingly been set to \"%s\".\n"),pg_printf(("The default database encoding has accordingly been set to \"%s\".\n" ), pg_encoding_to_char(encodingid)) | |||
2429 | pg_encoding_to_char(encodingid))pg_printf(("The default database encoding has accordingly been set to \"%s\".\n" ), pg_encoding_to_char(encodingid)); | |||
2430 | } | |||
2431 | } | |||
2432 | else | |||
2433 | encodingid = get_encoding_id(encoding); | |||
2434 | ||||
2435 | if (!check_locale_encoding(lc_ctype, encodingid) || | |||
2436 | !check_locale_encoding(lc_collate, encodingid)) | |||
2437 | exit(1); /* check_locale_encoding printed the error */ | |||
2438 | ||||
2439 | } | |||
2440 | ||||
2441 | ||||
2442 | void | |||
2443 | setup_data_file_paths(void) | |||
2444 | { | |||
2445 | set_input(&bki_file, "postgres.bki"); | |||
2446 | set_input(&hba_file, "pg_hba.conf.sample"); | |||
2447 | set_input(&ident_file, "pg_ident.conf.sample"); | |||
2448 | set_input(&conf_file, "postgresql.conf.sample"); | |||
2449 | set_input(&dictionary_file, "snowball_create.sql"); | |||
2450 | set_input(&info_schema_file, "information_schema.sql"); | |||
2451 | set_input(&features_file, "sql_features.txt"); | |||
2452 | set_input(&system_constraints_file, "system_constraints.sql"); | |||
2453 | set_input(&system_functions_file, "system_functions.sql"); | |||
2454 | set_input(&system_views_file, "system_views.sql"); | |||
2455 | ||||
2456 | if (show_setting || debug) | |||
2457 | { | |||
2458 | fprintfpg_fprintf(stderrstderr, | |||
2459 | "VERSION=%s\n" | |||
2460 | "PGDATA=%s\nshare_path=%s\nPGPATH=%s\n" | |||
2461 | "POSTGRES_SUPERUSERNAME=%s\nPOSTGRES_BKI=%s\n" | |||
2462 | "POSTGRESQL_CONF_SAMPLE=%s\n" | |||
2463 | "PG_HBA_SAMPLE=%s\nPG_IDENT_SAMPLE=%s\n", | |||
2464 | PG_VERSION"15devel", | |||
2465 | pg_data, share_path, bin_path, | |||
2466 | username, bki_file, | |||
2467 | conf_file, | |||
2468 | hba_file, ident_file); | |||
2469 | if (show_setting) | |||
2470 | exit(0); | |||
2471 | } | |||
2472 | ||||
2473 | check_input(bki_file); | |||
2474 | check_input(hba_file); | |||
2475 | check_input(ident_file); | |||
2476 | check_input(conf_file); | |||
2477 | check_input(dictionary_file); | |||
2478 | check_input(info_schema_file); | |||
2479 | check_input(features_file); | |||
2480 | check_input(system_constraints_file); | |||
2481 | check_input(system_functions_file); | |||
2482 | check_input(system_views_file); | |||
2483 | } | |||
2484 | ||||
2485 | ||||
2486 | void | |||
2487 | setup_text_search(void) | |||
2488 | { | |||
2489 | if (!default_text_search_config) | |||
2490 | { | |||
2491 | default_text_search_config = find_matching_ts_config(lc_ctype); | |||
2492 | if (!default_text_search_config) | |||
2493 | { | |||
2494 | pg_log_info("could not find suitable text search configuration for locale \"%s\"",do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "could not find suitable text search configuration for locale \"%s\"" , lc_ctype); } while(0) | |||
2495 | lc_ctype)do { if (__builtin_expect((__pg_log_level <= PG_LOG_INFO) != 0, 1)) pg_log_generic(PG_LOG_INFO, "could not find suitable text search configuration for locale \"%s\"" , lc_ctype); } while(0); | |||
2496 | default_text_search_config = "simple"; | |||
2497 | } | |||
2498 | } | |||
2499 | else | |||
2500 | { | |||
2501 | const char *checkmatch = find_matching_ts_config(lc_ctype); | |||
2502 | ||||
2503 | if (checkmatch == NULL((void*)0)) | |||
2504 | { | |||
2505 | pg_log_warning("suitable text search configuration for locale \"%s\" is unknown",do { if (__builtin_expect((__pg_log_level <= PG_LOG_WARNING ) != 0, 1)) pg_log_generic(PG_LOG_WARNING, "suitable text search configuration for locale \"%s\" is unknown" , lc_ctype); } while(0) | |||
2506 | lc_ctype)do { if (__builtin_expect((__pg_log_level <= PG_LOG_WARNING ) != 0, 1)) pg_log_generic(PG_LOG_WARNING, "suitable text search configuration for locale \"%s\" is unknown" , lc_ctype); } while(0); | |||
2507 | } | |||
2508 | else if (strcmp(checkmatch, default_text_search_config) != 0) | |||
2509 | { | |||
2510 | pg_log_warning("specified text search configuration \"%s\" might not match locale \"%s\"",do { if (__builtin_expect((__pg_log_level <= PG_LOG_WARNING ) != 0, 1)) pg_log_generic(PG_LOG_WARNING, "specified text search configuration \"%s\" might not match locale \"%s\"" , default_text_search_config, lc_ctype); } while(0) | |||
2511 | default_text_search_config, lc_ctype)do { if (__builtin_expect((__pg_log_level <= PG_LOG_WARNING ) != 0, 1)) pg_log_generic(PG_LOG_WARNING, "specified text search configuration \"%s\" might not match locale \"%s\"" , default_text_search_config, lc_ctype); } while(0); | |||
2512 | } | |||
2513 | } | |||
2514 | ||||
2515 | printf(_("The default text search configuration will be set to \"%s\".\n"),pg_printf(("The default text search configuration will be set to \"%s\".\n" ), default_text_search_config) | |||
2516 | default_text_search_config)pg_printf(("The default text search configuration will be set to \"%s\".\n" ), default_text_search_config); | |||
2517 | ||||
2518 | } | |||
2519 | ||||
2520 | ||||
2521 | void | |||
2522 | setup_signals(void) | |||
2523 | { | |||
2524 | /* some of these are not valid on Windows */ | |||
2525 | #ifdef SIGHUP1 | |||
2526 | pqsignal(SIGHUP1, trapsig); | |||
2527 | #endif | |||
2528 | #ifdef SIGINT2 | |||
2529 | pqsignal(SIGINT2, trapsig); | |||
2530 | #endif | |||
2531 | #ifdef SIGQUIT3 | |||
2532 | pqsignal(SIGQUIT3, trapsig); | |||
2533 | #endif | |||
2534 | #ifdef SIGTERM15 | |||
2535 | pqsignal(SIGTERM15, trapsig); | |||
2536 | #endif | |||
2537 | ||||
2538 | /* Ignore SIGPIPE when writing to backend, so we can clean up */ | |||
2539 | #ifdef SIGPIPE13 | |||
2540 | pqsignal(SIGPIPE13, SIG_IGN((__sighandler_t) 1)); | |||
2541 | #endif | |||
2542 | ||||
2543 | /* Prevent SIGSYS so we can probe for kernel calls that might not work */ | |||
2544 | #ifdef SIGSYS31 | |||
2545 | pqsignal(SIGSYS31, SIG_IGN((__sighandler_t) 1)); | |||
2546 | #endif | |||
2547 | } | |||
2548 | ||||
2549 | ||||
2550 | void | |||
2551 | create_data_directory(void) | |||
2552 | { | |||
2553 | int ret; | |||
2554 | ||||
2555 | switch ((ret = pg_check_dir(pg_data))) | |||
2556 | { | |||
2557 | case 0: | |||
2558 | /* PGDATA not there, must create it */ | |||
2559 | printf(_("creating directory %s ... "),pg_printf(("creating directory %s ... "), pg_data) | |||
2560 | pg_data)pg_printf(("creating directory %s ... "), pg_data); | |||
2561 | fflush(stdoutstdout); | |||
2562 | ||||
2563 | if (pg_mkdir_p(pg_data, pg_dir_create_mode) != 0) | |||
2564 | { | |||
2565 | pg_log_error("could not create directory \"%s\": %m", pg_data)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not create directory \"%s\": %m" , pg_data); } while(0); | |||
2566 | exit(1); | |||
2567 | } | |||
2568 | else | |||
2569 | check_ok(); | |||
2570 | ||||
2571 | made_new_pgdata = true1; | |||
2572 | break; | |||
2573 | ||||
2574 | case 1: | |||
2575 | /* Present but empty, fix permissions and use it */ | |||
2576 | printf(_("fixing permissions on existing directory %s ... "),pg_printf(("fixing permissions on existing directory %s ... " ), pg_data) | |||
2577 | pg_data)pg_printf(("fixing permissions on existing directory %s ... " ), pg_data); | |||
2578 | fflush(stdoutstdout); | |||
2579 | ||||
2580 | if (chmod(pg_data, pg_dir_create_mode) != 0) | |||
2581 | { | |||
2582 | pg_log_error("could not change permissions of directory \"%s\": %m",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not change permissions of directory \"%s\": %m" , pg_data); } while(0) | |||
2583 | pg_data)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not change permissions of directory \"%s\": %m" , pg_data); } while(0); | |||
2584 | exit(1); | |||
2585 | } | |||
2586 | else | |||
2587 | check_ok(); | |||
2588 | ||||
2589 | found_existing_pgdata = true1; | |||
2590 | break; | |||
2591 | ||||
2592 | case 2: | |||
2593 | case 3: | |||
2594 | case 4: | |||
2595 | /* Present and not empty */ | |||
2596 | pg_log_error("directory \"%s\" exists but is not empty", pg_data)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "directory \"%s\" exists but is not empty" , pg_data); } while(0); | |||
2597 | if (ret != 4) | |||
2598 | warn_on_mount_point(ret); | |||
2599 | else | |||
2600 | fprintfpg_fprintf(stderrstderr, | |||
2601 | _("If you want to create a new database system, either remove or empty\n"("If you want to create a new database system, either remove or empty\n" "the directory \"%s\" or run %s\n" "with an argument other than \"%s\".\n" ) | |||
2602 | "the directory \"%s\" or run %s\n"("If you want to create a new database system, either remove or empty\n" "the directory \"%s\" or run %s\n" "with an argument other than \"%s\".\n" ) | |||
2603 | "with an argument other than \"%s\".\n")("If you want to create a new database system, either remove or empty\n" "the directory \"%s\" or run %s\n" "with an argument other than \"%s\".\n" ), | |||
2604 | pg_data, progname, pg_data); | |||
2605 | exit(1); /* no further message needed */ | |||
2606 | ||||
2607 | default: | |||
2608 | /* Trouble accessing directory */ | |||
2609 | pg_log_error("could not access directory \"%s\": %m", pg_data)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not access directory \"%s\": %m" , pg_data); } while(0); | |||
2610 | exit(1); | |||
2611 | } | |||
2612 | } | |||
2613 | ||||
2614 | ||||
2615 | /* Create WAL directory, and symlink if required */ | |||
2616 | void | |||
2617 | create_xlog_or_symlink(void) | |||
2618 | { | |||
2619 | char *subdirloc; | |||
2620 | ||||
2621 | /* form name of the place for the subdirectory or symlink */ | |||
2622 | subdirloc = psprintf("%s/pg_wal", pg_data); | |||
2623 | ||||
2624 | if (xlog_dir) | |||
2625 | { | |||
2626 | int ret; | |||
2627 | ||||
2628 | /* clean up xlog directory name, check it's absolute */ | |||
2629 | canonicalize_path(xlog_dir); | |||
2630 | if (!is_absolute_path(xlog_dir)( (((xlog_dir)[0]) == '/') )) | |||
2631 | { | |||
2632 | pg_log_error("WAL directory location must be an absolute path")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "WAL directory location must be an absolute path" ); } while(0); | |||
2633 | exit(1); | |||
2634 | } | |||
2635 | ||||
2636 | /* check if the specified xlog directory exists/is empty */ | |||
2637 | switch ((ret = pg_check_dir(xlog_dir))) | |||
2638 | { | |||
2639 | case 0: | |||
2640 | /* xlog directory not there, must create it */ | |||
2641 | printf(_("creating directory %s ... "),pg_printf(("creating directory %s ... "), xlog_dir) | |||
2642 | xlog_dir)pg_printf(("creating directory %s ... "), xlog_dir); | |||
2643 | fflush(stdoutstdout); | |||
2644 | ||||
2645 | if (pg_mkdir_p(xlog_dir, pg_dir_create_mode) != 0) | |||
2646 | { | |||
2647 | pg_log_error("could not create directory \"%s\": %m",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not create directory \"%s\": %m" , xlog_dir); } while(0) | |||
2648 | xlog_dir)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not create directory \"%s\": %m" , xlog_dir); } while(0); | |||
2649 | exit(1); | |||
2650 | } | |||
2651 | else | |||
2652 | check_ok(); | |||
2653 | ||||
2654 | made_new_xlogdir = true1; | |||
2655 | break; | |||
2656 | ||||
2657 | case 1: | |||
2658 | /* Present but empty, fix permissions and use it */ | |||
2659 | printf(_("fixing permissions on existing directory %s ... "),pg_printf(("fixing permissions on existing directory %s ... " ), xlog_dir) | |||
2660 | xlog_dir)pg_printf(("fixing permissions on existing directory %s ... " ), xlog_dir); | |||
2661 | fflush(stdoutstdout); | |||
2662 | ||||
2663 | if (chmod(xlog_dir, pg_dir_create_mode) != 0) | |||
2664 | { | |||
2665 | pg_log_error("could not change permissions of directory \"%s\": %m",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not change permissions of directory \"%s\": %m" , xlog_dir); } while(0) | |||
2666 | xlog_dir)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not change permissions of directory \"%s\": %m" , xlog_dir); } while(0); | |||
2667 | exit(1); | |||
2668 | } | |||
2669 | else | |||
2670 | check_ok(); | |||
2671 | ||||
2672 | found_existing_xlogdir = true1; | |||
2673 | break; | |||
2674 | ||||
2675 | case 2: | |||
2676 | case 3: | |||
2677 | case 4: | |||
2678 | /* Present and not empty */ | |||
2679 | pg_log_error("directory \"%s\" exists but is not empty", xlog_dir)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "directory \"%s\" exists but is not empty" , xlog_dir); } while(0); | |||
2680 | if (ret != 4) | |||
2681 | warn_on_mount_point(ret); | |||
2682 | else | |||
2683 | fprintfpg_fprintf(stderrstderr, | |||
2684 | _("If you want to store the WAL there, either remove or empty the directory\n"("If you want to store the WAL there, either remove or empty the directory\n" "\"%s\".\n") | |||
2685 | "\"%s\".\n")("If you want to store the WAL there, either remove or empty the directory\n" "\"%s\".\n"), | |||
2686 | xlog_dir); | |||
2687 | exit(1); | |||
2688 | ||||
2689 | default: | |||
2690 | /* Trouble accessing directory */ | |||
2691 | pg_log_error("could not access directory \"%s\": %m", xlog_dir)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not access directory \"%s\": %m" , xlog_dir); } while(0); | |||
2692 | exit(1); | |||
2693 | } | |||
2694 | ||||
2695 | #ifdef HAVE_SYMLINK1 | |||
2696 | if (symlink(xlog_dir, subdirloc) != 0) | |||
2697 | { | |||
2698 | pg_log_error("could not create symbolic link \"%s\": %m",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not create symbolic link \"%s\": %m" , subdirloc); } while(0) | |||
2699 | subdirloc)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not create symbolic link \"%s\": %m" , subdirloc); } while(0); | |||
2700 | exit(1); | |||
2701 | } | |||
2702 | #else | |||
2703 | pg_log_error("symlinks are not supported on this platform")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "symlinks are not supported on this platform" ); } while(0); | |||
2704 | exit(1); | |||
2705 | #endif | |||
2706 | } | |||
2707 | else | |||
2708 | { | |||
2709 | /* Without -X option, just make the subdirectory normally */ | |||
2710 | if (mkdir(subdirloc, pg_dir_create_mode) < 0) | |||
2711 | { | |||
2712 | pg_log_error("could not create directory \"%s\": %m",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not create directory \"%s\": %m" , subdirloc); } while(0) | |||
2713 | subdirloc)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not create directory \"%s\": %m" , subdirloc); } while(0); | |||
2714 | exit(1); | |||
2715 | } | |||
2716 | } | |||
2717 | ||||
2718 | free(subdirloc); | |||
2719 | } | |||
2720 | ||||
2721 | ||||
2722 | void | |||
2723 | warn_on_mount_point(int error) | |||
2724 | { | |||
2725 | if (error == 2) | |||
2726 | fprintfpg_fprintf(stderrstderr, | |||
2727 | _("It contains a dot-prefixed/invisible file, perhaps due to it being a mount point.\n")("It contains a dot-prefixed/invisible file, perhaps due to it being a mount point.\n" )); | |||
2728 | else if (error == 3) | |||
2729 | fprintfpg_fprintf(stderrstderr, | |||
2730 | _("It contains a lost+found directory, perhaps due to it being a mount point.\n")("It contains a lost+found directory, perhaps due to it being a mount point.\n" )); | |||
2731 | ||||
2732 | fprintfpg_fprintf(stderrstderr, | |||
2733 | _("Using a mount point directly as the data directory is not recommended.\n"("Using a mount point directly as the data directory is not recommended.\n" "Create a subdirectory under the mount point.\n") | |||
2734 | "Create a subdirectory under the mount point.\n")("Using a mount point directly as the data directory is not recommended.\n" "Create a subdirectory under the mount point.\n")); | |||
2735 | } | |||
2736 | ||||
2737 | ||||
2738 | void | |||
2739 | initialize_data_directory(void) | |||
2740 | { | |||
2741 | PG_CMD_DECLchar cmd[1024]; FILE *cmdfd; | |||
2742 | int i; | |||
2743 | ||||
2744 | setup_signals(); | |||
2745 | ||||
2746 | /* | |||
2747 | * Set mask based on requested PGDATA permissions. pg_mode_mask, and | |||
2748 | * friends like pg_dir_create_mode, are set to owner-only by default and | |||
2749 | * then updated if -g is passed in by calling SetDataDirectoryCreatePerm() | |||
2750 | * when parsing our options (see above). | |||
2751 | */ | |||
2752 | umask(pg_mode_mask); | |||
2753 | ||||
2754 | create_data_directory(); | |||
2755 | ||||
2756 | create_xlog_or_symlink(); | |||
2757 | ||||
2758 | /* Create required subdirectories (other than pg_wal) */ | |||
2759 | printf(_("creating subdirectories ... "))pg_printf(("creating subdirectories ... ")); | |||
2760 | fflush(stdoutstdout); | |||
2761 | ||||
2762 | for (i = 0; i < lengthof(subdirs)(sizeof (subdirs) / sizeof ((subdirs)[0])); i++) | |||
2763 | { | |||
2764 | char *path; | |||
2765 | ||||
2766 | path = psprintf("%s/%s", pg_data, subdirs[i]); | |||
2767 | ||||
2768 | /* | |||
2769 | * The parent directory already exists, so we only need mkdir() not | |||
2770 | * pg_mkdir_p() here, which avoids some failure modes; cf bug #13853. | |||
2771 | */ | |||
2772 | if (mkdir(path, pg_dir_create_mode) < 0) | |||
2773 | { | |||
2774 | pg_log_error("could not create directory \"%s\": %m", path)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not create directory \"%s\": %m" , path); } while(0); | |||
2775 | exit(1); | |||
2776 | } | |||
2777 | ||||
2778 | free(path); | |||
2779 | } | |||
2780 | ||||
2781 | check_ok(); | |||
2782 | ||||
2783 | /* Top level PG_VERSION is checked by bootstrapper, so make it first */ | |||
2784 | write_version_file(NULL((void*)0)); | |||
2785 | ||||
2786 | /* Select suitable configuration settings */ | |||
2787 | set_null_conf(); | |||
2788 | test_config_settings(); | |||
2789 | ||||
2790 | /* Now create all the text config files */ | |||
2791 | setup_config(); | |||
2792 | ||||
2793 | /* Bootstrap template1 */ | |||
2794 | bootstrap_template1(); | |||
2795 | ||||
2796 | /* | |||
2797 | * Make the per-database PG_VERSION for template1 only after init'ing it | |||
2798 | */ | |||
2799 | write_version_file("base/1"); | |||
2800 | ||||
2801 | /* | |||
2802 | * Create the stuff we don't need to use bootstrap mode for, using a | |||
2803 | * backend running in simple standalone mode. | |||
2804 | */ | |||
2805 | fputs(_("performing post-bootstrap initialization ... ")("performing post-bootstrap initialization ... "), stdoutstdout); | |||
2806 | fflush(stdoutstdout); | |||
2807 | ||||
2808 | snprintfpg_snprintf(cmd, sizeof(cmd), | |||
2809 | "\"%s\" %s %s template1 >%s", | |||
2810 | backend_exec, backend_options, extra_options, | |||
2811 | DEVNULL"/dev/null"); | |||
2812 | ||||
2813 | PG_CMD_OPENdo { cmdfd = popen_check(cmd, "w"); if (cmdfd == ((void*)0)) exit (1); } while (0); | |||
2814 | ||||
2815 | setup_auth(cmdfd); | |||
2816 | ||||
2817 | setup_run_file(cmdfd, system_constraints_file); | |||
2818 | ||||
2819 | setup_run_file(cmdfd, system_functions_file); | |||
2820 | ||||
2821 | setup_depend(cmdfd); | |||
2822 | ||||
2823 | /* | |||
2824 | * Note that no objects created after setup_depend() will be "pinned". | |||
2825 | * They are all droppable at the whim of the DBA. | |||
2826 | */ | |||
2827 | ||||
2828 | setup_run_file(cmdfd, system_views_file); | |||
2829 | ||||
2830 | setup_description(cmdfd); | |||
2831 | ||||
2832 | setup_collation(cmdfd); | |||
2833 | ||||
2834 | setup_run_file(cmdfd, dictionary_file); | |||
2835 | ||||
2836 | setup_privileges(cmdfd); | |||
2837 | ||||
2838 | setup_schema(cmdfd); | |||
2839 | ||||
2840 | load_plpgsql(cmdfd); | |||
2841 | ||||
2842 | vacuum_db(cmdfd); | |||
2843 | ||||
2844 | make_template0(cmdfd); | |||
2845 | ||||
2846 | make_postgres(cmdfd); | |||
2847 | ||||
2848 | PG_CMD_CLOSEdo { if (pclose_check(cmdfd)) exit(1); } while (0); | |||
2849 | ||||
2850 | check_ok(); | |||
2851 | } | |||
2852 | ||||
2853 | ||||
2854 | int | |||
2855 | main(int argc, char *argv[]) | |||
2856 | { | |||
2857 | static struct option long_options[] = { | |||
2858 | {"pgdata", required_argument1, NULL((void*)0), 'D'}, | |||
2859 | {"encoding", required_argument1, NULL((void*)0), 'E'}, | |||
2860 | {"locale", required_argument1, NULL((void*)0), 1}, | |||
2861 | {"lc-collate", required_argument1, NULL((void*)0), 2}, | |||
2862 | {"lc-ctype", required_argument1, NULL((void*)0), 3}, | |||
2863 | {"lc-monetary", required_argument1, NULL((void*)0), 4}, | |||
2864 | {"lc-numeric", required_argument1, NULL((void*)0), 5}, | |||
2865 | {"lc-time", required_argument1, NULL((void*)0), 6}, | |||
2866 | {"lc-messages", required_argument1, NULL((void*)0), 7}, | |||
2867 | {"no-locale", no_argument0, NULL((void*)0), 8}, | |||
2868 | {"text-search-config", required_argument1, NULL((void*)0), 'T'}, | |||
2869 | {"auth", required_argument1, NULL((void*)0), 'A'}, | |||
2870 | {"auth-local", required_argument1, NULL((void*)0), 10}, | |||
2871 | {"auth-host", required_argument1, NULL((void*)0), 11}, | |||
2872 | {"pwprompt", no_argument0, NULL((void*)0), 'W'}, | |||
2873 | {"pwfile", required_argument1, NULL((void*)0), 9}, | |||
2874 | {"username", required_argument1, NULL((void*)0), 'U'}, | |||
2875 | {"help", no_argument0, NULL((void*)0), '?'}, | |||
2876 | {"version", no_argument0, NULL((void*)0), 'V'}, | |||
2877 | {"debug", no_argument0, NULL((void*)0), 'd'}, | |||
2878 | {"show", no_argument0, NULL((void*)0), 's'}, | |||
2879 | {"noclean", no_argument0, NULL((void*)0), 'n'}, /* for backwards compatibility */ | |||
2880 | {"no-clean", no_argument0, NULL((void*)0), 'n'}, | |||
2881 | {"nosync", no_argument0, NULL((void*)0), 'N'}, /* for backwards compatibility */ | |||
2882 | {"no-sync", no_argument0, NULL((void*)0), 'N'}, | |||
2883 | {"no-instructions", no_argument0, NULL((void*)0), 13}, | |||
2884 | {"sync-only", no_argument0, NULL((void*)0), 'S'}, | |||
2885 | {"waldir", required_argument1, NULL((void*)0), 'X'}, | |||
2886 | {"wal-segsize", required_argument1, NULL((void*)0), 12}, | |||
2887 | {"data-checksums", no_argument0, NULL((void*)0), 'k'}, | |||
2888 | {"allow-group-access", no_argument0, NULL((void*)0), 'g'}, | |||
2889 | {"discard-caches", no_argument0, NULL((void*)0), 14}, | |||
2890 | {NULL((void*)0), 0, NULL((void*)0), 0} | |||
2891 | }; | |||
2892 | ||||
2893 | /* | |||
2894 | * options with no short version return a low integer, the rest return | |||
2895 | * their short version value | |||
2896 | */ | |||
2897 | int c; | |||
2898 | int option_index; | |||
2899 | char *effective_user; | |||
2900 | PQExpBuffer start_db_cmd; | |||
2901 | char pg_ctl_path[MAXPGPATH1024]; | |||
2902 | ||||
2903 | /* | |||
2904 | * Ensure that buffering behavior of stdout matches what it is in | |||
2905 | * interactive usage (at least on most platforms). This prevents | |||
2906 | * unexpected output ordering when, eg, output is redirected to a file. | |||
2907 | * POSIX says we must do this before any other usage of these files. | |||
2908 | */ | |||
2909 | setvbuf(stdoutstdout, NULL((void*)0), PG_IOLBF1, 0); | |||
2910 | ||||
2911 | pg_logging_init(argv[0]); | |||
2912 | progname = get_progname(argv[0]); | |||
2913 | set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("initdb")("initdb" "-" "15")); | |||
2914 | ||||
2915 | if (argc > 1) | |||
2916 | { | |||
2917 | if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) | |||
2918 | { | |||
2919 | usage(progname); | |||
2920 | exit(0); | |||
2921 | } | |||
2922 | if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) | |||
2923 | { | |||
2924 | puts("initdb (PostgreSQL) " PG_VERSION"15devel"); | |||
2925 | exit(0); | |||
2926 | } | |||
2927 | } | |||
2928 | ||||
2929 | /* process command-line options */ | |||
2930 | ||||
2931 | while ((c = getopt_long(argc, argv, "A:dD:E:gkL:nNsST:U:WX:", long_options, &option_index)) != -1) | |||
2932 | { | |||
2933 | switch (c) | |||
2934 | { | |||
2935 | case 'A': | |||
2936 | authmethodlocal = authmethodhost = pg_strdup(optarg); | |||
2937 | ||||
2938 | /* | |||
2939 | * When ident is specified, use peer for local connections. | |||
2940 | * Mirrored, when peer is specified, use ident for TCP/IP | |||
2941 | * connections. | |||
2942 | */ | |||
2943 | if (strcmp(authmethodhost, "ident") == 0) | |||
2944 | authmethodlocal = "peer"; | |||
2945 | else if (strcmp(authmethodlocal, "peer") == 0) | |||
2946 | authmethodhost = "ident"; | |||
2947 | break; | |||
2948 | case 10: | |||
2949 | authmethodlocal = pg_strdup(optarg); | |||
2950 | break; | |||
2951 | case 11: | |||
2952 | authmethodhost = pg_strdup(optarg); | |||
2953 | break; | |||
2954 | case 'D': | |||
2955 | pg_data = pg_strdup(optarg); | |||
2956 | break; | |||
2957 | case 'E': | |||
2958 | encoding = pg_strdup(optarg); | |||
2959 | break; | |||
2960 | case 'W': | |||
2961 | pwprompt = true1; | |||
2962 | break; | |||
2963 | case 'U': | |||
2964 | username = pg_strdup(optarg); | |||
2965 | break; | |||
2966 | case 'd': | |||
2967 | debug = true1; | |||
2968 | printf(_("Running in debug mode.\n"))pg_printf(("Running in debug mode.\n")); | |||
2969 | break; | |||
2970 | case 'n': | |||
2971 | noclean = true1; | |||
2972 | printf(_("Running in no-clean mode. Mistakes will not be cleaned up.\n"))pg_printf(("Running in no-clean mode. Mistakes will not be cleaned up.\n" )); | |||
2973 | break; | |||
2974 | case 'N': | |||
2975 | do_sync = false0; | |||
2976 | break; | |||
2977 | case 'S': | |||
2978 | sync_only = true1; | |||
2979 | break; | |||
2980 | case 'k': | |||
2981 | data_checksums = true1; | |||
2982 | break; | |||
2983 | case 'L': | |||
2984 | share_path = pg_strdup(optarg); | |||
2985 | break; | |||
2986 | case 1: | |||
2987 | locale = pg_strdup(optarg); | |||
2988 | break; | |||
2989 | case 2: | |||
2990 | lc_collate = pg_strdup(optarg); | |||
2991 | break; | |||
2992 | case 3: | |||
2993 | lc_ctype = pg_strdup(optarg); | |||
2994 | break; | |||
2995 | case 4: | |||
2996 | lc_monetary = pg_strdup(optarg); | |||
2997 | break; | |||
2998 | case 5: | |||
2999 | lc_numeric = pg_strdup(optarg); | |||
3000 | break; | |||
3001 | case 6: | |||
3002 | lc_time = pg_strdup(optarg); | |||
3003 | break; | |||
3004 | case 7: | |||
3005 | lc_messages = pg_strdup(optarg); | |||
3006 | break; | |||
3007 | case 8: | |||
3008 | locale = "C"; | |||
3009 | break; | |||
3010 | case 9: | |||
3011 | pwfilename = pg_strdup(optarg); | |||
3012 | break; | |||
3013 | case 's': | |||
3014 | show_setting = true1; | |||
3015 | break; | |||
3016 | case 'T': | |||
3017 | default_text_search_config = pg_strdup(optarg); | |||
3018 | break; | |||
3019 | case 'X': | |||
3020 | xlog_dir = pg_strdup(optarg); | |||
3021 | break; | |||
3022 | case 12: | |||
3023 | str_wal_segment_size_mb = pg_strdup(optarg); | |||
3024 | break; | |||
3025 | case 13: | |||
3026 | noinstructions = true1; | |||
3027 | break; | |||
3028 | case 'g': | |||
3029 | SetDataDirectoryCreatePerm(PG_DIR_MODE_GROUP((0400|0200|0100) | (0400 >> 3) | (0100 >> 3))); | |||
3030 | break; | |||
3031 | case 14: | |||
3032 | extra_options = psprintf("%s %s", | |||
3033 | extra_options, | |||
3034 | "-c debug_discard_caches=1"); | |||
3035 | break; | |||
3036 | default: | |||
3037 | /* getopt_long already emitted a complaint */ | |||
3038 | fprintfpg_fprintf(stderrstderr, _("Try \"%s --help\" for more information.\n")("Try \"%s --help\" for more information.\n"), | |||
3039 | progname); | |||
3040 | exit(1); | |||
3041 | } | |||
3042 | } | |||
3043 | ||||
3044 | ||||
3045 | /* | |||
3046 | * Non-option argument specifies data directory as long as it wasn't | |||
3047 | * already specified with -D / --pgdata | |||
3048 | */ | |||
3049 | if (optind < argc && !pg_data) | |||
3050 | { | |||
3051 | pg_data = pg_strdup(argv[optind]); | |||
3052 | optind++; | |||
3053 | } | |||
3054 | ||||
3055 | if (optind < argc) | |||
3056 | { | |||
3057 | pg_log_error("too many command-line arguments (first is \"%s\")",do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "too many command-line arguments (first is \"%s\")" , argv[optind]); } while(0) | |||
3058 | argv[optind])do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "too many command-line arguments (first is \"%s\")" , argv[optind]); } while(0); | |||
3059 | fprintfpg_fprintf(stderrstderr, _("Try \"%s --help\" for more information.\n")("Try \"%s --help\" for more information.\n"), | |||
3060 | progname); | |||
3061 | exit(1); | |||
3062 | } | |||
3063 | ||||
3064 | atexit(cleanup_directories_atexit); | |||
3065 | ||||
3066 | /* If we only need to fsync, just do it and exit */ | |||
3067 | if (sync_only) | |||
3068 | { | |||
3069 | setup_pgdata(); | |||
3070 | ||||
3071 | /* must check that directory is readable */ | |||
3072 | if (pg_check_dir(pg_data) <= 0) | |||
3073 | { | |||
3074 | pg_log_error("could not access directory \"%s\": %m", pg_data)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "could not access directory \"%s\": %m" , pg_data); } while(0); | |||
3075 | exit(1); | |||
3076 | } | |||
3077 | ||||
3078 | fputs(_("syncing data to disk ... ")("syncing data to disk ... "), stdoutstdout); | |||
3079 | fflush(stdoutstdout); | |||
3080 | fsync_pgdata(pg_data, PG_VERSION_NUM150000); | |||
3081 | check_ok(); | |||
3082 | return 0; | |||
3083 | } | |||
3084 | ||||
3085 | if (pwprompt && pwfilename) | |||
3086 | { | |||
3087 | pg_log_error("password prompt and password file cannot be specified together")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "password prompt and password file cannot be specified together" ); } while(0); | |||
3088 | exit(1); | |||
3089 | } | |||
3090 | ||||
3091 | check_authmethod_unspecified(&authmethodlocal); | |||
3092 | check_authmethod_unspecified(&authmethodhost); | |||
3093 | ||||
3094 | check_authmethod_valid(authmethodlocal, auth_methods_local, "local"); | |||
3095 | check_authmethod_valid(authmethodhost, auth_methods_host, "host"); | |||
3096 | ||||
3097 | check_need_password(authmethodlocal, authmethodhost); | |||
3098 | ||||
3099 | /* set wal segment size */ | |||
3100 | if (str_wal_segment_size_mb == NULL((void*)0)) | |||
3101 | wal_segment_size_mb = (DEFAULT_XLOG_SEG_SIZE(16*1024*1024)) / (1024 * 1024); | |||
3102 | else | |||
3103 | { | |||
3104 | char *endptr; | |||
3105 | ||||
3106 | /* check that the argument is a number */ | |||
3107 | wal_segment_size_mb = strtol(str_wal_segment_size_mb, &endptr, 10); | |||
3108 | ||||
3109 | /* verify that wal segment size is valid */ | |||
3110 | if (endptr == str_wal_segment_size_mb || *endptr != '\0') | |||
3111 | { | |||
3112 | pg_log_error("argument of --wal-segsize must be a number")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "argument of --wal-segsize must be a number" ); } while(0); | |||
3113 | exit(1); | |||
3114 | } | |||
3115 | if (!IsValidWalSegSize(wal_segment_size_mb * 1024 * 1024)((wal_segment_size_mb * 1024 * 1024 > 0 && ((wal_segment_size_mb * 1024 * 1024) & ((wal_segment_size_mb * 1024 * 1024)-1) ) == 0) && ((wal_segment_size_mb * 1024 * 1024) >= 1024 * 1024 && (wal_segment_size_mb * 1024 * 1024) <= 1024 * 1024 * 1024))) | |||
3116 | { | |||
3117 | pg_log_error("argument of --wal-segsize must be a power of 2 between 1 and 1024")do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "argument of --wal-segsize must be a power of 2 between 1 and 1024" ); } while(0); | |||
3118 | exit(1); | |||
3119 | } | |||
3120 | } | |||
3121 | ||||
3122 | get_restricted_token(); | |||
3123 | ||||
3124 | setup_pgdata(); | |||
3125 | ||||
3126 | setup_bin_paths(argv[0]); | |||
3127 | ||||
3128 | effective_user = get_id(); | |||
3129 | if (!username) | |||
3130 | username = effective_user; | |||
3131 | ||||
3132 | if (strncmp(username, "pg_", 3) == 0) | |||
3133 | { | |||
3134 | pg_log_error("superuser name \"%s\" is disallowed; role names cannot begin with \"pg_\"", username)do { if (__builtin_expect((__pg_log_level <= PG_LOG_ERROR) != 0, 1)) pg_log_generic(PG_LOG_ERROR, "superuser name \"%s\" is disallowed; role names cannot begin with \"pg_\"" , username); } while(0); | |||
3135 | exit(1); | |||
3136 | } | |||
3137 | ||||
3138 | printf(_("The files belonging to this database system will be owned "pg_printf(("The files belonging to this database system will be owned " "by user \"%s\".\n" "This user must also own the server process.\n\n" ), effective_user) | |||
3139 | "by user \"%s\".\n"pg_printf(("The files belonging to this database system will be owned " "by user \"%s\".\n" "This user must also own the server process.\n\n" ), effective_user) | |||
3140 | "This user must also own the server process.\n\n"),pg_printf(("The files belonging to this database system will be owned " "by user \"%s\".\n" "This user must also own the server process.\n\n" ), effective_user) | |||
3141 | effective_user)pg_printf(("The files belonging to this database system will be owned " "by user \"%s\".\n" "This user must also own the server process.\n\n" ), effective_user); | |||
3142 | ||||
3143 | set_info_version(); | |||
3144 | ||||
3145 | setup_data_file_paths(); | |||
3146 | ||||
3147 | setup_locale_encoding(); | |||
3148 | ||||
3149 | setup_text_search(); | |||
3150 | ||||
3151 | printf("\n")pg_printf("\n"); | |||
3152 | ||||
3153 | if (data_checksums) | |||
3154 | printf(_("Data page checksums are enabled.\n"))pg_printf(("Data page checksums are enabled.\n")); | |||
3155 | else | |||
3156 | printf(_("Data page checksums are disabled.\n"))pg_printf(("Data page checksums are disabled.\n")); | |||
3157 | ||||
3158 | if (pwprompt || pwfilename) | |||
3159 | get_su_pwd(); | |||
3160 | ||||
3161 | printf("\n")pg_printf("\n"); | |||
3162 | ||||
3163 | initialize_data_directory(); | |||
3164 | ||||
3165 | if (do_sync) | |||
3166 | { | |||
3167 | fputs(_("syncing data to disk ... ")("syncing data to disk ... "), stdoutstdout); | |||
3168 | fflush(stdoutstdout); | |||
3169 | fsync_pgdata(pg_data, PG_VERSION_NUM150000); | |||
3170 | check_ok(); | |||
3171 | } | |||
3172 | else | |||
3173 | printf(_("\nSync to disk skipped.\nThe data directory might become corrupt if the operating system crashes.\n"))pg_printf(("\nSync to disk skipped.\nThe data directory might become corrupt if the operating system crashes.\n" )); | |||
3174 | ||||
3175 | if (authwarning) | |||
3176 | { | |||
3177 | printf("\n")pg_printf("\n"); | |||
3178 | pg_log_warning("enabling \"trust\" authentication for local connections")do { if (__builtin_expect((__pg_log_level <= PG_LOG_WARNING ) != 0, 1)) pg_log_generic(PG_LOG_WARNING, "enabling \"trust\" authentication for local connections" ); } while(0); | |||
3179 | fprintfpg_fprintf(stderrstderr, _("You can change this by editing pg_hba.conf or using the option -A, or\n"("You can change this by editing pg_hba.conf or using the option -A, or\n" "--auth-local and --auth-host, the next time you run initdb.\n" ) | |||
3180 | "--auth-local and --auth-host, the next time you run initdb.\n")("You can change this by editing pg_hba.conf or using the option -A, or\n" "--auth-local and --auth-host, the next time you run initdb.\n" )); | |||
3181 | } | |||
3182 | ||||
3183 | if (!noinstructions) | |||
3184 | { | |||
3185 | /* | |||
3186 | * Build up a shell command to tell the user how to start the server | |||
3187 | */ | |||
3188 | start_db_cmd = createPQExpBuffer(); | |||
3189 | ||||
3190 | /* Get directory specification used to start initdb ... */ | |||
3191 | strlcpy(pg_ctl_path, argv[0], sizeof(pg_ctl_path)); | |||
3192 | canonicalize_path(pg_ctl_path); | |||
3193 | get_parent_directory(pg_ctl_path); | |||
3194 | /* ... and tag on pg_ctl instead */ | |||
3195 | join_path_components(pg_ctl_path, pg_ctl_path, "pg_ctl"); | |||
3196 | ||||
3197 | /* Convert the path to use native separators */ | |||
3198 | make_native_path(pg_ctl_path); | |||
3199 | ||||
3200 | /* path to pg_ctl, properly quoted */ | |||
3201 | appendShellString(start_db_cmd, pg_ctl_path); | |||
3202 | ||||
3203 | /* add -D switch, with properly quoted data directory */ | |||
3204 | appendPQExpBufferStr(start_db_cmd, " -D "); | |||
3205 | appendShellString(start_db_cmd, pgdata_native); | |||
3206 | ||||
3207 | /* add suggested -l switch and "start" command */ | |||
3208 | /* translator: This is a placeholder in a shell command. */ | |||
3209 | appendPQExpBuffer(start_db_cmd, " -l %s start", _("logfile")("logfile")); | |||
3210 | ||||
3211 | printf(_("\nSuccess. You can now start the database server using:\n\n"pg_printf(("\nSuccess. You can now start the database server using:\n\n" " %s\n\n"), start_db_cmd->data) | |||
3212 | " %s\n\n"),pg_printf(("\nSuccess. You can now start the database server using:\n\n" " %s\n\n"), start_db_cmd->data) | |||
3213 | start_db_cmd->data)pg_printf(("\nSuccess. You can now start the database server using:\n\n" " %s\n\n"), start_db_cmd->data); | |||
3214 | ||||
3215 | destroyPQExpBuffer(start_db_cmd); | |||
3216 | } | |||
3217 | ||||
3218 | ||||
3219 | success = true1; | |||
3220 | return 0; | |||
3221 | } |