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