btrfs-progs: subvol show: use clean_args_no_options instead of opencoding
[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         clean_args_no_options(argc, argv, cmd_subvol_show_usage);
943
944         if (check_argc_exact(argc - optind, 1))
945                 usage(cmd_subvol_show_usage);
946
947         fullpath = realpath(argv[optind], NULL);
948         if (!fullpath) {
949                 error("cannot find real path for '%s': %s",
950                         argv[optind], strerror(errno));
951                 goto out;
952         }
953
954         ret = test_issubvolume(fullpath);
955         if (ret < 0) {
956                 error("cannot access subvolume %s: %s", fullpath,
957                         strerror(-ret));
958                 goto out;
959         }
960         if (!ret) {
961                 error("not a subvolume: %s", fullpath);
962                 ret = 1;
963                 goto out;
964         }
965
966         ret = find_mount_root(fullpath, &mnt);
967         if (ret < 0) {
968                 error("find_mount_root failed on '%s': %s",
969                         fullpath, strerror(-ret));
970                 goto out;
971         }
972         if (ret > 0) {
973                 error("%s doesn't belong to btrfs mount point", fullpath);
974                 goto out;
975         }
976         ret = 1;
977         svpath = get_subvol_name(mnt, fullpath);
978
979         fd = btrfs_open_dir(fullpath, &dirstream1, 1);
980         if (fd < 0)
981                 goto out;
982
983         ret = btrfs_list_get_path_rootid(fd, &sv_id);
984         if (ret) {
985                 error("can't get rootid for '%s'", fullpath);
986                 goto out;
987         }
988
989         mntfd = btrfs_open_dir(mnt, &dirstream2, 1);
990         if (mntfd < 0)
991                 goto out;
992
993         if (sv_id == BTRFS_FS_TREE_OBJECTID) {
994                 printf("%s is toplevel subvolume\n", fullpath);
995                 goto out;
996         }
997
998         memset(&get_ri, 0, sizeof(get_ri));
999         get_ri.root_id = sv_id;
1000
1001         ret = btrfs_get_subvol(mntfd, &get_ri);
1002         if (ret) {
1003                 error("can't find '%s'", svpath);
1004                 goto out;
1005         }
1006
1007         /* print the info */
1008         printf("%s\n", fullpath);
1009         printf("\tName: \t\t\t%s\n", get_ri.name);
1010
1011         if (uuid_is_null(get_ri.uuid))
1012                 strcpy(uuidparse, "-");
1013         else
1014                 uuid_unparse(get_ri.uuid, uuidparse);
1015         printf("\tUUID: \t\t\t%s\n", uuidparse);
1016
1017         if (uuid_is_null(get_ri.puuid))
1018                 strcpy(uuidparse, "-");
1019         else
1020                 uuid_unparse(get_ri.puuid, uuidparse);
1021         printf("\tParent UUID: \t\t%s\n", uuidparse);
1022
1023         if (uuid_is_null(get_ri.ruuid))
1024                 strcpy(uuidparse, "-");
1025         else
1026                 uuid_unparse(get_ri.ruuid, uuidparse);
1027         printf("\tReceived UUID: \t\t%s\n", uuidparse);
1028
1029         if (get_ri.otime) {
1030                 struct tm tm;
1031
1032                 localtime_r(&get_ri.otime, &tm);
1033                 strftime(tstr, 256, "%Y-%m-%d %X %z", &tm);
1034         } else
1035                 strcpy(tstr, "-");
1036         printf("\tCreation time: \t\t%s\n", tstr);
1037
1038         printf("\tSubvolume ID: \t\t%llu\n", get_ri.root_id);
1039         printf("\tGeneration: \t\t%llu\n", get_ri.gen);
1040         printf("\tGen at creation: \t%llu\n", get_ri.ogen);
1041         printf("\tParent ID: \t\t%llu\n", get_ri.ref_tree);
1042         printf("\tTop level ID: \t\t%llu\n", get_ri.top_id);
1043
1044         if (get_ri.flags & BTRFS_ROOT_SUBVOL_RDONLY)
1045                 printf("\tFlags: \t\t\treadonly\n");
1046         else
1047                 printf("\tFlags: \t\t\t-\n");
1048
1049         /* print the snapshots of the given subvol if any*/
1050         printf("\tSnapshot(s):\n");
1051         filter_set = btrfs_list_alloc_filter_set();
1052         btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_BY_PARENT,
1053                                 (u64)(unsigned long)get_ri.uuid);
1054         btrfs_list_setup_print_column(BTRFS_LIST_PATH);
1055         btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
1056                         1, raw_prefix);
1057
1058         /* clean up */
1059         free(get_ri.path);
1060         free(get_ri.name);
1061         free(get_ri.full_path);
1062         btrfs_list_free_filter_set(filter_set);
1063
1064 out:
1065         close_file_or_dir(fd, dirstream1);
1066         close_file_or_dir(mntfd, dirstream2);
1067         free(mnt);
1068         free(fullpath);
1069         return !!ret;
1070 }
1071
1072 static const char * const cmd_subvol_sync_usage[] = {
1073         "btrfs subvolume sync <path> [<subvol-id>...]",
1074         "Wait until given subvolume(s) are completely removed from the filesystem.",
1075         "Wait until given subvolume(s) are completely removed from the filesystem",
1076         "after deletion.",
1077         "If no subvolume id is given, wait until all current deletion requests",
1078         "are completed, but do not wait for subvolumes deleted meanwhile.",
1079         "The status of subvolume ids is checked periodically.",
1080         "",
1081         "-s <N>       sleep N seconds between checks (default: 1)",
1082         NULL
1083 };
1084
1085 #if 0
1086 /*
1087  * If we're looking for any dead subvolume, take a shortcut and look
1088  * for any ORPHAN_ITEMs in the tree root
1089  */
1090 static int fs_has_dead_subvolumes(int fd)
1091 {
1092         int ret;
1093         struct btrfs_ioctl_search_args args;
1094         struct btrfs_ioctl_search_key *sk = &args.key;
1095         struct btrfs_ioctl_search_header sh;
1096         u64 min_subvolid = 0;
1097
1098 again:
1099         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1100         sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1101         sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1102         sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1103         sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1104         sk->min_offset = min_subvolid;
1105         sk->max_offset = (u64)-1;
1106         sk->min_transid = 0;
1107         sk->max_transid = (u64)-1;
1108         sk->nr_items = 1;
1109
1110         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1111         if (ret < 0)
1112                 return -errno;
1113
1114         if (!sk->nr_items)
1115                 return 0;
1116
1117         memcpy(&sh, args.buf, sizeof(sh));
1118         min_subvolid = sh.offset;
1119
1120         /*
1121          * Verify that the root item is really there and we haven't hit
1122          * a stale orphan
1123          */
1124         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1125         sk->min_objectid = min_subvolid;
1126         sk->max_objectid = min_subvolid;
1127         sk->min_type = BTRFS_ROOT_ITEM_KEY;
1128         sk->max_type = BTRFS_ROOT_ITEM_KEY;
1129         sk->min_offset = 0;
1130         sk->max_offset = (u64)-1;
1131         sk->min_transid = 0;
1132         sk->max_transid = (u64)-1;
1133         sk->nr_items = 1;
1134
1135         ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1136         if (ret < 0)
1137                 return -errno;
1138
1139         /*
1140          * Stale orphan, try the next one
1141          */
1142         if (!sk->nr_items) {
1143                 min_subvolid++;
1144                 goto again;
1145         }
1146
1147         return 1;
1148 }
1149 #endif
1150
1151 #define SUBVOL_ID_BATCH         1024
1152
1153 /*
1154  * Enumerate all dead subvolumes that exist in the filesystem.
1155  * Fill @ids and reallocate to bigger size if needed.
1156  */
1157 static int enumerate_dead_subvols(int fd, u64 **ids)
1158 {
1159         int ret;
1160         struct btrfs_ioctl_search_args args;
1161         struct btrfs_ioctl_search_key *sk = &args.key;
1162         int idx = 0;
1163         int count = 0;
1164
1165         memset(&args, 0, sizeof(args));
1166
1167         sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1168         sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1169         sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1170         sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1171         sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1172         sk->min_offset = 0;
1173         sk->max_offset = (u64)-1;
1174         sk->min_transid = 0;
1175         sk->max_transid = (u64)-1;
1176         sk->nr_items = 4096;
1177
1178         *ids = NULL;
1179         while (1) {
1180                 struct btrfs_ioctl_search_header *sh;
1181                 unsigned long off;
1182                 int i;
1183
1184                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1185                 if (ret < 0)
1186                         return -errno;
1187
1188                 if (!sk->nr_items)
1189                         return idx;
1190
1191                 off = 0;
1192                 for (i = 0; i < sk->nr_items; i++) {
1193                         sh = (struct btrfs_ioctl_search_header*)(args.buf + off);
1194                         off += sizeof(*sh);
1195
1196                         if (sh->type == BTRFS_ORPHAN_ITEM_KEY) {
1197                                 if (idx >= count) {
1198                                         u64 *newids;
1199
1200                                         count += SUBVOL_ID_BATCH;
1201                                         newids = (u64*)realloc(*ids, count);
1202                                         if (!newids)
1203                                                 return -ENOMEM;
1204                                         *ids = newids;
1205                                 }
1206                                 (*ids)[idx] = sh->offset;
1207                                 idx++;
1208                         }
1209                         off += sh->len;
1210
1211                         sk->min_objectid = sh->objectid;
1212                         sk->min_type = sh->type;
1213                         sk->min_offset = sh->offset;
1214                 }
1215                 if (sk->min_offset < (u64)-1)
1216                         sk->min_offset++;
1217                 else
1218                         break;
1219                 if (sk->min_type != BTRFS_ORPHAN_ITEM_KEY)
1220                         break;
1221                 if (sk->min_objectid != BTRFS_ORPHAN_OBJECTID)
1222                         break;
1223         }
1224
1225         return idx;
1226 }
1227
1228 static int cmd_subvol_sync(int argc, char **argv)
1229 {
1230         int fd = -1;
1231         int i;
1232         int ret = 1;
1233         DIR *dirstream = NULL;
1234         u64 *ids = NULL;
1235         int id_count;
1236         int sleep_interval = 1;
1237
1238         optind = 1;
1239         while (1) {
1240                 int c = getopt(argc, argv, "s:");
1241
1242                 if (c < 0)
1243                         break;
1244
1245                 switch (c) {
1246                 case 's':
1247                         sleep_interval = atoi(argv[optind]);
1248                         if (sleep_interval < 1) {
1249                                 error("invalid sleep interval %s",
1250                                         argv[optind]);
1251                                 ret = 1;
1252                                 goto out;
1253                         }
1254                         break;
1255                 default:
1256                         usage(cmd_subvol_sync_usage);
1257                 }
1258         }
1259
1260         if (check_argc_min(argc - optind, 1))
1261                 usage(cmd_subvol_sync_usage);
1262
1263         fd = btrfs_open_dir(argv[optind], &dirstream, 1);
1264         if (fd < 0) {
1265                 ret = 1;
1266                 goto out;
1267         }
1268         optind++;
1269
1270         id_count = argc - optind;
1271         if (!id_count) {
1272                 id_count = enumerate_dead_subvols(fd, &ids);
1273                 if (id_count < 0) {
1274                         error("can't enumerate dead subvolumes: %s",
1275                                         strerror(-id_count));
1276                         ret = 1;
1277                         goto out;
1278                 }
1279                 if (id_count == 0) {
1280                         ret = 0;
1281                         goto out;
1282                 }
1283         } else {
1284                 ids = (u64*)malloc(id_count * sizeof(u64));
1285                 if (!ids) {
1286                         error("not enough memory");
1287                         ret = 1;
1288                         goto out;
1289                 }
1290
1291                 for (i = 0; i < id_count; i++) {
1292                         u64 id;
1293                         const char *arg;
1294
1295                         arg = argv[optind + i];
1296                         errno = 0;
1297                         id = strtoull(arg, NULL, 10);
1298                         if (errno < 0) {
1299                                 error("unrecognized subvolume id %s", arg);
1300                                 ret = 1;
1301                                 goto out;
1302                         }
1303                         if (id < BTRFS_FIRST_FREE_OBJECTID
1304                                         || id > BTRFS_LAST_FREE_OBJECTID) {
1305                                 error("subvolume id %s out of range\n", arg);
1306                                 ret = 1;
1307                                 goto out;
1308                         }
1309                         ids[i] = id;
1310                 }
1311         }
1312
1313         ret = wait_for_subvolume_cleaning(fd, id_count, ids, sleep_interval);
1314
1315 out:
1316         free(ids);
1317         close_file_or_dir(fd, dirstream);
1318
1319         return !!ret;
1320 }
1321
1322 static const char subvolume_cmd_group_info[] =
1323 "manage subvolumes: create, delete, list, etc";
1324
1325 const struct cmd_group subvolume_cmd_group = {
1326         subvolume_cmd_group_usage, subvolume_cmd_group_info, {
1327                 { "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
1328                 { "delete", cmd_subvol_delete, cmd_subvol_delete_usage, NULL, 0 },
1329                 { "list", cmd_subvol_list, cmd_subvol_list_usage, NULL, 0 },
1330                 { "snapshot", cmd_subvol_snapshot, cmd_subvol_snapshot_usage,
1331                         NULL, 0 },
1332                 { "get-default", cmd_subvol_get_default,
1333                         cmd_subvol_get_default_usage, NULL, 0 },
1334                 { "set-default", cmd_subvol_set_default,
1335                         cmd_subvol_set_default_usage, NULL, 0 },
1336                 { "find-new", cmd_subvol_find_new, cmd_subvol_find_new_usage,
1337                         NULL, 0 },
1338                 { "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
1339                 { "sync", cmd_subvol_sync, cmd_subvol_sync_usage, NULL, 0 },
1340                 NULL_CMD_STRUCT
1341         }
1342 };
1343
1344 int cmd_subvolume(int argc, char **argv)
1345 {
1346         return handle_command_group(&subvolume_cmd_group, argc, argv);
1347 }