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