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