mirror of
https://github.com/kdave/btrfs-progs
synced 2024-12-25 15:42:23 +00:00
btrfs-progs: use libbtrfsutil for subvol show
Now implemented with btrfs_util_subvolume_path(), btrfs_util_subvolume_info(), and subvolume iterators. Signed-off-by: Omar Sandoval <osandov@fb.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
afb0426016
commit
9005b603d7
149
cmds-subvolume.c
149
cmds-subvolume.c
@ -954,19 +954,20 @@ static const char * const cmd_subvol_show_usage[] = {
|
|||||||
|
|
||||||
static int cmd_subvol_show(int argc, char **argv)
|
static int cmd_subvol_show(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct root_info get_ri;
|
|
||||||
struct btrfs_list_filter_set *filter_set = NULL;
|
|
||||||
char tstr[256];
|
char tstr[256];
|
||||||
char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
|
char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
|
||||||
char *fullpath = NULL;
|
char *fullpath = NULL;
|
||||||
char raw_prefix[] = "\t\t\t\t";
|
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
DIR *dirstream1 = NULL;
|
DIR *dirstream1 = NULL;
|
||||||
int by_rootid = 0;
|
int by_rootid = 0;
|
||||||
int by_uuid = 0;
|
int by_uuid = 0;
|
||||||
u64 rootid_arg;
|
u64 rootid_arg = 0;
|
||||||
u8 uuid_arg[BTRFS_UUID_SIZE];
|
u8 uuid_arg[BTRFS_UUID_SIZE];
|
||||||
|
struct btrfs_util_subvolume_iterator *iter;
|
||||||
|
struct btrfs_util_subvolume_info subvol;
|
||||||
|
char *subvol_path = NULL;
|
||||||
|
enum btrfs_util_error err;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int c;
|
int c;
|
||||||
@ -1003,96 +1004,142 @@ static int cmd_subvol_show(int argc, char **argv)
|
|||||||
usage(cmd_subvol_show_usage);
|
usage(cmd_subvol_show_usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&get_ri, 0, sizeof(get_ri));
|
|
||||||
fullpath = realpath(argv[optind], NULL);
|
fullpath = realpath(argv[optind], NULL);
|
||||||
if (!fullpath) {
|
if (!fullpath) {
|
||||||
error("cannot find real path for '%s': %m", argv[optind]);
|
error("cannot find real path for '%s': %m", argv[optind]);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (by_rootid) {
|
fd = open_file_or_dir(fullpath, &dirstream1);
|
||||||
ret = get_subvol_info_by_rootid(fullpath, &get_ri, rootid_arg);
|
if (fd < 0) {
|
||||||
} else if (by_uuid) {
|
error("can't access '%s'", fullpath);
|
||||||
ret = get_subvol_info_by_uuid(fullpath, &get_ri, uuid_arg);
|
goto out;
|
||||||
} else {
|
|
||||||
ret = get_subvol_info(fullpath, &get_ri);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (by_uuid) {
|
||||||
if (ret < 0) {
|
err = btrfs_util_create_subvolume_iterator_fd(fd,
|
||||||
error("Failed to get subvol info %s: %s",
|
BTRFS_FS_TREE_OBJECTID,
|
||||||
fullpath, strerror(-ret));
|
0, &iter);
|
||||||
} else {
|
if (err) {
|
||||||
error("Failed to get subvol info %s: %d",
|
error_btrfs_util(err);
|
||||||
fullpath, ret);
|
goto out;
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
|
for (;;) {
|
||||||
|
err = btrfs_util_subvolume_iterator_next_info(iter,
|
||||||
|
&subvol_path,
|
||||||
|
&subvol);
|
||||||
|
if (err == BTRFS_UTIL_ERROR_STOP_ITERATION) {
|
||||||
|
uuid_unparse(uuid_arg, uuidparse);
|
||||||
|
error("can't find uuid '%s' on '%s'", uuidparse,
|
||||||
|
fullpath);
|
||||||
|
btrfs_util_destroy_subvolume_iterator(iter);
|
||||||
|
goto out;
|
||||||
|
} else if (err) {
|
||||||
|
error_btrfs_util(err);
|
||||||
|
btrfs_util_destroy_subvolume_iterator(iter);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuid_compare(subvol.uuid, uuid_arg) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
free(subvol_path);
|
||||||
|
}
|
||||||
|
btrfs_util_destroy_subvolume_iterator(iter);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* If !by_rootid, rootid_arg = 0, which means find the
|
||||||
|
* subvolume ID of the fd and use that.
|
||||||
|
*/
|
||||||
|
err = btrfs_util_subvolume_info_fd(fd, rootid_arg, &subvol);
|
||||||
|
if (err) {
|
||||||
|
error_btrfs_util(err);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = btrfs_util_subvolume_path_fd(fd, subvol.id, &subvol_path);
|
||||||
|
if (err) {
|
||||||
|
error_btrfs_util(err);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print the info */
|
/* print the info */
|
||||||
printf("%s\n", get_ri.full_path);
|
printf("%s\n", subvol.id == BTRFS_FS_TREE_OBJECTID ? "/" : subvol_path);
|
||||||
printf("\tName: \t\t\t%s\n", get_ri.name);
|
printf("\tName: \t\t\t%s\n",
|
||||||
|
(subvol.id == BTRFS_FS_TREE_OBJECTID ? "<FS_TREE>" :
|
||||||
|
basename(subvol_path)));
|
||||||
|
|
||||||
if (uuid_is_null(get_ri.uuid))
|
if (uuid_is_null(subvol.uuid))
|
||||||
strcpy(uuidparse, "-");
|
strcpy(uuidparse, "-");
|
||||||
else
|
else
|
||||||
uuid_unparse(get_ri.uuid, uuidparse);
|
uuid_unparse(subvol.uuid, uuidparse);
|
||||||
printf("\tUUID: \t\t\t%s\n", uuidparse);
|
printf("\tUUID: \t\t\t%s\n", uuidparse);
|
||||||
|
|
||||||
if (uuid_is_null(get_ri.puuid))
|
if (uuid_is_null(subvol.parent_uuid))
|
||||||
strcpy(uuidparse, "-");
|
strcpy(uuidparse, "-");
|
||||||
else
|
else
|
||||||
uuid_unparse(get_ri.puuid, uuidparse);
|
uuid_unparse(subvol.parent_uuid, uuidparse);
|
||||||
printf("\tParent UUID: \t\t%s\n", uuidparse);
|
printf("\tParent UUID: \t\t%s\n", uuidparse);
|
||||||
|
|
||||||
if (uuid_is_null(get_ri.ruuid))
|
if (uuid_is_null(subvol.received_uuid))
|
||||||
strcpy(uuidparse, "-");
|
strcpy(uuidparse, "-");
|
||||||
else
|
else
|
||||||
uuid_unparse(get_ri.ruuid, uuidparse);
|
uuid_unparse(subvol.received_uuid, uuidparse);
|
||||||
printf("\tReceived UUID: \t\t%s\n", uuidparse);
|
printf("\tReceived UUID: \t\t%s\n", uuidparse);
|
||||||
|
|
||||||
if (get_ri.otime) {
|
if (subvol.otime.tv_sec) {
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
|
||||||
localtime_r(&get_ri.otime, &tm);
|
localtime_r(&subvol.otime.tv_sec, &tm);
|
||||||
strftime(tstr, 256, "%Y-%m-%d %X %z", &tm);
|
strftime(tstr, 256, "%Y-%m-%d %X %z", &tm);
|
||||||
} else
|
} else
|
||||||
strcpy(tstr, "-");
|
strcpy(tstr, "-");
|
||||||
printf("\tCreation time: \t\t%s\n", tstr);
|
printf("\tCreation time: \t\t%s\n", tstr);
|
||||||
|
|
||||||
printf("\tSubvolume ID: \t\t%llu\n", get_ri.root_id);
|
printf("\tSubvolume ID: \t\t%" PRIu64 "\n", subvol.id);
|
||||||
printf("\tGeneration: \t\t%llu\n", get_ri.gen);
|
printf("\tGeneration: \t\t%" PRIu64 "\n", subvol.generation);
|
||||||
printf("\tGen at creation: \t%llu\n", get_ri.ogen);
|
printf("\tGen at creation: \t%" PRIu64 "\n", subvol.otransid);
|
||||||
printf("\tParent ID: \t\t%llu\n", get_ri.ref_tree);
|
printf("\tParent ID: \t\t%" PRIu64 "\n", subvol.parent_id);
|
||||||
printf("\tTop level ID: \t\t%llu\n", get_ri.top_id);
|
printf("\tTop level ID: \t\t%" PRIu64 "\n", subvol.parent_id);
|
||||||
|
|
||||||
if (get_ri.flags & BTRFS_ROOT_SUBVOL_RDONLY)
|
if (subvol.flags & BTRFS_ROOT_SUBVOL_RDONLY)
|
||||||
printf("\tFlags: \t\t\treadonly\n");
|
printf("\tFlags: \t\t\treadonly\n");
|
||||||
else
|
else
|
||||||
printf("\tFlags: \t\t\t-\n");
|
printf("\tFlags: \t\t\t-\n");
|
||||||
|
|
||||||
/* print the snapshots of the given subvol if any*/
|
/* print the snapshots of the given subvol if any*/
|
||||||
printf("\tSnapshot(s):\n");
|
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);
|
|
||||||
|
|
||||||
fd = open_file_or_dir(fullpath, &dirstream1);
|
err = btrfs_util_create_subvolume_iterator_fd(fd,
|
||||||
if (fd < 0) {
|
BTRFS_FS_TREE_OBJECTID, 0,
|
||||||
fprintf(stderr, "ERROR: can't access '%s'\n", fullpath);
|
&iter);
|
||||||
goto out;
|
|
||||||
|
for (;;) {
|
||||||
|
struct btrfs_util_subvolume_info subvol2;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
err = btrfs_util_subvolume_iterator_next_info(iter, &path, &subvol2);
|
||||||
|
if (err == BTRFS_UTIL_ERROR_STOP_ITERATION) {
|
||||||
|
break;
|
||||||
|
} else if (err) {
|
||||||
|
error_btrfs_util(err);
|
||||||
|
btrfs_util_destroy_subvolume_iterator(iter);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuid_compare(subvol2.parent_uuid, subvol.uuid) == 0)
|
||||||
|
printf("\t\t\t\t%s\n", path);
|
||||||
|
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
|
btrfs_util_destroy_subvolume_iterator(iter);
|
||||||
1, raw_prefix);
|
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
/* clean up */
|
free(subvol_path);
|
||||||
free(get_ri.path);
|
|
||||||
free(get_ri.name);
|
|
||||||
free(get_ri.full_path);
|
|
||||||
free(filter_set);
|
|
||||||
|
|
||||||
close_file_or_dir(fd, dirstream1);
|
close_file_or_dir(fd, dirstream1);
|
||||||
free(fullpath);
|
free(fullpath);
|
||||||
return !!ret;
|
return !!ret;
|
||||||
|
118
utils.c
118
utils.c
@ -2495,124 +2495,6 @@ const char *subvol_strip_mountpoint(const char *mnt, const char *full_path)
|
|||||||
return full_path + len;
|
return full_path + len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns
|
|
||||||
* <0: Std error
|
|
||||||
* 0: All fine
|
|
||||||
* 1: Error; and error info printed to the terminal. Fixme.
|
|
||||||
* 2: If the fullpath is root tree instead of subvol tree
|
|
||||||
*/
|
|
||||||
int get_subvol_info(const char *fullpath, struct root_info *get_ri)
|
|
||||||
{
|
|
||||||
u64 sv_id;
|
|
||||||
int ret = 1;
|
|
||||||
int fd = -1;
|
|
||||||
int mntfd = -1;
|
|
||||||
char *mnt = NULL;
|
|
||||||
const char *svpath = NULL;
|
|
||||||
DIR *dirstream1 = NULL;
|
|
||||||
DIR *dirstream2 = NULL;
|
|
||||||
|
|
||||||
ret = test_issubvolume(fullpath);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
if (!ret) {
|
|
||||||
error("not a subvolume: %s", fullpath);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = find_mount_root(fullpath, &mnt);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
if (ret > 0) {
|
|
||||||
error("%s doesn't belong to btrfs mount point", fullpath);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
ret = 1;
|
|
||||||
svpath = subvol_strip_mountpoint(mnt, fullpath);
|
|
||||||
|
|
||||||
fd = btrfs_open_dir(fullpath, &dirstream1, 1);
|
|
||||||
if (fd < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = btrfs_list_get_path_rootid(fd, &sv_id);
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
mntfd = btrfs_open_dir(mnt, &dirstream2, 1);
|
|
||||||
if (mntfd < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
memset(get_ri, 0, sizeof(*get_ri));
|
|
||||||
get_ri->root_id = sv_id;
|
|
||||||
|
|
||||||
if (sv_id == BTRFS_FS_TREE_OBJECTID)
|
|
||||||
ret = btrfs_get_toplevel_subvol(mntfd, get_ri);
|
|
||||||
else
|
|
||||||
ret = btrfs_get_subvol(mntfd, get_ri);
|
|
||||||
if (ret)
|
|
||||||
error("can't find '%s': %d", svpath, ret);
|
|
||||||
|
|
||||||
out:
|
|
||||||
close_file_or_dir(mntfd, dirstream2);
|
|
||||||
close_file_or_dir(fd, dirstream1);
|
|
||||||
free(mnt);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_subvol_info_by_rootid(const char *mnt, struct root_info *get_ri, u64 r_id)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
int ret;
|
|
||||||
DIR *dirstream = NULL;
|
|
||||||
|
|
||||||
fd = btrfs_open_dir(mnt, &dirstream, 1);
|
|
||||||
if (fd < 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memset(get_ri, 0, sizeof(*get_ri));
|
|
||||||
get_ri->root_id = r_id;
|
|
||||||
|
|
||||||
if (r_id == BTRFS_FS_TREE_OBJECTID)
|
|
||||||
ret = btrfs_get_toplevel_subvol(fd, get_ri);
|
|
||||||
else
|
|
||||||
ret = btrfs_get_subvol(fd, get_ri);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
error("can't find rootid '%llu' on '%s': %d", r_id, mnt, ret);
|
|
||||||
|
|
||||||
close_file_or_dir(fd, dirstream);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_subvol_info_by_uuid(const char *mnt, struct root_info *get_ri, u8 *uuid_arg)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
int ret;
|
|
||||||
DIR *dirstream = NULL;
|
|
||||||
|
|
||||||
fd = btrfs_open_dir(mnt, &dirstream, 1);
|
|
||||||
if (fd < 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memset(get_ri, 0, sizeof(*get_ri));
|
|
||||||
uuid_copy(get_ri->uuid, uuid_arg);
|
|
||||||
|
|
||||||
ret = btrfs_get_subvol(fd, get_ri);
|
|
||||||
if (ret) {
|
|
||||||
char uuid_parsed[BTRFS_UUID_UNPARSED_SIZE];
|
|
||||||
uuid_unparse(uuid_arg, uuid_parsed);
|
|
||||||
error("can't find uuid '%s' on '%s': %d",
|
|
||||||
uuid_parsed, mnt, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
close_file_or_dir(fd, dirstream);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the seed manually */
|
/* Set the seed manually */
|
||||||
void init_rand_seed(u64 seed)
|
void init_rand_seed(u64 seed)
|
||||||
{
|
{
|
||||||
|
5
utils.h
5
utils.h
@ -153,11 +153,6 @@ int test_issubvolume(const char *path);
|
|||||||
int test_isdir(const char *path);
|
int test_isdir(const char *path);
|
||||||
|
|
||||||
const char *subvol_strip_mountpoint(const char *mnt, const char *full_path);
|
const char *subvol_strip_mountpoint(const char *mnt, const char *full_path);
|
||||||
int get_subvol_info(const char *fullpath, struct root_info *get_ri);
|
|
||||||
int get_subvol_info_by_rootid(const char *mnt, struct root_info *get_ri,
|
|
||||||
u64 rootid_arg);
|
|
||||||
int get_subvol_info_by_uuid(const char *mnt, struct root_info *get_ri,
|
|
||||||
u8 *uuid_arg);
|
|
||||||
int find_next_key(struct btrfs_path *path, struct btrfs_key *key);
|
int find_next_key(struct btrfs_path *path, struct btrfs_key *key);
|
||||||
const char* btrfs_group_type_str(u64 flag);
|
const char* btrfs_group_type_str(u64 flag);
|
||||||
const char* btrfs_group_profile_str(u64 flag);
|
const char* btrfs_group_profile_str(u64 flag);
|
||||||
|
Loading…
Reference in New Issue
Block a user