Btrfs-progs: enhance btrfs qgroup to print the result as a table
[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 #define _XOPEN_SOURCE 500
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/ioctl.h>
23 #include <errno.h>
24 #include <uuid/uuid.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <ftw.h>
28
29 #include "kerncompat.h"
30 #include "ctree.h"
31 #include "ioctl.h"
32 #include "utils.h"
33 #include "volumes.h"
34 #include "version.h"
35 #include "commands.h"
36 #include "list_sort.h"
37
38 static const char * const filesystem_cmd_group_usage[] = {
39         "btrfs filesystem [<group>] <command> [<args>]",
40         NULL
41 };
42
43 static const char * const cmd_df_usage[] = {
44         "btrfs filesystem df <path>",
45         "Show space usage information for a mount point",
46         NULL
47 };
48
49 static char *group_type_str(u64 flag)
50 {
51         switch (flag & BTRFS_BLOCK_GROUP_TYPE_MASK) {
52         case BTRFS_BLOCK_GROUP_DATA:
53                 return "Data";
54         case BTRFS_BLOCK_GROUP_SYSTEM:
55                 return "System";
56         case BTRFS_BLOCK_GROUP_METADATA:
57                 return "Metadata";
58         case BTRFS_BLOCK_GROUP_DATA|BTRFS_BLOCK_GROUP_METADATA:
59                 return "Data+Metadata";
60         default:
61                 return "unknown";
62         }
63 }
64
65 static char *group_profile_str(u64 flag)
66 {
67         switch (flag & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
68         case 0:
69                 return "single";
70         case BTRFS_BLOCK_GROUP_RAID0:
71                 return "RAID0";
72         case BTRFS_BLOCK_GROUP_RAID1:
73                 return "RAID1";
74         case BTRFS_BLOCK_GROUP_RAID5:
75                 return "RAID5";
76         case BTRFS_BLOCK_GROUP_RAID6:
77                 return "RAID6";
78         case BTRFS_BLOCK_GROUP_DUP:
79                 return "DUP";
80         case BTRFS_BLOCK_GROUP_RAID10:
81                 return "RAID10";
82         default:
83                 return "unknown";
84         }
85 }
86
87 static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret)
88 {
89         u64 count = 0;
90         int ret, e;
91         struct btrfs_ioctl_space_args *sargs;
92
93         sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
94         if (!sargs)
95                 return -ENOMEM;
96
97         sargs->space_slots = 0;
98         sargs->total_spaces = 0;
99
100         ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
101         e = errno;
102         if (ret) {
103                 fprintf(stderr, "ERROR: couldn't get space info - %s\n",
104                         strerror(e));
105                 free(sargs);
106                 return ret;
107         }
108         if (!sargs->total_spaces) {
109                 free(sargs);
110                 return 0;
111         }
112         count = sargs->total_spaces;
113         free(sargs);
114
115         sargs = malloc(sizeof(struct btrfs_ioctl_space_args) +
116                         (count * sizeof(struct btrfs_ioctl_space_info)));
117         if (!sargs)
118                 ret = -ENOMEM;
119
120         sargs->space_slots = count;
121         sargs->total_spaces = 0;
122         ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
123         e = errno;
124         if (ret) {
125                 fprintf(stderr, "ERROR: get space info count %llu - %s\n",
126                                 count, strerror(e));
127                 free(sargs);
128                 return ret;
129         }
130         *sargs_ret = sargs;
131         return 0;
132 }
133
134 static void print_df(struct btrfs_ioctl_space_args *sargs)
135 {
136         u64 i;
137         struct btrfs_ioctl_space_info *sp = sargs->spaces;
138
139         for (i = 0; i < sargs->total_spaces; i++, sp++) {
140                 printf("%s, %s: total=%s, used=%s\n",
141                         group_type_str(sp->flags),
142                         group_profile_str(sp->flags),
143                         pretty_size(sp->total_bytes),
144                         pretty_size(sp->used_bytes));
145         }
146 }
147
148 static int cmd_df(int argc, char **argv)
149 {
150         struct btrfs_ioctl_space_args *sargs = NULL;
151         int ret;
152         int fd;
153         char *path;
154         DIR  *dirstream = NULL;
155
156         if (check_argc_exact(argc, 2))
157                 usage(cmd_df_usage);
158
159         path = argv[1];
160
161         fd = open_file_or_dir(path, &dirstream);
162         if (fd < 0) {
163                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
164                 return 1;
165         }
166         ret = get_df(fd, &sargs);
167
168         if (!ret && sargs) {
169                 print_df(sargs);
170                 free(sargs);
171         } else {
172                 fprintf(stderr, "ERROR: get_df failed %s\n", strerror(ret));
173         }
174
175         close_file_or_dir(fd, dirstream);
176         return !!ret;
177 }
178
179 static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search)
180 {
181         char uuidbuf[37];
182         struct list_head *cur;
183         struct btrfs_device *device;
184         int search_len = strlen(search);
185
186         search_len = min(search_len, 37);
187         uuid_unparse(fs_devices->fsid, uuidbuf);
188         if (!strncmp(uuidbuf, search, search_len))
189                 return 1;
190
191         list_for_each(cur, &fs_devices->devices) {
192                 device = list_entry(cur, struct btrfs_device, dev_list);
193                 if ((device->label && strcmp(device->label, search) == 0) ||
194                     strcmp(device->name, search) == 0)
195                         return 1;
196         }
197         return 0;
198 }
199
200 /*
201  * Sort devices by devid, ascending
202  */
203 static int cmp_device_id(void *priv, struct list_head *a,
204                 struct list_head *b)
205 {
206         const struct btrfs_device *da = list_entry(a, struct btrfs_device,
207                         dev_list);
208         const struct btrfs_device *db = list_entry(b, struct btrfs_device,
209                         dev_list);
210
211         return da->devid < db->devid ? -1 :
212                 da->devid > db->devid ? 1 : 0;
213 }
214
215 static void print_one_uuid(struct btrfs_fs_devices *fs_devices)
216 {
217         char uuidbuf[37];
218         struct list_head *cur;
219         struct btrfs_device *device;
220         u64 devs_found = 0;
221         u64 total;
222
223         uuid_unparse(fs_devices->fsid, uuidbuf);
224         device = list_entry(fs_devices->devices.next, struct btrfs_device,
225                             dev_list);
226         if (device->label && device->label[0])
227                 printf("Label: '%s' ", device->label);
228         else
229                 printf("Label: none ");
230
231
232         total = device->total_devs;
233         printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf,
234                (unsigned long long)total,
235                pretty_size(device->super_bytes_used));
236
237         list_sort(NULL, &fs_devices->devices, cmp_device_id);
238         list_for_each(cur, &fs_devices->devices) {
239                 device = list_entry(cur, struct btrfs_device, dev_list);
240
241                 printf("\tdevid %4llu size %s used %s path %s\n",
242                        (unsigned long long)device->devid,
243                        pretty_size(device->total_bytes),
244                        pretty_size(device->bytes_used), device->name);
245
246                 devs_found++;
247         }
248         if (devs_found < total) {
249                 printf("\t*** Some devices missing\n");
250         }
251         printf("\n");
252 }
253
254 static const char * const cmd_show_usage[] = {
255         "btrfs filesystem show [--all-devices|<uuid>]",
256         "Show the structure of a filesystem",
257         "If no argument is given, structure of all present filesystems is shown.",
258         NULL
259 };
260
261 static int cmd_show(int argc, char **argv)
262 {
263         struct list_head *all_uuids;
264         struct btrfs_fs_devices *fs_devices;
265         struct list_head *cur_uuid;
266         char *search = NULL;
267         int ret;
268         int where = BTRFS_SCAN_PROC;
269         int searchstart = 1;
270
271         if( argc > 1 && !strcmp(argv[1],"--all-devices")){
272                 where = BTRFS_SCAN_DEV;
273                 searchstart += 1;
274         }
275
276         if (check_argc_max(argc, searchstart + 1))
277                 usage(cmd_show_usage);
278
279         ret = scan_for_btrfs(where, 0);
280
281         if (ret){
282                 fprintf(stderr, "ERROR: error %d while scanning\n", ret);
283                 return 1;
284         }
285         
286         if(searchstart < argc)
287                 search = argv[searchstart];
288
289         all_uuids = btrfs_scanned_uuids();
290         list_for_each(cur_uuid, all_uuids) {
291                 fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices,
292                                         list);
293                 if (search && uuid_search(fs_devices, search) == 0)
294                         continue;
295                 print_one_uuid(fs_devices);
296         }
297         printf("%s\n", BTRFS_BUILD_VERSION);
298         return 0;
299 }
300
301 static const char * const cmd_sync_usage[] = {
302         "btrfs filesystem sync <path>",
303         "Force a sync on a filesystem",
304         NULL
305 };
306
307 static int cmd_sync(int argc, char **argv)
308 {
309         int     fd, res, e;
310         char    *path;
311         DIR     *dirstream = NULL;
312
313         if (check_argc_exact(argc, 2))
314                 usage(cmd_sync_usage);
315
316         path = argv[1];
317
318         fd = open_file_or_dir(path, &dirstream);
319         if (fd < 0) {
320                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
321                 return 1;
322         }
323
324         printf("FSSync '%s'\n", path);
325         res = ioctl(fd, BTRFS_IOC_SYNC);
326         e = errno;
327         close_file_or_dir(fd, dirstream);
328         if( res < 0 ){
329                 fprintf(stderr, "ERROR: unable to fs-syncing '%s' - %s\n", 
330                         path, strerror(e));
331                 return 1;
332         }
333
334         return 0;
335 }
336
337 static int parse_compress_type(char *s)
338 {
339         if (strcmp(optarg, "zlib") == 0)
340                 return BTRFS_COMPRESS_ZLIB;
341         else if (strcmp(optarg, "lzo") == 0)
342                 return BTRFS_COMPRESS_LZO;
343         else {
344                 fprintf(stderr, "Unknown compress type %s\n", s);
345                 exit(1);
346         };
347 }
348
349 static const char * const cmd_defrag_usage[] = {
350         "btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
351         "Defragment a file or a directory",
352         "",
353         "-v             be verbose",
354         "-r             defragment files recursively",
355         "-c[zlib,lzo]   compress the file while defragmenting",
356         "-f             flush data to disk immediately after defragmenting",
357         "-s start       defragment only from byte onward",
358         "-l len         defragment only up to len bytes",
359         "-t size        minimal size of file to be considered for defragmenting",
360         NULL
361 };
362
363 static int do_defrag(int fd, int fancy_ioctl,
364                 struct btrfs_ioctl_defrag_range_args *range)
365 {
366         int ret;
367
368         if (!fancy_ioctl)
369                 ret = ioctl(fd, BTRFS_IOC_DEFRAG, NULL);
370         else
371                 ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, range);
372
373         return ret;
374 }
375
376 static int defrag_global_fancy_ioctl;
377 static struct btrfs_ioctl_defrag_range_args defrag_global_range;
378 static int defrag_global_verbose;
379 static int defrag_global_errors;
380 static int defrag_callback(const char *fpath, const struct stat *sb,
381                 int typeflag, struct FTW *ftwbuf)
382 {
383         int ret = 0;
384         int e = 0;
385         int fd = 0;
386
387         if (typeflag == FTW_F) {
388                 if (defrag_global_verbose)
389                         printf("%s\n", fpath);
390                 fd = open(fpath, O_RDWR);
391                 e = errno;
392                 if (fd < 0)
393                         goto error;
394                 ret = do_defrag(fd, defrag_global_fancy_ioctl, &defrag_global_range);
395                 e = errno;
396                 close(fd);
397                 if (ret && e == ENOTTY) {
398                         fprintf(stderr, "ERROR: defrag range ioctl not "
399                                 "supported in this kernel, please try "
400                                 "without any options.\n");
401                         defrag_global_errors++;
402                         return ENOTTY;
403                 }
404                 if (ret)
405                         goto error;
406         }
407         return 0;
408
409 error:
410         fprintf(stderr, "ERROR: defrag failed on %s - %s\n", fpath, strerror(e));
411         defrag_global_errors++;
412         return 0;
413 }
414
415 static int cmd_defrag(int argc, char **argv)
416 {
417         int fd;
418         int flush = 0;
419         u64 start = 0;
420         u64 len = (u64)-1;
421         u32 thresh = 0;
422         int i;
423         int recursive = 0;
424         int ret = 0;
425         struct btrfs_ioctl_defrag_range_args range;
426         int e = 0;
427         int compress_type = BTRFS_COMPRESS_NONE;
428         DIR *dirstream;
429
430         defrag_global_errors = 0;
431         defrag_global_verbose = 0;
432         defrag_global_errors = 0;
433         defrag_global_fancy_ioctl = 0;
434         optind = 1;
435         while(1) {
436                 int c = getopt(argc, argv, "vrc::fs:l:t:");
437                 if (c < 0)
438                         break;
439
440                 switch(c) {
441                 case 'c':
442                         compress_type = BTRFS_COMPRESS_ZLIB;
443                         if (optarg)
444                                 compress_type = parse_compress_type(optarg);
445                         defrag_global_fancy_ioctl = 1;
446                         break;
447                 case 'f':
448                         flush = 1;
449                         defrag_global_fancy_ioctl = 1;
450                         break;
451                 case 'v':
452                         defrag_global_verbose = 1;
453                         break;
454                 case 's':
455                         start = parse_size(optarg);
456                         defrag_global_fancy_ioctl = 1;
457                         break;
458                 case 'l':
459                         len = parse_size(optarg);
460                         defrag_global_fancy_ioctl = 1;
461                         break;
462                 case 't':
463                         thresh = parse_size(optarg);
464                         defrag_global_fancy_ioctl = 1;
465                         break;
466                 case 'r':
467                         recursive = 1;
468                         break;
469                 default:
470                         usage(cmd_defrag_usage);
471                 }
472         }
473
474         if (check_argc_min(argc - optind, 1))
475                 usage(cmd_defrag_usage);
476
477         memset(&defrag_global_range, 0, sizeof(range));
478         defrag_global_range.start = start;
479         defrag_global_range.len = len;
480         defrag_global_range.extent_thresh = thresh;
481         if (compress_type) {
482                 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
483                 defrag_global_range.compress_type = compress_type;
484         }
485         if (flush)
486                 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
487
488         for (i = optind; i < argc; i++) {
489                 dirstream = NULL;
490                 fd = open_file_or_dir(argv[i], &dirstream);
491                 if (fd < 0) {
492                         fprintf(stderr, "ERROR: failed to open %s - %s\n", argv[i],
493                                         strerror(errno));
494                         defrag_global_errors++;
495                         close_file_or_dir(fd, dirstream);
496                         continue;
497                 }
498                 if (recursive) {
499                         struct stat st;
500
501                         fstat(fd, &st);
502                         if (S_ISDIR(st.st_mode)) {
503                                 ret = nftw(argv[i], defrag_callback, 10,
504                                                 FTW_MOUNT | FTW_PHYS);
505                                 if (ret == ENOTTY)
506                                         exit(1);
507                                 /* errors are handled in the callback */
508                                 ret = 0;
509                         } else {
510                                 if (defrag_global_verbose)
511                                         printf("%s\n", argv[i]);
512                                 ret = do_defrag(fd, defrag_global_fancy_ioctl,
513                                                 &defrag_global_range);
514                                 e = errno;
515                         }
516                 } else {
517                         if (defrag_global_verbose)
518                                 printf("%s\n", argv[i]);
519                         ret = do_defrag(fd, defrag_global_fancy_ioctl,
520                                         &defrag_global_range);
521                         e = errno;
522                 }
523                 close_file_or_dir(fd, dirstream);
524                 if (ret && e == ENOTTY) {
525                         fprintf(stderr, "ERROR: defrag range ioctl not "
526                                 "supported in this kernel, please try "
527                                 "without any options.\n");
528                         defrag_global_errors++;
529                         break;
530                 }
531                 if (ret) {
532                         fprintf(stderr, "ERROR: defrag failed on %s - %s\n",
533                                 argv[i], strerror(e));
534                         defrag_global_errors++;
535                 }
536         }
537         if (defrag_global_verbose)
538                 printf("%s\n", BTRFS_BUILD_VERSION);
539         if (defrag_global_errors)
540                 fprintf(stderr, "total %d failures\n", defrag_global_errors);
541
542         return !!defrag_global_errors;
543 }
544
545 static const char * const cmd_resize_usage[] = {
546         "btrfs filesystem resize [devid:][+/-]<newsize>[gkm]|[devid:]max <path>",
547         "Resize a filesystem",
548         "If 'max' is passed, the filesystem will occupy all available space",
549         "on the device 'devid'.",
550         NULL
551 };
552
553 static int cmd_resize(int argc, char **argv)
554 {
555         struct btrfs_ioctl_vol_args     args;
556         int     fd, res, len, e;
557         char    *amount, *path;
558         DIR     *dirstream = NULL;
559
560         if (check_argc_exact(argc, 3))
561                 usage(cmd_resize_usage);
562
563         amount = argv[1];
564         path = argv[2];
565
566         len = strlen(amount);
567         if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
568                 fprintf(stderr, "ERROR: size value too long ('%s)\n",
569                         amount);
570                 return 1;
571         }
572
573         fd = open_file_or_dir(path, &dirstream);
574         if (fd < 0) {
575                 fprintf(stderr, "ERROR: can't access to '%s'\n", path);
576                 return 1;
577         }
578
579         printf("Resize '%s' of '%s'\n", path, amount);
580         strncpy_null(args.name, amount);
581         res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
582         e = errno;
583         close_file_or_dir(fd, dirstream);
584         if( res < 0 ){
585                 fprintf(stderr, "ERROR: unable to resize '%s' - %s\n", 
586                         path, strerror(e));
587                 return 1;
588         }
589         return 0;
590 }
591
592 static const char * const cmd_label_usage[] = {
593         "btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
594         "Get or change the label of a filesystem",
595         "With one argument, get the label of filesystem on <device>.",
596         "If <newlabel> is passed, set the filesystem label to <newlabel>.",
597         NULL
598 };
599
600 static int cmd_label(int argc, char **argv)
601 {
602         if (check_argc_min(argc, 2) || check_argc_max(argc, 3))
603                 usage(cmd_label_usage);
604
605         if (argc > 2)
606                 return set_label(argv[1], argv[2]);
607         else
608                 return get_label(argv[1]);
609 }
610
611 const struct cmd_group filesystem_cmd_group = {
612         filesystem_cmd_group_usage, NULL, {
613                 { "df", cmd_df, cmd_df_usage, NULL, 0 },
614                 { "show", cmd_show, cmd_show_usage, NULL, 0 },
615                 { "sync", cmd_sync, cmd_sync_usage, NULL, 0 },
616                 { "defragment", cmd_defrag, cmd_defrag_usage, NULL, 0 },
617                 { "balance", cmd_balance, NULL, &balance_cmd_group, 1 },
618                 { "resize", cmd_resize, cmd_resize_usage, NULL, 0 },
619                 { "label", cmd_label, cmd_label_usage, NULL, 0 },
620                 NULL_CMD_STRUCT
621         }
622 };
623
624 int cmd_filesystem(int argc, char **argv)
625 {
626         return handle_command_group(&filesystem_cmd_group, argc, argv);
627 }