Btrfs-progs: restructure list_subvolumes
[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
27 #include "kerncompat.h"
28 #include "ioctl.h"
29 #include "qgroup.h"
30
31 #include "ctree.h"
32 #include "commands.h"
33 #include "btrfs-list.h"
34
35 static const char * const subvolume_cmd_group_usage[] = {
36         "btrfs subvolume <command> <args>",
37         NULL
38 };
39
40 /*
41  * test if path is a directory
42  * this function return
43  * 0-> path exists but it is not a directory
44  * 1-> path exists and it is  a directory
45  * -1 -> path is unaccessible
46  */
47 static int test_isdir(char *path)
48 {
49         struct stat     st;
50         int             res;
51
52         res = stat(path, &st);
53         if(res < 0 )
54                 return -1;
55
56         return S_ISDIR(st.st_mode);
57 }
58
59 static const char * const cmd_subvol_create_usage[] = {
60         "btrfs subvolume create [<dest>/]<name>",
61         "Create a subvolume",
62         "Create a subvolume <name> in <dest>.  If <dest> is not given",
63         "subvolume <name> will be created in the current directory.",
64         NULL
65 };
66
67 static int cmd_subvol_create(int argc, char **argv)
68 {
69         int     res, fddst, len, e;
70         char    *newname;
71         char    *dstdir;
72         char    *dst;
73         struct btrfs_qgroup_inherit *inherit = NULL;
74
75         optind = 1;
76         while (1) {
77                 int c = getopt(argc, argv, "c:i:r");
78                 if (c < 0)
79                         break;
80
81                 switch (c) {
82                 case 'c':
83                         res = qgroup_inherit_add_copy(&inherit, optarg, 0);
84                         if (res)
85                                 return res;
86                         break;
87                 case 'i':
88                         res = qgroup_inherit_add_group(&inherit, optarg);
89                         if (res)
90                                 return res;
91                         break;
92                 default:
93                         usage(cmd_subvol_create_usage);
94                 }
95         }
96
97         if (check_argc_exact(argc - optind, 1))
98                 usage(cmd_subvol_create_usage);
99
100         dst = argv[optind];
101
102         res = test_isdir(dst);
103         if(res >= 0 ){
104                 fprintf(stderr, "ERROR: '%s' exists\n", dst);
105                 return 12;
106         }
107
108         newname = strdup(dst);
109         newname = basename(newname);
110         dstdir = strdup(dst);
111         dstdir = dirname(dstdir);
112
113         if( !strcmp(newname,".") || !strcmp(newname,"..") ||
114              strchr(newname, '/') ){
115                 fprintf(stderr, "ERROR: uncorrect subvolume name ('%s')\n",
116                         newname);
117                 return 14;
118         }
119
120         len = strlen(newname);
121         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
122                 fprintf(stderr, "ERROR: subvolume name too long ('%s)\n",
123                         newname);
124                 return 14;
125         }
126
127         fddst = open_file_or_dir(dstdir);
128         if (fddst < 0) {
129                 fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
130                 return 12;
131         }
132
133         printf("Create subvolume '%s/%s'\n", dstdir, newname);
134         if (inherit) {
135                 struct btrfs_ioctl_vol_args_v2  args;
136
137                 memset(&args, 0, sizeof(args));
138                 strncpy(args.name, newname, BTRFS_SUBVOL_NAME_MAX);
139                 args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
140                 args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
141                 args.size = qgroup_inherit_size(inherit);
142                 args.qgroup_inherit = inherit;
143
144                 res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE_V2, &args);
145         } else {
146                 struct btrfs_ioctl_vol_args     args;
147
148                 memset(&args, 0, sizeof(args));
149                 strncpy(args.name, newname, BTRFS_SUBVOL_NAME_MAX);
150                 args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
151
152                 res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
153         }
154
155         e = errno;
156
157         close(fddst);
158
159         if(res < 0 ){
160                 fprintf( stderr, "ERROR: cannot create subvolume - %s\n",
161                         strerror(e));
162                 return 11;
163         }
164         free(inherit);
165
166         return 0;
167 }
168
169 /*
170  * test if path is a subvolume:
171  * this function return
172  * 0-> path exists but it is not a subvolume
173  * 1-> path exists and it is  a subvolume
174  * -1 -> path is unaccessible
175  */
176 int test_issubvolume(char *path)
177 {
178         struct stat     st;
179         int             res;
180
181         res = stat(path, &st);
182         if(res < 0 )
183                 return -1;
184
185         return (st.st_ino == 256) && S_ISDIR(st.st_mode);
186 }
187
188 static const char * const cmd_subvol_delete_usage[] = {
189         "btrfs subvolume delete <name>",
190         "Delete a subvolume",
191         NULL
192 };
193
194 static int cmd_subvol_delete(int argc, char **argv)
195 {
196         int     res, fd, len, e;
197         struct btrfs_ioctl_vol_args     args;
198         char    *dname, *vname, *cpath;
199         char    *path;
200
201         if (check_argc_exact(argc, 2))
202                 usage(cmd_subvol_delete_usage);
203
204         path = argv[1];
205
206         res = test_issubvolume(path);
207         if(res<0){
208                 fprintf(stderr, "ERROR: error accessing '%s'\n", path);
209                 return 12;
210         }
211         if(!res){
212                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", path);
213                 return 13;
214         }
215
216         cpath = realpath(path, 0);
217         dname = strdup(cpath);
218         dname = dirname(dname);
219         vname = strdup(cpath);
220         vname = basename(vname);
221         free(cpath);
222
223         if( !strcmp(vname,".") || !strcmp(vname,"..") ||
224              strchr(vname, '/') ){
225                 fprintf(stderr, "ERROR: incorrect subvolume name ('%s')\n",
226                         vname);
227                 return 14;
228         }
229
230         len = strlen(vname);
231         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
232                 fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
233                         vname);
234                 return 14;
235         }
236
237         fd = open_file_or_dir(dname);
238         if (fd < 0) {
239                 close(fd);
240                 fprintf(stderr, "ERROR: can't access to '%s'\n", dname);
241                 return 12;
242         }
243
244         printf("Delete subvolume '%s/%s'\n", dname, vname);
245         strncpy(args.name, vname, BTRFS_PATH_NAME_MAX);
246         args.name[BTRFS_PATH_NAME_MAX-1] = 0;
247         res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
248         e = errno;
249
250         close(fd);
251
252         if(res < 0 ){
253                 fprintf( stderr, "ERROR: cannot delete '%s/%s' - %s\n",
254                         dname, vname, strerror(e));
255                 return 11;
256         }
257
258         return 0;
259 }
260
261 static const char * const cmd_subvol_list_usage[] = {
262         "btrfs subvolume list [-pu] [-s 0|1] <path>",
263         "List subvolumes (and snapshots)",
264         "",
265         "-p           print parent ID",
266         "-u           print the uuid of subvolumes (and snapshots)",
267         "-s value     list snapshots with generation in ascending/descending order",
268         "             (1: ascending, 0: descending)",
269         NULL
270 };
271
272 static int cmd_subvol_list(int argc, char **argv)
273 {
274         struct btrfs_list_filter_set *filter_set;
275         struct btrfs_list_comparer_set *comparer_set;
276         int fd;
277         int ret;
278         int order;
279         char *subvol;
280
281         filter_set = btrfs_list_alloc_filter_set();
282         comparer_set = btrfs_list_alloc_comparer_set();
283
284         optind = 1;
285         while(1) {
286                 int c = getopt(argc, argv, "ps:u");
287                 if (c < 0)
288                         break;
289
290                 switch(c) {
291                 case 'p':
292                         btrfs_list_setup_print_column(BTRFS_LIST_PARENT);
293                         break;
294                 case 's':
295                         order = atoi(optarg);
296                         btrfs_list_setup_filter(&filter_set,
297                                                 BTRFS_LIST_FILTER_SNAPSHOT_ONLY,
298                                                 0);
299                         btrfs_list_setup_comparer(&comparer_set,
300                                                   BTRFS_LIST_COMP_OGEN,
301                                                   !order);
302                         btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
303                         btrfs_list_setup_print_column(BTRFS_LIST_OTIME);
304                         break;
305                 case 'u':
306                         btrfs_list_setup_print_column(BTRFS_LIST_UUID);
307                         break;
308                 default:
309                         usage(cmd_subvol_list_usage);
310                 }
311         }
312
313         if (check_argc_exact(argc - optind, 1))
314                 usage(cmd_subvol_list_usage);
315
316         subvol = argv[optind];
317
318         ret = test_issubvolume(subvol);
319         if (ret < 0) {
320                 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
321                 return 12;
322         }
323         if (!ret) {
324                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
325                 return 13;
326         }
327
328         fd = open_file_or_dir(subvol);
329         if (fd < 0) {
330                 fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
331                 return 12;
332         }
333
334         ret = btrfs_list_subvols(fd, filter_set, comparer_set);
335         if (ret)
336                 return 19;
337         return 0;
338 }
339
340 static const char * const cmd_snapshot_usage[] = {
341         "btrfs subvolume snapshot [-r] <source> [<dest>/]<name>",
342         "Create a snapshot of the subvolume",
343         "Create a writable/readonly snapshot of the subvolume <source> with",
344         "the name <name> in the <dest> directory",
345         "",
346         "-r     create a readonly snapshot",
347         NULL
348 };
349
350 static int cmd_snapshot(int argc, char **argv)
351 {
352         char    *subvol, *dst;
353         int     res, fd, fddst, len, e, readonly = 0;
354         char    *newname;
355         char    *dstdir;
356         struct btrfs_ioctl_vol_args_v2  args;
357         struct btrfs_qgroup_inherit *inherit = NULL;
358
359         optind = 1;
360         memset(&args, 0, sizeof(args));
361         while (1) {
362                 int c = getopt(argc, argv, "c:i:r");
363                 if (c < 0)
364                         break;
365
366                 switch (c) {
367                 case 'c':
368                         res = qgroup_inherit_add_copy(&inherit, optarg, 0);
369                         if (res)
370                                 return res;
371                         break;
372                 case 'i':
373                         res = qgroup_inherit_add_group(&inherit, optarg);
374                         if (res)
375                                 return res;
376                         break;
377                 case 'r':
378                         readonly = 1;
379                         break;
380                 case 'x':
381                         res = qgroup_inherit_add_copy(&inherit, optarg, 1);
382                         if (res)
383                                 return res;
384                         break;
385                 default:
386                         usage(cmd_snapshot_usage);
387                 }
388         }
389
390         if (check_argc_exact(argc - optind, 2))
391                 usage(cmd_snapshot_usage);
392
393         subvol = argv[optind];
394         dst = argv[optind + 1];
395
396         res = test_issubvolume(subvol);
397         if(res<0){
398                 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
399                 return 12;
400         }
401         if(!res){
402                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
403                 return 13;
404         }
405
406         res = test_isdir(dst);
407         if(res == 0 ){
408                 fprintf(stderr, "ERROR: '%s' exists and it is not a directory\n", dst);
409                 return 12;
410         }
411
412         if(res>0){
413                 newname = strdup(subvol);
414                 newname = basename(newname);
415                 dstdir = dst;
416         }else{
417                 newname = strdup(dst);
418                 newname = basename(newname);
419                 dstdir = strdup(dst);
420                 dstdir = dirname(dstdir);
421         }
422
423         if( !strcmp(newname,".") || !strcmp(newname,"..") ||
424              strchr(newname, '/') ){
425                 fprintf(stderr, "ERROR: incorrect snapshot name ('%s')\n",
426                         newname);
427                 return 14;
428         }
429
430         len = strlen(newname);
431         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
432                 fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
433                         newname);
434                 return 14;
435         }
436
437         fddst = open_file_or_dir(dstdir);
438         if (fddst < 0) {
439                 fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
440                 return 12;
441         }
442
443         fd = open_file_or_dir(subvol);
444         if (fd < 0) {
445                 close(fddst);
446                 fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
447                 return 12;
448         }
449
450         if (readonly) {
451                 args.flags |= BTRFS_SUBVOL_RDONLY;
452                 printf("Create a readonly snapshot of '%s' in '%s/%s'\n",
453                        subvol, dstdir, newname);
454         } else {
455                 printf("Create a snapshot of '%s' in '%s/%s'\n",
456                        subvol, dstdir, newname);
457         }
458
459         args.fd = fd;
460         if (inherit) {
461                 args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
462                 args.size = qgroup_inherit_size(inherit);
463                 args.qgroup_inherit = inherit;
464         }
465         strncpy(args.name, newname, BTRFS_SUBVOL_NAME_MAX);
466         args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
467         res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);
468         e = errno;
469
470         close(fd);
471         close(fddst);
472
473         if(res < 0 ){
474                 fprintf( stderr, "ERROR: cannot snapshot '%s' - %s\n",
475                         subvol, strerror(e));
476                 return 11;
477         }
478         free(inherit);
479
480         return 0;
481 }
482
483 static const char * const cmd_subvol_get_default_usage[] = {
484         "btrfs subvolume get-default <path>",
485         "Get the default subvolume of a filesystem",
486         NULL
487 };
488
489 static int cmd_subvol_get_default(int argc, char **argv)
490 {
491         int fd;
492         int ret;
493         char *subvol;
494         struct btrfs_list_filter_set *filter_set;
495         u64 default_id;
496
497         if (check_argc_exact(argc, 2))
498                 usage(cmd_subvol_get_default_usage);
499
500         subvol = argv[1];
501
502         ret = test_issubvolume(subvol);
503         if (ret < 0) {
504                 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
505                 return 12;
506         }
507         if (!ret) {
508                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
509                 return 13;
510         }
511
512         fd = open_file_or_dir(subvol);
513         if (fd < 0) {
514                 fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
515                 return 12;
516         }
517
518         ret = btrfs_list_get_default_subvolume(fd, &default_id);
519         if (ret) {
520                 fprintf(stderr, "ERROR: can't perform the search - %s\n",
521                         strerror(errno));
522                 return ret;
523         }
524
525         if (default_id == 0) {
526                 fprintf(stderr, "ERROR: 'default' dir item not found\n");
527                 return ret;
528         }
529
530         /* no need to resolve roots if FS_TREE is default */
531         if (default_id == BTRFS_FS_TREE_OBJECTID) {
532                 printf("ID 5 (FS_TREE)\n");
533                 return ret;
534         }
535
536         filter_set = btrfs_list_alloc_filter_set();
537         btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_ROOTID,
538                                 default_id);
539
540         ret = btrfs_list_subvols(fd, filter_set, NULL);
541         if (ret)
542                 return 19;
543         return 0;
544 }
545
546 static const char * const cmd_subvol_set_default_usage[] = {
547         "btrfs subvolume set-default <subvolid> <path>",
548         "Set the default subvolume of a filesystem",
549         NULL
550 };
551
552 static int cmd_subvol_set_default(int argc, char **argv)
553 {
554         int     ret=0, fd, e;
555         u64     objectid;
556         char    *path;
557         char    *subvolid;
558
559         if (check_argc_exact(argc, 3))
560                 usage(cmd_subvol_set_default_usage);
561
562         subvolid = argv[1];
563         path = argv[2];
564
565         fd = open_file_or_dir(path);
566         if (fd < 0) {
567                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
568                 return 12;
569         }
570
571         objectid = (unsigned long long)strtoll(subvolid, NULL, 0);
572         if (errno == ERANGE) {
573                 fprintf(stderr, "ERROR: invalid tree id (%s)\n",subvolid);
574                 return 30;
575         }
576         ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
577         e = errno;
578         close(fd);
579         if( ret < 0 ){
580                 fprintf(stderr, "ERROR: unable to set a new default subvolume - %s\n",
581                         strerror(e));
582                 return 30;
583         }
584         return 0;
585 }
586
587 static const char * const cmd_find_new_usage[] = {
588         "btrfs subvolume find-new <path> <lastgen>",
589         "List the recently modified files in a filesystem",
590         NULL
591 };
592
593 static int cmd_find_new(int argc, char **argv)
594 {
595         int fd;
596         int ret;
597         char *subvol;
598         u64 last_gen;
599
600         if (check_argc_exact(argc, 3))
601                 usage(cmd_find_new_usage);
602
603         subvol = argv[1];
604         last_gen = atoll(argv[2]);
605
606         ret = test_issubvolume(subvol);
607         if (ret < 0) {
608                 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
609                 return 12;
610         }
611         if (!ret) {
612                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
613                 return 13;
614         }
615
616         fd = open_file_or_dir(subvol);
617         if (fd < 0) {
618                 fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
619                 return 12;
620         }
621         ret = btrfs_list_find_updated_files(fd, 0, last_gen);
622         if (ret)
623                 return 19;
624         return 0;
625 }
626
627 const struct cmd_group subvolume_cmd_group = {
628         subvolume_cmd_group_usage, NULL, {
629                 { "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
630                 { "delete", cmd_subvol_delete, cmd_subvol_delete_usage, NULL, 0 },
631                 { "list", cmd_subvol_list, cmd_subvol_list_usage, NULL, 0 },
632                 { "snapshot", cmd_snapshot, cmd_snapshot_usage, NULL, 0 },
633                 { "get-default", cmd_subvol_get_default,
634                         cmd_subvol_get_default_usage, NULL, 0 },
635                 { "set-default", cmd_subvol_set_default,
636                         cmd_subvol_set_default_usage, NULL, 0 },
637                 { "find-new", cmd_find_new, cmd_find_new_usage, NULL, 0 },
638                 { 0, 0, 0, 0, 0 }
639         }
640 };
641
642 int cmd_subvolume(int argc, char **argv)
643 {
644         return handle_command_group(&subvolume_cmd_group, argc, argv);
645 }