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