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