00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "postgres_fe.h"
00011
00012 #include "miscadmin.h"
00013
00014 #include "pg_upgrade.h"
00015
00016 #include <getopt_long.h>
00017 #include <time.h>
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #ifdef WIN32
00021 #include <io.h>
00022 #endif
00023
00024
00025 static void usage(void);
00026 static void check_required_directory(char **dirpath, char **configpath,
00027 char *envVarName, char *cmdLineOption, char *description);
00028
00029
00030 UserOpts user_opts;
00031
00032
00033
00034
00035
00036
00037
00038 void
00039 parseCommandLine(int argc, char *argv[])
00040 {
00041 static struct option long_options[] = {
00042 {"old-datadir", required_argument, NULL, 'd'},
00043 {"new-datadir", required_argument, NULL, 'D'},
00044 {"old-bindir", required_argument, NULL, 'b'},
00045 {"new-bindir", required_argument, NULL, 'B'},
00046 {"old-options", required_argument, NULL, 'o'},
00047 {"new-options", required_argument, NULL, 'O'},
00048 {"old-port", required_argument, NULL, 'p'},
00049 {"new-port", required_argument, NULL, 'P'},
00050
00051 {"user", required_argument, NULL, 'u'},
00052 {"check", no_argument, NULL, 'c'},
00053 {"link", no_argument, NULL, 'k'},
00054 {"retain", no_argument, NULL, 'r'},
00055 {"jobs", required_argument, NULL, 'j'},
00056 {"verbose", no_argument, NULL, 'v'},
00057 {NULL, 0, NULL, 0}
00058 };
00059 int option;
00060 int optindex = 0;
00061 int os_user_effective_id;
00062 FILE *fp;
00063 char **filename;
00064 time_t run_time = time(NULL);
00065
00066 user_opts.transfer_mode = TRANSFER_MODE_COPY;
00067
00068 os_info.progname = get_progname(argv[0]);
00069
00070
00071 old_cluster.port = getenv("PGPORTOLD") ? atoi(getenv("PGPORTOLD")) : DEF_PGUPORT;
00072 new_cluster.port = getenv("PGPORTNEW") ? atoi(getenv("PGPORTNEW")) : DEF_PGUPORT;
00073
00074 os_user_effective_id = get_user_info(&os_info.user);
00075
00076 if (getenv("PGUSER"))
00077 {
00078 pg_free(os_info.user);
00079
00080 os_info.user = pg_strdup(getenv("PGUSER"));
00081 }
00082
00083 if (argc > 1)
00084 {
00085 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0 ||
00086 strcmp(argv[1], "-?") == 0)
00087 {
00088 usage();
00089 exit(0);
00090 }
00091 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
00092 {
00093 puts("pg_upgrade (PostgreSQL) " PG_VERSION);
00094 exit(0);
00095 }
00096 }
00097
00098
00099 if (os_user_effective_id == 0)
00100 pg_log(PG_FATAL, "%s: cannot be run as root\n", os_info.progname);
00101
00102 if ((log_opts.internal = fopen_priv(INTERNAL_LOG_FILE, "a")) == NULL)
00103 pg_log(PG_FATAL, "cannot write to log file %s\n", INTERNAL_LOG_FILE);
00104
00105 while ((option = getopt_long(argc, argv, "d:D:b:B:cj:ko:O:p:P:ru:v",
00106 long_options, &optindex)) != -1)
00107 {
00108 switch (option)
00109 {
00110 case 'b':
00111 old_cluster.bindir = pg_strdup(optarg);
00112 break;
00113
00114 case 'B':
00115 new_cluster.bindir = pg_strdup(optarg);
00116 break;
00117
00118 case 'c':
00119 user_opts.check = true;
00120 break;
00121
00122 case 'd':
00123 old_cluster.pgdata = pg_strdup(optarg);
00124 old_cluster.pgconfig = pg_strdup(optarg);
00125 break;
00126
00127 case 'D':
00128 new_cluster.pgdata = pg_strdup(optarg);
00129 new_cluster.pgconfig = pg_strdup(optarg);
00130 break;
00131
00132 case 'j':
00133 user_opts.jobs = atoi(optarg);
00134 break;
00135
00136 case 'k':
00137 user_opts.transfer_mode = TRANSFER_MODE_LINK;
00138 break;
00139
00140 case 'o':
00141 old_cluster.pgopts = pg_strdup(optarg);
00142 break;
00143
00144 case 'O':
00145 new_cluster.pgopts = pg_strdup(optarg);
00146 break;
00147
00148
00149
00150
00151
00152
00153 case 'p':
00154 if ((old_cluster.port = atoi(optarg)) <= 0)
00155 {
00156 pg_log(PG_FATAL, "invalid old port number\n");
00157 exit(1);
00158 }
00159 break;
00160
00161 case 'P':
00162 if ((new_cluster.port = atoi(optarg)) <= 0)
00163 {
00164 pg_log(PG_FATAL, "invalid new port number\n");
00165 exit(1);
00166 }
00167 break;
00168
00169 case 'r':
00170 log_opts.retain = true;
00171 break;
00172
00173 case 'u':
00174 pg_free(os_info.user);
00175 os_info.user = pg_strdup(optarg);
00176
00177
00178
00179
00180
00181 pg_putenv("PGUSER", os_info.user);
00182 break;
00183
00184 case 'v':
00185 pg_log(PG_REPORT, "Running in verbose mode\n");
00186 log_opts.verbose = true;
00187 break;
00188
00189 default:
00190 pg_log(PG_FATAL,
00191 "Try \"%s --help\" for more information.\n",
00192 os_info.progname);
00193 break;
00194 }
00195 }
00196
00197
00198 for (filename = output_files; *filename != NULL; filename++)
00199 {
00200 if ((fp = fopen_priv(*filename, "a")) == NULL)
00201 pg_log(PG_FATAL, "cannot write to log file %s\n", *filename);
00202
00203
00204 fprintf(fp, "\n"
00205 "-----------------------------------------------------------------\n"
00206 " pg_upgrade run on %s"
00207 "-----------------------------------------------------------------\n\n",
00208 ctime(&run_time));
00209 fclose(fp);
00210 }
00211
00212
00213 check_required_directory(&old_cluster.bindir, NULL, "PGBINOLD", "-b",
00214 "old cluster binaries reside");
00215 check_required_directory(&new_cluster.bindir, NULL, "PGBINNEW", "-B",
00216 "new cluster binaries reside");
00217 check_required_directory(&old_cluster.pgdata, &old_cluster.pgconfig,
00218 "PGDATAOLD", "-d", "old cluster data resides");
00219 check_required_directory(&new_cluster.pgdata, &new_cluster.pgconfig,
00220 "PGDATANEW", "-D", "new cluster data resides");
00221 }
00222
00223
00224 static void
00225 usage(void)
00226 {
00227 printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\
00228 \nUsage:\n\
00229 pg_upgrade [OPTION]...\n\
00230 \n\
00231 Options:\n\
00232 -b, --old-bindir=OLDBINDIR old cluster executable directory\n\
00233 -B, --new-bindir=NEWBINDIR new cluster executable directory\n\
00234 -c, --check check clusters only, don't change any data\n\
00235 -d, --old-datadir=OLDDATADIR old cluster data directory\n\
00236 -D, --new-datadir=NEWDATADIR new cluster data directory\n\
00237 -j, --jobs number of simultaneous processes or threads to use\n\
00238 -k, --link link instead of copying files to new cluster\n\
00239 -o, --old-options=OPTIONS old cluster options to pass to the server\n\
00240 -O, --new-options=OPTIONS new cluster options to pass to the server\n\
00241 -p, --old-port=OLDPORT old cluster port number (default %d)\n\
00242 -P, --new-port=NEWPORT new cluster port number (default %d)\n\
00243 -r, --retain retain SQL and log files after success\n\
00244 -u, --user=NAME cluster superuser (default \"%s\")\n\
00245 -v, --verbose enable verbose internal logging\n\
00246 -V, --version display version information, then exit\n\
00247 -?, -h, --help show this help, then exit\n\
00248 \n\
00249 Before running pg_upgrade you must:\n\
00250 create a new database cluster (using the new version of initdb)\n\
00251 shutdown the postmaster servicing the old cluster\n\
00252 shutdown the postmaster servicing the new cluster\n\
00253 \n\
00254 When you run pg_upgrade, you must provide the following information:\n\
00255 the data directory for the old cluster (-d OLDDATADIR)\n\
00256 the data directory for the new cluster (-D NEWDATADIR)\n\
00257 the \"bin\" directory for the old version (-b OLDBINDIR)\n\
00258 the \"bin\" directory for the new version (-B NEWBINDIR)\n\
00259 \n\
00260 For example:\n\
00261 pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n\
00262 or\n"), old_cluster.port, new_cluster.port, os_info.user);
00263 #ifndef WIN32
00264 printf(_("\
00265 $ export PGDATAOLD=oldCluster/data\n\
00266 $ export PGDATANEW=newCluster/data\n\
00267 $ export PGBINOLD=oldCluster/bin\n\
00268 $ export PGBINNEW=newCluster/bin\n\
00269 $ pg_upgrade\n"));
00270 #else
00271 printf(_("\
00272 C:\\> set PGDATAOLD=oldCluster/data\n\
00273 C:\\> set PGDATANEW=newCluster/data\n\
00274 C:\\> set PGBINOLD=oldCluster/bin\n\
00275 C:\\> set PGBINNEW=newCluster/bin\n\
00276 C:\\> pg_upgrade\n"));
00277 #endif
00278 printf(_("\nReport bugs to <[email protected]>.\n"));
00279 }
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 static void
00296 check_required_directory(char **dirpath, char **configpath,
00297 char *envVarName, char *cmdLineOption,
00298 char *description)
00299 {
00300 if (*dirpath == NULL || strlen(*dirpath) == 0)
00301 {
00302 const char *envVar;
00303
00304 if ((envVar = getenv(envVarName)) && strlen(envVar))
00305 {
00306 *dirpath = pg_strdup(envVar);
00307 if (configpath)
00308 *configpath = pg_strdup(envVar);
00309 }
00310 else
00311 pg_log(PG_FATAL, "You must identify the directory where the %s.\n"
00312 "Please use the %s command-line option or the %s environment variable.\n",
00313 description, cmdLineOption, envVarName);
00314 }
00315
00316
00317
00318
00319
00320 #ifndef WIN32
00321 if ((*dirpath)[strlen(*dirpath) - 1] == '/')
00322 #else
00323 if ((*dirpath)[strlen(*dirpath) - 1] == '/' ||
00324 (*dirpath)[strlen(*dirpath) - 1] == '\\')
00325 #endif
00326 (*dirpath)[strlen(*dirpath) - 1] = 0;
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336 void
00337 adjust_data_dir(ClusterInfo *cluster)
00338 {
00339 char filename[MAXPGPATH];
00340 char cmd[MAXPGPATH],
00341 cmd_output[MAX_STRING];
00342 FILE *fp,
00343 *output;
00344
00345
00346 snprintf(filename, sizeof(filename), "%s/postgresql.conf", cluster->pgconfig);
00347 if ((fp = fopen(filename, "r")) == NULL)
00348 return;
00349 fclose(fp);
00350
00351
00352 snprintf(filename, sizeof(filename), "%s/PG_VERSION", cluster->pgconfig);
00353 if ((fp = fopen(filename, "r")) != NULL)
00354 {
00355 fclose(fp);
00356 return;
00357 }
00358
00359
00360
00361 prep_status("Finding the real data directory for the %s cluster",
00362 CLUSTER_NAME(cluster));
00363
00364
00365
00366
00367
00368
00369 snprintf(cmd, sizeof(cmd), "\"%s/postmaster\" -D \"%s\" -C data_directory",
00370 cluster->bindir, cluster->pgconfig);
00371
00372 if ((output = popen(cmd, "r")) == NULL ||
00373 fgets(cmd_output, sizeof(cmd_output), output) == NULL)
00374 pg_log(PG_FATAL, "Could not get data directory using %s: %s\n",
00375 cmd, getErrorText(errno));
00376
00377 pclose(output);
00378
00379
00380 if (strchr(cmd_output, '\n') != NULL)
00381 *strchr(cmd_output, '\n') = '\0';
00382
00383 cluster->pgdata = pg_strdup(cmd_output);
00384
00385 check_ok();
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 void
00398 get_sock_dir(ClusterInfo *cluster, bool live_check)
00399 {
00400 #ifdef HAVE_UNIX_SOCKETS
00401
00402
00403
00404
00405
00406 if (GET_MAJOR_VERSION(cluster->major_version) >= 901)
00407 {
00408 if (!live_check)
00409 {
00410
00411 cluster->sockdir = pg_malloc(MAXPGPATH);
00412 if (!getcwd(cluster->sockdir, MAXPGPATH))
00413 pg_log(PG_FATAL, "cannot find current directory\n");
00414 }
00415 else
00416 {
00417
00418
00419
00420
00421 unsigned short orig_port = cluster->port;
00422 char filename[MAXPGPATH], line[MAXPGPATH];
00423 FILE *fp;
00424 int lineno;
00425
00426 snprintf(filename, sizeof(filename), "%s/postmaster.pid",
00427 cluster->pgdata);
00428 if ((fp = fopen(filename, "r")) == NULL)
00429 pg_log(PG_FATAL, "Cannot open file %s: %m\n", filename);
00430
00431 for (lineno = 1;
00432 lineno <= Max(LOCK_FILE_LINE_PORT, LOCK_FILE_LINE_SOCKET_DIR);
00433 lineno++)
00434 {
00435 if (fgets(line, sizeof(line), fp) == NULL)
00436 pg_log(PG_FATAL, "Cannot read line %d from %s: %m\n", lineno, filename);
00437
00438
00439 if (lineno == LOCK_FILE_LINE_PORT)
00440 sscanf(line, "%hu", &old_cluster.port);
00441 if (lineno == LOCK_FILE_LINE_SOCKET_DIR)
00442 {
00443 cluster->sockdir = pg_malloc(MAXPGPATH);
00444
00445 sscanf(line, "%s\n", cluster->sockdir);
00446 }
00447 }
00448 fclose(fp);
00449
00450
00451 if (orig_port != DEF_PGUPORT && old_cluster.port != orig_port)
00452 pg_log(PG_WARNING, "User-supplied old port number %hu corrected to %hu\n",
00453 orig_port, cluster->port);
00454 }
00455 }
00456 else
00457
00458 cluster->sockdir = NULL;
00459
00460 #else
00461 cluster->sockdir = NULL;
00462 #endif
00463 }