diff --git a/btrfs-list.c b/btrfs-list.c index 8eec05ea..92a537f4 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -1582,7 +1582,9 @@ int btrfs_get_subvol(int fd, struct root_info *the_ri) rbn = rb_next(rbn); continue; } - if (!comp_entry_with_rootid(the_ri, ri, 0)) { + + if (!comp_entry_with_rootid(the_ri, ri, 0) || + !uuid_compare(the_ri->uuid, ri->uuid)) { memcpy(the_ri, ri, offsetof(struct root_info, path)); the_ri->path = strdup_or_null(ri->path); the_ri->name = strdup_or_null(ri->name); diff --git a/cmds-subvolume.c b/cmds-subvolume.c index de6204ea..666f6e05 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -891,8 +891,13 @@ static int cmd_subvol_find_new(int argc, char **argv) } static const char * const cmd_subvol_show_usage[] = { - "btrfs subvolume show ", - "Show more information of the subvolume", + "btrfs subvolume show [options] |", + "Show more information about the subvolume", + "-r|--rootid rootid of the subvolume", + "-u|--uuid uuid of the subvolume", + "", + "If no option is specified, will be shown, otherwise", + "the rootid or uuid are resolved relative to the path.", NULL }; @@ -907,12 +912,46 @@ static int cmd_subvol_show(int argc, char **argv) int fd = -1; int ret = 1; DIR *dirstream1 = NULL; + int by_rootid = 0; + int by_uuid = 0; + u64 rootid_arg; + u8 uuid_arg[BTRFS_UUID_SIZE]; - clean_args_no_options(argc, argv, cmd_subvol_show_usage); + while (1) { + int c; + static const struct option long_options[] = { + { "rootid", required_argument, NULL, 'r'}, + { "uuid", required_argument, NULL, 'u'}, + { NULL, 0, NULL, 0 } + }; + + c = getopt_long(argc, argv, "r:u:", long_options, NULL); + if (c < 0) + break; + + switch (c) { + case 'r': + rootid_arg = arg_strtou64(optarg); + by_rootid = 1; + break; + case 'u': + uuid_parse(optarg, uuid_arg); + by_uuid = 1; + break; + default: + usage(cmd_subvol_show_usage); + } + } if (check_argc_exact(argc - optind, 1)) usage(cmd_subvol_show_usage); + if (by_rootid && by_uuid) { + error( + "options --rootid and --uuid cannot be used at the same time"); + usage(cmd_subvol_show_usage); + } + memset(&get_ri, 0, sizeof(get_ri)); fullpath = realpath(argv[optind], NULL); if (!fullpath) { @@ -921,7 +960,14 @@ static int cmd_subvol_show(int argc, char **argv) goto out; } - ret = get_subvol_info(fullpath, &get_ri); + if (by_rootid) { + ret = get_subvol_info_by_rootid(fullpath, &get_ri, rootid_arg); + } else if (by_uuid) { + ret = get_subvol_info_by_uuid(fullpath, &get_ri, uuid_arg); + } else { + ret = get_subvol_info(fullpath, &get_ri); + } + if (ret) { if (ret < 0) { error("Failed to get subvol info %s: %s", diff --git a/utils.c b/utils.c index 243ee1e5..bb049133 100644 --- a/utils.c +++ b/utils.c @@ -2433,6 +2433,58 @@ out: 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 */ void init_rand_seed(u64 seed) { diff --git a/utils.h b/utils.h index bf8eb1ed..091f8fab 100644 --- a/utils.h +++ b/utils.h @@ -134,7 +134,10 @@ int test_isdir(const char *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); const char* btrfs_group_type_str(u64 flag); const char* btrfs_group_profile_str(u64 flag);