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