Esempio n. 1
0
File: exec.c Progetto: GisKook/Gis
/*
 * resolve_symlinks - resolve symlinks to the underlying file
 *
 * Replace "path" by the absolute path to the referenced file.
 *
 * Returns 0 if OK, -1 if error.
 *
 * Note: we are not particularly tense about producing nice error messages
 * because we are not really expecting error here; we just determined that
 * the symlink does point to a valid executable.
 */
static int
resolve_symlinks(char *path)
{
#ifdef HAVE_READLINK
	struct stat buf;
	char		orig_wd[MAXPGPATH],
				link_buf[MAXPGPATH];
	char	   *fname;

	/*
	 * To resolve a symlink properly, we have to chdir into its directory and
	 * then chdir to where the symlink points; otherwise we may fail to
	 * resolve relative links correctly (consider cases involving mount
	 * points, for example).  After following the final symlink, we use
	 * getcwd() to figure out where the heck we're at.
	 *
	 * One might think we could skip all this if path doesn't point to a
	 * symlink to start with, but that's wrong.  We also want to get rid of
	 * any directory symlinks that are present in the given path. We expect
	 * getcwd() to give us an accurate, symlink-free path.
	 */
	if (!getcwd(orig_wd, MAXPGPATH))
	{
		log_error(_("could not identify current directory: %s"),
				  strerror(errno));
		return -1;
	}

	for (;;)
	{
		char	   *lsep;
		int			rllen;

		lsep = last_dir_separator(path);
		if (lsep)
		{
			*lsep = '\0';
			if (chdir(path) == -1)
			{
				log_error(_("could not change directory to \"%s\""), path);
				return -1;
			}
			fname = lsep + 1;
		}
		else
			fname = path;

		if (lstat(fname, &buf) < 0 ||
			!S_ISLNK(buf.st_mode))
			break;

		rllen = readlink(fname, link_buf, sizeof(link_buf));
		if (rllen < 0 || rllen >= sizeof(link_buf))
		{
			log_error(_("could not read symbolic link \"%s\""), fname);
			return -1;
		}
		link_buf[rllen] = '\0';
		strcpy(path, link_buf);
	}

	/* must copy final component out of 'path' temporarily */
	strcpy(link_buf, fname);

	if (!getcwd(path, MAXPGPATH))
	{
		log_error(_("could not identify current directory: %s"),
				  strerror(errno));
		return -1;
	}
	join_path_components(path, path, link_buf);
	canonicalize_path(path);

	if (chdir(orig_wd) == -1)
	{
		log_error(_("could not change directory to \"%s\""), orig_wd);
		return -1;
	}
#endif   /* HAVE_READLINK */

	return 0;
}
Esempio n. 2
0
/*
 * find_my_exec -- find an absolute path to a valid executable
 *
 *	argv0 is the name passed on the command line
 *	retpath is the output area (must be of size MAXPGPATH)
 *	Returns 0 if OK, -1 if error.
 *
 * The reason we have to work so hard to find an absolute path is that
 * on some platforms we can't do dynamic loading unless we know the
 * executable's location.  Also, we need a full path not a relative
 * path because we will later change working directory.  Finally, we want
 * a true path not a symlink location, so that we can locate other files
 * that are part of our installation relative to the executable.
 *
 * This function is not thread-safe because it calls validate_exec(),
 * which calls getgrgid().	This function should be used only in
 * non-threaded binaries, not in library routines.
 */
int
find_my_exec(const char *argv0, char *retpath)
{
	char		cwd[MAXPGPATH],
				test_path[MAXPGPATH];
	char	   *path;

	if (!getcwd(cwd, MAXPGPATH))
	{
		log_error(_("could not identify current directory: %s"),
				  strerror(errno));
		return -1;
	}

	/*
	 * If argv0 contains a separator, then PATH wasn't used.
	 */
	if (first_dir_separator(argv0) != NULL)
	{
		if (is_absolute_path(argv0))
			StrNCpy(retpath, argv0, MAXPGPATH);
		else
			join_path_components(retpath, cwd, argv0);
		canonicalize_path(retpath);

		if (validate_exec(retpath) == 0)
			return resolve_symlinks(retpath);

		log_error(_("invalid binary \"%s\""), retpath);
		return -1;
	}

#ifdef WIN32
	/* Win32 checks the current directory first for names without slashes */
	join_path_components(retpath, cwd, argv0);
	if (validate_exec(retpath) == 0)
		return resolve_symlinks(retpath);
#endif

	/*
	 * Since no explicit path was supplied, the user must have been relying on
	 * PATH.  We'll search the same PATH.
	 */
	if ((path = getenv("PATH")) && *path)
	{
		char	   *startp = NULL,
				   *endp = NULL;

		do
		{
			if (!startp)
				startp = path;
			else
				startp = endp + 1;

			endp = first_path_separator(startp);
			if (!endp)
				endp = startp + strlen(startp); /* point to end */

			StrNCpy(test_path, startp, Min(endp - startp + 1, MAXPGPATH));

			if (is_absolute_path(test_path))
				join_path_components(retpath, test_path, argv0);
			else
			{
				join_path_components(retpath, cwd, test_path);
				join_path_components(retpath, retpath, argv0);
			}
			canonicalize_path(retpath);

			switch (validate_exec(retpath))
			{
				case 0: /* found ok */
					return resolve_symlinks(retpath);
				case -1:		/* wasn't even a candidate, keep looking */
					break;
				case -2:		/* found but disqualified */
					log_error(_("could not read binary \"%s\""),
							  retpath);
					break;
			}
		} while (*endp);
	}

	log_error(_("could not find a \"%s\" to execute"), argv0);
	return -1;
}
Esempio n. 3
0
/*
 * Entry point of pg_arman command.
 */
int
main(int argc, char *argv[])
{
	const char	   *cmd = NULL;
	const char	   *range1 = NULL;
	const char	   *range2 = NULL;
	pgBackupRange	range;
	int				i;

	/* do not buffer progress messages */
	setvbuf(stdout, 0, _IONBF, 0);	/* TODO: remove this */

	/* initialize configuration */
	catalog_init_config(&current);

	/* overwrite configuration with command line arguments */
	i = pgut_getopt(argc, argv, options);

	for (; i < argc; i++)
	{
		if (cmd == NULL)
			cmd = argv[i];
		else if (range1 == NULL)
			range1 = argv[i];
		else if (range2 == NULL)
			range2 = argv[i];
		else
			elog(ERROR, "too many arguments");
	}

	/* command argument (backup/restore/show/...) is required. */
	if (cmd == NULL)
	{
		help(false);
		return 1;
	}

	/* get object range argument if any */
	if (range1 && range2)
		parse_range(&range, range1, range2);
	else if (range1)
		parse_range(&range, range1, "");
	else
		range.begin = range.end = 0;

	/* Read default configuration from file. */
	if (backup_path)
	{
		char	path[MAXPGPATH];
		/* Check if backup_path is directory. */
		struct stat stat_buf;
		int rc = stat(backup_path, &stat_buf);

		/* If rc == -1,  there is no file or directory. So it's OK. */
		if (rc != -1 && !S_ISDIR(stat_buf.st_mode))
			elog(ERROR, "-B, --backup-path must be a path to directory");

		join_path_components(path, backup_path, PG_RMAN_INI_FILE);
		pgut_readopt(path, options, ERROR);
	}

	/* BACKUP_PATH is always required */
	if (backup_path == NULL)
		elog(ERROR, "required parameter not specified: BACKUP_PATH (-B, --backup-path)");

	/* path must be absolute */
	if (backup_path != NULL && !is_absolute_path(backup_path))
		elog(ERROR, "-B, --backup-path must be an absolute path");
	if (pgdata != NULL && !is_absolute_path(pgdata))
		elog(ERROR, "-D, --pgdata must be an absolute path");
	if (arclog_path != NULL && !is_absolute_path(arclog_path))
		elog(ERROR, "-A, --arclog-path must be an absolute path");

	/* Sanity checks with commands */
	if (pg_strcasecmp(cmd, "delete") == 0 && arclog_path == NULL)
		elog(ERROR, "delete command needs ARCLOG_PATH (-A, --arclog-path) to be set");

	/* setup exclusion list for file search */
	for (i = 0; pgdata_exclude[i]; i++)		/* find first empty slot */
		;
	if (arclog_path)
		pgdata_exclude[i++] = arclog_path;

	/* do actual operation */
	if (pg_strcasecmp(cmd, "init") == 0)
		return do_init();
	else if (pg_strcasecmp(cmd, "backup") == 0)
	{
		pgBackupOption bkupopt;
		int res;
		bkupopt.smooth_checkpoint = smooth_checkpoint;
		bkupopt.keep_data_generations = keep_data_generations;
		bkupopt.keep_data_days = keep_data_days;

		/* Do the backup */
		res = do_backup(bkupopt);
		if (res != 0)
			return res;

		/* If validation has been requested, do it */
		range.begin = current.start_time;
		range.end = current.start_time + 1;
		if (backup_validate)
			do_validate(&range);
	}
	else if (pg_strcasecmp(cmd, "restore") == 0)
		return do_restore(target_time, target_xid,
					target_inclusive, target_tli);
	else if (pg_strcasecmp(cmd, "show") == 0)
		return do_show(&range, show_all);
	else if (pg_strcasecmp(cmd, "validate") == 0)
		return do_validate(&range);
	else if (pg_strcasecmp(cmd, "delete") == 0)
		return do_delete(&range);
	else
		elog(ERROR, "invalid command \"%s\"", cmd);

	return 0;
}