2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public
4 * License v2 as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 * General Public License for more details.
11 * You should have received a copy of the GNU General Public
12 * License along with this program; if not, write to the
13 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14 * Boston, MA 021110-1307, USA.
21 #include <sys/ioctl.h>
27 #include <uuid/uuid.h>
29 #include "kerncompat.h"
36 #include "btrfs-list.h"
39 static const char * const subvolume_cmd_group_usage[] = {
40 "btrfs subvolume <command> <args>",
44 static const char * const cmd_subvol_create_usage[] = {
45 "btrfs subvolume create [-i <qgroupid>] [<dest>/]<name>",
47 "Create a subvolume <name> in <dest>. If <dest> is not given",
48 "subvolume <name> will be created in the current directory.",
50 "-i <qgroupid> add the newly created subvolume to a qgroup. This",
51 " option can be given multiple times.",
55 static int cmd_subvol_create(int argc, char **argv)
64 struct btrfs_qgroup_inherit *inherit = NULL;
65 DIR *dirstream = NULL;
69 int c = getopt(argc, argv, "c:i:");
75 res = qgroup_inherit_add_copy(&inherit, optarg, 0);
82 res = qgroup_inherit_add_group(&inherit, optarg);
89 usage(cmd_subvol_create_usage);
93 if (check_argc_exact(argc - optind, 1))
94 usage(cmd_subvol_create_usage);
98 retval = 1; /* failure */
99 res = test_isdir(dst);
101 fprintf(stderr, "ERROR: '%s' exists\n", dst);
105 dupname = strdup(dst);
106 newname = basename(dupname);
107 dupdir = strdup(dst);
108 dstdir = dirname(dupdir);
110 if (!test_issubvolname(newname)) {
111 fprintf(stderr, "ERROR: incorrect subvolume name '%s'\n",
116 len = strlen(newname);
117 if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
118 fprintf(stderr, "ERROR: subvolume name too long '%s'\n",
123 fddst = open_file_or_dir(dstdir, &dirstream);
125 fprintf(stderr, "ERROR: can't access '%s'\n", dstdir);
129 printf("Create subvolume '%s/%s'\n", dstdir, newname);
131 struct btrfs_ioctl_vol_args_v2 args;
133 memset(&args, 0, sizeof(args));
134 strncpy_null(args.name, newname);
135 args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
136 args.size = qgroup_inherit_size(inherit);
137 args.qgroup_inherit = inherit;
139 res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE_V2, &args);
141 struct btrfs_ioctl_vol_args args;
143 memset(&args, 0, sizeof(args));
144 strncpy_null(args.name, newname);
146 res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
150 fprintf(stderr, "ERROR: cannot create subvolume - %s\n",
155 retval = 0; /* success */
157 close_file_or_dir(fddst, dirstream);
166 * test if path is a subvolume:
167 * this function return
168 * 0-> path exists but it is not a subvolume
169 * 1-> path exists and it is a subvolume
170 * -1 -> path is unaccessible
172 int test_issubvolume(char *path)
177 res = stat(path, &st);
181 return (st.st_ino == 256) && S_ISDIR(st.st_mode);
184 static int wait_for_commit(int fd)
188 ret = ioctl(fd, BTRFS_IOC_START_SYNC, NULL);
191 return ioctl(fd, BTRFS_IOC_WAIT_SYNC, NULL);
194 static const char * const cmd_subvol_delete_usage[] = {
195 "btrfs subvolume delete [options] <subvolume> [<subvolume>...]",
196 "Delete subvolume(s)",
197 "Delete subvolumes from the filesystem. The corresponding directory",
198 "is removed instantly but the data blocks are removed later.",
199 "The deletion does not involve full commit by default due to",
200 "performance reasons (as a consequence, the subvolume may appear again",
201 "after a crash). Use one of the --commit options to wait until the",
202 "operation is safely stored on the media.",
204 "-c|--commit-after wait for transaction commit at the end of the operation",
205 "-C|--commit-each wait for transaction commit after deleting each subvolume",
209 static int cmd_subvol_delete(int argc, char **argv)
211 int res, len, e, ret = 0;
214 struct btrfs_ioctl_vol_args args;
215 char *dname, *vname, *cpath;
216 char *dupdname = NULL;
217 char *dupvname = NULL;
219 DIR *dirstream = NULL;
221 struct option long_options[] = {
222 {"commit-after", no_argument, NULL, 'c'}, /* sync mode 1 */
223 {"commit-each", no_argument, NULL, 'C'}, /* sync mode 2 */
231 c = getopt_long(argc, argv, "cC", long_options, NULL);
243 usage(cmd_subvol_delete_usage);
247 if (check_argc_min(argc - optind, 1))
248 usage(cmd_subvol_delete_usage);
250 printf("Transaction commit: %s\n",
251 !sync_mode ? "none (default)" :
252 sync_mode == 1 ? "at the end" : "after each");
259 res = test_issubvolume(path);
261 fprintf(stderr, "ERROR: error accessing '%s'\n", path);
266 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", path);
271 cpath = realpath(path, NULL);
274 fprintf(stderr, "ERROR: finding real path for '%s': %s\n",
275 path, strerror(errno));
278 dupdname = strdup(cpath);
279 dname = dirname(dupdname);
280 dupvname = strdup(cpath);
281 vname = basename(dupvname);
284 if (!test_issubvolname(vname)) {
285 fprintf(stderr, "ERROR: incorrect subvolume name '%s'\n",
292 if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
293 fprintf(stderr, "ERROR: snapshot name too long '%s'\n",
299 fd = open_file_or_dir(dname, &dirstream);
301 fprintf(stderr, "ERROR: can't access '%s'\n", dname);
306 printf("Delete subvolume '%s/%s'\n", dname, vname);
307 strncpy_null(args.name, vname);
308 res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
312 fprintf( stderr, "ERROR: cannot delete '%s/%s' - %s\n",
313 dname, vname, strerror(e));
318 if (sync_mode == 1) {
319 res = wait_for_commit(fd);
322 "ERROR: unable to wait for commit after '%s': %s\n",
323 path, strerror(errno));
335 close_file_or_dir(fd, dirstream);
336 /* avoid double free */
342 if (sync_mode == 2 && fd != -1) {
343 res = wait_for_commit(fd);
346 "ERROR: unable to do final sync: %s\n",
351 close_file_or_dir(fd, dirstream);
358 * - uppercase for filters and sort options
359 * - lowercase for enabling specific items in the output
361 static const char * const cmd_subvol_list_usage[] = {
362 "btrfs subvolume list [options] [-G [+|-]value] [-C [+|-]value] "
363 "[--sort=gen,ogen,rootid,path] <path>",
364 "List subvolumes (and snapshots)",
366 "-p print parent ID",
367 "-a print all the subvolumes in the filesystem and",
368 " distinguish absolute and relative path with respect",
369 " to the given <path>",
370 "-c print the ogeneration of the subvolume",
371 "-g print the generation of the subvolume",
372 "-o print only subvolumes bellow specified path",
373 "-u print the uuid of subvolumes (and snapshots)",
374 "-q print the parent uuid of the snapshots",
375 "-t print the result as a table",
376 "-s list snapshots only in the filesystem",
377 "-r list readonly subvolumes (including snapshots)",
378 "-d list deleted subvolumes that are not yet cleaned",
380 " filter the subvolumes by generation",
381 " (+value: >= value; -value: <= value; value: = value)",
383 " filter the subvolumes by ogeneration",
384 " (+value: >= value; -value: <= value; value: = value)",
385 "--sort=gen,ogen,rootid,path",
386 " list the subvolume in order of gen, ogen, rootid or path",
387 " you also can add '+' or '-' in front of each items.",
388 " (+:ascending, -:descending, ascending default)",
392 static int cmd_subvol_list(int argc, char **argv)
394 struct btrfs_list_filter_set *filter_set;
395 struct btrfs_list_comparer_set *comparer_set;
399 int ret = -1, uerr = 0;
402 int is_tab_result = 0;
404 int is_only_in_path = 0;
405 struct option long_options[] = {
406 {"sort", 1, NULL, 'S'},
409 DIR *dirstream = NULL;
411 filter_set = btrfs_list_alloc_filter_set();
412 comparer_set = btrfs_list_alloc_comparer_set();
416 c = getopt_long(argc, argv,
417 "acdgopqsurG:C:t", long_options, NULL);
423 btrfs_list_setup_print_column(BTRFS_LIST_PARENT);
429 btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
432 btrfs_list_setup_filter(&filter_set,
433 BTRFS_LIST_FILTER_DELETED,
437 btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
446 btrfs_list_setup_filter(&filter_set,
447 BTRFS_LIST_FILTER_SNAPSHOT_ONLY,
449 btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
450 btrfs_list_setup_print_column(BTRFS_LIST_OTIME);
453 btrfs_list_setup_print_column(BTRFS_LIST_UUID);
456 btrfs_list_setup_print_column(BTRFS_LIST_PUUID);
459 flags |= BTRFS_ROOT_SUBVOL_RDONLY;
462 btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
463 ret = btrfs_list_parse_filter_string(optarg,
465 BTRFS_LIST_FILTER_GEN);
473 btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
474 ret = btrfs_list_parse_filter_string(optarg,
476 BTRFS_LIST_FILTER_CGEN);
483 ret = btrfs_list_parse_sort_string(optarg,
498 btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_FLAGS,
501 if (check_argc_exact(argc - optind, 1)) {
506 subvol = argv[optind];
507 fd = open_file_or_dir(subvol, &dirstream);
510 fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
514 ret = btrfs_list_get_path_rootid(fd, &top_id);
516 fprintf(stderr, "ERROR: can't get rootid for '%s'\n", subvol);
521 btrfs_list_setup_filter(&filter_set,
522 BTRFS_LIST_FILTER_FULL_PATH,
524 else if (is_only_in_path)
525 btrfs_list_setup_filter(&filter_set,
526 BTRFS_LIST_FILTER_TOPID_EQUAL,
529 /* by default we shall print the following columns*/
530 btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
531 btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
532 btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
533 btrfs_list_setup_print_column(BTRFS_LIST_PATH);
536 ret = btrfs_list_subvols_print(fd, filter_set, comparer_set,
537 BTRFS_LIST_LAYOUT_TABLE,
538 !is_list_all && !is_only_in_path, NULL);
540 ret = btrfs_list_subvols_print(fd, filter_set, comparer_set,
541 BTRFS_LIST_LAYOUT_DEFAULT,
542 !is_list_all && !is_only_in_path, NULL);
545 close_file_or_dir(fd, dirstream);
547 btrfs_list_free_filter_set(filter_set);
549 btrfs_list_free_comparer_set(comparer_set);
551 usage(cmd_subvol_list_usage);
555 static const char * const cmd_snapshot_usage[] = {
556 "btrfs subvolume snapshot [-r] <source> <dest>|[<dest>/]<name>",
557 "btrfs subvolume snapshot [-r] [-i <qgroupid>] <source> <dest>|[<dest>/]<name>",
558 "Create a snapshot of the subvolume",
559 "Create a writable/readonly snapshot of the subvolume <source> with",
560 "the name <name> in the <dest> directory. If only <dest> is given,",
561 "the subvolume will be named the basename of <source>.",
563 "-r create a readonly snapshot",
564 "-i <qgroupid> add the newly created snapshot to a qgroup. This",
565 " option can be given multiple times.",
569 static int cmd_snapshot(int argc, char **argv)
573 int fd = -1, fddst = -1;
574 int len, readonly = 0;
575 char *dupname = NULL;
579 struct btrfs_ioctl_vol_args_v2 args;
580 struct btrfs_qgroup_inherit *inherit = NULL;
581 DIR *dirstream1 = NULL, *dirstream2 = NULL;
584 memset(&args, 0, sizeof(args));
586 int c = getopt(argc, argv, "c:i:r");
592 res = qgroup_inherit_add_copy(&inherit, optarg, 0);
599 res = qgroup_inherit_add_group(&inherit, optarg);
609 res = qgroup_inherit_add_copy(&inherit, optarg, 1);
616 usage(cmd_snapshot_usage);
620 if (check_argc_exact(argc - optind, 2))
621 usage(cmd_snapshot_usage);
623 subvol = argv[optind];
624 dst = argv[optind + 1];
626 retval = 1; /* failure */
627 res = test_issubvolume(subvol);
629 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
633 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
637 res = test_isdir(dst);
639 fprintf(stderr, "ERROR: '%s' exists and it is not a directory\n", dst);
644 dupname = strdup(subvol);
645 newname = basename(dupname);
648 dupname = strdup(dst);
649 newname = basename(dupname);
650 dupdir = strdup(dst);
651 dstdir = dirname(dupdir);
654 if (!test_issubvolname(newname)) {
655 fprintf(stderr, "ERROR: incorrect snapshot name '%s'\n",
660 len = strlen(newname);
661 if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
662 fprintf(stderr, "ERROR: snapshot name too long '%s'\n",
667 fddst = open_file_or_dir(dstdir, &dirstream1);
669 fprintf(stderr, "ERROR: can't access '%s'\n", dstdir);
673 fd = open_file_or_dir(subvol, &dirstream2);
675 fprintf(stderr, "ERROR: can't access '%s'\n", dstdir);
680 args.flags |= BTRFS_SUBVOL_RDONLY;
681 printf("Create a readonly snapshot of '%s' in '%s/%s'\n",
682 subvol, dstdir, newname);
684 printf("Create a snapshot of '%s' in '%s/%s'\n",
685 subvol, dstdir, newname);
690 args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
691 args.size = qgroup_inherit_size(inherit);
692 args.qgroup_inherit = inherit;
694 strncpy_null(args.name, newname);
696 res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);
699 fprintf( stderr, "ERROR: cannot snapshot '%s' - %s\n",
700 subvol, strerror(errno));
704 retval = 0; /* success */
707 close_file_or_dir(fddst, dirstream1);
708 close_file_or_dir(fd, dirstream2);
716 static const char * const cmd_subvol_get_default_usage[] = {
717 "btrfs subvolume get-default <path>",
718 "Get the default subvolume of a filesystem",
722 static int cmd_subvol_get_default(int argc, char **argv)
727 struct btrfs_list_filter_set *filter_set;
729 DIR *dirstream = NULL;
731 if (check_argc_exact(argc, 2))
732 usage(cmd_subvol_get_default_usage);
735 fd = open_file_or_dir(subvol, &dirstream);
737 fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
741 ret = btrfs_list_get_default_subvolume(fd, &default_id);
743 fprintf(stderr, "ERROR: can't perform the search - %s\n",
749 if (default_id == 0) {
750 fprintf(stderr, "ERROR: 'default' dir item not found\n");
754 /* no need to resolve roots if FS_TREE is default */
755 if (default_id == BTRFS_FS_TREE_OBJECTID) {
756 printf("ID 5 (FS_TREE)\n");
761 filter_set = btrfs_list_alloc_filter_set();
762 btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_ROOTID,
765 /* by default we shall print the following columns*/
766 btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
767 btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
768 btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
769 btrfs_list_setup_print_column(BTRFS_LIST_PATH);
771 ret = btrfs_list_subvols_print(fd, filter_set, NULL,
772 BTRFS_LIST_LAYOUT_DEFAULT, 1, NULL);
775 btrfs_list_free_filter_set(filter_set);
777 close_file_or_dir(fd, dirstream);
781 static const char * const cmd_subvol_set_default_usage[] = {
782 "btrfs subvolume set-default <subvolid> <path>",
783 "Set the default subvolume of a filesystem",
787 static int cmd_subvol_set_default(int argc, char **argv)
793 DIR *dirstream = NULL;
795 if (check_argc_exact(argc, 3))
796 usage(cmd_subvol_set_default_usage);
801 objectid = arg_strtou64(subvolid);
803 fd = open_file_or_dir(path, &dirstream);
805 fprintf(stderr, "ERROR: can't access '%s'\n", path);
809 ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
811 close_file_or_dir(fd, dirstream);
813 fprintf(stderr, "ERROR: unable to set a new default subvolume - %s\n",
820 static const char * const cmd_find_new_usage[] = {
821 "btrfs subvolume find-new <path> <lastgen>",
822 "List the recently modified files in a filesystem",
826 static int cmd_find_new(int argc, char **argv)
832 DIR *dirstream = NULL;
834 if (check_argc_exact(argc, 3))
835 usage(cmd_find_new_usage);
838 last_gen = arg_strtou64(argv[2]);
840 ret = test_issubvolume(subvol);
842 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
846 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
850 fd = open_file_or_dir(subvol, &dirstream);
852 fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
856 ret = ioctl(fd, BTRFS_IOC_SYNC);
858 fprintf(stderr, "ERROR: unable to fs-syncing '%s' - %s\n",
859 subvol, strerror(errno));
860 close_file_or_dir(fd, dirstream);
864 ret = btrfs_list_find_updated_files(fd, 0, last_gen);
865 close_file_or_dir(fd, dirstream);
869 static const char * const cmd_subvol_show_usage[] = {
870 "btrfs subvolume show <subvol-path>",
871 "Show more information of the subvolume",
875 static int cmd_subvol_show(int argc, char **argv)
877 struct root_info get_ri;
878 struct btrfs_list_filter_set *filter_set;
880 char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
881 char *fullpath = NULL, *svpath = NULL, *mnt = NULL;
882 char raw_prefix[] = "\t\t\t\t";
884 int fd = -1, mntfd = -1;
886 DIR *dirstream1 = NULL, *dirstream2 = NULL;
888 if (check_argc_exact(argc, 2))
889 usage(cmd_subvol_show_usage);
891 fullpath = realpath(argv[1], NULL);
893 fprintf(stderr, "ERROR: finding real path for '%s', %s\n",
894 argv[1], strerror(errno));
898 ret = test_issubvolume(fullpath);
900 fprintf(stderr, "ERROR: error accessing '%s'\n", fullpath);
904 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", fullpath);
908 ret = find_mount_root(fullpath, &mnt);
910 fprintf(stderr, "ERROR: find_mount_root failed on '%s': "
911 "%s\n", fullpath, strerror(-ret));
916 "ERROR: %s doesn't belong to btrfs mount point\n",
922 svpath = get_subvol_name(mnt, fullpath);
924 fd = open_file_or_dir(fullpath, &dirstream1);
926 fprintf(stderr, "ERROR: can't access '%s'\n", fullpath);
930 ret = btrfs_list_get_path_rootid(fd, &sv_id);
932 fprintf(stderr, "ERROR: can't get rootid for '%s'\n",
937 mntfd = open_file_or_dir(mnt, &dirstream2);
939 fprintf(stderr, "ERROR: can't access '%s'\n", mnt);
943 ret = btrfs_list_get_path_rootid(mntfd, &mntid);
945 fprintf(stderr, "ERROR: can't get rootid for '%s'\n", mnt);
949 if (sv_id == BTRFS_FS_TREE_OBJECTID) {
950 printf("%s is btrfs root\n", fullpath);
954 memset(&get_ri, 0, sizeof(get_ri));
955 get_ri.root_id = sv_id;
957 if (btrfs_get_subvol(mntfd, &get_ri)) {
958 fprintf(stderr, "ERROR: can't find '%s'\n",
965 printf("%s\n", fullpath);
966 printf("\tName: \t\t\t%s\n", get_ri.name);
968 if (uuid_is_null(get_ri.uuid))
969 strcpy(uuidparse, "-");
971 uuid_unparse(get_ri.uuid, uuidparse);
972 printf("\tuuid: \t\t\t%s\n", uuidparse);
974 if (uuid_is_null(get_ri.puuid))
975 strcpy(uuidparse, "-");
977 uuid_unparse(get_ri.puuid, uuidparse);
978 printf("\tParent uuid: \t\t%s\n", uuidparse);
983 localtime_r(&get_ri.otime, &tm);
984 strftime(tstr, 256, "%Y-%m-%d %X", &tm);
987 printf("\tCreation time: \t\t%s\n", tstr);
989 printf("\tObject ID: \t\t%llu\n", get_ri.root_id);
990 printf("\tGeneration (Gen): \t%llu\n", get_ri.gen);
991 printf("\tGen at creation: \t%llu\n", get_ri.ogen);
992 printf("\tParent: \t\t%llu\n", get_ri.ref_tree);
993 printf("\tTop Level: \t\t%llu\n", get_ri.top_id);
995 if (get_ri.flags & BTRFS_ROOT_SUBVOL_RDONLY)
996 printf("\tFlags: \t\t\treadonly\n");
998 printf("\tFlags: \t\t\t-\n");
1000 /* print the snapshots of the given subvol if any*/
1001 printf("\tSnapshot(s):\n");
1002 filter_set = btrfs_list_alloc_filter_set();
1003 btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_BY_PARENT,
1004 (u64)(unsigned long)get_ri.uuid);
1005 btrfs_list_setup_print_column(BTRFS_LIST_PATH);
1006 btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
1012 free(get_ri.full_path);
1013 btrfs_list_free_filter_set(filter_set);
1016 close_file_or_dir(fd, dirstream1);
1017 close_file_or_dir(mntfd, dirstream2);
1023 const struct cmd_group subvolume_cmd_group = {
1024 subvolume_cmd_group_usage, NULL, {
1025 { "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
1026 { "delete", cmd_subvol_delete, cmd_subvol_delete_usage, NULL, 0 },
1027 { "list", cmd_subvol_list, cmd_subvol_list_usage, NULL, 0 },
1028 { "snapshot", cmd_snapshot, cmd_snapshot_usage, NULL, 0 },
1029 { "get-default", cmd_subvol_get_default,
1030 cmd_subvol_get_default_usage, NULL, 0 },
1031 { "set-default", cmd_subvol_set_default,
1032 cmd_subvol_set_default_usage, NULL, 0 },
1033 { "find-new", cmd_find_new, cmd_find_new_usage, NULL, 0 },
1034 { "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
1039 int cmd_subvolume(int argc, char **argv)
1041 return handle_command_group(&subvolume_cmd_group, argc, argv);