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