]> granicus.if.org Git - postgresql/blob - contrib/pg_upgrade/option.c
Remove cvs keywords from all files.
[postgresql] / contrib / pg_upgrade / option.c
1 /*
2  *      opt.c
3  *
4  *      options functions
5  *
6  *      Copyright (c) 2010, 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(migratorContext *ctx);
20 static void validateDirectoryOption(migratorContext *ctx, char **dirpath,
21                                    char *envVarName, char *cmdLineOption, char *description);
22 static void get_pkglibdirs(migratorContext *ctx);
23 static char *get_pkglibdir(migratorContext *ctx, const char *bindir);
24
25
26 /*
27  * parseCommandLine()
28  *
29  *      Parses the command line (argc, argv[]) into the given migratorContext object
30  *      and initializes the rest of the object.
31  */
32 void
33 parseCommandLine(migratorContext *ctx, 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                     user_id;
55
56         if (getenv("PGUSER"))
57         {
58                 pg_free(ctx->user);
59                 ctx->user = pg_strdup(ctx, getenv("PGUSER"));
60         }
61
62         ctx->progname = get_progname(argv[0]);
63         ctx->old.port = getenv("PGPORT") ? atoi(getenv("PGPORT")) : DEF_PGPORT;
64         ctx->new.port = getenv("PGPORT") ? atoi(getenv("PGPORT")) : DEF_PGPORT;
65         /* must save value, getenv()'s pointer is not stable */
66
67         ctx->transfer_mode = TRANSFER_MODE_COPY;
68
69         /* user lookup and 'root' test must be split because of usage() */
70         user_id = get_user_info(ctx, &ctx->user);
71
72         if (argc > 1)
73         {
74                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0 ||
75                         strcmp(argv[1], "-?") == 0)
76                 {
77                         usage(ctx);
78                         exit_nicely(ctx, false);
79                 }
80                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
81                 {
82                         pg_log(ctx, PG_REPORT, "pg_upgrade " PG_VERSION "\n");
83                         exit_nicely(ctx, false);
84                 }
85         }
86
87         if (user_id == 0)
88                 pg_log(ctx, PG_FATAL, "%s: cannot be run as root\n", ctx->progname);
89
90         getcwd(ctx->cwd, MAXPGPATH);
91
92         while ((option = getopt_long(argc, argv, "d:D:b:B:cgG:kl:p:P:u:v",
93                                                                  long_options, &optindex)) != -1)
94         {
95                 switch (option)
96                 {
97                         case 'd':
98                                 ctx->old.pgdata = pg_strdup(ctx, optarg);
99                                 break;
100
101                         case 'D':
102                                 ctx->new.pgdata = pg_strdup(ctx, optarg);
103                                 break;
104
105                         case 'b':
106                                 ctx->old.bindir = pg_strdup(ctx, optarg);
107                                 break;
108
109                         case 'B':
110                                 ctx->new.bindir = pg_strdup(ctx, optarg);
111                                 break;
112
113                         case 'c':
114                                 ctx->check = true;
115                                 break;
116
117                         case 'g':
118                                 pg_log(ctx, PG_REPORT, "Running in debug mode\n");
119                                 ctx->debug = true;
120                                 break;
121
122                         case 'G':
123                                 if ((ctx->debug_fd = fopen(optarg, "w")) == NULL)
124                                 {
125                                         pg_log(ctx, PG_FATAL, "cannot open debug file\n");
126                                         exit_nicely(ctx, false);
127                                 }
128                                 break;
129
130                         case 'k':
131                                 ctx->transfer_mode = TRANSFER_MODE_LINK;
132                                 break;
133
134                         case 'l':
135                                 ctx->logfile = pg_strdup(ctx, optarg);
136                                 break;
137
138                         case 'p':
139                                 if ((ctx->old.port = atoi(optarg)) <= 0)
140                                 {
141                                         pg_log(ctx, PG_FATAL, "invalid old port number\n");
142                                         exit_nicely(ctx, false);
143                                 }
144                                 break;
145
146                         case 'P':
147                                 if ((ctx->new.port = atoi(optarg)) <= 0)
148                                 {
149                                         pg_log(ctx, PG_FATAL, "invalid new port number\n");
150                                         exit_nicely(ctx, false);
151                                 }
152                                 break;
153
154                         case 'u':
155                                 pg_free(ctx->user);
156                                 ctx->user = pg_strdup(ctx, optarg);
157                                 break;
158
159                         case 'v':
160                                 pg_log(ctx, PG_REPORT, "Running in verbose mode\n");
161                                 ctx->verbose = true;
162                                 break;
163
164                         default:
165                                 pg_log(ctx, PG_FATAL,
166                                            "Try \"%s --help\" for more information.\n",
167                                            ctx->progname);
168                                 break;
169                 }
170         }
171
172         if (ctx->logfile != NULL)
173         {
174                 /*
175                  * We must use append mode so output generated by child processes via
176                  * ">>" will not be overwritten, and we want the file truncated on
177                  * start.
178                  */
179                 /* truncate */
180                 if ((ctx->log_fd = fopen(ctx->logfile, "w")) == NULL)
181                         pg_log(ctx, PG_FATAL, "Cannot write to log file %s\n", ctx->logfile);
182                 fclose(ctx->log_fd);
183                 if ((ctx->log_fd = fopen(ctx->logfile, "a")) == NULL)
184                         pg_log(ctx, PG_FATAL, "Cannot write to log file %s\n", ctx->logfile);
185         }
186         else
187                 ctx->logfile = strdup(DEVNULL);
188
189         /* if no debug file name, output to the terminal */
190         if (ctx->debug && !ctx->debug_fd)
191         {
192                 ctx->debug_fd = fopen(DEVTTY, "w");
193                 if (!ctx->debug_fd)
194                         pg_log(ctx, PG_FATAL, "Cannot write to terminal\n");
195         }
196
197         /* Get values from env if not already set */
198         validateDirectoryOption(ctx, &ctx->old.pgdata, "OLDDATADIR", "-d",
199                                                         "old cluster data resides");
200         validateDirectoryOption(ctx, &ctx->new.pgdata, "NEWDATADIR", "-D",
201                                                         "new cluster data resides");
202         validateDirectoryOption(ctx, &ctx->old.bindir, "OLDBINDIR", "-b",
203                                                         "old cluster binaries reside");
204         validateDirectoryOption(ctx, &ctx->new.bindir, "NEWBINDIR", "-B",
205                                                         "new cluster binaries reside");
206
207         get_pkglibdirs(ctx);
208 }
209
210
211 static void
212 usage(migratorContext *ctx)
213 {
214         printf(_("\nUsage: pg_upgrade [OPTIONS]...\n\
215 \n\
216 Options:\n\
217  -b, --old-bindir=old_bindir      old cluster executable directory\n\
218  -B, --new-bindir=new_bindir      new cluster executable directory\n\
219  -c, --check                      check clusters only, don't change any data\n\
220  -d, --old-datadir=old_datadir    old cluster data directory\n\
221  -D, --new-datadir=new_datadir    new cluster data directory\n\
222  -g, --debug                      enable debugging\n\
223  -G, --debugfile=debug_filename   output debugging activity to file\n\
224  -k, --link                       link instead of copying files to new cluster\n\
225  -l, --logfile=log_filename       log session activity to file\n\
226  -p, --old-port=old_portnum       old cluster port number (default %d)\n\
227  -P, --new-port=new_portnum       new cluster port number (default %d)\n\
228  -u, --user=username              clusters superuser (default \"%s\")\n\
229  -v, --verbose                    enable verbose output\n\
230  -V, --version                    display version information, then exit\n\
231  -h, --help                       show this help, then exit\n\
232 \n\
233 Before running pg_upgrade you must:\n\
234   create a new database cluster (using the new version of initdb)\n\
235   shutdown the postmaster servicing the old cluster\n\
236   shutdown the postmaster servicing the new cluster\n\
237 \n\
238 When you run pg_upgrade, you must provide the following information:\n\
239   the data directory for the old cluster  (-d OLDDATADIR)\n\
240   the data directory for the new cluster  (-D NEWDATADIR)\n\
241   the 'bin' directory for the old version (-b OLDBINDIR)\n\
242   the 'bin' directory for the new version (-B NEWBINDIR)\n\
243 \n\
244 For example:\n\
245   pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n\
246 or\n"), ctx->old.port, ctx->new.port, ctx->user);
247 #ifndef WIN32
248         printf(_("\
249   $ export OLDDATADIR=oldCluster/data\n\
250   $ export NEWDATADIR=newCluster/data\n\
251   $ export OLDBINDIR=oldCluster/bin\n\
252   $ export NEWBINDIR=newCluster/bin\n\
253   $ pg_upgrade\n"));
254 #else
255         printf(_("\
256   C:\\> set OLDDATADIR=oldCluster/data\n\
257   C:\\> set NEWDATADIR=newCluster/data\n\
258   C:\\> set OLDBINDIR=oldCluster/bin\n\
259   C:\\> set NEWBINDIR=newCluster/bin\n\
260   C:\\> pg_upgrade\n"));
261 #endif
262 }
263
264
265 /*
266  * validateDirectoryOption()
267  *
268  * Validates a directory option.
269  *      dirpath           - the directory name supplied on the command line
270  *      envVarName        - the name of an environment variable to get if dirpath is NULL
271  *      cmdLineOption - the command line option corresponds to this directory (-o, -O, -n, -N)
272  *      description   - a description of this directory option
273  *
274  * We use the last two arguments to construct a meaningful error message if the
275  * user hasn't provided the required directory name.
276  */
277 static void
278 validateDirectoryOption(migratorContext *ctx, char **dirpath,
279                                         char *envVarName, char *cmdLineOption, char *description)
280 {
281         if (*dirpath == NULL || (strlen(*dirpath) == 0))
282         {
283                 const char *envVar;
284
285                 if ((envVar = getenv(envVarName)) && strlen(envVar))
286                         *dirpath = pg_strdup(ctx, envVar);
287                 else
288                 {
289                         pg_log(ctx, PG_FATAL, "You must identify the directory where the %s\n"
290                                    "Please use the %s command-line option or the %s environment variable\n",
291                                    description, cmdLineOption, envVarName);
292                 }
293         }
294
295         /*
296          * Trim off any trailing path separators
297          */
298 #ifndef WIN32
299         if ((*dirpath)[strlen(*dirpath) - 1] == '/')
300 #else
301         if ((*dirpath)[strlen(*dirpath) - 1] == '/' ||
302                 (*dirpath)[strlen(*dirpath) - 1] == '\\')
303 #endif
304                 (*dirpath)[strlen(*dirpath) - 1] = 0;
305 }
306
307
308 static void
309 get_pkglibdirs(migratorContext *ctx)
310 {
311         ctx->old.libpath = get_pkglibdir(ctx, ctx->old.bindir);
312         ctx->new.libpath = get_pkglibdir(ctx, ctx->new.bindir);
313 }
314
315
316 static char *
317 get_pkglibdir(migratorContext *ctx, const char *bindir)
318 {
319         char            cmd[MAXPGPATH];
320         char            bufin[MAX_STRING];
321         FILE       *output;
322         int                     i;
323
324         snprintf(cmd, sizeof(cmd), "\"%s/pg_config\" --pkglibdir", bindir);
325
326         if ((output = popen(cmd, "r")) == NULL)
327                 pg_log(ctx, PG_FATAL, "Could not get pkglibdir data: %s\n",
328                            getErrorText(errno));
329
330         fgets(bufin, sizeof(bufin), output);
331
332         if (output)
333                 pclose(output);
334
335         /* Remove trailing newline */
336         i = strlen(bufin) - 1;
337
338         if (bufin[i] == '\n')
339                 bufin[i] = '\0';
340
341         return pg_strdup(ctx, bufin);
342 }