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