Btrfs-progs: rearrange files in the repo
[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
30 #include "btrfs_cmds.h"
31
32 /* btrfs-list.c */
33 int list_subvols(int fd, int print_parent, int get_default);
34 int find_updated_files(int fd, u64 root_id, u64 oldest_gen);
35
36 /*
37  * test if path is a directory
38  * this function return
39  * 0-> path exists but it is not a directory
40  * 1-> path exists and it is  a directory
41  * -1 -> path is unaccessible
42  */
43 static int test_isdir(char *path)
44 {
45         struct stat     st;
46         int             res;
47
48         res = stat(path, &st);
49         if(res < 0 )
50                 return -1;
51
52         return S_ISDIR(st.st_mode);
53 }
54
55 int do_create_subvol(int argc, char **argv)
56 {
57         int     res, fddst, len, e;
58         char    *newname;
59         char    *dstdir;
60         struct btrfs_ioctl_vol_args     args;
61         char    *dst = argv[1];
62
63         res = test_isdir(dst);
64         if(res >= 0 ){
65                 fprintf(stderr, "ERROR: '%s' exists\n", dst);
66                 return 12;
67         }
68
69         newname = strdup(dst);
70         newname = basename(newname);
71         dstdir = strdup(dst);
72         dstdir = dirname(dstdir);
73
74         if( !strcmp(newname,".") || !strcmp(newname,"..") ||
75              strchr(newname, '/') ){
76                 fprintf(stderr, "ERROR: uncorrect subvolume name ('%s')\n",
77                         newname);
78                 return 14;
79         }
80
81         len = strlen(newname);
82         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
83                 fprintf(stderr, "ERROR: subvolume name too long ('%s)\n",
84                         newname);
85                 return 14;
86         }
87
88         fddst = open_file_or_dir(dstdir);
89         if (fddst < 0) {
90                 fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
91                 return 12;
92         }
93
94         printf("Create subvolume '%s/%s'\n", dstdir, newname);
95         strncpy(args.name, newname, BTRFS_PATH_NAME_MAX);
96         res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
97         e = errno;
98
99         close(fddst);
100
101         if(res < 0 ){
102                 fprintf( stderr, "ERROR: cannot create subvolume - %s\n",
103                         strerror(e));
104                 return 11;
105         }
106
107         return 0;
108
109 }
110
111 /*
112  * test if path is a subvolume:
113  * this function return
114  * 0-> path exists but it is not a subvolume
115  * 1-> path exists and it is  a subvolume
116  * -1 -> path is unaccessible
117  */
118 static int test_issubvolume(char *path)
119 {
120         struct stat     st;
121         int             res;
122
123         res = stat(path, &st);
124         if(res < 0 )
125                 return -1;
126
127         return (st.st_ino == 256) && S_ISDIR(st.st_mode);
128 }
129
130 int do_delete_subvolume(int argc, char **argv)
131 {
132         int     res, fd, len, e;
133         struct btrfs_ioctl_vol_args     args;
134         char    *dname, *vname, *cpath;
135         char    *path = argv[1];
136
137         res = test_issubvolume(path);
138         if(res<0){
139                 fprintf(stderr, "ERROR: error accessing '%s'\n", path);
140                 return 12;
141         }
142         if(!res){
143                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", path);
144                 return 13;
145         }
146
147         cpath = realpath(path, 0);
148         dname = strdup(cpath);
149         dname = dirname(dname);
150         vname = strdup(cpath);
151         vname = basename(vname);
152         free(cpath);
153
154         if( !strcmp(vname,".") || !strcmp(vname,"..") ||
155              strchr(vname, '/') ){
156                 fprintf(stderr, "ERROR: incorrect subvolume name ('%s')\n",
157                         vname);
158                 return 14;
159         }
160
161         len = strlen(vname);
162         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
163                 fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
164                         vname);
165                 return 14;
166         }
167
168         fd = open_file_or_dir(dname);
169         if (fd < 0) {
170                 close(fd);
171                 fprintf(stderr, "ERROR: can't access to '%s'\n", dname);
172                 return 12;
173         }
174
175         printf("Delete subvolume '%s/%s'\n", dname, vname);
176         strncpy(args.name, vname, BTRFS_PATH_NAME_MAX);
177         res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
178         e = errno;
179
180         close(fd);
181
182         if(res < 0 ){
183                 fprintf( stderr, "ERROR: cannot delete '%s/%s' - %s\n",
184                         dname, vname, strerror(e));
185                 return 11;
186         }
187
188         return 0;
189
190 }
191
192 int do_subvol_list(int argc, char **argv)
193 {
194         int fd;
195         int ret;
196         int print_parent = 0;
197         char *subvol;
198         int optind = 1;
199
200         while(1) {
201                 int c = getopt(argc, argv, "p");
202                 if (c < 0) break;
203                 switch(c) {
204                 case 'p':
205                         print_parent = 1;
206                         optind++;
207                         break;
208                 }
209         }
210         
211         if (argc - optind != 1) {
212                 fprintf(stderr, "ERROR: invalid arguments for subvolume list\n");
213                 return 1;
214         }
215
216         subvol = argv[optind];
217
218         ret = test_issubvolume(subvol);
219         if (ret < 0) {
220                 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
221                 return 12;
222         }
223         if (!ret) {
224                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
225                 return 13;
226         }
227
228         fd = open_file_or_dir(subvol);
229         if (fd < 0) {
230                 fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
231                 return 12;
232         }
233         ret = list_subvols(fd, print_parent, 0);
234         if (ret)
235                 return 19;
236         return 0;
237 }
238
239 int do_clone(int argc, char **argv)
240 {
241         char    *subvol, *dst;
242         int     res, fd, fddst, len, e, optind = 0, readonly = 0;
243         char    *newname;
244         char    *dstdir;
245         struct btrfs_ioctl_vol_args_v2  args;
246
247         memset(&args, 0, sizeof(args));
248
249         while (1) {
250                 int c = getopt(argc, argv, "r");
251
252                 if (c < 0)
253                         break;
254                 switch (c) {
255                 case 'r':
256                         optind++;
257                         readonly = 1;
258                         break;
259                 default:
260                         fprintf(stderr,
261                                 "Invalid arguments for subvolume snapshot\n");
262                         free(argv);
263                         return 1;
264                 }
265         }
266         if (argc - optind != 3) {
267                 fprintf(stderr, "Invalid arguments for subvolume snapshot\n");
268                 free(argv);
269                 return 1;
270         }
271
272         subvol = argv[optind+1];
273         dst = argv[optind+2];
274
275         res = test_issubvolume(subvol);
276         if(res<0){
277                 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
278                 return 12;
279         }
280         if(!res){
281                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
282                 return 13;
283         }
284
285         res = test_isdir(dst);
286         if(res == 0 ){
287                 fprintf(stderr, "ERROR: '%s' exists and it is not a directory\n", dst);
288                 return 12;
289         }
290
291         if(res>0){
292                 newname = strdup(subvol);
293                 newname = basename(newname);
294                 dstdir = dst;
295         }else{
296                 newname = strdup(dst);
297                 newname = basename(newname);
298                 dstdir = strdup(dst);
299                 dstdir = dirname(dstdir);
300         }
301
302         if( !strcmp(newname,".") || !strcmp(newname,"..") ||
303              strchr(newname, '/') ){
304                 fprintf(stderr, "ERROR: incorrect snapshot name ('%s')\n",
305                         newname);
306                 return 14;
307         }
308
309         len = strlen(newname);
310         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
311                 fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
312                         newname);
313                 return 14;
314         }
315
316         fddst = open_file_or_dir(dstdir);
317         if (fddst < 0) {
318                 fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
319                 return 12;
320         }
321
322         fd = open_file_or_dir(subvol);
323         if (fd < 0) {
324                 close(fddst);
325                 fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
326                 return 12;
327         }
328
329         if (readonly) {
330                 args.flags |= BTRFS_SUBVOL_RDONLY;
331                 printf("Create a readonly snapshot of '%s' in '%s/%s'\n",
332                        subvol, dstdir, newname);
333         } else {
334                 printf("Create a snapshot of '%s' in '%s/%s'\n",
335                        subvol, dstdir, newname);
336         }
337
338         args.fd = fd;
339         strncpy(args.name, newname, BTRFS_SUBVOL_NAME_MAX);
340         res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);
341         e = errno;
342
343         close(fd);
344         close(fddst);
345
346         if(res < 0 ){
347                 fprintf( stderr, "ERROR: cannot snapshot '%s' - %s\n",
348                         subvol, strerror(e));
349                 return 11;
350         }
351
352         return 0;
353
354 }
355
356 int do_get_default_subvol(int nargs, char **argv)
357 {
358         int fd;
359         int ret;
360         char *subvol;
361
362         subvol = argv[1];
363
364         ret = test_issubvolume(subvol);
365         if (ret < 0) {
366                 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
367                 return 12;
368         }
369         if (!ret) {
370                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
371                 return 13;
372         }
373
374         fd = open_file_or_dir(subvol);
375         if (fd < 0) {
376                 fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
377                 return 12;
378         }
379         ret = list_subvols(fd, 0, 1);
380         if (ret)
381                 return 19;
382         return 0;
383 }
384
385 int do_set_default_subvol(int nargs, char **argv)
386 {
387         int     ret=0, fd, e;
388         u64     objectid;
389         char    *path = argv[2];
390         char    *subvolid = argv[1];
391
392         fd = open_file_or_dir(path);
393         if (fd < 0) {
394                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
395                 return 12;
396         }
397
398         objectid = (unsigned long long)strtoll(subvolid, NULL, 0);
399         if (errno == ERANGE) {
400                 fprintf(stderr, "ERROR: invalid tree id (%s)\n",subvolid);
401                 return 30;
402         }
403         ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
404         e = errno;
405         close(fd);
406         if( ret < 0 ){
407                 fprintf(stderr, "ERROR: unable to set a new default subvolume - %s\n",
408                         strerror(e));
409                 return 30;
410         }
411         return 0;
412 }
413
414 int do_find_newer(int argc, char **argv)
415 {
416         int fd;
417         int ret;
418         char *subvol;
419         u64 last_gen;
420
421         subvol = argv[1];
422         last_gen = atoll(argv[2]);
423
424         ret = test_issubvolume(subvol);
425         if (ret < 0) {
426                 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
427                 return 12;
428         }
429         if (!ret) {
430                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
431                 return 13;
432         }
433
434         fd = open_file_or_dir(subvol);
435         if (fd < 0) {
436                 fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
437                 return 12;
438         }
439         ret = find_updated_files(fd, 0, last_gen);
440         if (ret)
441                 return 19;
442         return 0;
443 }
444