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