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