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