Пример #1
0
int
main(int argc, char **argv)
{
	RestoreOptions *opts;
	int			c;
	int			exit_code;
	Archive    *AH;
	char	   *inputFileSpec;
	static int	disable_triggers = 0;
	static int	no_data_for_failed_tables = 0;
	static int	outputNoTablespaces = 0;
	static int	use_setsessauth = 0;

	struct option cmdopts[] = {
		{"clean", 0, NULL, 'c'},
		{"create", 0, NULL, 'C'},
		{"data-only", 0, NULL, 'a'},
		{"dbname", 1, NULL, 'd'},
		{"exit-on-error", 0, NULL, 'e'},
		{"file", 1, NULL, 'f'},
		{"format", 1, NULL, 'F'},
		{"function", 1, NULL, 'P'},
		{"host", 1, NULL, 'h'},
		{"ignore-version", 0, NULL, 'i'},
		{"index", 1, NULL, 'I'},
		{"jobs", 1, NULL, 'j'},
		{"list", 0, NULL, 'l'},
		{"no-privileges", 0, NULL, 'x'},
		{"no-acl", 0, NULL, 'x'},
		{"no-owner", 0, NULL, 'O'},
		{"no-reconnect", 0, NULL, 'R'},
		{"port", 1, NULL, 'p'},
		{"no-password", 0, NULL, 'w'},
		{"password", 0, NULL, 'W'},
		{"schema", 1, NULL, 'n'},
		{"schema-only", 0, NULL, 's'},
		{"superuser", 1, NULL, 'S'},
		{"table", 1, NULL, 't'},
		{"trigger", 1, NULL, 'T'},
		{"use-list", 1, NULL, 'L'},
		{"username", 1, NULL, 'U'},
		{"verbose", 0, NULL, 'v'},
		{"single-transaction", 0, NULL, '1'},

		/*
		 * the following options don't have an equivalent short option letter
		 */
		{"disable-triggers", no_argument, &disable_triggers, 1},
		{"no-data-for-failed-tables", no_argument, &no_data_for_failed_tables, 1},
		{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
		{"role", required_argument, NULL, 2},
		{"use-set-session-authorization", no_argument, &use_setsessauth, 1},

		{NULL, 0, NULL, 0}
	};

	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));

	init_parallel_dump_utils();

	opts = NewRestoreOptions();

	progname = get_progname(argv[0]);

	if (argc > 1)
	{
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
		{
			usage(progname);
			exit(0);
		}
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
		{
			puts("pg_restore (PostgreSQL) " PG_VERSION);
			exit(0);
		}
	}

	while ((c = getopt_long(argc, argv, "acCd:ef:F:h:iI:j:lL:n:Op:P:RsS:t:T:U:vwWxX:1",
							cmdopts, NULL)) != -1)
	{
		switch (c)
		{
			case 'a':			/* Dump data only */
				opts->dataOnly = 1;
				break;
			case 'c':			/* clean (i.e., drop) schema prior to create */
				opts->dropSchema = 1;
				break;
			case 'C':
				opts->createDB = 1;
				break;
			case 'd':
				opts->dbname = strdup(optarg);
				break;
			case 'e':
				opts->exit_on_error = true;
				break;
			case 'f':			/* output file name */
				opts->filename = strdup(optarg);
				break;
			case 'F':
				if (strlen(optarg) != 0)
					opts->formatName = strdup(optarg);
				break;
			case 'h':
				if (strlen(optarg) != 0)
					opts->pghost = strdup(optarg);
				break;
			case 'i':
				/* ignored, deprecated option */
				break;

			case 'j':			/* number of restore jobs */
				opts->number_of_jobs = atoi(optarg);
				break;

			case 'l':			/* Dump the TOC summary */
				opts->tocSummary = 1;
				break;

			case 'L':			/* input TOC summary file name */
				opts->tocFile = strdup(optarg);
				break;

			case 'n':			/* Dump data for this schema only */
				opts->schemaNames = strdup(optarg);
				break;

			case 'O':
				opts->noOwner = 1;
				break;

			case 'p':
				if (strlen(optarg) != 0)
					opts->pgport = strdup(optarg);
				break;
			case 'R':
				/* no-op, still accepted for backwards compatibility */
				break;
			case 'P':			/* Function */
				opts->selTypes = 1;
				opts->selFunction = 1;
				opts->functionNames = strdup(optarg);
				break;
			case 'I':			/* Index */
				opts->selTypes = 1;
				opts->selIndex = 1;
				opts->indexNames = strdup(optarg);
				break;
			case 'T':			/* Trigger */
				opts->selTypes = 1;
				opts->selTrigger = 1;
				opts->triggerNames = strdup(optarg);
				break;
			case 's':			/* dump schema only */
				opts->schemaOnly = 1;
				break;
			case 'S':			/* Superuser username */
				if (strlen(optarg) != 0)
					opts->superuser = strdup(optarg);
				break;
			case 't':			/* Dump data for this table only */
				opts->selTypes = 1;
				opts->selTable = 1;
				opts->tableNames = strdup(optarg);
				break;

			case 'U':
				opts->username = optarg;
				break;

			case 'v':			/* verbose */
				opts->verbose = 1;
				break;

			case 'w':
				opts->promptPassword = TRI_NO;
				break;

			case 'W':
				opts->promptPassword = TRI_YES;
				break;

			case 'x':			/* skip ACL dump */
				opts->aclsSkip = 1;
				break;

			case 'X':
				/* -X is a deprecated alternative to long options */
				if (strcmp(optarg, "disable-triggers") == 0)
					disable_triggers = 1;
				else if (strcmp(optarg, "no-data-for-failed-tables") == 0)
					no_data_for_failed_tables = 1;
				else if (strcmp(optarg, "no-tablespaces") == 0)
					outputNoTablespaces = 1;
				else if (strcmp(optarg, "use-set-session-authorization") == 0)
					use_setsessauth = 1;
				else
				{
					fprintf(stderr,
							_("%s: invalid -X option -- %s\n"),
							progname, optarg);
					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
					exit(1);
				}
				break;

			case '1':			/* Restore data in a single transaction */
				opts->single_txn = true;
				opts->exit_on_error = true;
				break;

			case 0:

				/*
				 * This covers the long options without a short equivalent,
				 * including those equivalent to -X xxx.
				 */
				break;

			case 2:				/* SET ROLE */
				opts->use_role = optarg;
				break;

			default:
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
				exit(1);
		}
	}

	/* Get file name from command line */
	if (optind < argc)
		inputFileSpec = argv[optind++];
	else
		inputFileSpec = NULL;

	/* Complain if any arguments remain */
	if (optind < argc)
	{
		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
				progname, argv[optind]);
		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
				progname);
		exit(1);
	}

	/* Should get at most one of -d and -f, else user is confused */
	if (opts->dbname)
	{
		if (opts->filename)
		{
			fprintf(stderr, _("%s: options -d/--dbname and -f/--file cannot be used together\n"),
					progname);
			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
					progname);
			exit(1);
		}
		opts->useDB = 1;
	}

	/* Can't do single-txn mode with multiple connections */
	if (opts->single_txn && opts->number_of_jobs > 1)
	{
		fprintf(stderr, _("%s: cannot specify both --single-transaction and multiple jobs\n"),
				progname);
		exit(1);
	}

	opts->disable_triggers = disable_triggers;
	opts->noDataForFailedTables = no_data_for_failed_tables;
	opts->noTablespace = outputNoTablespaces;
	opts->use_setsessauth = use_setsessauth;

	if (opts->formatName)
	{
		switch (opts->formatName[0])
		{
			case 'c':
			case 'C':
				opts->format = archCustom;
				break;

			case 'f':
			case 'F':
				opts->format = archFiles;
				break;

			case 't':
			case 'T':
				opts->format = archTar;
				break;

			default:
				write_msg(NULL, "unrecognized archive format \"%s\"; please specify \"c\" or \"t\"\n",
						  opts->formatName);
				exit(1);
		}
	}

	AH = OpenArchive(inputFileSpec, opts->format);

	/* Let the archiver know how noisy to be */
	AH->verbose = opts->verbose;

	/*
	 * Whether to keep submitting sql commands as "pg_restore ... | psql ... "
	 */
	AH->exit_on_error = opts->exit_on_error;

	if (opts->tocFile)
		SortTocFromFile(AH, opts);
	else if (opts->noDataForFailedTables)
	{
		/*
		 * we implement this option by clearing idWanted entries, so must
		 * create a dummy idWanted array if there wasn't a tocFile
		 */
		InitDummyWantedList(AH, opts);
	}

	if (opts->tocSummary)
		PrintTOCSummary(AH, opts);
	else
		RestoreArchive(AH, opts);

	/* done, print a summary of ignored errors */
	if (AH->n_errors)
		fprintf(stderr, _("WARNING: errors ignored on restore: %d\n"),
				AH->n_errors);

	/* AH may be freed in CloseArchive? */
	exit_code = AH->n_errors ? 1 : 0;

	CloseArchive(AH);

	return exit_code;
}
Пример #2
0
int
main(int argc, char **argv)
{
	RestoreOptions *opts;
	int			c;
	int			exit_code;
	int			numWorkers = 1;
	Archive    *AH;
	char	   *inputFileSpec;
	static int	disable_triggers = 0;
	static int	if_exists = 0;
	static int	no_data_for_failed_tables = 0;
	static int	outputNoTablespaces = 0;
	static int	use_setsessauth = 0;
	static int	no_security_labels = 0;

	struct option cmdopts[] = {
		{"clean", 0, NULL, 'c'},
		{"create", 0, NULL, 'C'},
		{"data-only", 0, NULL, 'a'},
		{"dbname", 1, NULL, 'd'},
		{"exit-on-error", 0, NULL, 'e'},
		{"file", 1, NULL, 'f'},
		{"format", 1, NULL, 'F'},
		{"function", 1, NULL, 'P'},
		{"host", 1, NULL, 'h'},
		{"ignore-version", 0, NULL, 'i'},
		{"index", 1, NULL, 'I'},
		{"jobs", 1, NULL, 'j'},
		{"list", 0, NULL, 'l'},
		{"no-privileges", 0, NULL, 'x'},
		{"no-acl", 0, NULL, 'x'},
		{"no-owner", 0, NULL, 'O'},
		{"no-reconnect", 0, NULL, 'R'},
		{"port", 1, NULL, 'p'},
		{"no-password", 0, NULL, 'w'},
		{"password", 0, NULL, 'W'},
		{"schema", 1, NULL, 'n'},
		{"schema-only", 0, NULL, 's'},
		{"superuser", 1, NULL, 'S'},
		{"table", 1, NULL, 't'},
		{"trigger", 1, NULL, 'T'},
		{"use-list", 1, NULL, 'L'},
		{"username", 1, NULL, 'U'},
		{"verbose", 0, NULL, 'v'},
		{"single-transaction", 0, NULL, '1'},

		/*
		 * the following options don't have an equivalent short option letter
		 */
		{"disable-triggers", no_argument, &disable_triggers, 1},
		{"if-exists", no_argument, &if_exists, 1},
		{"no-data-for-failed-tables", no_argument, &no_data_for_failed_tables, 1},
		{"no-tablespaces", no_argument, &outputNoTablespaces, 1},
		{"role", required_argument, NULL, 2},
		{"section", required_argument, NULL, 3},
		{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
		{"no-security-labels", no_argument, &no_security_labels, 1},

		{NULL, 0, NULL, 0}
	};

	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));

	init_parallel_dump_utils();

	opts = NewRestoreOptions();

	progname = get_progname(argv[0]);

	if (argc > 1)
	{
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
		{
			usage(progname);
			exit_nicely(0);
		}
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
		{
			puts("pg_restore (PostgreSQL) " PG_VERSION);
			exit_nicely(0);
		}
	}

	while ((c = getopt_long(argc, argv, "acCd:ef:F:h:iI:j:lL:n:Op:P:RsS:t:T:U:vwWx1",
							cmdopts, NULL)) != -1)
	{
		switch (c)
		{
			case 'a':			/* Dump data only */
				opts->dataOnly = 1;
				break;
			case 'c':			/* clean (i.e., drop) schema prior to create */
				opts->dropSchema = 1;
				break;
			case 'C':
				opts->createDB = 1;
				break;
			case 'd':
				opts->dbname = pg_strdup(optarg);
				break;
			case 'e':
				opts->exit_on_error = true;
				break;
			case 'f':			/* output file name */
				opts->filename = pg_strdup(optarg);
				break;
			case 'F':
				if (strlen(optarg) != 0)
					opts->formatName = pg_strdup(optarg);
				break;
			case 'h':
				if (strlen(optarg) != 0)
					opts->pghost = pg_strdup(optarg);
				break;
			case 'i':
				/* ignored, deprecated option */
				break;

			case 'j':			/* number of restore jobs */
				numWorkers = atoi(optarg);
				break;

			case 'l':			/* Dump the TOC summary */
				opts->tocSummary = 1;
				break;

			case 'L':			/* input TOC summary file name */
				opts->tocFile = pg_strdup(optarg);
				break;

			case 'n':			/* Dump data for this schema only */
				simple_string_list_append(&opts->schemaNames, optarg);
				break;

			case 'O':
				opts->noOwner = 1;
				break;

			case 'p':
				if (strlen(optarg) != 0)
					opts->pgport = pg_strdup(optarg);
				break;
			case 'R':
				/* no-op, still accepted for backwards compatibility */
				break;
			case 'P':			/* Function */
				opts->selTypes = 1;
				opts->selFunction = 1;
				simple_string_list_append(&opts->functionNames, optarg);
				break;
			case 'I':			/* Index */
				opts->selTypes = 1;
				opts->selIndex = 1;
				simple_string_list_append(&opts->indexNames, optarg);
				break;
			case 'T':			/* Trigger */
				opts->selTypes = 1;
				opts->selTrigger = 1;
				simple_string_list_append(&opts->triggerNames, optarg);
				break;
			case 's':			/* dump schema only */
				opts->schemaOnly = 1;
				break;
			case 'S':			/* Superuser username */
				if (strlen(optarg) != 0)
					opts->superuser = pg_strdup(optarg);
				break;
			case 't':			/* Dump data for this table only */
				opts->selTypes = 1;
				opts->selTable = 1;
				simple_string_list_append(&opts->tableNames, optarg);
				break;

			case 'U':
				opts->username = pg_strdup(optarg);
				break;

			case 'v':			/* verbose */
				opts->verbose = 1;
				break;

			case 'w':
				opts->promptPassword = TRI_NO;
				break;

			case 'W':
				opts->promptPassword = TRI_YES;
				break;

			case 'x':			/* skip ACL dump */
				opts->aclsSkip = 1;
				break;

			case '1':			/* Restore data in a single transaction */
				opts->single_txn = true;
				opts->exit_on_error = true;
				break;

			case 0:

				/*
				 * This covers the long options without a short equivalent.
				 */
				break;

			case 2:				/* SET ROLE */
				opts->use_role = pg_strdup(optarg);
				break;

			case 3:				/* section */
				set_dump_section(optarg, &(opts->dumpSections));
				break;

			default:
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
				exit_nicely(1);
		}
	}

	/* Get file name from command line */
	if (optind < argc)
		inputFileSpec = argv[optind++];
	else
		inputFileSpec = NULL;

	/* Complain if any arguments remain */
	if (optind < argc)
	{
		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
				progname, argv[optind]);
		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
				progname);
		exit_nicely(1);
	}

	/* Should get at most one of -d and -f, else user is confused */
	if (opts->dbname)
	{
		if (opts->filename)
		{
			fprintf(stderr, _("%s: options -d/--dbname and -f/--file cannot be used together\n"),
					progname);
			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
					progname);
			exit_nicely(1);
		}
		opts->useDB = 1;
	}

	if (opts->dataOnly && opts->schemaOnly)
	{
		fprintf(stderr, _("%s: options -s/--schema-only and -a/--data-only cannot be used together\n"),
				progname);
		exit_nicely(1);
	}

	if (opts->dataOnly && opts->dropSchema)
	{
		fprintf(stderr, _("%s: options -c/--clean and -a/--data-only cannot be used together\n"),
				progname);
		exit_nicely(1);
	}

	/* Can't do single-txn mode with multiple connections */
	if (opts->single_txn && numWorkers > 1)
	{
		fprintf(stderr, _("%s: cannot specify both --single-transaction and multiple jobs\n"),
				progname);
		exit_nicely(1);
	}

	opts->disable_triggers = disable_triggers;
	opts->noDataForFailedTables = no_data_for_failed_tables;
	opts->noTablespace = outputNoTablespaces;
	opts->use_setsessauth = use_setsessauth;
	opts->no_security_labels = no_security_labels;

	if (if_exists && !opts->dropSchema)
	{
		fprintf(stderr, _("%s: option --if-exists requires -c/--clean option\n"),
				progname);
		exit_nicely(1);
	}
	opts->if_exists = if_exists;

	if (opts->formatName)
	{
		switch (opts->formatName[0])
		{
			case 'c':
			case 'C':
				opts->format = archCustom;
				break;

			case 'd':
			case 'D':
				opts->format = archDirectory;
				break;

			case 't':
			case 'T':
				opts->format = archTar;
				break;

			default:
				write_msg(NULL, "unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"\n",
						  opts->formatName);
				exit_nicely(1);
		}
	}

	AH = OpenArchive(inputFileSpec, opts->format);

	/*
	 * We don't have a connection yet but that doesn't matter. The connection
	 * is initialized to NULL and if we terminate through exit_nicely() while
	 * it's still NULL, the cleanup function will just be a no-op.
	 */
	on_exit_close_archive(AH);

	/* Let the archiver know how noisy to be */
	AH->verbose = opts->verbose;

	/*
	 * Whether to keep submitting sql commands as "pg_restore ... | psql ... "
	 */
	AH->exit_on_error = opts->exit_on_error;

	if (opts->tocFile)
		SortTocFromFile(AH, opts);

	/* See comments in pg_dump.c */
#ifdef WIN32
	if (numWorkers > MAXIMUM_WAIT_OBJECTS)
	{
		fprintf(stderr, _("%s: maximum number of parallel jobs is %d\n"),
				progname, MAXIMUM_WAIT_OBJECTS);
		exit(1);
	}
#endif

	AH->numWorkers = numWorkers;

	if (opts->tocSummary)
		PrintTOCSummary(AH, opts);
	else
	{
		SetArchiveRestoreOptions(AH, opts);
		RestoreArchive(AH);
	}

	/* done, print a summary of ignored errors */
	if (AH->n_errors)
		fprintf(stderr, _("WARNING: errors ignored on restore: %d\n"),
				AH->n_errors);

	/* AH may be freed in CloseArchive? */
	exit_code = AH->n_errors ? 1 : 0;

	CloseArchive(AH);

	return exit_code;
}
Пример #3
0
int
main(int argc, char **argv)
{
	PQExpBuffer valueBuf = NULL;
	PQExpBuffer escapeBuf = createPQExpBuffer();
	RestoreOptions *opts;
	int			c;
	int			exit_code = 0;
	Archive    *AH;
	char	   *inputFileSpec = NULL;
	extern int	optind;
	extern char *optarg;
	static int	use_setsessauth = 0;
	static int	disable_triggers = 0;
	SegmentDatabase SegDB;
	StatusOp   *pOp;
	struct sigaction act;
	pid_t		newpid;

	/* int i; */
	PQExpBuffer	pszCmdLine;
	int			status;
	int			rc;
	char	   *pszErrorMsg;
	ArchiveHandle *pAH;
	int 		postDataSchemaOnly = 0;

#ifdef USE_DDBOOST
	char    *ddp_file_name = NULL;
	char 	*dd_boost_dir = NULL;
#endif

	struct option cmdopts[] = {
		{"clean", 0, NULL, 'c'},
		{"create", 0, NULL, 'C'},
		{"data-only", 0, NULL, 'a'},
		{"dbname", 1, NULL, 'd'},
		{"exit-on-error", 0, NULL, 'e'},
		{"file", 1, NULL, 'f'},
		{"format", 1, NULL, 'F'},
		{"function", 1, NULL, 'P'},
		{"host", 1, NULL, 'h'},
		{"ignore-version", 0, NULL, 'i'},
		{"index", 1, NULL, 'I'},
		{"list", 0, NULL, 'l'},
		{"no-privileges", 0, NULL, 'x'},
		{"no-acl", 0, NULL, 'x'},
		{"no-owner", 0, NULL, 'O'},
		{"no-reconnect", 0, NULL, 'R'},
		{"port", 1, NULL, 'p'},
		{"password", 0, NULL, 'W'},
		{"schema-only", 0, NULL, 's'},
		{"superuser", 1, NULL, 'S'},
		{"table", 1, NULL, 't'},
		{"trigger", 1, NULL, 'T'},
		{"use-list", 1, NULL, 'L'},
		{"username", 1, NULL, 'U'},
		{"verbose", 0, NULL, 'v'},

		/*
		 * the following options don't have an equivalent short option letter,
		 * but are available as '-X long-name'
		 */
		{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
		{"disable-triggers", no_argument, &disable_triggers, 1},

		/*
		 * the following are cdb specific, and don't have an equivalent short
		 * option
		 */
		{"gp-d", required_argument, NULL, 1},
		{"gp-e", no_argument, NULL, 2},
		{"gp-k", required_argument, NULL, 3},
		{"gp-c", required_argument, NULL, 4},
		{"target-dbid", required_argument, NULL, 5},
		{"target-host", required_argument, NULL, 6},
		{"target-port", required_argument, NULL, 7},
		{"post-data-schema-only", no_argument, &postDataSchemaOnly, 1},
		{"dd_boost_file", required_argument, NULL, 8},
		{"dd_boost_enabled", no_argument, NULL, 9},
		{"dd_boost_dir", required_argument, NULL, 10},
		{"dd_boost_buf_size", required_argument, NULL, 11},
		{"gp-f", required_argument, NULL, 12},
		{"prefix", required_argument, NULL, 13},
		{"status", required_argument, NULL, 14},
		{"netbackup-service-host", required_argument, NULL, 15},
		{"netbackup-block-size", required_argument, NULL, 16},
		{"change-schema-file", required_argument, NULL, 17},
		{"schema-level-file", required_argument, NULL, 18},
		{"ddboost-storage-unit",required_argument, NULL, 19},
		{NULL, 0, NULL, 0}
	};

	set_pglocale_pgservice(argv[0], "pg_dump");

	opts = NewRestoreOptions();

	/* set format default */
	opts->formatName = "p";

	progname = get_progname(argv[0]);

	if (argc > 1)
	{
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
		{
			usage(progname);
			exit(0);
		}
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
		{
			puts("pg_restore (Greenplum Database) " PG_VERSION);
			exit(0);
		}
	}

	while ((c = getopt_long(argc, argv, "acCd:ef:F:h:iI:lL:Op:P:RsS:t:T:uU:vwWxX:",
							cmdopts, NULL)) != -1)
	{
		switch (c)
		{
			case 'a':			/* Dump data only */
				opts->dataOnly = 1;
				break;
			case 'c':			/* clean (i.e., drop) schema prior to create */
				opts->dropSchema = 1;
				break;
			case 'C':
				opts->createDB = 1;
				break;
			case 'd':
				opts->dbname = strdup(optarg);
				break;
			case 'e':
				opts->exit_on_error = true;
				break;
			case 'f':			/* output file name */
				opts->filename = strdup(optarg);
				break;
			case 'F':
				if (strlen(optarg) != 0)
					opts->formatName = strdup(optarg);
				break;
			case 'h':
				if (strlen(optarg) != 0)
					opts->pghost = strdup(optarg);
				break;
			case 'i':
				/* obsolete option */
				break;

			case 'l':			/* Dump the TOC summary */
				opts->tocSummary = 1;
				break;

			case 'L':			/* input TOC summary file name */
				opts->tocFile = strdup(optarg);
				break;

			case 'O':
				opts->noOwner = 1;
				break;
			case 'p':
				if (strlen(optarg) != 0)
					opts->pgport = strdup(optarg);
				break;
			case 'R':
				/* no-op, still accepted for backwards compatibility */
				break;
			case 'P':			/* Function */
				opts->selTypes = 1;
				opts->selFunction = 1;
				opts->functionNames = strdup(optarg);
				break;
			case 'I':			/* Index */
				opts->selTypes = 1;
				opts->selIndex = 1;
				opts->indexNames = strdup(optarg);
				break;
			case 'T':			/* Trigger */
				opts->selTypes = 1;
				opts->selTrigger = 1;
				opts->triggerNames = strdup(optarg);
				break;
			case 's':			/* dump schema only */
				opts->schemaOnly = 1;
				break;
			case 'S':			/* Superuser username */
				if (strlen(optarg) != 0)
					opts->superuser = strdup(optarg);
				break;
			case 't':			/* Dump data for this table only */
				opts->selTypes = 1;
				opts->selTable = 1;
				opts->tableNames = strdup(optarg);
				break;

			case 'u':
				opts->promptPassword = TRI_YES;
				opts->username = simple_prompt("User name: ", 100, true);
				break;

			case 'U':
				opts->username = optarg;
				break;

			case 'v':			/* verbose */
				opts->verbose = 1;
				break;

			case 'w':
				opts->promptPassword = TRI_NO;
				break;

			case 'W':
				opts->promptPassword = TRI_YES;
				break;

			case 'x':			/* skip ACL dump */
				opts->aclsSkip = 1;
				break;

			case 'X':
				/* -X is a deprecated alternative to long options */
				if (strcmp(optarg, "use-set-session-authorization") == 0)
					use_setsessauth = 1;
				else if (strcmp(optarg, "disable-triggers") == 0)
					disable_triggers = 1;
				else
				{
					fprintf(stderr,
							_("%s: invalid -X option -- %s\n"),
							progname, optarg);
					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
					exit(1);
				}
				break;

			case 0:
				/* This covers the long options equivalent to -X xxx. */
				break;

			case 1:				/* --gp-d MPP Output Directory */
				g_pszMPPOutputDirectory = strdup(optarg);
				break;

			case 2:				/* --gp-e On Error Stop for psql */
				g_bOnErrorStop = opts->exit_on_error = true;
				break;

			case 3:				/* --gp-k MPP Dump Info Format is
								 * Key_s-dbid_s-role_t-dbid */
				g_gpdumpInfo = strdup(optarg);
				if (!ParseCDBDumpInfo(progname, g_gpdumpInfo, &g_gpdumpKey, &g_role, &g_sourceDBID, &g_MPPPassThroughCredentials))
				{
					exit(1);
				}
				break;
			case 4:				/* gp-c */
				g_compPg = strdup(optarg);
				break;
			case 5:				/* target-dbid */
				g_targetDBID = atoi(strdup(optarg));
				break;
			case 6:				/* target-host */
				g_targetHost = strdup(optarg);
				break;
			case 7:				/* target-port */
				g_targetPort = strdup(optarg);
				break;
#ifdef USE_DDBOOST
			case 9:
				dd_boost_enabled = 1;
				break;
			case 10:
				dd_boost_dir = strdup(optarg);
				break;
			case 11:
				dd_boost_buf_size = strdup(optarg);
				break;
#endif
			case 12:
				table_filter_file = strdup(optarg);
				break;

			case 13:
				dump_prefix = strdup(optarg);
				break;
            /* Hack to pass in the status_file name to cdbbackup.c (gp_restore_launch) */
			case 14:
				break;
			case 15:
				netbackup_service_host = strdup(optarg);
				break;
			case 16:
				netbackup_block_size = strdup(optarg);
				break;
			case 17:
				change_schema_file = strdup(optarg);
				break;
			case 18:
				schema_level_file = strdup(optarg);
				break;
#ifdef USE_DDBOOST
			case 19:
				ddboost_storage_unit = strdup(optarg);
				break;
#endif
			default:
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
				exit(1);
		}
	}

	/* Should get at most one of -d and -f, else user is confused */
	if (opts->dbname)
	{
		if (opts->filename)
		{
			fprintf(stderr, _("%s: cannot specify both -d and -f output\n"),
					progname);
			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
					progname);
			exit(1);
		}
		opts->useDB = 1;
	}

	opts->disable_triggers = disable_triggers;
	opts->use_setsessauth = use_setsessauth;

	if (opts->formatName)
	{

		switch (opts->formatName[0])
		{

			case 'c':
			case 'C':
				opts->format = archCustom;
				break;

			case 'f':
			case 'F':
				opts->format = archFiles;
				break;

			case 't':
			case 'T':
				opts->format = archTar;
				break;

			case 'p':
			case 'P':
				bUsePSQL = true;
				break;

			default:
				mpp_err_msg(logInfo, progname, "unrecognized archive format '%s'; please specify 't' or 'c'\n",
							opts->formatName);
				exit(1);
		}
	}

	if (g_gpdumpInfo == NULL)
	{
		mpp_err_msg(logInfo, progname, "missing required parameter gp-k (backup key)\n");
		exit(1);
	}

#ifdef USE_DDBOOST
	if (dd_boost_enabled)
	{
		/* remote is always false when restoring from primary DDR */
		int err = DD_ERR_NONE;
		err = ddp_init("gp_dump");
		if (err != DD_ERR_NONE)
		{
			mpp_err_msg("ERROR", "ddboost", "ddboost init failed. Err = %d\n", err);
			exit(1);
		}

		if (initDDSystem(&ddp_inst, &ddp_conn, &dd_client_info, &ddboost_storage_unit, false, &DEFAULT_BACKUP_DIRECTORY, false))
               	{
			mpp_err_msg(logInfo, progname, "Initializing DD system failed\n");
			exit(1);
		}

		mpp_err_msg(logInfo, progname, "ddboost is initialized\n");

		ddp_file_name = formDDBoostFileName(g_gpdumpKey, postDataSchemaOnly, dd_boost_dir);
		if (ddp_file_name == NULL)
		{
			mpp_err_msg(logInfo, progname, "Error in opening ddboost file\n");
			exit(1);
		}
	}
#endif

	SegDB.dbid = g_sourceDBID;
	SegDB.role = g_role;
	SegDB.port = opts->pgport ? atoi(opts->pgport) : 5432;
	SegDB.pszHost = opts->pghost ? strdup(opts->pghost) : NULL;
	SegDB.pszDBName = opts->dbname ? strdup(opts->dbname) : NULL;
	SegDB.pszDBUser = opts->username ? strdup(opts->username) : NULL;
	SegDB.pszDBPswd = NULL;

	if (g_MPPPassThroughCredentials != NULL && *g_MPPPassThroughCredentials != '\0')
	{
		unsigned int nBytes;
		char	   *pszDBPswd = Base64ToData(g_MPPPassThroughCredentials, &nBytes);

		if (pszDBPswd == NULL)
		{
			mpp_err_msg(logError, progname, "Invalid Greenplum DB Credentials:  %s\n", g_MPPPassThroughCredentials);
			exit(1);
		}
		if (nBytes > 0)
		{
			SegDB.pszDBPswd = malloc(nBytes + 1);
			if (SegDB.pszDBPswd == NULL)
			{
				mpp_err_msg(logInfo, progname, "Cannot allocate memory for Greenplum Database Credentials\n");
				exit(1);
			}

			memcpy(SegDB.pszDBPswd, pszDBPswd, nBytes);
			SegDB.pszDBPswd[nBytes] = '\0';
		}
	}

	if (g_role == ROLE_MASTER)
		g_conn = MakeDBConnection(&SegDB, true);
	else
		g_conn = MakeDBConnection(&SegDB, false);
	if (PQstatus(g_conn) == CONNECTION_BAD)
	{
		exit_horribly(NULL, NULL, "connection to database \"%s\" failed: %s",
					  PQdb(g_conn), PQerrorMessage(g_conn));
	}

	if (g_gpdumpKey != NULL)
	{
		/*
		 * Open the database again, for writing status info
		 */
		g_conn_status = MakeDBConnection(&SegDB, false);

		if (PQstatus(g_conn_status) == CONNECTION_BAD)
		{
			exit_horribly(NULL, NULL, "Connection on host %s failed: %s",
						  StringNotNull(SegDB.pszHost, "localhost"),
						  PQerrorMessage(g_conn_status));
		}

		g_main_tid = pthread_self();

		g_pStatusOpList = CreateStatusOpList();
		if (g_pStatusOpList == NULL)
		{
			exit_horribly(NULL, NULL, "cannot allocate memory for gp_backup_status operation\n");
		}

		/*
		 * Create thread for monitoring for cancel requests.  If we're running
		 * using PSQL, the monitor is not allowed to start until the worker
		 * process is forked.  This is done to prevent the forked process from
		 * being blocked by locks held by library routines (__tz_convert, for
		 * example).
		 */
		if (bUsePSQL)
		{
			pthread_mutex_lock(&g_threadSyncPoint);
		}
		pthread_create(&g_monitor_tid,
					   NULL,
					   monitorThreadProc,
					   NULL);

		/* Install Ctrl-C interrupt handler, now that we have a connection */
		if (!bUsePSQL)
		{
			act.sa_handler = myHandler;
			sigemptyset(&act.sa_mask);
			act.sa_flags = 0;
			act.sa_flags |= SA_RESTART;
			if (sigaction(SIGINT, &act, NULL) < 0)
			{
				mpp_err_msg(logInfo, progname, "Error trying to set SIGINT interrupt handler\n");
			}

			act.sa_handler = myHandler;
			sigemptyset(&act.sa_mask);
			act.sa_flags = 0;
			act.sa_flags |= SA_RESTART;
			if (sigaction(SIGTERM, &act, NULL) < 0)
			{
				mpp_err_msg(logInfo, progname, "Error trying to set SIGTERM interrupt handler\n");
			}
		}

		pOp = CreateStatusOp(TASK_START, TASK_RC_SUCCESS, SUFFIX_START, TASK_MSG_SUCCESS);
		if (pOp == NULL)
		{
			exit_horribly(NULL, NULL, "cannot allocate memory for gp_backup_status operation\n");
		}
		AddToStatusOpList(g_pStatusOpList, pOp);
	}
	/* end cdb additions */

	if (bUsePSQL)
	{
		/* Install Ctrl-C interrupt handler, now that we have a connection */
		act.sa_handler = psqlHandler;
		sigemptyset(&act.sa_mask);
		act.sa_flags = 0;
		act.sa_flags |= SA_RESTART;
		if (sigaction(SIGINT, &act, NULL) < 0)
		{
			mpp_err_msg(logInfo, progname, "Error trying to set SIGINT interrupt handler\n");
		}

		act.sa_handler = psqlHandler;
		sigemptyset(&act.sa_mask);
		act.sa_flags = 0;
		act.sa_flags |= SA_RESTART;
		if (sigaction(SIGTERM, &act, NULL) < 0)
		{
			mpp_err_msg(logInfo, progname, "Error trying to set SIGTERM interrupt handler\n");
		}

		/* Establish a SIGCHLD handler to catch termination the psql process */
		act.sa_handler = myChildHandler;
		sigemptyset(&act.sa_mask);
		act.sa_flags = 0;
		act.sa_flags |= SA_RESTART;
		if (sigaction(SIGCHLD, &act, NULL) < 0)
		{
			mpp_err_msg(logInfo, progname, "Error trying to set SIGCHLD interrupt handler\n");
			exit(1);
		}

		mpp_err_msg(logInfo, progname, "Before fork of gp_restore_agent\n");

		newpid = fork();
		if (newpid < 0)
		{
			mpp_err_msg(logError, progname, "Failed to fork\n");
		}
		else if (newpid == 0)
		{
			/* TODO: use findAcceptableBackupFilePathName(...) to look for the file name
			 *       if user invoked gp_restore_agent directly without supplying a file name.
			 *       If the agent is invoked from gp_restore_launch, then we are ok.
			 */
			if (optind < argc)
			{
				char *rawInputFile = argv[optind];

				valueBuf = createPQExpBuffer();
				inputFileSpec = shellEscape(rawInputFile, valueBuf, false, false);
			}

			if (inputFileSpec == NULL || inputFileSpec[0] == '\0')
			{
				mpp_err_msg(logError, progname, "dump file path is empty");
				exit(1);
			}

			if (postDataSchemaOnly)
			{
				if (strstr(inputFileSpec,"_post_data") == NULL)
				{
					fprintf(stderr,"Adding _post_data to the end of the file name?\n");
					char * newFS = malloc(strlen(inputFileSpec) + strlen("_post_data") + 1);
					strcpy(newFS, inputFileSpec);
					strcat(newFS, "_post_data");
					inputFileSpec = newFS;
				}
			}

			pszCmdLine = createPQExpBuffer();
#ifdef USE_DDBOOST
			if (dd_boost_enabled)
			{
				formDDBoostPsqlCommandLine(pszCmdLine, argv[0],
									(postDataSchemaOnly == 1 ? true : false),
									g_role, g_compPg, ddp_file_name,
									dd_boost_buf_size, table_filter_file,
									change_schema_file, schema_level_file,
									ddboost_storage_unit);
			}
			else
			{
#endif
				formPsqlCommandLine(pszCmdLine, argv[0], (postDataSchemaOnly == 1), g_role,
									inputFileSpec, g_compPg, table_filter_file,
									netbackup_service_host, netbackup_block_size,
									change_schema_file, schema_level_file);
#ifdef USE_DDBOOST
			}
#endif

			appendPQExpBuffer(pszCmdLine, " -h %s -p %s -U %s -d ",
							  g_targetHost, g_targetPort, SegDB.pszDBUser);
			shellEscape(SegDB.pszDBName, pszCmdLine, true /* quote */, false /* reset */);
			appendPQExpBuffer(pszCmdLine, " -a ");

			if (g_bOnErrorStop)
				appendPQExpBuffer(pszCmdLine, " -v ON_ERROR_STOP=");

			if (g_role == ROLE_SEGDB)
				putenv("PGOPTIONS=-c gp_session_role=UTILITY");
			if (g_role == ROLE_MASTER)
				putenv("PGOPTIONS=-c gp_session_role=DISPATCH");

			mpp_err_msg(logInfo, progname, "Command Line: %s\n", pszCmdLine->data);

			/*
			 * Make this new process the process group leader of the children
			 * being launched.	This allows a signal to be sent to all
			 * processes in the group simultaneously.
			 */
			setpgid(newpid, newpid);

			execl("/bin/sh", "sh", "-c", pszCmdLine->data, NULL);

			mpp_err_msg(logInfo, progname, "Error in gp_restore_agent - execl of %s with Command Line %s failed",
						"/bin/sh", pszCmdLine->data);

			_exit(127);
		}
		else
		{
			/*
			 * Make the new child process the process group leader of the
			 * children being launched.  This allows a signal to be sent to
			 * all processes in the group simultaneously.
			 *
			 * This is a redundant call to avoid a race condition suggested by
			 * Stevens.
			 */
			setpgid(newpid, newpid);

			/* Allow the monitor thread to begin execution. */
			pthread_mutex_unlock(&g_threadSyncPoint);

			/* Parent .  Lets sleep and wake up until we see it's done */
			while (!bPSQLDone)
			{
				sleep(5);
			}

			/*
			 * If this process has been sent a SIGINT or SIGTERM, we need to
			 * send a SIGINT to the psql process GROUP.
			 */
			if (bKillPsql)
			{
				mpp_err_msg(logInfo, progname, "Terminating psql due to signal.\n");
				kill(-newpid, SIGINT);
			}

			waitpid(newpid, &status, 0);
			if (WIFEXITED(status))
			{
				rc = WEXITSTATUS(status);
				if (rc == 0)
				{
					mpp_err_msg(logInfo, progname, "psql finished with rc %d.\n", rc);
					/* Normal completion falls to end of routine. */
				}
				else
				{
					if (rc >= 128)
					{
						/*
						 * If the exit code has the 128-bit set, the exit code
						 * represents a shell exited by signal where the
						 * signal number is exitCode - 128.
						 */
						rc -= 128;
						pszErrorMsg = MakeString("psql finished abnormally with signal number %d.\n", rc);
					}
					else
					{
						pszErrorMsg = MakeString("psql finished abnormally with return code %d.\n", rc);
					}
					makeSureMonitorThreadEnds(TASK_RC_FAILURE, pszErrorMsg);
					free(pszErrorMsg);
					exit_code = 2;
				}
			}
			else if (WIFSIGNALED(status))
			{
				pszErrorMsg = MakeString("psql finished abnormally with signal number %d.\n", WTERMSIG(status));
				mpp_err_msg(logError, progname, pszErrorMsg);
				makeSureMonitorThreadEnds(TASK_RC_FAILURE, pszErrorMsg);
				free(pszErrorMsg);
				exit_code = 2;
			}
			else
			{
				pszErrorMsg = MakeString("psql crashed or finished badly; status=%#x.\n", status);
				mpp_err_msg(logError, progname, pszErrorMsg);
				makeSureMonitorThreadEnds(TASK_RC_FAILURE, pszErrorMsg);
				free(pszErrorMsg);
				exit_code = 2;
			}
		}
	}
	else
	{
		AH = OpenArchive(inputFileSpec, opts->format);

		/* Let the archiver know how noisy to be */
		AH->verbose = opts->verbose;

		/*
	     * Whether to keep submitting sql commands as "pg_restore ... | psql ... "
		 */
		AH->exit_on_error = opts->exit_on_error;

		if (opts->tocFile)
			SortTocFromFile(AH, opts);

		if (opts->tocSummary)
			PrintTOCSummary(AH, opts);
		else
		{
			pAH = (ArchiveHandle *) AH;

			if (opts->useDB)
			{
				/* check for version mismatch */
				if (pAH->version < K_VERS_1_3)
					die_horribly(NULL, NULL, "direct database connections are not supported in pre-1.3 archives\n");

				pAH->connection = g_conn;
				/* XXX Should get this from the archive */
				AH->minRemoteVersion = 070100;
				AH->maxRemoteVersion = 999999;

				_check_database_version(pAH);
			}

			RestoreArchive(AH, opts);

			/*
			 * The following is necessary when the -C option is used.  A new
			 * connection is gotten to the database within RestoreArchive
			 */
			if (pAH->connection != g_conn)
				g_conn = pAH->connection;
		}

		/* done, print a summary of ignored errors */
		if (AH->n_errors)
			fprintf(stderr, _("WARNING: errors ignored on restore: %d\n"),
					AH->n_errors);

		/* AH may be freed in CloseArchive? */
		exit_code = AH->n_errors ? 1 : 0;

		CloseArchive(AH);
	}

#ifdef USE_DDBOOST
	if(dd_boost_enabled)
		cleanupDDSystem();
	free(ddboost_storage_unit);
#endif

	makeSureMonitorThreadEnds(TASK_RC_SUCCESS, TASK_MSG_SUCCESS);

	DestroyStatusOpList(g_pStatusOpList);

	if (change_schema_file)
		free(change_schema_file);
	if (schema_level_file)
		free(schema_level_file);
	if (SegDB.pszHost)
		free(SegDB.pszHost);
	if (SegDB.pszDBName)
		free(SegDB.pszDBName);
	if (SegDB.pszDBUser)
		free(SegDB.pszDBUser);
	if (SegDB.pszDBPswd)
		free(SegDB.pszDBPswd);
	if (valueBuf)
		destroyPQExpBuffer(valueBuf);
	if (escapeBuf)
		destroyPQExpBuffer(escapeBuf);

	PQfinish(g_conn);
	if (exit_code == 0)
		mpp_err_msg(logInfo, progname, "Finished successfully\n");
	else
		mpp_err_msg(logError, progname, "Finished with errors\n");
	return exit_code;
}
Пример #4
0
int
main(int argc, char **argv)
{
	RestoreOptions *opts;
	int			c;
	int			exit_code;
	Archive    *AH;
	char	   *inputFileSpec;
	extern int	optind;
	extern char *optarg;
	static int	use_setsessauth = 0;
	static int	disable_triggers = 0;

	struct option cmdopts[] = {
		{"clean", 0, NULL, 'c'},
		{"create", 0, NULL, 'C'},
		{"data-only", 0, NULL, 'a'},
		{"dbname", 1, NULL, 'd'},
		{"exit-on-error", 0, NULL, 'e'},
		{"file", 1, NULL, 'f'},
		{"format", 1, NULL, 'F'},
		{"function", 1, NULL, 'P'},
		{"host", 1, NULL, 'h'},
		{"ignore-version", 0, NULL, 'i'},
		{"index", 1, NULL, 'I'},
		{"list", 0, NULL, 'l'},
		{"no-privileges", 0, NULL, 'x'},
		{"no-acl", 0, NULL, 'x'},
		{"no-owner", 0, NULL, 'O'},
		{"no-reconnect", 0, NULL, 'R'},
		{"port", 1, NULL, 'p'},
		{"password", 0, NULL, 'W'},
		{"schema", 1, NULL, 'n'},
		{"schema-only", 0, NULL, 's'},
		{"superuser", 1, NULL, 'S'},
		{"table", 1, NULL, 't'},
		{"trigger", 1, NULL, 'T'},
		{"use-list", 1, NULL, 'L'},
		{"username", 1, NULL, 'U'},
		{"verbose", 0, NULL, 'v'},

		/*
		 * the following options don't have an equivalent short option letter,
		 * but are available as '-X long-name'
		 */
		{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
		{"disable-triggers", no_argument, &disable_triggers, 1},

		{NULL, 0, NULL, 0}
	};

	set_pglocale_pgservice(argv[0], "pg_dump");

	opts = NewRestoreOptions();

	progname = get_progname(argv[0]);

	if (argc > 1)
	{
		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
		{
			usage(progname);
			exit(0);
		}
		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
		{
			puts("pg_restore (PostgreSQL) " PG_VERSION);
			exit(0);
		}
	}

	while ((c = getopt_long(argc, argv, "acCd:ef:F:h:iI:lL:n:Op:P:RsS:t:T:uU:vWxX:",
							cmdopts, NULL)) != -1)
	{
		switch (c)
		{
			case 'a':			/* Dump data only */
				opts->dataOnly = 1;
				break;
			case 'c':			/* clean (i.e., drop) schema prior to create */
				opts->dropSchema = 1;
				break;
			case 'C':
				opts->create = 1;
				break;
			case 'd':
				opts->dbname = strdup(optarg);
				break;
			case 'e':
				opts->exit_on_error = true;
				break;
			case 'f':			/* output file name */
				opts->filename = strdup(optarg);
				break;
			case 'F':
				if (strlen(optarg) != 0)
					opts->formatName = strdup(optarg);
				break;
			case 'h':
				if (strlen(optarg) != 0)
					opts->pghost = strdup(optarg);
				break;
			case 'i':
				opts->ignoreVersion = 1;
				break;

			case 'l':			/* Dump the TOC summary */
				opts->tocSummary = 1;
				break;

			case 'L':			/* input TOC summary file name */
				opts->tocFile = strdup(optarg);
				break;

			case 'O':
				opts->noOwner = 1;
				break;
			case 'p':
				if (strlen(optarg) != 0)
					opts->pgport = strdup(optarg);
				break;
			case 'R':
				/* no-op, still accepted for backwards compatibility */
				break;
			case 'P':			/* Function */
				opts->selTypes = 1;
				opts->selFunction = 1;
				opts->functionNames = strdup(optarg);
				break;
			case 'I':			/* Index */
				opts->selTypes = 1;
				opts->selIndex = 1;
				opts->indexNames = strdup(optarg);
				break;
			case 'T':			/* Trigger */
				opts->selTypes = 1;
				opts->selTrigger = 1;
				opts->triggerNames = strdup(optarg);
				break;
			case 's':			/* dump schema only */
				opts->schemaOnly = 1;
				break;
			case 'S':			/* Superuser username */
				if (strlen(optarg) != 0)
					opts->superuser = strdup(optarg);
				break;
			case 't':			/* Dump data for this table only */
				opts->selTypes = 1;
				opts->selTable = 1;
				opts->tableNames = strdup(optarg);
				break;

			case 'n':			/* Dump data for this schema only */
				opts->selTypes = 1;
				opts->schemaNames = strdup(optarg);
				break;

			case 'u':
				opts->requirePassword = true;
				opts->username = simple_prompt("User name: ", 100, true);
				break;

			case 'U':
				opts->username = optarg;
				break;

			case 'v':			/* verbose */
				opts->verbose = 1;
				break;

			case 'W':
				opts->requirePassword = true;
				break;

			case 'x':			/* skip ACL dump */
				opts->aclsSkip = 1;
				break;

			case 'X':
				if (strcmp(optarg, "use-set-session-authorization") == 0)
					use_setsessauth = 1;
				else if (strcmp(optarg, "disable-triggers") == 0)
					disable_triggers = 1;
				else
				{
					fprintf(stderr,
							_("%s: invalid -X option -- %s\n"),
							progname, optarg);
					fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
					exit(1);
				}
				break;

				/* This covers the long options equivalent to -X xxx. */
			case 0:
				break;

			default:
				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
				exit(1);
		}
	}

	if (optind < argc)
		inputFileSpec = argv[optind];
	else
		inputFileSpec = NULL;

	/* Should get at most one of -d and -f, else user is confused */
	if (opts->dbname)
	{
		if (opts->filename)
		{
			fprintf(stderr, _("%s: cannot specify both -d and -f output\n"),
					progname);
			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
					progname);
			exit(1);
		}
		opts->useDB = 1;
	}

	opts->disable_triggers = disable_triggers;
	opts->use_setsessauth = use_setsessauth;

	if (opts->formatName)
	{

		switch (opts->formatName[0])
		{

			case 'c':
			case 'C':
				opts->format = archCustom;
				break;

			case 'f':
			case 'F':
				opts->format = archFiles;
				break;

			case 't':
			case 'T':
				opts->format = archTar;
				break;

			default:
				write_msg(NULL, "unrecognized archive format \"%s\"; please specify \"c\" or \"t\"\n",
						  opts->formatName);
				exit(1);
		}
	}

	AH = OpenArchive(inputFileSpec, opts->format);

	/* Let the archiver know how noisy to be */
	AH->verbose = opts->verbose;

	/*
	 * Whether to keep submitting sql commands as "pg_restore ... | psql ... "
	 */
	AH->exit_on_error = opts->exit_on_error;

	if (opts->tocFile)
		SortTocFromFile(AH, opts);

	if (opts->tocSummary)
		PrintTOCSummary(AH, opts);
	else
		RestoreArchive(AH, opts);

	/* done, print a summary of ignored errors */
	if (AH->n_errors)
		fprintf(stderr, _("WARNING: errors ignored on restore: %d\n"),
				AH->n_errors);

	/* AH may be freed in CloseArchive? */
	exit_code = AH->n_errors ? 1 : 0;

	CloseArchive(AH);

	return exit_code;
}