btrfs-progs: pass positive errno to strerror in cmd_df()
[platform/upstream/btrfs-progs.git] / cmds-filesystem.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 #define _XOPEN_SOURCE 500
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/ioctl.h>
23 #include <errno.h>
24 #include <uuid/uuid.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <ftw.h>
28 #include <mntent.h>
29 #include <linux/limits.h>
30 #include <getopt.h>
31
32 #include "kerncompat.h"
33 #include "ctree.h"
34 #include "ioctl.h"
35 #include "utils.h"
36 #include "volumes.h"
37 #include "version.h"
38 #include "commands.h"
39 #include "list_sort.h"
40
41 static const char * const filesystem_cmd_group_usage[] = {
42         "btrfs filesystem [<group>] <command> [<args>]",
43         NULL
44 };
45
46 static const char * const cmd_df_usage[] = {
47         "btrfs filesystem df <path>",
48         "Show space usage information for a mount point",
49         NULL
50 };
51
52 static char *group_type_str(u64 flag)
53 {
54         switch (flag & BTRFS_BLOCK_GROUP_TYPE_MASK) {
55         case BTRFS_BLOCK_GROUP_DATA:
56                 return "Data";
57         case BTRFS_BLOCK_GROUP_SYSTEM:
58                 return "System";
59         case BTRFS_BLOCK_GROUP_METADATA:
60                 return "Metadata";
61         case BTRFS_BLOCK_GROUP_DATA|BTRFS_BLOCK_GROUP_METADATA:
62                 return "Data+Metadata";
63         default:
64                 return "unknown";
65         }
66 }
67
68 static char *group_profile_str(u64 flag)
69 {
70         switch (flag & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
71         case 0:
72                 return "single";
73         case BTRFS_BLOCK_GROUP_RAID0:
74                 return "RAID0";
75         case BTRFS_BLOCK_GROUP_RAID1:
76                 return "RAID1";
77         case BTRFS_BLOCK_GROUP_RAID5:
78                 return "RAID5";
79         case BTRFS_BLOCK_GROUP_RAID6:
80                 return "RAID6";
81         case BTRFS_BLOCK_GROUP_DUP:
82                 return "DUP";
83         case BTRFS_BLOCK_GROUP_RAID10:
84                 return "RAID10";
85         default:
86                 return "unknown";
87         }
88 }
89
90 static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret)
91 {
92         u64 count = 0;
93         int ret, e;
94         struct btrfs_ioctl_space_args *sargs;
95
96         sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
97         if (!sargs)
98                 return -ENOMEM;
99
100         sargs->space_slots = 0;
101         sargs->total_spaces = 0;
102
103         ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
104         e = errno;
105         if (ret) {
106                 fprintf(stderr, "ERROR: couldn't get space info - %s\n",
107                         strerror(e));
108                 free(sargs);
109                 return -e;
110         }
111         /* This really should never happen */
112         if (!sargs->total_spaces) {
113                 free(sargs);
114                 return -ENOENT;
115         }
116         count = sargs->total_spaces;
117         free(sargs);
118
119         sargs = malloc(sizeof(struct btrfs_ioctl_space_args) +
120                         (count * sizeof(struct btrfs_ioctl_space_info)));
121         if (!sargs)
122                 ret = -ENOMEM;
123
124         sargs->space_slots = count;
125         sargs->total_spaces = 0;
126         ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
127         e = errno;
128         if (ret) {
129                 fprintf(stderr, "ERROR: get space info count %llu - %s\n",
130                                 count, strerror(e));
131                 free(sargs);
132                 return -e;
133         }
134         *sargs_ret = sargs;
135         return 0;
136 }
137
138 static void print_df(struct btrfs_ioctl_space_args *sargs)
139 {
140         u64 i;
141         struct btrfs_ioctl_space_info *sp = sargs->spaces;
142
143         for (i = 0; i < sargs->total_spaces; i++, sp++) {
144                 printf("%s, %s: total=%s, used=%s\n",
145                         group_type_str(sp->flags),
146                         group_profile_str(sp->flags),
147                         pretty_size(sp->total_bytes),
148                         pretty_size(sp->used_bytes));
149         }
150 }
151
152 static int cmd_df(int argc, char **argv)
153 {
154         struct btrfs_ioctl_space_args *sargs = NULL;
155         int ret;
156         int fd;
157         char *path;
158         DIR  *dirstream = NULL;
159
160         if (check_argc_exact(argc, 2))
161                 usage(cmd_df_usage);
162
163         path = argv[1];
164
165         fd = open_file_or_dir(path, &dirstream);
166         if (fd < 0) {
167                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
168                 return 1;
169         }
170         ret = get_df(fd, &sargs);
171
172         if (!ret && sargs) {
173                 print_df(sargs);
174                 free(sargs);
175         } else {
176                 fprintf(stderr, "ERROR: get_df failed %s\n", strerror(-ret));
177         }
178
179         close_file_or_dir(fd, dirstream);
180         return !!ret;
181 }
182
183 static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search)
184 {
185         char uuidbuf[37];
186         struct list_head *cur;
187         struct btrfs_device *device;
188         int search_len = strlen(search);
189
190         search_len = min(search_len, 37);
191         uuid_unparse(fs_devices->fsid, uuidbuf);
192         if (!strncmp(uuidbuf, search, search_len))
193                 return 1;
194
195         list_for_each(cur, &fs_devices->devices) {
196                 device = list_entry(cur, struct btrfs_device, dev_list);
197                 if ((device->label && strcmp(device->label, search) == 0) ||
198                     strcmp(device->name, search) == 0)
199                         return 1;
200         }
201         return 0;
202 }
203
204 /*
205  * Sort devices by devid, ascending
206  */
207 static int cmp_device_id(void *priv, struct list_head *a,
208                 struct list_head *b)
209 {
210         const struct btrfs_device *da = list_entry(a, struct btrfs_device,
211                         dev_list);
212         const struct btrfs_device *db = list_entry(b, struct btrfs_device,
213                         dev_list);
214
215         return da->devid < db->devid ? -1 :
216                 da->devid > db->devid ? 1 : 0;
217 }
218
219 static void print_one_uuid(struct btrfs_fs_devices *fs_devices)
220 {
221         char uuidbuf[37];
222         struct list_head *cur;
223         struct btrfs_device *device;
224         u64 devs_found = 0;
225         u64 total;
226
227         uuid_unparse(fs_devices->fsid, uuidbuf);
228         device = list_entry(fs_devices->devices.next, struct btrfs_device,
229                             dev_list);
230         if (device->label && device->label[0])
231                 printf("Label: '%s' ", device->label);
232         else
233                 printf("Label: none ");
234
235
236         total = device->total_devs;
237         printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf,
238                (unsigned long long)total,
239                pretty_size(device->super_bytes_used));
240
241         list_sort(NULL, &fs_devices->devices, cmp_device_id);
242         list_for_each(cur, &fs_devices->devices) {
243                 device = list_entry(cur, struct btrfs_device, dev_list);
244
245                 printf("\tdevid %4llu size %s used %s path %s\n",
246                        (unsigned long long)device->devid,
247                        pretty_size(device->total_bytes),
248                        pretty_size(device->bytes_used), device->name);
249
250                 devs_found++;
251         }
252         if (devs_found < total) {
253                 printf("\t*** Some devices missing\n");
254         }
255         printf("\n");
256 }
257
258 /* adds up all the used spaces as reported by the space info ioctl
259  */
260 static u64 calc_used_bytes(struct btrfs_ioctl_space_args *si)
261 {
262         u64 ret = 0;
263         int i;
264         for (i = 0; i < si->total_spaces; i++)
265                 ret += si->spaces[i].used_bytes;
266         return ret;
267 }
268
269 static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
270                 struct btrfs_ioctl_dev_info_args *dev_info,
271                 struct btrfs_ioctl_space_args *space_info,
272                 char *label, char *path)
273 {
274         int i;
275         char uuidbuf[37];
276         struct btrfs_ioctl_dev_info_args *tmp_dev_info;
277
278         uuid_unparse(fs_info->fsid, uuidbuf);
279         printf("Label: %s  uuid: %s\n",
280                 strlen(label) ? label : "none", uuidbuf);
281
282         printf("\tTotal devices %llu FS bytes used %s\n",
283                                 fs_info->num_devices,
284                         pretty_size(calc_used_bytes(space_info)));
285
286         for (i = 0; i < fs_info->num_devices; i++) {
287                 tmp_dev_info = (struct btrfs_ioctl_dev_info_args *)&dev_info[i];
288                 printf("\tdevid    %llu size %s used %s path %s\n",
289                         tmp_dev_info->devid,
290                         pretty_size(tmp_dev_info->total_bytes),
291                         pretty_size(tmp_dev_info->bytes_used),
292                         tmp_dev_info->path);
293         }
294
295         printf("\n");
296         return 0;
297 }
298
299 /* This function checks if the given input parameter is
300  * an uuid or a path
301  * return -1: some error in the given input
302  * return 0: unknow input
303  * return 1: given input is uuid
304  * return 2: given input is path
305  */
306 static int check_arg_type(char *input)
307 {
308         uuid_t  out;
309         char path[PATH_MAX];
310
311         if (!input)
312                 return BTRFS_ARG_UNKNOWN;
313
314         if (realpath(input, path)) {
315                 if (is_block_device(input) == 1)
316                         return BTRFS_ARG_BLKDEV;
317
318                 if (is_mount_point(input) == 1)
319                         return BTRFS_ARG_MNTPOINT;
320
321                 return BTRFS_ARG_UNKNOWN;
322         }
323
324         if (!uuid_parse(input, out))
325                 return BTRFS_ARG_UUID;
326
327         return BTRFS_ARG_UNKNOWN;
328 }
329
330 static int btrfs_scan_kernel(void *search)
331 {
332         int ret = 0, fd, type;
333         FILE *f;
334         struct mntent *mnt;
335         struct btrfs_ioctl_fs_info_args fs_info_arg;
336         struct btrfs_ioctl_dev_info_args *dev_info_arg = NULL;
337         struct btrfs_ioctl_space_args *space_info_arg;
338         char label[BTRFS_LABEL_SIZE];
339         uuid_t uuid;
340
341         f = setmntent("/proc/self/mounts", "r");
342         if (f == NULL)
343                 return 1;
344
345         type = check_arg_type(search);
346         if (type == BTRFS_ARG_BLKDEV)
347                 return 1;
348
349         while ((mnt = getmntent(f)) != NULL) {
350                 if (strcmp(mnt->mnt_type, "btrfs"))
351                         continue;
352                 ret = get_fs_info(mnt->mnt_dir, &fs_info_arg,
353                                 &dev_info_arg);
354                 if (ret)
355                         return ret;
356
357                 switch (type) {
358                 case BTRFS_ARG_UUID:
359                         ret = uuid_parse(search, uuid);
360                         if (ret)
361                                 return 1;
362                         if (uuid_compare(fs_info_arg.fsid, uuid))
363                                 continue;
364                         break;
365                 case BTRFS_ARG_MNTPOINT:
366                         if (strcmp(search, mnt->mnt_dir))
367                                 continue;
368                         break;
369                 case BTRFS_ARG_UNKNOWN:
370                         break;
371                 }
372
373                 fd = open(mnt->mnt_dir, O_RDONLY);
374                 if ((fd != -1) && !get_df(fd, &space_info_arg)) {
375                         get_label_mounted(mnt->mnt_dir, label);
376                         print_one_fs(&fs_info_arg, dev_info_arg,
377                                         space_info_arg, label, mnt->mnt_dir);
378                         free(space_info_arg);
379                 }
380                 if (fd != -1)
381                         close(fd);
382                 free(dev_info_arg);
383         }
384         return ret;
385 }
386
387 static const char * const cmd_show_usage[] = {
388         "btrfs filesystem show [options|<path>|<uuid>]",
389         "Show the structure of a filesystem",
390         "-d|--all-devices   show only disks under /dev containing btrfs filesystem",
391         "-m|--mounted       show only mounted btrfs",
392         "If no argument is given, structure of all present filesystems is shown.",
393         NULL
394 };
395
396 static int cmd_show(int argc, char **argv)
397 {
398         struct list_head *all_uuids;
399         struct btrfs_fs_devices *fs_devices;
400         struct list_head *cur_uuid;
401         char *search = NULL;
402         int ret;
403         int where = BTRFS_SCAN_LBLKID;
404         int type = 0;
405         char mp[BTRFS_PATH_NAME_MAX + 1];
406
407         while (1) {
408                 int long_index;
409                 static struct option long_options[] = {
410                         { "all-devices", no_argument, NULL, 'd'},
411                         { "mounted", no_argument, NULL, 'm'},
412                         { NULL, no_argument, NULL, 0 },
413                 };
414                 int c = getopt_long(argc, argv, "dm", long_options,
415                                         &long_index);
416                 if (c < 0)
417                         break;
418                 switch (c) {
419                 case 'd':
420                         where = BTRFS_SCAN_DEV;
421                         break;
422                 case 'm':
423                         where = BTRFS_SCAN_MOUNTED;
424                         break;
425                 default:
426                         usage(cmd_show_usage);
427                 }
428         }
429
430         if (where == BTRFS_SCAN_LBLKID) {
431                 if (check_argc_max(argc, optind + 1))
432                         usage(cmd_show_usage);
433         } else {
434                 if (check_argc_max(argc, optind))
435                         usage(cmd_show_usage);
436         }
437         if (argc > optind) {
438                 search = argv[optind];
439                 type = check_arg_type(search);
440                 if (type == BTRFS_ARG_UNKNOWN) {
441                         fprintf(stderr, "ERROR: arg type unknown\n");
442                         usage(cmd_show_usage);
443                 }
444                 if (type == BTRFS_ARG_BLKDEV) {
445                         ret = get_btrfs_mount(search, mp, sizeof(mp));
446                         if (ret == 0)
447                                 search = mp;
448                 }
449         }
450
451         if (where == BTRFS_SCAN_DEV)
452                 goto devs_only;
453
454         /* show mounted btrfs */
455         btrfs_scan_kernel(search);
456
457         /* shows mounted only */
458         if (where == BTRFS_SCAN_MOUNTED)
459                 goto out;
460
461 devs_only:
462         ret = scan_for_btrfs(where, !BTRFS_UPDATE_KERNEL);
463
464         if (ret) {
465                 fprintf(stderr, "ERROR: %d while scanning\n", ret);
466                 return 1;
467         }
468         
469         all_uuids = btrfs_scanned_uuids();
470         list_for_each(cur_uuid, all_uuids) {
471                 fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices,
472                                         list);
473                 if (search && uuid_search(fs_devices, search) == 0)
474                         continue;
475
476                 print_one_uuid(fs_devices);
477         }
478
479 out:
480         printf("%s\n", BTRFS_BUILD_VERSION);
481         return 0;
482 }
483
484 static const char * const cmd_sync_usage[] = {
485         "btrfs filesystem sync <path>",
486         "Force a sync on a filesystem",
487         NULL
488 };
489
490 static int cmd_sync(int argc, char **argv)
491 {
492         int     fd, res, e;
493         char    *path;
494         DIR     *dirstream = NULL;
495
496         if (check_argc_exact(argc, 2))
497                 usage(cmd_sync_usage);
498
499         path = argv[1];
500
501         fd = open_file_or_dir(path, &dirstream);
502         if (fd < 0) {
503                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
504                 return 1;
505         }
506
507         printf("FSSync '%s'\n", path);
508         res = ioctl(fd, BTRFS_IOC_SYNC);
509         e = errno;
510         close_file_or_dir(fd, dirstream);
511         if( res < 0 ){
512                 fprintf(stderr, "ERROR: unable to fs-syncing '%s' - %s\n", 
513                         path, strerror(e));
514                 return 1;
515         }
516
517         return 0;
518 }
519
520 static int parse_compress_type(char *s)
521 {
522         if (strcmp(optarg, "zlib") == 0)
523                 return BTRFS_COMPRESS_ZLIB;
524         else if (strcmp(optarg, "lzo") == 0)
525                 return BTRFS_COMPRESS_LZO;
526         else {
527                 fprintf(stderr, "Unknown compress type %s\n", s);
528                 exit(1);
529         };
530 }
531
532 static const char * const cmd_defrag_usage[] = {
533         "btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
534         "Defragment a file or a directory",
535         "",
536         "-v             be verbose",
537         "-r             defragment files recursively",
538         "-c[zlib,lzo]   compress the file while defragmenting",
539         "-f             flush data to disk immediately after defragmenting",
540         "-s start       defragment only from byte onward",
541         "-l len         defragment only up to len bytes",
542         "-t size        minimal size of file to be considered for defragmenting",
543         NULL
544 };
545
546 static int do_defrag(int fd, int fancy_ioctl,
547                 struct btrfs_ioctl_defrag_range_args *range)
548 {
549         int ret;
550
551         if (!fancy_ioctl)
552                 ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL);
553         else
554                 ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, range);
555
556         return ret;
557 }
558
559 static int defrag_global_fancy_ioctl;
560 static struct btrfs_ioctl_defrag_range_args defrag_global_range;
561 static int defrag_global_verbose;
562 static int defrag_global_errors;
563 static int defrag_callback(const char *fpath, const struct stat *sb,
564                 int typeflag, struct FTW *ftwbuf)
565 {
566         int ret = 0;
567         int e = 0;
568         int fd = 0;
569
570         if (typeflag == FTW_F) {
571                 if (defrag_global_verbose)
572                         printf("%s\n", fpath);
573                 fd = open(fpath, O_RDWR);
574                 e = errno;
575                 if (fd < 0)
576                         goto error;
577                 ret = do_defrag(fd, defrag_global_fancy_ioctl, &defrag_global_range);
578                 e = errno;
579                 close(fd);
580                 if (ret && e == ENOTTY) {
581                         fprintf(stderr, "ERROR: defrag range ioctl not "
582                                 "supported in this kernel, please try "
583                                 "without any options.\n");
584                         defrag_global_errors++;
585                         return ENOTTY;
586                 }
587                 if (ret)
588                         goto error;
589         }
590         return 0;
591
592 error:
593         fprintf(stderr, "ERROR: defrag failed on %s - %s\n", fpath, strerror(e));
594         defrag_global_errors++;
595         return 0;
596 }
597
598 static int cmd_defrag(int argc, char **argv)
599 {
600         int fd;
601         int flush = 0;
602         u64 start = 0;
603         u64 len = (u64)-1;
604         u32 thresh = 0;
605         int i;
606         int recursive = 0;
607         int ret = 0;
608         struct btrfs_ioctl_defrag_range_args range;
609         int e = 0;
610         int compress_type = BTRFS_COMPRESS_NONE;
611         DIR *dirstream;
612
613         defrag_global_errors = 0;
614         defrag_global_verbose = 0;
615         defrag_global_errors = 0;
616         defrag_global_fancy_ioctl = 0;
617         optind = 1;
618         while(1) {
619                 int c = getopt(argc, argv, "vrc::fs:l:t:");
620                 if (c < 0)
621                         break;
622
623                 switch(c) {
624                 case 'c':
625                         compress_type = BTRFS_COMPRESS_ZLIB;
626                         if (optarg)
627                                 compress_type = parse_compress_type(optarg);
628                         defrag_global_fancy_ioctl = 1;
629                         break;
630                 case 'f':
631                         flush = 1;
632                         defrag_global_fancy_ioctl = 1;
633                         break;
634                 case 'v':
635                         defrag_global_verbose = 1;
636                         break;
637                 case 's':
638                         start = parse_size(optarg);
639                         defrag_global_fancy_ioctl = 1;
640                         break;
641                 case 'l':
642                         len = parse_size(optarg);
643                         defrag_global_fancy_ioctl = 1;
644                         break;
645                 case 't':
646                         thresh = parse_size(optarg);
647                         defrag_global_fancy_ioctl = 1;
648                         break;
649                 case 'r':
650                         recursive = 1;
651                         break;
652                 default:
653                         usage(cmd_defrag_usage);
654                 }
655         }
656
657         if (check_argc_min(argc - optind, 1))
658                 usage(cmd_defrag_usage);
659
660         memset(&defrag_global_range, 0, sizeof(range));
661         defrag_global_range.start = start;
662         defrag_global_range.len = len;
663         defrag_global_range.extent_thresh = thresh;
664         if (compress_type) {
665                 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
666                 defrag_global_range.compress_type = compress_type;
667         }
668         if (flush)
669                 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
670
671         for (i = optind; i < argc; i++) {
672                 dirstream = NULL;
673                 fd = open_file_or_dir(argv[i], &dirstream);
674                 if (fd < 0) {
675                         fprintf(stderr, "ERROR: failed to open %s - %s\n", argv[i],
676                                         strerror(errno));
677                         defrag_global_errors++;
678                         close_file_or_dir(fd, dirstream);
679                         continue;
680                 }
681                 if (recursive) {
682                         struct stat st;
683
684                         fstat(fd, &st);
685                         if (S_ISDIR(st.st_mode)) {
686                                 ret = nftw(argv[i], defrag_callback, 10,
687                                                 FTW_MOUNT | FTW_PHYS);
688                                 if (ret == ENOTTY)
689                                         exit(1);
690                                 /* errors are handled in the callback */
691                                 ret = 0;
692                         } else {
693                                 if (defrag_global_verbose)
694                                         printf("%s\n", argv[i]);
695                                 ret = do_defrag(fd, defrag_global_fancy_ioctl,
696                                                 &defrag_global_range);
697                                 e = errno;
698                         }
699                 } else {
700                         if (defrag_global_verbose)
701                                 printf("%s\n", argv[i]);
702                         ret = do_defrag(fd, defrag_global_fancy_ioctl,
703                                         &defrag_global_range);
704                         e = errno;
705                 }
706                 close_file_or_dir(fd, dirstream);
707                 if (ret && e == ENOTTY) {
708                         fprintf(stderr, "ERROR: defrag range ioctl not "
709                                 "supported in this kernel, please try "
710                                 "without any options.\n");
711                         defrag_global_errors++;
712                         break;
713                 }
714                 if (ret) {
715                         fprintf(stderr, "ERROR: defrag failed on %s - %s\n",
716                                 argv[i], strerror(e));
717                         defrag_global_errors++;
718                 }
719         }
720         if (defrag_global_verbose)
721                 printf("%s\n", BTRFS_BUILD_VERSION);
722         if (defrag_global_errors)
723                 fprintf(stderr, "total %d failures\n", defrag_global_errors);
724
725         return !!defrag_global_errors;
726 }
727
728 static const char * const cmd_resize_usage[] = {
729         "btrfs filesystem resize [devid:][+/-]<newsize>[gkm]|[devid:]max <path>",
730         "Resize a filesystem",
731         "If 'max' is passed, the filesystem will occupy all available space",
732         "on the device 'devid'.",
733         NULL
734 };
735
736 static int cmd_resize(int argc, char **argv)
737 {
738         struct btrfs_ioctl_vol_args     args;
739         int     fd, res, len, e;
740         char    *amount, *path;
741         DIR     *dirstream = NULL;
742
743         if (check_argc_exact(argc, 3))
744                 usage(cmd_resize_usage);
745
746         amount = argv[1];
747         path = argv[2];
748
749         len = strlen(amount);
750         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
751                 fprintf(stderr, "ERROR: size value too long ('%s)\n",
752                         amount);
753                 return 1;
754         }
755
756         fd = open_file_or_dir(path, &dirstream);
757         if (fd < 0) {
758                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
759                 return 1;
760         }
761
762         printf("Resize '%s' of '%s'\n", path, amount);
763         strncpy_null(args.name, amount);
764         res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
765         e = errno;
766         close_file_or_dir(fd, dirstream);
767         if( res < 0 ){
768                 fprintf(stderr, "ERROR: unable to resize '%s' - %s\n", 
769                         path, strerror(e));
770                 return 1;
771         }
772         return 0;
773 }
774
775 static const char * const cmd_label_usage[] = {
776         "btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
777         "Get or change the label of a filesystem",
778         "With one argument, get the label of filesystem on <device>.",
779         "If <newlabel> is passed, set the filesystem label to <newlabel>.",
780         NULL
781 };
782
783 static int cmd_label(int argc, char **argv)
784 {
785         if (check_argc_min(argc, 2) || check_argc_max(argc, 3))
786                 usage(cmd_label_usage);
787
788         if (argc > 2)
789                 return set_label(argv[1], argv[2]);
790         else
791                 return get_label(argv[1]);
792 }
793
794 const struct cmd_group filesystem_cmd_group = {
795         filesystem_cmd_group_usage, NULL, {
796                 { "df", cmd_df, cmd_df_usage, NULL, 0 },
797                 { "show", cmd_show, cmd_show_usage, NULL, 0 },
798                 { "sync", cmd_sync, cmd_sync_usage, NULL, 0 },
799                 { "defragment", cmd_defrag, cmd_defrag_usage, NULL, 0 },
800                 { "balance", cmd_balance, NULL, &balance_cmd_group, 1 },
801                 { "resize", cmd_resize, cmd_resize_usage, NULL, 0 },
802                 { "label", cmd_label, cmd_label_usage, NULL, 0 },
803                 NULL_CMD_STRUCT
804         }
805 };
806
807 int cmd_filesystem(int argc, char **argv)
808 {
809         return handle_command_group(&filesystem_cmd_group, argc, argv);
810 }