コード例 #1
0
static int cmd_scrub_cancel(int argc, char **argv)
{
	char *path;
	int ret;
	int fdmnt;
	int err;
	char mp[BTRFS_PATH_NAME_MAX + 1];
	struct btrfs_fs_devices *fs_devices_mnt = NULL;

	if (check_argc_exact(argc, 2))
		usage(cmd_scrub_cancel_usage);

	path = argv[1];

	fdmnt = open_file_or_dir(path);
	if (fdmnt < 0) {
		fprintf(stderr, "ERROR: scrub cancel failed\n");
		return 12;
	}

again:
	ret = ioctl(fdmnt, BTRFS_IOC_SCRUB_CANCEL, NULL);
	err = errno;
	close(fdmnt);

	if (ret && err == EINVAL) {
		/* path is no mounted btrfs. try if it's a device */
		ret = check_mounted_where(fdmnt, path, mp, sizeof(mp),
					  &fs_devices_mnt);
		close(fdmnt);
		if (ret) {
			fdmnt = open_file_or_dir(mp);
			if (fdmnt >= 0) {
				path = mp;
				goto again;
			}
		}
	}

	if (ret) {
		fprintf(stderr, "ERROR: scrub cancel failed on %s: %s\n", path,
			err == ENOTCONN ? "not running" : strerror(errno));
		return 1;
	}

	printf("scrub cancelled\n");

	return 0;
}
コード例 #2
0
ファイル: cmds-balance.c プロジェクト: B-Rich/btrfs-progs
static int cmd_balance_pause(int argc, char **argv)
{
	const char *path;
	int fd;
	int ret;
	int e;
	DIR *dirstream = NULL;

	if (check_argc_exact(argc, 2))
		usage(cmd_balance_pause_usage);

	path = argv[1];

	fd = open_file_or_dir(path, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", path);
		return 1;
	}

	ret = ioctl(fd, BTRFS_IOC_BALANCE_CTL, BTRFS_BALANCE_CTL_PAUSE);
	e = errno;
	close_file_or_dir(fd, dirstream);

	if (ret < 0) {
		fprintf(stderr, "ERROR: balance pause on '%s' failed - %s\n",
			path, (e == ENOTCONN) ? "Not running" : strerror(e));
		if (e == ENOTCONN)
			return 2;
		else
			return 1;
	}

	return 0;
}
コード例 #3
0
ファイル: cmds-quota.c プロジェクト: osandov/btrfs-progs
static int quota_ctl(int cmd, int argc, char **argv)
{
	int ret = 0;
	int fd;
	int e;
	char *path = argv[1];
	struct btrfs_ioctl_quota_ctl_args args;
	DIR *dirstream = NULL;

	if (check_argc_exact(argc, 2))
		return -1;

	memset(&args, 0, sizeof(args));
	args.cmd = cmd;

	fd = open_file_or_dir(path, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", path);
		return 1;
	}

	ret = ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args);
	e = errno;
	close_file_or_dir(fd, dirstream);
	if (ret < 0) {
		fprintf(stderr, "ERROR: quota command failed: %s\n",
			strerror(e));
		return 1;
	}
	return 0;
}
コード例 #4
0
static int qgroup_create(int create, int argc, char **argv)
{
	int ret = 0;
	int fd;
	int e;
	char *path = argv[2];
	struct btrfs_ioctl_qgroup_create_args args;
	DIR *dirstream = NULL;

	if (check_argc_exact(argc, 3))
		return -1;

	memset(&args, 0, sizeof(args));
	args.create = create;
	args.qgroupid = parse_qgroupid(argv[1]);

	fd = open_file_or_dir(path, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", path);
		return 1;
	}

	ret = ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args);
	e = errno;
	close_file_or_dir(fd, dirstream);
	if (ret < 0) {
		fprintf(stderr, "ERROR: unable to %s quota group: %s\n",
			create ? "create":"destroy", strerror(e));
		return 1;
	}
	return 0;
}
コード例 #5
0
ファイル: cmds-balance.c プロジェクト: chyyuu/ski-fsstress
static int cmd_balance_cancel(int argc, char **argv)
{
	const char *path;
	int fd;
	int ret;
	int e;

	if (check_argc_exact(argc, 2))
		usage(cmd_balance_cancel_usage);

	path = argv[1];

	fd = open_file_or_dir(path);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access to '%s'\n", path);
		return 12;
	}

	ret = ioctl(fd, BTRFS_IOC_BALANCE_CTL, BTRFS_BALANCE_CTL_CANCEL);
	e = errno;
	close(fd);

	if (ret < 0) {
		fprintf(stderr, "ERROR: balance cancel on '%s' failed - %s\n",
			path, (e == ENOTCONN) ? "Not in progress" : strerror(e));
		return 19;
	}

	return 0;
}
コード例 #6
0
ファイル: cmds-subvolume.c プロジェクト: osandov/btrfs-progs
static int cmd_subvol_set_default(int argc, char **argv)
{
	int	ret=0, fd, e;
	u64	objectid;
	char	*path;
	char	*subvolid;
	DIR	*dirstream = NULL;

	if (check_argc_exact(argc, 3))
		usage(cmd_subvol_set_default_usage);

	subvolid = argv[1];
	path = argv[2];

	objectid = arg_strtou64(subvolid);

	fd = open_file_or_dir(path, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", path);
		return 1;
	}

	ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
	e = errno;
	close_file_or_dir(fd, dirstream);
	if (ret < 0) {
		fprintf(stderr, "ERROR: unable to set a new default subvolume - %s\n",
			strerror(e));
		return 1;
	}
	return 0;
}
コード例 #7
0
ファイル: cmds-subvolume.c プロジェクト: osandov/btrfs-progs
static int cmd_subvol_get_default(int argc, char **argv)
{
	int fd = -1;
	int ret;
	char *subvol;
	struct btrfs_list_filter_set *filter_set;
	u64 default_id;
	DIR *dirstream = NULL;

	if (check_argc_exact(argc, 2))
		usage(cmd_subvol_get_default_usage);

	subvol = argv[1];
	fd = open_file_or_dir(subvol, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
		return 1;
	}

	ret = btrfs_list_get_default_subvolume(fd, &default_id);
	if (ret) {
		fprintf(stderr, "ERROR: can't perform the search - %s\n",
			strerror(errno));
		goto out;
	}

	ret = 1;
	if (default_id == 0) {
		fprintf(stderr, "ERROR: 'default' dir item not found\n");
		goto out;
	}

	/* no need to resolve roots if FS_TREE is default */
	if (default_id == BTRFS_FS_TREE_OBJECTID) {
		printf("ID 5 (FS_TREE)\n");
		ret = 0;
		goto out;
	}

	filter_set = btrfs_list_alloc_filter_set();
	btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_ROOTID,
				default_id);

	/* by default we shall print the following columns*/
	btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
	btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
	btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
	btrfs_list_setup_print_column(BTRFS_LIST_PATH);

	ret = btrfs_list_subvols_print(fd, filter_set, NULL,
		BTRFS_LIST_LAYOUT_DEFAULT, 1, NULL);

	if (filter_set)
		btrfs_list_free_filter_set(filter_set);
out:
	close_file_or_dir(fd, dirstream);
	return !!ret;
}
コード例 #8
0
ファイル: cmds-balance.c プロジェクト: B-Rich/btrfs-progs
static int cmd_balance_resume(int argc, char **argv)
{
	struct btrfs_ioctl_balance_args args;
	const char *path;
	DIR *dirstream = NULL;
	int fd;
	int ret;
	int e;

	if (check_argc_exact(argc, 2))
		usage(cmd_balance_resume_usage);

	path = argv[1];

	fd = open_file_or_dir(path, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", path);
		return 1;
	}

	memset(&args, 0, sizeof(args));
	args.flags |= BTRFS_BALANCE_RESUME;

	ret = ioctl(fd, BTRFS_IOC_BALANCE_V2, &args);
	e = errno;
	close_file_or_dir(fd, dirstream);

	if (ret < 0) {
		if (e == ECANCELED) {
			if (args.state & BTRFS_BALANCE_STATE_PAUSE_REQ)
				fprintf(stderr, "balance paused by user\n");
			if (args.state & BTRFS_BALANCE_STATE_CANCEL_REQ)
				fprintf(stderr, "balance canceled by user\n");
		} else if (e == ENOTCONN || e == EINPROGRESS) {
			fprintf(stderr, "ERROR: balance resume on '%s' "
				"failed - %s\n", path,
				(e == ENOTCONN) ? "Not in progress" :
						  "Already running");
			if (e == ENOTCONN)
				return 2;
			else
				return 1;
		} else {
			fprintf(stderr,
"ERROR: error during balancing '%s' - %s\n"
"There may be more info in syslog - try dmesg | tail\n", path, strerror(e));
			return 1;
		}
	} else {
		printf("Done, had to relocate %llu out of %llu chunks\n",
		       (unsigned long long)args.stat.completed,
		       (unsigned long long)args.stat.considered);
	}

	return 0;
}
コード例 #9
0
ファイル: cmds-balance.c プロジェクト: B-Rich/btrfs-progs
static int do_balance(const char *path, struct btrfs_ioctl_balance_args *args,
		      int nofilters)
{
	int fd;
	int ret;
	int e;
	DIR *dirstream = NULL;

	fd = open_file_or_dir(path, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", path);
		return 1;
	}

	ret = ioctl(fd, BTRFS_IOC_BALANCE_V2, args);
	e = errno;

	if (ret < 0) {
		/*
		 * older kernels don't have the new balance ioctl, try the
		 * old one.  But, the old one doesn't know any filters, so
		 * don't fall back if they tried to use the fancy new things
		 */
		if (e == ENOTTY && nofilters) {
			ret = do_balance_v1(fd);
			if (ret == 0)
				goto out;
			e = errno;
		}

		if (e == ECANCELED) {
			if (args->state & BTRFS_BALANCE_STATE_PAUSE_REQ)
				fprintf(stderr, "balance paused by user\n");
			if (args->state & BTRFS_BALANCE_STATE_CANCEL_REQ)
				fprintf(stderr, "balance canceled by user\n");
			ret = 0;
		} else {
			fprintf(stderr, "ERROR: error during balancing '%s' "
				"- %s\n", path, strerror(e));
			if (e != EINPROGRESS)
				fprintf(stderr, "There may be more info in "
					"syslog - try dmesg | tail\n");
			ret = 1;
		}
	} else {
		printf("Done, had to relocate %llu out of %llu chunks\n",
		       (unsigned long long)args->stat.completed,
		       (unsigned long long)args->stat.considered);
		ret = 0;
	}

out:
	close_file_or_dir(fd, dirstream);
	return ret;
}
コード例 #10
0
ファイル: utils.c プロジェクト: AnupBansod/assignments
/*
 * Given a pathname, return a filehandle to:
 * 	the original pathname or,
 * 	if the pathname is a mounted btrfs device, to its mountpoint.
 *
 * On error, return -1, errno should be set.
 */
int open_path_or_dev_mnt(const char *path, DIR **dirstream)
{
	char mp[BTRFS_PATH_NAME_MAX + 1];
	int fdmnt;

	if (is_block_device(path)) {
		int ret;

		ret = get_btrfs_mount(path, mp, sizeof(mp));
		if (ret < 0) {
			/* not a mounted btrfs dev */
			errno = EINVAL;
			return -1;
		}
		fdmnt = open_file_or_dir(mp, dirstream);
	} else {
		fdmnt = open_file_or_dir(path, dirstream);
	}

	return fdmnt;
}
コード例 #11
0
ファイル: cmds-replace.c プロジェクト: xpsair/btrfs-progs
static int cmd_replace_cancel(int argc, char **argv)
{
	struct btrfs_ioctl_dev_replace_args args = {0};
	int ret;
	int c;
	int fd;
	int e;
	char *path;
	DIR *dirstream = NULL;

	while ((c = getopt(argc, argv, "")) != -1) {
		switch (c) {
		case '?':
		default:
			usage(cmd_replace_cancel_usage);
		}
	}

	if (check_argc_exact(argc - optind, 1))
		usage(cmd_replace_cancel_usage);

	path = argv[optind];
	fd = open_file_or_dir(path, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access \"%s\": %s\n",
			path, strerror(errno));
		return 1;
	}

	args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL;
	args.result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT;
	ret = ioctl(fd, BTRFS_IOC_DEV_REPLACE, &args);
	e = errno;
	close_file_or_dir(fd, dirstream);
	if (ret) {
		fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_CANCEL) failed on \"%s\": %s",
			path, strerror(e));
		if (args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_RESULT)
			fprintf(stderr, ", %s\n",
				replace_dev_result2string(args.result));
		else
			fprintf(stderr, "\n");
		return 1;
	}
	if (args.result == BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED) {
		printf("INFO: ioctl(DEV_REPLACE_CANCEL)\"%s\": %s\n",
			path, replace_dev_result2string(args.result));
		return 2;
	}
	return 0;
}
コード例 #12
0
ファイル: cmds-device.c プロジェクト: osandov/btrfs-progs
static int cmd_rm_dev(int argc, char **argv)
{
	char	*mntpnt;
	int	i, fdmnt, ret=0, e;
	DIR	*dirstream = NULL;

	if (check_argc_min(argc, 3))
		usage(cmd_rm_dev_usage);

	mntpnt = argv[argc - 1];

	fdmnt = open_file_or_dir(mntpnt, &dirstream);
	if (fdmnt < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", mntpnt);
		return 1;
	}

	for(i=1 ; i < argc - 1; i++ ){
		struct	btrfs_ioctl_vol_args arg;
		int	res;

		if (!is_block_device(argv[i])) {
			fprintf(stderr,
				"ERROR: %s is not a block device\n", argv[i]);
			ret++;
			continue;
		}
		memset(&arg, 0, sizeof(arg));
		strncpy_null(arg.name, argv[i]);
		res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
		e = errno;
		if (res) {
			const char *msg;

			if (res > 0)
				msg = btrfs_err_str(res);
			else
				msg = strerror(e);
			fprintf(stderr,
				"ERROR: error removing the device '%s' - %s\n",
				argv[i], msg);
			ret++;
		}
	}

	close_file_or_dir(fdmnt, dirstream);
	return !!ret;
}
コード例 #13
0
ファイル: cmds-subvolume.c プロジェクト: osandov/btrfs-progs
static int cmd_find_new(int argc, char **argv)
{
	int fd;
	int ret;
	char *subvol;
	u64 last_gen;
	DIR *dirstream = NULL;

	if (check_argc_exact(argc, 3))
		usage(cmd_find_new_usage);

	subvol = argv[1];
	last_gen = arg_strtou64(argv[2]);

	ret = test_issubvolume(subvol);
	if (ret < 0) {
		fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
		return 1;
	}
	if (!ret) {
		fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
		return 1;
	}

	fd = open_file_or_dir(subvol, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
		return 1;
	}

	ret = ioctl(fd, BTRFS_IOC_SYNC);
	if (ret < 0) {
		fprintf(stderr, "ERROR: unable to fs-syncing '%s' - %s\n",
			subvol, strerror(errno));
		close_file_or_dir(fd, dirstream);
		return 1;
	}

	ret = btrfs_list_find_updated_files(fd, 0, last_gen);
	close_file_or_dir(fd, dirstream);
	return !!ret;
}
コード例 #14
0
ファイル: cmds-replace.c プロジェクト: AK47POMA/btrfs-progs
static int cmd_cancel_replace(int argc, char **argv)
{
	struct btrfs_ioctl_dev_replace_args args = {0};
	int ret;
	int c;
	int fd;
	int e;
	char *path;

	while ((c = getopt(argc, argv, "")) != -1) {
		switch (c) {
		case '?':
		default:
			usage(cmd_cancel_replace_usage);
		}
	}

	if (check_argc_exact(argc - optind, 1))
		usage(cmd_cancel_replace_usage);

	path = argv[optind];
	fd = open_file_or_dir(path);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access \"%s\": %s\n",
			path, strerror(errno));
		return -1;
	}

	args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL;
	ret = ioctl(fd, BTRFS_IOC_DEV_REPLACE, &args);
	e = errno;
	close(fd);
	if (ret) {
		fprintf(stderr, "ERROR: ioctl(DEV_REPLACE_CANCEL) failed on \"%s\": %s, %s\n",
			path, strerror(e),
			replace_dev_result2string(args.result));
		return ret;
	}

	return 0;
}
コード例 #15
0
static int qgroup_assign(int assign, int argc, char **argv)
{
	int ret = 0;
	int fd;
	int e;
	char *path = argv[3];
	struct btrfs_ioctl_qgroup_assign_args args;
	DIR *dirstream = NULL;

	if (check_argc_exact(argc, 4))
		return -1;

	memset(&args, 0, sizeof(args));
	args.assign = assign;
	args.src = parse_qgroupid(argv[1]);
	args.dst = parse_qgroupid(argv[2]);

	/*
	 * FIXME src should accept subvol path
	 */
	if (btrfs_qgroup_level(args.src) >= btrfs_qgroup_level(args.dst)) {
		fprintf(stderr, "ERROR: bad relation requested '%s'\n", path);
		return 1;
	}
	fd = open_file_or_dir(path, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", path);
		return 1;
	}

	ret = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
	e = errno;
	close_file_or_dir(fd, dirstream);
	if (ret < 0) {
		fprintf(stderr, "ERROR: unable to assign quota group: %s\n",
			strerror(e));
		return 1;
	}
	return 0;
}
コード例 #16
0
static int cmd_rm_dev(int argc, char **argv)
{
	char	*mntpnt;
	int	i, fdmnt, ret=0, e;

	if (check_argc_min(argc, 3))
		usage(cmd_rm_dev_usage);

	mntpnt = argv[argc - 1];

	fdmnt = open_file_or_dir(mntpnt);
	if (fdmnt < 0) {
		fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt);
		return 12;
	}

	for(i=1 ; i < argc - 1; i++ ){
		struct	btrfs_ioctl_vol_args arg;
		int	res;

		strncpy(arg.name, argv[i], BTRFS_PATH_NAME_MAX);
		arg.name[BTRFS_PATH_NAME_MAX-1] = 0;
		res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
		e = errno;
		if(res<0){
			fprintf(stderr, "ERROR: error removing the device '%s' - %s\n",
				argv[i], strerror(e));
			ret++;
		}
	}

	close(fdmnt);
	if( ret)
		return ret+20;
	else
		return 0;
}
コード例 #17
0
ファイル: cmds-subvolume.c プロジェクト: osandov/btrfs-progs
static int cmd_snapshot(int argc, char **argv)
{
	char	*subvol, *dst;
	int	res, retval;
	int	fd = -1, fddst = -1;
	int	len, readonly = 0;
	char	*dupname = NULL;
	char	*dupdir = NULL;
	char	*newname;
	char	*dstdir;
	struct btrfs_ioctl_vol_args_v2	args;
	struct btrfs_qgroup_inherit *inherit = NULL;
	DIR *dirstream1 = NULL, *dirstream2 = NULL;

	optind = 1;
	memset(&args, 0, sizeof(args));
	while (1) {
		int c = getopt(argc, argv, "c:i:r");
		if (c < 0)
			break;

		switch (c) {
		case 'c':
			res = qgroup_inherit_add_copy(&inherit, optarg, 0);
			if (res) {
				retval = res;
				goto out;
			}
			break;
		case 'i':
			res = qgroup_inherit_add_group(&inherit, optarg);
			if (res) {
				retval = res;
				goto out;
			}
			break;
		case 'r':
			readonly = 1;
			break;
		case 'x':
			res = qgroup_inherit_add_copy(&inherit, optarg, 1);
			if (res) {
				retval = res;
				goto out;
			}
			break;
		default:
			usage(cmd_snapshot_usage);
		}
	}

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

	subvol = argv[optind];
	dst = argv[optind + 1];

	retval = 1;	/* failure */
	res = test_issubvolume(subvol);
	if (res < 0) {
		fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
		goto out;
	}
	if (!res) {
		fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
		goto out;
	}

	res = test_isdir(dst);
	if (res == 0) {
		fprintf(stderr, "ERROR: '%s' exists and it is not a directory\n", dst);
		goto out;
	}

	if (res > 0) {
		dupname = strdup(subvol);
		newname = basename(dupname);
		dstdir = dst;
	} else {
		dupname = strdup(dst);
		newname = basename(dupname);
		dupdir = strdup(dst);
		dstdir = dirname(dupdir);
	}

	if (!test_issubvolname(newname)) {
		fprintf(stderr, "ERROR: incorrect snapshot name '%s'\n",
			newname);
		goto out;
	}

	len = strlen(newname);
	if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
		fprintf(stderr, "ERROR: snapshot name too long '%s'\n",
			newname);
		goto out;
	}

	fddst = open_file_or_dir(dstdir, &dirstream1);
	if (fddst < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", dstdir);
		goto out;
	}

	fd = open_file_or_dir(subvol, &dirstream2);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", dstdir);
		goto out;
	}

	if (readonly) {
		args.flags |= BTRFS_SUBVOL_RDONLY;
		printf("Create a readonly snapshot of '%s' in '%s/%s'\n",
		       subvol, dstdir, newname);
	} else {
		printf("Create a snapshot of '%s' in '%s/%s'\n",
		       subvol, dstdir, newname);
	}

	args.fd = fd;
	if (inherit) {
		args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
		args.size = qgroup_inherit_size(inherit);
		args.qgroup_inherit = inherit;
	}
	strncpy_null(args.name, newname);

	res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);

	if (res < 0) {
		fprintf( stderr, "ERROR: cannot snapshot '%s' - %s\n",
			subvol, strerror(errno));
		goto out;
	}

	retval = 0;	/* success */

out:
	close_file_or_dir(fddst, dirstream1);
	close_file_or_dir(fd, dirstream2);
	free(inherit);
	free(dupname);
	free(dupdir);

	return retval;
}
コード例 #18
0
ファイル: cmds-subvolume.c プロジェクト: osandov/btrfs-progs
static int cmd_subvol_list(int argc, char **argv)
{
	struct btrfs_list_filter_set *filter_set;
	struct btrfs_list_comparer_set *comparer_set;
	u64 flags = 0;
	int fd = -1;
	u64 top_id;
	int ret = -1, uerr = 0;
	char *subvol;
	int is_tab_result = 0;
	int is_list_all = 0;
	int is_only_in_path = 0;
	DIR *dirstream = NULL;

	filter_set = btrfs_list_alloc_filter_set();
	comparer_set = btrfs_list_alloc_comparer_set();

	optind = 1;
	while(1) {
		int c;
		static const struct option long_options[] = {
			{"sort", required_argument, NULL, 'S'},
			{NULL, 0, NULL, 0}
		};

		c = getopt_long(argc, argv,
				    "acdgopqsurRG:C:t", long_options, NULL);
		if (c < 0)
			break;

		switch(c) {
		case 'p':
			btrfs_list_setup_print_column(BTRFS_LIST_PARENT);
			break;
		case 'a':
			is_list_all = 1;
			break;
		case 'c':
			btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
			break;
		case 'd':
			btrfs_list_setup_filter(&filter_set,
						BTRFS_LIST_FILTER_DELETED,
						0);
			break;
		case 'g':
			btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
			break;
		case 'o':
			is_only_in_path = 1;
			break;
		case 't':
			is_tab_result = 1;
			break;
		case 's':
			btrfs_list_setup_filter(&filter_set,
						BTRFS_LIST_FILTER_SNAPSHOT_ONLY,
						0);
			btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
			btrfs_list_setup_print_column(BTRFS_LIST_OTIME);
			break;
		case 'u':
			btrfs_list_setup_print_column(BTRFS_LIST_UUID);
			break;
		case 'q':
			btrfs_list_setup_print_column(BTRFS_LIST_PUUID);
			break;
		case 'R':
			btrfs_list_setup_print_column(BTRFS_LIST_RUUID);
			break;
		case 'r':
			flags |= BTRFS_ROOT_SUBVOL_RDONLY;
			break;
		case 'G':
			btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
			ret = btrfs_list_parse_filter_string(optarg,
							&filter_set,
							BTRFS_LIST_FILTER_GEN);
			if (ret) {
				uerr = 1;
				goto out;
			}
			break;

		case 'C':
			btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
			ret = btrfs_list_parse_filter_string(optarg,
							&filter_set,
							BTRFS_LIST_FILTER_CGEN);
			if (ret) {
				uerr = 1;
				goto out;
			}
			break;
		case 'S':
			ret = btrfs_list_parse_sort_string(optarg,
							   &comparer_set);
			if (ret) {
				uerr = 1;
				goto out;
			}
			break;

		default:
			uerr = 1;
			goto out;
		}
	}

	if (flags)
		btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_FLAGS,
					flags);

	if (check_argc_exact(argc - optind, 1)) {
		uerr = 1;
		goto out;
	}

	subvol = argv[optind];
	fd = open_file_or_dir(subvol, &dirstream);
	if (fd < 0) {
		ret = -1;
		fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
		goto out;
	}

	ret = btrfs_list_get_path_rootid(fd, &top_id);
	if (ret) {
		fprintf(stderr, "ERROR: can't get rootid for '%s'\n", subvol);
		goto out;
	}

	if (is_list_all)
		btrfs_list_setup_filter(&filter_set,
					BTRFS_LIST_FILTER_FULL_PATH,
					top_id);
	else if (is_only_in_path)
		btrfs_list_setup_filter(&filter_set,
					BTRFS_LIST_FILTER_TOPID_EQUAL,
					top_id);

	/* by default we shall print the following columns*/
	btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
	btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
	btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
	btrfs_list_setup_print_column(BTRFS_LIST_PATH);

	if (is_tab_result)
		ret = btrfs_list_subvols_print(fd, filter_set, comparer_set,
				BTRFS_LIST_LAYOUT_TABLE,
				!is_list_all && !is_only_in_path, NULL);
	else
		ret = btrfs_list_subvols_print(fd, filter_set, comparer_set,
				BTRFS_LIST_LAYOUT_DEFAULT,
				!is_list_all && !is_only_in_path, NULL);

out:
	close_file_or_dir(fd, dirstream);
	if (filter_set)
		btrfs_list_free_filter_set(filter_set);
	if (comparer_set)
		btrfs_list_free_comparer_set(comparer_set);
	if (uerr)
		usage(cmd_subvol_list_usage);
	return !!ret;
}
コード例 #19
0
ファイル: cmds-subvolume.c プロジェクト: osandov/btrfs-progs
static int cmd_subvol_delete(int argc, char **argv)
{
	int	res, e, ret = 0;
	int cnt;
	int fd = -1;
	struct btrfs_ioctl_vol_args	args;
	char	*dname, *vname, *cpath;
	char	*dupdname = NULL;
	char	*dupvname = NULL;
	char	*path;
	DIR	*dirstream = NULL;
	int verbose = 0;
	int commit_mode = 0;

	optind = 1;
	while (1) {
		int c;
		static const struct option long_options[] = {
			{"commit-after", no_argument, NULL, 'c'},  /* commit mode 1 */
			{"commit-each", no_argument, NULL, 'C'},  /* commit mode 2 */
			{NULL, 0, NULL, 0}
		};

		c = getopt_long(argc, argv, "cC", long_options, NULL);
		if (c < 0)
			break;

		switch(c) {
		case 'c':
			commit_mode = 1;
			break;
		case 'C':
			commit_mode = 2;
			break;
		case 'v':
			verbose++;
			break;
		default:
			usage(cmd_subvol_delete_usage);
		}
	}

	if (check_argc_min(argc - optind, 1))
		usage(cmd_subvol_delete_usage);

	if (verbose > 0) {
		printf("Transaction commit: %s\n",
			!commit_mode ? "none (default)" :
			commit_mode == 1 ? "at the end" : "after each");
	}

	cnt = optind;

again:
	path = argv[cnt];

	res = test_issubvolume(path);
	if (res < 0) {
		fprintf(stderr, "ERROR: error accessing '%s'\n", path);
		ret = 1;
		goto out;
	}
	if (!res) {
		fprintf(stderr, "ERROR: '%s' is not a subvolume\n", path);
		ret = 1;
		goto out;
	}

	cpath = realpath(path, NULL);
	if (!cpath) {
		ret = errno;
		fprintf(stderr, "ERROR: finding real path for '%s': %s\n",
			path, strerror(errno));
		goto out;
	}
	dupdname = strdup(cpath);
	dname = dirname(dupdname);
	dupvname = strdup(cpath);
	vname = basename(dupvname);
	free(cpath);

	fd = open_file_or_dir(dname, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", dname);
		ret = 1;
		goto out;
	}

	printf("Delete subvolume (%s): '%s/%s'\n",
		commit_mode == 2 || (commit_mode == 1 && cnt + 1 == argc)
		? "commit" : "no-commit", dname, vname);
	memset(&args, 0, sizeof(args));
	strncpy_null(args.name, vname);
	res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
	e = errno;

	if(res < 0 ){
		fprintf( stderr, "ERROR: cannot delete '%s/%s' - %s\n",
			dname, vname, strerror(e));
		ret = 1;
		goto out;
	}

	if (commit_mode == 1) {
		res = wait_for_commit(fd);
		if (res < 0) {
			fprintf(stderr,
				"ERROR: unable to wait for commit after '%s': %s\n",
				path, strerror(errno));
			ret = 1;
		}
	}

out:
	free(dupdname);
	free(dupvname);
	dupdname = NULL;
	dupvname = NULL;
	cnt++;
	if (cnt < argc) {
		close_file_or_dir(fd, dirstream);
		/* avoid double free */
		fd = -1;
		dirstream = NULL;
		goto again;
	}

	if (commit_mode == 2 && fd != -1) {
		res = wait_for_commit(fd);
		if (res < 0) {
			fprintf(stderr,
				"ERROR: unable to do final sync: %s\n",
				strerror(errno));
			ret = 1;
		}
	}
	close_file_or_dir(fd, dirstream);

	return ret;
}
コード例 #20
0
ファイル: cmds-subvolume.c プロジェクト: osandov/btrfs-progs
static int cmd_subvol_sync(int argc, char **argv)
{
	int fd = -1;
	int i;
	int ret = 1;
	DIR *dirstream = NULL;
	u64 *ids = NULL;
	int id_count;
	int sleep_interval = 1;

	optind = 1;
	while (1) {
		int c = getopt(argc, argv, "s:");

		if (c < 0)
			break;

		switch (c) {
		case 's':
			sleep_interval = atoi(argv[optind]);
			if (sleep_interval < 1) {
				fprintf(stderr,
					"ERROR: invalid sleep interval %s\n",
					argv[optind]);
				ret = 1;
				goto out;
			}
			break;
		default:
			usage(cmd_subvol_sync_usage);
		}
	}

	if (check_argc_min(argc - optind, 1))
		usage(cmd_subvol_sync_usage);

	fd = open_file_or_dir(argv[optind], &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind]);
		ret = 1;
		goto out;
	}
	optind++;

	id_count = argc - optind;
	if (!id_count) {
		id_count = SUBVOL_ID_BATCH;
		ids = (u64*)malloc(id_count * sizeof(u64));
		if (!ids) {
			fprintf(stderr, "ERROR: not enough memory\n");
			ret = 1;
			goto out;
		}
		id_count = enumerate_dead_subvols(fd, id_count, &ids);
		if (id_count < 0) {
			fprintf(stderr, "ERROR: can't enumerate dead subvolumes: %s\n",
					strerror(-id_count));
			ret = 1;
			goto out;
		}
		if (id_count == 0) {
			ret = 0;
			goto out;
		}
	} else {
		ids = (u64*)malloc(id_count * sizeof(u64));
		if (!ids) {
			fprintf(stderr, "ERROR: not enough memory\n");
			ret = 1;
			goto out;
		}

		for (i = 0; i < id_count; i++) {
			u64 id;
			const char *arg;

			arg = argv[optind + i];
			errno = 0;
			id = strtoull(arg, NULL, 10);
			if (errno < 0) {
				fprintf(stderr,
					"ERROR: unrecognized subvolume id %s\n",
					arg);
				ret = 1;
				goto out;
			}
			if (id < BTRFS_FIRST_FREE_OBJECTID
					|| id > BTRFS_LAST_FREE_OBJECTID) {
				fprintf(stderr,
					"ERROR: subvolume id %s out of range\n",
					arg);
				ret = 1;
				goto out;
			}
			ids[i] = id;
		}
	}

	ret = wait_for_subvolume_cleaning(fd, id_count, ids, sleep_interval);

out:
	free(ids);
	close_file_or_dir(fd, dirstream);

	return !!ret;
}
コード例 #21
0
ファイル: cmds-subvolume.c プロジェクト: osandov/btrfs-progs
static int cmd_subvol_create(int argc, char **argv)
{
	int	retval, res, len;
	int	fddst = -1;
	char	*dupname = NULL;
	char	*dupdir = NULL;
	char	*newname;
	char	*dstdir;
	char	*dst;
	struct btrfs_qgroup_inherit *inherit = NULL;
	DIR	*dirstream = NULL;

	optind = 1;
	while (1) {
		int c = getopt(argc, argv, "c:i:v");
		if (c < 0)
			break;

		switch (c) {
		case 'c':
			res = qgroup_inherit_add_copy(&inherit, optarg, 0);
			if (res) {
				retval = res;
				goto out;
			}
			break;
		case 'i':
			res = qgroup_inherit_add_group(&inherit, optarg);
			if (res) {
				retval = res;
				goto out;
			}
			break;
		default:
			usage(cmd_subvol_create_usage);
		}
	}

	if (check_argc_exact(argc - optind, 1))
		usage(cmd_subvol_create_usage);

	dst = argv[optind];

	retval = 1;	/* failure */
	res = test_isdir(dst);
	if (res >= 0) {
		fprintf(stderr, "ERROR: '%s' exists\n", dst);
		goto out;
	}

	dupname = strdup(dst);
	newname = basename(dupname);
	dupdir = strdup(dst);
	dstdir = dirname(dupdir);

	if (!test_issubvolname(newname)) {
		fprintf(stderr, "ERROR: incorrect subvolume name '%s'\n",
			newname);
		goto out;
	}

	len = strlen(newname);
	if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
		fprintf(stderr, "ERROR: subvolume name too long '%s'\n",
			newname);
		goto out;
	}

	fddst = open_file_or_dir(dstdir, &dirstream);
	if (fddst < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", dstdir);
		goto out;
	}

	printf("Create subvolume '%s/%s'\n", dstdir, newname);
	if (inherit) {
		struct btrfs_ioctl_vol_args_v2	args;

		memset(&args, 0, sizeof(args));
		strncpy_null(args.name, newname);
		args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
		args.size = qgroup_inherit_size(inherit);
		args.qgroup_inherit = inherit;

		res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE_V2, &args);
	} else {
		struct btrfs_ioctl_vol_args	args;

		memset(&args, 0, sizeof(args));
		strncpy_null(args.name, newname);

		res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
	}

	if (res < 0) {
		fprintf(stderr, "ERROR: cannot create subvolume - %s\n",
			strerror(errno));
		goto out;
	}

	retval = 0;	/* success */
out:
	close_file_or_dir(fddst, dirstream);
	free(inherit);
	free(dupname);
	free(dupdir);

	return retval;
}
コード例 #22
0
static int scrub_start(int argc, char **argv, int resume)
{
	int fdmnt;
	int prg_fd = -1;
	int fdres = -1;
	int ret;
	pid_t pid;
	int c;
	int i;
	int err = 0;
	int e_uncorrectable = 0;
	int e_correctable = 0;
	int print_raw = 0;
	char *path;
	int do_background = 1;
	int do_wait = 0;
	int do_print = 0;
	int do_quiet = 0;
	int do_record = 1;
	int readonly = 0;
	int do_stats_per_dev = 0;
	int ioprio_class = IOPRIO_CLASS_IDLE;
	int ioprio_classdata = 0;
	int n_start = 0;
	int n_skip = 0;
	int n_resume = 0;
	struct btrfs_ioctl_fs_info_args fi_args;
	struct btrfs_ioctl_dev_info_args *di_args = NULL;
	struct scrub_progress *sp = NULL;
	struct scrub_fs_stat fs_stat;
	struct timeval tv;
	struct sockaddr_un addr = {
		.sun_family = AF_UNIX,
	};
	pthread_t *t_devs = NULL;
	pthread_t t_prog;
	pthread_attr_t t_attr;
	struct scrub_file_record **past_scrubs = NULL;
	struct scrub_file_record *last_scrub = NULL;
	char *datafile = strdup(SCRUB_DATA_FILE);
	char fsid[37];
	char sock_path[BTRFS_PATH_NAME_MAX + 1] = "";
	struct scrub_progress_cycle spc;
	pthread_mutex_t spc_write_mutex = PTHREAD_MUTEX_INITIALIZER;
	void *terr;
	u64 devid;

	optind = 1;
	while ((c = getopt(argc, argv, "BdqrRc:n:")) != -1) {
		switch (c) {
		case 'B':
			do_background = 0;
			do_wait = 1;
			do_print = 1;
			break;
		case 'd':
			do_stats_per_dev = 1;
			break;
		case 'q':
			do_quiet = 1;
			break;
		case 'r':
			readonly = 1;
			break;
		case 'R':
			print_raw = 1;
			break;
		case 'c':
			ioprio_class = (int)strtol(optarg, NULL, 10);
			break;
		case 'n':
			ioprio_classdata = (int)strtol(optarg, NULL, 10);
			break;
		case '?':
		default:
			usage(resume ? cmd_scrub_resume_usage :
						cmd_scrub_start_usage);
		}
	}

	/* try to catch most error cases before forking */

	if (check_argc_exact(argc - optind, 1)) {
		usage(resume ? cmd_scrub_resume_usage :
					cmd_scrub_start_usage);
	}

	spc.progress = NULL;
	if (do_quiet && do_print)
		do_print = 0;

	if (mkdir_p(datafile)) {
		ERR(!do_quiet, "WARNING: cannot create scrub data "
			       "file, mkdir %s failed: %s. Status recording "
			       "disabled\n", datafile, strerror(errno));
		do_record = 0;
	}
	free(datafile);

	path = argv[optind];

	fdmnt = open_file_or_dir(path);
	if (fdmnt < 0) {
		ERR(!do_quiet, "ERROR: can't access '%s'\n", path);
		return 12;
	}

	ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
	if (ret) {
		ERR(!do_quiet, "ERROR: getting dev info for scrub failed: "
		    "%s\n", strerror(-ret));
		err = 1;
		goto out;
	}
	if (!fi_args.num_devices) {
		ERR(!do_quiet, "ERROR: no devices found\n");
		err = 1;
		goto out;
	}

	uuid_unparse(fi_args.fsid, fsid);
	fdres = scrub_open_file_r(SCRUB_DATA_FILE, fsid);
	if (fdres < 0 && fdres != -ENOENT) {
		ERR(!do_quiet, "WARNING: failed to open status file: "
		    "%s\n", strerror(-fdres));
	} else if (fdres >= 0) {
		past_scrubs = scrub_read_file(fdres, !do_quiet);
		if (IS_ERR(past_scrubs))
			ERR(!do_quiet, "WARNING: failed to read status file: "
			    "%s\n", strerror(-PTR_ERR(past_scrubs)));
		close(fdres);
	}

	t_devs = malloc(fi_args.num_devices * sizeof(*t_devs));
	sp = calloc(fi_args.num_devices, sizeof(*sp));
	spc.progress = calloc(fi_args.num_devices * 2, sizeof(*spc.progress));

	if (!t_devs || !sp || !spc.progress) {
		ERR(!do_quiet, "ERROR: scrub failed: %s", strerror(errno));
		err = 1;
		goto out;
	}

	ret = pthread_attr_init(&t_attr);
	if (ret) {
		ERR(!do_quiet, "ERROR: pthread_attr_init failed: %s\n",
		    strerror(ret));
		err = 1;
		goto out;
	}

	for (i = 0; i < fi_args.num_devices; ++i) {
		devid = di_args[i].devid;
		ret = pthread_mutex_init(&sp[i].progress_mutex, NULL);
		if (ret) {
			ERR(!do_quiet, "ERROR: pthread_mutex_init failed: "
			    "%s\n", strerror(ret));
			err = 1;
			goto out;
		}
		last_scrub = last_dev_scrub(past_scrubs, devid);
		sp[i].scrub_args.devid = devid;
		sp[i].fd = fdmnt;
		if (resume && last_scrub && (last_scrub->stats.canceled ||
					     !last_scrub->stats.finished)) {
			++n_resume;
			sp[i].scrub_args.start = last_scrub->p.last_physical;
			sp[i].resumed = last_scrub;
		} else if (resume) {
			++n_skip;
			sp[i].skip = 1;
			sp[i].resumed = last_scrub;
			continue;
		} else {
			++n_start;
			sp[i].scrub_args.start = 0ll;
			sp[i].resumed = NULL;
		}
		sp[i].skip = 0;
		sp[i].scrub_args.end = (u64)-1ll;
		sp[i].scrub_args.flags = readonly ? BTRFS_SCRUB_READONLY : 0;
		sp[i].ioprio_class = ioprio_class;
		sp[i].ioprio_classdata = ioprio_classdata;
	}

	if (!n_start && !n_resume) {
		if (!do_quiet)
			printf("scrub: nothing to resume for %s, fsid %s\n",
			       path, fsid);
		err = 0;
		goto out;
	}

	ret = prg_fd = socket(AF_UNIX, SOCK_STREAM, 0);
	while (ret != -1) {
		ret = scrub_datafile(SCRUB_PROGRESS_SOCKET_PATH, fsid, NULL,
					sock_path, sizeof(sock_path));
		/* ignore EOVERFLOW, try using a shorter path for the socket */
		addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
		strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);
		ret = bind(prg_fd, (struct sockaddr *)&addr, sizeof(addr));
		if (ret != -1 || errno != EADDRINUSE)
			break;
		/*
		 * bind failed with EADDRINUSE. so let's see if anyone answers
		 * when we make a call to the socket ...
		 */
		ret = connect(prg_fd, (struct sockaddr *)&addr, sizeof(addr));
		if (!ret || errno != ECONNREFUSED) {
			/* ... yes, so scrub must be running. error out */
			fprintf(stderr, "ERROR: scrub already running\n");
			close(prg_fd);
			goto out;
		}
		/*
		 * ... no, this means someone left us alone with an unused
		 * socket in the file system. remove it and try again.
		 */
		ret = unlink(sock_path);
	}
	if (ret != -1)
		ret = listen(prg_fd, 100);
	if (ret == -1) {
		ERR(!do_quiet, "WARNING: failed to open the progress status "
		    "socket at %s: %s. Progress cannot be queried\n",
		    sock_path[0] ? sock_path : SCRUB_PROGRESS_SOCKET_PATH,
		    strerror(errno));
		if (prg_fd != -1) {
			close(prg_fd);
			prg_fd = -1;
			if (sock_path[0])
				unlink(sock_path);
		}
	}

	if (do_record) {
		/* write all-zero progress file for a start */
		ret = scrub_write_progress(&spc_write_mutex, fsid, sp,
					   fi_args.num_devices);
		if (ret) {
			ERR(!do_quiet, "WARNING: failed to write the progress "
			    "status file: %s. Status recording disabled\n",
			    strerror(-ret));
			do_record = 0;
		}
	}

	if (do_background) {
		pid = fork();
		if (pid == -1) {
			ERR(!do_quiet, "ERROR: cannot scrub, fork failed: "
					"%s\n", strerror(errno));
			err = 1;
			goto out;
		}

		if (pid) {
			int stat;
			scrub_handle_sigint_parent();
			if (!do_quiet)
				printf("scrub %s on %s, fsid %s (pid=%d)\n",
				       n_start ? "started" : "resumed",
				       path, fsid, pid);
			if (!do_wait) {
				err = 0;
				goto out;
			}
			ret = wait(&stat);
			if (ret != pid) {
				ERR(!do_quiet, "ERROR: wait failed: (ret=%d) "
				    "%s\n", ret, strerror(errno));
				err = 1;
				goto out;
			}
			if (!WIFEXITED(stat) || WEXITSTATUS(stat)) {
				ERR(!do_quiet, "ERROR: scrub process failed\n");
				err = WIFEXITED(stat) ? WEXITSTATUS(stat) : -1;
				goto out;
			}
			err = 0;
			goto out;
		}
	}

	scrub_handle_sigint_child(fdmnt);

	for (i = 0; i < fi_args.num_devices; ++i) {
		if (sp[i].skip) {
			sp[i].scrub_args.progress = sp[i].resumed->p;
			sp[i].stats = sp[i].resumed->stats;
			sp[i].ret = 0;
			sp[i].stats.finished = 1;
			continue;
		}
		devid = di_args[i].devid;
		gettimeofday(&tv, NULL);
		sp[i].stats.t_start = tv.tv_sec;
		ret = pthread_create(&t_devs[i], &t_attr,
					scrub_one_dev, &sp[i]);
		if (ret) {
			if (do_print)
				fprintf(stderr, "ERROR: creating "
					"scrub_one_dev[%llu] thread failed: "
					"%s\n", devid, strerror(ret));
			err = 1;
			goto out;
		}
	}

	spc.fdmnt = fdmnt;
	spc.prg_fd = prg_fd;
	spc.do_record = do_record;
	spc.write_mutex = &spc_write_mutex;
	spc.shared_progress = sp;
	spc.fi = &fi_args;
	ret = pthread_create(&t_prog, &t_attr, scrub_progress_cycle, &spc);
	if (ret) {
		if (do_print)
			fprintf(stderr, "ERROR: creating progress thread "
				"failed: %s\n", strerror(ret));
		err = 1;
		goto out;
	}

	err = 0;
	for (i = 0; i < fi_args.num_devices; ++i) {
		if (sp[i].skip)
			continue;
		devid = di_args[i].devid;
		ret = pthread_join(t_devs[i], NULL);
		if (ret) {
			if (do_print)
				fprintf(stderr, "ERROR: pthread_join failed "
					"for scrub_one_dev[%llu]: %s\n", devid,
					strerror(ret));
			++err;
			continue;
		}
		if (sp[i].ret && sp[i].ioctl_errno == ENODEV) {
			if (do_print)
				fprintf(stderr, "WARNING: device %lld not "
					"present\n", devid);
			continue;
		}
		if (sp[i].ret && sp[i].ioctl_errno == ECANCELED) {
			++err;
		} else if (sp[i].ret) {
			if (do_print)
				fprintf(stderr, "ERROR: scrubbing %s failed "
					"for device id %lld (%s)\n", path,
					devid, strerror(sp[i].ioctl_errno));
			++err;
			continue;
		}
		if (sp[i].scrub_args.progress.uncorrectable_errors > 0)
			e_uncorrectable++;
		if (sp[i].scrub_args.progress.corrected_errors > 0
		    || sp[i].scrub_args.progress.unverified_errors > 0)
			e_correctable++;
	}

	if (do_print) {
		const char *append = "done";
		if (!do_stats_per_dev)
			init_fs_stat(&fs_stat);
		for (i = 0; i < fi_args.num_devices; ++i) {
			if (do_stats_per_dev) {
				print_scrub_dev(&di_args[i],
						&sp[i].scrub_args.progress,
						print_raw,
						sp[i].ret ? "canceled" : "done",
						&sp[i].stats);
			} else {
				if (sp[i].ret)
					append = "canceled";
				add_to_fs_stat(&sp[i].scrub_args.progress,
						&sp[i].stats, &fs_stat);
			}
		}
		if (!do_stats_per_dev) {
			printf("scrub %s for %s\n", append, fsid);
			print_fs_stat(&fs_stat, print_raw);
		}
	}

	ret = pthread_cancel(t_prog);
	if (!ret)
		ret = pthread_join(t_prog, &terr);
	if (do_print && ret) {
		fprintf(stderr, "ERROR: progress thead handling failed: %s\n",
			strerror(ret));
	}

	if (do_print && terr && terr != PTHREAD_CANCELED) {
		fprintf(stderr, "ERROR: recording progress "
			"failed: %s\n", strerror(-PTR_ERR(terr)));
	}

	if (do_record) {
		ret = scrub_write_progress(&spc_write_mutex, fsid, sp,
					   fi_args.num_devices);
		if (ret && do_print) {
			fprintf(stderr, "ERROR: failed to record the result: "
				"%s\n", strerror(-ret));
		}
	}

	scrub_handle_sigint_child(-1);

out:
	free_history(past_scrubs);
	free(di_args);
	free(t_devs);
	free(sp);
	free(spc.progress);
	if (prg_fd > -1) {
		close(prg_fd);
		if (sock_path[0])
			unlink(sock_path);
	}
	close(fdmnt);

	if (err)
		return 1;
	if (e_correctable)
		return 7;
	if (e_uncorrectable)
		return 8;
	return 0;
}
コード例 #23
0
static int cmd_scrub_status(int argc, char **argv)
{
	char *path;
	struct btrfs_ioctl_fs_info_args fi_args;
	struct btrfs_ioctl_dev_info_args *di_args = NULL;
	struct scrub_file_record **past_scrubs = NULL;
	struct scrub_file_record *last_scrub;
	struct scrub_fs_stat fs_stat;
	struct sockaddr_un addr = {
		.sun_family = AF_UNIX,
	};
	int ret;
	int fdmnt;
	int i;
	int print_raw = 0;
	int do_stats_per_dev = 0;
	char c;
	char fsid[37];
	int fdres = -1;
	int err = 0;

	optind = 1;
	while ((c = getopt(argc, argv, "dR")) != -1) {
		switch (c) {
		case 'd':
			do_stats_per_dev = 1;
			break;
		case 'R':
			print_raw = 1;
			break;
		case '?':
		default:
			usage(cmd_scrub_status_usage);
		}
	}

	if (check_argc_exact(argc - optind, 1))
		usage(cmd_scrub_status_usage);

	path = argv[optind];

	fdmnt = open_file_or_dir(path);
	if (fdmnt < 0) {
		fprintf(stderr, "ERROR: can't access to '%s'\n", path);
		return 12;
	}

	ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
	if (ret) {
		fprintf(stderr, "ERROR: getting dev info for scrub failed: "
				"%s\n", strerror(-ret));
		err = 1;
		goto out;
	}
	if (!fi_args.num_devices) {
		fprintf(stderr, "ERROR: no devices found\n");
		err = 1;
		goto out;
	}

	uuid_unparse(fi_args.fsid, fsid);

	fdres = socket(AF_UNIX, SOCK_STREAM, 0);
	if (fdres == -1) {
		fprintf(stderr, "ERROR: failed to create socket to "
			"receive progress information: %s\n",
			strerror(errno));
		err = 1;
		goto out;
	}
	scrub_datafile(SCRUB_PROGRESS_SOCKET_PATH, fsid,
			NULL, addr.sun_path, sizeof(addr.sun_path));
	/* ignore EOVERFLOW, just use shorter name and hope for the best */
	addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
	ret = connect(fdres, (struct sockaddr *)&addr, sizeof(addr));
	if (ret == -1) {
		fdres = scrub_open_file_r(SCRUB_DATA_FILE, fsid);
		if (fdres < 0 && fdres != -ENOENT) {
			fprintf(stderr, "WARNING: failed to open status file: "
				"%s\n", strerror(-fdres));
			err = 1;
			goto out;
		}
	}

	if (fdres >= 0) {
		past_scrubs = scrub_read_file(fdres, 1);
		if (IS_ERR(past_scrubs))
			fprintf(stderr, "WARNING: failed to read status: %s\n",
				strerror(-PTR_ERR(past_scrubs)));
	}

	printf("scrub status for %s\n", fsid);

	if (do_stats_per_dev) {
		for (i = 0; i < fi_args.num_devices; ++i) {
			last_scrub = last_dev_scrub(past_scrubs,
							di_args[i].devid);
			if (!last_scrub) {
				print_scrub_dev(&di_args[i], NULL, print_raw,
						NULL, NULL);
				continue;
			}
			print_scrub_dev(&di_args[i], &last_scrub->p, print_raw,
					last_scrub->stats.finished ?
							"history" : "status",
					&last_scrub->stats);
		}
	} else {
		init_fs_stat(&fs_stat);
		for (i = 0; i < fi_args.num_devices; ++i) {
			last_scrub = last_dev_scrub(past_scrubs,
							di_args[i].devid);
			if (!last_scrub)
				continue;
			add_to_fs_stat(&last_scrub->p, &last_scrub->stats,
					&fs_stat);
		}
		print_fs_stat(&fs_stat, print_raw);
	}

out:
	free_history(past_scrubs);
	free(di_args);
	close(fdmnt);
	if (fdres > -1)
		close(fdres);

	return err;
}
コード例 #24
0
ファイル: cmds-quota.c プロジェクト: osandov/btrfs-progs
static int cmd_quota_rescan(int argc, char **argv)
{
	int ret = 0;
	int fd;
	int e;
	char *path = NULL;
	struct btrfs_ioctl_quota_rescan_args args;
	unsigned long ioctlnum = BTRFS_IOC_QUOTA_RESCAN;
	DIR *dirstream = NULL;
	int wait_for_completion = 0;

	optind = 1;
	while (1) {
		int c = getopt(argc, argv, "sw");
		if (c < 0)
			break;
		switch (c) {
		case 's':
			ioctlnum = BTRFS_IOC_QUOTA_RESCAN_STATUS;
			break;
		case 'w':
			wait_for_completion = 1;
			break;
		default:
			usage(cmd_quota_rescan_usage);
		}
	}

	if (ioctlnum != BTRFS_IOC_QUOTA_RESCAN && wait_for_completion) {
		fprintf(stderr, "ERROR: -w cannot be used with -s\n");
		return 1;
	}

	if (check_argc_exact(argc - optind, 1))
		usage(cmd_quota_rescan_usage);

	memset(&args, 0, sizeof(args));

	path = argv[optind];
	fd = open_file_or_dir(path, &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", path);
		return 1;
	}

	ret = ioctl(fd, ioctlnum, &args);
	e = errno;

	if (wait_for_completion && (ret == 0 || e == EINPROGRESS)) {
		ret = ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT, &args);
		e = errno;
	}
	close_file_or_dir(fd, dirstream);

	if (ioctlnum == BTRFS_IOC_QUOTA_RESCAN) {
		if (ret < 0) {
			fprintf(stderr, "ERROR: quota rescan failed: "
				"%s\n", strerror(e));
			return 1;
		}  else {
			printf("quota rescan started\n");
		}
	} else {
		if (!args.flags) {
			printf("no rescan operation in progress\n");
		} else {
			printf("rescan operation running (current key %lld)\n",
				args.progress);
		}
	}

	return 0;
}
コード例 #25
0
ファイル: cmds-fi-usage.c プロジェクト: asj/btrfs-progs
int cmd_filesystem_usage(int argc, char **argv)
{
	int ret = 0;
	unsigned unit_mode;
	int i;
	int more_than_one = 0;
	int tabular = 0;

	unit_mode = get_unit_mode_from_arg(&argc, argv, 1);

	optind = 1;
	while (1) {
		int c;

		c = getopt(argc, argv, "T");
		if (c < 0)
			break;

		switch (c) {
		case 'T':
			tabular = 1;
			break;
		default:
			usage(cmd_filesystem_usage_usage);
		}
	}

	if (check_argc_min(argc - optind, 1))
		usage(cmd_filesystem_usage_usage);

	for (i = optind; i < argc; i++) {
		int fd;
		DIR *dirstream = NULL;
		struct chunk_info *chunkinfo = NULL;
		struct device_info *devinfo = NULL;
		int chunkcount = 0;
		int devcount = 0;

		fd = open_file_or_dir(argv[i], &dirstream);
		if (fd < 0) {
			fprintf(stderr, "ERROR: can't access '%s'\n",
				argv[i]);
			ret = 1;
			goto out;
		}
		if (more_than_one)
			printf("\n");

		ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount,
				&devinfo, &devcount);
		if (ret)
			goto cleanup;

		ret = print_filesystem_usage_overall(fd, chunkinfo, chunkcount,
				devinfo, devcount, argv[i], unit_mode);
		if (ret)
			goto cleanup;
		printf("\n");
		ret = print_filesystem_usage_by_chunk(fd, chunkinfo, chunkcount,
				devinfo, devcount, argv[i], unit_mode, tabular);
cleanup:
		close_file_or_dir(fd, dirstream);
		free(chunkinfo);
		free(devinfo);

		if (ret)
			goto out;
		more_than_one = 1;
	}

out:
	return !!ret;
}
コード例 #26
0
static int cmd_subvol_sync(int argc, char **argv)
{
	int fd = -1;
	int i;
	int ret = 1;
	DIR *dirstream = NULL;
	u64 *ids = NULL;
	int id_count;
	int remaining;
	int sleep_interval = 1;

	optind = 1;
	while (1) {
		int c = getopt(argc, argv, "s:");

		if (c < 0)
			break;

		switch (c) {
		case 's':
			sleep_interval = atoi(argv[optind]);
			if (sleep_interval < 1) {
				fprintf(stderr,
					"ERROR: invalid sleep interval %s\n",
					argv[optind]);
				ret = 1;
				goto out;
			}
			break;
		default:
			usage(cmd_subvol_sync_usage);
		}
	}

	if (check_argc_min(argc - optind, 1))
		usage(cmd_subvol_sync_usage);

	fd = open_file_or_dir(argv[optind], &dirstream);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind]);
		ret = 1;
		goto out;
	}
	optind++;

	id_count = argc - optind;

	/*
	 * Wait for all
	 */
	if (!id_count) {
		while (1) {
			ret = fs_has_dead_subvolumes(fd);
			if (ret < 0) {
				fprintf(stderr, "ERROR: can't perform the search - %s\n",
						strerror(-ret));
				ret = 1;
				goto out;
			}
			if (!ret)
				goto out;
			sleep(sleep_interval);
		}
	}

	/*
	 * Wait only for the requested ones
	 */
	ids = (u64*)malloc(sizeof(u64) * id_count);

	if (!ids) {
		fprintf(stderr, "ERROR: not enough memory\n");
		ret = 1;
		goto out;
	}

	for (i = 0; i < id_count; i++) {
		u64 id;
		const char *arg;

		arg = argv[optind + i];
		errno = 0;
		id = strtoull(arg, NULL, 10);
		if (errno < 0) {
			fprintf(stderr, "ERROR: unrecognized subvolume id %s\n",
				arg);
			ret = 1;
			goto out;
		}
		if (id < BTRFS_FIRST_FREE_OBJECTID || id > BTRFS_LAST_FREE_OBJECTID) {
			fprintf(stderr, "ERROR: subvolume id %s out of range\n",
				arg);
			ret = 1;
			goto out;
		}
		ids[i] = id;
	}

	remaining = id_count;
	while (1) {
		for (i = 0; i < id_count; i++) {
			if (!ids[i])
				continue;
			ret = is_subvolume_cleaned(fd, ids[i]);
			if (ret < 0) {
				fprintf(stderr, "ERROR: can't perform the search - %s\n",
						strerror(-ret));
				goto out;
			}
			if (ret) {
				printf("Subvolume id %llu is gone\n", ids[i]);
				ids[i] = 0;
				remaining--;
			}
		}
		if (!remaining)
			break;
		sleep(sleep_interval);
	}

out:
	free(ids);
	close_file_or_dir(fd, dirstream);

	return !!ret;
}
コード例 #27
0
ファイル: cmds-balance.c プロジェクト: chyyuu/ski-fsstress
/* Checks the status of the balance if any
 * return codes:
 *   2 : Error failed to know if there is any pending balance
 *   1 : Successful to know status of a pending balance
 *   0 : When there is no pending balance or completed
 */
static int cmd_balance_status(int argc, char **argv)
{
	struct btrfs_ioctl_balance_args args;
	const char *path;
	int fd;
	int verbose = 0;
	int ret;
	int e;

	optind = 1;
	while (1) {
		int longindex;
		static struct option longopts[] = {
			{ "verbose", no_argument, NULL, 'v' },
			{ 0, 0, 0, 0}
		};

		int opt = getopt_long(argc, argv, "v", longopts, &longindex);
		if (opt < 0)
			break;

		switch (opt) {
		case 'v':
			verbose = 1;
			break;
		default:
			usage(cmd_balance_status_usage);
		}
	}

	if (check_argc_exact(argc - optind, 1))
		usage(cmd_balance_status_usage);

	path = argv[optind];

	fd = open_file_or_dir(path);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access to '%s'\n", path);
		return 2;
	}

	ret = ioctl(fd, BTRFS_IOC_BALANCE_PROGRESS, &args);
	e = errno;
	close(fd);

	if (ret < 0) {
		if (e == ENOTCONN) {
			printf("No balance found on '%s'\n", path);
			return 0;
		}
		fprintf(stderr, "ERROR: balance status on '%s' failed - %s\n",
			path, strerror(e));
		return 2;
	}

	if (args.state & BTRFS_BALANCE_STATE_RUNNING) {
		printf("Balance on '%s' is running", path);
		if (args.state & BTRFS_BALANCE_STATE_CANCEL_REQ)
			printf(", cancel requested\n");
		else if (args.state & BTRFS_BALANCE_STATE_PAUSE_REQ)
			printf(", pause requested\n");
		else
			printf("\n");
	} else {
		printf("Balance on '%s' is paused\n", path);
	}

	printf("%llu out of about %llu chunks balanced (%llu considered), "
	       "%3.f%% left\n", (unsigned long long)args.stat.completed,
	       (unsigned long long)args.stat.expected,
	       (unsigned long long)args.stat.considered,
	       100 * (1 - (float)args.stat.completed/args.stat.expected));

	if (verbose)
		dump_ioctl_balance_args(&args);

	return 1;
}
コード例 #28
0
ファイル: cmds-replace.c プロジェクト: AK47POMA/btrfs-progs
static int dev_replace_handle_sigint(int fd)
{
	struct sigaction sa = {
		.sa_handler = fd == -1 ? SIG_DFL : dev_replace_sigint_handler
	};

	dev_replace_cancel_fd = fd;
	return sigaction(SIGINT, &sa, NULL);
}

static const char *const cmd_start_replace_usage[] = {
	"btrfs replace start srcdev|devid targetdev [-Bfr] mount_point",
	"Replace device of a btrfs filesystem.",
	"On a live filesystem, duplicate the data to the target device which",
	"is currently stored on the source device. If the source device is not",
	"available anymore, or if the -r option is set, the data is built",
	"only using the RAID redundancy mechanisms. After completion of the",
	"operation, the source device is removed from the filesystem.",
	"If the srcdev is a numerical value, it is assumed to be the device id",
	"of the filesystem which is mounted at mount_point, otherwise it is",
	"the path to the source device. If the source device is disconnected,",
	"from the system, you have to use the devid parameter format.",
	"The targetdev needs to be same size or larger than the srcdev.",
	"",
	"-r     only read from srcdev if no other zero-defect mirror exists",
	"       (enable this if your drive has lots of read errors, the access",
	"       would be very slow)",
	"-f     force using and overwriting targetdev even if it looks like",
	"       containing a valid btrfs filesystem. A valid filesystem is",
	"       assumed if a btrfs superblock is found which contains a",
	"       correct checksum. Devices which are currently mounted are",
	"       never allowed to be used as the targetdev",
	"-B     do not background",
	NULL
};

static int cmd_start_replace(int argc, char **argv)
{
	struct btrfs_ioctl_dev_replace_args start_args = {0};
	struct btrfs_ioctl_dev_replace_args status_args = {0};
	int ret;
	int i;
	int c;
	int fdmnt = -1;
	int fdsrcdev = -1;
	int fddstdev = -1;
	char *path;
	char *srcdev;
	char *dstdev;
	int avoid_reading_from_srcdev = 0;
	int force_using_targetdev = 0;
	u64 total_devs = 1;
	struct btrfs_fs_devices *fs_devices_mnt = NULL;
	struct stat st;
	u64 dstdev_block_count;
	int do_not_background = 0;
	int mixed = 0;

	while ((c = getopt(argc, argv, "Brf")) != -1) {
		switch (c) {
		case 'B':
			do_not_background = 1;
			break;
		case 'r':
			avoid_reading_from_srcdev = 1;
			break;
		case 'f':
			force_using_targetdev = 1;
			break;
		case '?':
		default:
			usage(cmd_start_replace_usage);
		}
	}

	start_args.start.cont_reading_from_srcdev_mode =
		avoid_reading_from_srcdev ?
		 BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID :
		 BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS;
	if (check_argc_exact(argc - optind, 3))
		usage(cmd_start_replace_usage);
	path = argv[optind + 2];

	fdmnt = open_path_or_dev_mnt(path);

	if (fdmnt < 0) {
		fprintf(stderr, "ERROR: can't access \"%s\": %s\n",
			path, strerror(errno));
		goto leave_with_error;
	}

	/* check for possible errors before backgrounding */
	status_args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS;
	ret = ioctl(fdmnt, BTRFS_IOC_DEV_REPLACE, &status_args);
	if (ret) {
		fprintf(stderr,
			"ERROR: ioctl(DEV_REPLACE_STATUS) failed on \"%s\": %s, %s\n",
			path, strerror(errno),
			replace_dev_result2string(status_args.result));
		goto leave_with_error;
	}

	if (status_args.result != BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR) {
		fprintf(stderr,
			"ERROR: ioctl(DEV_REPLACE_STATUS) on \"%s\" returns error: %s\n",
			path, replace_dev_result2string(status_args.result));
		goto leave_with_error;
	}

	if (status_args.status.replace_state ==
	    BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED) {
		fprintf(stderr,
			"ERROR: btrfs replace on \"%s\" already started!\n",
			path);
		goto leave_with_error;
	}

	srcdev = argv[optind];
	dstdev = argv[optind + 1];

	if (is_numerical(srcdev)) {
		struct btrfs_ioctl_fs_info_args fi_args;
		struct btrfs_ioctl_dev_info_args *di_args = NULL;

		if (atoi(srcdev) == 0) {
			fprintf(stderr, "Error: Failed to parse the numerical devid value '%s'\n",
				srcdev);
			goto leave_with_error;
		}
		start_args.start.srcdevid = (__u64)atoi(srcdev);

		ret = get_fs_info(path, &fi_args, &di_args);
		if (ret) {
			fprintf(stderr, "ERROR: getting dev info for devstats failed: "
					"%s\n", strerror(-ret));
			free(di_args);
			goto leave_with_error;
		}
		if (!fi_args.num_devices) {
			fprintf(stderr, "ERROR: no devices found\n");
			free(di_args);
			goto leave_with_error;
		}

		for (i = 0; i < fi_args.num_devices; i++)
			if (start_args.start.srcdevid == di_args[i].devid)
				break;
		free(di_args);
		if (i == fi_args.num_devices) {
			fprintf(stderr, "Error: '%s' is not a valid devid for filesystem '%s'\n",
				srcdev, path);
			goto leave_with_error;
		}
	} else {
		fdsrcdev = open(srcdev, O_RDWR);
		if (fdsrcdev < 0) {
			fprintf(stderr, "Error: Unable to open device '%s'\n",
				srcdev);
			goto leave_with_error;
		}
		ret = fstat(fdsrcdev, &st);
		if (ret) {
			fprintf(stderr, "Error: Unable to stat '%s'\n", srcdev);
			goto leave_with_error;
		}
		if (!S_ISBLK(st.st_mode)) {
			fprintf(stderr, "Error: '%s' is not a block device\n",
				srcdev);
			goto leave_with_error;
		}
		strncpy((char *)start_args.start.srcdev_name, srcdev,
			BTRFS_DEVICE_PATH_NAME_MAX);
		close(fdsrcdev);
		fdsrcdev = -1;
		start_args.start.srcdevid = 0;
	}

	ret = check_mounted(dstdev);
	if (ret < 0) {
		fprintf(stderr, "Error checking %s mount status\n", dstdev);
		goto leave_with_error;
	}
	if (ret == 1) {
		fprintf(stderr,
			"Error, target device %s is in use and currently mounted!\n",
			dstdev);
		goto leave_with_error;
	}
	fddstdev = open(dstdev, O_RDWR);
	if (fddstdev < 0) {
		fprintf(stderr, "Unable to open %s\n", dstdev);
		goto leave_with_error;
	}
	ret = btrfs_scan_one_device(fddstdev, dstdev, &fs_devices_mnt,
				    &total_devs, BTRFS_SUPER_INFO_OFFSET);
	if (ret >= 0 && !force_using_targetdev) {
		fprintf(stderr,
			"Error, target device %s contains filesystem, use '-f' to force overwriting.\n",
			dstdev);
		goto leave_with_error;
	}
	ret = fstat(fddstdev, &st);
	if (ret) {
		fprintf(stderr, "Error: Unable to stat '%s'\n", dstdev);
		goto leave_with_error;
	}
	if (!S_ISBLK(st.st_mode)) {
		fprintf(stderr, "Error: '%s' is not a block device\n", dstdev);
		goto leave_with_error;
	}
	strncpy((char *)start_args.start.tgtdev_name, dstdev,
		BTRFS_DEVICE_PATH_NAME_MAX);
	if (btrfs_prepare_device(fddstdev, dstdev, 1, &dstdev_block_count, 0,
				 &mixed, 0)) {
		fprintf(stderr, "Error: Failed to prepare device '%s'\n",
			dstdev);
		goto leave_with_error;
	}
	close(fddstdev);
	fddstdev = -1;

	dev_replace_handle_sigint(fdmnt);
	if (!do_not_background) {
		if (daemon(0, 0) < 0) {
			fprintf(stderr, "ERROR, backgrounding failed: %s\n",
				strerror(errno));
			goto leave_with_error;
		}
	}

	start_args.cmd = BTRFS_IOCTL_DEV_REPLACE_CMD_START;
	ret = ioctl(fdmnt, BTRFS_IOC_DEV_REPLACE, &start_args);
	if (do_not_background) {
		if (ret) {
			fprintf(stderr,
				"ERROR: ioctl(DEV_REPLACE_START) failed on \"%s\": %s, %s\n",
				path, strerror(errno),
				replace_dev_result2string(start_args.result));
			goto leave_with_error;
		}

		if (start_args.result !=
		    BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR) {
			fprintf(stderr,
				"ERROR: ioctl(DEV_REPLACE_START) on \"%s\" returns error: %s\n",
				path,
				replace_dev_result2string(start_args.result));
			goto leave_with_error;
		}
	}
	close(fdmnt);
	return 0;

leave_with_error:
	if (fdmnt != -1)
		close(fdmnt);
	if (fdsrcdev != -1)
		close(fdsrcdev);
	if (fddstdev != -1)
		close(fddstdev);
	return -1;
}

static const char *const cmd_status_replace_usage[] = {
	"btrfs replace status mount_point [-1]",
	"Print status and progress information of a running device replace",
	"operation",
	"",
	"-1     print once instead of print continously until the replace",
	"       operation finishes (or is canceled)",
	NULL
};

static int cmd_status_replace(int argc, char **argv)
{
	int fd;
	int e;
	int c;
	char *path;
	int once = 0;
	int ret;

	while ((c = getopt(argc, argv, "1")) != -1) {
		switch (c) {
		case '1':
			once = 1;
			break;
		case '?':
		default:
			usage(cmd_status_replace_usage);
		}
	}

	if (check_argc_exact(argc - optind, 1))
		usage(cmd_status_replace_usage);

	path = argv[optind];
	fd = open_file_or_dir(path);
	e = errno;
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access \"%s\": %s\n",
			path, strerror(e));
		return -1;
	}

	ret = print_replace_status(fd, path, once);
	close(fd);
	return ret;
}
コード例 #29
0
ファイル: cmds-subvolume.c プロジェクト: osandov/btrfs-progs
static int cmd_subvol_show(int argc, char **argv)
{
	struct root_info get_ri;
	struct btrfs_list_filter_set *filter_set;
	char tstr[256];
	char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
	char *fullpath = NULL, *svpath = NULL, *mnt = NULL;
	char raw_prefix[] = "\t\t\t\t";
	u64 sv_id, mntid;
	int fd = -1, mntfd = -1;
	int ret = 1;
	DIR *dirstream1 = NULL, *dirstream2 = NULL;

	if (check_argc_exact(argc, 2))
		usage(cmd_subvol_show_usage);

	fullpath = realpath(argv[1], NULL);
	if (!fullpath) {
		fprintf(stderr, "ERROR: finding real path for '%s', %s\n",
			argv[1], strerror(errno));
		goto out;
	}

	ret = test_issubvolume(fullpath);
	if (ret < 0) {
		fprintf(stderr, "ERROR: error accessing '%s'\n", fullpath);
		goto out;
	}
	if (!ret) {
		fprintf(stderr, "ERROR: '%s' is not a subvolume\n", fullpath);
		ret = 1;
		goto out;
	}

	ret = find_mount_root(fullpath, &mnt);
	if (ret < 0) {
		fprintf(stderr, "ERROR: find_mount_root failed on '%s': "
				"%s\n", fullpath, strerror(-ret));
		goto out;
	}
	if (ret > 0) {
		fprintf(stderr,
			"ERROR: %s doesn't belong to btrfs mount point\n",
			fullpath);
		goto out;
	}
	ret = 1;
	svpath = get_subvol_name(mnt, fullpath);

	fd = open_file_or_dir(fullpath, &dirstream1);
	if (fd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", fullpath);
		goto out;
	}

	ret = btrfs_list_get_path_rootid(fd, &sv_id);
	if (ret) {
		fprintf(stderr, "ERROR: can't get rootid for '%s'\n",
			fullpath);
		goto out;
	}

	mntfd = open_file_or_dir(mnt, &dirstream2);
	if (mntfd < 0) {
		fprintf(stderr, "ERROR: can't access '%s'\n", mnt);
		goto out;
	}

	ret = btrfs_list_get_path_rootid(mntfd, &mntid);
	if (ret) {
		fprintf(stderr, "ERROR: can't get rootid for '%s'\n", mnt);
		goto out;
	}

	if (sv_id == BTRFS_FS_TREE_OBJECTID) {
		printf("%s is btrfs root\n", fullpath);
		goto out;
	}

	memset(&get_ri, 0, sizeof(get_ri));
	get_ri.root_id = sv_id;

	ret = btrfs_get_subvol(mntfd, &get_ri);
	if (ret) {
		fprintf(stderr, "ERROR: can't find '%s'\n",
			svpath);
		goto out;
	}

	/* print the info */
	printf("%s\n", fullpath);
	printf("\tName: \t\t\t%s\n", get_ri.name);

	if (uuid_is_null(get_ri.uuid))
		strcpy(uuidparse, "-");
	else
		uuid_unparse(get_ri.uuid, uuidparse);
	printf("\tUUID: \t\t\t%s\n", uuidparse);

	if (uuid_is_null(get_ri.puuid))
		strcpy(uuidparse, "-");
	else
		uuid_unparse(get_ri.puuid, uuidparse);
	printf("\tParent UUID: \t\t%s\n", uuidparse);

	if (uuid_is_null(get_ri.ruuid))
		strcpy(uuidparse, "-");
	else
		uuid_unparse(get_ri.ruuid, uuidparse);
	printf("\tReceived UUID: \t\t%s\n", uuidparse);

	if (get_ri.otime) {
		struct tm tm;

		localtime_r(&get_ri.otime, &tm);
		strftime(tstr, 256, "%Y-%m-%d %X %z", &tm);
	} else
		strcpy(tstr, "-");
	printf("\tCreation time: \t\t%s\n", tstr);

	printf("\tSubvolume ID: \t\t%llu\n", get_ri.root_id);
	printf("\tGeneration: \t\t%llu\n", get_ri.gen);
	printf("\tGen at creation: \t%llu\n", get_ri.ogen);
	printf("\tParent ID: \t\t%llu\n", get_ri.ref_tree);
	printf("\tTop level ID: \t\t%llu\n", get_ri.top_id);

	if (get_ri.flags & BTRFS_ROOT_SUBVOL_RDONLY)
		printf("\tFlags: \t\t\treadonly\n");
	else
		printf("\tFlags: \t\t\t-\n");

	/* print the snapshots of the given subvol if any*/
	printf("\tSnapshot(s):\n");
	filter_set = btrfs_list_alloc_filter_set();
	btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_BY_PARENT,
				(u64)(unsigned long)get_ri.uuid);
	btrfs_list_setup_print_column(BTRFS_LIST_PATH);
	btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
			1, raw_prefix);

	/* clean up */
	free(get_ri.path);
	free(get_ri.name);
	free(get_ri.full_path);
	btrfs_list_free_filter_set(filter_set);

out:
	close_file_or_dir(fd, dirstream1);
	close_file_or_dir(mntfd, dirstream2);
	free(mnt);
	free(fullpath);
	return !!ret;
}
コード例 #30
0
static int cmd_add_dev(int argc, char **argv)
{
	char	*mntpnt;
	int	i, fdmnt, ret=0, e;

	if (check_argc_min(argc, 3))
		usage(cmd_add_dev_usage);

	mntpnt = argv[argc - 1];

	fdmnt = open_file_or_dir(mntpnt);
	if (fdmnt < 0) {
		fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt);
		return 12;
	}

	for (i = 1; i < argc - 1; i++ ){
		struct btrfs_ioctl_vol_args ioctl_args;
		int	devfd, res;
		u64 dev_block_count = 0;
		struct stat st;
		int mixed = 0;

		res = check_mounted(argv[i]);
		if (res < 0) {
			fprintf(stderr, "error checking %s mount status\n",
				argv[i]);
			ret++;
			continue;
		}
		if (res == 1) {
			fprintf(stderr, "%s is mounted\n", argv[i]);
			ret++;
			continue;
		}

		devfd = open(argv[i], O_RDWR);
		if (!devfd) {
			fprintf(stderr, "ERROR: Unable to open device '%s'\n", argv[i]);
			close(devfd);
			ret++;
			continue;
		}
		res = fstat(devfd, &st);
		if (res) {
			fprintf(stderr, "ERROR: Unable to stat '%s'\n", argv[i]);
			close(devfd);
			ret++;
			continue;
		}
		if (!S_ISBLK(st.st_mode)) {
			fprintf(stderr, "ERROR: '%s' is not a block device\n", argv[i]);
			close(devfd);
			ret++;
			continue;
		}

		res = btrfs_prepare_device(devfd, argv[i], 1, &dev_block_count,
					   0, &mixed, 0);
		if (res) {
			fprintf(stderr, "ERROR: Unable to init '%s'\n", argv[i]);
			close(devfd);
			ret++;
			continue;
		}
		close(devfd);

		strncpy(ioctl_args.name, argv[i], BTRFS_PATH_NAME_MAX);
		ioctl_args.name[BTRFS_PATH_NAME_MAX-1] = 0;
		res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
		e = errno;
		if(res<0){
			fprintf(stderr, "ERROR: error adding the device '%s' - %s\n",
				argv[i], strerror(e));
			ret++;
		}

	}

	close(fdmnt);
	if (ret)
		return ret+20;
	else
		return 0;
}