mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			315 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			315 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *	opt.c
 | |
|  *
 | |
|  *	options functions
 | |
|  *
 | |
|  *	Copyright (c) 2010-2011, PostgreSQL Global Development Group
 | |
|  *	contrib/pg_upgrade/option.c
 | |
|  */
 | |
| 
 | |
| #include "pg_upgrade.h"
 | |
| 
 | |
| #include "getopt_long.h"
 | |
| 
 | |
| #ifdef WIN32
 | |
| #include <io.h>
 | |
| #endif
 | |
| 
 | |
| 
 | |
| static void usage(void);
 | |
| static void validateDirectoryOption(char **dirpath,
 | |
| 				   char *envVarName, char *cmdLineOption, char *description);
 | |
| 
 | |
| 
 | |
| UserOpts	user_opts;
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * parseCommandLine()
 | |
|  *
 | |
|  *	Parses the command line (argc, argv[]) and loads structures
 | |
|  */
 | |
| void
 | |
| parseCommandLine(int argc, char *argv[])
 | |
| {
 | |
| 	static struct option long_options[] = {
 | |
| 		{"old-datadir", required_argument, NULL, 'd'},
 | |
| 		{"new-datadir", required_argument, NULL, 'D'},
 | |
| 		{"old-bindir", required_argument, NULL, 'b'},
 | |
| 		{"new-bindir", required_argument, NULL, 'B'},
 | |
| 		{"old-port", required_argument, NULL, 'p'},
 | |
| 		{"new-port", required_argument, NULL, 'P'},
 | |
| 
 | |
| 		{"user", required_argument, NULL, 'u'},
 | |
| 		{"check", no_argument, NULL, 'c'},
 | |
| 		{"debug", no_argument, NULL, 'g'},
 | |
| 		{"debugfile", required_argument, NULL, 'G'},
 | |
| 		{"link", no_argument, NULL, 'k'},
 | |
| 		{"logfile", required_argument, NULL, 'l'},
 | |
| 		{"verbose", no_argument, NULL, 'v'},
 | |
| 		{NULL, 0, NULL, 0}
 | |
| 	};
 | |
| 	int			option;			/* Command line option */
 | |
| 	int			optindex = 0;	/* used by getopt_long */
 | |
| 	int			os_user_effective_id;
 | |
| 
 | |
| 	user_opts.transfer_mode = TRANSFER_MODE_COPY;
 | |
| 
 | |
| 	os_info.progname = get_progname(argv[0]);
 | |
| 
 | |
| 	/* Process libpq env. variables; load values here for usage() output */
 | |
| 	old_cluster.port = getenv("PGPORT") ? atoi(getenv("PGPORT")) : DEF_PGPORT;
 | |
| 	new_cluster.port = getenv("PGPORT") ? atoi(getenv("PGPORT")) : DEF_PGPORT;
 | |
| 
 | |
| 	os_user_effective_id = get_user_info(&os_info.user);
 | |
| 	/* we override just the database user name;  we got the OS id above */
 | |
| 	if (getenv("PGUSER"))
 | |
| 	{
 | |
| 		pg_free(os_info.user);
 | |
| 		/* must save value, getenv()'s pointer is not stable */
 | |
| 		os_info.user = pg_strdup(getenv("PGUSER"));
 | |
| 	}
 | |
| 
 | |
| 	if (argc > 1)
 | |
| 	{
 | |
| 		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0 ||
 | |
| 			strcmp(argv[1], "-?") == 0)
 | |
| 		{
 | |
| 			usage();
 | |
| 			exit(0);
 | |
| 		}
 | |
| 		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
 | |
| 		{
 | |
| 			puts("pg_upgrade (PostgreSQL) " PG_VERSION);
 | |
| 			exit(0);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Allow help and version to be run as root, so do the test here. */
 | |
| 	if (os_user_effective_id == 0)
 | |
| 		pg_log(PG_FATAL, "%s: cannot be run as root\n", os_info.progname);
 | |
| 
 | |
| 	getcwd(os_info.cwd, MAXPGPATH);
 | |
| 
 | |
| 	while ((option = getopt_long(argc, argv, "d:D:b:B:cgG:kl:p:P:u:v",
 | |
| 								 long_options, &optindex)) != -1)
 | |
| 	{
 | |
| 		switch (option)
 | |
| 		{
 | |
| 			case 'b':
 | |
| 				old_cluster.bindir = pg_strdup(optarg);
 | |
| 				break;
 | |
| 
 | |
| 			case 'B':
 | |
| 				new_cluster.bindir = pg_strdup(optarg);
 | |
| 				break;
 | |
| 
 | |
| 			case 'c':
 | |
| 				user_opts.check = true;
 | |
| 				break;
 | |
| 
 | |
| 			case 'd':
 | |
| 				old_cluster.pgdata = pg_strdup(optarg);
 | |
| 				break;
 | |
| 
 | |
| 			case 'D':
 | |
| 				new_cluster.pgdata = pg_strdup(optarg);
 | |
| 				break;
 | |
| 
 | |
| 			case 'g':
 | |
| 				pg_log(PG_REPORT, "Running in debug mode\n");
 | |
| 				log_opts.debug = true;
 | |
| 				break;
 | |
| 
 | |
| 			case 'G':
 | |
| 				if ((log_opts.debug_fd = fopen(optarg, "w")) == NULL)
 | |
| 				{
 | |
| 					pg_log(PG_FATAL, "cannot open debug file\n");
 | |
| 					exit(1);
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case 'k':
 | |
| 				user_opts.transfer_mode = TRANSFER_MODE_LINK;
 | |
| 				break;
 | |
| 
 | |
| 			case 'l':
 | |
| 				log_opts.filename = pg_strdup(optarg);
 | |
| 				break;
 | |
| 
 | |
| 			case 'p':
 | |
| 				if ((old_cluster.port = atoi(optarg)) <= 0)
 | |
| 				{
 | |
| 					pg_log(PG_FATAL, "invalid old port number\n");
 | |
| 					exit(1);
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case 'P':
 | |
| 				if ((new_cluster.port = atoi(optarg)) <= 0)
 | |
| 				{
 | |
| 					pg_log(PG_FATAL, "invalid new port number\n");
 | |
| 					exit(1);
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case 'u':
 | |
| 				pg_free(os_info.user);
 | |
| 				os_info.user = pg_strdup(optarg);
 | |
| 
 | |
| 				/*
 | |
| 				 * Push the user name into the environment so pre-9.1
 | |
| 				 * pg_ctl/libpq uses it.
 | |
| 				 */
 | |
| 				pg_putenv("PGUSER", os_info.user);
 | |
| 				break;
 | |
| 
 | |
| 			case 'v':
 | |
| 				pg_log(PG_REPORT, "Running in verbose mode\n");
 | |
| 				log_opts.verbose = true;
 | |
| 				break;
 | |
| 
 | |
| 			default:
 | |
| 				pg_log(PG_FATAL,
 | |
| 					   "Try \"%s --help\" for more information.\n",
 | |
| 					   os_info.progname);
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (log_opts.filename != NULL)
 | |
| 	{
 | |
| 		/*
 | |
| 		 * We must use append mode so output generated by child processes via
 | |
| 		 * ">>" will not be overwritten, and we want the file truncated on
 | |
| 		 * start.
 | |
| 		 */
 | |
| 		/* truncate */
 | |
| 		if ((log_opts.fd = fopen(log_opts.filename, "w")) == NULL)
 | |
| 			pg_log(PG_FATAL, "cannot write to log file %s\n", log_opts.filename);
 | |
| 		fclose(log_opts.fd);
 | |
| 		if ((log_opts.fd = fopen(log_opts.filename, "a")) == NULL)
 | |
| 			pg_log(PG_FATAL, "cannot write to log file %s\n", log_opts.filename);
 | |
| 	}
 | |
| 	else
 | |
| 		log_opts.filename = strdup(DEVNULL);
 | |
| 
 | |
| 	/* if no debug file name, output to the terminal */
 | |
| 	if (log_opts.debug && !log_opts.debug_fd)
 | |
| 	{
 | |
| 		log_opts.debug_fd = fopen(DEVTTY, "w");
 | |
| 		if (!log_opts.debug_fd)
 | |
| 			pg_log(PG_FATAL, "cannot write to terminal\n");
 | |
| 	}
 | |
| 
 | |
| 	/* Get values from env if not already set */
 | |
| 	validateDirectoryOption(&old_cluster.bindir, "OLDBINDIR", "-b",
 | |
| 							"old cluster binaries reside");
 | |
| 	validateDirectoryOption(&new_cluster.bindir, "NEWBINDIR", "-B",
 | |
| 							"new cluster binaries reside");
 | |
| 	validateDirectoryOption(&old_cluster.pgdata, "OLDDATADIR", "-d",
 | |
| 							"old cluster data resides");
 | |
| 	validateDirectoryOption(&new_cluster.pgdata, "NEWDATADIR", "-D",
 | |
| 							"new cluster data resides");
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| usage(void)
 | |
| {
 | |
| 	printf(_("pg_upgrade upgrades a PostgreSQL cluster to a different major version.\n\
 | |
| \nUsage:\n\
 | |
|   pg_upgrade [OPTIONS]...\n\
 | |
| \n\
 | |
| Options:\n\
 | |
|   -b, --old-bindir=OLDBINDIR    old cluster executable directory\n\
 | |
|   -B, --new-bindir=NEWBINDIR    new cluster executable directory\n\
 | |
|   -c, --check                   check clusters only, don't change any data\n\
 | |
|   -d, --old-datadir=OLDDATADIR  old cluster data directory\n\
 | |
|   -D, --new-datadir=NEWDATADIR  new cluster data directory\n\
 | |
|   -g, --debug                   enable debugging\n\
 | |
|   -G, --debugfile=FILENAME      output debugging activity to file\n\
 | |
|   -k, --link                    link instead of copying files to new cluster\n\
 | |
|   -l, --logfile=FILENAME        log session activity to file\n\
 | |
|   -p, --old-port=OLDPORT        old cluster port number (default %d)\n\
 | |
|   -P, --new-port=NEWPORT        new cluster port number (default %d)\n\
 | |
|   -u, --user=NAME               clusters superuser (default \"%s\")\n\
 | |
|   -v, --verbose                 enable verbose output\n\
 | |
|   -V, --version                 display version information, then exit\n\
 | |
|   -h, --help                    show this help, then exit\n\
 | |
| \n\
 | |
| Before running pg_upgrade you must:\n\
 | |
|   create a new database cluster (using the new version of initdb)\n\
 | |
|   shutdown the postmaster servicing the old cluster\n\
 | |
|   shutdown the postmaster servicing the new cluster\n\
 | |
| \n\
 | |
| When you run pg_upgrade, you must provide the following information:\n\
 | |
|   the data directory for the old cluster  (-d OLDDATADIR)\n\
 | |
|   the data directory for the new cluster  (-D NEWDATADIR)\n\
 | |
|   the \"bin\" directory for the old version (-b OLDBINDIR)\n\
 | |
|   the \"bin\" directory for the new version (-B NEWBINDIR)\n\
 | |
| \n\
 | |
| For example:\n\
 | |
|   pg_upgrade -d oldCluster/data -D newCluster/data -b oldCluster/bin -B newCluster/bin\n\
 | |
| or\n"), old_cluster.port, new_cluster.port, os_info.user);
 | |
| #ifndef WIN32
 | |
| 	printf(_("\
 | |
|   $ export OLDDATADIR=oldCluster/data\n\
 | |
|   $ export NEWDATADIR=newCluster/data\n\
 | |
|   $ export OLDBINDIR=oldCluster/bin\n\
 | |
|   $ export NEWBINDIR=newCluster/bin\n\
 | |
|   $ pg_upgrade\n"));
 | |
| #else
 | |
| 	printf(_("\
 | |
|   C:\\> set OLDDATADIR=oldCluster/data\n\
 | |
|   C:\\> set NEWDATADIR=newCluster/data\n\
 | |
|   C:\\> set OLDBINDIR=oldCluster/bin\n\
 | |
|   C:\\> set NEWBINDIR=newCluster/bin\n\
 | |
|   C:\\> pg_upgrade\n"));
 | |
| #endif
 | |
| 	printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * validateDirectoryOption()
 | |
|  *
 | |
|  * Validates a directory option.
 | |
|  *	dirpath		  - the directory name supplied on the command line
 | |
|  *	envVarName	  - the name of an environment variable to get if dirpath is NULL
 | |
|  *	cmdLineOption - the command line option corresponds to this directory (-o, -O, -n, -N)
 | |
|  *	description   - a description of this directory option
 | |
|  *
 | |
|  * We use the last two arguments to construct a meaningful error message if the
 | |
|  * user hasn't provided the required directory name.
 | |
|  */
 | |
| static void
 | |
| validateDirectoryOption(char **dirpath,
 | |
| 					char *envVarName, char *cmdLineOption, char *description)
 | |
| {
 | |
| 	if (*dirpath == NULL || (strlen(*dirpath) == 0))
 | |
| 	{
 | |
| 		const char *envVar;
 | |
| 
 | |
| 		if ((envVar = getenv(envVarName)) && strlen(envVar))
 | |
| 			*dirpath = pg_strdup(envVar);
 | |
| 		else
 | |
| 		{
 | |
| 			pg_log(PG_FATAL, "You must identify the directory where the %s\n"
 | |
| 				   "Please use the %s command-line option or the %s environment variable\n",
 | |
| 				   description, cmdLineOption, envVarName);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Trim off any trailing path separators
 | |
| 	 */
 | |
| #ifndef WIN32
 | |
| 	if ((*dirpath)[strlen(*dirpath) - 1] == '/')
 | |
| #else
 | |
| 	if ((*dirpath)[strlen(*dirpath) - 1] == '/' ||
 | |
| 		(*dirpath)[strlen(*dirpath) - 1] == '\\')
 | |
| #endif
 | |
| 		(*dirpath)[strlen(*dirpath) - 1] = 0;
 | |
| }
 |