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