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