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