btrfs-progs: make getopt tables static const
[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", 1, 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 (get_ri.otime) {
978                 struct tm tm;
979
980                 localtime_r(&get_ri.otime, &tm);
981                 strftime(tstr, 256, "%Y-%m-%d %X", &tm);
982         } else
983                 strcpy(tstr, "-");
984         printf("\tCreation time: \t\t%s\n", tstr);
985
986         printf("\tObject ID: \t\t%llu\n", get_ri.root_id);
987         printf("\tGeneration (Gen): \t%llu\n", get_ri.gen);
988         printf("\tGen at creation: \t%llu\n", get_ri.ogen);
989         printf("\tParent: \t\t%llu\n", get_ri.ref_tree);
990         printf("\tTop Level: \t\t%llu\n", get_ri.top_id);
991
992         if (get_ri.flags & BTRFS_ROOT_SUBVOL_RDONLY)
993                 printf("\tFlags: \t\t\treadonly\n");
994         else
995                 printf("\tFlags: \t\t\t-\n");
996
997         /* print the snapshots of the given subvol if any*/
998         printf("\tSnapshot(s):\n");
999         filter_set = btrfs_list_alloc_filter_set();
1000         btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_BY_PARENT,
1001                                 (u64)(unsigned long)get_ri.uuid);
1002         btrfs_list_setup_print_column(BTRFS_LIST_PATH);
1003         btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
1004                         1, raw_prefix);
1005
1006         /* clean up */
1007         free(get_ri.path);
1008         free(get_ri.name);
1009         free(get_ri.full_path);
1010         btrfs_list_free_filter_set(filter_set);
1011
1012 out:
1013         close_file_or_dir(fd, dirstream1);
1014         close_file_or_dir(mntfd, dirstream2);
1015         free(mnt);
1016         free(fullpath);
1017         return !!ret;
1018 }
1019
1020 static const char * const cmd_subvol_sync_usage[] = {
1021         "btrfs subvolume sync <path> [<subvol-id>...]",
1022         "Wait until given subvolume(s) are completely removed from the filesystem.",
1023         "Wait until given subvolume(s) are completely removed from the filesystem",
1024         "after deletion.",
1025         "If no subvolume id is given, wait until all ongoing deletion requests",
1026         "are complete. This may take long if new deleted subvolumes appear during",
1027         "the sleep interval.",
1028         "",
1029         "-s <N>       sleep N seconds between checks (default: 1)",
1030         NULL
1031 };
1032
1033 static int is_subvolume_cleaned(int fd, u64 subvolid)
1034 {
1035         int ret;
1036         struct btrfs_ioctl_search_args args;
1037         struct btrfs_ioctl_search_key *sk = &args.key;
1038
1039         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1040         sk->min_objectid = subvolid;
1041         sk->max_objectid = subvolid;
1042         sk->min_type = BTRFS_ROOT_ITEM_KEY;
1043         sk->max_type = BTRFS_ROOT_ITEM_KEY;
1044         sk->min_offset = 0;
1045         sk->max_offset = (u64)-1;
1046         sk->min_transid = 0;
1047         sk->max_transid = (u64)-1;
1048         sk->nr_items = 1;
1049
1050         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1051         if (ret < 0)
1052                 return -errno;
1053
1054         if (sk->nr_items == 0)
1055                 return 1;
1056
1057         return 0;
1058 }
1059
1060 /*
1061  * If we're looking for any dead subvolume, take a shortcut and look
1062  * for any ORPHAN_ITEMs in the tree root
1063  */
1064 static int fs_has_dead_subvolumes(int fd)
1065 {
1066         int ret;
1067         struct btrfs_ioctl_search_args args;
1068         struct btrfs_ioctl_search_key *sk = &args.key;
1069         struct btrfs_ioctl_search_header sh;
1070         u64 min_subvolid = 0;
1071
1072 again:
1073         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1074         sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1075         sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1076         sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1077         sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1078         sk->min_offset = min_subvolid;
1079         sk->max_offset = (u64)-1;
1080         sk->min_transid = 0;
1081         sk->max_transid = (u64)-1;
1082         sk->nr_items = 1;
1083
1084         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1085         if (ret < 0)
1086                 return -errno;
1087
1088         if (!sk->nr_items)
1089                 return 0;
1090
1091         memcpy(&sh, args.buf, sizeof(sh));
1092         min_subvolid = sh.offset;
1093
1094         /*
1095          * Verify that the root item is really there and we haven't hit
1096          * a stale orphan
1097          */
1098         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1099         sk->min_objectid = min_subvolid;
1100         sk->max_objectid = min_subvolid;
1101         sk->min_type = BTRFS_ROOT_ITEM_KEY;
1102         sk->max_type = BTRFS_ROOT_ITEM_KEY;
1103         sk->min_offset = 0;
1104         sk->max_offset = (u64)-1;
1105         sk->min_transid = 0;
1106         sk->max_transid = (u64)-1;
1107         sk->nr_items = 1;
1108
1109         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1110         if (ret < 0)
1111                 return -errno;
1112
1113         /*
1114          * Stale orphan, try the next one
1115          */
1116         if (!sk->nr_items) {
1117                 min_subvolid++;
1118                 goto again;
1119         }
1120
1121         return 1;
1122 }
1123
1124 static int cmd_subvol_sync(int argc, char **argv)
1125 {
1126         int fd = -1;
1127         int i;
1128         int ret = 1;
1129         DIR *dirstream = NULL;
1130         u64 *ids = NULL;
1131         int id_count;
1132         int remaining;
1133         int sleep_interval = 1;
1134
1135         optind = 1;
1136         while (1) {
1137                 int c = getopt(argc, argv, "s:");
1138
1139                 if (c < 0)
1140                         break;
1141
1142                 switch (c) {
1143                 case 's':
1144                         sleep_interval = atoi(argv[optind]);
1145                         if (sleep_interval < 1) {
1146                                 fprintf(stderr,
1147                                         "ERROR: invalid sleep interval %s\n",
1148                                         argv[optind]);
1149                                 ret = 1;
1150                                 goto out;
1151                         }
1152                         break;
1153                 default:
1154                         usage(cmd_subvol_sync_usage);
1155                 }
1156         }
1157
1158         if (check_argc_min(argc - optind, 1))
1159                 usage(cmd_subvol_sync_usage);
1160
1161         fd = open_file_or_dir(argv[optind], &dirstream);
1162         if (fd < 0) {
1163                 fprintf(stderr, "ERROR: can't access '%s'\n", argv[optind]);
1164                 ret = 1;
1165                 goto out;
1166         }
1167         optind++;
1168
1169         id_count = argc - optind;
1170
1171         /*
1172          * Wait for all
1173          */
1174         if (!id_count) {
1175                 while (1) {
1176                         ret = fs_has_dead_subvolumes(fd);
1177                         if (ret < 0) {
1178                                 fprintf(stderr, "ERROR: can't perform the search - %s\n",
1179                                                 strerror(-ret));
1180                                 ret = 1;
1181                                 goto out;
1182                         }
1183                         if (!ret)
1184                                 goto out;
1185                         sleep(sleep_interval);
1186                 }
1187         }
1188
1189         /*
1190          * Wait only for the requested ones
1191          */
1192         ids = (u64*)malloc(sizeof(u64) * id_count);
1193
1194         if (!ids) {
1195                 fprintf(stderr, "ERROR: not enough memory\n");
1196                 ret = 1;
1197                 goto out;
1198         }
1199
1200         for (i = 0; i < id_count; i++) {
1201                 u64 id;
1202                 const char *arg;
1203
1204                 arg = argv[optind + i];
1205                 errno = 0;
1206                 id = strtoull(arg, NULL, 10);
1207                 if (errno < 0) {
1208                         fprintf(stderr, "ERROR: unrecognized subvolume id %s\n",
1209                                 arg);
1210                         ret = 1;
1211                         goto out;
1212                 }
1213                 if (id < BTRFS_FIRST_FREE_OBJECTID || id > BTRFS_LAST_FREE_OBJECTID) {
1214                         fprintf(stderr, "ERROR: subvolume id %s out of range\n",
1215                                 arg);
1216                         ret = 1;
1217                         goto out;
1218                 }
1219                 ids[i] = id;
1220         }
1221
1222         remaining = id_count;
1223         while (1) {
1224                 for (i = 0; i < id_count; i++) {
1225                         if (!ids[i])
1226                                 continue;
1227                         ret = is_subvolume_cleaned(fd, ids[i]);
1228                         if (ret < 0) {
1229                                 fprintf(stderr, "ERROR: can't perform the search - %s\n",
1230                                                 strerror(-ret));
1231                                 goto out;
1232                         }
1233                         if (ret) {
1234                                 printf("Subvolume id %llu is gone\n", ids[i]);
1235                                 ids[i] = 0;
1236                                 remaining--;
1237                         }
1238                 }
1239                 if (!remaining)
1240                         break;
1241                 sleep(sleep_interval);
1242         }
1243
1244 out:
1245         free(ids);
1246         close_file_or_dir(fd, dirstream);
1247
1248         return !!ret;
1249 }
1250
1251 const struct cmd_group subvolume_cmd_group = {
1252         subvolume_cmd_group_usage, NULL, {
1253                 { "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
1254                 { "delete", cmd_subvol_delete, cmd_subvol_delete_usage, NULL, 0 },
1255                 { "list", cmd_subvol_list, cmd_subvol_list_usage, NULL, 0 },
1256                 { "snapshot", cmd_snapshot, cmd_snapshot_usage, NULL, 0 },
1257                 { "get-default", cmd_subvol_get_default,
1258                         cmd_subvol_get_default_usage, NULL, 0 },
1259                 { "set-default", cmd_subvol_set_default,
1260                         cmd_subvol_set_default_usage, NULL, 0 },
1261                 { "find-new", cmd_find_new, cmd_find_new_usage, NULL, 0 },
1262                 { "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
1263                 { "sync", cmd_subvol_sync, cmd_subvol_sync_usage, NULL, 0 },
1264                 NULL_CMD_STRUCT
1265         }
1266 };
1267
1268 int cmd_subvolume(int argc, char **argv)
1269 {
1270         return handle_command_group(&subvolume_cmd_group, argc, argv);
1271 }