]> granicus.if.org Git - postgresql/blob - contrib/pg_upgrade/option.c
79b59ee17d25f7a3fd2d77b19d1d8374f681e036
[postgresql] / contrib / pg_upgrade / option.c
1 /*
2  *      opt.c
3  *
4  *      options functions
5  *
6  *      Copyright (c) 2010-2014, PostgreSQL Global Development Group
7  *      contrib/pg_upgrade/option.c
8  */
9
10 #include "postgres_fe.h"
11
12 #include "miscadmin.h"
13
14 #include "pg_upgrade.h"
15
16 #include <getopt_long.h>
17 #include <time.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #ifdef WIN32
21 #include <io.h>
22 #endif
23
24
25 static void usage(void);
26 static void check_required_directory(char **dirpath, char **configpath,
27                                    char *envVarName, char *cmdLineOption, char *description);
28 #define FIX_DEFAULT_READ_ONLY "-c default_transaction_read_only=false"
29
30
31 UserOpts        user_opts;
32
33
34 /*
35  * parseCommandLine()
36  *
37  *      Parses the command line (argc, argv[]) and loads structures
38  */
39 void
40 parseCommandLine(int argc, char *argv[])
41 {
42         static struct option long_options[] = {
43                 {"old-datadir", required_argument, NULL, 'd'},
44                 {"new-datadir", required_argument, NULL, 'D'},
45                 {"old-bindir", required_argument, NULL, 'b'},
46                 {"new-bindir", required_argument, NULL, 'B'},
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                 {"verbose", no_argument, NULL, 'v'},
58                 {NULL, 0, NULL, 0}
59         };
60         int                     option;                 /* Command line option */
61         int                     optindex = 0;   /* used by getopt_long */
62         int                     os_user_effective_id;
63         FILE       *fp;
64         char      **filename;
65         time_t          run_time = time(NULL);
66
67         user_opts.transfer_mode = TRANSFER_MODE_COPY;
68
69         os_info.progname = get_progname(argv[0]);
70
71         /* Process libpq env. variables; load values here for usage() output */
72         old_cluster.port = getenv("PGPORTOLD") ? atoi(getenv("PGPORTOLD")) : DEF_PGUPORT;
73         new_cluster.port = getenv("PGPORTNEW") ? atoi(getenv("PGPORTNEW")) : DEF_PGUPORT;
74
75         os_user_effective_id = get_user_info(&os_info.user);
76         /* we override just the database user name;  we got the OS id above */
77         if (getenv("PGUSER"))
78         {
79                 pg_free(os_info.user);
80                 /* must save value, getenv()'s pointer is not stable */
81                 os_info.user = pg_strdup(getenv("PGUSER"));
82         }
83
84         if (argc > 1)
85         {
86                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
87                 {
88                         usage();
89                         exit(0);
90                 }
91                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
92                 {
93                         puts("pg_upgrade (PostgreSQL) " PG_VERSION);
94                         exit(0);
95                 }
96         }
97
98         /* Allow help and version to be run as root, so do the test here. */
99         if (os_user_effective_id == 0)
100                 pg_fatal("%s: cannot be run as root\n", os_info.progname);
101
102         if ((log_opts.internal = fopen_priv(INTERNAL_LOG_FILE, "a")) == NULL)
103                 pg_fatal("cannot write to log file %s\n", INTERNAL_LOG_FILE);
104
105         while ((option = getopt_long(argc, argv, "d:D:b:B:cj:ko:O:p:P:rU:v",
106                                                                  long_options, &optindex)) != -1)
107         {
108                 switch (option)
109                 {
110                         case 'b':
111                                 old_cluster.bindir = pg_strdup(optarg);
112                                 break;
113
114                         case 'B':
115                                 new_cluster.bindir = pg_strdup(optarg);
116                                 break;
117
118                         case 'c':
119                                 user_opts.check = true;
120                                 break;
121
122                         case 'd':
123                                 old_cluster.pgdata = pg_strdup(optarg);
124                                 old_cluster.pgconfig = pg_strdup(optarg);
125                                 break;
126
127                         case 'D':
128                                 new_cluster.pgdata = pg_strdup(optarg);
129                                 new_cluster.pgconfig = pg_strdup(optarg);
130                                 break;
131
132                         case 'j':
133                                 user_opts.jobs = atoi(optarg);
134                                 break;
135
136                         case 'k':
137                                 user_opts.transfer_mode = TRANSFER_MODE_LINK;
138                                 break;
139
140                         case 'o':
141                                 old_cluster.pgopts = pg_strdup(optarg);
142                                 break;
143
144                         case 'O':
145                                 new_cluster.pgopts = pg_strdup(optarg);
146                                 break;
147
148                                 /*
149                                  * Someday, the port number option could be removed and passed
150                                  * using -o/-O, but that requires postmaster -C to be
151                                  * supported on all old/new versions.
152                                  */
153                         case 'p':
154                                 if ((old_cluster.port = atoi(optarg)) <= 0)
155                                 {
156                                         pg_fatal("invalid old port number\n");
157                                         exit(1);
158                                 }
159                                 break;
160
161                         case 'P':
162                                 if ((new_cluster.port = atoi(optarg)) <= 0)
163                                 {
164                                         pg_fatal("invalid new port number\n");
165                                         exit(1);
166                                 }
167                                 break;
168
169                         case 'r':
170                                 log_opts.retain = true;
171                                 break;
172
173                         case 'U':
174                                 pg_free(os_info.user);
175                                 os_info.user = pg_strdup(optarg);
176                                 os_info.user_specified = true;
177
178                                 /*
179                                  * Push the user name into the environment so pre-9.1
180                                  * pg_ctl/libpq uses it.
181                                  */
182                                 pg_putenv("PGUSER", os_info.user);
183                                 break;
184
185                         case 'v':
186                                 pg_log(PG_REPORT, "Running in verbose mode\n");
187                                 log_opts.verbose = true;
188                                 break;
189
190                         default:
191                                 pg_fatal("Try \"%s --help\" for more information.\n",
192                                            os_info.progname);
193                                 break;
194                 }
195         }
196
197         /* label start of upgrade in logfiles */
198         for (filename = output_files; *filename != NULL; filename++)
199         {
200                 if ((fp = fopen_priv(*filename, "a")) == NULL)
201                         pg_fatal("cannot write to log file %s\n", *filename);
202
203                 /* Start with newline because we might be appending to a file. */
204                 fprintf(fp, "\n"
205                 "-----------------------------------------------------------------\n"
206                                 "  pg_upgrade run on %s"
207                                 "-----------------------------------------------------------------\n\n",
208                                 ctime(&run_time));
209                 fclose(fp);
210         }
211
212         /* Turn off read-only mode;  add prefix to PGOPTIONS? */
213         if (getenv("PGOPTIONS"))
214         {
215                 char *pgoptions = psprintf("%s %s", FIX_DEFAULT_READ_ONLY,
216                                                                         getenv("PGOPTIONS"));
217                 pg_putenv("PGOPTIONS", pgoptions);
218                 pfree(pgoptions);
219         }
220         else
221                 pg_putenv("PGOPTIONS", FIX_DEFAULT_READ_ONLY);
222
223         /* Get values from env if not already set */
224         check_required_directory(&old_cluster.bindir, NULL, "PGBINOLD", "-b",
225                                                          "old cluster binaries reside");
226         check_required_directory(&new_cluster.bindir, NULL, "PGBINNEW", "-B",
227                                                          "new cluster binaries reside");
228         check_required_directory(&old_cluster.pgdata, &old_cluster.pgconfig,
229                                                          "PGDATAOLD", "-d", "old cluster data resides");
230         check_required_directory(&new_cluster.pgdata, &new_cluster.pgconfig,
231                                                          "PGDATANEW", "-D", "new cluster data resides");
232 }
233
234
235 static void
236 usage(void)
237 {
238         printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\
239 \nUsage:\n\
240   pg_upgrade [OPTION]...\n\
241 \n\
242 Options:\n\
243   -b, --old-bindir=BINDIR      old cluster executable directory\n\
244   -B, --new-bindir=BINDIR       new cluster executable directory\n\
245   -c, --check                   check clusters only, don't change any data\n\
246   -d, --old-datadir=DATADIR     old cluster data directory\n\
247   -D, --new-datadir=DATADIR     new cluster data directory\n\
248   -j, --jobs                    number of simultaneous processes or threads to use\n\
249   -k, --link                    link instead of copying files to new cluster\n\
250   -o, --old-options=OPTIONS     old cluster options to pass to the server\n\
251   -O, --new-options=OPTIONS     new cluster options to pass to the server\n\
252   -p, --old-port=PORT           old cluster port number (default %d)\n\
253   -P, --new-port=PORT           new cluster port number (default %d)\n\
254   -r, --retain                  retain SQL and log files after success\n\
255   -U, --username=NAME           cluster superuser (default \"%s\")\n\
256   -v, --verbose                 enable verbose internal logging\n\
257   -V, --version                 display version information, then exit\n\
258   -?, --help                    show this help, then exit\n\
259 \n\
260 Before running pg_upgrade you must:\n\
261   create a new database cluster (using the new version of initdb)\n\
262   shutdown the postmaster servicing the old cluster\n\
263   shutdown the postmaster servicing the new cluster\n\
264 \n\
265 When you run pg_upgrade, you must provide the following information:\n\
266   the data directory for the old cluster  (-d DATADIR)\n\
267   the data directory for the new cluster  (-D DATADIR)\n\
268   the \"bin\" directory for the old version (-b BINDIR)\n\
269   the \"bin\" directory for the new version (-B BINDIR)\n\
270 \n\
271 For example:\n\
272   pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n\
273 or\n"), old_cluster.port, new_cluster.port, os_info.user);
274 #ifndef WIN32
275         printf(_("\
276   $ export PGDATAOLD=oldCluster/data\n\
277   $ export PGDATANEW=newCluster/data\n\
278   $ export PGBINOLD=oldCluster/bin\n\
279   $ export PGBINNEW=newCluster/bin\n\
280   $ pg_upgrade\n"));
281 #else
282         printf(_("\
283   C:\\> set PGDATAOLD=oldCluster/data\n\
284   C:\\> set PGDATANEW=newCluster/data\n\
285   C:\\> set PGBINOLD=oldCluster/bin\n\
286   C:\\> set PGBINNEW=newCluster/bin\n\
287   C:\\> pg_upgrade\n"));
288 #endif
289         printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
290 }
291
292
293 /*
294  * check_required_directory()
295  *
296  * Checks a directory option.
297  *      dirpath           - the directory name supplied on the command line
298  *      configpath        - optional configuration directory
299  *      envVarName        - the name of an environment variable to get if dirpath is NULL
300  *      cmdLineOption - the command line option corresponds to this directory (-o, -O, -n, -N)
301  *      description   - a description of this directory option
302  *
303  * We use the last two arguments to construct a meaningful error message if the
304  * user hasn't provided the required directory name.
305  */
306 static void
307 check_required_directory(char **dirpath, char **configpath,
308                                                  char *envVarName, char *cmdLineOption,
309                                                  char *description)
310 {
311         if (*dirpath == NULL || strlen(*dirpath) == 0)
312         {
313                 const char *envVar;
314
315                 if ((envVar = getenv(envVarName)) && strlen(envVar))
316                 {
317                         *dirpath = pg_strdup(envVar);
318                         if (configpath)
319                                 *configpath = pg_strdup(envVar);
320                 }
321                 else
322                         pg_fatal("You must identify the directory where the %s.\n"
323                                    "Please use the %s command-line option or the %s environment variable.\n",
324                                    description, cmdLineOption, envVarName);
325         }
326
327         /*
328          * Trim off any trailing path separators because we construct paths by
329          * appending to this path.
330          */
331 #ifndef WIN32
332         if ((*dirpath)[strlen(*dirpath) - 1] == '/')
333 #else
334         if ((*dirpath)[strlen(*dirpath) - 1] == '/' ||
335                 (*dirpath)[strlen(*dirpath) - 1] == '\\')
336 #endif
337                 (*dirpath)[strlen(*dirpath) - 1] = 0;
338 }
339
340 /*
341  * adjust_data_dir
342  *
343  * If a configuration-only directory was specified, find the real data dir
344  * by quering the running server.  This has limited checking because we
345  * can't check for a running server because we can't find postmaster.pid.
346  */
347 void
348 adjust_data_dir(ClusterInfo *cluster)
349 {
350         char            filename[MAXPGPATH];
351         char            cmd[MAXPGPATH],
352                                 cmd_output[MAX_STRING];
353         FILE       *fp,
354                            *output;
355
356         /* If there is no postgresql.conf, it can't be a config-only dir */
357         snprintf(filename, sizeof(filename), "%s/postgresql.conf", cluster->pgconfig);
358         if ((fp = fopen(filename, "r")) == NULL)
359                 return;
360         fclose(fp);
361
362         /* If PG_VERSION exists, it can't be a config-only dir */
363         snprintf(filename, sizeof(filename), "%s/PG_VERSION", cluster->pgconfig);
364         if ((fp = fopen(filename, "r")) != NULL)
365         {
366                 fclose(fp);
367                 return;
368         }
369
370         /* Must be a configuration directory, so find the real data directory. */
371
372         prep_status("Finding the real data directory for the %s cluster",
373                                 CLUSTER_NAME(cluster));
374
375         /*
376          * We don't have a data directory yet, so we can't check the PG version,
377          * so this might fail --- only works for PG 9.2+.       If this fails,
378          * pg_upgrade will fail anyway because the data files will not be found.
379          */
380         snprintf(cmd, sizeof(cmd), "\"%s/postmaster\" -D \"%s\" -C data_directory",
381                          cluster->bindir, cluster->pgconfig);
382
383         if ((output = popen(cmd, "r")) == NULL ||
384                 fgets(cmd_output, sizeof(cmd_output), output) == NULL)
385                 pg_fatal("Could not get data directory using %s: %s\n",
386                            cmd, getErrorText(errno));
387
388         pclose(output);
389
390         /* Remove trailing newline */
391         if (strchr(cmd_output, '\n') != NULL)
392                 *strchr(cmd_output, '\n') = '\0';
393
394         cluster->pgdata = pg_strdup(cmd_output);
395
396         check_ok();
397 }
398
399
400 /*
401  * get_sock_dir
402  *
403  * Identify the socket directory to use for this cluster.  If we're doing
404  * a live check (old cluster only), we need to find out where the postmaster
405  * is listening.  Otherwise, we're going to put the socket into the current
406  * directory.
407  */
408 void
409 get_sock_dir(ClusterInfo *cluster, bool live_check)
410 {
411 #ifdef HAVE_UNIX_SOCKETS
412
413         /*
414          * sockdir and port were added to postmaster.pid in PG 9.1. Pre-9.1 cannot
415          * process pg_ctl -w for sockets in non-default locations.
416          */
417         if (GET_MAJOR_VERSION(cluster->major_version) >= 901)
418         {
419                 if (!live_check)
420                 {
421                         /* Use the current directory for the socket */
422                         cluster->sockdir = pg_malloc(MAXPGPATH);
423                         if (!getcwd(cluster->sockdir, MAXPGPATH))
424                                 pg_fatal("cannot find current directory\n");
425                 }
426                 else
427                 {
428                         /*
429                          * If we are doing a live check, we will use the old cluster's
430                          * Unix domain socket directory so we can connect to the live
431                          * server.
432                          */
433                         unsigned short orig_port = cluster->port;
434                         char            filename[MAXPGPATH],
435                                                 line[MAXPGPATH];
436                         FILE       *fp;
437                         int                     lineno;
438
439                         snprintf(filename, sizeof(filename), "%s/postmaster.pid",
440                                          cluster->pgdata);
441                         if ((fp = fopen(filename, "r")) == NULL)
442                                 pg_fatal("Cannot open file %s: %m\n", filename);
443
444                         for (lineno = 1;
445                            lineno <= Max(LOCK_FILE_LINE_PORT, LOCK_FILE_LINE_SOCKET_DIR);
446                                  lineno++)
447                         {
448                                 if (fgets(line, sizeof(line), fp) == NULL)
449                                         pg_fatal("Cannot read line %d from %s: %m\n", lineno, filename);
450
451                                 /* potentially overwrite user-supplied value */
452                                 if (lineno == LOCK_FILE_LINE_PORT)
453                                         sscanf(line, "%hu", &old_cluster.port);
454                                 if (lineno == LOCK_FILE_LINE_SOCKET_DIR)
455                                 {
456                                         cluster->sockdir = pg_malloc(MAXPGPATH);
457                                         /* strip off newline */
458                                         sscanf(line, "%s\n", cluster->sockdir);
459                                 }
460                         }
461                         fclose(fp);
462
463                         /* warn of port number correction */
464                         if (orig_port != DEF_PGUPORT && old_cluster.port != orig_port)
465                                 pg_log(PG_WARNING, "User-supplied old port number %hu corrected to %hu\n",
466                                            orig_port, cluster->port);
467                 }
468         }
469         else
470
471                 /*
472                  * Can't get sockdir and pg_ctl -w can't use a non-default, use
473                  * default
474                  */
475                 cluster->sockdir = NULL;
476 #else                                                   /* !HAVE_UNIX_SOCKETS */
477         cluster->sockdir = NULL;
478 #endif
479 }