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