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