btrfs-progs: qgroup: cleanup the redundant function add_qgroup
[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 void free_fs_devices(struct btrfs_fs_devices *fs_devices)
435 {
436         struct btrfs_fs_devices *cur_seed, *next_seed;
437         struct btrfs_device *device;
438
439         while (!list_empty(&fs_devices->devices)) {
440                 device = list_entry(fs_devices->devices.next,
441                                         struct btrfs_device, dev_list);
442                 list_del(&device->dev_list);
443
444                 free(device->name);
445                 free(device->label);
446                 free(device);
447         }
448
449         /* free seed fs chain */
450         cur_seed = fs_devices->seed;
451         fs_devices->seed = NULL;
452         while (cur_seed) {
453                 next_seed = cur_seed->seed;
454                 free(cur_seed);
455
456                 cur_seed = next_seed;
457         }
458
459         list_del(&fs_devices->list);
460         free(fs_devices);
461 }
462
463 static int copy_device(struct btrfs_device *dst,
464                        struct btrfs_device *src)
465 {
466         dst->devid = src->devid;
467         memcpy(dst->uuid, src->uuid, BTRFS_UUID_SIZE);
468         if (src->name == NULL)
469                 dst->name = NULL;
470         else {
471                 dst->name = strdup(src->name);
472                 if (!dst->name)
473                         return -ENOMEM;
474         }
475         if (src->label == NULL)
476                 dst->label = NULL;
477         else {
478                 dst->label = strdup(src->label);
479                 if (!dst->label) {
480                         free(dst->name);
481                         return -ENOMEM;
482                 }
483         }
484         dst->total_devs = src->total_devs;
485         dst->super_bytes_used = src->super_bytes_used;
486         dst->total_bytes = src->total_bytes;
487         dst->bytes_used = src->bytes_used;
488         dst->generation = src->generation;
489
490         return 0;
491 }
492
493 static int copy_fs_devices(struct btrfs_fs_devices *dst,
494                            struct btrfs_fs_devices *src)
495 {
496         struct btrfs_device *cur_dev, *dev_copy;
497         int ret = 0;
498
499         memcpy(dst->fsid, src->fsid, BTRFS_FSID_SIZE);
500         INIT_LIST_HEAD(&dst->devices);
501         dst->seed = NULL;
502
503         list_for_each_entry(cur_dev, &src->devices, dev_list) {
504                 dev_copy = malloc(sizeof(*dev_copy));
505                 if (!dev_copy) {
506                         ret = -ENOMEM;
507                         break;
508                 }
509
510                 ret = copy_device(dev_copy, cur_dev);
511                 if (ret) {
512                         free(dev_copy);
513                         break;
514                 }
515
516                 list_add(&dev_copy->dev_list, &dst->devices);
517                 dev_copy->fs_devices = dst;
518         }
519
520         return ret;
521 }
522
523 static int find_and_copy_seed(struct btrfs_fs_devices *seed,
524                               struct btrfs_fs_devices *copy,
525                               struct list_head *fs_uuids) {
526         struct btrfs_fs_devices *cur_fs;
527
528         list_for_each_entry(cur_fs, fs_uuids, list)
529                 if (!memcmp(seed->fsid, cur_fs->fsid, BTRFS_FSID_SIZE))
530                         return copy_fs_devices(copy, cur_fs);
531
532         return 1;
533 }
534
535 static int has_seed_devices(struct btrfs_fs_devices *fs_devices)
536 {
537         struct btrfs_device *device;
538         int dev_cnt_total, dev_cnt = 0;
539
540         device = list_first_entry(&fs_devices->devices, struct btrfs_device,
541                                   dev_list);
542
543         dev_cnt_total = device->total_devs;
544
545         list_for_each_entry(device, &fs_devices->devices, dev_list)
546                 dev_cnt++;
547
548         return dev_cnt_total != dev_cnt;
549 }
550
551 static int search_umounted_fs_uuids(struct list_head *all_uuids,
552                                     char *search, int *found)
553 {
554         struct btrfs_fs_devices *cur_fs, *fs_copy;
555         struct list_head *fs_uuids;
556         int ret = 0;
557
558         fs_uuids = btrfs_scanned_uuids();
559
560         /*
561          * The fs_uuids list is global, and open_ctree_* will
562          * modify it, make a private copy here
563          */
564         list_for_each_entry(cur_fs, fs_uuids, list) {
565                 /* don't bother handle all fs, if search target specified */
566                 if (search) {
567                         if (uuid_search(cur_fs, search) == 0)
568                                 continue;
569                         if (found)
570                                 *found = 1;
571                 }
572
573                 /* skip all fs already shown as mounted fs */
574                 if (is_seen_fsid(cur_fs->fsid, seen_fsid_hash))
575                         continue;
576
577                 fs_copy = calloc(1, sizeof(*fs_copy));
578                 if (!fs_copy) {
579                         ret = -ENOMEM;
580                         goto out;
581                 }
582
583                 ret = copy_fs_devices(fs_copy, cur_fs);
584                 if (ret) {
585                         free(fs_copy);
586                         goto out;
587                 }
588
589                 list_add(&fs_copy->list, all_uuids);
590         }
591
592 out:
593         return ret;
594 }
595
596 static int map_seed_devices(struct list_head *all_uuids)
597 {
598         struct btrfs_fs_devices *cur_fs, *cur_seed;
599         struct btrfs_fs_devices *seed_copy;
600         struct btrfs_fs_devices *opened_fs;
601         struct btrfs_device *device;
602         struct btrfs_fs_info *fs_info;
603         struct list_head *fs_uuids;
604         int ret = 0;
605
606         fs_uuids = btrfs_scanned_uuids();
607
608         list_for_each_entry(cur_fs, all_uuids, list) {
609                 device = list_first_entry(&cur_fs->devices,
610                                                 struct btrfs_device, dev_list);
611                 if (!device)
612                         continue;
613
614                 /* skip fs without seeds */
615                 if (!has_seed_devices(cur_fs))
616                         continue;
617
618                 /*
619                  * open_ctree_* detects seed/sprout mapping
620                  */
621                 fs_info = open_ctree_fs_info(device->name, 0, 0, 0,
622                                                 OPEN_CTREE_PARTIAL);
623                 if (!fs_info)
624                         continue;
625
626                 /*
627                  * copy the seed chain under the opened fs
628                  */
629                 opened_fs = fs_info->fs_devices;
630                 cur_seed = cur_fs;
631                 while (opened_fs->seed) {
632                         seed_copy = malloc(sizeof(*seed_copy));
633                         if (!seed_copy) {
634                                 ret = -ENOMEM;
635                                 goto fail_out;
636                         }
637                         ret = find_and_copy_seed(opened_fs->seed, seed_copy,
638                                                  fs_uuids);
639                         if (ret) {
640                                 free(seed_copy);
641                                 goto fail_out;
642                         }
643
644                         cur_seed->seed = seed_copy;
645
646                         opened_fs = opened_fs->seed;
647                         cur_seed = cur_seed->seed;
648                 }
649
650                 close_ctree(fs_info->chunk_root);
651         }
652
653 out:
654         return ret;
655 fail_out:
656         close_ctree(fs_info->chunk_root);
657         goto out;
658 }
659
660 static const char * const cmd_filesystem_show_usage[] = {
661         "btrfs filesystem show [options] [<path>|<uuid>|<device>|label]",
662         "Show the structure of a filesystem",
663         "-d|--all-devices   show only disks under /dev containing btrfs filesystem",
664         "-m|--mounted       show only mounted btrfs",
665         HELPINFO_UNITS_LONG,
666         "If no argument is given, structure of all present filesystems is shown.",
667         NULL
668 };
669
670 static int cmd_filesystem_show(int argc, char **argv)
671 {
672         LIST_HEAD(all_uuids);
673         struct btrfs_fs_devices *fs_devices;
674         char *search = NULL;
675         int ret;
676         /* default, search both kernel and udev */
677         int where = -1;
678         int type = 0;
679         char mp[PATH_MAX];
680         char path[PATH_MAX];
681         u8 fsid[BTRFS_FSID_SIZE];
682         char uuid_buf[BTRFS_UUID_UNPARSED_SIZE];
683         unsigned unit_mode;
684         int found = 0;
685
686         unit_mode = get_unit_mode_from_arg(&argc, argv, 0);
687
688         while (1) {
689                 int c;
690                 static const struct option long_options[] = {
691                         { "all-devices", no_argument, NULL, 'd'},
692                         { "mounted", no_argument, NULL, 'm'},
693                         { NULL, 0, NULL, 0 }
694                 };
695
696                 c = getopt_long(argc, argv, "dm", long_options, NULL);
697                 if (c < 0)
698                         break;
699                 switch (c) {
700                 case 'd':
701                         where = BTRFS_SCAN_LBLKID;
702                         break;
703                 case 'm':
704                         where = BTRFS_SCAN_MOUNTED;
705                         break;
706                 default:
707                         usage(cmd_filesystem_show_usage);
708                 }
709         }
710
711         if (check_argc_max(argc, optind + 1))
712                 usage(cmd_filesystem_show_usage);
713
714         if (argc > optind) {
715                 search = argv[optind];
716                 if (*search == 0)
717                         usage(cmd_filesystem_show_usage);
718                 type = check_arg_type(search);
719
720                 /*
721                  * For search is a device:
722                  *     realpath do /dev/mapper/XX => /dev/dm-X
723                  *     which is required by BTRFS_SCAN_DEV
724                  * For search is a mountpoint:
725                  *     realpath do  /mnt/btrfs/  => /mnt/btrfs
726                  *     which shall be recognized by btrfs_scan_kernel()
727                  */
728                 if (realpath(search, path))
729                         search = path;
730
731                 /*
732                  * Needs special handling if input arg is block dev And if
733                  * input arg is mount-point just print it right away
734                  */
735                 if (type == BTRFS_ARG_BLKDEV && where != BTRFS_SCAN_LBLKID) {
736                         ret = get_btrfs_mount(search, mp, sizeof(mp));
737                         if (!ret) {
738                                 /* given block dev is mounted */
739                                 search = mp;
740                                 type = BTRFS_ARG_MNTPOINT;
741                         } else {
742                                 ret = dev_to_fsid(search, fsid);
743                                 if (ret) {
744                                         error("no btrfs on %s", search);
745                                         return 1;
746                                 }
747                                 uuid_unparse(fsid, uuid_buf);
748                                 search = uuid_buf;
749                                 type = BTRFS_ARG_UUID;
750                                 goto devs_only;
751                         }
752                 }
753         }
754
755         if (where == BTRFS_SCAN_LBLKID)
756                 goto devs_only;
757
758         /* show mounted btrfs */
759         ret = btrfs_scan_kernel(search, unit_mode);
760         if (search && !ret) {
761                 /* since search is found we are done */
762                 goto out;
763         }
764
765         /* shows mounted only */
766         if (where == BTRFS_SCAN_MOUNTED)
767                 goto out;
768
769 devs_only:
770         ret = btrfs_scan_devices();
771
772         if (ret) {
773                 error("blkid device scan returned %d", ret);
774                 return 1;
775         }
776
777         ret = search_umounted_fs_uuids(&all_uuids, search, &found);
778         if (ret < 0) {
779                 error("searching target device returned error %d", ret);
780                 return 1;
781         }
782
783         /*
784          * The seed/sprout mapping are not detected yet,
785          * do mapping build for all umounted fs
786          */
787         ret = map_seed_devices(&all_uuids);
788         if (ret) {
789                 error("mapping seed devices returned error %d", ret);
790                 return 1;
791         }
792
793         list_for_each_entry(fs_devices, &all_uuids, list)
794                 print_one_uuid(fs_devices, unit_mode);
795
796         if (search && !found) {
797                 error("not a valid btrfs filesystem: %s", search);
798                 ret = 1;
799         }
800         while (!list_empty(&all_uuids)) {
801                 fs_devices = list_entry(all_uuids.next,
802                                         struct btrfs_fs_devices, list);
803                 free_fs_devices(fs_devices);
804         }
805 out:
806         free_seen_fsid(seen_fsid_hash);
807         return ret;
808 }
809
810 static const char * const cmd_filesystem_sync_usage[] = {
811         "btrfs filesystem sync <path>",
812         "Force a sync on a filesystem",
813         NULL
814 };
815
816 static int cmd_filesystem_sync(int argc, char **argv)
817 {
818         int     fd, res, e;
819         char    *path;
820         DIR     *dirstream = NULL;
821
822         clean_args_no_options(argc, argv, cmd_filesystem_sync_usage);
823
824         if (check_argc_exact(argc - optind, 1))
825                 usage(cmd_filesystem_sync_usage);
826
827         path = argv[optind];
828
829         fd = btrfs_open_dir(path, &dirstream, 1);
830         if (fd < 0)
831                 return 1;
832
833         res = ioctl(fd, BTRFS_IOC_SYNC);
834         e = errno;
835         close_file_or_dir(fd, dirstream);
836         if( res < 0 ){
837                 error("sync ioctl failed on '%s': %s", path, strerror(e));
838                 return 1;
839         }
840
841         return 0;
842 }
843
844 static int parse_compress_type(char *s)
845 {
846         if (strcmp(optarg, "zlib") == 0)
847                 return BTRFS_COMPRESS_ZLIB;
848         else if (strcmp(optarg, "lzo") == 0)
849                 return BTRFS_COMPRESS_LZO;
850         else if (strcmp(optarg, "zstd") == 0)
851                 return BTRFS_COMPRESS_ZSTD;
852         else {
853                 error("unknown compression type %s", s);
854                 exit(1);
855         };
856 }
857
858 static const char * const cmd_filesystem_defrag_usage[] = {
859         "btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
860         "Defragment a file or a directory",
861         "",
862         "-v                  be verbose",
863         "-r                  defragment files recursively",
864         "-c[zlib,lzo,zstd]   compress the file while defragmenting",
865         "-f                  flush data to disk immediately after defragmenting",
866         "-s start            defragment only from byte onward",
867         "-l len              defragment only up to len bytes",
868         "-t size             target extent size hint (default: 32M)",
869         "",
870         "Warning: most Linux kernels will break up the ref-links of COW data",
871         "(e.g., files copied with 'cp --reflink', snapshots) which may cause",
872         "considerable increase of space usage. See btrfs-filesystem(8) for",
873         "more information.",
874         NULL
875 };
876
877 static struct btrfs_ioctl_defrag_range_args defrag_global_range;
878 static int defrag_global_verbose;
879 static int defrag_global_errors;
880 static int defrag_callback(const char *fpath, const struct stat *sb,
881                 int typeflag, struct FTW *ftwbuf)
882 {
883         int ret = 0;
884         int err = 0;
885         int fd = 0;
886
887         if ((typeflag == FTW_F) && S_ISREG(sb->st_mode)) {
888                 if (defrag_global_verbose)
889                         printf("%s\n", fpath);
890                 fd = open(fpath, O_RDWR);
891                 if (fd < 0) {
892                         err = errno;
893                         goto error;
894                 }
895                 ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &defrag_global_range);
896                 close(fd);
897                 if (ret && errno == ENOTTY) {
898                         error(
899 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
900                         defrag_global_errors++;
901                         return ENOTTY;
902                 }
903                 if (ret) {
904                         err = errno;
905                         goto error;
906                 }
907         }
908         return 0;
909
910 error:
911         error("defrag failed on %s: %s", fpath, strerror(err));
912         defrag_global_errors++;
913         return 0;
914 }
915
916 static int cmd_filesystem_defrag(int argc, char **argv)
917 {
918         int fd;
919         int flush = 0;
920         u64 start = 0;
921         u64 len = (u64)-1;
922         u64 thresh;
923         int i;
924         int recursive = 0;
925         int ret = 0;
926         int compress_type = BTRFS_COMPRESS_NONE;
927         DIR *dirstream;
928
929         /*
930          * Kernel has a different default (256K) that is supposed to be safe,
931          * but it does not defragment very well. The 32M will likely lead to
932          * better results and is independent of the kernel default. We have to
933          * use the v2 defrag ioctl.
934          */
935         thresh = SZ_32M;
936
937         defrag_global_errors = 0;
938         defrag_global_verbose = 0;
939         defrag_global_errors = 0;
940         while(1) {
941                 int c = getopt(argc, argv, "vrc::fs:l:t:");
942                 if (c < 0)
943                         break;
944
945                 switch(c) {
946                 case 'c':
947                         compress_type = BTRFS_COMPRESS_ZLIB;
948                         if (optarg)
949                                 compress_type = parse_compress_type(optarg);
950                         break;
951                 case 'f':
952                         flush = 1;
953                         break;
954                 case 'v':
955                         defrag_global_verbose = 1;
956                         break;
957                 case 's':
958                         start = parse_size(optarg);
959                         break;
960                 case 'l':
961                         len = parse_size(optarg);
962                         break;
963                 case 't':
964                         thresh = parse_size(optarg);
965                         if (thresh > (u32)-1) {
966                                 warning(
967                             "target extent size %llu too big, trimmed to %u",
968                                         thresh, (u32)-1);
969                                 thresh = (u32)-1;
970                         }
971                         break;
972                 case 'r':
973                         recursive = 1;
974                         break;
975                 default:
976                         usage(cmd_filesystem_defrag_usage);
977                 }
978         }
979
980         if (check_argc_min(argc - optind, 1))
981                 usage(cmd_filesystem_defrag_usage);
982
983         memset(&defrag_global_range, 0, sizeof(defrag_global_range));
984         defrag_global_range.start = start;
985         defrag_global_range.len = len;
986         defrag_global_range.extent_thresh = (u32)thresh;
987         if (compress_type) {
988                 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
989                 defrag_global_range.compress_type = compress_type;
990         }
991         if (flush)
992                 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
993
994         /*
995          * Look for directory arguments and warn if the recursive mode is not
996          * requested, as this is not implemented as recursive defragmentation
997          * in kernel. The stat errors are silent here as we check them below.
998          */
999         if (!recursive) {
1000                 int found = 0;
1001
1002                 for (i = optind; i < argc; i++) {
1003                         struct stat st;
1004
1005                         if (stat(argv[i], &st))
1006                                 continue;
1007
1008                         if (S_ISDIR(st.st_mode)) {
1009                                 warning(
1010                         "directory specified but recursive mode not requested: %s",
1011                                         argv[i]);
1012                                 found = 1;
1013                         }
1014                 }
1015                 if (found) {
1016                         warning(
1017 "a directory passed to the defrag ioctl will not process the files\n"
1018 "recursively but will defragment the subvolume tree and the extent tree.\n"
1019 "If this is not intended, please use option -r .");
1020                 }
1021         }
1022
1023         for (i = optind; i < argc; i++) {
1024                 struct stat st;
1025                 int defrag_err = 0;
1026
1027                 dirstream = NULL;
1028                 fd = open_file_or_dir(argv[i], &dirstream);
1029                 if (fd < 0) {
1030                         error("cannot open %s: %s", argv[i],
1031                                         strerror(errno));
1032                         defrag_global_errors++;
1033                         close_file_or_dir(fd, dirstream);
1034                         continue;
1035                 }
1036                 if (fstat(fd, &st)) {
1037                         error("failed to stat %s: %s",
1038                                         argv[i], strerror(errno));
1039                         defrag_global_errors++;
1040                         close_file_or_dir(fd, dirstream);
1041                         continue;
1042                 }
1043                 if (!(S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))) {
1044                         error("%s is not a directory or a regular file",
1045                                         argv[i]);
1046                         defrag_global_errors++;
1047                         close_file_or_dir(fd, dirstream);
1048                         continue;
1049                 }
1050                 if (recursive && S_ISDIR(st.st_mode)) {
1051                         ret = nftw(argv[i], defrag_callback, 10,
1052                                                 FTW_MOUNT | FTW_PHYS);
1053                         if (ret == ENOTTY)
1054                                 exit(1);
1055                         /* errors are handled in the callback */
1056                         ret = 0;
1057                 } else {
1058                         if (defrag_global_verbose)
1059                                 printf("%s\n", argv[i]);
1060                         ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE,
1061                                         &defrag_global_range);
1062                         defrag_err = errno;
1063                 }
1064                 close_file_or_dir(fd, dirstream);
1065                 if (ret && defrag_err == ENOTTY) {
1066                         error(
1067 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
1068                         defrag_global_errors++;
1069                         break;
1070                 }
1071                 if (ret) {
1072                         error("defrag failed on %s: %s", argv[i],
1073                                         strerror(defrag_err));
1074                         defrag_global_errors++;
1075                 }
1076         }
1077         if (defrag_global_errors)
1078                 fprintf(stderr, "total %d failures\n", defrag_global_errors);
1079
1080         return !!defrag_global_errors;
1081 }
1082
1083 static const char * const cmd_filesystem_resize_usage[] = {
1084         "btrfs filesystem resize [devid:][+/-]<newsize>[kKmMgGtTpPeE]|[devid:]max <path>",
1085         "Resize a filesystem",
1086         "If 'max' is passed, the filesystem will occupy all available space",
1087         "on the device 'devid'.",
1088         "[kK] means KiB, which denotes 1KiB = 1024B, 1MiB = 1024KiB, etc.",
1089         NULL
1090 };
1091
1092 static int cmd_filesystem_resize(int argc, char **argv)
1093 {
1094         struct btrfs_ioctl_vol_args     args;
1095         int     fd, res, len, e;
1096         char    *amount, *path;
1097         DIR     *dirstream = NULL;
1098         struct stat st;
1099
1100         clean_args_no_options_relaxed(argc, argv, cmd_filesystem_resize_usage);
1101
1102         if (check_argc_exact(argc - optind, 2))
1103                 usage(cmd_filesystem_resize_usage);
1104
1105         amount = argv[optind];
1106         path = argv[optind + 1];
1107
1108         len = strlen(amount);
1109         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
1110                 error("resize value too long (%s)", amount);
1111                 return 1;
1112         }
1113
1114         res = stat(path, &st);
1115         if (res < 0) {
1116                 error("resize: cannot stat %s: %s", path, strerror(errno));
1117                 return 1;
1118         }
1119         if (!S_ISDIR(st.st_mode)) {
1120                 error("resize works on mounted filesystems and accepts only\n"
1121                         "directories as argument. Passing file containing a btrfs image\n"
1122                         "would resize the underlying filesystem instead of the image.\n");
1123                 return 1;
1124         }
1125
1126         fd = btrfs_open_dir(path, &dirstream, 1);
1127         if (fd < 0)
1128                 return 1;
1129
1130         printf("Resize '%s' of '%s'\n", path, amount);
1131         memset(&args, 0, sizeof(args));
1132         strncpy_null(args.name, amount);
1133         res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
1134         e = errno;
1135         close_file_or_dir(fd, dirstream);
1136         if( res < 0 ){
1137                 switch (e) {
1138                 case EFBIG:
1139                         error("unable to resize '%s': no enough free space",
1140                                 path);
1141                         break;
1142                 default:
1143                         error("unable to resize '%s': %s", path, strerror(e));
1144                         break;
1145                 }
1146                 return 1;
1147         } else if (res > 0) {
1148                 const char *err_str = btrfs_err_str(res);
1149
1150                 if (err_str) {
1151                         error("resizing of '%s' failed: %s", path, err_str);
1152                 } else {
1153                         error("resizing of '%s' failed: unknown error %d",
1154                                 path, res);
1155                 }
1156                 return 1;
1157         }
1158         return 0;
1159 }
1160
1161 static const char * const cmd_filesystem_label_usage[] = {
1162         "btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
1163         "Get or change the label of a filesystem",
1164         "With one argument, get the label of filesystem on <device>.",
1165         "If <newlabel> is passed, set the filesystem label to <newlabel>.",
1166         NULL
1167 };
1168
1169 static int cmd_filesystem_label(int argc, char **argv)
1170 {
1171         clean_args_no_options(argc, argv, cmd_filesystem_label_usage);
1172
1173         if (check_argc_min(argc - optind, 1) ||
1174                         check_argc_max(argc - optind, 2))
1175                 usage(cmd_filesystem_label_usage);
1176
1177         if (argc - optind > 1) {
1178                 return set_label(argv[optind], argv[optind + 1]);
1179         } else {
1180                 char label[BTRFS_LABEL_SIZE];
1181                 int ret;
1182
1183                 ret = get_label(argv[optind], label);
1184                 if (!ret)
1185                         fprintf(stdout, "%s\n", label);
1186
1187                 return ret;
1188         }
1189 }
1190
1191 static const char filesystem_cmd_group_info[] =
1192 "overall filesystem tasks and information";
1193
1194 const struct cmd_group filesystem_cmd_group = {
1195         filesystem_cmd_group_usage, filesystem_cmd_group_info, {
1196                 { "df", cmd_filesystem_df, cmd_filesystem_df_usage, NULL, 0 },
1197                 { "du", cmd_filesystem_du, cmd_filesystem_du_usage, NULL, 0 },
1198                 { "show", cmd_filesystem_show, cmd_filesystem_show_usage, NULL,
1199                         0 },
1200                 { "sync", cmd_filesystem_sync, cmd_filesystem_sync_usage, NULL,
1201                         0 },
1202                 { "defragment", cmd_filesystem_defrag,
1203                         cmd_filesystem_defrag_usage, NULL, 0 },
1204                 { "balance", cmd_balance, NULL, &balance_cmd_group,
1205                         CMD_HIDDEN },
1206                 { "resize", cmd_filesystem_resize, cmd_filesystem_resize_usage,
1207                         NULL, 0 },
1208                 { "label", cmd_filesystem_label, cmd_filesystem_label_usage,
1209                         NULL, 0 },
1210                 { "usage", cmd_filesystem_usage,
1211                         cmd_filesystem_usage_usage, NULL, 0 },
1212
1213                 NULL_CMD_STRUCT
1214         }
1215 };
1216
1217 int cmd_filesystem(int argc, char **argv)
1218 {
1219         return handle_command_group(&filesystem_cmd_group, argc, argv);
1220 }