PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
option.c
Go to the documentation of this file.
1/*
2 * option.c
3 *
4 * options functions
5 *
6 * Copyright (c) 2010-2025, PostgreSQL Global Development Group
7 * src/bin/pg_upgrade/option.c
8 */
9
10#include "postgres_fe.h"
11
12#ifdef WIN32
13#include <io.h>
14#endif
15
16#include "common/string.h"
18#include "getopt_long.h"
19#include "pg_upgrade.h"
20#include "utils/pidfile.h"
21
22static void usage(void);
23static void check_required_directory(char **dirpath,
24 const char *envVarName, bool useCwd,
25 const char *cmdLineOption, const char *description,
26 bool missingOk);
27#define FIX_DEFAULT_READ_ONLY "-c default_transaction_read_only=false"
28
29
31
32
33/*
34 * parseCommandLine()
35 *
36 * Parses the command line (argc, argv[]) and loads structures
37 */
38void
39parseCommandLine(int argc, char *argv[])
40{
41 static struct option long_options[] = {
42 {"old-datadir", required_argument, NULL, 'd'},
43 {"new-datadir", required_argument, NULL, 'D'},
44 {"old-bindir", required_argument, NULL, 'b'},
45 {"new-bindir", required_argument, NULL, 'B'},
46 {"no-sync", no_argument, NULL, 'N'},
47 {"old-options", required_argument, NULL, 'o'},
48 {"new-options", required_argument, NULL, 'O'},
49 {"old-port", required_argument, NULL, 'p'},
50 {"new-port", required_argument, NULL, 'P'},
51
52 {"username", required_argument, NULL, 'U'},
53 {"check", no_argument, NULL, 'c'},
54 {"link", no_argument, NULL, 'k'},
55 {"retain", no_argument, NULL, 'r'},
56 {"jobs", required_argument, NULL, 'j'},
57 {"socketdir", required_argument, NULL, 's'},
58 {"verbose", no_argument, NULL, 'v'},
59 {"clone", no_argument, NULL, 1},
60 {"copy", no_argument, NULL, 2},
61 {"copy-file-range", no_argument, NULL, 3},
62 {"sync-method", required_argument, NULL, 4},
63 {"no-statistics", no_argument, NULL, 5},
64 {"set-char-signedness", required_argument, NULL, 6},
65 {"swap", no_argument, NULL, 7},
66
67 {NULL, 0, NULL, 0}
68 };
69 int option; /* Command line option */
70 int optindex = 0; /* used by getopt_long */
71 int os_user_effective_id;
72 DataDirSyncMethod unused;
73
74 user_opts.do_sync = true;
78
79 os_info.progname = get_progname(argv[0]);
80
81 /* Process libpq env. variables; load values here for usage() output */
82 old_cluster.port = getenv("PGPORTOLD") ? atoi(getenv("PGPORTOLD")) : DEF_PGUPORT;
83 new_cluster.port = getenv("PGPORTNEW") ? atoi(getenv("PGPORTNEW")) : DEF_PGUPORT;
84
85 os_user_effective_id = get_user_info(&os_info.user);
86 /* we override just the database user name; we got the OS id above */
87 if (getenv("PGUSER"))
88 {
90 /* must save value, getenv()'s pointer is not stable */
91 os_info.user = pg_strdup(getenv("PGUSER"));
92 }
93
94 if (argc > 1)
95 {
96 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
97 {
98 usage();
99 exit(0);
100 }
101 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
102 {
103 puts("pg_upgrade (PostgreSQL) " PG_VERSION);
104 exit(0);
105 }
106 }
107
108 /* Allow help and version to be run as root, so do the test here. */
109 if (os_user_effective_id == 0)
110 pg_fatal("%s: cannot be run as root", os_info.progname);
111
112 while ((option = getopt_long(argc, argv, "b:B:cd:D:j:kNo:O:p:P:rs:U:v",
113 long_options, &optindex)) != -1)
114 {
115 switch (option)
116 {
117 case 'b':
119 break;
120
121 case 'B':
123 break;
124
125 case 'c':
126 user_opts.check = true;
127 break;
128
129 case 'd':
131 break;
132
133 case 'D':
135 break;
136
137 case 'j':
138 user_opts.jobs = atoi(optarg);
139 break;
140
141 case 'k':
143 break;
144
145 case 'N':
146 user_opts.do_sync = false;
147 break;
148
149 case 'o':
150 /* append option? */
151 if (!old_cluster.pgopts)
153 else
154 {
155 char *old_pgopts = old_cluster.pgopts;
156
157 old_cluster.pgopts = psprintf("%s %s", old_pgopts, optarg);
158 free(old_pgopts);
159 }
160 break;
161
162 case 'O':
163 /* append option? */
164 if (!new_cluster.pgopts)
166 else
167 {
168 char *new_pgopts = new_cluster.pgopts;
169
170 new_cluster.pgopts = psprintf("%s %s", new_pgopts, optarg);
171 free(new_pgopts);
172 }
173 break;
174
175 case 'p':
176 if ((old_cluster.port = atoi(optarg)) <= 0)
177 pg_fatal("invalid old port number");
178 break;
179
180 case 'P':
181 if ((new_cluster.port = atoi(optarg)) <= 0)
182 pg_fatal("invalid new port number");
183 break;
184
185 case 'r':
186 log_opts.retain = true;
187 break;
188
189 case 's':
191 break;
192
193 case 'U':
196 os_info.user_specified = true;
197 break;
198
199 case 'v':
200 log_opts.verbose = true;
201 break;
202
203 case 1:
205 break;
206
207 case 2:
209 break;
210
211 case 3:
213 break;
214 case 4:
215 if (!parse_sync_method(optarg, &unused))
216 exit(1);
218 break;
219
220 case 5:
221 user_opts.do_statistics = false;
222 break;
223
224 case 6:
225 if (pg_strcasecmp(optarg, "signed") == 0)
227 else if (pg_strcasecmp(optarg, "unsigned") == 0)
229 else
230 pg_fatal("invalid argument for option %s", "--set-char-signedness");
231 break;
232
233 case 7:
235 break;
236
237 default:
238 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
240 exit(1);
241 }
242 }
243
244 if (optind < argc)
245 pg_fatal("too many command-line arguments (first is \"%s\")", argv[optind]);
246
249
250 if (log_opts.verbose)
251 pg_log(PG_REPORT, "Running in verbose mode");
252
253 log_opts.isatty = isatty(fileno(stdout));
254
255 /* Turn off read-only mode; add prefix to PGOPTIONS? */
256 if (getenv("PGOPTIONS"))
257 {
258 char *pgoptions = psprintf("%s %s", FIX_DEFAULT_READ_ONLY,
259 getenv("PGOPTIONS"));
260
261 setenv("PGOPTIONS", pgoptions, 1);
262 pfree(pgoptions);
263 }
264 else
265 setenv("PGOPTIONS", FIX_DEFAULT_READ_ONLY, 1);
266
267 /* Get values from env if not already set */
268 check_required_directory(&old_cluster.bindir, "PGBINOLD", false,
269 "-b", _("old cluster binaries reside"), false);
270 check_required_directory(&new_cluster.bindir, "PGBINNEW", false,
271 "-B", _("new cluster binaries reside"), true);
272 check_required_directory(&old_cluster.pgdata, "PGDATAOLD", false,
273 "-d", _("old cluster data resides"), false);
274 check_required_directory(&new_cluster.pgdata, "PGDATANEW", false,
275 "-D", _("new cluster data resides"), false);
276 check_required_directory(&user_opts.socketdir, "PGSOCKETDIR", true,
277 "-s", _("sockets will be created"), false);
278
279#ifdef WIN32
280
281 /*
282 * On Windows, initdb --sync-only will fail with a "Permission denied"
283 * error on file pg_upgrade_utility.log if pg_upgrade is run inside the
284 * new cluster directory, so we do a check here.
285 */
286 {
287 char cwd[MAXPGPATH],
288 new_cluster_pgdata[MAXPGPATH];
289
290 strlcpy(new_cluster_pgdata, new_cluster.pgdata, MAXPGPATH);
291 canonicalize_path(new_cluster_pgdata);
292
293 if (!getcwd(cwd, MAXPGPATH))
294 pg_fatal("could not determine current directory");
296 if (path_is_prefix_of_path(new_cluster_pgdata, cwd))
297 pg_fatal("cannot run pg_upgrade from inside the new cluster data directory on Windows");
298 }
299#endif
300}
301
302
303static void
304usage(void)
305{
306 printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\n"));
307 printf(_("Usage:\n"));
308 printf(_(" pg_upgrade [OPTION]...\n\n"));
309 printf(_("Options:\n"));
310 printf(_(" -b, --old-bindir=BINDIR old cluster executable directory\n"));
311 printf(_(" -B, --new-bindir=BINDIR new cluster executable directory (default\n"
312 " same directory as pg_upgrade)\n"));
313 printf(_(" -c, --check check clusters only, don't change any data\n"));
314 printf(_(" -d, --old-datadir=DATADIR old cluster data directory\n"));
315 printf(_(" -D, --new-datadir=DATADIR new cluster data directory\n"));
316 printf(_(" -j, --jobs=NUM number of simultaneous processes or threads to use\n"));
317 printf(_(" -k, --link link instead of copying files to new cluster\n"));
318 printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n"));
319 printf(_(" -o, --old-options=OPTIONS old cluster options to pass to the server\n"));
320 printf(_(" -O, --new-options=OPTIONS new cluster options to pass to the server\n"));
321 printf(_(" -p, --old-port=PORT old cluster port number (default %d)\n"), old_cluster.port);
322 printf(_(" -P, --new-port=PORT new cluster port number (default %d)\n"), new_cluster.port);
323 printf(_(" -r, --retain retain SQL and log files after success\n"));
324 printf(_(" -s, --socketdir=DIR socket directory to use (default current dir.)\n"));
325 printf(_(" -U, --username=NAME cluster superuser (default \"%s\")\n"), os_info.user);
326 printf(_(" -v, --verbose enable verbose internal logging\n"));
327 printf(_(" -V, --version display version information, then exit\n"));
328 printf(_(" --clone clone instead of copying files to new cluster\n"));
329 printf(_(" --copy copy files to new cluster (default)\n"));
330 printf(_(" --copy-file-range copy files to new cluster with copy_file_range\n"));
331 printf(_(" --no-statistics do not import statistics from old cluster\n"));
332 printf(_(" --set-char-signedness=OPTION set new cluster char signedness to \"signed\" or\n"
333 " \"unsigned\"\n"));
334 printf(_(" --swap move data directories to new cluster\n"));
335 printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
336 printf(_(" -?, --help show this help, then exit\n"));
337 printf(_("\n"
338 "Before running pg_upgrade you must:\n"
339 " create a new database cluster (using the new version of initdb)\n"
340 " shutdown the postmaster servicing the old cluster\n"
341 " shutdown the postmaster servicing the new cluster\n"));
342 printf(_("\n"
343 "When you run pg_upgrade, you must provide the following information:\n"
344 " the data directory for the old cluster (-d DATADIR)\n"
345 " the data directory for the new cluster (-D DATADIR)\n"
346 " the \"bin\" directory for the old version (-b BINDIR)\n"
347 " the \"bin\" directory for the new version (-B BINDIR)\n"));
348 printf(_("\n"
349 "For example:\n"
350 " pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n"
351 "or\n"));
352#ifndef WIN32
353 printf(_(" $ export PGDATAOLD=oldCluster/data\n"
354 " $ export PGDATANEW=newCluster/data\n"
355 " $ export PGBINOLD=oldCluster/bin\n"
356 " $ export PGBINNEW=newCluster/bin\n"
357 " $ pg_upgrade\n"));
358#else
359 printf(_(" C:\\> set PGDATAOLD=oldCluster/data\n"
360 " C:\\> set PGDATANEW=newCluster/data\n"
361 " C:\\> set PGBINOLD=oldCluster/bin\n"
362 " C:\\> set PGBINNEW=newCluster/bin\n"
363 " C:\\> pg_upgrade\n"));
364#endif
365 printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
366 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
367}
368
369
370/*
371 * check_required_directory()
372 *
373 * Checks a directory option.
374 * dirpath - the directory name supplied on the command line, or NULL
375 * envVarName - the name of an environment variable to get if dirpath is NULL
376 * useCwd - true if OK to default to CWD
377 * cmdLineOption - the command line option for this directory
378 * description - a description of this directory option
379 * missingOk - true if OK that both dirpath and envVarName are not existing
380 *
381 * We use the last two arguments to construct a meaningful error message if the
382 * user hasn't provided the required directory name.
383 */
384static void
385check_required_directory(char **dirpath, const char *envVarName, bool useCwd,
386 const char *cmdLineOption, const char *description,
387 bool missingOk)
388{
389 if (*dirpath == NULL || strlen(*dirpath) == 0)
390 {
391 const char *envVar;
392
393 if ((envVar = getenv(envVarName)) && strlen(envVar))
394 *dirpath = pg_strdup(envVar);
395 else if (useCwd)
396 {
397 char cwd[MAXPGPATH];
398
399 if (!getcwd(cwd, MAXPGPATH))
400 pg_fatal("could not determine current directory");
401 *dirpath = pg_strdup(cwd);
402 }
403 else if (missingOk)
404 return;
405 else
406 pg_fatal("You must identify the directory where the %s.\n"
407 "Please use the %s command-line option or the %s environment variable.",
408 description, cmdLineOption, envVarName);
409 }
410
411 /*
412 * Clean up the path, in particular trimming any trailing path separators,
413 * because we construct paths by appending to this path.
414 */
415 canonicalize_path(*dirpath);
416}
417
418/*
419 * adjust_data_dir
420 *
421 * If a configuration-only directory was specified, find the real data dir
422 * by querying the running server. This has limited checking because we
423 * can't check for a running server because we can't find postmaster.pid.
424 *
425 * On entry, cluster->pgdata has been set from command line or env variable,
426 * but cluster->pgconfig isn't set. We fill both variables with corrected
427 * values.
428 */
429void
431{
432 char filename[MAXPGPATH];
433 char cmd[MAXPGPATH],
434 cmd_output[MAX_STRING];
435 FILE *fp,
436 *output;
437 int rc;
438
439 /* Initially assume config dir and data dir are the same */
440 cluster->pgconfig = pg_strdup(cluster->pgdata);
441
442 /* If there is no postgresql.conf, it can't be a config-only dir */
443 snprintf(filename, sizeof(filename), "%s/postgresql.conf", cluster->pgconfig);
444 if ((fp = fopen(filename, "r")) == NULL)
445 return;
446 fclose(fp);
447
448 /* If PG_VERSION exists, it can't be a config-only dir */
449 snprintf(filename, sizeof(filename), "%s/PG_VERSION", cluster->pgconfig);
450 if ((fp = fopen(filename, "r")) != NULL)
451 {
452 fclose(fp);
453 return;
454 }
455
456 /* Must be a configuration directory, so find the real data directory. */
457
458 if (cluster == &old_cluster)
459 prep_status("Finding the real data directory for the source cluster");
460 else
461 prep_status("Finding the real data directory for the target cluster");
462
463 /*
464 * We don't have a data directory yet, so we can't check the PG version,
465 * so this might fail --- only works for PG 9.2+. If this fails,
466 * pg_upgrade will fail anyway because the data files will not be found.
467 */
468 snprintf(cmd, sizeof(cmd), "\"%s/postgres\" -D \"%s\" -C data_directory",
469 cluster->bindir, cluster->pgconfig);
470 fflush(NULL);
471
472 if ((output = popen(cmd, "r")) == NULL ||
473 fgets(cmd_output, sizeof(cmd_output), output) == NULL)
474 pg_fatal("could not get data directory using %s: %m", cmd);
475
476 rc = pclose(output);
477 if (rc != 0)
478 pg_fatal("could not get data directory using %s: %s",
479 cmd, wait_result_to_str(rc));
480
481 /* strip trailing newline and carriage return */
482 (void) pg_strip_crlf(cmd_output);
483
484 cluster->pgdata = pg_strdup(cmd_output);
485
486 check_ok();
487}
488
489
490/*
491 * get_sock_dir
492 *
493 * Identify the socket directory to use for this cluster. If we're doing
494 * a live check (old cluster only), we need to find out where the postmaster
495 * is listening. Otherwise, we're going to put the socket into the current
496 * directory.
497 */
498void
500{
501#if !defined(WIN32)
503 cluster->sockdir = user_opts.socketdir;
504 else
505 {
506 /*
507 * If we are doing a live check, we will use the old cluster's Unix
508 * domain socket directory so we can connect to the live server.
509 */
510 unsigned short orig_port = cluster->port;
511 char filename[MAXPGPATH],
512 line[MAXPGPATH];
513 FILE *fp;
514 int lineno;
515
516 snprintf(filename, sizeof(filename), "%s/postmaster.pid",
517 cluster->pgdata);
518 if ((fp = fopen(filename, "r")) == NULL)
519 pg_fatal("could not open file \"%s\": %m", filename);
520
521 for (lineno = 1;
523 lineno++)
524 {
525 if (fgets(line, sizeof(line), fp) == NULL)
526 pg_fatal("could not read line %d from file \"%s\": %m",
527 lineno, filename);
528
529 /* potentially overwrite user-supplied value */
530 if (lineno == LOCK_FILE_LINE_PORT)
531 sscanf(line, "%hu", &old_cluster.port);
532 if (lineno == LOCK_FILE_LINE_SOCKET_DIR)
533 {
534 /* strip trailing newline and carriage return */
535 cluster->sockdir = pg_strdup(line);
536 (void) pg_strip_crlf(cluster->sockdir);
537 }
538 }
539 fclose(fp);
540
541 /* warn of port number correction */
542 if (orig_port != DEF_PGUPORT && old_cluster.port != orig_port)
543 pg_log(PG_WARNING, "user-supplied old port number %hu corrected to %hu",
544 orig_port, cluster->port);
545 }
546#else /* WIN32 */
547 cluster->sockdir = NULL;
548#endif
549}
#define Max(x, y)
Definition: c.h:969
void cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
Definition: cluster.c:107
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
#define _(x)
Definition: elog.c:91
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void pg_free(void *ptr)
Definition: fe_memutils.c:105
DataDirSyncMethod
Definition: file_utils.h:28
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:60
#define no_argument
Definition: getopt_long.h:25
#define required_argument
Definition: getopt_long.h:26
#define free(a)
Definition: header.h:65
FILE * output
static void check_ok(void)
Definition: initdb.c:2117
void pfree(void *pointer)
Definition: mcxt.c:2150
bool parse_sync_method(const char *optarg, DataDirSyncMethod *sync_method)
Definition: option_utils.c:90
#define pg_fatal(...)
#define MAXPGPATH
static char * filename
Definition: pg_dumpall.c:123
PGDLLIMPORT int optind
Definition: getopt.c:51
PGDLLIMPORT char * optarg
Definition: getopt.c:53
OSInfo os_info
Definition: pg_upgrade.c:73
ClusterInfo new_cluster
Definition: pg_upgrade.c:72
ClusterInfo old_cluster
Definition: pg_upgrade.c:71
int get_user_info(char **user_name_p)
Definition: util.c:323
void void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2
@ TRANSFER_MODE_COPY
Definition: pg_upgrade.h:262
@ TRANSFER_MODE_LINK
Definition: pg_upgrade.h:264
@ TRANSFER_MODE_SWAP
Definition: pg_upgrade.h:265
@ TRANSFER_MODE_CLONE
Definition: pg_upgrade.h:261
@ TRANSFER_MODE_COPY_FILE_RANGE
Definition: pg_upgrade.h:263
#define DEF_PGUPORT
Definition: pg_upgrade.h:20
LogOpts log_opts
Definition: util.c:17
@ PG_WARNING
Definition: pg_upgrade.h:277
@ PG_REPORT
Definition: pg_upgrade.h:276
#define MAX_STRING
Definition: pg_upgrade.h:22
void prep_status(const char *fmt,...) pg_attribute_printf(1
#define LOCK_FILE_LINE_PORT
Definition: pidfile.h:40
#define LOCK_FILE_LINE_SOCKET_DIR
Definition: pidfile.h:41
bool path_is_prefix_of_path(const char *path1, const char *path2)
Definition: path.c:637
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
void canonicalize_path(char *path)
Definition: path.c:337
#define snprintf
Definition: port.h:239
const char * get_progname(const char *argv0)
Definition: path.c:652
#define printf(...)
Definition: port.h:245
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
#define FIX_DEFAULT_READ_ONLY
Definition: option.c:27
UserOpts user_opts
Definition: option.c:30
void adjust_data_dir(ClusterInfo *cluster)
Definition: option.c:430
void parseCommandLine(int argc, char *argv[])
Definition: option.c:39
static void usage(void)
Definition: option.c:304
void get_sock_dir(ClusterInfo *cluster)
Definition: option.c:499
static void check_required_directory(char **dirpath, const char *envVarName, bool useCwd, const char *cmdLineOption, const char *description, bool missingOk)
Definition: option.c:385
int pg_strip_crlf(char *str)
Definition: string.c:154
char * pgdata
Definition: pg_upgrade.h:292
unsigned short port
Definition: pg_upgrade.h:299
char * bindir
Definition: pg_upgrade.h:295
char * pgopts
Definition: pg_upgrade.h:296
bool retain
Definition: pg_upgrade.h:315
bool isatty
Definition: pg_upgrade.h:321
bool verbose
Definition: pg_upgrade.h:314
char * user
Definition: pg_upgrade.h:355
const char * progname
Definition: pg_upgrade.h:354
bool user_specified
Definition: pg_upgrade.h:356
char * sync_method
Definition: pg_upgrade.h:336
bool do_statistics
Definition: pg_upgrade.h:337
bool do_sync
Definition: pg_upgrade.h:332
char * socketdir
Definition: pg_upgrade.h:335
bool live_check
Definition: pg_upgrade.h:331
int char_signedness
Definition: pg_upgrade.h:338
transferMode transfer_mode
Definition: pg_upgrade.h:333
bool check
Definition: pg_upgrade.h:330
int jobs
Definition: pg_upgrade.h:334
char * wait_result_to_str(int exitstatus)
Definition: wait_error.c:33
const char * description
#define setenv(x, y, z)
Definition: win32_port.h:545