6 * Copyright (c) 2010-2013, PostgreSQL Global Development Group
7 * contrib/pg_upgrade/option.c
10 #include "postgres_fe.h"
12 #include "miscadmin.h"
14 #include "pg_upgrade.h"
16 #include <getopt_long.h>
18 #include <sys/types.h>
25 static void usage(void);
26 static void check_required_directory(char **dirpath, char **configpath,
27 char *envVarName, char *cmdLineOption, char *description);
36 * Parses the command line (argc, argv[]) and loads structures
39 parseCommandLine(int argc, char *argv[])
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 {"old-options", required_argument, NULL, 'o'},
47 {"new-options", required_argument, NULL, 'O'},
48 {"old-port", required_argument, NULL, 'p'},
49 {"new-port", required_argument, NULL, 'P'},
51 {"username", required_argument, NULL, 'U'},
52 {"check", no_argument, NULL, 'c'},
53 {"link", no_argument, NULL, 'k'},
54 {"retain", no_argument, NULL, 'r'},
55 {"jobs", required_argument, NULL, 'j'},
56 {"verbose", no_argument, NULL, 'v'},
59 int option; /* Command line option */
60 int optindex = 0; /* used by getopt_long */
61 int os_user_effective_id;
64 time_t run_time = time(NULL);
66 user_opts.transfer_mode = TRANSFER_MODE_COPY;
68 os_info.progname = get_progname(argv[0]);
70 /* Process libpq env. variables; load values here for usage() output */
71 old_cluster.port = getenv("PGPORTOLD") ? atoi(getenv("PGPORTOLD")) : DEF_PGUPORT;
72 new_cluster.port = getenv("PGPORTNEW") ? atoi(getenv("PGPORTNEW")) : DEF_PGUPORT;
74 os_user_effective_id = get_user_info(&os_info.user);
75 /* we override just the database user name; we got the OS id above */
78 pg_free(os_info.user);
79 /* must save value, getenv()'s pointer is not stable */
80 os_info.user = pg_strdup(getenv("PGUSER"));
85 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
90 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
92 puts("pg_upgrade (PostgreSQL) " PG_VERSION);
97 /* Allow help and version to be run as root, so do the test here. */
98 if (os_user_effective_id == 0)
99 pg_fatal("%s: cannot be run as root\n", os_info.progname);
101 if ((log_opts.internal = fopen_priv(INTERNAL_LOG_FILE, "a")) == NULL)
102 pg_fatal("cannot write to log file %s\n", INTERNAL_LOG_FILE);
104 while ((option = getopt_long(argc, argv, "d:D:b:B:cj:ko:O:p:P:rU:v",
105 long_options, &optindex)) != -1)
110 old_cluster.bindir = pg_strdup(optarg);
114 new_cluster.bindir = pg_strdup(optarg);
118 user_opts.check = true;
122 old_cluster.pgdata = pg_strdup(optarg);
123 old_cluster.pgconfig = pg_strdup(optarg);
127 new_cluster.pgdata = pg_strdup(optarg);
128 new_cluster.pgconfig = pg_strdup(optarg);
132 user_opts.jobs = atoi(optarg);
136 user_opts.transfer_mode = TRANSFER_MODE_LINK;
140 old_cluster.pgopts = pg_strdup(optarg);
144 new_cluster.pgopts = pg_strdup(optarg);
148 * Someday, the port number option could be removed and passed
149 * using -o/-O, but that requires postmaster -C to be
150 * supported on all old/new versions.
153 if ((old_cluster.port = atoi(optarg)) <= 0)
155 pg_fatal("invalid old port number\n");
161 if ((new_cluster.port = atoi(optarg)) <= 0)
163 pg_fatal("invalid new port number\n");
169 log_opts.retain = true;
173 pg_free(os_info.user);
174 os_info.user = pg_strdup(optarg);
175 os_info.user_specified = true;
178 * Push the user name into the environment so pre-9.1
179 * pg_ctl/libpq uses it.
181 pg_putenv("PGUSER", os_info.user);
185 pg_log(PG_REPORT, "Running in verbose mode\n");
186 log_opts.verbose = true;
190 pg_fatal("Try \"%s --help\" for more information.\n",
196 /* label start of upgrade in logfiles */
197 for (filename = output_files; *filename != NULL; filename++)
199 if ((fp = fopen_priv(*filename, "a")) == NULL)
200 pg_fatal("cannot write to log file %s\n", *filename);
202 /* Start with newline because we might be appending to a file. */
204 "-----------------------------------------------------------------\n"
205 " pg_upgrade run on %s"
206 "-----------------------------------------------------------------\n\n",
211 /* Get values from env if not already set */
212 check_required_directory(&old_cluster.bindir, NULL, "PGBINOLD", "-b",
213 "old cluster binaries reside");
214 check_required_directory(&new_cluster.bindir, NULL, "PGBINNEW", "-B",
215 "new cluster binaries reside");
216 check_required_directory(&old_cluster.pgdata, &old_cluster.pgconfig,
217 "PGDATAOLD", "-d", "old cluster data resides");
218 check_required_directory(&new_cluster.pgdata, &new_cluster.pgconfig,
219 "PGDATANEW", "-D", "new cluster data resides");
226 printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\
228 pg_upgrade [OPTION]...\n\
231 -b, --old-bindir=BINDIR old cluster executable directory\n\
232 -B, --new-bindir=BINDIR new cluster executable directory\n\
233 -c, --check check clusters only, don't change any data\n\
234 -d, --old-datadir=DATADIR old cluster data directory\n\
235 -D, --new-datadir=DATADIR new cluster data directory\n\
236 -j, --jobs number of simultaneous processes or threads to use\n\
237 -k, --link link instead of copying files to new cluster\n\
238 -o, --old-options=OPTIONS old cluster options to pass to the server\n\
239 -O, --new-options=OPTIONS new cluster options to pass to the server\n\
240 -p, --old-port=PORT old cluster port number (default %d)\n\
241 -P, --new-port=PORT new cluster port number (default %d)\n\
242 -r, --retain retain SQL and log files after success\n\
243 -U, --username=NAME cluster superuser (default \"%s\")\n\
244 -v, --verbose enable verbose internal logging\n\
245 -V, --version display version information, then exit\n\
246 -?, --help show this help, then exit\n\
248 Before running pg_upgrade you must:\n\
249 create a new database cluster (using the new version of initdb)\n\
250 shutdown the postmaster servicing the old cluster\n\
251 shutdown the postmaster servicing the new cluster\n\
253 When you run pg_upgrade, you must provide the following information:\n\
254 the data directory for the old cluster (-d DATADIR)\n\
255 the data directory for the new cluster (-D DATADIR)\n\
256 the \"bin\" directory for the old version (-b BINDIR)\n\
257 the \"bin\" directory for the new version (-B BINDIR)\n\
260 pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n\
261 or\n"), old_cluster.port, new_cluster.port, os_info.user);
264 $ export PGDATAOLD=oldCluster/data\n\
265 $ export PGDATANEW=newCluster/data\n\
266 $ export PGBINOLD=oldCluster/bin\n\
267 $ export PGBINNEW=newCluster/bin\n\
271 C:\\> set PGDATAOLD=oldCluster/data\n\
272 C:\\> set PGDATANEW=newCluster/data\n\
273 C:\\> set PGBINOLD=oldCluster/bin\n\
274 C:\\> set PGBINNEW=newCluster/bin\n\
275 C:\\> pg_upgrade\n"));
277 printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
282 * check_required_directory()
284 * Checks a directory option.
285 * dirpath - the directory name supplied on the command line
286 * configpath - optional configuration directory
287 * envVarName - the name of an environment variable to get if dirpath is NULL
288 * cmdLineOption - the command line option corresponds to this directory (-o, -O, -n, -N)
289 * description - a description of this directory option
291 * We use the last two arguments to construct a meaningful error message if the
292 * user hasn't provided the required directory name.
295 check_required_directory(char **dirpath, char **configpath,
296 char *envVarName, char *cmdLineOption,
299 if (*dirpath == NULL || strlen(*dirpath) == 0)
303 if ((envVar = getenv(envVarName)) && strlen(envVar))
305 *dirpath = pg_strdup(envVar);
307 *configpath = pg_strdup(envVar);
310 pg_fatal("You must identify the directory where the %s.\n"
311 "Please use the %s command-line option or the %s environment variable.\n",
312 description, cmdLineOption, envVarName);
316 * Trim off any trailing path separators because we construct paths by
317 * appending to this path.
320 if ((*dirpath)[strlen(*dirpath) - 1] == '/')
322 if ((*dirpath)[strlen(*dirpath) - 1] == '/' ||
323 (*dirpath)[strlen(*dirpath) - 1] == '\\')
325 (*dirpath)[strlen(*dirpath) - 1] = 0;
331 * If a configuration-only directory was specified, find the real data dir
332 * by quering the running server. This has limited checking because we
333 * can't check for a running server because we can't find postmaster.pid.
336 adjust_data_dir(ClusterInfo *cluster)
338 char filename[MAXPGPATH];
340 cmd_output[MAX_STRING];
344 /* If there is no postgresql.conf, it can't be a config-only dir */
345 snprintf(filename, sizeof(filename), "%s/postgresql.conf", cluster->pgconfig);
346 if ((fp = fopen(filename, "r")) == NULL)
350 /* If PG_VERSION exists, it can't be a config-only dir */
351 snprintf(filename, sizeof(filename), "%s/PG_VERSION", cluster->pgconfig);
352 if ((fp = fopen(filename, "r")) != NULL)
358 /* Must be a configuration directory, so find the real data directory. */
360 prep_status("Finding the real data directory for the %s cluster",
361 CLUSTER_NAME(cluster));
364 * We don't have a data directory yet, so we can't check the PG version,
365 * so this might fail --- only works for PG 9.2+. If this fails,
366 * pg_upgrade will fail anyway because the data files will not be found.
368 snprintf(cmd, sizeof(cmd), "\"%s/postmaster\" -D \"%s\" -C data_directory",
369 cluster->bindir, cluster->pgconfig);
371 if ((output = popen(cmd, "r")) == NULL ||
372 fgets(cmd_output, sizeof(cmd_output), output) == NULL)
373 pg_fatal("Could not get data directory using %s: %s\n",
374 cmd, getErrorText(errno));
378 /* Remove trailing newline */
379 if (strchr(cmd_output, '\n') != NULL)
380 *strchr(cmd_output, '\n') = '\0';
382 cluster->pgdata = pg_strdup(cmd_output);
391 * Identify the socket directory to use for this cluster. If we're doing
392 * a live check (old cluster only), we need to find out where the postmaster
393 * is listening. Otherwise, we're going to put the socket into the current
397 get_sock_dir(ClusterInfo *cluster, bool live_check)
399 #ifdef HAVE_UNIX_SOCKETS
402 * sockdir and port were added to postmaster.pid in PG 9.1. Pre-9.1 cannot
403 * process pg_ctl -w for sockets in non-default locations.
405 if (GET_MAJOR_VERSION(cluster->major_version) >= 901)
409 /* Use the current directory for the socket */
410 cluster->sockdir = pg_malloc(MAXPGPATH);
411 if (!getcwd(cluster->sockdir, MAXPGPATH))
412 pg_fatal("cannot find current directory\n");
417 * If we are doing a live check, we will use the old cluster's
418 * Unix domain socket directory so we can connect to the live
421 unsigned short orig_port = cluster->port;
422 char filename[MAXPGPATH],
427 snprintf(filename, sizeof(filename), "%s/postmaster.pid",
429 if ((fp = fopen(filename, "r")) == NULL)
430 pg_fatal("Cannot open file %s: %m\n", filename);
433 lineno <= Max(LOCK_FILE_LINE_PORT, LOCK_FILE_LINE_SOCKET_DIR);
436 if (fgets(line, sizeof(line), fp) == NULL)
437 pg_fatal("Cannot read line %d from %s: %m\n", lineno, filename);
439 /* potentially overwrite user-supplied value */
440 if (lineno == LOCK_FILE_LINE_PORT)
441 sscanf(line, "%hu", &old_cluster.port);
442 if (lineno == LOCK_FILE_LINE_SOCKET_DIR)
444 cluster->sockdir = pg_malloc(MAXPGPATH);
445 /* strip off newline */
446 sscanf(line, "%s\n", cluster->sockdir);
451 /* warn of port number correction */
452 if (orig_port != DEF_PGUPORT && old_cluster.port != orig_port)
453 pg_log(PG_WARNING, "User-supplied old port number %hu corrected to %hu\n",
454 orig_port, cluster->port);
460 * Can't get sockdir and pg_ctl -w can't use a non-default, use
463 cluster->sockdir = NULL;
464 #else /* !HAVE_UNIX_SOCKETS */
465 cluster->sockdir = NULL;