btrfs-progs: subvol: group options in help
[platform/upstream/btrfs-progs.git] / cmds-subvolume.c
1 /*
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.
5  *
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.
10  *
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.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/ioctl.h>
22 #include <errno.h>
23 #include <sys/stat.h>
24 #include <sys/vfs.h>
25 #include <libgen.h>
26 #include <limits.h>
27 #include <getopt.h>
28 #include <uuid/uuid.h>
29 #include <linux/magic.h>
30
31 #include "kerncompat.h"
32 #include "ioctl.h"
33 #include "qgroup.h"
34
35 #include "ctree.h"
36 #include "commands.h"
37 #include "utils.h"
38 #include "btrfs-list.h"
39 #include "utils.h"
40 #include "help.h"
41
42 static int is_subvolume_cleaned(int fd, u64 subvolid)
43 {
44         int ret;
45         struct btrfs_ioctl_search_args args;
46         struct btrfs_ioctl_search_key *sk = &args.key;
47
48         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
49         sk->min_objectid = subvolid;
50         sk->max_objectid = subvolid;
51         sk->min_type = BTRFS_ROOT_ITEM_KEY;
52         sk->max_type = BTRFS_ROOT_ITEM_KEY;
53         sk->min_offset = 0;
54         sk->max_offset = (u64)-1;
55         sk->min_transid = 0;
56         sk->max_transid = (u64)-1;
57         sk->nr_items = 1;
58
59         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
60         if (ret < 0)
61                 return -errno;
62
63         if (sk->nr_items == 0)
64                 return 1;
65
66         return 0;
67 }
68
69 static int wait_for_subvolume_cleaning(int fd, int count, u64 *ids,
70                 int sleep_interval)
71 {
72         int ret;
73         int i;
74
75         while (1) {
76                 int clean = 1;
77
78                 for (i = 0; i < count; i++) {
79                         if (!ids[i])
80                                 continue;
81                         ret = is_subvolume_cleaned(fd, ids[i]);
82                         if (ret < 0) {
83                                 error(
84                             "cannot read status of dead subvolume %llu: %s",
85                                         (unsigned long long)ids[i], strerror(-ret));
86                                 return ret;
87                         }
88                         if (ret) {
89                                 printf("Subvolume id %llu is gone\n", ids[i]);
90                                 ids[i] = 0;
91                         } else {
92                                 clean = 0;
93                         }
94                 }
95                 if (clean)
96                         break;
97                 sleep(sleep_interval);
98         }
99
100         return 0;
101 }
102
103 static const char * const subvolume_cmd_group_usage[] = {
104         "btrfs subvolume <command> <args>",
105         NULL
106 };
107
108 static const char * const cmd_subvol_create_usage[] = {
109         "btrfs subvolume create [-i <qgroupid>] [<dest>/]<name>",
110         "Create a subvolume",
111         "Create a subvolume <name> in <dest>.  If <dest> is not given",
112         "subvolume <name> will be created in the current directory.",
113         "",
114         "-i <qgroupid>  add the newly created subvolume to a qgroup. This",
115         "               option can be given multiple times.",
116         NULL
117 };
118
119 static int cmd_subvol_create(int argc, char **argv)
120 {
121         int     retval, res, len;
122         int     fddst = -1;
123         char    *dupname = NULL;
124         char    *dupdir = NULL;
125         char    *newname;
126         char    *dstdir;
127         char    *dst;
128         struct btrfs_qgroup_inherit *inherit = NULL;
129         DIR     *dirstream = NULL;
130
131         while (1) {
132                 int c = getopt(argc, argv, "c:i:");
133                 if (c < 0)
134                         break;
135
136                 switch (c) {
137                 case 'c':
138                         res = qgroup_inherit_add_copy(&inherit, optarg, 0);
139                         if (res) {
140                                 retval = res;
141                                 goto out;
142                         }
143                         break;
144                 case 'i':
145                         res = qgroup_inherit_add_group(&inherit, optarg);
146                         if (res) {
147                                 retval = res;
148                                 goto out;
149                         }
150                         break;
151                 default:
152                         usage(cmd_subvol_create_usage);
153                 }
154         }
155
156         if (check_argc_exact(argc - optind, 1))
157                 usage(cmd_subvol_create_usage);
158
159         dst = argv[optind];
160
161         retval = 1;     /* failure */
162         res = test_isdir(dst);
163         if (res < 0 && res != -ENOENT) {
164                 error("cannot access %s: %s", dst, strerror(-res));
165                 goto out;
166         }
167         if (res >= 0) {
168                 error("target path already exists: %s", dst);
169                 goto out;
170         }
171
172         dupname = strdup(dst);
173         newname = basename(dupname);
174         dupdir = strdup(dst);
175         dstdir = dirname(dupdir);
176
177         if (!test_issubvolname(newname)) {
178                 error("invalid subvolume name: %s", newname);
179                 goto out;
180         }
181
182         len = strlen(newname);
183         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
184                 error("subvolume name too long: %s", newname);
185                 goto out;
186         }
187
188         fddst = btrfs_open_dir(dstdir, &dirstream, 1);
189         if (fddst < 0)
190                 goto out;
191
192         printf("Create subvolume '%s/%s'\n", dstdir, newname);
193         if (inherit) {
194                 struct btrfs_ioctl_vol_args_v2  args;
195
196                 memset(&args, 0, sizeof(args));
197                 strncpy_null(args.name, newname);
198                 args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
199                 args.size = qgroup_inherit_size(inherit);
200                 args.qgroup_inherit = inherit;
201
202                 res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE_V2, &args);
203         } else {
204                 struct btrfs_ioctl_vol_args     args;
205
206                 memset(&args, 0, sizeof(args));
207                 strncpy_null(args.name, newname);
208
209                 res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
210         }
211
212         if (res < 0) {
213                 error("cannot create subvolume: %s", strerror(errno));
214                 goto out;
215         }
216
217         retval = 0;     /* success */
218 out:
219         close_file_or_dir(fddst, dirstream);
220         free(inherit);
221         free(dupname);
222         free(dupdir);
223
224         return retval;
225 }
226
227 static int wait_for_commit(int fd)
228 {
229         int ret;
230
231         ret = ioctl(fd, BTRFS_IOC_START_SYNC, NULL);
232         if (ret < 0)
233                 return ret;
234         return ioctl(fd, BTRFS_IOC_WAIT_SYNC, NULL);
235 }
236
237 static const char * const cmd_subvol_delete_usage[] = {
238         "btrfs subvolume delete [options] <subvolume> [<subvolume>...]",
239         "Delete subvolume(s)",
240         "Delete subvolumes from the filesystem. The corresponding directory",
241         "is removed instantly but the data blocks are removed later.",
242         "The deletion does not involve full commit by default due to",
243         "performance reasons (as a consequence, the subvolume may appear again",
244         "after a crash). Use one of the --commit options to wait until the",
245         "operation is safely stored on the media.",
246         "",
247         "-c|--commit-after      wait for transaction commit at the end of the operation",
248         "-C|--commit-each       wait for transaction commit after deleting each subvolume",
249         "-v|--verbose           verbose output of operations",
250         NULL
251 };
252
253 static int cmd_subvol_delete(int argc, char **argv)
254 {
255         int res, ret = 0;
256         int cnt;
257         int fd = -1;
258         struct btrfs_ioctl_vol_args     args;
259         char    *dname, *vname, *cpath;
260         char    *dupdname = NULL;
261         char    *dupvname = NULL;
262         char    *path;
263         DIR     *dirstream = NULL;
264         int verbose = 0;
265         int commit_mode = 0;
266         u8 fsid[BTRFS_FSID_SIZE];
267         char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
268         struct seen_fsid *seen_fsid_hash[SEEN_FSID_HASH_SIZE] = { NULL, };
269         enum { COMMIT_AFTER = 1, COMMIT_EACH = 2 };
270
271         while (1) {
272                 int c;
273                 static const struct option long_options[] = {
274                         {"commit-after", no_argument, NULL, 'c'},
275                         {"commit-each", no_argument, NULL, 'C'},
276                         {"verbose", no_argument, NULL, 'v'},
277                         {NULL, 0, NULL, 0}
278                 };
279
280                 c = getopt_long(argc, argv, "cCv", long_options, NULL);
281                 if (c < 0)
282                         break;
283
284                 switch(c) {
285                 case 'c':
286                         commit_mode = COMMIT_AFTER;
287                         break;
288                 case 'C':
289                         commit_mode = COMMIT_EACH;
290                         break;
291                 case 'v':
292                         verbose++;
293                         break;
294                 default:
295                         usage(cmd_subvol_delete_usage);
296                 }
297         }
298
299         if (check_argc_min(argc - optind, 1))
300                 usage(cmd_subvol_delete_usage);
301
302         if (verbose > 0) {
303                 printf("Transaction commit: %s\n",
304                         !commit_mode ? "none (default)" :
305                         commit_mode == COMMIT_AFTER ? "at the end" : "after each");
306         }
307
308         cnt = optind;
309
310 again:
311         path = argv[cnt];
312
313         res = test_issubvolume(path);
314         if (res < 0) {
315                 error("cannot access subvolume %s: %s", path, strerror(-res));
316                 ret = 1;
317                 goto out;
318         }
319         if (!res) {
320                 error("not a subvolume: %s", path);
321                 ret = 1;
322                 goto out;
323         }
324
325         cpath = realpath(path, NULL);
326         if (!cpath) {
327                 ret = errno;
328                 error("cannot find real path for '%s': %s",
329                         path, strerror(errno));
330                 goto out;
331         }
332         dupdname = strdup(cpath);
333         dname = dirname(dupdname);
334         dupvname = strdup(cpath);
335         vname = basename(dupvname);
336         free(cpath);
337
338         fd = btrfs_open_dir(dname, &dirstream, 1);
339         if (fd < 0) {
340                 ret = 1;
341                 goto out;
342         }
343
344         printf("Delete subvolume (%s): '%s/%s'\n",
345                 commit_mode == COMMIT_EACH || (commit_mode == COMMIT_AFTER && cnt + 1 == argc)
346                 ? "commit" : "no-commit", dname, vname);
347         memset(&args, 0, sizeof(args));
348         strncpy_null(args.name, vname);
349         res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
350         if(res < 0 ){
351                 error("cannot delete '%s/%s': %s", dname, vname,
352                         strerror(errno));
353                 ret = 1;
354                 goto out;
355         }
356
357         if (commit_mode == COMMIT_EACH) {
358                 res = wait_for_commit(fd);
359                 if (res < 0) {
360                         error("unable to wait for commit after '%s': %s",
361                                 path, strerror(errno));
362                         ret = 1;
363                 }
364         } else if (commit_mode == COMMIT_AFTER) {
365                 res = get_fsid(dname, fsid, 0);
366                 if (res < 0) {
367                         error("unable to get fsid for '%s': %s",
368                                 path, strerror(-res));
369                         error(
370                         "delete suceeded but commit may not be done in the end");
371                         ret = 1;
372                         goto out;
373                 }
374
375                 if (add_seen_fsid(fsid, seen_fsid_hash, fd, dirstream) == 0) {
376                         if (verbose > 0) {
377                                 uuid_unparse(fsid, uuidbuf);
378                                 printf("  new fs is found for '%s', fsid: %s\n",
379                                                 path, uuidbuf);
380                         }
381                         /*
382                          * This is the first time a subvolume on this
383                          * filesystem is deleted, keep fd in order to issue
384                          * SYNC ioctl in the end
385                          */
386                         goto keep_fd;
387                 }
388         }
389
390 out:
391         close_file_or_dir(fd, dirstream);
392 keep_fd:
393         fd = -1;
394         dirstream = NULL;
395         free(dupdname);
396         free(dupvname);
397         dupdname = NULL;
398         dupvname = NULL;
399         cnt++;
400         if (cnt < argc)
401                 goto again;
402
403         if (commit_mode == COMMIT_AFTER) {
404                 int slot;
405
406                 /*
407                  * Traverse seen_fsid_hash and issue SYNC ioctl on each
408                  * filesystem
409                  */
410                 for (slot = 0; slot < SEEN_FSID_HASH_SIZE; slot++) {
411                         struct seen_fsid *seen = seen_fsid_hash[slot];
412
413                         while (seen) {
414                                 res = wait_for_commit(seen->fd);
415                                 if (res < 0) {
416                                         uuid_unparse(seen->fsid, uuidbuf);
417                                         error(
418                         "unable to do final sync after deletion: %s, fsid: %s",
419                                                 strerror(errno), uuidbuf);
420                                         ret = 1;
421                                 } else if (verbose > 0) {
422                                         uuid_unparse(seen->fsid, uuidbuf);
423                                         printf("final sync is done for fsid: %s\n",
424                                                 uuidbuf);
425                                 }
426                                 seen = seen->next;
427                         }
428                 }
429                 /* fd will also be closed in free_seen_fsid */
430                 free_seen_fsid(seen_fsid_hash);
431         }
432
433         return ret;
434 }
435
436 /*
437  * Naming of options:
438  * - uppercase for filters and sort options
439  * - lowercase for enabling specific items in the output
440  */
441 static const char * const cmd_subvol_list_usage[] = {
442         "btrfs subvolume list [options] <path>",
443         "List subvolumes and snapshots in the filesystem.",
444         "",
445         "Path filtering:",
446         "-o           print only subvolumes below specified path",
447         "-a           print all the subvolumes in the filesystem and",
448         "             distinguish absolute and relative path with respect",
449         "             to the given <path>",
450         "",
451         "Field selection:",
452         "-p           print parent ID",
453         "-c           print the ogeneration of the subvolume",
454         "-g           print the generation of the subvolume",
455         "-u           print the uuid of subvolumes (and snapshots)",
456         "-q           print the parent uuid of the snapshots",
457         "-R           print the uuid of the received snapshots",
458         "",
459         "Type filtering:",
460         "-s           list only snapshots",
461         "-r           list readonly subvolumes (including snapshots)",
462         "-d           list deleted subvolumes that are not yet cleaned",
463         "",
464         "Other:",
465         "-t           print the result as a table",
466         "",
467         "Sorting:",
468         "-G [+|-]value",
469         "             filter the subvolumes by generation",
470         "             (+value: >= value; -value: <= value; value: = value)",
471         "-C [+|-]value",
472         "             filter the subvolumes by ogeneration",
473         "             (+value: >= value; -value: <= value; value: = value)",
474         "--sort=gen,ogen,rootid,path",
475         "             list the subvolume in order of gen, ogen, rootid or path",
476         "             you also can add '+' or '-' in front of each items.",
477         "             (+:ascending, -:descending, ascending default)",
478         NULL,
479 };
480
481 static int cmd_subvol_list(int argc, char **argv)
482 {
483         struct btrfs_list_filter_set *filter_set;
484         struct btrfs_list_comparer_set *comparer_set;
485         u64 flags = 0;
486         int fd = -1;
487         u64 top_id;
488         int ret = -1, uerr = 0;
489         char *subvol;
490         int is_list_all = 0;
491         int is_only_in_path = 0;
492         DIR *dirstream = NULL;
493         enum btrfs_list_layout layout = BTRFS_LIST_LAYOUT_DEFAULT;
494
495         filter_set = btrfs_list_alloc_filter_set();
496         comparer_set = btrfs_list_alloc_comparer_set();
497
498         while(1) {
499                 int c;
500                 static const struct option long_options[] = {
501                         {"sort", required_argument, NULL, 'S'},
502                         {NULL, 0, NULL, 0}
503                 };
504
505                 c = getopt_long(argc, argv,
506                                     "acdgopqsurRG:C:t", long_options, NULL);
507                 if (c < 0)
508                         break;
509
510                 switch(c) {
511                 case 'p':
512                         btrfs_list_setup_print_column(BTRFS_LIST_PARENT);
513                         break;
514                 case 'a':
515                         is_list_all = 1;
516                         break;
517                 case 'c':
518                         btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
519                         break;
520                 case 'd':
521                         btrfs_list_setup_filter(&filter_set,
522                                                 BTRFS_LIST_FILTER_DELETED,
523                                                 0);
524                         break;
525                 case 'g':
526                         btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
527                         break;
528                 case 'o':
529                         is_only_in_path = 1;
530                         break;
531                 case 't':
532                         layout = BTRFS_LIST_LAYOUT_TABLE;
533                         break;
534                 case 's':
535                         btrfs_list_setup_filter(&filter_set,
536                                                 BTRFS_LIST_FILTER_SNAPSHOT_ONLY,
537                                                 0);
538                         btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
539                         btrfs_list_setup_print_column(BTRFS_LIST_OTIME);
540                         break;
541                 case 'u':
542                         btrfs_list_setup_print_column(BTRFS_LIST_UUID);
543                         break;
544                 case 'q':
545                         btrfs_list_setup_print_column(BTRFS_LIST_PUUID);
546                         break;
547                 case 'R':
548                         btrfs_list_setup_print_column(BTRFS_LIST_RUUID);
549                         break;
550                 case 'r':
551                         flags |= BTRFS_ROOT_SUBVOL_RDONLY;
552                         break;
553                 case 'G':
554                         btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
555                         ret = btrfs_list_parse_filter_string(optarg,
556                                                         &filter_set,
557                                                         BTRFS_LIST_FILTER_GEN);
558                         if (ret) {
559                                 uerr = 1;
560                                 goto out;
561                         }
562                         break;
563
564                 case 'C':
565                         btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
566                         ret = btrfs_list_parse_filter_string(optarg,
567                                                         &filter_set,
568                                                         BTRFS_LIST_FILTER_CGEN);
569                         if (ret) {
570                                 uerr = 1;
571                                 goto out;
572                         }
573                         break;
574                 case 'S':
575                         ret = btrfs_list_parse_sort_string(optarg,
576                                                            &comparer_set);
577                         if (ret) {
578                                 uerr = 1;
579                                 goto out;
580                         }
581                         break;
582
583                 default:
584                         uerr = 1;
585                         goto out;
586                 }
587         }
588
589         if (check_argc_exact(argc - optind, 1)) {
590                 uerr = 1;
591                 goto out;
592         }
593
594         subvol = argv[optind];
595         fd = btrfs_open_dir(subvol, &dirstream, 1);
596         if (fd < 0) {
597                 ret = -1;
598                 error("can't access '%s'", subvol);
599                 goto out;
600         }
601
602         if (flags)
603                 btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_FLAGS,
604                                         flags);
605
606         ret = btrfs_list_get_path_rootid(fd, &top_id);
607         if (ret)
608                 goto out;
609
610         if (is_list_all)
611                 btrfs_list_setup_filter(&filter_set,
612                                         BTRFS_LIST_FILTER_FULL_PATH,
613                                         top_id);
614         else if (is_only_in_path)
615                 btrfs_list_setup_filter(&filter_set,
616                                         BTRFS_LIST_FILTER_TOPID_EQUAL,
617                                         top_id);
618
619         /* by default we shall print the following columns*/
620         btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
621         btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
622         btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
623         btrfs_list_setup_print_column(BTRFS_LIST_PATH);
624
625         ret = btrfs_list_subvols_print(fd, filter_set, comparer_set,
626                         layout, !is_list_all && !is_only_in_path, NULL);
627
628 out:
629         close_file_or_dir(fd, dirstream);
630         if (filter_set)
631                 free(filter_set);
632         if (comparer_set)
633                 free(comparer_set);
634         if (uerr)
635                 usage(cmd_subvol_list_usage);
636         return !!ret;
637 }
638
639 static const char * const cmd_subvol_snapshot_usage[] = {
640         "btrfs subvolume snapshot [-r] [-i <qgroupid>] <source> <dest>|[<dest>/]<name>",
641         "Create a snapshot of the subvolume",
642         "Create a writable/readonly snapshot of the subvolume <source> with",
643         "the name <name> in the <dest> directory.  If only <dest> is given,",
644         "the subvolume will be named the basename of <source>.",
645         "",
646         "-r             create a readonly snapshot",
647         "-i <qgroupid>  add the newly created snapshot to a qgroup. This",
648         "               option can be given multiple times.",
649         NULL
650 };
651
652 static int cmd_subvol_snapshot(int argc, char **argv)
653 {
654         char    *subvol, *dst;
655         int     res, retval;
656         int     fd = -1, fddst = -1;
657         int     len, readonly = 0;
658         char    *dupname = NULL;
659         char    *dupdir = NULL;
660         char    *newname;
661         char    *dstdir;
662         struct btrfs_ioctl_vol_args_v2  args;
663         struct btrfs_qgroup_inherit *inherit = NULL;
664         DIR *dirstream1 = NULL, *dirstream2 = NULL;
665
666         memset(&args, 0, sizeof(args));
667         while (1) {
668                 int c = getopt(argc, argv, "c:i:r");
669                 if (c < 0)
670                         break;
671
672                 switch (c) {
673                 case 'c':
674                         res = qgroup_inherit_add_copy(&inherit, optarg, 0);
675                         if (res) {
676                                 retval = res;
677                                 goto out;
678                         }
679                         break;
680                 case 'i':
681                         res = qgroup_inherit_add_group(&inherit, optarg);
682                         if (res) {
683                                 retval = res;
684                                 goto out;
685                         }
686                         break;
687                 case 'r':
688                         readonly = 1;
689                         break;
690                 case 'x':
691                         res = qgroup_inherit_add_copy(&inherit, optarg, 1);
692                         if (res) {
693                                 retval = res;
694                                 goto out;
695                         }
696                         break;
697                 default:
698                         usage(cmd_subvol_snapshot_usage);
699                 }
700         }
701
702         if (check_argc_exact(argc - optind, 2))
703                 usage(cmd_subvol_snapshot_usage);
704
705         subvol = argv[optind];
706         dst = argv[optind + 1];
707
708         retval = 1;     /* failure */
709         res = test_issubvolume(subvol);
710         if (res < 0) {
711                 error("cannot access subvolume %s: %s", subvol, strerror(-res));
712                 goto out;
713         }
714         if (!res) {
715                 error("not a subvolume: %s", subvol);
716                 goto out;
717         }
718
719         res = test_isdir(dst);
720         if (res < 0 && res != -ENOENT) {
721                 error("cannot access %s: %s", dst, strerror(-res));
722                 goto out;
723         }
724         if (res == 0) {
725                 error("'%s' exists and it is not a directory", dst);
726                 goto out;
727         }
728
729         if (res > 0) {
730                 dupname = strdup(subvol);
731                 newname = basename(dupname);
732                 dstdir = dst;
733         } else {
734                 dupname = strdup(dst);
735                 newname = basename(dupname);
736                 dupdir = strdup(dst);
737                 dstdir = dirname(dupdir);
738         }
739
740         if (!test_issubvolname(newname)) {
741                 error("invalid snapshot name '%s'", newname);
742                 goto out;
743         }
744
745         len = strlen(newname);
746         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
747                 error("snapshot name too long '%s'", newname);
748                 goto out;
749         }
750
751         fddst = btrfs_open_dir(dstdir, &dirstream1, 1);
752         if (fddst < 0)
753                 goto out;
754
755         fd = btrfs_open_dir(subvol, &dirstream2, 1);
756         if (fd < 0)
757                 goto out;
758
759         if (readonly) {
760                 args.flags |= BTRFS_SUBVOL_RDONLY;
761                 printf("Create a readonly snapshot of '%s' in '%s/%s'\n",
762                        subvol, dstdir, newname);
763         } else {
764                 printf("Create a snapshot of '%s' in '%s/%s'\n",
765                        subvol, dstdir, newname);
766         }
767
768         args.fd = fd;
769         if (inherit) {
770                 args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
771                 args.size = qgroup_inherit_size(inherit);
772                 args.qgroup_inherit = inherit;
773         }
774         strncpy_null(args.name, newname);
775
776         res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);
777
778         if (res < 0) {
779                 error("cannot snapshot '%s': %s", subvol, strerror(errno));
780                 goto out;
781         }
782
783         retval = 0;     /* success */
784
785 out:
786         close_file_or_dir(fddst, dirstream1);
787         close_file_or_dir(fd, dirstream2);
788         free(inherit);
789         free(dupname);
790         free(dupdir);
791
792         return retval;
793 }
794
795 static const char * const cmd_subvol_get_default_usage[] = {
796         "btrfs subvolume get-default <path>",
797         "Get the default subvolume of a filesystem",
798         NULL
799 };
800
801 static int cmd_subvol_get_default(int argc, char **argv)
802 {
803         int fd = -1;
804         int ret;
805         char *subvol;
806         struct btrfs_list_filter_set *filter_set;
807         u64 default_id;
808         DIR *dirstream = NULL;
809
810         clean_args_no_options(argc, argv, cmd_subvol_get_default_usage);
811
812         if (check_argc_exact(argc - optind, 1))
813                 usage(cmd_subvol_get_default_usage);
814
815         subvol = argv[1];
816         fd = btrfs_open_dir(subvol, &dirstream, 1);
817         if (fd < 0)
818                 return 1;
819
820         ret = btrfs_list_get_default_subvolume(fd, &default_id);
821         if (ret) {
822                 error("failed to look up default subvolume: %s",
823                         strerror(errno));
824                 goto out;
825         }
826
827         ret = 1;
828         if (default_id == 0) {
829                 error("'default' dir item not found");
830                 goto out;
831         }
832
833         /* no need to resolve roots if FS_TREE is default */
834         if (default_id == BTRFS_FS_TREE_OBJECTID) {
835                 printf("ID 5 (FS_TREE)\n");
836                 ret = 0;
837                 goto out;
838         }
839
840         filter_set = btrfs_list_alloc_filter_set();
841         btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_ROOTID,
842                                 default_id);
843
844         /* by default we shall print the following columns*/
845         btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
846         btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
847         btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
848         btrfs_list_setup_print_column(BTRFS_LIST_PATH);
849
850         ret = btrfs_list_subvols_print(fd, filter_set, NULL,
851                 BTRFS_LIST_LAYOUT_DEFAULT, 1, NULL);
852
853         if (filter_set)
854                 free(filter_set);
855 out:
856         close_file_or_dir(fd, dirstream);
857         return !!ret;
858 }
859
860 static const char * const cmd_subvol_set_default_usage[] = {
861         "btrfs subvolume set-default <subvolid> <path>",
862         "Set the default subvolume of a filesystem",
863         NULL
864 };
865
866 static int cmd_subvol_set_default(int argc, char **argv)
867 {
868         int     ret=0, fd, e;
869         u64     objectid;
870         char    *path;
871         char    *subvolid;
872         DIR     *dirstream = NULL;
873
874         clean_args_no_options(argc, argv, cmd_subvol_set_default_usage);
875
876         if (check_argc_exact(argc - optind, 2))
877                 usage(cmd_subvol_set_default_usage);
878
879         subvolid = argv[optind];
880         path = argv[optind + 1];
881
882         objectid = arg_strtou64(subvolid);
883
884         fd = btrfs_open_dir(path, &dirstream, 1);
885         if (fd < 0)
886                 return 1;
887
888         ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
889         e = errno;
890         close_file_or_dir(fd, dirstream);
891         if (ret < 0) {
892                 error("unable to set a new default subvolume: %s",
893                         strerror(e));
894                 return 1;
895         }
896         return 0;
897 }
898
899 static const char * const cmd_subvol_find_new_usage[] = {
900         "btrfs subvolume find-new <path> <lastgen>",
901         "List the recently modified files in a filesystem",
902         NULL
903 };
904
905 static int cmd_subvol_find_new(int argc, char **argv)
906 {
907         int fd;
908         int ret;
909         char *subvol;
910         u64 last_gen;
911         DIR *dirstream = NULL;
912
913         clean_args_no_options(argc, argv, cmd_subvol_find_new_usage);
914
915         if (check_argc_exact(argc - optind, 2))
916                 usage(cmd_subvol_find_new_usage);
917
918         subvol = argv[optind];
919         last_gen = arg_strtou64(argv[optind + 1]);
920
921         ret = test_issubvolume(subvol);
922         if (ret < 0) {
923                 error("cannot access subvolume %s: %s", subvol, strerror(-ret));
924                 return 1;
925         }
926         if (!ret) {
927                 error("not a subvolume: %s", subvol);
928                 return 1;
929         }
930
931         fd = btrfs_open_dir(subvol, &dirstream, 1);
932         if (fd < 0)
933                 return 1;
934
935         ret = ioctl(fd, BTRFS_IOC_SYNC);
936         if (ret < 0) {
937                 error("sync ioctl failed on '%s': %s",
938                         subvol, strerror(errno));
939                 close_file_or_dir(fd, dirstream);
940                 return 1;
941         }
942
943         ret = btrfs_list_find_updated_files(fd, 0, last_gen);
944         close_file_or_dir(fd, dirstream);
945         return !!ret;
946 }
947
948 static const char * const cmd_subvol_show_usage[] = {
949         "btrfs subvolume show [options] <subvol-path>|<mnt>",
950         "Show more information about the subvolume",
951         "-r|--rootid   rootid of the subvolume",
952         "-u|--uuid     uuid of the subvolume",
953         "",
954         "If no option is specified, <subvol-path> will be shown, otherwise",
955         "the rootid or uuid are resolved relative to the <mnt> path.",
956         NULL
957 };
958
959 static int cmd_subvol_show(int argc, char **argv)
960 {
961         struct root_info get_ri;
962         struct btrfs_list_filter_set *filter_set = NULL;
963         char tstr[256];
964         char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
965         char *fullpath = NULL;
966         char raw_prefix[] = "\t\t\t\t";
967         int fd = -1;
968         int ret = 1;
969         DIR *dirstream1 = NULL;
970         int by_rootid = 0;
971         int by_uuid = 0;
972         u64 rootid_arg;
973         u8 uuid_arg[BTRFS_UUID_SIZE];
974
975         while (1) {
976                 int c;
977                 static const struct option long_options[] = {
978                         { "rootid", required_argument, NULL, 'r'},
979                         { "uuid", required_argument, NULL, 'u'},
980                         { NULL, 0, NULL, 0 }
981                 };
982
983                 c = getopt_long(argc, argv, "r:u:", long_options, NULL);
984                 if (c < 0)
985                         break;
986
987                 switch (c) {
988                 case 'r':
989                         rootid_arg = arg_strtou64(optarg);
990                         by_rootid = 1;
991                         break;
992                 case 'u':
993                         uuid_parse(optarg, uuid_arg);
994                         by_uuid = 1;
995                         break;
996                 default:
997                         usage(cmd_subvol_show_usage);
998                 }
999         }
1000
1001         if (check_argc_exact(argc - optind, 1))
1002                 usage(cmd_subvol_show_usage);
1003
1004         if (by_rootid && by_uuid) {
1005                 error(
1006                 "options --rootid and --uuid cannot be used at the same time");
1007                 usage(cmd_subvol_show_usage);
1008         }
1009
1010         memset(&get_ri, 0, sizeof(get_ri));
1011         fullpath = realpath(argv[optind], NULL);
1012         if (!fullpath) {
1013                 error("cannot find real path for '%s': %s",
1014                         argv[optind], strerror(errno));
1015                 goto out;
1016         }
1017
1018         if (by_rootid) {
1019                 ret = get_subvol_info_by_rootid(fullpath, &get_ri, rootid_arg);
1020         } else if (by_uuid) {
1021                 ret = get_subvol_info_by_uuid(fullpath, &get_ri, uuid_arg);
1022         } else {
1023                 ret = get_subvol_info(fullpath, &get_ri);
1024         }
1025
1026         if (ret) {
1027                 if (ret < 0) {
1028                         error("Failed to get subvol info %s: %s",
1029                                         fullpath, strerror(-ret));
1030                 } else {
1031                         error("Failed to get subvol info %s: %d",
1032                                         fullpath, ret);
1033                 }
1034                 return ret;
1035         }
1036
1037         /* print the info */
1038         printf("%s\n", get_ri.full_path);
1039         printf("\tName: \t\t\t%s\n", get_ri.name);
1040
1041         if (uuid_is_null(get_ri.uuid))
1042                 strcpy(uuidparse, "-");
1043         else
1044                 uuid_unparse(get_ri.uuid, uuidparse);
1045         printf("\tUUID: \t\t\t%s\n", uuidparse);
1046
1047         if (uuid_is_null(get_ri.puuid))
1048                 strcpy(uuidparse, "-");
1049         else
1050                 uuid_unparse(get_ri.puuid, uuidparse);
1051         printf("\tParent UUID: \t\t%s\n", uuidparse);
1052
1053         if (uuid_is_null(get_ri.ruuid))
1054                 strcpy(uuidparse, "-");
1055         else
1056                 uuid_unparse(get_ri.ruuid, uuidparse);
1057         printf("\tReceived UUID: \t\t%s\n", uuidparse);
1058
1059         if (get_ri.otime) {
1060                 struct tm tm;
1061
1062                 localtime_r(&get_ri.otime, &tm);
1063                 strftime(tstr, 256, "%Y-%m-%d %X %z", &tm);
1064         } else
1065                 strcpy(tstr, "-");
1066         printf("\tCreation time: \t\t%s\n", tstr);
1067
1068         printf("\tSubvolume ID: \t\t%llu\n", get_ri.root_id);
1069         printf("\tGeneration: \t\t%llu\n", get_ri.gen);
1070         printf("\tGen at creation: \t%llu\n", get_ri.ogen);
1071         printf("\tParent ID: \t\t%llu\n", get_ri.ref_tree);
1072         printf("\tTop level ID: \t\t%llu\n", get_ri.top_id);
1073
1074         if (get_ri.flags & BTRFS_ROOT_SUBVOL_RDONLY)
1075                 printf("\tFlags: \t\t\treadonly\n");
1076         else
1077                 printf("\tFlags: \t\t\t-\n");
1078
1079         /* print the snapshots of the given subvol if any*/
1080         printf("\tSnapshot(s):\n");
1081         filter_set = btrfs_list_alloc_filter_set();
1082         btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_BY_PARENT,
1083                                 (u64)(unsigned long)get_ri.uuid);
1084         btrfs_list_setup_print_column(BTRFS_LIST_PATH);
1085
1086         fd = open_file_or_dir(fullpath, &dirstream1);
1087         if (fd < 0) {
1088                 fprintf(stderr, "ERROR: can't access '%s'\n", fullpath);
1089                 goto out;
1090         }
1091         btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
1092                         1, raw_prefix);
1093
1094 out:
1095         /* clean up */
1096         free(get_ri.path);
1097         free(get_ri.name);
1098         free(get_ri.full_path);
1099         free(filter_set);
1100
1101         close_file_or_dir(fd, dirstream1);
1102         free(fullpath);
1103         return !!ret;
1104 }
1105
1106 static const char * const cmd_subvol_sync_usage[] = {
1107         "btrfs subvolume sync <path> [<subvol-id>...]",
1108         "Wait until given subvolume(s) are completely removed from the filesystem.",
1109         "Wait until given subvolume(s) are completely removed from the filesystem",
1110         "after deletion.",
1111         "If no subvolume id is given, wait until all current deletion requests",
1112         "are completed, but do not wait for subvolumes deleted meanwhile.",
1113         "The status of subvolume ids is checked periodically.",
1114         "",
1115         "-s <N>       sleep N seconds between checks (default: 1)",
1116         NULL
1117 };
1118
1119 #if 0
1120 /*
1121  * If we're looking for any dead subvolume, take a shortcut and look
1122  * for any ORPHAN_ITEMs in the tree root
1123  */
1124 static int fs_has_dead_subvolumes(int fd)
1125 {
1126         int ret;
1127         struct btrfs_ioctl_search_args args;
1128         struct btrfs_ioctl_search_key *sk = &args.key;
1129         struct btrfs_ioctl_search_header sh;
1130         u64 min_subvolid = 0;
1131
1132 again:
1133         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1134         sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1135         sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1136         sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1137         sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1138         sk->min_offset = min_subvolid;
1139         sk->max_offset = (u64)-1;
1140         sk->min_transid = 0;
1141         sk->max_transid = (u64)-1;
1142         sk->nr_items = 1;
1143
1144         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1145         if (ret < 0)
1146                 return -errno;
1147
1148         if (!sk->nr_items)
1149                 return 0;
1150
1151         memcpy(&sh, args.buf, sizeof(sh));
1152         min_subvolid = sh.offset;
1153
1154         /*
1155          * Verify that the root item is really there and we haven't hit
1156          * a stale orphan
1157          */
1158         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1159         sk->min_objectid = min_subvolid;
1160         sk->max_objectid = min_subvolid;
1161         sk->min_type = BTRFS_ROOT_ITEM_KEY;
1162         sk->max_type = BTRFS_ROOT_ITEM_KEY;
1163         sk->min_offset = 0;
1164         sk->max_offset = (u64)-1;
1165         sk->min_transid = 0;
1166         sk->max_transid = (u64)-1;
1167         sk->nr_items = 1;
1168
1169         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1170         if (ret < 0)
1171                 return -errno;
1172
1173         /*
1174          * Stale orphan, try the next one
1175          */
1176         if (!sk->nr_items) {
1177                 min_subvolid++;
1178                 goto again;
1179         }
1180
1181         return 1;
1182 }
1183 #endif
1184
1185 #define SUBVOL_ID_BATCH         1024
1186
1187 /*
1188  * Enumerate all dead subvolumes that exist in the filesystem.
1189  * Fill @ids and reallocate to bigger size if needed.
1190  */
1191 static int enumerate_dead_subvols(int fd, u64 **ids)
1192 {
1193         int ret;
1194         struct btrfs_ioctl_search_args args;
1195         struct btrfs_ioctl_search_key *sk = &args.key;
1196         int idx = 0;
1197         int count = 0;
1198
1199         memset(&args, 0, sizeof(args));
1200
1201         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1202         sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1203         sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1204         sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1205         sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1206         sk->min_offset = 0;
1207         sk->max_offset = (u64)-1;
1208         sk->min_transid = 0;
1209         sk->max_transid = (u64)-1;
1210         sk->nr_items = 4096;
1211
1212         *ids = NULL;
1213         while (1) {
1214                 struct btrfs_ioctl_search_header *sh;
1215                 unsigned long off;
1216                 int i;
1217
1218                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1219                 if (ret < 0)
1220                         return -errno;
1221
1222                 if (!sk->nr_items)
1223                         return idx;
1224
1225                 off = 0;
1226                 for (i = 0; i < sk->nr_items; i++) {
1227                         sh = (struct btrfs_ioctl_search_header*)(args.buf + off);
1228                         off += sizeof(*sh);
1229
1230                         if (btrfs_search_header_type(sh)
1231                             == BTRFS_ORPHAN_ITEM_KEY) {
1232                                 if (idx >= count) {
1233                                         u64 *newids;
1234
1235                                         count += SUBVOL_ID_BATCH;
1236                                         newids = (u64*)realloc(*ids,
1237                                                         count * sizeof(u64));
1238                                         if (!newids)
1239                                                 return -ENOMEM;
1240                                         *ids = newids;
1241                                 }
1242                                 (*ids)[idx] = btrfs_search_header_offset(sh);
1243                                 idx++;
1244                         }
1245                         off += btrfs_search_header_len(sh);
1246
1247                         sk->min_objectid = btrfs_search_header_objectid(sh);
1248                         sk->min_type = btrfs_search_header_type(sh);
1249                         sk->min_offset = btrfs_search_header_offset(sh);
1250                 }
1251                 if (sk->min_offset < (u64)-1)
1252                         sk->min_offset++;
1253                 else
1254                         break;
1255                 if (sk->min_type != BTRFS_ORPHAN_ITEM_KEY)
1256                         break;
1257                 if (sk->min_objectid != BTRFS_ORPHAN_OBJECTID)
1258                         break;
1259         }
1260
1261         return idx;
1262 }
1263
1264 static int cmd_subvol_sync(int argc, char **argv)
1265 {
1266         int fd = -1;
1267         int i;
1268         int ret = 1;
1269         DIR *dirstream = NULL;
1270         u64 *ids = NULL;
1271         int id_count;
1272         int sleep_interval = 1;
1273
1274         while (1) {
1275                 int c = getopt(argc, argv, "s:");
1276
1277                 if (c < 0)
1278                         break;
1279
1280                 switch (c) {
1281                 case 's':
1282                         sleep_interval = atoi(optarg);
1283                         if (sleep_interval < 1) {
1284                                 error("invalid sleep interval %s", optarg);
1285                                 ret = 1;
1286                                 goto out;
1287                         }
1288                         break;
1289                 default:
1290                         usage(cmd_subvol_sync_usage);
1291                 }
1292         }
1293
1294         if (check_argc_min(argc - optind, 1))
1295                 usage(cmd_subvol_sync_usage);
1296
1297         fd = btrfs_open_dir(argv[optind], &dirstream, 1);
1298         if (fd < 0) {
1299                 ret = 1;
1300                 goto out;
1301         }
1302         optind++;
1303
1304         id_count = argc - optind;
1305         if (!id_count) {
1306                 id_count = enumerate_dead_subvols(fd, &ids);
1307                 if (id_count < 0) {
1308                         error("can't enumerate dead subvolumes: %s",
1309                                         strerror(-id_count));
1310                         ret = 1;
1311                         goto out;
1312                 }
1313                 if (id_count == 0) {
1314                         ret = 0;
1315                         goto out;
1316                 }
1317         } else {
1318                 ids = (u64*)malloc(id_count * sizeof(u64));
1319                 if (!ids) {
1320                         error("not enough memory");
1321                         ret = 1;
1322                         goto out;
1323                 }
1324
1325                 for (i = 0; i < id_count; i++) {
1326                         u64 id;
1327                         const char *arg;
1328
1329                         arg = argv[optind + i];
1330                         errno = 0;
1331                         id = strtoull(arg, NULL, 10);
1332                         if (errno < 0) {
1333                                 error("unrecognized subvolume id %s", arg);
1334                                 ret = 1;
1335                                 goto out;
1336                         }
1337                         if (id < BTRFS_FIRST_FREE_OBJECTID
1338                                         || id > BTRFS_LAST_FREE_OBJECTID) {
1339                                 error("subvolume id %s out of range", arg);
1340                                 ret = 1;
1341                                 goto out;
1342                         }
1343                         ids[i] = id;
1344                 }
1345         }
1346
1347         ret = wait_for_subvolume_cleaning(fd, id_count, ids, sleep_interval);
1348
1349 out:
1350         free(ids);
1351         close_file_or_dir(fd, dirstream);
1352
1353         return !!ret;
1354 }
1355
1356 static const char subvolume_cmd_group_info[] =
1357 "manage subvolumes: create, delete, list, etc";
1358
1359 const struct cmd_group subvolume_cmd_group = {
1360         subvolume_cmd_group_usage, subvolume_cmd_group_info, {
1361                 { "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
1362                 { "delete", cmd_subvol_delete, cmd_subvol_delete_usage, NULL, 0 },
1363                 { "list", cmd_subvol_list, cmd_subvol_list_usage, NULL, 0 },
1364                 { "snapshot", cmd_subvol_snapshot, cmd_subvol_snapshot_usage,
1365                         NULL, 0 },
1366                 { "get-default", cmd_subvol_get_default,
1367                         cmd_subvol_get_default_usage, NULL, 0 },
1368                 { "set-default", cmd_subvol_set_default,
1369                         cmd_subvol_set_default_usage, NULL, 0 },
1370                 { "find-new", cmd_subvol_find_new, cmd_subvol_find_new_usage,
1371                         NULL, 0 },
1372                 { "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
1373                 { "sync", cmd_subvol_sync, cmd_subvol_sync_usage, NULL, 0 },
1374                 NULL_CMD_STRUCT
1375         }
1376 };
1377
1378 int cmd_subvolume(int argc, char **argv)
1379 {
1380         return handle_command_group(&subvolume_cmd_group, argc, argv);
1381 }