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