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