46aa497362ad3144c20f60cd0737f9fde72453ee
[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 #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 <uuid/uuid.h>
24 #include <ctype.h>
25 #include <fcntl.h>
26 #include <ftw.h>
27 #include <mntent.h>
28 #include <linux/limits.h>
29 #include <getopt.h>
30
31 #include "kerncompat.h"
32 #include "ctree.h"
33 #include "utils.h"
34 #include "volumes.h"
35 #include "commands.h"
36 #include "cmds-fi-usage.h"
37 #include "list_sort.h"
38 #include "disk-io.h"
39 #include "help.h"
40
41 /*
42  * for btrfs fi show, we maintain a hash of fsids we've already printed.
43  * This way we don't print dups if a given FS is mounted more than once.
44  */
45 static struct seen_fsid *seen_fsid_hash[SEEN_FSID_HASH_SIZE] = {NULL,};
46
47 static const char * const filesystem_cmd_group_usage[] = {
48         "btrfs filesystem [<group>] <command> [<args>]",
49         NULL
50 };
51
52 static const char * const cmd_filesystem_df_usage[] = {
53         "btrfs filesystem df [options] <path>",
54         "Show space usage information for a mount point",
55         HELPINFO_UNITS_SHORT_LONG,
56         NULL
57 };
58
59 static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret)
60 {
61         u64 count = 0;
62         int ret;
63         struct btrfs_ioctl_space_args *sargs;
64
65         sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
66         if (!sargs)
67                 return -ENOMEM;
68
69         sargs->space_slots = 0;
70         sargs->total_spaces = 0;
71
72         ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
73         if (ret < 0) {
74                 error("cannot get space info: %s", strerror(errno));
75                 free(sargs);
76                 return -errno;
77         }
78         /* This really should never happen */
79         if (!sargs->total_spaces) {
80                 free(sargs);
81                 return -ENOENT;
82         }
83         count = sargs->total_spaces;
84         free(sargs);
85
86         sargs = malloc(sizeof(struct btrfs_ioctl_space_args) +
87                         (count * sizeof(struct btrfs_ioctl_space_info)));
88         if (!sargs)
89                 return -ENOMEM;
90
91         sargs->space_slots = count;
92         sargs->total_spaces = 0;
93         ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
94         if (ret < 0) {
95                 error("cannot get space info with %llu slots: %s",
96                                 count, strerror(errno));
97                 free(sargs);
98                 return -errno;
99         }
100         *sargs_ret = sargs;
101         return 0;
102 }
103
104 static void print_df(struct btrfs_ioctl_space_args *sargs, unsigned unit_mode)
105 {
106         u64 i;
107         struct btrfs_ioctl_space_info *sp = sargs->spaces;
108
109         for (i = 0; i < sargs->total_spaces; i++, sp++) {
110                 printf("%s, %s: total=%s, used=%s\n",
111                         btrfs_group_type_str(sp->flags),
112                         btrfs_group_profile_str(sp->flags),
113                         pretty_size_mode(sp->total_bytes, unit_mode),
114                         pretty_size_mode(sp->used_bytes, unit_mode));
115         }
116 }
117
118 static int cmd_filesystem_df(int argc, char **argv)
119 {
120         struct btrfs_ioctl_space_args *sargs = NULL;
121         int ret;
122         int fd;
123         char *path;
124         DIR *dirstream = NULL;
125         unsigned unit_mode;
126
127         unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
128
129         clean_args_no_options(argc, argv, cmd_filesystem_df_usage);
130
131         if (check_argc_exact(argc - optind, 1))
132                 usage(cmd_filesystem_df_usage);
133
134         path = argv[optind];
135
136         fd = btrfs_open_dir(path, &dirstream, 1);
137         if (fd < 0)
138                 return 1;
139
140         ret = get_df(fd, &sargs);
141
142         if (ret == 0) {
143                 print_df(sargs, unit_mode);
144                 free(sargs);
145         } else {
146                 error("get_df failed %s", strerror(-ret));
147         }
148
149         close_file_or_dir(fd, dirstream);
150         return !!ret;
151 }
152
153 static int match_search_item_kernel(__u8 *fsid, char *mnt, char *label,
154                                         char *search)
155 {
156         char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
157         int search_len = strlen(search);
158
159         search_len = min(search_len, BTRFS_UUID_UNPARSED_SIZE);
160         uuid_unparse(fsid, uuidbuf);
161         if (!strncmp(uuidbuf, search, search_len))
162                 return 1;
163
164         if (*label && strcmp(label, search) == 0)
165                 return 1;
166
167         if (strcmp(mnt, search) == 0)
168                 return 1;
169
170         return 0;
171 }
172
173 static int uuid_search(struct btrfs_fs_devices *fs_devices, const char *search)
174 {
175         char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
176         struct list_head *cur;
177         struct btrfs_device *device;
178         int search_len = strlen(search);
179
180         search_len = min(search_len, BTRFS_UUID_UNPARSED_SIZE);
181         uuid_unparse(fs_devices->fsid, uuidbuf);
182         if (!strncmp(uuidbuf, search, search_len))
183                 return 1;
184
185         list_for_each(cur, &fs_devices->devices) {
186                 device = list_entry(cur, struct btrfs_device, dev_list);
187                 if ((device->label && strcmp(device->label, search) == 0) ||
188                     strcmp(device->name, search) == 0)
189                         return 1;
190         }
191         return 0;
192 }
193
194 /*
195  * Sort devices by devid, ascending
196  */
197 static int cmp_device_id(void *priv, struct list_head *a,
198                 struct list_head *b)
199 {
200         const struct btrfs_device *da = list_entry(a, struct btrfs_device,
201                         dev_list);
202         const struct btrfs_device *db = list_entry(b, struct btrfs_device,
203                         dev_list);
204
205         return da->devid < db->devid ? -1 :
206                 da->devid > db->devid ? 1 : 0;
207 }
208
209 static void splice_device_list(struct list_head *seed_devices,
210                                struct list_head *all_devices)
211 {
212         struct btrfs_device *in_all, *next_all;
213         struct btrfs_device *in_seed, *next_seed;
214
215         list_for_each_entry_safe(in_all, next_all, all_devices, dev_list) {
216                 list_for_each_entry_safe(in_seed, next_seed, seed_devices,
217                                                                 dev_list) {
218                         if (in_all->devid == in_seed->devid) {
219                                 /*
220                                  * When do dev replace in a sprout fs
221                                  * to a dev in its seed fs, the replacing
222                                  * dev will reside in the sprout fs and
223                                  * the replaced dev will still exist
224                                  * in the seed fs.
225                                  * So pick the latest one when showing
226                                  * the sprout fs.
227                                  */
228                                 if (in_all->generation
229                                                 < in_seed->generation) {
230                                         list_del(&in_all->dev_list);
231                                         free(in_all);
232                                 } else if (in_all->generation
233                                                 > in_seed->generation) {
234                                         list_del(&in_seed->dev_list);
235                                         free(in_seed);
236                                 }
237                                 break;
238                         }
239                 }
240         }
241
242         list_splice(seed_devices, all_devices);
243 }
244
245 static void print_devices(struct btrfs_fs_devices *fs_devices,
246                           u64 *devs_found, unsigned unit_mode)
247 {
248         struct btrfs_device *device;
249         struct btrfs_fs_devices *cur_fs;
250         struct list_head *all_devices;
251
252         all_devices = &fs_devices->devices;
253         cur_fs = fs_devices->seed;
254         /* add all devices of seed fs to the fs to be printed */
255         while (cur_fs) {
256                 splice_device_list(&cur_fs->devices, all_devices);
257                 cur_fs = cur_fs->seed;
258         }
259
260         list_sort(NULL, all_devices, cmp_device_id);
261         list_for_each_entry(device, all_devices, dev_list) {
262                 printf("\tdevid %4llu size %s used %s path %s\n",
263                        (unsigned long long)device->devid,
264                        pretty_size_mode(device->total_bytes, unit_mode),
265                        pretty_size_mode(device->bytes_used, unit_mode),
266                        device->name);
267
268                 (*devs_found)++;
269         }
270 }
271
272 static void print_one_uuid(struct btrfs_fs_devices *fs_devices,
273                            unsigned unit_mode)
274 {
275         char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
276         struct btrfs_device *device;
277         u64 devs_found = 0;
278         u64 total;
279
280         if (add_seen_fsid(fs_devices->fsid, seen_fsid_hash, -1, NULL))
281                 return;
282
283         uuid_unparse(fs_devices->fsid, uuidbuf);
284         device = list_entry(fs_devices->devices.next, struct btrfs_device,
285                             dev_list);
286         if (device->label && device->label[0])
287                 printf("Label: '%s' ", device->label);
288         else
289                 printf("Label: none ");
290
291         total = device->total_devs;
292         printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf,
293                (unsigned long long)total,
294                pretty_size_mode(device->super_bytes_used, unit_mode));
295
296         print_devices(fs_devices, &devs_found, unit_mode);
297
298         if (devs_found < total) {
299                 printf("\t*** Some devices missing\n");
300         }
301         printf("\n");
302 }
303
304 /* adds up all the used spaces as reported by the space info ioctl
305  */
306 static u64 calc_used_bytes(struct btrfs_ioctl_space_args *si)
307 {
308         u64 ret = 0;
309         int i;
310         for (i = 0; i < si->total_spaces; i++)
311                 ret += si->spaces[i].used_bytes;
312         return ret;
313 }
314
315 static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
316                 struct btrfs_ioctl_dev_info_args *dev_info,
317                 struct btrfs_ioctl_space_args *space_info,
318                 char *label, unsigned unit_mode)
319 {
320         int i;
321         int fd;
322         int missing = 0;
323         char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
324         struct btrfs_ioctl_dev_info_args *tmp_dev_info;
325         int ret;
326
327         ret = add_seen_fsid(fs_info->fsid, seen_fsid_hash, -1, NULL);
328         if (ret == -EEXIST)
329                 return 0;
330         else if (ret)
331                 return ret;
332
333         uuid_unparse(fs_info->fsid, uuidbuf);
334         if (label && *label)
335                 printf("Label: '%s' ", label);
336         else
337                 printf("Label: none ");
338
339         printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf,
340                         fs_info->num_devices,
341                         pretty_size_mode(calc_used_bytes(space_info),
342                                          unit_mode));
343
344         for (i = 0; i < fs_info->num_devices; i++) {
345                 char *canonical_path;
346
347                 tmp_dev_info = (struct btrfs_ioctl_dev_info_args *)&dev_info[i];
348
349                 /* Add check for missing devices even mounted */
350                 fd = open((char *)tmp_dev_info->path, O_RDONLY);
351                 if (fd < 0) {
352                         missing = 1;
353                         continue;
354                 }
355                 close(fd);
356                 canonical_path = canonicalize_path((char *)tmp_dev_info->path);
357                 printf("\tdevid %4llu size %s used %s path %s\n",
358                         tmp_dev_info->devid,
359                         pretty_size_mode(tmp_dev_info->total_bytes, unit_mode),
360                         pretty_size_mode(tmp_dev_info->bytes_used, unit_mode),
361                         canonical_path);
362
363                 free(canonical_path);
364         }
365
366         if (missing)
367                 printf("\t*** Some devices missing\n");
368         printf("\n");
369         return 0;
370 }
371
372 static int btrfs_scan_kernel(void *search, unsigned unit_mode)
373 {
374         int ret = 0, fd;
375         int found = 0;
376         FILE *f;
377         struct mntent *mnt;
378         struct btrfs_ioctl_fs_info_args fs_info_arg;
379         struct btrfs_ioctl_dev_info_args *dev_info_arg = NULL;
380         struct btrfs_ioctl_space_args *space_info_arg = NULL;
381         char label[BTRFS_LABEL_SIZE];
382
383         f = setmntent("/proc/self/mounts", "r");
384         if (f == NULL)
385                 return 1;
386
387         memset(label, 0, sizeof(label));
388         while ((mnt = getmntent(f)) != NULL) {
389                 free(dev_info_arg);
390                 dev_info_arg = NULL;
391                 if (strcmp(mnt->mnt_type, "btrfs"))
392                         continue;
393                 ret = get_fs_info(mnt->mnt_dir, &fs_info_arg,
394                                 &dev_info_arg);
395                 if (ret)
396                         goto out;
397
398                 /* skip all fs already shown as mounted fs */
399                 if (is_seen_fsid(fs_info_arg.fsid, seen_fsid_hash))
400                         continue;
401
402                 ret = get_label_mounted(mnt->mnt_dir, label);
403                 /* provide backward kernel compatibility */
404                 if (ret == -ENOTTY)
405                         ret = get_label_unmounted(
406                                 (const char *)dev_info_arg->path, label);
407
408                 if (ret)
409                         goto out;
410
411                 if (search && !match_search_item_kernel(fs_info_arg.fsid,
412                                         mnt->mnt_dir, label, search)) {
413                         continue;
414                 }
415
416                 fd = open(mnt->mnt_dir, O_RDONLY);
417                 if ((fd != -1) && !get_df(fd, &space_info_arg)) {
418                         print_one_fs(&fs_info_arg, dev_info_arg,
419                                      space_info_arg, label, unit_mode);
420                         free(space_info_arg);
421                         memset(label, 0, sizeof(label));
422                         found = 1;
423                 }
424                 if (fd != -1)
425                         close(fd);
426         }
427
428 out:
429         free(dev_info_arg);
430         endmntent(f);
431         return !found;
432 }
433
434 static int dev_to_fsid(const char *dev, __u8 *fsid)
435 {
436         struct btrfs_super_block *disk_super;
437         char buf[BTRFS_SUPER_INFO_SIZE];
438         int ret;
439         int fd;
440
441         fd = open(dev, O_RDONLY);
442         if (fd < 0) {
443                 ret = -errno;
444                 return ret;
445         }
446
447         disk_super = (struct btrfs_super_block *)buf;
448         ret = btrfs_read_dev_super(fd, disk_super,
449                                    BTRFS_SUPER_INFO_OFFSET, SBREAD_DEFAULT);
450         if (ret)
451                 goto out;
452
453         memcpy(fsid, disk_super->fsid, BTRFS_FSID_SIZE);
454         ret = 0;
455
456 out:
457         close(fd);
458         return ret;
459 }
460
461 static void free_fs_devices(struct btrfs_fs_devices *fs_devices)
462 {
463         struct btrfs_fs_devices *cur_seed, *next_seed;
464         struct btrfs_device *device;
465
466         while (!list_empty(&fs_devices->devices)) {
467                 device = list_entry(fs_devices->devices.next,
468                                         struct btrfs_device, dev_list);
469                 list_del(&device->dev_list);
470
471                 free(device->name);
472                 free(device->label);
473                 free(device);
474         }
475
476         /* free seed fs chain */
477         cur_seed = fs_devices->seed;
478         fs_devices->seed = NULL;
479         while (cur_seed) {
480                 next_seed = cur_seed->seed;
481                 free(cur_seed);
482
483                 cur_seed = next_seed;
484         }
485
486         list_del(&fs_devices->list);
487         free(fs_devices);
488 }
489
490 static int copy_device(struct btrfs_device *dst,
491                        struct btrfs_device *src)
492 {
493         dst->devid = src->devid;
494         memcpy(dst->uuid, src->uuid, BTRFS_UUID_SIZE);
495         if (src->name == NULL)
496                 dst->name = NULL;
497         else {
498                 dst->name = strdup(src->name);
499                 if (!dst->name)
500                         return -ENOMEM;
501         }
502         if (src->label == NULL)
503                 dst->label = NULL;
504         else {
505                 dst->label = strdup(src->label);
506                 if (!dst->label) {
507                         free(dst->name);
508                         return -ENOMEM;
509                 }
510         }
511         dst->total_devs = src->total_devs;
512         dst->super_bytes_used = src->super_bytes_used;
513         dst->total_bytes = src->total_bytes;
514         dst->bytes_used = src->bytes_used;
515         dst->generation = src->generation;
516
517         return 0;
518 }
519
520 static int copy_fs_devices(struct btrfs_fs_devices *dst,
521                            struct btrfs_fs_devices *src)
522 {
523         struct btrfs_device *cur_dev, *dev_copy;
524         int ret = 0;
525
526         memcpy(dst->fsid, src->fsid, BTRFS_FSID_SIZE);
527         INIT_LIST_HEAD(&dst->devices);
528         dst->seed = NULL;
529
530         list_for_each_entry(cur_dev, &src->devices, dev_list) {
531                 dev_copy = malloc(sizeof(*dev_copy));
532                 if (!dev_copy) {
533                         ret = -ENOMEM;
534                         break;
535                 }
536
537                 ret = copy_device(dev_copy, cur_dev);
538                 if (ret) {
539                         free(dev_copy);
540                         break;
541                 }
542
543                 list_add(&dev_copy->dev_list, &dst->devices);
544                 dev_copy->fs_devices = dst;
545         }
546
547         return ret;
548 }
549
550 static int find_and_copy_seed(struct btrfs_fs_devices *seed,
551                               struct btrfs_fs_devices *copy,
552                               struct list_head *fs_uuids) {
553         struct btrfs_fs_devices *cur_fs;
554
555         list_for_each_entry(cur_fs, fs_uuids, list)
556                 if (!memcmp(seed->fsid, cur_fs->fsid, BTRFS_FSID_SIZE))
557                         return copy_fs_devices(copy, cur_fs);
558
559         return 1;
560 }
561
562 static int has_seed_devices(struct btrfs_fs_devices *fs_devices)
563 {
564         struct btrfs_device *device;
565         int dev_cnt_total, dev_cnt = 0;
566
567         device = list_first_entry(&fs_devices->devices, struct btrfs_device,
568                                   dev_list);
569
570         dev_cnt_total = device->total_devs;
571
572         list_for_each_entry(device, &fs_devices->devices, dev_list)
573                 dev_cnt++;
574
575         return dev_cnt_total != dev_cnt;
576 }
577
578 static int search_umounted_fs_uuids(struct list_head *all_uuids,
579                                     char *search, int *found)
580 {
581         struct btrfs_fs_devices *cur_fs, *fs_copy;
582         struct list_head *fs_uuids;
583         int ret = 0;
584
585         fs_uuids = btrfs_scanned_uuids();
586
587         /*
588          * The fs_uuids list is global, and open_ctree_* will
589          * modify it, make a private copy here
590          */
591         list_for_each_entry(cur_fs, fs_uuids, list) {
592                 /* don't bother handle all fs, if search target specified */
593                 if (search) {
594                         if (uuid_search(cur_fs, search) == 0)
595                                 continue;
596                         if (found)
597                                 *found = 1;
598                 }
599
600                 /* skip all fs already shown as mounted fs */
601                 if (is_seen_fsid(cur_fs->fsid, seen_fsid_hash))
602                         continue;
603
604                 fs_copy = calloc(1, sizeof(*fs_copy));
605                 if (!fs_copy) {
606                         ret = -ENOMEM;
607                         goto out;
608                 }
609
610                 ret = copy_fs_devices(fs_copy, cur_fs);
611                 if (ret) {
612                         free(fs_copy);
613                         goto out;
614                 }
615
616                 list_add(&fs_copy->list, all_uuids);
617         }
618
619 out:
620         return ret;
621 }
622
623 static int map_seed_devices(struct list_head *all_uuids)
624 {
625         struct btrfs_fs_devices *cur_fs, *cur_seed;
626         struct btrfs_fs_devices *seed_copy;
627         struct btrfs_fs_devices *opened_fs;
628         struct btrfs_device *device;
629         struct btrfs_fs_info *fs_info;
630         struct list_head *fs_uuids;
631         int ret = 0;
632
633         fs_uuids = btrfs_scanned_uuids();
634
635         list_for_each_entry(cur_fs, all_uuids, list) {
636                 device = list_first_entry(&cur_fs->devices,
637                                                 struct btrfs_device, dev_list);
638                 if (!device)
639                         continue;
640
641                 /* skip fs without seeds */
642                 if (!has_seed_devices(cur_fs))
643                         continue;
644
645                 /*
646                  * open_ctree_* detects seed/sprout mapping
647                  */
648                 fs_info = open_ctree_fs_info(device->name, 0, 0, 0,
649                                                 OPEN_CTREE_PARTIAL);
650                 if (!fs_info)
651                         continue;
652
653                 /*
654                  * copy the seed chain under the opened fs
655                  */
656                 opened_fs = fs_info->fs_devices;
657                 cur_seed = cur_fs;
658                 while (opened_fs->seed) {
659                         seed_copy = malloc(sizeof(*seed_copy));
660                         if (!seed_copy) {
661                                 ret = -ENOMEM;
662                                 goto fail_out;
663                         }
664                         ret = find_and_copy_seed(opened_fs->seed, seed_copy,
665                                                  fs_uuids);
666                         if (ret) {
667                                 free(seed_copy);
668                                 goto fail_out;
669                         }
670
671                         cur_seed->seed = seed_copy;
672
673                         opened_fs = opened_fs->seed;
674                         cur_seed = cur_seed->seed;
675                 }
676
677                 close_ctree(fs_info->chunk_root);
678         }
679
680 out:
681         return ret;
682 fail_out:
683         close_ctree(fs_info->chunk_root);
684         goto out;
685 }
686
687 static const char * const cmd_filesystem_show_usage[] = {
688         "btrfs filesystem show [options] [<path>|<uuid>|<device>|label]",
689         "Show the structure of a filesystem",
690         "-d|--all-devices   show only disks under /dev containing btrfs filesystem",
691         "-m|--mounted       show only mounted btrfs",
692         HELPINFO_UNITS_LONG,
693         "If no argument is given, structure of all present filesystems is shown.",
694         NULL
695 };
696
697 static int cmd_filesystem_show(int argc, char **argv)
698 {
699         LIST_HEAD(all_uuids);
700         struct btrfs_fs_devices *fs_devices;
701         char *search = NULL;
702         int ret;
703         /* default, search both kernel and udev */
704         int where = -1;
705         int type = 0;
706         char mp[PATH_MAX];
707         char path[PATH_MAX];
708         __u8 fsid[BTRFS_FSID_SIZE];
709         char uuid_buf[BTRFS_UUID_UNPARSED_SIZE];
710         unsigned unit_mode;
711         int found = 0;
712
713         unit_mode = get_unit_mode_from_arg(&argc, argv, 0);
714
715         while (1) {
716                 int c;
717                 static const struct option long_options[] = {
718                         { "all-devices", no_argument, NULL, 'd'},
719                         { "mounted", no_argument, NULL, 'm'},
720                         { NULL, 0, NULL, 0 }
721                 };
722
723                 c = getopt_long(argc, argv, "dm", long_options, NULL);
724                 if (c < 0)
725                         break;
726                 switch (c) {
727                 case 'd':
728                         where = BTRFS_SCAN_LBLKID;
729                         break;
730                 case 'm':
731                         where = BTRFS_SCAN_MOUNTED;
732                         break;
733                 default:
734                         usage(cmd_filesystem_show_usage);
735                 }
736         }
737
738         if (check_argc_max(argc, optind + 1))
739                 usage(cmd_filesystem_show_usage);
740
741         if (argc > optind) {
742                 search = argv[optind];
743                 if (*search == 0)
744                         usage(cmd_filesystem_show_usage);
745                 type = check_arg_type(search);
746
747                 /*
748                  * For search is a device:
749                  *     realpath do /dev/mapper/XX => /dev/dm-X
750                  *     which is required by BTRFS_SCAN_DEV
751                  * For search is a mountpoint:
752                  *     realpath do  /mnt/btrfs/  => /mnt/btrfs
753                  *     which shall be recognized by btrfs_scan_kernel()
754                  */
755                 if (realpath(search, path))
756                         search = path;
757
758                 /*
759                  * Needs special handling if input arg is block dev And if
760                  * input arg is mount-point just print it right away
761                  */
762                 if (type == BTRFS_ARG_BLKDEV && where != BTRFS_SCAN_LBLKID) {
763                         ret = get_btrfs_mount(search, mp, sizeof(mp));
764                         if (!ret) {
765                                 /* given block dev is mounted */
766                                 search = mp;
767                                 type = BTRFS_ARG_MNTPOINT;
768                         } else {
769                                 ret = dev_to_fsid(search, fsid);
770                                 if (ret) {
771                                         error("no btrfs on %s", search);
772                                         return 1;
773                                 }
774                                 uuid_unparse(fsid, uuid_buf);
775                                 search = uuid_buf;
776                                 type = BTRFS_ARG_UUID;
777                                 goto devs_only;
778                         }
779                 }
780         }
781
782         if (where == BTRFS_SCAN_LBLKID)
783                 goto devs_only;
784
785         /* show mounted btrfs */
786         ret = btrfs_scan_kernel(search, unit_mode);
787         if (search && !ret) {
788                 /* since search is found we are done */
789                 goto out;
790         }
791
792         /* shows mounted only */
793         if (where == BTRFS_SCAN_MOUNTED)
794                 goto out;
795
796 devs_only:
797         ret = btrfs_scan_devices();
798
799         if (ret) {
800                 error("blkid device scan returned %d", ret);
801                 return 1;
802         }
803
804         ret = search_umounted_fs_uuids(&all_uuids, search, &found);
805         if (ret < 0) {
806                 error("searching target device returned error %d", ret);
807                 return 1;
808         }
809
810         /*
811          * The seed/sprout mapping are not detected yet,
812          * do mapping build for all umounted fs
813          */
814         ret = map_seed_devices(&all_uuids);
815         if (ret) {
816                 error("mapping seed devices returned error %d", ret);
817                 return 1;
818         }
819
820         list_for_each_entry(fs_devices, &all_uuids, list)
821                 print_one_uuid(fs_devices, unit_mode);
822
823         if (search && !found) {
824                 error("not a valid btrfs filesystem: %s", search);
825                 ret = 1;
826         }
827         while (!list_empty(&all_uuids)) {
828                 fs_devices = list_entry(all_uuids.next,
829                                         struct btrfs_fs_devices, list);
830                 free_fs_devices(fs_devices);
831         }
832 out:
833         free_seen_fsid(seen_fsid_hash);
834         return ret;
835 }
836
837 static const char * const cmd_filesystem_sync_usage[] = {
838         "btrfs filesystem sync <path>",
839         "Force a sync on a filesystem",
840         NULL
841 };
842
843 static int cmd_filesystem_sync(int argc, char **argv)
844 {
845         int     fd, res, e;
846         char    *path;
847         DIR     *dirstream = NULL;
848
849         clean_args_no_options(argc, argv, cmd_filesystem_sync_usage);
850
851         if (check_argc_exact(argc - optind, 1))
852                 usage(cmd_filesystem_sync_usage);
853
854         path = argv[optind];
855
856         fd = btrfs_open_dir(path, &dirstream, 1);
857         if (fd < 0)
858                 return 1;
859
860         res = ioctl(fd, BTRFS_IOC_SYNC);
861         e = errno;
862         close_file_or_dir(fd, dirstream);
863         if( res < 0 ){
864                 error("sync ioctl failed on '%s': %s", path, strerror(e));
865                 return 1;
866         }
867
868         return 0;
869 }
870
871 static int parse_compress_type(char *s)
872 {
873         if (strcmp(optarg, "zlib") == 0)
874                 return BTRFS_COMPRESS_ZLIB;
875         else if (strcmp(optarg, "lzo") == 0)
876                 return BTRFS_COMPRESS_LZO;
877         else if (strcmp(optarg, "zstd") == 0)
878                 return BTRFS_COMPRESS_ZSTD;
879         else {
880                 error("unknown compression type %s", s);
881                 exit(1);
882         };
883 }
884
885 static const char * const cmd_filesystem_defrag_usage[] = {
886         "btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
887         "Defragment a file or a directory",
888         "",
889         "-v                  be verbose",
890         "-r                  defragment files recursively",
891         "-c[zlib,lzo,zstd]   compress the file while defragmenting",
892         "-f                  flush data to disk immediately after defragmenting",
893         "-s start            defragment only from byte onward",
894         "-l len              defragment only up to len bytes",
895         "-t size             target extent size hint (default: 32M)",
896         "",
897         "Warning: most Linux kernels will break up the ref-links of COW data",
898         "(e.g., files copied with 'cp --reflink', snapshots) which may cause",
899         "considerable increase of space usage. See btrfs-filesystem(8) for",
900         "more information.",
901         NULL
902 };
903
904 static struct btrfs_ioctl_defrag_range_args defrag_global_range;
905 static int defrag_global_verbose;
906 static int defrag_global_errors;
907 static int defrag_callback(const char *fpath, const struct stat *sb,
908                 int typeflag, struct FTW *ftwbuf)
909 {
910         int ret = 0;
911         int err = 0;
912         int fd = 0;
913
914         if ((typeflag == FTW_F) && S_ISREG(sb->st_mode)) {
915                 if (defrag_global_verbose)
916                         printf("%s\n", fpath);
917                 fd = open(fpath, O_RDWR);
918                 if (fd < 0) {
919                         err = errno;
920                         goto error;
921                 }
922                 ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &defrag_global_range);
923                 close(fd);
924                 if (ret && errno == ENOTTY) {
925                         error(
926 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
927                         defrag_global_errors++;
928                         return ENOTTY;
929                 }
930                 if (ret) {
931                         err = errno;
932                         goto error;
933                 }
934         }
935         return 0;
936
937 error:
938         error("defrag failed on %s: %s", fpath, strerror(err));
939         defrag_global_errors++;
940         return 0;
941 }
942
943 static int cmd_filesystem_defrag(int argc, char **argv)
944 {
945         int fd;
946         int flush = 0;
947         u64 start = 0;
948         u64 len = (u64)-1;
949         u64 thresh;
950         int i;
951         int recursive = 0;
952         int ret = 0;
953         int compress_type = BTRFS_COMPRESS_NONE;
954         DIR *dirstream;
955
956         /*
957          * Kernel has a different default (256K) that is supposed to be safe,
958          * but it does not defragment very well. The 32M will likely lead to
959          * better results and is independent of the kernel default. We have to
960          * use the v2 defrag ioctl.
961          */
962         thresh = SZ_32M;
963
964         defrag_global_errors = 0;
965         defrag_global_verbose = 0;
966         defrag_global_errors = 0;
967         while(1) {
968                 int c = getopt(argc, argv, "vrc::fs:l:t:");
969                 if (c < 0)
970                         break;
971
972                 switch(c) {
973                 case 'c':
974                         compress_type = BTRFS_COMPRESS_ZLIB;
975                         if (optarg)
976                                 compress_type = parse_compress_type(optarg);
977                         break;
978                 case 'f':
979                         flush = 1;
980                         break;
981                 case 'v':
982                         defrag_global_verbose = 1;
983                         break;
984                 case 's':
985                         start = parse_size(optarg);
986                         break;
987                 case 'l':
988                         len = parse_size(optarg);
989                         break;
990                 case 't':
991                         thresh = parse_size(optarg);
992                         if (thresh > (u32)-1) {
993                                 warning(
994                             "target extent size %llu too big, trimmed to %u",
995                                         thresh, (u32)-1);
996                                 thresh = (u32)-1;
997                         }
998                         break;
999                 case 'r':
1000                         recursive = 1;
1001                         break;
1002                 default:
1003                         usage(cmd_filesystem_defrag_usage);
1004                 }
1005         }
1006
1007         if (check_argc_min(argc - optind, 1))
1008                 usage(cmd_filesystem_defrag_usage);
1009
1010         memset(&defrag_global_range, 0, sizeof(defrag_global_range));
1011         defrag_global_range.start = start;
1012         defrag_global_range.len = len;
1013         defrag_global_range.extent_thresh = (u32)thresh;
1014         if (compress_type) {
1015                 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
1016                 defrag_global_range.compress_type = compress_type;
1017         }
1018         if (flush)
1019                 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
1020
1021         /*
1022          * Look for directory arguments and warn if the recursive mode is not
1023          * requested, as this is not implemented as recursive defragmentation
1024          * in kernel. The stat errors are silent here as we check them below.
1025          */
1026         if (!recursive) {
1027                 int found = 0;
1028
1029                 for (i = optind; i < argc; i++) {
1030                         struct stat st;
1031
1032                         if (stat(argv[i], &st))
1033                                 continue;
1034
1035                         if (S_ISDIR(st.st_mode)) {
1036                                 warning(
1037                         "directory specified but recursive mode not requested: %s",
1038                                         argv[i]);
1039                                 found = 1;
1040                         }
1041                 }
1042                 if (found) {
1043                         warning(
1044 "a directory passed to the defrag ioctl will not process the files\n"
1045 "recursively but will defragment the subvolume tree and the extent tree.\n"
1046 "If this is not intended, please use option -r .");
1047                 }
1048         }
1049
1050         for (i = optind; i < argc; i++) {
1051                 struct stat st;
1052                 int defrag_err = 0;
1053
1054                 dirstream = NULL;
1055                 fd = open_file_or_dir(argv[i], &dirstream);
1056                 if (fd < 0) {
1057                         error("cannot open %s: %s", argv[i],
1058                                         strerror(errno));
1059                         defrag_global_errors++;
1060                         close_file_or_dir(fd, dirstream);
1061                         continue;
1062                 }
1063                 if (fstat(fd, &st)) {
1064                         error("failed to stat %s: %s",
1065                                         argv[i], strerror(errno));
1066                         defrag_global_errors++;
1067                         close_file_or_dir(fd, dirstream);
1068                         continue;
1069                 }
1070                 if (!(S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))) {
1071                         error("%s is not a directory or a regular file",
1072                                         argv[i]);
1073                         defrag_global_errors++;
1074                         close_file_or_dir(fd, dirstream);
1075                         continue;
1076                 }
1077                 if (recursive && S_ISDIR(st.st_mode)) {
1078                         ret = nftw(argv[i], defrag_callback, 10,
1079                                                 FTW_MOUNT | FTW_PHYS);
1080                         if (ret == ENOTTY)
1081                                 exit(1);
1082                         /* errors are handled in the callback */
1083                         ret = 0;
1084                 } else {
1085                         if (defrag_global_verbose)
1086                                 printf("%s\n", argv[i]);
1087                         ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE,
1088                                         &defrag_global_range);
1089                         defrag_err = errno;
1090                 }
1091                 close_file_or_dir(fd, dirstream);
1092                 if (ret && defrag_err == ENOTTY) {
1093                         error(
1094 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
1095                         defrag_global_errors++;
1096                         break;
1097                 }
1098                 if (ret) {
1099                         error("defrag failed on %s: %s", argv[i],
1100                                         strerror(defrag_err));
1101                         defrag_global_errors++;
1102                 }
1103         }
1104         if (defrag_global_errors)
1105                 fprintf(stderr, "total %d failures\n", defrag_global_errors);
1106
1107         return !!defrag_global_errors;
1108 }
1109
1110 static const char * const cmd_filesystem_resize_usage[] = {
1111         "btrfs filesystem resize [devid:][+/-]<newsize>[kKmMgGtTpPeE]|[devid:]max <path>",
1112         "Resize a filesystem",
1113         "If 'max' is passed, the filesystem will occupy all available space",
1114         "on the device 'devid'.",
1115         "[kK] means KiB, which denotes 1KiB = 1024B, 1MiB = 1024KiB, etc.",
1116         NULL
1117 };
1118
1119 static int cmd_filesystem_resize(int argc, char **argv)
1120 {
1121         struct btrfs_ioctl_vol_args     args;
1122         int     fd, res, len, e;
1123         char    *amount, *path;
1124         DIR     *dirstream = NULL;
1125         struct stat st;
1126
1127         clean_args_no_options_relaxed(argc, argv, cmd_filesystem_resize_usage);
1128
1129         if (check_argc_exact(argc - optind, 2))
1130                 usage(cmd_filesystem_resize_usage);
1131
1132         amount = argv[optind];
1133         path = argv[optind + 1];
1134
1135         len = strlen(amount);
1136         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
1137                 error("resize value too long (%s)", amount);
1138                 return 1;
1139         }
1140
1141         res = stat(path, &st);
1142         if (res < 0) {
1143                 error("resize: cannot stat %s: %s", path, strerror(errno));
1144                 return 1;
1145         }
1146         if (!S_ISDIR(st.st_mode)) {
1147                 error("resize works on mounted filesystems and accepts only\n"
1148                         "directories as argument. Passing file containing a btrfs image\n"
1149                         "would resize the underlying filesystem instead of the image.\n");
1150                 return 1;
1151         }
1152
1153         fd = btrfs_open_dir(path, &dirstream, 1);
1154         if (fd < 0)
1155                 return 1;
1156
1157         printf("Resize '%s' of '%s'\n", path, amount);
1158         memset(&args, 0, sizeof(args));
1159         strncpy_null(args.name, amount);
1160         res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
1161         e = errno;
1162         close_file_or_dir(fd, dirstream);
1163         if( res < 0 ){
1164                 switch (e) {
1165                 case EFBIG:
1166                         error("unable to resize '%s': no enough free space",
1167                                 path);
1168                         break;
1169                 default:
1170                         error("unable to resize '%s': %s", path, strerror(e));
1171                         break;
1172                 }
1173                 return 1;
1174         } else if (res > 0) {
1175                 const char *err_str = btrfs_err_str(res);
1176
1177                 if (err_str) {
1178                         error("resizing of '%s' failed: %s", path, err_str);
1179                 } else {
1180                         error("resizing of '%s' failed: unknown error %d",
1181                                 path, res);
1182                 }
1183                 return 1;
1184         }
1185         return 0;
1186 }
1187
1188 static const char * const cmd_filesystem_label_usage[] = {
1189         "btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
1190         "Get or change the label of a filesystem",
1191         "With one argument, get the label of filesystem on <device>.",
1192         "If <newlabel> is passed, set the filesystem label to <newlabel>.",
1193         NULL
1194 };
1195
1196 static int cmd_filesystem_label(int argc, char **argv)
1197 {
1198         clean_args_no_options(argc, argv, cmd_filesystem_label_usage);
1199
1200         if (check_argc_min(argc - optind, 1) ||
1201                         check_argc_max(argc - optind, 2))
1202                 usage(cmd_filesystem_label_usage);
1203
1204         if (argc - optind > 1) {
1205                 return set_label(argv[optind], argv[optind + 1]);
1206         } else {
1207                 char label[BTRFS_LABEL_SIZE];
1208                 int ret;
1209
1210                 ret = get_label(argv[optind], label);
1211                 if (!ret)
1212                         fprintf(stdout, "%s\n", label);
1213
1214                 return ret;
1215         }
1216 }
1217
1218 static const char filesystem_cmd_group_info[] =
1219 "overall filesystem tasks and information";
1220
1221 const struct cmd_group filesystem_cmd_group = {
1222         filesystem_cmd_group_usage, filesystem_cmd_group_info, {
1223                 { "df", cmd_filesystem_df, cmd_filesystem_df_usage, NULL, 0 },
1224                 { "du", cmd_filesystem_du, cmd_filesystem_du_usage, NULL, 0 },
1225                 { "show", cmd_filesystem_show, cmd_filesystem_show_usage, NULL,
1226                         0 },
1227                 { "sync", cmd_filesystem_sync, cmd_filesystem_sync_usage, NULL,
1228                         0 },
1229                 { "defragment", cmd_filesystem_defrag,
1230                         cmd_filesystem_defrag_usage, NULL, 0 },
1231                 { "balance", cmd_balance, NULL, &balance_cmd_group,
1232                         CMD_HIDDEN },
1233                 { "resize", cmd_filesystem_resize, cmd_filesystem_resize_usage,
1234                         NULL, 0 },
1235                 { "label", cmd_filesystem_label, cmd_filesystem_label_usage,
1236                         NULL, 0 },
1237                 { "usage", cmd_filesystem_usage,
1238                         cmd_filesystem_usage_usage, NULL, 0 },
1239
1240                 NULL_CMD_STRUCT
1241         }
1242 };
1243
1244 int cmd_filesystem(int argc, char **argv)
1245 {
1246         return handle_command_group(&filesystem_cmd_group, argc, argv);
1247 }