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.
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.
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.
21 #include <sys/ioctl.h>
23 #include <uuid/uuid.h>
26 #include "kerncompat.h"
35 #include "btrfslabel.h"
37 static const char filesystem_cmd_group_usage
[] =
38 "btrfs filesystem [<group>] <command> [<args>]";
40 static const char * const cmd_df_usage
[] = {
41 "btrfs filesystem df <path>",
42 "Show space usage information for a mount point",
46 static int cmd_df(int argc
, char **argv
)
48 struct btrfs_ioctl_space_args
*sargs
;
55 if (check_argc_exact(argc
, 2))
60 fd
= open_file_or_dir(path
);
62 fprintf(stderr
, "ERROR: can't access to '%s'\n", path
);
66 sargs
= malloc(sizeof(struct btrfs_ioctl_space_args
));
70 sargs
->space_slots
= 0;
71 sargs
->total_spaces
= 0;
73 ret
= ioctl(fd
, BTRFS_IOC_SPACE_INFO
, sargs
);
76 fprintf(stderr
, "ERROR: couldn't get space info on '%s' - %s\n",
81 if (!sargs
->total_spaces
)
84 count
= sargs
->total_spaces
;
86 sargs
= realloc(sargs
, sizeof(struct btrfs_ioctl_space_args
) +
87 (count
* sizeof(struct btrfs_ioctl_space_info
)));
91 sargs
->space_slots
= count
;
92 sargs
->total_spaces
= 0;
94 ret
= ioctl(fd
, BTRFS_IOC_SPACE_INFO
, sargs
);
97 fprintf(stderr
, "ERROR: couldn't get space info on '%s' - %s\n",
104 for (i
= 0; i
< sargs
->total_spaces
; i
++) {
105 char description
[80];
109 u64 flags
= sargs
->spaces
[i
].flags
;
111 memset(description
, 0, 80);
113 if (flags
& BTRFS_BLOCK_GROUP_DATA
) {
114 if (flags
& BTRFS_BLOCK_GROUP_METADATA
) {
115 snprintf(description
, 14, "%s",
119 snprintf(description
, 5, "%s", "Data");
122 } else if (flags
& BTRFS_BLOCK_GROUP_SYSTEM
) {
123 snprintf(description
, 7, "%s", "System");
125 } else if (flags
& BTRFS_BLOCK_GROUP_METADATA
) {
126 snprintf(description
, 9, "%s", "Metadata");
130 if (flags
& BTRFS_BLOCK_GROUP_RAID0
) {
131 snprintf(description
+written
, 8, "%s", ", RAID0");
133 } else if (flags
& BTRFS_BLOCK_GROUP_RAID1
) {
134 snprintf(description
+written
, 8, "%s", ", RAID1");
136 } else if (flags
& BTRFS_BLOCK_GROUP_DUP
) {
137 snprintf(description
+written
, 6, "%s", ", DUP");
139 } else if (flags
& BTRFS_BLOCK_GROUP_RAID10
) {
140 snprintf(description
+written
, 9, "%s", ", RAID10");
144 total_bytes
= pretty_sizes(sargs
->spaces
[i
].total_bytes
);
145 used_bytes
= pretty_sizes(sargs
->spaces
[i
].used_bytes
);
146 printf("%s: total=%s, used=%s\n", description
, total_bytes
,
154 static int uuid_search(struct btrfs_fs_devices
*fs_devices
, char *search
)
156 struct list_head
*cur
;
157 struct btrfs_device
*device
;
159 list_for_each(cur
, &fs_devices
->devices
) {
160 device
= list_entry(cur
, struct btrfs_device
, dev_list
);
161 if ((device
->label
&& strcmp(device
->label
, search
) == 0) ||
162 strcmp(device
->name
, search
) == 0)
168 static void print_one_uuid(struct btrfs_fs_devices
*fs_devices
)
171 struct list_head
*cur
;
172 struct btrfs_device
*device
;
173 char *super_bytes_used
;
177 uuid_unparse(fs_devices
->fsid
, uuidbuf
);
178 device
= list_entry(fs_devices
->devices
.next
, struct btrfs_device
,
180 if (device
->label
&& device
->label
[0])
181 printf("Label: '%s' ", device
->label
);
183 printf("Label: none ");
185 super_bytes_used
= pretty_sizes(device
->super_bytes_used
);
187 total
= device
->total_devs
;
188 printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf
,
189 (unsigned long long)total
, super_bytes_used
);
191 free(super_bytes_used
);
193 list_for_each(cur
, &fs_devices
->devices
) {
196 device
= list_entry(cur
, struct btrfs_device
, dev_list
);
197 total_bytes
= pretty_sizes(device
->total_bytes
);
198 bytes_used
= pretty_sizes(device
->bytes_used
);
199 printf("\tdevid %4llu size %s used %s path %s\n",
200 (unsigned long long)device
->devid
,
201 total_bytes
, bytes_used
, device
->name
);
206 if (devs_found
< total
) {
207 printf("\t*** Some devices missing\n");
212 static const char * const cmd_show_usage
[] = {
213 "btrfs filesystem show [--all-devices] [<uuid>|<label>]",
214 "Show the structure of a filesystem",
215 "If no argument is given, structure of all present filesystems is shown.",
219 static int cmd_show(int argc
, char **argv
)
221 struct list_head
*all_uuids
;
222 struct btrfs_fs_devices
*fs_devices
;
223 struct list_head
*cur_uuid
;
229 if( argc
> 1 && !strcmp(argv
[1],"--all-devices")){
234 if (check_argc_max(argc
, searchstart
+ 1))
235 usage(cmd_show_usage
);
238 ret
= btrfs_scan_block_devices(0);
240 ret
= btrfs_scan_one_dir("/dev", 0);
243 fprintf(stderr
, "ERROR: error %d while scanning\n", ret
);
247 if(searchstart
< argc
)
248 search
= argv
[searchstart
];
250 all_uuids
= btrfs_scanned_uuids();
251 list_for_each(cur_uuid
, all_uuids
) {
252 fs_devices
= list_entry(cur_uuid
, struct btrfs_fs_devices
,
254 if (search
&& uuid_search(fs_devices
, search
) == 0)
256 print_one_uuid(fs_devices
);
258 printf("%s\n", BTRFS_BUILD_VERSION
);
262 static const char * const cmd_sync_usage
[] = {
263 "btrfs filesystem sync <path>",
264 "Force a sync on a filesystem",
268 static int cmd_sync(int argc
, char **argv
)
273 if (check_argc_exact(argc
, 2))
274 usage(cmd_sync_usage
);
278 fd
= open_file_or_dir(path
);
280 fprintf(stderr
, "ERROR: can't access to '%s'\n", path
);
284 printf("FSSync '%s'\n", path
);
285 res
= ioctl(fd
, BTRFS_IOC_SYNC
);
289 fprintf(stderr
, "ERROR: unable to fs-syncing '%s' - %s\n",
297 static u64
parse_size(char *s
)
303 if (!isdigit(s
[len
- 1])) {
304 c
= tolower(s
[len
- 1]);
315 fprintf(stderr
, "Unknown size descriptor %c\n", c
);
320 return atoll(s
) * mult
;
323 static int parse_compress_type(char *s
)
325 if (strcmp(optarg
, "zlib") == 0)
326 return BTRFS_COMPRESS_ZLIB
;
327 else if (strcmp(optarg
, "lzo") == 0)
328 return BTRFS_COMPRESS_LZO
;
330 fprintf(stderr
, "Unknown compress type %s\n", s
);
335 static const char * const cmd_defrag_usage
[] = {
336 "btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
337 "Defragment a file or a directory",
340 "-c[zlib,lzo] compress the file while defragmenting",
341 "-f flush data to disk immediately after defragmenting",
342 "-s start defragment only from byte onward",
343 "-l len defragment only up to len bytes",
344 "-t size minimal size of file to be considered for defragmenting",
348 static int cmd_defrag(int argc
, char **argv
)
360 struct btrfs_ioctl_defrag_range_args range
;
362 int compress_type
= BTRFS_COMPRESS_NONE
;
366 int c
= getopt(argc
, argv
, "vc::fs:l:t:");
372 compress_type
= BTRFS_COMPRESS_ZLIB
;
374 compress_type
= parse_compress_type(optarg
);
385 start
= parse_size(optarg
);
389 len
= parse_size(optarg
);
393 thresh
= parse_size(optarg
);
397 usage(cmd_defrag_usage
);
401 if (check_argc_min(argc
- optind
, 1))
402 usage(cmd_defrag_usage
);
404 memset(&range
, 0, sizeof(range
));
407 range
.extent_thresh
= thresh
;
409 range
.flags
|= BTRFS_DEFRAG_RANGE_COMPRESS
;
410 range
.compress_type
= compress_type
;
413 range
.flags
|= BTRFS_DEFRAG_RANGE_START_IO
;
415 for (i
= optind
; i
< argc
; i
++) {
417 printf("%s\n", argv
[i
]);
418 fd
= open_file_or_dir(argv
[i
]);
420 fprintf(stderr
, "failed to open %s\n", argv
[i
]);
426 ret
= ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
);
429 ret
= ioctl(fd
, BTRFS_IOC_DEFRAG_RANGE
, &range
);
430 if (ret
&& errno
== ENOTTY
) {
431 fprintf(stderr
, "ERROR: defrag range ioctl not "
432 "supported in this kernel, please try "
433 "without any options.\n");
440 fprintf(stderr
, "ERROR: defrag failed on %s - %s\n",
441 argv
[i
], strerror(e
));
447 printf("%s\n", BTRFS_BUILD_VERSION
);
449 fprintf(stderr
, "total %d failures\n", errors
);
456 static const char * const cmd_resize_usage
[] = {
457 "btrfs filesystem resize [+/-]<newsize>[gkm]|max <path>",
458 "Resize a filesystem",
459 "If 'max' is passed, the filesystem will occupy all available space",
464 static int cmd_resize(int argc
, char **argv
)
466 struct btrfs_ioctl_vol_args args
;
470 if (check_argc_exact(argc
, 3))
471 usage(cmd_resize_usage
);
476 fd
= open_file_or_dir(path
);
478 fprintf(stderr
, "ERROR: can't access to '%s'\n", path
);
481 len
= strlen(amount
);
482 if (len
== 0 || len
>= BTRFS_VOL_NAME_MAX
) {
483 fprintf(stderr
, "ERROR: size value too long ('%s)\n",
488 printf("Resize '%s' of '%s'\n", path
, amount
);
489 strncpy(args
.name
, amount
, BTRFS_PATH_NAME_MAX
);
490 res
= ioctl(fd
, BTRFS_IOC_RESIZE
, &args
);
494 fprintf(stderr
, "ERROR: unable to resize '%s' - %s\n",
501 static const char * const cmd_label_usage
[] = {
502 "btrfs filesystem label <device> [<newlabel>]",
503 "Get or change the label of an unmounted filesystem",
504 "With one argument, get the label of filesystem on <device>.",
505 "If <newlabel> is passed, set the filesystem label to <newlabel>.",
509 static int cmd_label(int argc
, char **argv
)
511 if (check_argc_min(argc
, 2) || check_argc_max(argc
, 3))
512 usage(cmd_label_usage
);
515 return set_label(argv
[1], argv
[2]);
517 return get_label(argv
[1]);
520 const struct cmd_group filesystem_cmd_group
= {
521 filesystem_cmd_group_usage
, NULL
, {
522 { "df", cmd_df
, cmd_df_usage
, NULL
, 0 },
523 { "show", cmd_show
, cmd_show_usage
, NULL
, 0 },
524 { "sync", cmd_sync
, cmd_sync_usage
, NULL
, 0 },
525 { "defragment", cmd_defrag
, cmd_defrag_usage
, NULL
, 0 },
526 { "balance", cmd_balance
, NULL
, &balance_cmd_group
, 1 },
527 { "resize", cmd_resize
, cmd_resize_usage
, NULL
, 0 },
528 { "label", cmd_label
, cmd_label_usage
, NULL
, 0 },
533 int cmd_filesystem(int argc
, char **argv
)
535 return handle_command_group(&filesystem_cmd_group
, argc
, argv
);