btrfs-progs: add getopt stubs where needed
[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         clean_args_no_options(argc, argv, cmd_subvol_get_default_usage);
792
793         if (check_argc_exact(argc - optind, 2))
794                 usage(cmd_subvol_get_default_usage);
795
796         subvol = argv[1];
797         fd = btrfs_open_dir(subvol, &dirstream, 1);
798         if (fd < 0)
799                 return 1;
800
801         ret = btrfs_list_get_default_subvolume(fd, &default_id);
802         if (ret) {
803                 error("failed to look up default subvolume: %s",
804                         strerror(errno));
805                 goto out;
806         }
807
808         ret = 1;
809         if (default_id == 0) {
810                 error("'default' dir item not found");
811                 goto out;
812         }
813
814         /* no need to resolve roots if FS_TREE is default */
815         if (default_id == BTRFS_FS_TREE_OBJECTID) {
816                 printf("ID 5 (FS_TREE)\n");
817                 ret = 0;
818                 goto out;
819         }
820
821         filter_set = btrfs_list_alloc_filter_set();
822         btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_ROOTID,
823                                 default_id);
824
825         /* by default we shall print the following columns*/
826         btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
827         btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
828         btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
829         btrfs_list_setup_print_column(BTRFS_LIST_PATH);
830
831         ret = btrfs_list_subvols_print(fd, filter_set, NULL,
832                 BTRFS_LIST_LAYOUT_DEFAULT, 1, NULL);
833
834         if (filter_set)
835                 btrfs_list_free_filter_set(filter_set);
836 out:
837         close_file_or_dir(fd, dirstream);
838         return !!ret;
839 }
840
841 static const char * const cmd_subvol_set_default_usage[] = {
842         "btrfs subvolume set-default <subvolid> <path>",
843         "Set the default subvolume of a filesystem",
844         NULL
845 };
846
847 static int cmd_subvol_set_default(int argc, char **argv)
848 {
849         int     ret=0, fd, e;
850         u64     objectid;
851         char    *path;
852         char    *subvolid;
853         DIR     *dirstream = NULL;
854
855         clean_args_no_options(argc, argv, cmd_subvol_set_default_usage);
856
857         if (check_argc_exact(argc - optind, 2))
858                 usage(cmd_subvol_set_default_usage);
859
860         subvolid = argv[optind];
861         path = argv[optind + 1];
862
863         objectid = arg_strtou64(subvolid);
864
865         fd = btrfs_open_dir(path, &dirstream, 1);
866         if (fd < 0)
867                 return 1;
868
869         ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
870         e = errno;
871         close_file_or_dir(fd, dirstream);
872         if (ret < 0) {
873                 error("unable to set a new default subvolume: %s",
874                         strerror(e));
875                 return 1;
876         }
877         return 0;
878 }
879
880 static const char * const cmd_subvol_find_new_usage[] = {
881         "btrfs subvolume find-new <path> <lastgen>",
882         "List the recently modified files in a filesystem",
883         NULL
884 };
885
886 static int cmd_subvol_find_new(int argc, char **argv)
887 {
888         int fd;
889         int ret;
890         char *subvol;
891         u64 last_gen;
892         DIR *dirstream = NULL;
893
894         clean_args_no_options(argc, argv, cmd_subvol_find_new_usage);
895
896         if (check_argc_exact(argc - optind, 2))
897                 usage(cmd_subvol_find_new_usage);
898
899         subvol = argv[optind];
900         last_gen = arg_strtou64(argv[optind + 1]);
901
902         ret = test_issubvolume(subvol);
903         if (ret < 0) {
904                 error("cannot access subvolume %s: %s", subvol, strerror(-ret));
905                 return 1;
906         }
907         if (!ret) {
908                 error("not a subvolume: %s", subvol);
909                 return 1;
910         }
911
912         fd = btrfs_open_dir(subvol, &dirstream, 1);
913         if (fd < 0)
914                 return 1;
915
916         ret = ioctl(fd, BTRFS_IOC_SYNC);
917         if (ret < 0) {
918                 error("sync ioctl failed on '%s': %s",
919                         subvol, strerror(errno));
920                 close_file_or_dir(fd, dirstream);
921                 return 1;
922         }
923
924         ret = btrfs_list_find_updated_files(fd, 0, last_gen);
925         close_file_or_dir(fd, dirstream);
926         return !!ret;
927 }
928
929 static const char * const cmd_subvol_show_usage[] = {
930         "btrfs subvolume show <subvol-path>",
931         "Show more information of the subvolume",
932         NULL
933 };
934
935 static int cmd_subvol_show(int argc, char **argv)
936 {
937         struct root_info get_ri;
938         struct btrfs_list_filter_set *filter_set;
939         char tstr[256];
940         char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
941         char *fullpath = NULL, *svpath = NULL, *mnt = NULL;
942         char raw_prefix[] = "\t\t\t\t";
943         u64 sv_id;
944         int fd = -1, mntfd = -1;
945         int ret = 1;
946         DIR *dirstream1 = NULL, *dirstream2 = NULL;
947
948         clean_args_no_options(argc, argv, cmd_subvol_show_usage);
949
950         if (check_argc_exact(argc - optind, 1))
951                 usage(cmd_subvol_show_usage);
952
953         fullpath = realpath(argv[optind], NULL);
954         if (!fullpath) {
955                 error("cannot find real path for '%s': %s",
956                         argv[optind], strerror(errno));
957                 goto out;
958         }
959
960         ret = test_issubvolume(fullpath);
961         if (ret < 0) {
962                 error("cannot access subvolume %s: %s", fullpath,
963                         strerror(-ret));
964                 goto out;
965         }
966         if (!ret) {
967                 error("not a subvolume: %s", fullpath);
968                 ret = 1;
969                 goto out;
970         }
971
972         ret = find_mount_root(fullpath, &mnt);
973         if (ret < 0) {
974                 error("find_mount_root failed on '%s': %s",
975                         fullpath, strerror(-ret));
976                 goto out;
977         }
978         if (ret > 0) {
979                 error("%s doesn't belong to btrfs mount point", fullpath);
980                 goto out;
981         }
982         ret = 1;
983         svpath = get_subvol_name(mnt, fullpath);
984
985         fd = btrfs_open_dir(fullpath, &dirstream1, 1);
986         if (fd < 0)
987                 goto out;
988
989         ret = btrfs_list_get_path_rootid(fd, &sv_id);
990         if (ret) {
991                 error("can't get rootid for '%s'", fullpath);
992                 goto out;
993         }
994
995         mntfd = btrfs_open_dir(mnt, &dirstream2, 1);
996         if (mntfd < 0)
997                 goto out;
998
999         if (sv_id == BTRFS_FS_TREE_OBJECTID) {
1000                 printf("%s is toplevel subvolume\n", fullpath);
1001                 goto out;
1002         }
1003
1004         memset(&get_ri, 0, sizeof(get_ri));
1005         get_ri.root_id = sv_id;
1006
1007         ret = btrfs_get_subvol(mntfd, &get_ri);
1008         if (ret) {
1009                 error("can't find '%s'", svpath);
1010                 goto out;
1011         }
1012
1013         /* print the info */
1014         printf("%s\n", fullpath);
1015         printf("\tName: \t\t\t%s\n", get_ri.name);
1016
1017         if (uuid_is_null(get_ri.uuid))
1018                 strcpy(uuidparse, "-");
1019         else
1020                 uuid_unparse(get_ri.uuid, uuidparse);
1021         printf("\tUUID: \t\t\t%s\n", uuidparse);
1022
1023         if (uuid_is_null(get_ri.puuid))
1024                 strcpy(uuidparse, "-");
1025         else
1026                 uuid_unparse(get_ri.puuid, uuidparse);
1027         printf("\tParent UUID: \t\t%s\n", uuidparse);
1028
1029         if (uuid_is_null(get_ri.ruuid))
1030                 strcpy(uuidparse, "-");
1031         else
1032                 uuid_unparse(get_ri.ruuid, uuidparse);
1033         printf("\tReceived UUID: \t\t%s\n", uuidparse);
1034
1035         if (get_ri.otime) {
1036                 struct tm tm;
1037
1038                 localtime_r(&get_ri.otime, &tm);
1039                 strftime(tstr, 256, "%Y-%m-%d %X %z", &tm);
1040         } else
1041                 strcpy(tstr, "-");
1042         printf("\tCreation time: \t\t%s\n", tstr);
1043
1044         printf("\tSubvolume ID: \t\t%llu\n", get_ri.root_id);
1045         printf("\tGeneration: \t\t%llu\n", get_ri.gen);
1046         printf("\tGen at creation: \t%llu\n", get_ri.ogen);
1047         printf("\tParent ID: \t\t%llu\n", get_ri.ref_tree);
1048         printf("\tTop level ID: \t\t%llu\n", get_ri.top_id);
1049
1050         if (get_ri.flags & BTRFS_ROOT_SUBVOL_RDONLY)
1051                 printf("\tFlags: \t\t\treadonly\n");
1052         else
1053                 printf("\tFlags: \t\t\t-\n");
1054
1055         /* print the snapshots of the given subvol if any*/
1056         printf("\tSnapshot(s):\n");
1057         filter_set = btrfs_list_alloc_filter_set();
1058         btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_BY_PARENT,
1059                                 (u64)(unsigned long)get_ri.uuid);
1060         btrfs_list_setup_print_column(BTRFS_LIST_PATH);
1061         btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
1062                         1, raw_prefix);
1063
1064         /* clean up */
1065         free(get_ri.path);
1066         free(get_ri.name);
1067         free(get_ri.full_path);
1068         btrfs_list_free_filter_set(filter_set);
1069
1070 out:
1071         close_file_or_dir(fd, dirstream1);
1072         close_file_or_dir(mntfd, dirstream2);
1073         free(mnt);
1074         free(fullpath);
1075         return !!ret;
1076 }
1077
1078 static const char * const cmd_subvol_sync_usage[] = {
1079         "btrfs subvolume sync <path> [<subvol-id>...]",
1080         "Wait until given subvolume(s) are completely removed from the filesystem.",
1081         "Wait until given subvolume(s) are completely removed from the filesystem",
1082         "after deletion.",
1083         "If no subvolume id is given, wait until all current deletion requests",
1084         "are completed, but do not wait for subvolumes deleted meanwhile.",
1085         "The status of subvolume ids is checked periodically.",
1086         "",
1087         "-s <N>       sleep N seconds between checks (default: 1)",
1088         NULL
1089 };
1090
1091 #if 0
1092 /*
1093  * If we're looking for any dead subvolume, take a shortcut and look
1094  * for any ORPHAN_ITEMs in the tree root
1095  */
1096 static int fs_has_dead_subvolumes(int fd)
1097 {
1098         int ret;
1099         struct btrfs_ioctl_search_args args;
1100         struct btrfs_ioctl_search_key *sk = &args.key;
1101         struct btrfs_ioctl_search_header sh;
1102         u64 min_subvolid = 0;
1103
1104 again:
1105         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1106         sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1107         sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1108         sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1109         sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1110         sk->min_offset = min_subvolid;
1111         sk->max_offset = (u64)-1;
1112         sk->min_transid = 0;
1113         sk->max_transid = (u64)-1;
1114         sk->nr_items = 1;
1115
1116         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1117         if (ret < 0)
1118                 return -errno;
1119
1120         if (!sk->nr_items)
1121                 return 0;
1122
1123         memcpy(&sh, args.buf, sizeof(sh));
1124         min_subvolid = sh.offset;
1125
1126         /*
1127          * Verify that the root item is really there and we haven't hit
1128          * a stale orphan
1129          */
1130         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1131         sk->min_objectid = min_subvolid;
1132         sk->max_objectid = min_subvolid;
1133         sk->min_type = BTRFS_ROOT_ITEM_KEY;
1134         sk->max_type = BTRFS_ROOT_ITEM_KEY;
1135         sk->min_offset = 0;
1136         sk->max_offset = (u64)-1;
1137         sk->min_transid = 0;
1138         sk->max_transid = (u64)-1;
1139         sk->nr_items = 1;
1140
1141         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1142         if (ret < 0)
1143                 return -errno;
1144
1145         /*
1146          * Stale orphan, try the next one
1147          */
1148         if (!sk->nr_items) {
1149                 min_subvolid++;
1150                 goto again;
1151         }
1152
1153         return 1;
1154 }
1155 #endif
1156
1157 #define SUBVOL_ID_BATCH         1024
1158
1159 /*
1160  * Enumerate all dead subvolumes that exist in the filesystem.
1161  * Fill @ids and reallocate to bigger size if needed.
1162  */
1163 static int enumerate_dead_subvols(int fd, u64 **ids)
1164 {
1165         int ret;
1166         struct btrfs_ioctl_search_args args;
1167         struct btrfs_ioctl_search_key *sk = &args.key;
1168         int idx = 0;
1169         int count = 0;
1170
1171         memset(&args, 0, sizeof(args));
1172
1173         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1174         sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1175         sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1176         sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1177         sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1178         sk->min_offset = 0;
1179         sk->max_offset = (u64)-1;
1180         sk->min_transid = 0;
1181         sk->max_transid = (u64)-1;
1182         sk->nr_items = 4096;
1183
1184         *ids = NULL;
1185         while (1) {
1186                 struct btrfs_ioctl_search_header *sh;
1187                 unsigned long off;
1188                 int i;
1189
1190                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1191                 if (ret < 0)
1192                         return -errno;
1193
1194                 if (!sk->nr_items)
1195                         return idx;
1196
1197                 off = 0;
1198                 for (i = 0; i < sk->nr_items; i++) {
1199                         sh = (struct btrfs_ioctl_search_header*)(args.buf + off);
1200                         off += sizeof(*sh);
1201
1202                         if (sh->type == BTRFS_ORPHAN_ITEM_KEY) {
1203                                 if (idx >= count) {
1204                                         u64 *newids;
1205
1206                                         count += SUBVOL_ID_BATCH;
1207                                         newids = (u64*)realloc(*ids, count);
1208                                         if (!newids)
1209                                                 return -ENOMEM;
1210                                         *ids = newids;
1211                                 }
1212                                 (*ids)[idx] = sh->offset;
1213                                 idx++;
1214                         }
1215                         off += sh->len;
1216
1217                         sk->min_objectid = sh->objectid;
1218                         sk->min_type = sh->type;
1219                         sk->min_offset = sh->offset;
1220                 }
1221                 if (sk->min_offset < (u64)-1)
1222                         sk->min_offset++;
1223                 else
1224                         break;
1225                 if (sk->min_type != BTRFS_ORPHAN_ITEM_KEY)
1226                         break;
1227                 if (sk->min_objectid != BTRFS_ORPHAN_OBJECTID)
1228                         break;
1229         }
1230
1231         return idx;
1232 }
1233
1234 static int cmd_subvol_sync(int argc, char **argv)
1235 {
1236         int fd = -1;
1237         int i;
1238         int ret = 1;
1239         DIR *dirstream = NULL;
1240         u64 *ids = NULL;
1241         int id_count;
1242         int sleep_interval = 1;
1243
1244         optind = 1;
1245         while (1) {
1246                 int c = getopt(argc, argv, "s:");
1247
1248                 if (c < 0)
1249                         break;
1250
1251                 switch (c) {
1252                 case 's':
1253                         sleep_interval = atoi(argv[optind]);
1254                         if (sleep_interval < 1) {
1255                                 error("invalid sleep interval %s",
1256                                         argv[optind]);
1257                                 ret = 1;
1258                                 goto out;
1259                         }
1260                         break;
1261                 default:
1262                         usage(cmd_subvol_sync_usage);
1263                 }
1264         }
1265
1266         if (check_argc_min(argc - optind, 1))
1267                 usage(cmd_subvol_sync_usage);
1268
1269         fd = btrfs_open_dir(argv[optind], &dirstream, 1);
1270         if (fd < 0) {
1271                 ret = 1;
1272                 goto out;
1273         }
1274         optind++;
1275
1276         id_count = argc - optind;
1277         if (!id_count) {
1278                 id_count = enumerate_dead_subvols(fd, &ids);
1279                 if (id_count < 0) {
1280                         error("can't enumerate dead subvolumes: %s",
1281                                         strerror(-id_count));
1282                         ret = 1;
1283                         goto out;
1284                 }
1285                 if (id_count == 0) {
1286                         ret = 0;
1287                         goto out;
1288                 }
1289         } else {
1290                 ids = (u64*)malloc(id_count * sizeof(u64));
1291                 if (!ids) {
1292                         error("not enough memory");
1293                         ret = 1;
1294                         goto out;
1295                 }
1296
1297                 for (i = 0; i < id_count; i++) {
1298                         u64 id;
1299                         const char *arg;
1300
1301                         arg = argv[optind + i];
1302                         errno = 0;
1303                         id = strtoull(arg, NULL, 10);
1304                         if (errno < 0) {
1305                                 error("unrecognized subvolume id %s", arg);
1306                                 ret = 1;
1307                                 goto out;
1308                         }
1309                         if (id < BTRFS_FIRST_FREE_OBJECTID
1310                                         || id > BTRFS_LAST_FREE_OBJECTID) {
1311                                 error("subvolume id %s out of range\n", arg);
1312                                 ret = 1;
1313                                 goto out;
1314                         }
1315                         ids[i] = id;
1316                 }
1317         }
1318
1319         ret = wait_for_subvolume_cleaning(fd, id_count, ids, sleep_interval);
1320
1321 out:
1322         free(ids);
1323         close_file_or_dir(fd, dirstream);
1324
1325         return !!ret;
1326 }
1327
1328 static const char subvolume_cmd_group_info[] =
1329 "manage subvolumes: create, delete, list, etc";
1330
1331 const struct cmd_group subvolume_cmd_group = {
1332         subvolume_cmd_group_usage, subvolume_cmd_group_info, {
1333                 { "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
1334                 { "delete", cmd_subvol_delete, cmd_subvol_delete_usage, NULL, 0 },
1335                 { "list", cmd_subvol_list, cmd_subvol_list_usage, NULL, 0 },
1336                 { "snapshot", cmd_subvol_snapshot, cmd_subvol_snapshot_usage,
1337                         NULL, 0 },
1338                 { "get-default", cmd_subvol_get_default,
1339                         cmd_subvol_get_default_usage, NULL, 0 },
1340                 { "set-default", cmd_subvol_set_default,
1341                         cmd_subvol_set_default_usage, NULL, 0 },
1342                 { "find-new", cmd_subvol_find_new, cmd_subvol_find_new_usage,
1343                         NULL, 0 },
1344                 { "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
1345                 { "sync", cmd_subvol_sync, cmd_subvol_sync_usage, NULL, 0 },
1346                 NULL_CMD_STRUCT
1347         }
1348 };
1349
1350 int cmd_subvolume(int argc, char **argv)
1351 {
1352         return handle_command_group(&subvolume_cmd_group, argc, argv);
1353 }