btrfs-progs: Fix 'btrfs device stats --check' cli option
[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
267         while (1) {
268                 int c;
269                 static const struct option long_options[] = {
270                         {"commit-after", no_argument, NULL, 'c'},  /* commit mode 1 */
271                         {"commit-each", no_argument, NULL, 'C'},  /* commit mode 2 */
272                         {"verbose", no_argument, NULL, 'v'},
273                         {NULL, 0, NULL, 0}
274                 };
275
276                 c = getopt_long(argc, argv, "cCv", long_options, NULL);
277                 if (c < 0)
278                         break;
279
280                 switch(c) {
281                 case 'c':
282                         commit_mode = 1;
283                         break;
284                 case 'C':
285                         commit_mode = 2;
286                         break;
287                 case 'v':
288                         verbose++;
289                         break;
290                 default:
291                         usage(cmd_subvol_delete_usage);
292                 }
293         }
294
295         if (check_argc_min(argc - optind, 1))
296                 usage(cmd_subvol_delete_usage);
297
298         if (verbose > 0) {
299                 printf("Transaction commit: %s\n",
300                         !commit_mode ? "none (default)" :
301                         commit_mode == 1 ? "at the end" : "after each");
302         }
303
304         cnt = optind;
305
306 again:
307         path = argv[cnt];
308
309         res = test_issubvolume(path);
310         if (res < 0) {
311                 error("cannot access subvolume %s: %s", path, strerror(-res));
312                 ret = 1;
313                 goto out;
314         }
315         if (!res) {
316                 error("not a subvolume: %s", path);
317                 ret = 1;
318                 goto out;
319         }
320
321         cpath = realpath(path, NULL);
322         if (!cpath) {
323                 ret = errno;
324                 error("cannot find real path for '%s': %s",
325                         path, strerror(errno));
326                 goto out;
327         }
328         dupdname = strdup(cpath);
329         dname = dirname(dupdname);
330         dupvname = strdup(cpath);
331         vname = basename(dupvname);
332         free(cpath);
333
334         fd = btrfs_open_dir(dname, &dirstream, 1);
335         if (fd < 0) {
336                 ret = 1;
337                 goto out;
338         }
339
340         printf("Delete subvolume (%s): '%s/%s'\n",
341                 commit_mode == 2 || (commit_mode == 1 && cnt + 1 == argc)
342                 ? "commit" : "no-commit", dname, vname);
343         memset(&args, 0, sizeof(args));
344         strncpy_null(args.name, vname);
345         res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
346         if(res < 0 ){
347                 error("cannot delete '%s/%s': %s", dname, vname,
348                         strerror(errno));
349                 ret = 1;
350                 goto out;
351         }
352
353         if (commit_mode == 1) {
354                 res = wait_for_commit(fd);
355                 if (res < 0) {
356                         error("unable to wait for commit after '%s': %s",
357                                 path, strerror(errno));
358                         ret = 1;
359                 }
360         }
361
362 out:
363         free(dupdname);
364         free(dupvname);
365         dupdname = NULL;
366         dupvname = NULL;
367         cnt++;
368         if (cnt < argc) {
369                 close_file_or_dir(fd, dirstream);
370                 /* avoid double free */
371                 fd = -1;
372                 dirstream = NULL;
373                 goto again;
374         }
375
376         if (commit_mode == 2 && fd != -1) {
377                 res = wait_for_commit(fd);
378                 if (res < 0) {
379                         error("unable to do final sync after deletion: %s",
380                                 strerror(errno));
381                         ret = 1;
382                 }
383         }
384         close_file_or_dir(fd, dirstream);
385
386         return ret;
387 }
388
389 /*
390  * Naming of options:
391  * - uppercase for filters and sort options
392  * - lowercase for enabling specific items in the output
393  */
394 static const char * const cmd_subvol_list_usage[] = {
395         "btrfs subvolume list [options] [-G [+|-]value] [-C [+|-]value] "
396         "[--sort=gen,ogen,rootid,path] <path>",
397         "List subvolumes (and snapshots)",
398         "",
399         "-p           print parent ID",
400         "-a           print all the subvolumes in the filesystem and",
401         "             distinguish absolute and relative path with respect",
402         "             to the given <path>",
403         "-c           print the ogeneration of the subvolume",
404         "-g           print the generation of the subvolume",
405         "-o           print only subvolumes below specified path",
406         "-u           print the uuid of subvolumes (and snapshots)",
407         "-q           print the parent uuid of the snapshots",
408         "-R           print the uuid of the received snapshots",
409         "-t           print the result as a table",
410         "-s           list snapshots only in the filesystem",
411         "-r           list readonly subvolumes (including snapshots)",
412         "-d           list deleted subvolumes that are not yet cleaned",
413         "-G [+|-]value",
414         "             filter the subvolumes by generation",
415         "             (+value: >= value; -value: <= value; value: = value)",
416         "-C [+|-]value",
417         "             filter the subvolumes by ogeneration",
418         "             (+value: >= value; -value: <= value; value: = value)",
419         "--sort=gen,ogen,rootid,path",
420         "             list the subvolume in order of gen, ogen, rootid or path",
421         "             you also can add '+' or '-' in front of each items.",
422         "             (+:ascending, -:descending, ascending default)",
423         NULL,
424 };
425
426 static int cmd_subvol_list(int argc, char **argv)
427 {
428         struct btrfs_list_filter_set *filter_set;
429         struct btrfs_list_comparer_set *comparer_set;
430         u64 flags = 0;
431         int fd = -1;
432         u64 top_id;
433         int ret = -1, uerr = 0;
434         char *subvol;
435         int is_list_all = 0;
436         int is_only_in_path = 0;
437         DIR *dirstream = NULL;
438         enum btrfs_list_layout layout = BTRFS_LIST_LAYOUT_DEFAULT;
439
440         filter_set = btrfs_list_alloc_filter_set();
441         comparer_set = btrfs_list_alloc_comparer_set();
442
443         while(1) {
444                 int c;
445                 static const struct option long_options[] = {
446                         {"sort", required_argument, NULL, 'S'},
447                         {NULL, 0, NULL, 0}
448                 };
449
450                 c = getopt_long(argc, argv,
451                                     "acdgopqsurRG:C:t", long_options, NULL);
452                 if (c < 0)
453                         break;
454
455                 switch(c) {
456                 case 'p':
457                         btrfs_list_setup_print_column(BTRFS_LIST_PARENT);
458                         break;
459                 case 'a':
460                         is_list_all = 1;
461                         break;
462                 case 'c':
463                         btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
464                         break;
465                 case 'd':
466                         btrfs_list_setup_filter(&filter_set,
467                                                 BTRFS_LIST_FILTER_DELETED,
468                                                 0);
469                         break;
470                 case 'g':
471                         btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
472                         break;
473                 case 'o':
474                         is_only_in_path = 1;
475                         break;
476                 case 't':
477                         layout = BTRFS_LIST_LAYOUT_TABLE;
478                         break;
479                 case 's':
480                         btrfs_list_setup_filter(&filter_set,
481                                                 BTRFS_LIST_FILTER_SNAPSHOT_ONLY,
482                                                 0);
483                         btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
484                         btrfs_list_setup_print_column(BTRFS_LIST_OTIME);
485                         break;
486                 case 'u':
487                         btrfs_list_setup_print_column(BTRFS_LIST_UUID);
488                         break;
489                 case 'q':
490                         btrfs_list_setup_print_column(BTRFS_LIST_PUUID);
491                         break;
492                 case 'R':
493                         btrfs_list_setup_print_column(BTRFS_LIST_RUUID);
494                         break;
495                 case 'r':
496                         flags |= BTRFS_ROOT_SUBVOL_RDONLY;
497                         break;
498                 case 'G':
499                         btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
500                         ret = btrfs_list_parse_filter_string(optarg,
501                                                         &filter_set,
502                                                         BTRFS_LIST_FILTER_GEN);
503                         if (ret) {
504                                 uerr = 1;
505                                 goto out;
506                         }
507                         break;
508
509                 case 'C':
510                         btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
511                         ret = btrfs_list_parse_filter_string(optarg,
512                                                         &filter_set,
513                                                         BTRFS_LIST_FILTER_CGEN);
514                         if (ret) {
515                                 uerr = 1;
516                                 goto out;
517                         }
518                         break;
519                 case 'S':
520                         ret = btrfs_list_parse_sort_string(optarg,
521                                                            &comparer_set);
522                         if (ret) {
523                                 uerr = 1;
524                                 goto out;
525                         }
526                         break;
527
528                 default:
529                         uerr = 1;
530                         goto out;
531                 }
532         }
533
534         if (check_argc_exact(argc - optind, 1)) {
535                 uerr = 1;
536                 goto out;
537         }
538
539         subvol = argv[optind];
540         fd = btrfs_open_dir(subvol, &dirstream, 1);
541         if (fd < 0) {
542                 ret = -1;
543                 error("can't access '%s'", subvol);
544                 goto out;
545         }
546
547         if (flags)
548                 btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_FLAGS,
549                                         flags);
550
551         ret = btrfs_list_get_path_rootid(fd, &top_id);
552         if (ret)
553                 goto out;
554
555         if (is_list_all)
556                 btrfs_list_setup_filter(&filter_set,
557                                         BTRFS_LIST_FILTER_FULL_PATH,
558                                         top_id);
559         else if (is_only_in_path)
560                 btrfs_list_setup_filter(&filter_set,
561                                         BTRFS_LIST_FILTER_TOPID_EQUAL,
562                                         top_id);
563
564         /* by default we shall print the following columns*/
565         btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
566         btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
567         btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
568         btrfs_list_setup_print_column(BTRFS_LIST_PATH);
569
570         ret = btrfs_list_subvols_print(fd, filter_set, comparer_set,
571                         layout, !is_list_all && !is_only_in_path, NULL);
572
573 out:
574         close_file_or_dir(fd, dirstream);
575         if (filter_set)
576                 free(filter_set);
577         if (comparer_set)
578                 free(comparer_set);
579         if (uerr)
580                 usage(cmd_subvol_list_usage);
581         return !!ret;
582 }
583
584 static const char * const cmd_subvol_snapshot_usage[] = {
585         "btrfs subvolume snapshot [-r] [-i <qgroupid>] <source> <dest>|[<dest>/]<name>",
586         "Create a snapshot of the subvolume",
587         "Create a writable/readonly snapshot of the subvolume <source> with",
588         "the name <name> in the <dest> directory.  If only <dest> is given,",
589         "the subvolume will be named the basename of <source>.",
590         "",
591         "-r             create a readonly snapshot",
592         "-i <qgroupid>  add the newly created snapshot to a qgroup. This",
593         "               option can be given multiple times.",
594         NULL
595 };
596
597 static int cmd_subvol_snapshot(int argc, char **argv)
598 {
599         char    *subvol, *dst;
600         int     res, retval;
601         int     fd = -1, fddst = -1;
602         int     len, readonly = 0;
603         char    *dupname = NULL;
604         char    *dupdir = NULL;
605         char    *newname;
606         char    *dstdir;
607         struct btrfs_ioctl_vol_args_v2  args;
608         struct btrfs_qgroup_inherit *inherit = NULL;
609         DIR *dirstream1 = NULL, *dirstream2 = NULL;
610
611         memset(&args, 0, sizeof(args));
612         while (1) {
613                 int c = getopt(argc, argv, "c:i:r");
614                 if (c < 0)
615                         break;
616
617                 switch (c) {
618                 case 'c':
619                         res = qgroup_inherit_add_copy(&inherit, optarg, 0);
620                         if (res) {
621                                 retval = res;
622                                 goto out;
623                         }
624                         break;
625                 case 'i':
626                         res = qgroup_inherit_add_group(&inherit, optarg);
627                         if (res) {
628                                 retval = res;
629                                 goto out;
630                         }
631                         break;
632                 case 'r':
633                         readonly = 1;
634                         break;
635                 case 'x':
636                         res = qgroup_inherit_add_copy(&inherit, optarg, 1);
637                         if (res) {
638                                 retval = res;
639                                 goto out;
640                         }
641                         break;
642                 default:
643                         usage(cmd_subvol_snapshot_usage);
644                 }
645         }
646
647         if (check_argc_exact(argc - optind, 2))
648                 usage(cmd_subvol_snapshot_usage);
649
650         subvol = argv[optind];
651         dst = argv[optind + 1];
652
653         retval = 1;     /* failure */
654         res = test_issubvolume(subvol);
655         if (res < 0) {
656                 error("cannot access subvolume %s: %s", subvol, strerror(-res));
657                 goto out;
658         }
659         if (!res) {
660                 error("not a subvolume: %s", subvol);
661                 goto out;
662         }
663
664         res = test_isdir(dst);
665         if (res < 0 && res != -ENOENT) {
666                 error("cannot access %s: %s", dst, strerror(-res));
667                 goto out;
668         }
669         if (res == 0) {
670                 error("'%s' exists and it is not a directory", dst);
671                 goto out;
672         }
673
674         if (res > 0) {
675                 dupname = strdup(subvol);
676                 newname = basename(dupname);
677                 dstdir = dst;
678         } else {
679                 dupname = strdup(dst);
680                 newname = basename(dupname);
681                 dupdir = strdup(dst);
682                 dstdir = dirname(dupdir);
683         }
684
685         if (!test_issubvolname(newname)) {
686                 error("invalid snapshot name '%s'", newname);
687                 goto out;
688         }
689
690         len = strlen(newname);
691         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
692                 error("snapshot name too long '%s'", newname);
693                 goto out;
694         }
695
696         fddst = btrfs_open_dir(dstdir, &dirstream1, 1);
697         if (fddst < 0)
698                 goto out;
699
700         fd = btrfs_open_dir(subvol, &dirstream2, 1);
701         if (fd < 0)
702                 goto out;
703
704         if (readonly) {
705                 args.flags |= BTRFS_SUBVOL_RDONLY;
706                 printf("Create a readonly snapshot of '%s' in '%s/%s'\n",
707                        subvol, dstdir, newname);
708         } else {
709                 printf("Create a snapshot of '%s' in '%s/%s'\n",
710                        subvol, dstdir, newname);
711         }
712
713         args.fd = fd;
714         if (inherit) {
715                 args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
716                 args.size = qgroup_inherit_size(inherit);
717                 args.qgroup_inherit = inherit;
718         }
719         strncpy_null(args.name, newname);
720
721         res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);
722
723         if (res < 0) {
724                 error("cannot snapshot '%s': %s", subvol, strerror(errno));
725                 goto out;
726         }
727
728         retval = 0;     /* success */
729
730 out:
731         close_file_or_dir(fddst, dirstream1);
732         close_file_or_dir(fd, dirstream2);
733         free(inherit);
734         free(dupname);
735         free(dupdir);
736
737         return retval;
738 }
739
740 static const char * const cmd_subvol_get_default_usage[] = {
741         "btrfs subvolume get-default <path>",
742         "Get the default subvolume of a filesystem",
743         NULL
744 };
745
746 static int cmd_subvol_get_default(int argc, char **argv)
747 {
748         int fd = -1;
749         int ret;
750         char *subvol;
751         struct btrfs_list_filter_set *filter_set;
752         u64 default_id;
753         DIR *dirstream = NULL;
754
755         clean_args_no_options(argc, argv, cmd_subvol_get_default_usage);
756
757         if (check_argc_exact(argc - optind, 1))
758                 usage(cmd_subvol_get_default_usage);
759
760         subvol = argv[1];
761         fd = btrfs_open_dir(subvol, &dirstream, 1);
762         if (fd < 0)
763                 return 1;
764
765         ret = btrfs_list_get_default_subvolume(fd, &default_id);
766         if (ret) {
767                 error("failed to look up default subvolume: %s",
768                         strerror(errno));
769                 goto out;
770         }
771
772         ret = 1;
773         if (default_id == 0) {
774                 error("'default' dir item not found");
775                 goto out;
776         }
777
778         /* no need to resolve roots if FS_TREE is default */
779         if (default_id == BTRFS_FS_TREE_OBJECTID) {
780                 printf("ID 5 (FS_TREE)\n");
781                 ret = 0;
782                 goto out;
783         }
784
785         filter_set = btrfs_list_alloc_filter_set();
786         btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_ROOTID,
787                                 default_id);
788
789         /* by default we shall print the following columns*/
790         btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
791         btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
792         btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
793         btrfs_list_setup_print_column(BTRFS_LIST_PATH);
794
795         ret = btrfs_list_subvols_print(fd, filter_set, NULL,
796                 BTRFS_LIST_LAYOUT_DEFAULT, 1, NULL);
797
798         if (filter_set)
799                 free(filter_set);
800 out:
801         close_file_or_dir(fd, dirstream);
802         return !!ret;
803 }
804
805 static const char * const cmd_subvol_set_default_usage[] = {
806         "btrfs subvolume set-default <subvolid> <path>",
807         "Set the default subvolume of a filesystem",
808         NULL
809 };
810
811 static int cmd_subvol_set_default(int argc, char **argv)
812 {
813         int     ret=0, fd, e;
814         u64     objectid;
815         char    *path;
816         char    *subvolid;
817         DIR     *dirstream = NULL;
818
819         clean_args_no_options(argc, argv, cmd_subvol_set_default_usage);
820
821         if (check_argc_exact(argc - optind, 2))
822                 usage(cmd_subvol_set_default_usage);
823
824         subvolid = argv[optind];
825         path = argv[optind + 1];
826
827         objectid = arg_strtou64(subvolid);
828
829         fd = btrfs_open_dir(path, &dirstream, 1);
830         if (fd < 0)
831                 return 1;
832
833         ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
834         e = errno;
835         close_file_or_dir(fd, dirstream);
836         if (ret < 0) {
837                 error("unable to set a new default subvolume: %s",
838                         strerror(e));
839                 return 1;
840         }
841         return 0;
842 }
843
844 static const char * const cmd_subvol_find_new_usage[] = {
845         "btrfs subvolume find-new <path> <lastgen>",
846         "List the recently modified files in a filesystem",
847         NULL
848 };
849
850 static int cmd_subvol_find_new(int argc, char **argv)
851 {
852         int fd;
853         int ret;
854         char *subvol;
855         u64 last_gen;
856         DIR *dirstream = NULL;
857
858         clean_args_no_options(argc, argv, cmd_subvol_find_new_usage);
859
860         if (check_argc_exact(argc - optind, 2))
861                 usage(cmd_subvol_find_new_usage);
862
863         subvol = argv[optind];
864         last_gen = arg_strtou64(argv[optind + 1]);
865
866         ret = test_issubvolume(subvol);
867         if (ret < 0) {
868                 error("cannot access subvolume %s: %s", subvol, strerror(-ret));
869                 return 1;
870         }
871         if (!ret) {
872                 error("not a subvolume: %s", subvol);
873                 return 1;
874         }
875
876         fd = btrfs_open_dir(subvol, &dirstream, 1);
877         if (fd < 0)
878                 return 1;
879
880         ret = ioctl(fd, BTRFS_IOC_SYNC);
881         if (ret < 0) {
882                 error("sync ioctl failed on '%s': %s",
883                         subvol, strerror(errno));
884                 close_file_or_dir(fd, dirstream);
885                 return 1;
886         }
887
888         ret = btrfs_list_find_updated_files(fd, 0, last_gen);
889         close_file_or_dir(fd, dirstream);
890         return !!ret;
891 }
892
893 static const char * const cmd_subvol_show_usage[] = {
894         "btrfs subvolume show <subvol-path>",
895         "Show more information of the subvolume",
896         NULL
897 };
898
899 static int cmd_subvol_show(int argc, char **argv)
900 {
901         struct root_info get_ri;
902         struct btrfs_list_filter_set *filter_set = NULL;
903         char tstr[256];
904         char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
905         char *fullpath = NULL;
906         char raw_prefix[] = "\t\t\t\t";
907         int fd = -1;
908         int ret = 1;
909         DIR *dirstream1 = NULL;
910
911         clean_args_no_options(argc, argv, cmd_subvol_show_usage);
912
913         if (check_argc_exact(argc - optind, 1))
914                 usage(cmd_subvol_show_usage);
915
916         memset(&get_ri, 0, sizeof(get_ri));
917         fullpath = realpath(argv[optind], NULL);
918         if (!fullpath) {
919                 error("cannot find real path for '%s': %s",
920                         argv[optind], strerror(errno));
921                 goto out;
922         }
923
924         ret = get_subvol_info(fullpath, &get_ri);
925         if (ret) {
926                 if (ret < 0) {
927                         error("Failed to get subvol info %s: %s",
928                                         fullpath, strerror(-ret));
929                 } else {
930                         error("Failed to get subvol info %s: %d",
931                                         fullpath, ret);
932                 }
933                 return ret;
934         }
935
936         /* print the info */
937         printf("%s\n", fullpath);
938         printf("\tName: \t\t\t%s\n", get_ri.name);
939
940         if (uuid_is_null(get_ri.uuid))
941                 strcpy(uuidparse, "-");
942         else
943                 uuid_unparse(get_ri.uuid, uuidparse);
944         printf("\tUUID: \t\t\t%s\n", uuidparse);
945
946         if (uuid_is_null(get_ri.puuid))
947                 strcpy(uuidparse, "-");
948         else
949                 uuid_unparse(get_ri.puuid, uuidparse);
950         printf("\tParent UUID: \t\t%s\n", uuidparse);
951
952         if (uuid_is_null(get_ri.ruuid))
953                 strcpy(uuidparse, "-");
954         else
955                 uuid_unparse(get_ri.ruuid, uuidparse);
956         printf("\tReceived UUID: \t\t%s\n", uuidparse);
957
958         if (get_ri.otime) {
959                 struct tm tm;
960
961                 localtime_r(&get_ri.otime, &tm);
962                 strftime(tstr, 256, "%Y-%m-%d %X %z", &tm);
963         } else
964                 strcpy(tstr, "-");
965         printf("\tCreation time: \t\t%s\n", tstr);
966
967         printf("\tSubvolume ID: \t\t%llu\n", get_ri.root_id);
968         printf("\tGeneration: \t\t%llu\n", get_ri.gen);
969         printf("\tGen at creation: \t%llu\n", get_ri.ogen);
970         printf("\tParent ID: \t\t%llu\n", get_ri.ref_tree);
971         printf("\tTop level ID: \t\t%llu\n", get_ri.top_id);
972
973         if (get_ri.flags & BTRFS_ROOT_SUBVOL_RDONLY)
974                 printf("\tFlags: \t\t\treadonly\n");
975         else
976                 printf("\tFlags: \t\t\t-\n");
977
978         /* print the snapshots of the given subvol if any*/
979         printf("\tSnapshot(s):\n");
980         filter_set = btrfs_list_alloc_filter_set();
981         btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_BY_PARENT,
982                                 (u64)(unsigned long)get_ri.uuid);
983         btrfs_list_setup_print_column(BTRFS_LIST_PATH);
984
985         fd = open_file_or_dir(fullpath, &dirstream1);
986         if (fd < 0) {
987                 fprintf(stderr, "ERROR: can't access '%s'\n", fullpath);
988                 goto out;
989         }
990         btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
991                         1, raw_prefix);
992
993 out:
994         /* clean up */
995         free(get_ri.path);
996         free(get_ri.name);
997         free(get_ri.full_path);
998         free(filter_set);
999
1000         close_file_or_dir(fd, dirstream1);
1001         free(fullpath);
1002         return !!ret;
1003 }
1004
1005 static const char * const cmd_subvol_sync_usage[] = {
1006         "btrfs subvolume sync <path> [<subvol-id>...]",
1007         "Wait until given subvolume(s) are completely removed from the filesystem.",
1008         "Wait until given subvolume(s) are completely removed from the filesystem",
1009         "after deletion.",
1010         "If no subvolume id is given, wait until all current deletion requests",
1011         "are completed, but do not wait for subvolumes deleted meanwhile.",
1012         "The status of subvolume ids is checked periodically.",
1013         "",
1014         "-s <N>       sleep N seconds between checks (default: 1)",
1015         NULL
1016 };
1017
1018 #if 0
1019 /*
1020  * If we're looking for any dead subvolume, take a shortcut and look
1021  * for any ORPHAN_ITEMs in the tree root
1022  */
1023 static int fs_has_dead_subvolumes(int fd)
1024 {
1025         int ret;
1026         struct btrfs_ioctl_search_args args;
1027         struct btrfs_ioctl_search_key *sk = &args.key;
1028         struct btrfs_ioctl_search_header sh;
1029         u64 min_subvolid = 0;
1030
1031 again:
1032         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1033         sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1034         sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1035         sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1036         sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1037         sk->min_offset = min_subvolid;
1038         sk->max_offset = (u64)-1;
1039         sk->min_transid = 0;
1040         sk->max_transid = (u64)-1;
1041         sk->nr_items = 1;
1042
1043         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1044         if (ret < 0)
1045                 return -errno;
1046
1047         if (!sk->nr_items)
1048                 return 0;
1049
1050         memcpy(&sh, args.buf, sizeof(sh));
1051         min_subvolid = sh.offset;
1052
1053         /*
1054          * Verify that the root item is really there and we haven't hit
1055          * a stale orphan
1056          */
1057         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1058         sk->min_objectid = min_subvolid;
1059         sk->max_objectid = min_subvolid;
1060         sk->min_type = BTRFS_ROOT_ITEM_KEY;
1061         sk->max_type = BTRFS_ROOT_ITEM_KEY;
1062         sk->min_offset = 0;
1063         sk->max_offset = (u64)-1;
1064         sk->min_transid = 0;
1065         sk->max_transid = (u64)-1;
1066         sk->nr_items = 1;
1067
1068         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1069         if (ret < 0)
1070                 return -errno;
1071
1072         /*
1073          * Stale orphan, try the next one
1074          */
1075         if (!sk->nr_items) {
1076                 min_subvolid++;
1077                 goto again;
1078         }
1079
1080         return 1;
1081 }
1082 #endif
1083
1084 #define SUBVOL_ID_BATCH         1024
1085
1086 /*
1087  * Enumerate all dead subvolumes that exist in the filesystem.
1088  * Fill @ids and reallocate to bigger size if needed.
1089  */
1090 static int enumerate_dead_subvols(int fd, u64 **ids)
1091 {
1092         int ret;
1093         struct btrfs_ioctl_search_args args;
1094         struct btrfs_ioctl_search_key *sk = &args.key;
1095         int idx = 0;
1096         int count = 0;
1097
1098         memset(&args, 0, sizeof(args));
1099
1100         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1101         sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1102         sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1103         sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1104         sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1105         sk->min_offset = 0;
1106         sk->max_offset = (u64)-1;
1107         sk->min_transid = 0;
1108         sk->max_transid = (u64)-1;
1109         sk->nr_items = 4096;
1110
1111         *ids = NULL;
1112         while (1) {
1113                 struct btrfs_ioctl_search_header *sh;
1114                 unsigned long off;
1115                 int i;
1116
1117                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1118                 if (ret < 0)
1119                         return -errno;
1120
1121                 if (!sk->nr_items)
1122                         return idx;
1123
1124                 off = 0;
1125                 for (i = 0; i < sk->nr_items; i++) {
1126                         sh = (struct btrfs_ioctl_search_header*)(args.buf + off);
1127                         off += sizeof(*sh);
1128
1129                         if (btrfs_search_header_type(sh)
1130                             == BTRFS_ORPHAN_ITEM_KEY) {
1131                                 if (idx >= count) {
1132                                         u64 *newids;
1133
1134                                         count += SUBVOL_ID_BATCH;
1135                                         newids = (u64*)realloc(*ids,
1136                                                         count * sizeof(u64));
1137                                         if (!newids)
1138                                                 return -ENOMEM;
1139                                         *ids = newids;
1140                                 }
1141                                 (*ids)[idx] = btrfs_search_header_offset(sh);
1142                                 idx++;
1143                         }
1144                         off += btrfs_search_header_len(sh);
1145
1146                         sk->min_objectid = btrfs_search_header_objectid(sh);
1147                         sk->min_type = btrfs_search_header_type(sh);
1148                         sk->min_offset = btrfs_search_header_offset(sh);
1149                 }
1150                 if (sk->min_offset < (u64)-1)
1151                         sk->min_offset++;
1152                 else
1153                         break;
1154                 if (sk->min_type != BTRFS_ORPHAN_ITEM_KEY)
1155                         break;
1156                 if (sk->min_objectid != BTRFS_ORPHAN_OBJECTID)
1157                         break;
1158         }
1159
1160         return idx;
1161 }
1162
1163 static int cmd_subvol_sync(int argc, char **argv)
1164 {
1165         int fd = -1;
1166         int i;
1167         int ret = 1;
1168         DIR *dirstream = NULL;
1169         u64 *ids = NULL;
1170         int id_count;
1171         int sleep_interval = 1;
1172
1173         while (1) {
1174                 int c = getopt(argc, argv, "s:");
1175
1176                 if (c < 0)
1177                         break;
1178
1179                 switch (c) {
1180                 case 's':
1181                         sleep_interval = atoi(optarg);
1182                         if (sleep_interval < 1) {
1183                                 error("invalid sleep interval %s", optarg);
1184                                 ret = 1;
1185                                 goto out;
1186                         }
1187                         break;
1188                 default:
1189                         usage(cmd_subvol_sync_usage);
1190                 }
1191         }
1192
1193         if (check_argc_min(argc - optind, 1))
1194                 usage(cmd_subvol_sync_usage);
1195
1196         fd = btrfs_open_dir(argv[optind], &dirstream, 1);
1197         if (fd < 0) {
1198                 ret = 1;
1199                 goto out;
1200         }
1201         optind++;
1202
1203         id_count = argc - optind;
1204         if (!id_count) {
1205                 id_count = enumerate_dead_subvols(fd, &ids);
1206                 if (id_count < 0) {
1207                         error("can't enumerate dead subvolumes: %s",
1208                                         strerror(-id_count));
1209                         ret = 1;
1210                         goto out;
1211                 }
1212                 if (id_count == 0) {
1213                         ret = 0;
1214                         goto out;
1215                 }
1216         } else {
1217                 ids = (u64*)malloc(id_count * sizeof(u64));
1218                 if (!ids) {
1219                         error("not enough memory");
1220                         ret = 1;
1221                         goto out;
1222                 }
1223
1224                 for (i = 0; i < id_count; i++) {
1225                         u64 id;
1226                         const char *arg;
1227
1228                         arg = argv[optind + i];
1229                         errno = 0;
1230                         id = strtoull(arg, NULL, 10);
1231                         if (errno < 0) {
1232                                 error("unrecognized subvolume id %s", arg);
1233                                 ret = 1;
1234                                 goto out;
1235                         }
1236                         if (id < BTRFS_FIRST_FREE_OBJECTID
1237                                         || id > BTRFS_LAST_FREE_OBJECTID) {
1238                                 error("subvolume id %s out of range", arg);
1239                                 ret = 1;
1240                                 goto out;
1241                         }
1242                         ids[i] = id;
1243                 }
1244         }
1245
1246         ret = wait_for_subvolume_cleaning(fd, id_count, ids, sleep_interval);
1247
1248 out:
1249         free(ids);
1250         close_file_or_dir(fd, dirstream);
1251
1252         return !!ret;
1253 }
1254
1255 static const char subvolume_cmd_group_info[] =
1256 "manage subvolumes: create, delete, list, etc";
1257
1258 const struct cmd_group subvolume_cmd_group = {
1259         subvolume_cmd_group_usage, subvolume_cmd_group_info, {
1260                 { "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
1261                 { "delete", cmd_subvol_delete, cmd_subvol_delete_usage, NULL, 0 },
1262                 { "list", cmd_subvol_list, cmd_subvol_list_usage, NULL, 0 },
1263                 { "snapshot", cmd_subvol_snapshot, cmd_subvol_snapshot_usage,
1264                         NULL, 0 },
1265                 { "get-default", cmd_subvol_get_default,
1266                         cmd_subvol_get_default_usage, NULL, 0 },
1267                 { "set-default", cmd_subvol_set_default,
1268                         cmd_subvol_set_default_usage, NULL, 0 },
1269                 { "find-new", cmd_subvol_find_new, cmd_subvol_find_new_usage,
1270                         NULL, 0 },
1271                 { "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
1272                 { "sync", cmd_subvol_sync, cmd_subvol_sync_usage, NULL, 0 },
1273                 NULL_CMD_STRUCT
1274         }
1275 };
1276
1277 int cmd_subvolume(int argc, char **argv)
1278 {
1279         return handle_command_group(&subvolume_cmd_group, argc, argv);
1280 }