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