#include <ctype.h>
#include <uuid/uuid.h>
#include <errno.h>
+#include <getopt.h>
#include "ctree.h"
#include "disk-io.h"
#include "utils.h"
#include "commands.h"
#include "crc32c.h"
-#include "cmds-inspect-dump-super.h"
+#include "help.h"
static int check_csum_sblock(void *sb, int csum_size)
{
- char result[BTRFS_CSUM_SIZE];
+ u8 result[BTRFS_CSUM_SIZE];
u32 crc = ~(u32)0;
- crc = btrfs_csum_data(NULL, (char *)sb + BTRFS_CSUM_SIZE,
+ crc = btrfs_csum_data((char *)sb + BTRFS_CSUM_SIZE,
crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
btrfs_csum_final(crc, result);
buf = malloc(sizeof(*buf) + sizeof(*sb));
if (!buf) {
- fprintf(stderr, "%s\n", strerror(ENOMEM));
- goto out;
+ error("not enough memory");
+ return;
}
write_extent_buffer(buf, sb, 0, sizeof(*sb));
+ buf->len = sizeof(*sb);
array_size = btrfs_super_sys_array_size(sb);
array_ptr = sb->sys_chunk_array;
sb_array_offset = offsetof(struct btrfs_super_block, sys_chunk_array);
+
+ if (array_size > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) {
+ error("sys_array_size %u shouldn't exceed %u bytes",
+ array_size, BTRFS_SYSTEM_CHUNK_ARRAY_SIZE);
+ goto out;
+ }
+
cur_offset = 0;
item = 0;
if (cur_offset + len > array_size)
goto out_short_read;
- print_chunk(buf, chunk);
num_stripes = btrfs_chunk_num_stripes(buf, chunk);
if (!num_stripes) {
- printk(
- "ERROR: invalid number of stripes %u in sys_array at offset %u\n",
+ error(
+ "invalid number of stripes %u in sys_array at offset %u",
num_stripes, cur_offset);
break;
}
len = btrfs_chunk_item_size(num_stripes);
if (cur_offset + len > array_size)
goto out_short_read;
+ print_chunk_item(buf, chunk);
} else {
- printk(
- "ERROR: unexpected item type %u in sys_array at offset %u\n",
+ error("unexpected item type %u in sys_array at offset %u",
(u32)key.type, cur_offset);
break;
}
item++;
}
- free(buf);
out:
+ free(buf);
return;
out_short_read:
- printk("ERROR: sys_array too short to read %u bytes at offset %u\n",
+ error("sys_array too short to read %u bytes at offset %u",
len, cur_offset);
free(buf);
}
char *output;
};
+#define DEF_COMPAT_RO_FLAG_ENTRY(bit_name) \
+ {BTRFS_FEATURE_COMPAT_RO_##bit_name, #bit_name}
+
+static struct readable_flag_entry compat_ro_flags_array[] = {
+ DEF_COMPAT_RO_FLAG_ENTRY(FREE_SPACE_TREE),
+ DEF_COMPAT_RO_FLAG_ENTRY(FREE_SPACE_TREE_VALID),
+};
+static const int compat_ro_flags_num = sizeof(compat_ro_flags_array) /
+ sizeof(struct readable_flag_entry);
+
#define DEF_INCOMPAT_FLAG_ENTRY(bit_name) \
{BTRFS_FEATURE_INCOMPAT_##bit_name, #bit_name}
DEF_INCOMPAT_FLAG_ENTRY(DEFAULT_SUBVOL),
DEF_INCOMPAT_FLAG_ENTRY(MIXED_GROUPS),
DEF_INCOMPAT_FLAG_ENTRY(COMPRESS_LZO),
- DEF_INCOMPAT_FLAG_ENTRY(COMPRESS_LZOv2),
+ DEF_INCOMPAT_FLAG_ENTRY(COMPRESS_ZSTD),
DEF_INCOMPAT_FLAG_ENTRY(BIG_METADATA),
DEF_INCOMPAT_FLAG_ENTRY(EXTENDED_IREF),
DEF_INCOMPAT_FLAG_ENTRY(RAID56),
printf(")\n");
}
+static void print_readable_compat_ro_flag(u64 flag)
+{
+ /*
+ * We know about the FREE_SPACE_TREE{,_VALID} bits, but we don't
+ * actually support them yet.
+ */
+ return __print_readable_flag(flag, compat_ro_flags_array,
+ compat_ro_flags_num,
+ BTRFS_FEATURE_COMPAT_RO_SUPP |
+ BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE |
+ BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID);
+}
+
static void print_readable_incompat_flag(u64 flag)
{
return __print_readable_flag(flag, incompat_flags_array,
int i;
char *s, buf[BTRFS_UUID_UNPARSED_SIZE];
u8 *p;
+ u32 csum_size;
+ u16 csum_type;
+
+ csum_type = btrfs_super_csum_type(sb);
+ csum_size = BTRFS_CSUM_SIZE;
+ printf("csum_type\t\t%hu (", csum_type);
+ if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) {
+ printf("INVALID");
+ } else {
+ if (csum_type == BTRFS_CSUM_TYPE_CRC32) {
+ printf("crc32c");
+ csum_size = btrfs_csum_sizes[csum_type];
+ } else {
+ printf("unknown");
+ }
+ }
+ printf(")\n");
+ printf("csum_size\t\t%llu\n", (unsigned long long)csum_size);
printf("csum\t\t\t0x");
- for (i = 0, p = sb->csum; i < btrfs_super_csum_size(sb); i++)
+ for (i = 0, p = sb->csum; i < csum_size; i++)
printf("%02x", p[i]);
- if (check_csum_sblock(sb, btrfs_super_csum_size(sb)))
+ if (check_csum_sblock(sb, csum_size))
printf(" [match]");
else
printf(" [DON'T MATCH]");
(unsigned long long)btrfs_super_sectorsize(sb));
printf("nodesize\t\t%llu\n",
(unsigned long long)btrfs_super_nodesize(sb));
- printf("leafsize\t\t%llu\n",
- (unsigned long long)btrfs_super_leafsize(sb));
+ printf("leafsize (deprecated)\t\t%u\n",
+ le32_to_cpu(sb->__unused_leafsize));
printf("stripesize\t\t%llu\n",
(unsigned long long)btrfs_super_stripesize(sb));
printf("root_dir\t\t%llu\n",
(unsigned long long)btrfs_super_compat_flags(sb));
printf("compat_ro_flags\t\t0x%llx\n",
(unsigned long long)btrfs_super_compat_ro_flags(sb));
+ print_readable_compat_ro_flag(btrfs_super_compat_ro_flags(sb));
printf("incompat_flags\t\t0x%llx\n",
(unsigned long long)btrfs_super_incompat_flags(sb));
print_readable_incompat_flag(btrfs_super_incompat_flags(sb));
- printf("csum_type\t\t%llu\n",
- (unsigned long long)btrfs_super_csum_type(sb));
- printf("csum_size\t\t%llu\n",
- (unsigned long long)btrfs_super_csum_size(sb));
printf("cache_generation\t%llu\n",
(unsigned long long)btrfs_super_cache_generation(sb));
printf("uuid_tree_generation\t%llu\n",
if (ret == 0 && errno == 0)
return 0;
- fprintf(stderr,
- "ERROR: Failed to read the superblock on %s at %llu\n",
- filename, (unsigned long long)sb_bytenr);
- fprintf(stderr,
- "ERROR: error = '%s', errno = %d\n", strerror(errno), errno);
+ error("failed to read the superblock on %s at %llu",
+ filename, (unsigned long long)sb_bytenr);
+ error("error = '%m', errno = %d", errno);
return 1;
}
printf("superblock: bytenr=%llu, device=%s\n", sb_bytenr, filename);
printf("---------------------------------------------------------\n");
if (btrfs_super_magic(sb) != BTRFS_MAGIC && !force) {
- fprintf(stderr,
- "ERROR: bad magic on superblock on %s at %llu\n",
- filename, (unsigned long long)sb_bytenr);
+ error("bad magic on superblock on %s at %llu",
+ filename, (unsigned long long)sb_bytenr);
} else {
dump_superblock(sb, full);
}
const char * const cmd_inspect_dump_super_usage[] = {
"btrfs inspect-internal dump-super [options] device [device...]",
- "Dump superblock from a device",
- "-f print full superblock information",
- "-a print information of all superblocks",
- "-i <super_mirror> specify which mirror to print out",
- "-F attempt to dump superblocks with bad magic",
- "-s <bytenr> specify alternate superblock offset",
+ "Dump superblock from a device in a textual form",
+ "-f|--full print full superblock information, backup roots etc.",
+ "-a|--all print information about all superblocks",
+ "-s|--super <super> specify which copy to print out (values: 0, 1, 2)",
+ "-F|--force attempt to dump superblocks with bad magic",
+ "--bytenr <offset> specify alternate superblock offset",
+ "",
+ "Deprecated syntax:",
+ "-s <bytenr> specify alternate superblock offset, values other than 0, 1, 2",
+ " will be interpreted as --bytenr for backward compatibility,",
+ " option renamed for consistency with other tools (eg. check)",
+ "-i <super> specify which copy to print out (values: 0, 1, 2), now moved",
+ " to -s|--super",
NULL
};
int cmd_inspect_dump_super(int argc, char **argv)
{
- int opt;
int all = 0;
int full = 0;
int force = 0;
u64 arg;
u64 sb_bytenr = btrfs_sb_offset(0);
- while ((opt = getopt(argc, argv, "fFai:s:")) != -1) {
- switch (opt) {
+ while (1) {
+ int c;
+ enum { GETOPT_VAL_BYTENR = 257 };
+ static const struct option long_options[] = {
+ {"all", no_argument, NULL, 'a'},
+ {"bytenr", required_argument, NULL, GETOPT_VAL_BYTENR },
+ {"full", no_argument, NULL, 'f'},
+ {"force", no_argument, NULL, 'F'},
+ {"super", required_argument, NULL, 's' },
+ {NULL, 0, NULL, 0}
+ };
+
+ c = getopt_long(argc, argv, "fFai:s:", long_options, NULL);
+ if (c < 0)
+ break;
+
+ switch (c) {
case 'i':
+ warning(
+ "option -i is deprecated, please use -s or --super");
arg = arg_strtou64(optarg);
if (arg >= BTRFS_SUPER_MIRROR_MAX) {
- fprintf(stderr,
- "Illegal super_mirror %llu\n",
- arg);
- usage(cmd_inspect_dump_super_usage);
+ error("super mirror too big: %llu >= %d",
+ arg, BTRFS_SUPER_MIRROR_MAX);
+ return 1;
}
sb_bytenr = btrfs_sb_offset(arg);
break;
force = 1;
break;
case 's':
- sb_bytenr = arg_strtou64(optarg);
+ arg = arg_strtou64(optarg);
+ if (BTRFS_SUPER_MIRROR_MAX <= arg) {
+ warning(
+ "deprecated use of -s <bytenr> with %llu, assuming --bytenr",
+ (unsigned long long)arg);
+ sb_bytenr = arg;
+ } else {
+ sb_bytenr = btrfs_sb_offset(arg);
+ }
+ all = 0;
+ break;
+ case GETOPT_VAL_BYTENR:
+ arg = arg_strtou64(optarg);
+ sb_bytenr = arg;
all = 0;
break;
default:
for (i = optind; i < argc; i++) {
filename = argv[i];
- fd = open(filename, O_RDONLY, 0666);
+ fd = open(filename, O_RDONLY);
if (fd < 0) {
- fprintf(stderr, "Could not open %s\n", filename);
+ error("cannot open %s: %m", filename);
ret = 1;
goto out;
}