Btrfs-progs: introduce -g -c --sort options into btrfs subvol list command
This patch introduces '-g' '-c' '--sort' options The option '-g' can help you filter the subvolumes by the generation, you may use it just like: btrfs subvol list -g +/-value <path> '+' means the generation of the subvolumes should >= the value you specified. '-' means the generation should <= the value If you don't input either '+' nor '-', this command will list the subvolumes that their generation equals to the value. However if you want to find gengeration between value1 and value2 you may use the above like: btrfs sub list -g -value1 -g +value2 <path> The option '-c' can help you filter the subvolumes by the ogeneration, you may use it just like: btrfs subvol list -c +/-value <path> The usage is the same to '-g' You might want to list subvolumes in order of some items, such as root id, gen and so on, you can use '--sort'. Now you can sort the subvolumes by root id, gen, ogen and path. For example: If you want to list subvolumes in order of rootid, you can use the option like that: btrfs sub list --sort=+/-rooid <path> Here, '+' means the result is sorted by ascending order. '-' is by descending order. If you don't specify either '+' nor '-', the result is sorted by default - ascending order. If you want to combine sort items, you do it like that: btrfs sub list --sort=-rootid,+path,ogen,gen <path> Signed-off-by: Wang Shilong <wangsl-fnst@cn.fujitsu.com> Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
This commit is contained in:
parent
af3045cb20
commit
60d11eca66
168
btrfs-list.c
168
btrfs-list.c
|
@ -215,12 +215,48 @@ static int comp_entry_with_ogen(struct root_info *entry1,
|
|||
return is_descending ? -ret : ret;
|
||||
}
|
||||
|
||||
static int comp_entry_with_path(struct root_info *entry1,
|
||||
struct root_info *entry2,
|
||||
int is_descending)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (strcmp(entry1->full_path, entry2->full_path) > 0)
|
||||
ret = 1;
|
||||
else if (strcmp(entry1->full_path, entry2->full_path) < 0)
|
||||
ret = -1;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
return is_descending ? -ret : ret;
|
||||
}
|
||||
|
||||
static btrfs_list_comp_func all_comp_funcs[] = {
|
||||
[BTRFS_LIST_COMP_ROOTID] = comp_entry_with_rootid,
|
||||
[BTRFS_LIST_COMP_OGEN] = comp_entry_with_ogen,
|
||||
[BTRFS_LIST_COMP_GEN] = comp_entry_with_gen,
|
||||
[BTRFS_LIST_COMP_PATH] = comp_entry_with_path,
|
||||
};
|
||||
|
||||
static char *all_sort_items[] = {
|
||||
[BTRFS_LIST_COMP_ROOTID] = "rootid",
|
||||
[BTRFS_LIST_COMP_OGEN] = "ogen",
|
||||
[BTRFS_LIST_COMP_GEN] = "gen",
|
||||
[BTRFS_LIST_COMP_PATH] = "path",
|
||||
[BTRFS_LIST_COMP_MAX] = NULL,
|
||||
};
|
||||
|
||||
static int btrfs_list_get_sort_item(char *sort_name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BTRFS_LIST_COMP_MAX; i++) {
|
||||
if (strcmp(sort_name, all_sort_items[i]) == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct btrfs_list_comparer_set *btrfs_list_alloc_comparer_set(void)
|
||||
{
|
||||
struct btrfs_list_comparer_set *set;
|
||||
|
@ -1091,10 +1127,46 @@ static int filter_flags(struct root_info *ri, u64 flags)
|
|||
return ri->flags & flags;
|
||||
}
|
||||
|
||||
static int filter_gen_more(struct root_info *ri, u64 data)
|
||||
{
|
||||
return ri->gen >= data;
|
||||
}
|
||||
|
||||
static int filter_gen_less(struct root_info *ri, u64 data)
|
||||
{
|
||||
return ri->gen <= data;
|
||||
}
|
||||
|
||||
static int filter_gen_equal(struct root_info *ri, u64 data)
|
||||
{
|
||||
return ri->gen == data;
|
||||
}
|
||||
|
||||
static int filter_cgen_more(struct root_info *ri, u64 data)
|
||||
{
|
||||
return ri->ogen >= data;
|
||||
}
|
||||
|
||||
static int filter_cgen_less(struct root_info *ri, u64 data)
|
||||
{
|
||||
return ri->ogen <= data;
|
||||
}
|
||||
|
||||
static int filter_cgen_equal(struct root_info *ri, u64 data)
|
||||
{
|
||||
return ri->ogen == data;
|
||||
}
|
||||
|
||||
static btrfs_list_filter_func all_filter_funcs[] = {
|
||||
[BTRFS_LIST_FILTER_ROOTID] = filter_by_rootid,
|
||||
[BTRFS_LIST_FILTER_SNAPSHOT_ONLY] = filter_snapshot,
|
||||
[BTRFS_LIST_FILTER_FLAGS] = filter_flags,
|
||||
[BTRFS_LIST_FILTER_GEN_MORE] = filter_gen_more,
|
||||
[BTRFS_LIST_FILTER_GEN_LESS] = filter_gen_less,
|
||||
[BTRFS_LIST_FILTER_GEN_EQUAL] = filter_gen_equal,
|
||||
[BTRFS_LIST_FILTER_CGEN_MORE] = filter_cgen_more,
|
||||
[BTRFS_LIST_FILTER_CGEN_LESS] = filter_cgen_less,
|
||||
[BTRFS_LIST_FILTER_CGEN_EQUAL] = filter_cgen_equal,
|
||||
};
|
||||
|
||||
struct btrfs_list_filter_set *btrfs_list_alloc_filter_set(void)
|
||||
|
@ -1534,3 +1606,99 @@ char *btrfs_list_path_for_root(int fd, u64 root)
|
|||
|
||||
return ret_path;
|
||||
}
|
||||
|
||||
int btrfs_list_parse_sort_string(char *optarg,
|
||||
struct btrfs_list_comparer_set **comps)
|
||||
{
|
||||
int order;
|
||||
int flag;
|
||||
char *p;
|
||||
char **ptr_argv;
|
||||
int what_to_sort;
|
||||
|
||||
while ((p = strtok(optarg, ",")) != NULL) {
|
||||
flag = 0;
|
||||
ptr_argv = all_sort_items;
|
||||
|
||||
while (*ptr_argv) {
|
||||
if (strcmp(*ptr_argv, p) == 0) {
|
||||
flag = 1;
|
||||
break;
|
||||
} else {
|
||||
p++;
|
||||
if (strcmp(*ptr_argv, p) == 0) {
|
||||
flag = 1;
|
||||
p--;
|
||||
break;
|
||||
}
|
||||
p--;
|
||||
}
|
||||
ptr_argv++;
|
||||
}
|
||||
|
||||
if (flag == 0)
|
||||
return -1;
|
||||
|
||||
else {
|
||||
if (*p == '+') {
|
||||
order = 0;
|
||||
p++;
|
||||
} else if (*p == '-') {
|
||||
order = 1;
|
||||
p++;
|
||||
} else
|
||||
order = 0;
|
||||
|
||||
what_to_sort = btrfs_list_get_sort_item(p);
|
||||
btrfs_list_setup_comparer(comps, what_to_sort, order);
|
||||
}
|
||||
optarg = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to parse the argument of filter condition.
|
||||
*
|
||||
* type is the filter object.
|
||||
*/
|
||||
int btrfs_list_parse_filter_string(char *optarg,
|
||||
struct btrfs_list_filter_set **filters,
|
||||
enum btrfs_list_filter_enum type)
|
||||
{
|
||||
|
||||
u64 arg;
|
||||
char *ptr_parse_end = NULL;
|
||||
char *ptr_optarg_end = optarg + strlen(optarg);
|
||||
|
||||
switch (*(optarg++)) {
|
||||
case '+':
|
||||
arg = (u64)strtol(optarg, &ptr_parse_end, 10);
|
||||
type += 2;
|
||||
if (ptr_parse_end != ptr_optarg_end)
|
||||
return -1;
|
||||
|
||||
btrfs_list_setup_filter(filters, type, arg);
|
||||
break;
|
||||
case '-':
|
||||
arg = (u64)strtoll(optarg, &ptr_parse_end, 10);
|
||||
type += 1;
|
||||
if (ptr_parse_end != ptr_optarg_end)
|
||||
return -1;
|
||||
|
||||
btrfs_list_setup_filter(filters, type, arg);
|
||||
break;
|
||||
default:
|
||||
optarg--;
|
||||
arg = (u64)strtoll(optarg, &ptr_parse_end, 10);
|
||||
|
||||
if (ptr_parse_end != ptr_optarg_end)
|
||||
return -1;
|
||||
btrfs_list_setup_filter(filters, type, arg);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
14
btrfs-list.h
14
btrfs-list.h
|
@ -62,6 +62,14 @@ enum btrfs_list_filter_enum {
|
|||
BTRFS_LIST_FILTER_ROOTID,
|
||||
BTRFS_LIST_FILTER_SNAPSHOT_ONLY,
|
||||
BTRFS_LIST_FILTER_FLAGS,
|
||||
BTRFS_LIST_FILTER_GEN,
|
||||
BTRFS_LIST_FILTER_GEN_EQUAL = BTRFS_LIST_FILTER_GEN,
|
||||
BTRFS_LIST_FILTER_GEN_LESS,
|
||||
BTRFS_LIST_FILTER_GEN_MORE,
|
||||
BTRFS_LIST_FILTER_CGEN,
|
||||
BTRFS_LIST_FILTER_CGEN_EQUAL = BTRFS_LIST_FILTER_CGEN,
|
||||
BTRFS_LIST_FILTER_CGEN_LESS,
|
||||
BTRFS_LIST_FILTER_CGEN_MORE,
|
||||
BTRFS_LIST_FILTER_MAX,
|
||||
};
|
||||
|
||||
|
@ -69,9 +77,15 @@ enum btrfs_list_comp_enum {
|
|||
BTRFS_LIST_COMP_ROOTID,
|
||||
BTRFS_LIST_COMP_OGEN,
|
||||
BTRFS_LIST_COMP_GEN,
|
||||
BTRFS_LIST_COMP_PATH,
|
||||
BTRFS_LIST_COMP_MAX,
|
||||
};
|
||||
|
||||
int btrfs_list_parse_sort_string(char *optarg,
|
||||
struct btrfs_list_comparer_set **comps);
|
||||
int btrfs_list_parse_filter_string(char *optarg,
|
||||
struct btrfs_list_filter_set **filters,
|
||||
enum btrfs_list_filter_enum type);
|
||||
void btrfs_list_setup_print_column(enum btrfs_list_column_enum column);
|
||||
struct btrfs_list_filter_set *btrfs_list_alloc_filter_set(void);
|
||||
void btrfs_list_free_filter_set(struct btrfs_list_filter_set *filter_set);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "kerncompat.h"
|
||||
#include "ioctl.h"
|
||||
|
@ -259,7 +260,8 @@ static int cmd_subvol_delete(int argc, char **argv)
|
|||
}
|
||||
|
||||
static const char * const cmd_subvol_list_usage[] = {
|
||||
"btrfs subvolume list [-pur] [-s 0|1] <path>",
|
||||
"btrfs subvolume list [-pur] [-s 0|1] [-g [+|-]value] [-c [+|-]value] "
|
||||
"[--sort=gen,ogen,rootid,path] <path>",
|
||||
"List subvolumes (and snapshots)",
|
||||
"",
|
||||
"-p print parent ID",
|
||||
|
@ -267,7 +269,17 @@ static const char * const cmd_subvol_list_usage[] = {
|
|||
"-s value list snapshots with generation in ascending/descending order",
|
||||
" (1: ascending, 0: descending)",
|
||||
"-r list readonly subvolumes (including snapshots)",
|
||||
NULL
|
||||
"-g [+|-]value",
|
||||
" filter the subvolumes by generation",
|
||||
" (+value: >= value; -value: <= value; value: = value)",
|
||||
"-c [+|-]value",
|
||||
" filter the subvolumes by ogeneration",
|
||||
" (+value: >= value; -value: <= value; value: = value)",
|
||||
"--sort=gen,ogen,rootid,path",
|
||||
" list the subvolume in order of gen, ogen, rootid or path",
|
||||
" you also can add '+' or '-' in front of each items.",
|
||||
" (+:ascending, -:descending, ascending default)",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int cmd_subvol_list(int argc, char **argv)
|
||||
|
@ -278,14 +290,20 @@ static int cmd_subvol_list(int argc, char **argv)
|
|||
int fd;
|
||||
int ret;
|
||||
int order;
|
||||
int c;
|
||||
char *subvol;
|
||||
struct option long_options[] = {
|
||||
{"sort", 1, NULL, 'S'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
filter_set = btrfs_list_alloc_filter_set();
|
||||
comparer_set = btrfs_list_alloc_comparer_set();
|
||||
|
||||
optind = 1;
|
||||
while(1) {
|
||||
int c = getopt(argc, argv, "ps:ur");
|
||||
c = getopt_long(argc, argv,
|
||||
"ps:urg:c:", long_options, NULL);
|
||||
if (c < 0)
|
||||
break;
|
||||
|
||||
|
@ -303,13 +321,37 @@ static int cmd_subvol_list(int argc, char **argv)
|
|||
!order);
|
||||
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 '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)
|
||||
usage(cmd_subvol_list_usage);
|
||||
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)
|
||||
usage(cmd_subvol_list_usage);
|
||||
break;
|
||||
case 'S':
|
||||
ret = btrfs_list_parse_sort_string(optarg,
|
||||
&comparer_set);
|
||||
if (ret)
|
||||
usage(cmd_subvol_list_usage);
|
||||
break;
|
||||
|
||||
default:
|
||||
usage(cmd_subvol_list_usage);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ btrfs \- control a btrfs filesystem
|
|||
.PP
|
||||
\fBbtrfs\fP \fBsubvolume create\fP\fI [<dest>/]<name>\fP
|
||||
.PP
|
||||
\fBbtrfs\fP \fBsubvolume list\fP\fI [-pr] <path>\fP
|
||||
\fBbtrfs\fP \fBsubvolume list\fP\fI [-pr] [-s 0|1] [-g [+|-]value] [-c [+|-]value] [--rootid=rootid,gen,ogen,path] <path>\fP
|
||||
.PP
|
||||
\fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP
|
||||
.PP
|
||||
|
@ -108,18 +108,41 @@ Create a subvolume in \fI<dest>\fR (or in the current directory if
|
|||
\fI<dest>\fR is omitted).
|
||||
.TP
|
||||
|
||||
\fBsubvolume list\fR\fI [-pr] <path>\fR
|
||||
\fBsubvolume list\fR\fI [-pr][-s 0|1] [-g [+|-]value] [-c [+|-]value] [--sort=gen,ogen,rootid,path] <path>\fR
|
||||
.RS
|
||||
List the subvolumes present in the filesystem \fI<path>\fR. For every
|
||||
subvolume the following information is shown by default.
|
||||
ID <ID> top level <ID> path <path>
|
||||
where path is the relative path of the subvolume to the \fItop level\fR
|
||||
subvolume.
|
||||
|
||||
The subvolume's ID may be used by the \fBsubvolume set-default\fR command, or
|
||||
at mount time via the \fIsubvol=\fR option.
|
||||
If \fI-p\fR is given, then \fIparent <ID>\fR is added to the output between ID
|
||||
and top level. The parent's ID may be used at mount time via the
|
||||
\fIsubvolrootid=\fR option.
|
||||
If \fI-r\fR is given, only readonly subvolumes in the filesystem will be listed.
|
||||
|
||||
\fB-r\fP only readonly subvolumes in the filesystem wille be listed.
|
||||
|
||||
\fB-s\fP only snapshot subvolumes in the filesystem will be listed.
|
||||
|
||||
\fB-g [+|-]value\fP
|
||||
list subvolumes in the filesystem that its generation is
|
||||
>=, <= or = value. '+' means >= value, '-' means <= value, If there is
|
||||
neither '+' nor '-', it means = value.
|
||||
|
||||
\fB-c [+|-]value\fP
|
||||
list subvolumes in the filesystem that its ogeneration is
|
||||
>=, <= or = value. The usage is the same to '-g' option.
|
||||
|
||||
\fB--sort=gen,ogen,path,rootid\fP
|
||||
list subvolumes in order by specified items.
|
||||
you can add '+' or '-' in front of each items, '+' means ascending,'-'
|
||||
means descending. The default is ascending.
|
||||
|
||||
for \fB--sort\fP you can combine some items together by ',', just like
|
||||
\f--sort=+ogen,-gen,path,rootid\fR.
|
||||
.RE
|
||||
.TP
|
||||
|
||||
\fBsubvolume set-default\fR\fI <id> <path>\fR
|
||||
|
|
Loading…
Reference in a new issue