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