From: Wang Shilong <wangsl-f...@cn.fujitsu.com>

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-f...@cn.fujitsu.com>
Signed-off-by: Miao Xie <mi...@cn.fujitsu.com>
---
This patch is based on patchset:
[PATCH V4 0/7 ] Btrfs-progs: enhance btrfs subvol list only to show read-only 
snapshots
---
 btrfs-list.c     |  168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 btrfs-list.h     |   14 +++++
 cmds-subvolume.c |   50 +++++++++++++++-
 man/btrfs.8.in   |   29 ++++++++-
 4 files changed, 254 insertions(+), 7 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index 201f378..c6d9a18 100644
--- a/btrfs-list.c
+++ b/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;
+}
+
diff --git a/btrfs-list.h b/btrfs-list.h
index 21d0fdc..26a5c17 100644
--- a/btrfs-list.h
+++ b/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);
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index f385816..f5da022 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -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);
                }
diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index 0845b4d..5c95ccc 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -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
-- 
1.7.6.5
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to