btrfs-progs: move command definitions to commands.h
[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 "help.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 struct btrfs_ioctl_defrag_range_args defrag_global_range;
976 static int defrag_global_verbose;
977 static int defrag_global_errors;
978 static int defrag_callback(const char *fpath, const struct stat *sb,
979                 int typeflag, struct FTW *ftwbuf)
980 {
981         int ret = 0;
982         int err = 0;
983         int fd = 0;
984
985         if ((typeflag == FTW_F) && S_ISREG(sb->st_mode)) {
986                 if (defrag_global_verbose)
987                         printf("%s\n", fpath);
988                 fd = open(fpath, O_RDWR);
989                 if (fd < 0) {
990                         err = errno;
991                         goto error;
992                 }
993                 ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &defrag_global_range);
994                 close(fd);
995                 if (ret && errno == ENOTTY) {
996                         error(
997 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
998                         defrag_global_errors++;
999                         return ENOTTY;
1000                 }
1001                 if (ret) {
1002                         err = errno;
1003                         goto error;
1004                 }
1005         }
1006         return 0;
1007
1008 error:
1009         error("defrag failed on %s: %s", fpath, strerror(err));
1010         defrag_global_errors++;
1011         return 0;
1012 }
1013
1014 static int cmd_filesystem_defrag(int argc, char **argv)
1015 {
1016         int fd;
1017         int flush = 0;
1018         u64 start = 0;
1019         u64 len = (u64)-1;
1020         u64 thresh;
1021         int i;
1022         int recursive = 0;
1023         int ret = 0;
1024         int compress_type = BTRFS_COMPRESS_NONE;
1025         DIR *dirstream;
1026
1027         /*
1028          * Kernel has a different default (256K) that is supposed to be safe,
1029          * but it does not defragment very well. The 32M will likely lead to
1030          * better results and is independent of the kernel default. We have to
1031          * use the v2 defrag ioctl.
1032          */
1033         thresh = SZ_32M;
1034
1035         defrag_global_errors = 0;
1036         defrag_global_verbose = 0;
1037         defrag_global_errors = 0;
1038         while(1) {
1039                 int c = getopt(argc, argv, "vrc::fs:l:t:");
1040                 if (c < 0)
1041                         break;
1042
1043                 switch(c) {
1044                 case 'c':
1045                         compress_type = BTRFS_COMPRESS_ZLIB;
1046                         if (optarg)
1047                                 compress_type = parse_compress_type(optarg);
1048                         break;
1049                 case 'f':
1050                         flush = 1;
1051                         break;
1052                 case 'v':
1053                         defrag_global_verbose = 1;
1054                         break;
1055                 case 's':
1056                         start = parse_size(optarg);
1057                         break;
1058                 case 'l':
1059                         len = parse_size(optarg);
1060                         break;
1061                 case 't':
1062                         thresh = parse_size(optarg);
1063                         if (thresh > (u32)-1) {
1064                                 warning(
1065                             "target extent size %llu too big, trimmed to %u",
1066                                         thresh, (u32)-1);
1067                                 thresh = (u32)-1;
1068                         }
1069                         break;
1070                 case 'r':
1071                         recursive = 1;
1072                         break;
1073                 default:
1074                         usage(cmd_filesystem_defrag_usage);
1075                 }
1076         }
1077
1078         if (check_argc_min(argc - optind, 1))
1079                 usage(cmd_filesystem_defrag_usage);
1080
1081         memset(&defrag_global_range, 0, sizeof(defrag_global_range));
1082         defrag_global_range.start = start;
1083         defrag_global_range.len = len;
1084         defrag_global_range.extent_thresh = (u32)thresh;
1085         if (compress_type) {
1086                 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
1087                 defrag_global_range.compress_type = compress_type;
1088         }
1089         if (flush)
1090                 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
1091
1092         /*
1093          * Look for directory arguments and warn if the recursive mode is not
1094          * requested, as this is not implemented as recursive defragmentation
1095          * in kernel. The stat errors are silent here as we check them below.
1096          */
1097         if (!recursive) {
1098                 int found = 0;
1099
1100                 for (i = optind; i < argc; i++) {
1101                         struct stat st;
1102
1103                         if (stat(argv[i], &st))
1104                                 continue;
1105
1106                         if (S_ISDIR(st.st_mode)) {
1107                                 warning(
1108                         "directory specified but recursive mode not requested: %s",
1109                                         argv[i]);
1110                                 found = 1;
1111                         }
1112                 }
1113                 if (found) {
1114                         warning(
1115 "a directory passed to the defrag ioctl will not process the files\n"
1116 "recursively but will defragment the subvolume tree and the extent tree.\n"
1117 "If this is not intended, please use option -r .");
1118                 }
1119         }
1120
1121         for (i = optind; i < argc; i++) {
1122                 struct stat st;
1123                 int defrag_err = 0;
1124
1125                 dirstream = NULL;
1126                 fd = open_file_or_dir(argv[i], &dirstream);
1127                 if (fd < 0) {
1128                         error("cannot open %s: %s", argv[i],
1129                                         strerror(errno));
1130                         defrag_global_errors++;
1131                         close_file_or_dir(fd, dirstream);
1132                         continue;
1133                 }
1134                 if (fstat(fd, &st)) {
1135                         error("failed to stat %s: %s",
1136                                         argv[i], strerror(errno));
1137                         defrag_global_errors++;
1138                         close_file_or_dir(fd, dirstream);
1139                         continue;
1140                 }
1141                 if (!(S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))) {
1142                         error("%s is not a directory or a regular file",
1143                                         argv[i]);
1144                         defrag_global_errors++;
1145                         close_file_or_dir(fd, dirstream);
1146                         continue;
1147                 }
1148                 if (recursive && S_ISDIR(st.st_mode)) {
1149                         ret = nftw(argv[i], defrag_callback, 10,
1150                                                 FTW_MOUNT | FTW_PHYS);
1151                         if (ret == ENOTTY)
1152                                 exit(1);
1153                         /* errors are handled in the callback */
1154                         ret = 0;
1155                 } else {
1156                         if (defrag_global_verbose)
1157                                 printf("%s\n", argv[i]);
1158                         ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE,
1159                                         &defrag_global_range);
1160                         defrag_err = errno;
1161                 }
1162                 close_file_or_dir(fd, dirstream);
1163                 if (ret && defrag_err == ENOTTY) {
1164                         error(
1165 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
1166                         defrag_global_errors++;
1167                         break;
1168                 }
1169                 if (ret) {
1170                         error("defrag failed on %s: %s", argv[i],
1171                                         strerror(defrag_err));
1172                         defrag_global_errors++;
1173                 }
1174         }
1175         if (defrag_global_errors)
1176                 fprintf(stderr, "total %d failures\n", defrag_global_errors);
1177
1178         return !!defrag_global_errors;
1179 }
1180
1181 static const char * const cmd_filesystem_resize_usage[] = {
1182         "btrfs filesystem resize [devid:][+/-]<newsize>[kKmMgGtTpPeE]|[devid:]max <path>",
1183         "Resize a filesystem",
1184         "If 'max' is passed, the filesystem will occupy all available space",
1185         "on the device 'devid'.",
1186         "[kK] means KiB, which denotes 1KiB = 1024B, 1MiB = 1024KiB, etc.",
1187         NULL
1188 };
1189
1190 static int cmd_filesystem_resize(int argc, char **argv)
1191 {
1192         struct btrfs_ioctl_vol_args     args;
1193         int     fd, res, len, e;
1194         char    *amount, *path;
1195         DIR     *dirstream = NULL;
1196         struct stat st;
1197
1198         clean_args_no_options_relaxed(argc, argv, cmd_filesystem_resize_usage);
1199
1200         if (check_argc_exact(argc - optind, 2))
1201                 usage(cmd_filesystem_resize_usage);
1202
1203         amount = argv[optind];
1204         path = argv[optind + 1];
1205
1206         len = strlen(amount);
1207         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
1208                 error("resize value too long (%s)", amount);
1209                 return 1;
1210         }
1211
1212         res = stat(path, &st);
1213         if (res < 0) {
1214                 error("resize: cannot stat %s: %s", path, strerror(errno));
1215                 return 1;
1216         }
1217         if (!S_ISDIR(st.st_mode)) {
1218                 error("resize works on mounted filesystems and accepts only\n"
1219                         "directories as argument. Passing file containing a btrfs image\n"
1220                         "would resize the underlying filesystem instead of the image.\n");
1221                 return 1;
1222         }
1223
1224         fd = btrfs_open_dir(path, &dirstream, 1);
1225         if (fd < 0)
1226                 return 1;
1227
1228         printf("Resize '%s' of '%s'\n", path, amount);
1229         memset(&args, 0, sizeof(args));
1230         strncpy_null(args.name, amount);
1231         res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
1232         e = errno;
1233         close_file_or_dir(fd, dirstream);
1234         if( res < 0 ){
1235                 switch (e) {
1236                 case EFBIG:
1237                         error("unable to resize '%s': no enough free space",
1238                                 path);
1239                         break;
1240                 default:
1241                         error("unable to resize '%s': %s", path, strerror(e));
1242                         break;
1243                 }
1244                 return 1;
1245         } else if (res > 0) {
1246                 const char *err_str = btrfs_err_str(res);
1247
1248                 if (err_str) {
1249                         error("resizing of '%s' failed: %s", path, err_str);
1250                 } else {
1251                         error("resizing of '%s' failed: unknown error %d",
1252                                 path, res);
1253                 }
1254                 return 1;
1255         }
1256         return 0;
1257 }
1258
1259 static const char * const cmd_filesystem_label_usage[] = {
1260         "btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
1261         "Get or change the label of a filesystem",
1262         "With one argument, get the label of filesystem on <device>.",
1263         "If <newlabel> is passed, set the filesystem label to <newlabel>.",
1264         NULL
1265 };
1266
1267 static int cmd_filesystem_label(int argc, char **argv)
1268 {
1269         clean_args_no_options(argc, argv, cmd_filesystem_label_usage);
1270
1271         if (check_argc_min(argc - optind, 1) ||
1272                         check_argc_max(argc - optind, 2))
1273                 usage(cmd_filesystem_label_usage);
1274
1275         if (argc - optind > 1) {
1276                 return set_label(argv[optind], argv[optind + 1]);
1277         } else {
1278                 char label[BTRFS_LABEL_SIZE];
1279                 int ret;
1280
1281                 ret = get_label(argv[optind], label);
1282                 if (!ret)
1283                         fprintf(stdout, "%s\n", label);
1284
1285                 return ret;
1286         }
1287 }
1288
1289 static const char filesystem_cmd_group_info[] =
1290 "overall filesystem tasks and information";
1291
1292 const struct cmd_group filesystem_cmd_group = {
1293         filesystem_cmd_group_usage, filesystem_cmd_group_info, {
1294                 { "df", cmd_filesystem_df, cmd_filesystem_df_usage, NULL, 0 },
1295                 { "du", cmd_filesystem_du, cmd_filesystem_du_usage, NULL, 0 },
1296                 { "show", cmd_filesystem_show, cmd_filesystem_show_usage, NULL,
1297                         0 },
1298                 { "sync", cmd_filesystem_sync, cmd_filesystem_sync_usage, NULL,
1299                         0 },
1300                 { "defragment", cmd_filesystem_defrag,
1301                         cmd_filesystem_defrag_usage, NULL, 0 },
1302                 { "balance", cmd_balance, NULL, &balance_cmd_group,
1303                         CMD_HIDDEN },
1304                 { "resize", cmd_filesystem_resize, cmd_filesystem_resize_usage,
1305                         NULL, 0 },
1306                 { "label", cmd_filesystem_label, cmd_filesystem_label_usage,
1307                         NULL, 0 },
1308                 { "usage", cmd_filesystem_usage,
1309                         cmd_filesystem_usage_usage, NULL, 0 },
1310
1311                 NULL_CMD_STRUCT
1312         }
1313 };
1314
1315 int cmd_filesystem(int argc, char **argv)
1316 {
1317         return handle_command_group(&filesystem_cmd_group, argc, argv);
1318 }