Home | History | Annotate | Download | only in misc
      1 /*
      2  * dumpe2fs.c		- List the control structures of a second
      3  *			  extended filesystem
      4  *
      5  * Copyright (C) 1992, 1993, 1994  Remy Card <card (at) masi.ibp.fr>
      6  *                                 Laboratoire MASI, Institut Blaise Pascal
      7  *                                 Universite Pierre et Marie Curie (Paris VI)
      8  *
      9  * Copyright 1995, 1996, 1997 by Theodore Ts'o.
     10  *
     11  * %Begin-Header%
     12  * This file may be redistributed under the terms of the GNU Public
     13  * License.
     14  * %End-Header%
     15  */
     16 
     17 /*
     18  * History:
     19  * 94/01/09	- Creation
     20  * 94/02/27	- Ported to use the ext2fs library
     21  */
     22 
     23 #include "config.h"
     24 #ifdef HAVE_GETOPT_H
     25 #include <getopt.h>
     26 #else
     27 extern char *optarg;
     28 extern int optind;
     29 #endif
     30 #include <fcntl.h>
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <unistd.h>
     35 
     36 #include "ext2fs/ext2_fs.h"
     37 
     38 #include "ext2fs/ext2fs.h"
     39 #include "e2p/e2p.h"
     40 #include "ext2fs/kernel-jbd.h"
     41 #include <uuid/uuid.h>
     42 
     43 #include "support/nls-enable.h"
     44 #include "support/plausible.h"
     45 #include "../version.h"
     46 
     47 #define in_use(m, x)	(ext2fs_test_bit ((x), (m)))
     48 
     49 static const char * program_name = "dumpe2fs";
     50 static char * device_name = NULL;
     51 static int hex_format = 0;
     52 static int blocks64 = 0;
     53 
     54 static void usage(void)
     55 {
     56 	fprintf(stderr, _("Usage: %s [-bfghixV] [-o superblock=<num>] "
     57 		 "[-o blocksize=<num>] device\n"), program_name);
     58 	exit(1);
     59 }
     60 
     61 static void print_number(unsigned long long num)
     62 {
     63 	if (hex_format) {
     64 		if (blocks64)
     65 			printf("0x%08llx", num);
     66 		else
     67 			printf("0x%04llx", num);
     68 	} else
     69 		printf("%llu", num);
     70 }
     71 
     72 static void print_range(unsigned long long a, unsigned long long b)
     73 {
     74 	if (hex_format) {
     75 		if (blocks64)
     76 			printf("0x%08llx-0x%08llx", a, b);
     77 		else
     78 			printf("0x%04llx-0x%04llx", a, b);
     79 	} else
     80 		printf("%llu-%llu", a, b);
     81 }
     82 
     83 static void print_free(unsigned long group, char * bitmap,
     84 		       unsigned long num, unsigned long offset, int ratio)
     85 {
     86 	int p = 0;
     87 	unsigned long i;
     88 	unsigned long j;
     89 
     90 	offset /= ratio;
     91 	offset += group * num;
     92 	for (i = 0; i < num; i++)
     93 		if (!in_use (bitmap, i))
     94 		{
     95 			if (p)
     96 				printf (", ");
     97 			print_number((i + offset) * ratio);
     98 			for (j = i; j < num && !in_use (bitmap, j); j++)
     99 				;
    100 			if (--j != i) {
    101 				fputc('-', stdout);
    102 				print_number((j + offset) * ratio);
    103 				i = j;
    104 			}
    105 			p = 1;
    106 		}
    107 }
    108 
    109 static void print_bg_opt(int bg_flags, int mask,
    110 			  const char *str, int *first)
    111 {
    112 	if (bg_flags & mask) {
    113 		if (*first) {
    114 			fputs(" [", stdout);
    115 			*first = 0;
    116 		} else
    117 			fputs(", ", stdout);
    118 		fputs(str, stdout);
    119 	}
    120 }
    121 static void print_bg_opts(ext2_filsys fs, dgrp_t i)
    122 {
    123 	int first = 1, bg_flags = 0;
    124 
    125 	if (ext2fs_has_group_desc_csum(fs))
    126 		bg_flags = ext2fs_bg_flags(fs, i);
    127 
    128 	print_bg_opt(bg_flags, EXT2_BG_INODE_UNINIT, "INODE_UNINIT",
    129  		     &first);
    130 	print_bg_opt(bg_flags, EXT2_BG_BLOCK_UNINIT, "BLOCK_UNINIT",
    131  		     &first);
    132 	print_bg_opt(bg_flags, EXT2_BG_INODE_ZEROED, "ITABLE_ZEROED",
    133  		     &first);
    134 	if (!first)
    135 		fputc(']', stdout);
    136 	fputc('\n', stdout);
    137 }
    138 
    139 static void print_bg_rel_offset(ext2_filsys fs, blk64_t block, int itable,
    140 				blk64_t first_block, blk64_t last_block)
    141 {
    142 	if ((block >= first_block) && (block <= last_block)) {
    143 		if (itable && block == first_block)
    144 			return;
    145 		printf(" (+%u)", (unsigned)(block - first_block));
    146 	} else if (ext2fs_has_feature_flex_bg(fs->super)) {
    147 		dgrp_t flex_grp = ext2fs_group_of_blk2(fs, block);
    148 		printf(" (bg #%u + %u)", flex_grp,
    149 		       (unsigned)(block-ext2fs_group_first_block2(fs,flex_grp)));
    150 	}
    151 }
    152 
    153 static void list_desc(ext2_filsys fs, int grp_only)
    154 {
    155 	unsigned long i;
    156 	blk64_t	first_block, last_block;
    157 	blk64_t	super_blk, old_desc_blk, new_desc_blk;
    158 	char *block_bitmap=NULL, *inode_bitmap=NULL;
    159 	const char *units = _("blocks");
    160 	int inode_blocks_per_group, old_desc_blocks, reserved_gdt;
    161 	int		block_nbytes, inode_nbytes;
    162 	int has_super;
    163 	blk64_t		blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
    164 	ext2_ino_t	ino_itr = 1;
    165 	errcode_t	retval;
    166 
    167 	if (ext2fs_has_feature_bigalloc(fs->super))
    168 		units = _("clusters");
    169 
    170 	block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
    171 	inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
    172 
    173 	if (fs->block_map)
    174 		block_bitmap = malloc(block_nbytes);
    175 	if (fs->inode_map)
    176 		inode_bitmap = malloc(inode_nbytes);
    177 
    178 	inode_blocks_per_group = ((fs->super->s_inodes_per_group *
    179 				   EXT2_INODE_SIZE(fs->super)) +
    180 				  EXT2_BLOCK_SIZE(fs->super) - 1) /
    181 				 EXT2_BLOCK_SIZE(fs->super);
    182 	reserved_gdt = fs->super->s_reserved_gdt_blocks;
    183 	fputc('\n', stdout);
    184 	first_block = fs->super->s_first_data_block;
    185 	if (ext2fs_has_feature_meta_bg(fs->super))
    186 		old_desc_blocks = fs->super->s_first_meta_bg;
    187 	else
    188 		old_desc_blocks = fs->desc_blocks;
    189 	if (grp_only)
    190 		printf("group:block:super:gdt:bbitmap:ibitmap:itable\n");
    191 	for (i = 0; i < fs->group_desc_count; i++) {
    192 		first_block = ext2fs_group_first_block2(fs, i);
    193 		last_block = ext2fs_group_last_block2(fs, i);
    194 
    195 		ext2fs_super_and_bgd_loc2(fs, i, &super_blk,
    196 					  &old_desc_blk, &new_desc_blk, 0);
    197 
    198 		if (grp_only) {
    199 			printf("%lu:%llu:", i, first_block);
    200 			if (i == 0 || super_blk)
    201 				printf("%llu:", super_blk);
    202 			else
    203 				printf("-1:");
    204 			if (old_desc_blk) {
    205 				print_range(old_desc_blk,
    206 					    old_desc_blk + old_desc_blocks - 1);
    207 				printf(":");
    208 			} else if (new_desc_blk)
    209 				printf("%llu:", new_desc_blk);
    210 			else
    211 				printf("-1:");
    212 			printf("%llu:%llu:%llu\n",
    213 			       ext2fs_block_bitmap_loc(fs, i),
    214 			       ext2fs_inode_bitmap_loc(fs, i),
    215 			       ext2fs_inode_table_loc(fs, i));
    216 			continue;
    217 		}
    218 
    219 		printf(_("Group %lu: (Blocks "), i);
    220 		print_range(first_block, last_block);
    221 		fputs(")", stdout);
    222 		if (ext2fs_has_group_desc_csum(fs)) {
    223 			unsigned csum = ext2fs_bg_checksum(fs, i);
    224 			unsigned exp_csum = ext2fs_group_desc_csum(fs, i);
    225 
    226 			printf(_(" csum 0x%04x"), csum);
    227 			if (csum != exp_csum)
    228 				printf(_(" (EXPECTED 0x%04x)"), exp_csum);
    229 		}
    230 		print_bg_opts(fs, i);
    231 		has_super = ((i==0) || super_blk);
    232 		if (has_super) {
    233 			printf (_("  %s superblock at "),
    234 				i == 0 ? _("Primary") : _("Backup"));
    235 			print_number(super_blk);
    236 		}
    237 		if (old_desc_blk) {
    238 			printf("%s", _(", Group descriptors at "));
    239 			print_range(old_desc_blk,
    240 				    old_desc_blk + old_desc_blocks - 1);
    241 			if (reserved_gdt) {
    242 				printf("%s", _("\n  Reserved GDT blocks at "));
    243 				print_range(old_desc_blk + old_desc_blocks,
    244 					    old_desc_blk + old_desc_blocks +
    245 					    reserved_gdt - 1);
    246 			}
    247 		} else if (new_desc_blk) {
    248 			fputc(has_super ? ',' : ' ', stdout);
    249 			printf("%s", _(" Group descriptor at "));
    250 			print_number(new_desc_blk);
    251 			has_super++;
    252 		}
    253 		if (has_super)
    254 			fputc('\n', stdout);
    255 		fputs(_("  Block bitmap at "), stdout);
    256 		print_number(ext2fs_block_bitmap_loc(fs, i));
    257 		print_bg_rel_offset(fs, ext2fs_block_bitmap_loc(fs, i), 0,
    258 				    first_block, last_block);
    259 		if (ext2fs_has_feature_metadata_csum(fs->super))
    260 			printf(_(", csum 0x%08x"),
    261 			       ext2fs_block_bitmap_checksum(fs, i));
    262 		if (getenv("DUMPE2FS_IGNORE_80COL"))
    263 			fputs(_(","), stdout);
    264 		else
    265 			fputs(_("\n "), stdout);
    266 		fputs(_(" Inode bitmap at "), stdout);
    267 		print_number(ext2fs_inode_bitmap_loc(fs, i));
    268 		print_bg_rel_offset(fs, ext2fs_inode_bitmap_loc(fs, i), 0,
    269 				    first_block, last_block);
    270 		if (ext2fs_has_feature_metadata_csum(fs->super))
    271 			printf(_(", csum 0x%08x"),
    272 			       ext2fs_inode_bitmap_checksum(fs, i));
    273 		fputs(_("\n  Inode table at "), stdout);
    274 		print_range(ext2fs_inode_table_loc(fs, i),
    275 			    ext2fs_inode_table_loc(fs, i) +
    276 			    inode_blocks_per_group - 1);
    277 		print_bg_rel_offset(fs, ext2fs_inode_table_loc(fs, i), 1,
    278 				    first_block, last_block);
    279 		printf (_("\n  %u free %s, %u free inodes, "
    280 			  "%u directories%s"),
    281 			ext2fs_bg_free_blocks_count(fs, i), units,
    282 			ext2fs_bg_free_inodes_count(fs, i),
    283 			ext2fs_bg_used_dirs_count(fs, i),
    284 			ext2fs_bg_itable_unused(fs, i) ? "" : "\n");
    285 		if (ext2fs_bg_itable_unused(fs, i))
    286 			printf (_(", %u unused inodes\n"),
    287 				ext2fs_bg_itable_unused(fs, i));
    288 		if (block_bitmap) {
    289 			fputs(_("  Free blocks: "), stdout);
    290 			retval = ext2fs_get_block_bitmap_range2(fs->block_map,
    291 				 blk_itr, block_nbytes << 3, block_bitmap);
    292 			if (retval)
    293 				com_err("list_desc", retval,
    294 					"while reading block bitmap");
    295 			else
    296 				print_free(i, block_bitmap,
    297 					   fs->super->s_clusters_per_group,
    298 					   fs->super->s_first_data_block,
    299 					   EXT2FS_CLUSTER_RATIO(fs));
    300 			fputc('\n', stdout);
    301 			blk_itr += fs->super->s_clusters_per_group;
    302 		}
    303 		if (inode_bitmap) {
    304 			fputs(_("  Free inodes: "), stdout);
    305 			retval = ext2fs_get_inode_bitmap_range2(fs->inode_map,
    306 				 ino_itr, inode_nbytes << 3, inode_bitmap);
    307 			if (retval)
    308 				com_err("list_desc", retval,
    309 					"while reading inode bitmap");
    310 			else
    311 				print_free(i, inode_bitmap,
    312 					   fs->super->s_inodes_per_group,
    313 					   1, 1);
    314 			fputc('\n', stdout);
    315 			ino_itr += fs->super->s_inodes_per_group;
    316 		}
    317 	}
    318 	if (block_bitmap)
    319 		free(block_bitmap);
    320 	if (inode_bitmap)
    321 		free(inode_bitmap);
    322 }
    323 
    324 static void list_bad_blocks(ext2_filsys fs, int dump)
    325 {
    326 	badblocks_list		bb_list = 0;
    327 	badblocks_iterate	bb_iter;
    328 	blk_t			blk;
    329 	errcode_t		retval;
    330 	const char		*header, *fmt;
    331 
    332 	retval = ext2fs_read_bb_inode(fs, &bb_list);
    333 	if (retval) {
    334 		com_err("ext2fs_read_bb_inode", retval, 0);
    335 		return;
    336 	}
    337 	retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
    338 	if (retval) {
    339 		com_err("ext2fs_badblocks_list_iterate_begin", retval,
    340 			"%s", _("while printing bad block list"));
    341 		return;
    342 	}
    343 	if (dump) {
    344 		header = fmt = "%u\n";
    345 	} else {
    346 		header =  _("Bad blocks: %u");
    347 		fmt = ", %u";
    348 	}
    349 	while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
    350 		printf(header ? header : fmt, blk);
    351 		header = 0;
    352 	}
    353 	ext2fs_badblocks_list_iterate_end(bb_iter);
    354 	if (!dump)
    355 		fputc('\n', stdout);
    356 	ext2fs_badblocks_list_free(bb_list);
    357 }
    358 
    359 static const char *journal_checksum_type_str(__u8 type)
    360 {
    361 	switch (type) {
    362 	case JBD2_CRC32C_CHKSUM:
    363 		return "crc32c";
    364 	default:
    365 		return "unknown";
    366 	}
    367 }
    368 
    369 static void print_inline_journal_information(ext2_filsys fs)
    370 {
    371 	journal_superblock_t	*jsb;
    372 	struct ext2_inode	inode;
    373 	ext2_file_t		journal_file;
    374 	errcode_t		retval;
    375 	ino_t			ino = fs->super->s_journal_inum;
    376 	char			buf[1024];
    377 	__u32			*mask_ptr, mask, m;
    378 	int			i, j, size, printed = 0;
    379 
    380 	if (fs->flags & EXT2_FLAG_IMAGE_FILE)
    381 		return;
    382 	retval = ext2fs_read_inode(fs, ino,  &inode);
    383 	if (retval) {
    384 		com_err(program_name, retval, "%s",
    385 			_("while reading journal inode"));
    386 		exit(1);
    387 	}
    388 	retval = ext2fs_file_open2(fs, ino, &inode, 0, &journal_file);
    389 	if (retval) {
    390 		com_err(program_name, retval, "%s",
    391 			_("while opening journal inode"));
    392 		exit(1);
    393 	}
    394 	retval = ext2fs_file_read(journal_file, buf, sizeof(buf), 0);
    395 	if (retval) {
    396 		com_err(program_name, retval, "%s",
    397 			_("while reading journal super block"));
    398 		exit(1);
    399 	}
    400 	ext2fs_file_close(journal_file);
    401 	jsb = (journal_superblock_t *) buf;
    402 	if (be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) {
    403 		fprintf(stderr, "%s",
    404 			_("Journal superblock magic number invalid!\n"));
    405 		exit(1);
    406 	}
    407 	printf("%s", _("Journal features:        "));
    408 	for (i=0, mask_ptr=&jsb->s_feature_compat; i <3; i++,mask_ptr++) {
    409 		mask = be32_to_cpu(*mask_ptr);
    410 		for (j=0,m=1; j < 32; j++, m<<=1) {
    411 			if (mask & m) {
    412 				printf(" %s", e2p_jrnl_feature2string(i, m));
    413 				printed++;
    414 			}
    415 		}
    416 	}
    417 	if (printed == 0)
    418 		printf(" (none)");
    419 	printf("\n");
    420 	fputs(_("Journal size:             "), stdout);
    421 	if (ext2fs_has_feature_huge_file(fs->super) &&
    422 	    (inode.i_flags & EXT4_HUGE_FILE_FL))
    423 		size = inode.i_blocks / (fs->blocksize / 1024);
    424 	else
    425 		size = inode.i_blocks >> 1;
    426 	if (size < 8192)
    427 		printf("%uk\n", size);
    428 	else
    429 		printf("%uM\n", size >> 10);
    430 	printf(_("Journal length:           %u\n"
    431 		 "Journal sequence:         0x%08x\n"
    432 		 "Journal start:            %u\n"),
    433 	       (unsigned int)ntohl(jsb->s_maxlen),
    434 	       (unsigned int)ntohl(jsb->s_sequence),
    435 	       (unsigned int)ntohl(jsb->s_start));
    436 	if (jsb->s_feature_compat &
    437 	    ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM))
    438 		printf("%s", _("Journal checksum type:    crc32\n"));
    439 	if ((jsb->s_feature_incompat &
    440 	     ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V3)) ||
    441 	    (jsb->s_feature_incompat &
    442 	     ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2)))
    443 		printf(_("Journal checksum type:    %s\n"
    444 			 "Journal checksum:         0x%08x\n"),
    445 		       journal_checksum_type_str(jsb->s_checksum_type),
    446 		       ext2fs_be32_to_cpu(jsb->s_checksum));
    447 	if (jsb->s_errno != 0)
    448 		printf(_("Journal errno:            %d\n"),
    449 		       (int) ntohl(jsb->s_errno));
    450 }
    451 
    452 static void print_journal_information(ext2_filsys fs)
    453 {
    454 	errcode_t	retval;
    455 	char		buf[1024];
    456 	char		str[80];
    457 	unsigned int	i, j, printed = 0;
    458 	journal_superblock_t	*jsb;
    459 	__u32			*mask_ptr, mask, m;
    460 
    461 	/* Get the journal superblock */
    462 	if ((retval = io_channel_read_blk64(fs->io,
    463 					    fs->super->s_first_data_block + 1,
    464 					    -1024, buf))) {
    465 		com_err(program_name, retval, "%s",
    466 			_("while reading journal superblock"));
    467 		exit(1);
    468 	}
    469 	jsb = (journal_superblock_t *) buf;
    470 	if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
    471 	    (jsb->s_header.h_blocktype !=
    472 	     (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
    473 		com_err(program_name, 0, "%s",
    474 			_("Couldn't find journal superblock magic numbers"));
    475 		exit(1);
    476 	}
    477 
    478 	if (jsb->s_feature_compat &
    479 	    ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM))
    480 		printf("%s", _("Journal checksum type:    crc32\n"));
    481 	if ((jsb->s_feature_incompat &
    482 	     ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V3)) ||
    483 	    (jsb->s_feature_incompat &
    484 	     ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2)))
    485 		printf(_("Journal checksum type:    %s\n"
    486 			 "Journal checksum:         0x%08x\n"),
    487 		       journal_checksum_type_str(jsb->s_checksum_type),
    488 		       ext2fs_be32_to_cpu(jsb->s_checksum));
    489 
    490 	printf("%s", _("Journal features:        "));
    491 	for (i = 0, mask_ptr = &jsb->s_feature_compat; i < 3; i++, mask_ptr++) {
    492 		mask = be32_to_cpu(*mask_ptr);
    493 		for (j = 0, m = 1; j < 32; j++, m <<= 1) {
    494 			if (mask & m) {
    495 				printf(" %s", e2p_jrnl_feature2string(i, m));
    496 				printed++;
    497 			}
    498 		}
    499 	}
    500 
    501 	printf(_("\nJournal block size:       %u\n"
    502 		 "Journal length:           %u\n"
    503 		 "Journal first block:      %u\n"
    504 		 "Journal sequence:         0x%08x\n"
    505 		 "Journal start:            %u\n"
    506 		 "Journal number of users:  %u\n"),
    507 	       (unsigned int)ntohl(jsb->s_blocksize),  (unsigned int)ntohl(jsb->s_maxlen),
    508 	       (unsigned int)ntohl(jsb->s_first), (unsigned int)ntohl(jsb->s_sequence),
    509 	       (unsigned int)ntohl(jsb->s_start), (unsigned int)ntohl(jsb->s_nr_users));
    510 
    511 	for (i=0; i < ntohl(jsb->s_nr_users); i++) {
    512 		uuid_unparse(&jsb->s_users[i*16], str);
    513 		printf(i ? "                          %s\n"
    514 		       : _("Journal users:            %s\n"),
    515 		       str);
    516 	}
    517 }
    518 
    519 static void parse_extended_opts(const char *opts, blk64_t *superblock,
    520 				int *blocksize)
    521 {
    522 	char	*buf, *token, *next, *p, *arg, *badopt = 0;
    523 	int	len;
    524 	int	do_usage = 0;
    525 
    526 	len = strlen(opts);
    527 	buf = malloc(len+1);
    528 	if (!buf) {
    529 		fprintf(stderr, "%s",
    530 			_("Couldn't allocate memory to parse options!\n"));
    531 		exit(1);
    532 	}
    533 	strcpy(buf, opts);
    534 	for (token = buf; token && *token; token = next) {
    535 		p = strchr(token, ',');
    536 		next = 0;
    537 		if (p) {
    538 			*p = 0;
    539 			next = p+1;
    540 		}
    541 		arg = strchr(token, '=');
    542 		if (arg) {
    543 			*arg = 0;
    544 			arg++;
    545 		}
    546 		if (strcmp(token, "superblock") == 0 ||
    547 		    strcmp(token, "sb") == 0) {
    548 			if (!arg) {
    549 				do_usage++;
    550 				badopt = token;
    551 				continue;
    552 			}
    553 			*superblock = strtoul(arg, &p, 0);
    554 			if (*p) {
    555 				fprintf(stderr,
    556 					_("Invalid superblock parameter: %s\n"),
    557 					arg);
    558 				do_usage++;
    559 				continue;
    560 			}
    561 		} else if (strcmp(token, "blocksize") == 0 ||
    562 			   strcmp(token, "bs") == 0) {
    563 			if (!arg) {
    564 				do_usage++;
    565 				badopt = token;
    566 				continue;
    567 			}
    568 			*blocksize = strtoul(arg, &p, 0);
    569 			if (*p) {
    570 				fprintf(stderr,
    571 					_("Invalid blocksize parameter: %s\n"),
    572 					arg);
    573 				do_usage++;
    574 				continue;
    575 			}
    576 		} else {
    577 			do_usage++;
    578 			badopt = token;
    579 		}
    580 	}
    581 	if (do_usage) {
    582 		fprintf(stderr, _("\nBad extended option(s) specified: %s\n\n"
    583 			"Extended options are separated by commas, "
    584 			"and may take an argument which\n"
    585 			"\tis set off by an equals ('=') sign.\n\n"
    586 			"Valid extended options are:\n"
    587 			"\tsuperblock=<superblock number>\n"
    588 			"\tblocksize=<blocksize>\n"),
    589 			badopt ? badopt : "");
    590 		free(buf);
    591 		exit(1);
    592 	}
    593 	free(buf);
    594 }
    595 
    596 int main (int argc, char ** argv)
    597 {
    598 	errcode_t	retval;
    599 	ext2_filsys	fs;
    600 	int		print_badblocks = 0;
    601 	blk64_t		use_superblock = 0;
    602 	int		use_blocksize = 0;
    603 	int		image_dump = 0;
    604 	int		force = 0;
    605 	int		flags;
    606 	int		header_only = 0;
    607 	int		c;
    608 	int		grp_only = 0;
    609 
    610 #ifdef ENABLE_NLS
    611 	setlocale(LC_MESSAGES, "");
    612 	setlocale(LC_CTYPE, "");
    613 	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
    614 	textdomain(NLS_CAT_NAME);
    615 	set_com_err_gettext(gettext);
    616 #endif
    617 	add_error_table(&et_ext2_error_table);
    618 	fprintf (stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION,
    619 		 E2FSPROGS_DATE);
    620 	if (argc && *argv)
    621 		program_name = *argv;
    622 
    623 	while ((c = getopt(argc, argv, "bfghixVo:")) != EOF) {
    624 		switch (c) {
    625 		case 'b':
    626 			print_badblocks++;
    627 			break;
    628 		case 'f':
    629 			force++;
    630 			break;
    631 		case 'g':
    632 			grp_only++;
    633 			break;
    634 		case 'h':
    635 			header_only++;
    636 			break;
    637 		case 'i':
    638 			image_dump++;
    639 			break;
    640 		case 'o':
    641 			parse_extended_opts(optarg, &use_superblock,
    642 					    &use_blocksize);
    643 			break;
    644 		case 'V':
    645 			/* Print version number and exit */
    646 			fprintf(stderr, _("\tUsing %s\n"),
    647 				error_message(EXT2_ET_BASE));
    648 			exit(0);
    649 		case 'x':
    650 			hex_format++;
    651 			break;
    652 		default:
    653 			usage();
    654 		}
    655 	}
    656 	if (optind != argc - 1) {
    657 		usage();
    658 		exit(1);
    659 	}
    660 	device_name = argv[optind++];
    661 	flags = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS;
    662 	if (force)
    663 		flags |= EXT2_FLAG_FORCE;
    664 	if (image_dump)
    665 		flags |= EXT2_FLAG_IMAGE_FILE;
    666 try_open_again:
    667 	if (use_superblock && !use_blocksize) {
    668 		for (use_blocksize = EXT2_MIN_BLOCK_SIZE;
    669 		     use_blocksize <= EXT2_MAX_BLOCK_SIZE;
    670 		     use_blocksize *= 2) {
    671 			retval = ext2fs_open (device_name, flags,
    672 					      use_superblock,
    673 					      use_blocksize, unix_io_manager,
    674 					      &fs);
    675 			if (!retval)
    676 				break;
    677 		}
    678 	} else
    679 		retval = ext2fs_open (device_name, flags, use_superblock,
    680 				      use_blocksize, unix_io_manager, &fs);
    681 	if (retval && !(flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
    682 		flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
    683 		goto try_open_again;
    684 	}
    685 	if (!retval && (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS))
    686 		printf("%s", _("\n*** Checksum errors detected in filesystem!  Run e2fsck now!\n\n"));
    687 	flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
    688 	if (retval) {
    689 		com_err (program_name, retval, _("while trying to open %s"),
    690 			 device_name);
    691 		printf("%s", _("Couldn't find valid filesystem superblock.\n"));
    692 		if (retval == EXT2_ET_BAD_MAGIC)
    693 			check_plausibility(device_name, CHECK_FS_EXIST, NULL);
    694 		exit (1);
    695 	}
    696 	fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
    697 	if (ext2fs_has_feature_64bit(fs->super))
    698 		blocks64 = 1;
    699 	if (print_badblocks) {
    700 		list_bad_blocks(fs, 1);
    701 	} else {
    702 		if (grp_only)
    703 			goto just_descriptors;
    704 		list_super (fs->super);
    705 		if (ext2fs_has_feature_journal_dev(fs->super)) {
    706 			print_journal_information(fs);
    707 			ext2fs_close_free(&fs);
    708 			exit(0);
    709 		}
    710 		if (ext2fs_has_feature_journal(fs->super) &&
    711 		    (fs->super->s_journal_inum != 0))
    712 			print_inline_journal_information(fs);
    713 		list_bad_blocks(fs, 0);
    714 		if (header_only) {
    715 			ext2fs_close_free(&fs);
    716 			exit (0);
    717 		}
    718 		fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
    719 try_bitmaps_again:
    720 		retval = ext2fs_read_bitmaps (fs);
    721 		if (retval && !(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
    722 			fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
    723 			goto try_bitmaps_again;
    724 		}
    725 		if (!retval && (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS))
    726 			printf("%s", _("\n*** Checksum errors detected in bitmaps!  Run e2fsck now!\n\n"));
    727 just_descriptors:
    728 		list_desc(fs, grp_only);
    729 		if (retval) {
    730 			printf(_("\n%s: %s: error reading bitmaps: %s\n"),
    731 			       program_name, device_name,
    732 			       error_message(retval));
    733 		}
    734 	}
    735 	ext2fs_close_free(&fs);
    736 	remove_error_table(&et_ext2_error_table);
    737 	exit (0);
    738 }
    739