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