05134fd6d6954297e851207e828f59cd22ba74e0
[platform/upstream/btrfs-progs.git] / btrfs_cmds.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
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <libgen.h>
28 #include <limits.h>
29 #include <uuid/uuid.h>
30 #include <ctype.h>
31
32 #undef ULONG_MAX
33
34 #include "kerncompat.h"
35 #include "ctree.h"
36 #include "transaction.h"
37 #include "utils.h"
38 #include "version.h"
39 #include "ioctl.h"
40 #include "volumes.h"
41
42 #include "btrfs_cmds.h"
43
44 #ifdef __CHECKER__
45 #define BLKGETSIZE64 0
46 #define BTRFS_IOC_SNAP_CREATE 0
47 #define BTRFS_VOL_NAME_MAX 255
48 struct btrfs_ioctl_vol_args { char name[BTRFS_VOL_NAME_MAX]; };
49 static inline int ioctl(int fd, int define, void *arg) { return 0; }
50 #endif
51
52 /*
53  * test if path is a subvolume:
54  * this function return
55  * 0-> path exists but it is not a subvolume
56  * 1-> path exists and it is  a subvolume
57  * -1 -> path is unaccessible
58  */
59 static int test_issubvolume(char *path)
60 {
61
62         struct stat     st;
63         int             res;
64
65         res = stat(path, &st);
66         if(res < 0 )
67                 return -1;
68
69         return (st.st_ino == 256) && S_ISDIR(st.st_mode);
70
71 }
72
73 /*
74  * test if path is a directory
75  * this function return
76  * 0-> path exists but it is not a directory
77  * 1-> path exists and it is  a directory
78  * -1 -> path is unaccessible
79  */
80 static int test_isdir(char *path)
81 {
82         struct stat     st;
83         int             res;
84
85         res = stat(path, &st);
86         if(res < 0 )
87                 return -1;
88
89         return S_ISDIR(st.st_mode);
90
91 }
92
93 static int open_file_or_dir(const char *fname)
94 {
95         int ret;
96         struct stat st;
97         DIR *dirstream;
98         int fd;
99
100         ret = stat(fname, &st);
101         if (ret < 0) {
102                 return -1;
103         }
104         if (S_ISDIR(st.st_mode)) {
105                 dirstream = opendir(fname);
106                 if (!dirstream) {
107                         return -2;
108                 }
109                 fd = dirfd(dirstream);
110         } else {
111                 fd = open(fname, O_RDWR);
112         }
113         if (fd < 0) {
114                 return -3;
115         }
116         return fd;
117 }
118
119 static u64 parse_size(char *s)
120 {
121         int len = strlen(s);
122         char c;
123         u64 mult = 1;
124
125         if (!isdigit(s[len - 1])) {
126                 c = tolower(s[len - 1]);
127                 switch (c) {
128                 case 'g':
129                         mult *= 1024;
130                 case 'm':
131                         mult *= 1024;
132                 case 'k':
133                         mult *= 1024;
134                 case 'b':
135                         break;
136                 default:
137                         fprintf(stderr, "Unknown size descriptor %c\n", c);
138                         exit(1);
139                 }
140                 s[len - 1] = '\0';
141         }
142         return atoll(s) * mult;
143 }
144
145 int do_defrag(int ac, char **av)
146 {
147         int fd;
148         int compress = 0;
149         int flush = 0;
150         u64 start = 0;
151         u64 len = (u64)-1;
152         u32 thresh = 0;
153         int i;
154         int errors = 0;
155         int ret = 0;
156         int verbose = 0;
157         int fancy_ioctl = 0;
158         struct btrfs_ioctl_defrag_range_args range;
159
160         optind = 1;
161         while(1) {
162                 int c = getopt(ac, av, "vcfs:l:t:");
163                 if (c < 0)
164                         break;
165                 switch(c) {
166                 case 'c':
167                         compress = 1;
168                         fancy_ioctl = 1;
169                         break;
170                 case 'f':
171                         flush = 1;
172                         fancy_ioctl = 1;
173                         break;
174                 case 'v':
175                         verbose = 1;
176                         break;
177                 case 's':
178                         start = parse_size(optarg);
179                         fancy_ioctl = 1;
180                         break;
181                 case 'l':
182                         len = parse_size(optarg);
183                         fancy_ioctl = 1;
184                         break;
185                 case 't':
186                         thresh = parse_size(optarg);
187                         fancy_ioctl = 1;
188                         break;
189                 default:
190                         fprintf(stderr, "Invalid arguments for defragment\n");
191                         free(av);
192                         return 1;
193                 }
194         }
195         if (ac - optind == 0) {
196                 fprintf(stderr, "Invalid arguments for defragment\n");
197                 free(av);
198                 return 1;
199         }
200
201         memset(&range, 0, sizeof(range));
202         range.start = start;
203         range.len = len;
204         range.extent_thresh = thresh;
205         if (compress)
206                 range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
207         if (flush)
208                 range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
209
210         for (i = optind; i < ac; i++) {
211                 if (verbose)
212                         printf("%s\n", av[i]);
213                 fd = open_file_or_dir(av[i]);
214                 if (fd < 0) {
215                         fprintf(stderr, "failed to open %s\n", av[i]);
216                         perror("open:");
217                         errors++;
218                         continue;
219                 }
220                 if (!fancy_ioctl) {
221                         ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL);
222                 } else {
223                         ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &range);
224                         if (ret && errno == ENOTTY) {
225                                 fprintf(stderr, "defrag range ioctl not "
226                                         "supported in this kernel, please try "
227                                         "without any options.\n");
228                                 errors++;
229                                 break;
230                         }
231                 }
232                 if (ret) {
233                         fprintf(stderr, "ioctl failed on %s ret %d errno %d\n",
234                                 av[i], ret, errno);
235                         errors++;
236                 }
237                 close(fd);
238         }
239         if (verbose)
240                 printf("%s\n", BTRFS_BUILD_VERSION);
241         if (errors) {
242                 fprintf(stderr, "total %d failures\n", errors);
243                 exit(1);
244         }
245
246         free(av);
247         return errors + 20;
248 }
249
250 int do_subvol_list(int argc, char **argv)
251 {
252         int fd;
253         int ret;
254         char *subvol;
255
256         subvol = argv[1];
257
258         ret = test_issubvolume(subvol);
259         if (ret < 0) {
260                 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
261                 return 12;
262         }
263         if (!ret) {
264                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
265                 return 13;
266         }
267
268         fd = open_file_or_dir(subvol);
269         if (fd < 0) {
270                 fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
271                 return 12;
272         }
273         ret = list_subvols(fd);
274         if (ret)
275                 return 19;
276         return 0;
277 }
278
279 int do_clone(int argc, char **argv)
280 {
281         char    *subvol, *dst;
282         int     res, fd, fddst, len;
283         char    *newname;
284         char    *dstdir;
285
286         subvol = argv[1];
287         dst = argv[2];
288         struct btrfs_ioctl_vol_args     args;
289
290         res = test_issubvolume(subvol);
291         if(res<0){
292                 fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
293                 return 12;
294         }
295         if(!res){
296                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
297                 return 13;
298         }
299
300         res = test_isdir(dst);
301         if(res == 0 ){
302                 fprintf(stderr, "ERROR: '%s' exists and it is not a directory\n", dst);
303                 return 12;
304         }
305
306         if(res>0){
307                 newname = strdup(subvol);
308                 newname = basename(newname);
309                 dstdir = dst;
310         }else{
311                 newname = strdup(dst);
312                 newname = basename(newname);
313                 dstdir = strdup(dst);
314                 dstdir = dirname(dstdir);
315         }
316
317         if( !strcmp(newname,".") || !strcmp(newname,"..") ||
318              strchr(newname, '/') ){
319                 fprintf(stderr, "ERROR: incorrect snapshot name ('%s')\n",
320                         newname);
321                 return 14;
322         }
323
324         len = strlen(newname);
325         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
326                 fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
327                         newname);
328                 return 14;
329         }
330
331         fddst = open_file_or_dir(dstdir);
332         if (fddst < 0) {
333                 fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
334                 return 12;
335         }
336
337         fd = open_file_or_dir(subvol);
338         if (fd < 0) {
339                 close(fddst);
340                 fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
341                 return 12;
342         }
343
344         printf("Create a snapshot of '%s' in '%s/%s'\n",
345                subvol, dstdir, newname);
346         args.fd = fd;
347         strcpy(args.name, newname);
348         res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args);
349
350         close(fd);
351         close(fddst);
352
353         if(res < 0 ){
354                 fprintf( stderr, "ERROR: cannot snapshot '%s'\n",subvol);
355                 return 11;
356         }
357
358         return 0;
359
360 }
361
362 int do_delete_subvolume(int argc, char **argv)
363 {
364         int     res, fd, len;
365         struct btrfs_ioctl_vol_args     args;
366         char    *dname, *vname, *cpath;
367         char    *path = argv[1];
368
369         res = test_issubvolume(path);
370         if(res<0){
371                 fprintf(stderr, "ERROR: error accessing '%s'\n", path);
372                 return 12;
373         }
374         if(!res){
375                 fprintf(stderr, "ERROR: '%s' is not a subvolume\n", path);
376                 return 13;
377         }
378
379         cpath = realpath(path, 0);
380         dname = strdup(cpath);
381         dname = dirname(dname);
382         vname = strdup(cpath);
383         vname = basename(vname);
384         free(cpath);
385
386         if( !strcmp(vname,".") || !strcmp(vname,"..") ||
387              strchr(vname, '/') ){
388                 fprintf(stderr, "ERROR: incorrect subvolume name ('%s')\n",
389                         vname);
390                 return 14;
391         }
392
393         len = strlen(vname);
394         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
395                 fprintf(stderr, "ERROR: snapshot name too long ('%s)\n",
396                         vname);
397                 return 14;
398         }
399
400         fd = open_file_or_dir(dname);
401         if (fd < 0) {
402                 close(fd);
403                 fprintf(stderr, "ERROR: can't access to '%s'\n", dname);
404                 return 12;
405         }
406
407         printf("Delete subvolume '%s/%s'\n", dname, vname);
408         strcpy(args.name, vname);
409         res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
410
411         close(fd);
412
413         if(res < 0 ){
414                 fprintf( stderr, "ERROR: cannot delete '%s/%s'\n",dname, vname);
415                 return 11;
416         }
417
418         return 0;
419
420 }
421
422 int do_create_subvol(int argc, char **argv)
423 {
424         int     res, fddst, len;
425         char    *newname;
426         char    *dstdir;
427         struct btrfs_ioctl_vol_args     args;
428         char    *dst = argv[1];
429
430         res = test_isdir(dst);
431         if(res >= 0 ){
432                 fprintf(stderr, "ERROR: '%s' exists\n", dst);
433                 return 12;
434         }
435
436         newname = strdup(dst);
437         newname = basename(newname);
438         dstdir = strdup(dst);
439         dstdir = dirname(dstdir);
440
441         if( !strcmp(newname,".") || !strcmp(newname,"..") ||
442              strchr(newname, '/') ){
443                 fprintf(stderr, "ERROR: uncorrect subvolume name ('%s')\n",
444                         newname);
445                 return 14;
446         }
447
448         len = strlen(newname);
449         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
450                 fprintf(stderr, "ERROR: subvolume name too long ('%s)\n",
451                         newname);
452                 return 14;
453         }
454
455         fddst = open_file_or_dir(dstdir);
456         if (fddst < 0) {
457                 fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
458                 return 12;
459         }
460
461         printf("Create subvolume '%s/%s'\n", dstdir, newname);
462         strcpy(args.name, newname);
463         res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
464
465         close(fddst);
466
467         if(res < 0 ){
468                 fprintf( stderr, "ERROR: cannot create subvolume\n");
469                 return 11;
470         }
471
472         return 0;
473
474 }
475
476 int do_fssync(int argc, char **argv)
477 {
478         int fd, res;
479         char    *path = argv[1];
480
481         fd = open_file_or_dir(path);
482         if (fd < 0) {
483                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
484                 return 12;
485         }
486
487         printf("FSSync '%s'\n", path);
488         res = ioctl(fd, BTRFS_IOC_SYNC);
489         close(fd);
490         if( res < 0 ){
491                 fprintf(stderr, "ERROR: unable to fs-syncing '%s'\n", path);
492                 return 16;
493         }
494
495         return 0;
496 }
497
498 int do_scan(int argc, char **argv)
499 {
500         int     i, fd;
501         if(argc<=1){
502                 int ret;
503
504                 printf("Scanning for Btrfs filesystems\n");
505                 ret = btrfs_scan_one_dir("/dev", 1);
506                 if (ret){
507                         fprintf(stderr, "ERROR: error %d while scanning\n", ret);
508                         return 18;
509                 }
510                 return 0;
511         }
512
513         fd = open("/dev/btrfs-control", O_RDWR);
514         if (fd < 0) {
515                 perror("failed to open /dev/btrfs-control");
516                 return 10;
517         }
518
519         for( i = 1 ; i < argc ; i++ ){
520                 struct btrfs_ioctl_vol_args args;
521                 int ret;
522
523                 printf("Scanning for Btrfs filesystems in '%s'\n", argv[i]);
524
525                 strcpy(args.name, argv[i]);
526                 /*
527                  * FIXME: which are the error code returned by this ioctl ?
528                  * it seems that is impossible to understand if there no is
529                  * a btrfs filesystem from an I/O error !!!
530                  */
531                 ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args);
532
533                 if( ret < 0 ){
534                         close(fd);
535                         fprintf(stderr, "ERROR: unable to scan the device '%s'\n", argv[i]);
536                         return 11;
537                 }
538         }
539
540         close(fd);
541         return 0;
542
543 }
544
545 int do_resize(int argc, char **argv)
546 {
547
548         struct btrfs_ioctl_vol_args     args;
549         int     fd, res, len;
550         char    *amount=argv[1], *path=argv[2];
551
552         fd = open_file_or_dir(path);
553         if (fd < 0) {
554                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
555                 return 12;
556         }
557         len = strlen(amount);
558         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
559                 fprintf(stderr, "ERROR: size value too long ('%s)\n",
560                         amount);
561                 return 14;
562         }
563
564         printf("Resize '%s' of '%s'\n", path, amount);
565         strcpy(args.name, amount);
566         res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
567         close(fd);
568         if( res < 0 ){
569                 fprintf(stderr, "ERROR: unable to resize '%s'\n", path);
570                 return 30;
571         }
572         return 0;
573 }
574
575 static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search)
576 {
577         struct list_head *cur;
578         struct btrfs_device *device;
579
580         list_for_each(cur, &fs_devices->devices) {
581                 device = list_entry(cur, struct btrfs_device, dev_list);
582                 if ((device->label && strcmp(device->label, search) == 0) ||
583                     strcmp(device->name, search) == 0)
584                         return 1;
585         }
586         return 0;
587 }
588
589 static void print_one_uuid(struct btrfs_fs_devices *fs_devices)
590 {
591         char uuidbuf[37];
592         struct list_head *cur;
593         struct btrfs_device *device;
594         char *super_bytes_used;
595         u64 devs_found = 0;
596         u64 total;
597
598         uuid_unparse(fs_devices->fsid, uuidbuf);
599         device = list_entry(fs_devices->devices.next, struct btrfs_device,
600                             dev_list);
601         if (device->label && device->label[0])
602                 printf("Label: '%s' ", device->label);
603         else
604                 printf("Label: none ");
605
606         super_bytes_used = pretty_sizes(device->super_bytes_used);
607
608         total = device->total_devs;
609         printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf,
610                (unsigned long long)total, super_bytes_used);
611
612         free(super_bytes_used);
613
614         list_for_each(cur, &fs_devices->devices) {
615                 char *total_bytes;
616                 char *bytes_used;
617                 device = list_entry(cur, struct btrfs_device, dev_list);
618                 total_bytes = pretty_sizes(device->total_bytes);
619                 bytes_used = pretty_sizes(device->bytes_used);
620                 printf("\tdevid %4llu size %s used %s path %s\n",
621                        (unsigned long long)device->devid,
622                        total_bytes, bytes_used, device->name);
623                 free(total_bytes);
624                 free(bytes_used);
625                 devs_found++;
626         }
627         if (devs_found < total) {
628                 printf("\t*** Some devices missing\n");
629         }
630         printf("\n");
631 }
632
633 int do_show_filesystem(int argc, char **argv)
634 {
635         struct list_head *all_uuids;
636         struct btrfs_fs_devices *fs_devices;
637         struct list_head *cur_uuid;
638         char *search = argv[1];
639         int ret;
640
641         ret = btrfs_scan_one_dir("/dev", 0);
642         if (ret){
643                 fprintf(stderr, "ERROR: error %d while scanning\n", ret);
644                 return 18;
645         }
646
647         all_uuids = btrfs_scanned_uuids();
648         list_for_each(cur_uuid, all_uuids) {
649                 fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices,
650                                         list);
651                 if (search && uuid_search(fs_devices, search) == 0)
652                         continue;
653                 print_one_uuid(fs_devices);
654         }
655         printf("%s\n", BTRFS_BUILD_VERSION);
656         return 0;
657 }
658
659 int do_add_volume(int nargs, char **args)
660 {
661
662         char    *mntpnt = args[nargs-1];
663         int     i, fdmnt, ret=0;
664
665
666         fdmnt = open_file_or_dir(mntpnt);
667         if (fdmnt < 0) {
668                 fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt);
669                 return 12;
670         }
671
672         for(i=1 ; i < (nargs-1) ; i++ ){
673                 struct btrfs_ioctl_vol_args ioctl_args;
674                 int     devfd, res;
675                 u64 dev_block_count = 0;
676                 struct stat st;
677
678                 devfd = open(args[i], O_RDWR);
679                 if (!devfd) {
680                         fprintf(stderr, "ERROR: Unable to open device '%s'\n", args[i]);
681                         close(devfd);
682                         ret++;
683                         continue;
684                 }
685                 ret = fstat(devfd, &st);
686                 if (ret) {
687                         fprintf(stderr, "ERROR: Unable to stat '%s'\n", args[i]);
688                         close(devfd);
689                         ret++;
690                         continue;
691                 }
692                 if (!S_ISBLK(st.st_mode)) {
693                         fprintf(stderr, "ERROR: '%s' is not a block device\n", args[i]);
694                         close(devfd);
695                         ret++;
696                         continue;
697                 }
698
699                 res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count);
700                 if (res) {
701                         fprintf(stderr, "ERROR: Unable to init '%s'\n", args[i]);
702                         close(devfd);
703                         ret++;
704                         continue;
705                 }
706                 close(devfd);
707
708                 strcpy(ioctl_args.name, args[i]);
709                 res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args);
710                 if(res<0){
711                         fprintf(stderr, "ERROR: error adding the device '%s'\n", args[i]);
712                         ret++;
713                 }
714
715         }
716
717         close(fdmnt);
718         if( ret)
719                 return ret+20;
720         else
721                 return 0;
722
723 }
724
725 int do_balance(int argc, char **argv)
726 {
727
728         int     fdmnt, ret=0;
729         struct btrfs_ioctl_vol_args args;
730         char    *path = argv[1];
731
732         fdmnt = open_file_or_dir(path);
733         if (fdmnt < 0) {
734                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
735                 return 12;
736         }
737
738         memset(&args, 0, sizeof(args));
739         ret = ioctl(fdmnt, BTRFS_IOC_BALANCE, &args);
740         close(fdmnt);
741         if(ret<0){
742                 fprintf(stderr, "ERROR: balancing '%s'\n", path);
743
744                 return 19;
745         }
746         return 0;
747 }
748 int do_remove_volume(int nargs, char **args)
749 {
750
751         char    *mntpnt = args[nargs-1];
752         int     i, fdmnt, ret=0;
753
754         fdmnt = open_file_or_dir(mntpnt);
755         if (fdmnt < 0) {
756                 fprintf(stderr, "ERROR: can't access to '%s'\n", mntpnt);
757                 return 12;
758         }
759
760         for(i=1 ; i < (nargs-1) ; i++ ){
761                 struct  btrfs_ioctl_vol_args arg;
762                 int     res;
763
764                 strcpy(arg.name, args[i]);
765                 res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg);
766                 if(res<0){
767                         fprintf(stderr, "ERROR: error removing the device '%s'\n", args[i]);
768                         ret++;
769                 }
770         }
771
772         close(fdmnt);
773         if( ret)
774                 return ret+20;
775         else
776                 return 0;
777 }
778
779 int do_set_default_subvol(int nargs, char **argv)
780 {
781         int     ret=0, fd;
782         u64     objectid;
783         char    *path = argv[2];
784         char    *subvolid = argv[1];
785
786         fd = open_file_or_dir(path);
787         if (fd < 0) {
788                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
789                 return 12;
790         }
791
792         objectid = (unsigned long long)strtoll(subvolid, NULL, 0);
793         if (errno == ERANGE) {
794                 fprintf(stderr, "ERROR: invalid tree id (%s)\n",subvolid);
795                 return 30;
796         }
797         ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
798         close(fd);
799         if( ret < 0 ){
800                 fprintf(stderr, "ERROR: unable to set a new default subvolume\n");
801                 return 30;
802         }
803         return 0;
804 }
805
806 int do_df_filesystem(int nargs, char **argv)
807 {
808         struct btrfs_ioctl_space_args *sargs;
809         u64 count = 0, i;
810         int ret;
811         int fd;
812         char *path = argv[1];
813
814         fd = open_file_or_dir(path);
815         if (fd < 0) {
816                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
817                 return 12;
818         }
819
820         sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
821         if (!sargs)
822                 return -ENOMEM;
823
824         sargs->space_slots = 0;
825         sargs->total_spaces = 0;
826
827         ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
828         if (ret) {
829                 free(sargs);
830                 return ret;
831         }
832         if (!sargs->total_spaces)
833                 return 0;
834
835         count = sargs->total_spaces;
836
837         sargs = realloc(sargs, sizeof(struct btrfs_ioctl_space_args) +
838                         (count * sizeof(struct btrfs_ioctl_space_info)));
839         if (!sargs)
840                 return -ENOMEM;
841
842         sargs->space_slots = count;
843         sargs->total_spaces = 0;
844
845         ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
846         if (ret) {
847                 free(sargs);
848                 return ret;
849         }
850
851         for (i = 0; i < sargs->total_spaces; i++) {
852                 char description[80];
853                 char *total_bytes;
854                 char *used_bytes;
855                 int written = 0;
856                 u64 flags = sargs->spaces[i].flags;
857
858                 memset(description, 0, 80);
859
860                 if (flags & BTRFS_BLOCK_GROUP_DATA) {
861                         snprintf(description, 5, "%s", "Data");
862                         written += 4;
863                 } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) {
864                         snprintf(description, 7, "%s", "System");
865                         written += 6;
866                 } else if (flags & BTRFS_BLOCK_GROUP_METADATA) {
867                         snprintf(description, 9, "%s", "Metadata");
868                         written += 8;
869                 }
870
871                 if (flags & BTRFS_BLOCK_GROUP_RAID0) {
872                         snprintf(description+written, 8, "%s", ", RAID0");
873                         written += 7;
874                 } else if (flags & BTRFS_BLOCK_GROUP_RAID1) {
875                         snprintf(description+written, 8, "%s", ", RAID1");
876                         written += 7;
877                 } else if (flags & BTRFS_BLOCK_GROUP_DUP) {
878                         snprintf(description+written, 6, "%s", ", DUP");
879                         written += 5;
880                 } else if (flags & BTRFS_BLOCK_GROUP_RAID10) {
881                         snprintf(description+written, 9, "%s", ", RAID10");
882                         written += 8;
883                 }
884
885                 total_bytes = pretty_sizes(sargs->spaces[i].total_bytes);
886                 used_bytes = pretty_sizes(sargs->spaces[i].used_bytes);
887                 printf("%s: total=%s, used=%s\n", description, total_bytes,
888                        used_bytes);
889         }
890         free(sargs);
891
892         return 0;
893 }