Exemplo n.º 1
0
static int cmd_inspect_subvolid_resolve(int argc, char **argv)
{
	int ret;
	int fd = -1;
	u64 subvol_id;
	char path[PATH_MAX];
	DIR *dirstream = NULL;

	clean_args_no_options(argc, argv, cmd_inspect_subvolid_resolve_usage);

	if (check_argc_exact(argc - optind, 2))
		usage(cmd_inspect_subvolid_resolve_usage);

	fd = btrfs_open_dir(argv[optind + 1], &dirstream, 1);
	if (fd < 0) {
		ret = -ENOENT;
		goto out;
	}

	subvol_id = arg_strtou64(argv[optind]);
	ret = btrfs_subvolid_resolve(fd, path, sizeof(path), subvol_id);

	if (ret) {
		error("resolving subvolid %llu error %d",
			(unsigned long long)subvol_id, ret);
		goto out;
	}

	path[PATH_MAX - 1] = '\0';
	printf("%s\n", path);

out:
	close_file_or_dir(fd, dirstream);
	return ret ? 1 : 0;
}
static int do_receive(struct btrfs_receive *r, const char *tomnt,
		      char *realmnt, int r_fd, u64 max_errors)
{
	u64 subvol_id;
	int ret;
	char *dest_dir_full_path;
	char root_subvol_path[PATH_MAX];
	int end = 0;

	dest_dir_full_path = realpath(tomnt, NULL);
	if (!dest_dir_full_path) {
		ret = -errno;
		error("realpath(%s) failed: %s", tomnt, strerror(-ret));
		goto out;
	}
	r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
	if (r->dest_dir_fd < 0) {
		ret = -errno;
		error("cannot open destination directory %s: %s",
			dest_dir_full_path, strerror(-ret));
		goto out;
	}

	if (realmnt[0]) {
		r->root_path = realmnt;
	} else {
		ret = find_mount_root(dest_dir_full_path, &r->root_path);
		if (ret < 0) {
			error("failed to determine mount point for %s: %s",
				dest_dir_full_path, strerror(-ret));
			ret = -EINVAL;
			goto out;
		}
		if (ret > 0) {
			error("%s doesn't belong to btrfs mount point",
				dest_dir_full_path);
			ret = -EINVAL;
			goto out;
		}
	}
	r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
	if (r->mnt_fd < 0) {
		ret = -errno;
		error("cannot open %s: %s", r->root_path, strerror(-ret));
		goto out;
	}

	/*
	 * If we use -m or a default subvol we want to resolve the path to the
	 * subvolume we're sitting in so that we can adjust the paths of any
	 * subvols we want to receive in.
	 */
	ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
	if (ret) {
		error("cannot resolve our subvolid: %d",
			ret);
		goto out;
	}

	root_subvol_path[0] = 0;
	ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
				     PATH_MAX, subvol_id);
	if (ret) {
		error("cannot resolve our subvol path");
		goto out;
	}

	/*
	 * Ok we're inside of a subvol off of the root subvol, we need to
	 * actually set full_root_path.
	 */
	if (*root_subvol_path)
		r->full_root_path = root_subvol_path;

	if (r->dest_dir_chroot) {
		if (chroot(dest_dir_full_path)) {
			ret = -errno;
			error("failed to chroot to %s: %s",
				dest_dir_full_path, strerror(-ret));
			goto out;
		}
		if (chdir("/")) {
			ret = -errno;
			error("failed to chdir to / after chroot: %s",
				strerror(-ret));
			goto out;
		}
		fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
		r->root_path = strdup("/");
		r->dest_dir_path = r->root_path;
	} else {
		/*
		 * find_mount_root returns a root_path that is a subpath of
		 * dest_dir_full_path. Now get the other part of root_path,
		 * which is the destination dir relative to root_path.
		 */
		r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
		while (r->dest_dir_path[0] == '/')
			r->dest_dir_path++;
	}

	ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
	if (ret < 0)
		goto out;

	while (!end) {
		if (r->cached_capabilities_len) {
			if (g_verbose >= 3)
				fprintf(stderr, "clear cached capabilities\n");
			memset(r->cached_capabilities, 0,
					sizeof(r->cached_capabilities));
			r->cached_capabilities_len = 0;
		}

		ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
							 r->honor_end_cmd,
							 max_errors);
		if (ret < 0)
			goto out;
		if (ret)
			end = 1;

		close_inode_for_write(r);
		ret = finish_subvol(r);
		if (ret < 0)
			goto out;
	}
	ret = 0;

out:
	if (r->write_fd != -1) {
		close(r->write_fd);
		r->write_fd = -1;
	}

	if (r->root_path != realmnt)
		free(r->root_path);
	r->root_path = NULL;
	r->dest_dir_path = NULL;
	free(dest_dir_full_path);
	subvol_uuid_search_finit(&r->sus);
	if (r->mnt_fd != -1) {
		close(r->mnt_fd);
		r->mnt_fd = -1;
	}
	if (r->dest_dir_fd != -1) {
		close(r->dest_dir_fd);
		r->dest_dir_fd = -1;
	}

	return ret;
}