From: Anand Jain <anand.j...@oracle.com>

This will add new option -x to the btrfs subvol list
sub-command to display the snapshots under its parent subvol
with appropriate indentation.

Signed-off-by: Anand Jain <anand.j...@oracle.com>
---
 btrfs-list.c     |  135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 cmds-subvolume.c |    6 ++-
 man/btrfs.8.in   |    4 +-
 3 files changed, 143 insertions(+), 2 deletions(-)

diff --git a/btrfs-list.c b/btrfs-list.c
index 571efd0..43c279c 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -150,6 +150,11 @@ struct {
        },
 };
 
+struct str_print {
+       char path[BTRFS_PATH_NAME_MAX];
+       char otime[256];
+};
+
 static btrfs_list_filter_func all_filter_funcs[];
 static btrfs_list_comp_func all_comp_funcs[];
 
@@ -1414,6 +1419,133 @@ static void print_single_volume_info_default(struct 
root_info *subv)
        printf("\n");
 }
 
+static void print_single_volume_info_tree(struct root_info *subv,
+       struct str_print *sp)
+{
+       char tstr[256];
+
+       sprintf(sp->path, "%s", subv->full_path);
+       if (subv->otime)
+               strftime(tstr, 256, "%X %d-%m-%Y", localtime(&subv->otime));
+       else
+               strcpy(tstr, "-");
+       sprintf(sp->otime, "%s", tstr);
+}
+
+int snapshot_is_orphan(struct root_lookup *root_tree, void *uuid)
+{
+       struct rb_node *n;
+       struct root_info *entry;
+
+       n = rb_first(&root_tree->root);
+       while (n) {
+               entry = rb_entry(n, struct root_info, sort_node);
+               if ( ! uuid_compare(entry->uuid, uuid)) {
+                       return 0;
+               }
+               n = rb_next(n);
+       }
+       return 1;
+}
+
+void * print_snapshots_of(struct root_lookup *root_tree, void *uuid,
+       int indent, struct str_print *sp)
+{
+       struct rb_node *n;
+       struct root_info *entry;
+       int i = indent;
+       char ispace[BTRFS_PATH_NAME_MAX + 256];
+       char *ispacep = ispace;
+
+       n = rb_first(&root_tree->root);
+       while (n) {
+               entry = rb_entry(n, struct root_info, sort_node);
+               if ( ! uuid_compare(entry->puuid, uuid)) {
+                       while(i--) {
+                               sprintf(ispacep,"%s"," ");
+                               ispacep++;
+                       }
+                       print_single_volume_info_tree(entry, sp);
+                       strcat(ispace, sp->path);
+                       strcpy(sp->path, ispace);
+                       sp++;
+                       sp = (struct str_print *) print_snapshots_of(root_tree,
+                               entry->uuid, indent+1, sp);
+               }
+               i = indent;
+               n = rb_next(n);
+       }
+       return sp;
+}
+
+void print_subvol_tree(struct root_lookup *root_tree)
+{
+       struct rb_node *n;
+       struct root_info *entry;
+       int listlen = 0;
+       int max_slen = 0;
+       int pad;
+       int stmp;
+       int i;
+       struct str_print *head;
+       struct str_print *cur;
+
+       n = rb_first(&root_tree->root);
+       while (n) {
+               listlen++;
+               n = rb_next(n);
+       }
+       head = (struct str_print *) malloc(sizeof(struct str_print)*listlen);
+       memset(head, 0, sizeof(struct str_print)*listlen);
+
+       cur = head;
+       n = rb_first(&root_tree->root);
+       while (n) {
+               entry = rb_entry(n, struct root_info, sort_node);
+               if ( uuid_is_null(entry->puuid)) {
+                       print_single_volume_info_tree(entry, cur);
+                       cur++;
+                       cur = (struct str_print *) print_snapshots_of(root_tree,
+                                       entry->uuid, 1, cur);
+               }
+               n = rb_next(n);
+       }
+       n = rb_first(&root_tree->root);
+       while (n) {
+               entry = rb_entry(n, struct root_info, sort_node);
+               if ( !uuid_is_null(entry->puuid)
+                       && snapshot_is_orphan(root_tree, entry->puuid)) {
+                       print_single_volume_info_tree(entry, cur);
+                       cur++;
+                       cur = (struct str_print *) print_snapshots_of(root_tree,
+                                       entry->uuid, 1, cur);
+               }
+               n = rb_next(n);
+       }
+       //BUG_ON(cur != (head + (sizeof(struct str_print) * listlen)));
+
+       cur = head;
+       for (i=0; i < listlen; i++) {
+               stmp = strlen(cur->path);
+               if (stmp > max_slen)
+                       max_slen = stmp;
+               cur++;
+       }
+
+       cur = head;
+       for (i=0; i < listlen; i++) {
+               printf("%s", cur->path);
+               pad = max_slen - strlen(cur->path) + 1;
+               while(pad--)
+                       printf("%s"," ");
+               printf("%s"," ");
+               printf("%s", cur->otime);
+               printf("\n");
+               cur++;
+       }
+       free(head);
+}
+
 static void print_all_volume_info_tab_head()
 {
        int i;
@@ -1467,6 +1599,9 @@ static void print_all_volume_info(struct root_lookup 
*sorted_tree,
                        n = rb_next(n);
                }
                break;
+       case 2: // tree format
+               print_subvol_tree(sorted_tree);
+               break;
        default:
                printf("ERROR: default switch print_all_volume_info\n");
                return;
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index 411a5de..4f2704f 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -281,6 +281,7 @@ static const char * const cmd_subvol_list_usage[] = {
        "-u           print the uuid of subvolumes (and snapshots)",
        "-q           print the parent uuid of snapshots",
        "-t           print the result as a table",
+       "-x           print the result as a tree",
        "-s           list snapshots only in the filesystem",
        "-r           list readonly subvolumes (including snapshots)",
        "-g [+|-]value",
@@ -319,7 +320,7 @@ static int cmd_subvol_list(int argc, char **argv)
        optind = 1;
        while(1) {
                c = getopt_long(argc, argv,
-                                   "apsuqrg:c:t", long_options, NULL);
+                                   "apsuqrg:c:tx", long_options, NULL);
                if (c < 0)
                        break;
 
@@ -333,6 +334,9 @@ static int cmd_subvol_list(int argc, char **argv)
                case 't':
                        layout = 1;
                        break;
+               case 'x':
+                       layout = 2;
+                       break;
                case 's':
                        btrfs_list_setup_filter(&filter_set,
                                                BTRFS_LIST_FILTER_SNAPSHOT_ONLY,
diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index 9222580..1bb0415 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 [-aprts] [-g [+|-]value] [-c [+|-]value] 
[--rootid=rootid,gen,ogen,path] <path>\fP
+\fBbtrfs\fP \fBsubvolume list\fP\fI [-aprtxs] [-g [+|-]value] [-c [+|-]value] 
[--rootid=rootid,gen,ogen,path] <path>\fP
 .PP
 \fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP
 .PP
@@ -124,6 +124,8 @@ and top level. The parent's ID may be used at mount time 
via the
 
 \fB-t\fP print the result as a table.
 
+\fB-x\fP print the result as a tree.
+
 \fB-a\fP print all the subvolumes in the filesystem.
 
 \fB-r\fP only readonly subvolumes in the filesystem wille be listed.
-- 
1.7.1

--
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