OSDN Git Service

Change pg_upgrade to use port 50432 by default to avoid unintended
[pg-rex/syncrep.git] / contrib / pg_upgrade / option.c
1 /*
2  *      opt.c
3  *
4  *      options functions
5  *
6  *      Copyright (c) 2010-2011, PostgreSQL Global Development Group
7  *      contrib/pg_upgrade/option.c
8  */
9
10 #include "pg_upgrade.h"
11
12 #include "getopt_long.h"
13
14 #ifdef WIN32
15 #include <io.h>
16 #endif
17
18
19 static void usage(void);
20 static void check_required_directory(char **dirpath,
21                                    char *envVarName, char *cmdLineOption, char *description);
22
23
24 UserOpts        user_opts;
25
26
27 /*
28  * parseCommandLine()
29  *
30  *      Parses the command line (argc, argv[]) and loads structures
31  */
32 void
33 parseCommandLine(int argc, char *argv[])
34 {
35         static struct option long_options[] = {
36                 {"old-datadir", required_argument, NULL, 'd'},
37                 {"new-datadir", required_argument, NULL, 'D'},
38                 {"old-bindir", required_argument, NULL, 'b'},
39                 {"new-bindir", required_argument, NULL, 'B'},
40                 {"old-port", required_argument, NULL, 'p'},
41                 {"new-port", required_argument, NULL, 'P'},
42
43                 {"user", required_argument, NULL, 'u'},
44                 {"check", no_argument, NULL, 'c'},
45                 {"debug", no_argument, NULL, 'g'},
46                 {"debugfile", required_argument, NULL, 'G'},
47                 {"link", no_argument, NULL, 'k'},
48                 {"logfile", required_argument, NULL, 'l'},
49                 {"verbose", no_argument, NULL, 'v'},
50                 {NULL, 0, NULL, 0}
51         };
52         int                     option;                 /* Command line option */
53         int                     optindex = 0;   /* used by getopt_long */
54         int                     os_user_effective_id;
55
56         user_opts.transfer_mode = TRANSFER_MODE_COPY;
57
58         os_info.progname = get_progname(argv[0]);
59
60         /* Process libpq env. variables; load values here for usage() output */
61         old_cluster.port = getenv("PGPORTOLD") ? atoi(getenv("PGPORTOLD")) : DEF_PGUPORT;
62         new_cluster.port = getenv("PGPORTNEW") ? atoi(getenv("PGPORTNEW")) : DEF_PGUPORT;
63
64         os_user_effective_id = get_user_info(&os_info.user);
65         /* we override just the database user name;  we got the OS id above */
66         if (getenv("PGUSER"))
67         {
68                 pg_free(os_info.user);
69                 /* must save value, getenv()'s pointer is not stable */
70                 os_info.user = pg_strdup(getenv("PGUSER"));
71         }
72
73         if (argc > 1)
74         {
75                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0 ||
76                         strcmp(argv[1], "-?") == 0)
77                 {
78                         usage();
79                         exit(0);
80                 }
81                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
82                 {
83                         puts("pg_upgrade (PostgreSQL) " PG_VERSION);
84                         exit(0);
85                 }
86         }
87
88         /* Allow help and version to be run as root, so do the test here. */
89         if (os_user_effective_id == 0)
90                 pg_log(PG_FATAL, "%s: cannot be run as root\n", os_info.progname);
91
92         getcwd(os_info.cwd, MAXPGPATH);
93
94         while ((option = getopt_long(argc, argv, "d:D:b:B:cgG:kl:p:P:u:v",
95                                                                  long_options, &optindex)) != -1)
96         {
97                 switch (option)
98                 {
99                         case 'b':
100                                 old_cluster.bindir = pg_strdup(optarg);
101                                 break;
102
103                         case 'B':
104                                 new_cluster.bindir = pg_strdup(optarg);
105                                 break;
106
107                         case 'c':
108                                 user_opts.check = true;
109                                 break;
110
111                         case 'd':
112                                 old_cluster.pgdata = pg_strdup(optarg);
113                                 break;
114
115                         case 'D':
116                                 new_cluster.pgdata = pg_strdup(optarg);
117                                 break;
118
119                         case 'g':
120                                 pg_log(PG_REPORT, "Running in debug mode\n");
121                                 log_opts.debug = true;
122                                 break;
123
124                         case 'G':
125                                 if ((log_opts.debug_fd = fopen(optarg, "w")) == NULL)
126                                 {
127                                         pg_log(PG_FATAL, "cannot open debug file\n");
128                                         exit(1);
129                                 }
130                                 break;
131
132                         case 'k':
133                                 user_opts.transfer_mode = TRANSFER_MODE_LINK;
134                                 break;
135
136                         case 'l':
137                                 log_opts.filename = pg_strdup(optarg);
138                                 break;
139
140                         case 'p':
141                                 if ((old_cluster.port = atoi(optarg)) <= 0)
142                                 {
143                                         pg_log(PG_FATAL, "invalid old port number\n");
144                                         exit(1);
145                                 }
146                                 break;
147
148                         case 'P':
149                                 if ((new_cluster.port = atoi(optarg)) <= 0)
150                                 {
151                                         pg_log(PG_FATAL, "invalid new port number\n");
152                                         exit(1);
153                                 }
154                                 break;
155
156                         case 'u':
157                                 pg_free(os_info.user);
158                                 os_info.user = pg_strdup(optarg);
159
160                                 /*
161                                  * Push the user name into the environment so pre-9.1
162                                  * pg_ctl/libpq uses it.
163                                  */
164                                 pg_putenv("PGUSER", os_info.user);
165                                 break;
166
167                         case 'v':
168                                 pg_log(PG_REPORT, "Running in verbose mode\n");
169                                 log_opts.verbose = true;
170                                 break;
171
172                         default:
173                                 pg_log(PG_FATAL,
174                                            "Try \"%s --help\" for more information.\n",
175                                            os_info.progname);
176                                 break;
177                 }
178         }
179
180         if (log_opts.filename != NULL)
181         {
182                 /*
183                  * We must use append mode so output generated by child processes via
184                  * ">>" will not be overwritten, and we want the file truncated on
185                  * start.
186                  */
187                 /* truncate */
188                 if ((log_opts.fd = fopen(log_opts.filename, "w")) == NULL)
189                         pg_log(PG_FATAL, "cannot write to log file %s\n", log_opts.filename);
190                 fclose(log_opts.fd);
191                 if ((log_opts.fd = fopen(log_opts.filename, "a")) == NULL)
192                         pg_log(PG_FATAL, "cannot write to log file %s\n", log_opts.filename);
193         }
194         else
195                 log_opts.filename = strdup(DEVNULL);
196
197         /* if no debug file name, output to the terminal */
198         if (log_opts.debug && !log_opts.debug_fd)
199         {
200                 log_opts.debug_fd = fopen(DEVTTY, "w");
201                 if (!log_opts.debug_fd)
202                         pg_log(PG_FATAL, "cannot write to terminal\n");
203         }
204
205         /* Get values from env if not already set */
206         check_required_directory(&old_cluster.bindir, "PGBINOLD", "-b",
207                                                         "old cluster binaries reside");
208         check_required_directory(&new_cluster.bindir, "PGBINNEW", "-B",
209                                                         "new cluster binaries reside");
210         check_required_directory(&old_cluster.pgdata, "PGDATAOLD", "-d",
211                                                         "old cluster data resides");
212         check_required_directory(&new_cluster.pgdata, "PGDATANEW", "-D",
213                                                         "new cluster data resides");
214 }
215
216
217 static void
218 usage(void)
219 {
220         printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\
221 \nUsage:\n\
222   pg_upgrade [OPTIONS]...\n\
223 \n\
224 Options:\n\
225   -b, --old-bindir=OLDBINDIR    old cluster executable directory\n\
226   -B, --new-bindir=NEWBINDIR    new cluster executable directory\n\
227   -c, --check                   check clusters only, don't change any data\n\
228   -d, --old-datadir=OLDDATADIR  old cluster data directory\n\
229   -D, --new-datadir=NEWDATADIR  new cluster data directory\n\
230   -g, --debug                   enable debugging\n\
231   -G, --debugfile=FILENAME      output debugging activity to file\n\
232   -k, --link                    link instead of copying files to new cluster\n\
233   -l, --logfile=FILENAME        log session activity to file\n\
234   -p, --old-port=OLDPORT        old cluster port number (default %d)\n\
235   -P, --new-port=NEWPORT        new cluster port number (default %d)\n\
236   -u, --user=NAME               clusters superuser (default \"%s\")\n\
237   -v, --verbose                 enable verbose output\n\
238   -V, --version                 display version information, then exit\n\
239   -h, --help                    show this help, then exit\n\
240 \n\
241 Before running pg_upgrade you must:\n\
242   create a new database cluster (using the new version of initdb)\n\
243   shutdown the postmaster servicing the old cluster\n\
244   shutdown the postmaster servicing the new cluster\n\
245 \n\
246 When you run pg_upgrade, you must provide the following information:\n\
247   the data directory for the old cluster  (-d OLDDATADIR)\n\
248   the data directory for the new cluster  (-D NEWDATADIR)\n\
249   the \"bin\" directory for the old version (-b OLDBINDIR)\n\
250   the \"bin\" directory for the new version (-B NEWBINDIR)\n\
251 \n\
252 For example:\n\
253   pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n\
254 or\n"), old_cluster.port, new_cluster.port, os_info.user);
255 #ifndef WIN32
256         printf(_("\
257   $ export PGDATAOLD=oldCluster/data\n\
258   $ export PGDATANEW=newCluster/data\n\
259   $ export PGBINOLD=oldCluster/bin\n\
260   $ export PGBINNEW=newCluster/bin\n\
261   $ pg_upgrade\n"));
262 #else
263         printf(_("\
264   C:\\> set PGDATAOLD=oldCluster/data\n\
265   C:\\> set PGDATANEW=newCluster/data\n\
266   C:\\> set PGBINOLD=oldCluster/bin\n\
267   C:\\> set PGBINNEW=newCluster/bin\n\
268   C:\\> pg_upgrade\n"));
269 #endif
270         printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
271 }
272
273
274 /*
275  * check_required_directory()
276  *
277  * Checks a directory option.
278  *      dirpath           - the directory name supplied on the command line
279  *      envVarName        - the name of an environment variable to get if dirpath is NULL
280  *      cmdLineOption - the command line option corresponds to this directory (-o, -O, -n, -N)
281  *      description   - a description of this directory option
282  *
283  * We use the last two arguments to construct a meaningful error message if the
284  * user hasn't provided the required directory name.
285  */
286 static void
287 check_required_directory(char **dirpath, char *envVarName,
288                                                 char *cmdLineOption, char *description)
289 {
290         if (*dirpath == NULL || strlen(*dirpath) == 0)
291         {
292                 const char *envVar;
293
294                 if ((envVar = getenv(envVarName)) && strlen(envVar))
295                         *dirpath = pg_strdup(envVar);
296                 else
297                         pg_log(PG_FATAL, "You must identify the directory where the %s\n"
298                                    "Please use the %s command-line option or the %s environment variable\n",
299                                    description, cmdLineOption, envVarName);
300         }
301
302         /*
303          * Trim off any trailing path separators
304          */
305 #ifndef WIN32
306         if ((*dirpath)[strlen(*dirpath) - 1] == '/')
307 #else
308         if ((*dirpath)[strlen(*dirpath) - 1] == '/' ||
309                 (*dirpath)[strlen(*dirpath) - 1] == '\\')
310 #endif
311                 (*dirpath)[strlen(*dirpath) - 1] = 0;
312 }