]> granicus.if.org Git - postgresql/blob - contrib/pg_upgrade/option.c
pgindent run for release 9.3
[postgresql] / contrib / pg_upgrade / option.c
1 /*
2  *      opt.c
3  *
4  *      options functions
5  *
6  *      Copyright (c) 2010-2013, 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
29
30 UserOpts        user_opts;
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                 {"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'},
50
51                 {"user", 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'},
57                 {NULL, 0, NULL, 0}
58         };
59         int                     option;                 /* Command line option */
60         int                     optindex = 0;   /* used by getopt_long */
61         int                     os_user_effective_id;
62         FILE       *fp;
63         char      **filename;
64         time_t          run_time = time(NULL);
65
66         user_opts.transfer_mode = TRANSFER_MODE_COPY;
67
68         os_info.progname = get_progname(argv[0]);
69
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;
73
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 */
76         if (getenv("PGUSER"))
77         {
78                 pg_free(os_info.user);
79                 /* must save value, getenv()'s pointer is not stable */
80                 os_info.user = pg_strdup(getenv("PGUSER"));
81         }
82
83         if (argc > 1)
84         {
85                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0 ||
86                         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_log(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_log(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_log(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_log(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
177                                 /*
178                                  * Push the user name into the environment so pre-9.1
179                                  * pg_ctl/libpq uses it.
180                                  */
181                                 pg_putenv("PGUSER", os_info.user);
182                                 break;
183
184                         case 'v':
185                                 pg_log(PG_REPORT, "Running in verbose mode\n");
186                                 log_opts.verbose = true;
187                                 break;
188
189                         default:
190                                 pg_log(PG_FATAL,
191                                            "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_log(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         /* Get values from env if not already set */
213         check_required_directory(&old_cluster.bindir, NULL, "PGBINOLD", "-b",
214                                                          "old cluster binaries reside");
215         check_required_directory(&new_cluster.bindir, NULL, "PGBINNEW", "-B",
216                                                          "new cluster binaries reside");
217         check_required_directory(&old_cluster.pgdata, &old_cluster.pgconfig,
218                                                          "PGDATAOLD", "-d", "old cluster data resides");
219         check_required_directory(&new_cluster.pgdata, &new_cluster.pgconfig,
220                                                          "PGDATANEW", "-D", "new cluster data resides");
221 }
222
223
224 static void
225 usage(void)
226 {
227         printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\
228 \nUsage:\n\
229   pg_upgrade [OPTION]...\n\
230 \n\
231 Options:\n\
232   -b, --old-bindir=OLDBINDIR    old cluster executable directory\n\
233   -B, --new-bindir=NEWBINDIR    new cluster executable directory\n\
234   -c, --check                   check clusters only, don't change any data\n\
235   -d, --old-datadir=OLDDATADIR  old cluster data directory\n\
236   -D, --new-datadir=NEWDATADIR  new cluster data directory\n\
237   -j, --jobs                    number of simultaneous processes or threads to use\n\
238   -k, --link                    link instead of copying files to new cluster\n\
239   -o, --old-options=OPTIONS     old cluster options to pass to the server\n\
240   -O, --new-options=OPTIONS     new cluster options to pass to the server\n\
241   -p, --old-port=OLDPORT        old cluster port number (default %d)\n\
242   -P, --new-port=NEWPORT        new cluster port number (default %d)\n\
243   -r, --retain                  retain SQL and log files after success\n\
244   -u, --user=NAME               cluster superuser (default \"%s\")\n\
245   -v, --verbose                 enable verbose internal logging\n\
246   -V, --version                 display version information, then exit\n\
247   -?, -h, --help                show this help, then exit\n\
248 \n\
249 Before running pg_upgrade you must:\n\
250   create a new database cluster (using the new version of initdb)\n\
251   shutdown the postmaster servicing the old cluster\n\
252   shutdown the postmaster servicing the new cluster\n\
253 \n\
254 When you run pg_upgrade, you must provide the following information:\n\
255   the data directory for the old cluster  (-d OLDDATADIR)\n\
256   the data directory for the new cluster  (-D NEWDATADIR)\n\
257   the \"bin\" directory for the old version (-b OLDBINDIR)\n\
258   the \"bin\" directory for the new version (-B NEWBINDIR)\n\
259 \n\
260 For example:\n\
261   pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n\
262 or\n"), old_cluster.port, new_cluster.port, os_info.user);
263 #ifndef WIN32
264         printf(_("\
265   $ export PGDATAOLD=oldCluster/data\n\
266   $ export PGDATANEW=newCluster/data\n\
267   $ export PGBINOLD=oldCluster/bin\n\
268   $ export PGBINNEW=newCluster/bin\n\
269   $ pg_upgrade\n"));
270 #else
271         printf(_("\
272   C:\\> set PGDATAOLD=oldCluster/data\n\
273   C:\\> set PGDATANEW=newCluster/data\n\
274   C:\\> set PGBINOLD=oldCluster/bin\n\
275   C:\\> set PGBINNEW=newCluster/bin\n\
276   C:\\> pg_upgrade\n"));
277 #endif
278         printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
279 }
280
281
282 /*
283  * check_required_directory()
284  *
285  * Checks a directory option.
286  *      dirpath           - the directory name supplied on the command line
287  *      configpath        - optional configuration directory
288  *      envVarName        - the name of an environment variable to get if dirpath is NULL
289  *      cmdLineOption - the command line option corresponds to this directory (-o, -O, -n, -N)
290  *      description   - a description of this directory option
291  *
292  * We use the last two arguments to construct a meaningful error message if the
293  * user hasn't provided the required directory name.
294  */
295 static void
296 check_required_directory(char **dirpath, char **configpath,
297                                                  char *envVarName, char *cmdLineOption,
298                                                  char *description)
299 {
300         if (*dirpath == NULL || strlen(*dirpath) == 0)
301         {
302                 const char *envVar;
303
304                 if ((envVar = getenv(envVarName)) && strlen(envVar))
305                 {
306                         *dirpath = pg_strdup(envVar);
307                         if (configpath)
308                                 *configpath = pg_strdup(envVar);
309                 }
310                 else
311                         pg_log(PG_FATAL, "You must identify the directory where the %s.\n"
312                                    "Please use the %s command-line option or the %s environment variable.\n",
313                                    description, cmdLineOption, envVarName);
314         }
315
316         /*
317          * Trim off any trailing path separators because we construct paths by
318          * appending to this path.
319          */
320 #ifndef WIN32
321         if ((*dirpath)[strlen(*dirpath) - 1] == '/')
322 #else
323         if ((*dirpath)[strlen(*dirpath) - 1] == '/' ||
324                 (*dirpath)[strlen(*dirpath) - 1] == '\\')
325 #endif
326                 (*dirpath)[strlen(*dirpath) - 1] = 0;
327 }
328
329 /*
330  * adjust_data_dir
331  *
332  * If a configuration-only directory was specified, find the real data dir
333  * by quering the running server.  This has limited checking because we
334  * can't check for a running server because we can't find postmaster.pid.
335  */
336 void
337 adjust_data_dir(ClusterInfo *cluster)
338 {
339         char            filename[MAXPGPATH];
340         char            cmd[MAXPGPATH],
341                                 cmd_output[MAX_STRING];
342         FILE       *fp,
343                            *output;
344
345         /* If there is no postgresql.conf, it can't be a config-only dir */
346         snprintf(filename, sizeof(filename), "%s/postgresql.conf", cluster->pgconfig);
347         if ((fp = fopen(filename, "r")) == NULL)
348                 return;
349         fclose(fp);
350
351         /* If PG_VERSION exists, it can't be a config-only dir */
352         snprintf(filename, sizeof(filename), "%s/PG_VERSION", cluster->pgconfig);
353         if ((fp = fopen(filename, "r")) != NULL)
354         {
355                 fclose(fp);
356                 return;
357         }
358
359         /* Must be a configuration directory, so find the real data directory. */
360
361         prep_status("Finding the real data directory for the %s cluster",
362                                 CLUSTER_NAME(cluster));
363
364         /*
365          * We don't have a data directory yet, so we can't check the PG version,
366          * so this might fail --- only works for PG 9.2+.       If this fails,
367          * pg_upgrade will fail anyway because the data files will not be found.
368          */
369         snprintf(cmd, sizeof(cmd), "\"%s/postmaster\" -D \"%s\" -C data_directory",
370                          cluster->bindir, cluster->pgconfig);
371
372         if ((output = popen(cmd, "r")) == NULL ||
373                 fgets(cmd_output, sizeof(cmd_output), output) == NULL)
374                 pg_log(PG_FATAL, "Could not get data directory using %s: %s\n",
375                            cmd, getErrorText(errno));
376
377         pclose(output);
378
379         /* Remove trailing newline */
380         if (strchr(cmd_output, '\n') != NULL)
381                 *strchr(cmd_output, '\n') = '\0';
382
383         cluster->pgdata = pg_strdup(cmd_output);
384
385         check_ok();
386 }
387
388
389 /*
390  * get_sock_dir
391  *
392  * Identify the socket directory to use for this cluster.  If we're doing
393  * a live check (old cluster only), we need to find out where the postmaster
394  * is listening.  Otherwise, we're going to put the socket into the current
395  * directory.
396  */
397 void
398 get_sock_dir(ClusterInfo *cluster, bool live_check)
399 {
400 #ifdef HAVE_UNIX_SOCKETS
401
402         /*
403          * sockdir and port were added to postmaster.pid in PG 9.1. Pre-9.1 cannot
404          * process pg_ctl -w for sockets in non-default locations.
405          */
406         if (GET_MAJOR_VERSION(cluster->major_version) >= 901)
407         {
408                 if (!live_check)
409                 {
410                         /* Use the current directory for the socket */
411                         cluster->sockdir = pg_malloc(MAXPGPATH);
412                         if (!getcwd(cluster->sockdir, MAXPGPATH))
413                                 pg_log(PG_FATAL, "cannot find current directory\n");
414                 }
415                 else
416                 {
417                         /*
418                          * If we are doing a live check, we will use the old cluster's
419                          * Unix domain socket directory so we can connect to the live
420                          * server.
421                          */
422                         unsigned short orig_port = cluster->port;
423                         char            filename[MAXPGPATH],
424                                                 line[MAXPGPATH];
425                         FILE       *fp;
426                         int                     lineno;
427
428                         snprintf(filename, sizeof(filename), "%s/postmaster.pid",
429                                          cluster->pgdata);
430                         if ((fp = fopen(filename, "r")) == NULL)
431                                 pg_log(PG_FATAL, "Cannot open file %s: %m\n", filename);
432
433                         for (lineno = 1;
434                            lineno <= Max(LOCK_FILE_LINE_PORT, LOCK_FILE_LINE_SOCKET_DIR);
435                                  lineno++)
436                         {
437                                 if (fgets(line, sizeof(line), fp) == NULL)
438                                         pg_log(PG_FATAL, "Cannot read line %d from %s: %m\n", lineno, filename);
439
440                                 /* potentially overwrite user-supplied value */
441                                 if (lineno == LOCK_FILE_LINE_PORT)
442                                         sscanf(line, "%hu", &old_cluster.port);
443                                 if (lineno == LOCK_FILE_LINE_SOCKET_DIR)
444                                 {
445                                         cluster->sockdir = pg_malloc(MAXPGPATH);
446                                         /* strip off newline */
447                                         sscanf(line, "%s\n", cluster->sockdir);
448                                 }
449                         }
450                         fclose(fp);
451
452                         /* warn of port number correction */
453                         if (orig_port != DEF_PGUPORT && old_cluster.port != orig_port)
454                                 pg_log(PG_WARNING, "User-supplied old port number %hu corrected to %hu\n",
455                                            orig_port, cluster->port);
456                 }
457         }
458         else
459
460                 /*
461                  * Can't get sockdir and pg_ctl -w can't use a non-default, use
462                  * default
463                  */
464                 cluster->sockdir = NULL;
465 #else                                                   /* !HAVE_UNIX_SOCKETS */
466         cluster->sockdir = NULL;
467 #endif
468 }