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 #ifdef HAVE_GETOPT_H
     24 #include <getopt.h>
     25 #else
     26 extern char *optarg;
     27 extern int optind;
     28 #endif
     29 #include <fcntl.h>
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <string.h>
     33 #include <unistd.h>
     34 
     35 #include "ext2fs/ext2_fs.h"
     36 
     37 #include "ext2fs/ext2fs.h"
     38 #include "e2p/e2p.h"
     39 #include "jfs_user.h"
     40 #include <uuid/uuid.h>
     41 
     42 #include "../version.h"
     43 #include "nls-enable.h"
     44 
     45 #define in_use(m, x)	(ext2fs_test_bit ((x), (m)))
     46 
     47 const char * program_name = "dumpe2fs";
     48 char * device_name = NULL;
     49 int hex_format = 0;
     50 
     51 static void usage(void)
     52 {
     53 	fprintf (stderr, _("Usage: %s [-bfhixV] [-o superblock=<num>] "
     54 		 "[-o blocksize=<num>] device\n"), program_name);
     55 	exit (1);
     56 }
     57 
     58 static void print_number(unsigned long num)
     59 {
     60 	if (hex_format)
     61 		printf("0x%04lx", num);
     62 	else
     63 		printf("%lu", num);
     64 }
     65 
     66 static void print_range(unsigned long a, unsigned long b)
     67 {
     68 	if (hex_format)
     69 		printf("0x%04lx-0x%04lx", a, b);
     70 	else
     71 		printf("%lu-%lu", a, b);
     72 }
     73 
     74 static void print_free (unsigned long group, char * bitmap,
     75 			unsigned long nbytes, unsigned long offset)
     76 {
     77 	int p = 0;
     78 	unsigned long i;
     79 	unsigned long j;
     80 
     81 	offset += group * nbytes;
     82 	for (i = 0; i < nbytes; i++)
     83 		if (!in_use (bitmap, i))
     84 		{
     85 			if (p)
     86 				printf (", ");
     87 			print_number(i + offset);
     88 			for (j = i; j < nbytes && !in_use (bitmap, j); j++)
     89 				;
     90 			if (--j != i) {
     91 				fputc('-', stdout);
     92 				print_number(j + offset);
     93 				i = j;
     94 			}
     95 			p = 1;
     96 		}
     97 }
     98 
     99 static void print_bg_opt(int bg_flags, int mask,
    100 			  const char *str, int *first)
    101 {
    102 	if (bg_flags & mask) {
    103 		if (*first) {
    104 			fputs(" [", stdout);
    105 			*first = 0;
    106 		} else
    107 			fputs(", ", stdout);
    108 		fputs(str, stdout);
    109 	}
    110 }
    111 static void print_bg_opts(ext2_filsys fs, dgrp_t i)
    112 {
    113 	int first = 1, bg_flags = 0;
    114 
    115 	if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
    116 		bg_flags = fs->group_desc[i].bg_flags;
    117 
    118 	print_bg_opt(bg_flags, EXT2_BG_INODE_UNINIT, "INODE_UNINIT",
    119  		     &first);
    120 	print_bg_opt(bg_flags, EXT2_BG_BLOCK_UNINIT, "BLOCK_UNINIT",
    121  		     &first);
    122 	print_bg_opt(bg_flags, EXT2_BG_INODE_ZEROED, "ITABLE_ZEROED",
    123  		     &first);
    124 	if (!first)
    125 		fputc(']', stdout);
    126 	fputc('\n', stdout);
    127 }
    128 
    129 static void print_bg_rel_offset(ext2_filsys fs, blk64_t block, int itable,
    130 				blk64_t first_block, blk64_t last_block)
    131 {
    132 	if ((block >= first_block) && (block <= last_block)) {
    133 		if (itable && block == first_block)
    134 			return;
    135 		printf(" (+%u)", (unsigned)(block - first_block));
    136 	} else if (fs->super->s_feature_incompat &
    137 		   EXT4_FEATURE_INCOMPAT_FLEX_BG) {
    138 		dgrp_t flex_grp = ext2fs_group_of_blk(fs, block);
    139 		printf(" (bg #%u + %u)", flex_grp,
    140 		       (unsigned)(block-ext2fs_group_first_block(fs,flex_grp)));
    141 	}
    142 }
    143 
    144 static void list_desc (ext2_filsys fs)
    145 {
    146 	unsigned long i;
    147 	blk_t	first_block, last_block;
    148 	blk_t	super_blk, old_desc_blk, new_desc_blk;
    149 	char *block_bitmap=NULL, *inode_bitmap=NULL;
    150 	int inode_blocks_per_group, old_desc_blocks, reserved_gdt;
    151 	int		block_nbytes, inode_nbytes;
    152 	int has_super;
    153 	blk_t		blk_itr = fs->super->s_first_data_block;
    154 	ext2_ino_t	ino_itr = 1;
    155 
    156 	block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
    157 	inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
    158 
    159 	if (fs->block_map)
    160 		block_bitmap = malloc(block_nbytes);
    161 	if (fs->inode_map)
    162 		inode_bitmap = malloc(inode_nbytes);
    163 
    164 	inode_blocks_per_group = ((fs->super->s_inodes_per_group *
    165 				   EXT2_INODE_SIZE(fs->super)) +
    166 				  EXT2_BLOCK_SIZE(fs->super) - 1) /
    167 				 EXT2_BLOCK_SIZE(fs->super);
    168 	reserved_gdt = fs->super->s_reserved_gdt_blocks;
    169 	fputc('\n', stdout);
    170 	first_block = fs->super->s_first_data_block;
    171 	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
    172 		old_desc_blocks = fs->super->s_first_meta_bg;
    173 	else
    174 		old_desc_blocks = fs->desc_blocks;
    175 	for (i = 0; i < fs->group_desc_count; i++) {
    176 		first_block = ext2fs_group_first_block(fs, i);
    177 		last_block = ext2fs_group_last_block(fs, i);
    178 
    179 		ext2fs_super_and_bgd_loc(fs, i, &super_blk,
    180 					 &old_desc_blk, &new_desc_blk, 0);
    181 
    182 		printf (_("Group %lu: (Blocks "), i);
    183 		print_range(first_block, last_block);
    184 		fputs(")", stdout);
    185 		print_bg_opts(fs, i);
    186 		if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
    187 			printf(_("  Checksum 0x%04x, unused inodes %d\n"),
    188 			       fs->group_desc[i].bg_checksum,
    189 			       fs->group_desc[i].bg_itable_unused);
    190 		has_super = ((i==0) || super_blk);
    191 		if (has_super) {
    192 			printf (_("  %s superblock at "),
    193 				i == 0 ? _("Primary") : _("Backup"));
    194 			print_number(super_blk);
    195 		}
    196 		if (old_desc_blk) {
    197 			printf(_(", Group descriptors at "));
    198 			print_range(old_desc_blk,
    199 				    old_desc_blk + old_desc_blocks - 1);
    200 			if (reserved_gdt) {
    201 				printf(_("\n  Reserved GDT blocks at "));
    202 				print_range(old_desc_blk + old_desc_blocks,
    203 					    old_desc_blk + old_desc_blocks +
    204 					    reserved_gdt - 1);
    205 			}
    206 		} else if (new_desc_blk) {
    207 			fputc(has_super ? ',' : ' ', stdout);
    208 			printf(_(" Group descriptor at "));
    209 			print_number(new_desc_blk);
    210 			has_super++;
    211 		}
    212 		if (has_super)
    213 			fputc('\n', stdout);
    214 		fputs(_("  Block bitmap at "), stdout);
    215 		print_number(fs->group_desc[i].bg_block_bitmap);
    216 		print_bg_rel_offset(fs, fs->group_desc[i].bg_block_bitmap, 0,
    217 				    first_block, last_block);
    218 
    219 		fputs(_(", Inode bitmap at "), stdout);
    220 		print_number(fs->group_desc[i].bg_inode_bitmap);
    221 		print_bg_rel_offset(fs, fs->group_desc[i].bg_inode_bitmap, 0,
    222 				    first_block, last_block);
    223 
    224 		fputs(_("\n  Inode table at "), stdout);
    225 		print_range(fs->group_desc[i].bg_inode_table,
    226 			    fs->group_desc[i].bg_inode_table +
    227 			    inode_blocks_per_group - 1);
    228 		print_bg_rel_offset(fs, fs->group_desc[i].bg_inode_table, 1,
    229 				    first_block, last_block);
    230 
    231 		printf (_("\n  %u free blocks, %u free inodes, "
    232 			  "%u directories%s"),
    233 			fs->group_desc[i].bg_free_blocks_count,
    234 			fs->group_desc[i].bg_free_inodes_count,
    235 			fs->group_desc[i].bg_used_dirs_count,
    236 			fs->group_desc[i].bg_itable_unused ? "" : "\n");
    237 		if (fs->group_desc[i].bg_itable_unused)
    238 			printf (_(", %u unused inodes\n"),
    239 				fs->group_desc[i].bg_itable_unused);
    240 		if (block_bitmap) {
    241 			fputs(_("  Free blocks: "), stdout);
    242 			ext2fs_get_block_bitmap_range(fs->block_map,
    243 				 blk_itr, block_nbytes << 3, block_bitmap);
    244 			print_free (i, block_bitmap,
    245 				    fs->super->s_blocks_per_group,
    246 				    fs->super->s_first_data_block);
    247 			fputc('\n', stdout);
    248 			blk_itr += fs->super->s_blocks_per_group;
    249 		}
    250 		if (inode_bitmap) {
    251 			fputs(_("  Free inodes: "), stdout);
    252 			ext2fs_get_inode_bitmap_range(fs->inode_map,
    253 				 ino_itr, inode_nbytes << 3, inode_bitmap);
    254 			print_free (i, inode_bitmap,
    255 				    fs->super->s_inodes_per_group, 1);
    256 			fputc('\n', stdout);
    257 			ino_itr += fs->super->s_inodes_per_group;
    258 		}
    259 	}
    260 	if (block_bitmap)
    261 		free(block_bitmap);
    262 	if (inode_bitmap)
    263 		free(inode_bitmap);
    264 }
    265 
    266 static void list_bad_blocks(ext2_filsys fs, int dump)
    267 {
    268 	badblocks_list		bb_list = 0;
    269 	badblocks_iterate	bb_iter;
    270 	blk_t			blk;
    271 	errcode_t		retval;
    272 	const char		*header, *fmt;
    273 
    274 	retval = ext2fs_read_bb_inode(fs, &bb_list);
    275 	if (retval) {
    276 		com_err("ext2fs_read_bb_inode", retval, 0);
    277 		return;
    278 	}
    279 	retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
    280 	if (retval) {
    281 		com_err("ext2fs_badblocks_list_iterate_begin", retval,
    282 			_("while printing bad block list"));
    283 		return;
    284 	}
    285 	if (dump) {
    286 		header = fmt = "%u\n";
    287 	} else {
    288 		header =  _("Bad blocks: %u");
    289 		fmt = ", %u";
    290 	}
    291 	while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
    292 		printf(header ? header : fmt, blk);
    293 		header = 0;
    294 	}
    295 	ext2fs_badblocks_list_iterate_end(bb_iter);
    296 	if (!dump)
    297 		fputc('\n', stdout);
    298 	ext2fs_badblocks_list_free(bb_list);
    299 }
    300 
    301 static void print_inline_journal_information(ext2_filsys fs)
    302 {
    303 	journal_superblock_t	*jsb;
    304 	struct ext2_inode	inode;
    305 	ext2_file_t		journal_file;
    306 	errcode_t		retval;
    307 	ino_t			ino = fs->super->s_journal_inum;
    308 	char			buf[1024];
    309 	__u32			*mask_ptr, mask, m;
    310 	int			i, j, size, printed = 0;
    311 
    312 	retval = ext2fs_read_inode(fs, ino,  &inode);
    313 	if (retval) {
    314 		com_err(program_name, retval,
    315 			_("while reading journal inode"));
    316 		exit(1);
    317 	}
    318 	retval = ext2fs_file_open2(fs, ino, &inode, 0, &journal_file);
    319 	if (retval) {
    320 		com_err(program_name, retval,
    321 			_("while opening journal inode"));
    322 		exit(1);
    323 	}
    324 	retval = ext2fs_file_read(journal_file, buf, sizeof(buf), 0);
    325 	if (retval) {
    326 		com_err(program_name, retval,
    327 			_("while reading journal super block"));
    328 		exit(1);
    329 	}
    330 	ext2fs_file_close(journal_file);
    331 	jsb = (journal_superblock_t *) buf;
    332 	if (be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) {
    333 		fprintf(stderr,
    334 			"Journal superblock magic number invalid!\n");
    335 		exit(1);
    336 	}
    337 	printf(_("Journal features:        "));
    338 	for (i=0, mask_ptr=&jsb->s_feature_compat; i <3; i++,mask_ptr++) {
    339 		mask = be32_to_cpu(*mask_ptr);
    340 		for (j=0,m=1; j < 32; j++, m<<=1) {
    341 			if (mask & m) {
    342 				printf(" %s", e2p_jrnl_feature2string(i, m));
    343 				printed++;
    344 			}
    345 		}
    346 	}
    347 	if (printed == 0)
    348 		printf(" (none)");
    349 	printf("\n");
    350 	fputs(_("Journal size:             "), stdout);
    351 	if ((fs->super->s_feature_ro_compat &
    352 	     EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
    353 	    (inode.i_flags & EXT4_HUGE_FILE_FL))
    354 		size = inode.i_blocks / (fs->blocksize / 1024);
    355 	else
    356 		size = inode.i_blocks >> 1;
    357 	if (size < 8192)
    358 		printf("%uk\n", size);
    359 	else
    360 		printf("%uM\n", size >> 10);
    361 	printf(_("Journal length:           %u\n"
    362 		 "Journal sequence:         0x%08x\n"
    363 		 "Journal start:            %u\n"),
    364 	       (unsigned int)ntohl(jsb->s_maxlen),
    365 	       (unsigned int)ntohl(jsb->s_sequence),
    366 	       (unsigned int)ntohl(jsb->s_start));
    367 }
    368 
    369 static void print_journal_information(ext2_filsys fs)
    370 {
    371 	errcode_t	retval;
    372 	char		buf[1024];
    373 	char		str[80];
    374 	unsigned int	i;
    375 	journal_superblock_t	*jsb;
    376 
    377 	/* Get the journal superblock */
    378 	if ((retval = io_channel_read_blk(fs->io, fs->super->s_first_data_block+1, -1024, buf))) {
    379 		com_err(program_name, retval,
    380 			_("while reading journal superblock"));
    381 		exit(1);
    382 	}
    383 	jsb = (journal_superblock_t *) buf;
    384 	if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
    385 	    (jsb->s_header.h_blocktype !=
    386 	     (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
    387 		com_err(program_name, 0,
    388 			_("Couldn't find journal superblock magic numbers"));
    389 		exit(1);
    390 	}
    391 
    392 	printf(_("\nJournal block size:       %u\n"
    393 		 "Journal length:           %u\n"
    394 		 "Journal first block:      %u\n"
    395 		 "Journal sequence:         0x%08x\n"
    396 		 "Journal start:            %u\n"
    397 		 "Journal number of users:  %u\n"),
    398 	       (unsigned int)ntohl(jsb->s_blocksize),  (unsigned int)ntohl(jsb->s_maxlen),
    399 	       (unsigned int)ntohl(jsb->s_first), (unsigned int)ntohl(jsb->s_sequence),
    400 	       (unsigned int)ntohl(jsb->s_start), (unsigned int)ntohl(jsb->s_nr_users));
    401 
    402 	for (i=0; i < ntohl(jsb->s_nr_users); i++) {
    403 		uuid_unparse(&jsb->s_users[i*16], str);
    404 		printf(i ? "                          %s\n"
    405 		       : _("Journal users:            %s\n"),
    406 		       str);
    407 	}
    408 }
    409 
    410 static void parse_extended_opts(const char *opts, blk_t *superblock,
    411 				int *blocksize)
    412 {
    413 	char	*buf, *token, *next, *p, *arg, *badopt = 0;
    414 	int	len;
    415 	int	do_usage = 0;
    416 
    417 	len = strlen(opts);
    418 	buf = malloc(len+1);
    419 	if (!buf) {
    420 		fprintf(stderr,
    421 			_("Couldn't allocate memory to parse options!\n"));
    422 		exit(1);
    423 	}
    424 	strcpy(buf, opts);
    425 	for (token = buf; token && *token; token = next) {
    426 		p = strchr(token, ',');
    427 		next = 0;
    428 		if (p) {
    429 			*p = 0;
    430 			next = p+1;
    431 		}
    432 		arg = strchr(token, '=');
    433 		if (arg) {
    434 			*arg = 0;
    435 			arg++;
    436 		}
    437 		if (strcmp(token, "superblock") == 0 ||
    438 		    strcmp(token, "sb") == 0) {
    439 			if (!arg) {
    440 				do_usage++;
    441 				badopt = token;
    442 				continue;
    443 			}
    444 			*superblock = strtoul(arg, &p, 0);
    445 			if (*p) {
    446 				fprintf(stderr,
    447 					_("Invalid superblock parameter: %s\n"),
    448 					arg);
    449 				do_usage++;
    450 				continue;
    451 			}
    452 		} else if (strcmp(token, "blocksize") == 0 ||
    453 			   strcmp(token, "bs") == 0) {
    454 			if (!arg) {
    455 				do_usage++;
    456 				badopt = token;
    457 				continue;
    458 			}
    459 			*blocksize = strtoul(arg, &p, 0);
    460 			if (*p) {
    461 				fprintf(stderr,
    462 					_("Invalid blocksize parameter: %s\n"),
    463 					arg);
    464 				do_usage++;
    465 				continue;
    466 			}
    467 		} else {
    468 			do_usage++;
    469 			badopt = token;
    470 		}
    471 	}
    472 	if (do_usage) {
    473 		fprintf(stderr, _("\nBad extended option(s) specified: %s\n\n"
    474 			"Extended options are separated by commas, "
    475 			"and may take an argument which\n"
    476 			"\tis set off by an equals ('=') sign.\n\n"
    477 			"Valid extended options are:\n"
    478 			"\tsuperblock=<superblock number>\n"
    479 			"\tblocksize=<blocksize>\n"),
    480 			badopt ? badopt : "");
    481 		free(buf);
    482 		exit(1);
    483 	}
    484 	free(buf);
    485 }
    486 
    487 int main (int argc, char ** argv)
    488 {
    489 	errcode_t	retval;
    490 	ext2_filsys	fs;
    491 	int		print_badblocks = 0;
    492 	blk_t		use_superblock = 0;
    493 	int		use_blocksize = 0;
    494 	int		image_dump = 0;
    495 	int		force = 0;
    496 	int		flags;
    497 	int		header_only = 0;
    498 	int		c;
    499 
    500 #ifdef ENABLE_NLS
    501 	setlocale(LC_MESSAGES, "");
    502 	setlocale(LC_CTYPE, "");
    503 	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
    504 	textdomain(NLS_CAT_NAME);
    505 #endif
    506 	add_error_table(&et_ext2_error_table);
    507 	fprintf (stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION,
    508 		 E2FSPROGS_DATE);
    509 	if (argc && *argv)
    510 		program_name = *argv;
    511 
    512 	while ((c = getopt (argc, argv, "bfhixVo:")) != EOF) {
    513 		switch (c) {
    514 		case 'b':
    515 			print_badblocks++;
    516 			break;
    517 		case 'f':
    518 			force++;
    519 			break;
    520 		case 'h':
    521 			header_only++;
    522 			break;
    523 		case 'i':
    524 			image_dump++;
    525 			break;
    526 		case 'o':
    527 			parse_extended_opts(optarg, &use_superblock,
    528 					    &use_blocksize);
    529 			break;
    530 		case 'V':
    531 			/* Print version number and exit */
    532 			fprintf(stderr, _("\tUsing %s\n"),
    533 				error_message(EXT2_ET_BASE));
    534 			exit(0);
    535 		case 'x':
    536 			hex_format++;
    537 			break;
    538 		default:
    539 			usage();
    540 		}
    541 	}
    542 	if (optind > argc - 1)
    543 		usage();
    544 	device_name = argv[optind++];
    545 	flags = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES;
    546 	if (force)
    547 		flags |= EXT2_FLAG_FORCE;
    548 	if (image_dump)
    549 		flags |= EXT2_FLAG_IMAGE_FILE;
    550 
    551 	if (use_superblock && !use_blocksize) {
    552 		for (use_blocksize = EXT2_MIN_BLOCK_SIZE;
    553 		     use_blocksize <= EXT2_MAX_BLOCK_SIZE;
    554 		     use_blocksize *= 2) {
    555 			retval = ext2fs_open (device_name, flags,
    556 					      use_superblock,
    557 					      use_blocksize, unix_io_manager,
    558 					      &fs);
    559 			if (!retval)
    560 				break;
    561 		}
    562 	} else
    563 		retval = ext2fs_open (device_name, flags, use_superblock,
    564 				      use_blocksize, unix_io_manager, &fs);
    565 	if (retval) {
    566 		com_err (program_name, retval, _("while trying to open %s"),
    567 			 device_name);
    568 		printf (_("Couldn't find valid filesystem superblock.\n"));
    569 		exit (1);
    570 	}
    571 	if (print_badblocks) {
    572 		list_bad_blocks(fs, 1);
    573 	} else {
    574 		list_super (fs->super);
    575 		if (fs->super->s_feature_incompat &
    576 		      EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
    577 			print_journal_information(fs);
    578 			ext2fs_close(fs);
    579 			exit(0);
    580 		}
    581 		if ((fs->super->s_feature_compat &
    582 		     EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
    583 		    (fs->super->s_journal_inum != 0))
    584 			print_inline_journal_information(fs);
    585 		list_bad_blocks(fs, 0);
    586 		if (header_only) {
    587 			ext2fs_close (fs);
    588 			exit (0);
    589 		}
    590 		retval = ext2fs_read_bitmaps (fs);
    591 		list_desc (fs);
    592 		if (retval) {
    593 			printf(_("\n%s: %s: error reading bitmaps: %s\n"),
    594 			       program_name, device_name,
    595 			       error_message(retval));
    596 		}
    597 	}
    598 	ext2fs_close (fs);
    599 	remove_error_table(&et_ext2_error_table);
    600 	exit (0);
    601 }
    602