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