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