#include "utils.h"
#include "btrfs-list.h"
#include "utils.h"
+#include "help.h"
static int is_subvolume_cleaned(int fd, u64 subvolid)
{
struct btrfs_qgroup_inherit *inherit = NULL;
DIR *dirstream = NULL;
- optind = 1;
while (1) {
- int c = getopt(argc, argv, "c:i:v");
+ int c = getopt(argc, argv, "c:i:");
if (c < 0)
break;
return retval;
}
-/*
- * Test if path is a subvolume
- * Returns:
- * 0 - path exists but it is not a subvolume
- * 1 - path exists and it is a subvolume
- * < 0 - error
- */
-int test_issubvolume(const char *path)
-{
- struct stat st;
- struct statfs stfs;
- int res;
-
- res = stat(path, &st);
- if (res < 0)
- return -errno;
-
- if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode))
- return 0;
-
- res = statfs(path, &stfs);
- if (res < 0)
- return -errno;
-
- return (int)stfs.f_type == BTRFS_SUPER_MAGIC;
-}
-
static int wait_for_commit(int fd)
{
int ret;
"",
"-c|--commit-after wait for transaction commit at the end of the operation",
"-C|--commit-each wait for transaction commit after deleting each subvolume",
+ "-v|--verbose verbose output of operations",
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 */
+ {"verbose", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0}
};
- c = getopt_long(argc, argv, "cC", long_options, NULL);
+ c = getopt_long(argc, argv, "cCv", long_options, NULL);
if (c < 0)
break;
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;
+ enum btrfs_list_layout layout = BTRFS_LIST_LAYOUT_DEFAULT;
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[] = {
is_only_in_path = 1;
break;
case 't':
- is_tab_result = 1;
+ layout = BTRFS_LIST_LAYOUT_TABLE;
break;
case 's':
btrfs_list_setup_filter(&filter_set,
}
}
- if (flags)
- btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_FLAGS,
- flags);
-
if (check_argc_exact(argc - optind, 1)) {
uerr = 1;
goto out;
goto out;
}
+ if (flags)
+ btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_FLAGS,
+ flags);
+
ret = btrfs_list_get_path_rootid(fd, &top_id);
- if (ret) {
- error("can't get rootid for '%s'", subvol);
+ if (ret)
goto out;
- }
if (is_list_all)
btrfs_list_setup_filter(&filter_set,
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);
+ ret = btrfs_list_subvols_print(fd, filter_set, comparer_set,
+ layout, !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);
+ free(filter_set);
if (comparer_set)
- btrfs_list_free_comparer_set(comparer_set);
+ free(comparer_set);
if (uerr)
usage(cmd_subvol_list_usage);
return !!ret;
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");
BTRFS_LIST_LAYOUT_DEFAULT, 1, NULL);
if (filter_set)
- btrfs_list_free_filter_set(filter_set);
+ free(filter_set);
out:
close_file_or_dir(fd, dirstream);
return !!ret;
}
static const char * const cmd_subvol_show_usage[] = {
- "btrfs subvolume show <subvol-path>",
- "Show more information of the subvolume",
+ "btrfs subvolume show [options] <subvol-path>|<mnt>",
+ "Show more information about the subvolume",
+ "-r|--rootid rootid of the subvolume",
+ "-u|--uuid uuid of the subvolume",
+ "",
+ "If no option is specified, <subvol-path> will be shown, otherwise",
+ "the rootid or uuid are resolved relative to the <mnt> path.",
NULL
};
static int cmd_subvol_show(int argc, char **argv)
{
struct root_info get_ri;
- struct btrfs_list_filter_set *filter_set;
+ struct btrfs_list_filter_set *filter_set = NULL;
char tstr[256];
char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
- char *fullpath = NULL, *svpath = NULL, *mnt = NULL;
+ char *fullpath = NULL;
char raw_prefix[] = "\t\t\t\t";
- u64 sv_id;
- int fd = -1, mntfd = -1;
+ int fd = -1;
int ret = 1;
- DIR *dirstream1 = NULL, *dirstream2 = NULL;
+ DIR *dirstream1 = NULL;
+ int by_rootid = 0;
+ int by_uuid = 0;
+ u64 rootid_arg;
+ u8 uuid_arg[BTRFS_UUID_SIZE];
+
+ while (1) {
+ int c;
+ static const struct option long_options[] = {
+ { "rootid", required_argument, NULL, 'r'},
+ { "uuid", required_argument, NULL, 'u'},
+ { NULL, 0, NULL, 0 }
+ };
- clean_args_no_options(argc, argv, cmd_subvol_show_usage);
+ 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) {
error("cannot find real path for '%s': %s",
goto out;
}
- ret = test_issubvolume(fullpath);
- if (ret < 0) {
- error("cannot access subvolume %s: %s", fullpath,
- strerror(-ret));
- goto out;
- }
- if (!ret) {
- error("not a subvolume: %s", fullpath);
- ret = 1;
- goto out;
- }
-
- ret = find_mount_root(fullpath, &mnt);
- if (ret < 0) {
- error("find_mount_root failed on '%s': %s",
- fullpath, strerror(-ret));
- goto out;
- }
- if (ret > 0) {
- error("%s doesn't belong to btrfs mount point", fullpath);
- goto out;
- }
- ret = 1;
- svpath = get_subvol_name(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) {
- error("can't get rootid for '%s'", fullpath);
- goto out;
- }
-
- mntfd = btrfs_open_dir(mnt, &dirstream2, 1);
- if (mntfd < 0)
- goto out;
-
- if (sv_id == BTRFS_FS_TREE_OBJECTID) {
- printf("%s is toplevel subvolume\n", fullpath);
- goto out;
+ 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);
}
- memset(&get_ri, 0, sizeof(get_ri));
- get_ri.root_id = sv_id;
-
- ret = btrfs_get_subvol(mntfd, &get_ri);
if (ret) {
- error("can't find '%s'", svpath);
- goto out;
+ if (ret < 0) {
+ error("Failed to get subvol info %s: %s",
+ fullpath, strerror(-ret));
+ } else {
+ error("Failed to get subvol info %s: %d",
+ fullpath, ret);
+ }
+ return ret;
}
/* print the info */
- printf("%s\n", fullpath);
+ printf("%s\n", get_ri.full_path);
printf("\tName: \t\t\t%s\n", get_ri.name);
if (uuid_is_null(get_ri.uuid))
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);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: can't access '%s'\n", fullpath);
+ goto out;
+ }
btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
1, raw_prefix);
+out:
/* clean up */
free(get_ri.path);
free(get_ri.name);
free(get_ri.full_path);
- btrfs_list_free_filter_set(filter_set);
+ free(filter_set);
-out:
close_file_or_dir(fd, dirstream1);
- close_file_or_dir(mntfd, dirstream2);
- free(mnt);
free(fullpath);
return !!ret;
}
sh = (struct btrfs_ioctl_search_header*)(args.buf + off);
off += sizeof(*sh);
- if (sh->type == BTRFS_ORPHAN_ITEM_KEY) {
+ if (btrfs_search_header_type(sh)
+ == BTRFS_ORPHAN_ITEM_KEY) {
if (idx >= count) {
u64 *newids;
return -ENOMEM;
*ids = newids;
}
- (*ids)[idx] = sh->offset;
+ (*ids)[idx] = btrfs_search_header_offset(sh);
idx++;
}
- off += sh->len;
+ off += btrfs_search_header_len(sh);
- sk->min_objectid = sh->objectid;
- sk->min_type = sh->type;
- sk->min_offset = sh->offset;
+ sk->min_objectid = btrfs_search_header_objectid(sh);
+ sk->min_type = btrfs_search_header_type(sh);
+ sk->min_offset = btrfs_search_header_offset(sh);
}
if (sk->min_offset < (u64)-1)
sk->min_offset++;
int id_count;
int sleep_interval = 1;
- optind = 1;
while (1) {
int c = getopt(argc, argv, "s:");
switch (c) {
case 's':
- sleep_interval = atoi(argv[optind]);
+ sleep_interval = atoi(optarg);
if (sleep_interval < 1) {
- error("invalid sleep interval %s",
- argv[optind]);
+ error("invalid sleep interval %s", optarg);
ret = 1;
goto out;
}
}
if (id < BTRFS_FIRST_FREE_OBJECTID
|| id > BTRFS_LAST_FREE_OBJECTID) {
- error("subvolume id %s out of range\n", arg);
+ error("subvolume id %s out of range", arg);
ret = 1;
goto out;
}