Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
static int cmd_subvol_delete(int argc, char **argv)
{
	int	res, len, 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 sync_mode = 0;
	struct option long_options[] = {
		{"commit-after", no_argument, NULL, 'c'},  /* sync mode 1 */
		{"commit-each", no_argument, NULL, 'C'},  /* sync mode 2 */
		{NULL, 0, NULL, 0}
	};

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

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

		switch(c) {
		case 'c':
			sync_mode = 1;
			break;
		case 'C':
			sync_mode = 2;
			break;
		default:
			usage(cmd_subvol_delete_usage);
		}
	}

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

	printf("Transaction commit: %s\n",
		!sync_mode ? "none (default)" :
		sync_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);

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

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

	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'\n", dname, vname);
	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 (sync_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 (sync_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;
}