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