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