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