2 * dumpe2fs.c - List the control structures of a second
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)
9 * Copyright 1995, 1996, 1997 by Theodore Ts'o.
12 * This file may be redistributed under the terms of the GNU Public
20 * 94/02/27 - Ported to use the ext2fs library
36 #include "ext2fs/ext2_fs.h"
38 #include "ext2fs/ext2fs.h"
40 #include "ext2fs/kernel-jbd.h"
41 #include <uuid/uuid.h>
43 #include "support/nls-enable.h"
44 #include "support/plausible.h"
45 #include "../version.h"
47 #define in_use(m, x) (ext2fs_test_bit ((x), (m)))
49 static const char * program_name
= "dumpe2fs";
50 static char * device_name
= NULL
;
51 static int hex_format
= 0;
52 static int blocks64
= 0;
54 static void usage(void)
56 fprintf(stderr
, _("Usage: %s [-bfghimxV] [-o superblock=<num>] "
57 "[-o blocksize=<num>] device\n"), program_name
);
61 static void print_number(unsigned long long num
)
65 printf("0x%08llx", num
);
67 printf("0x%04llx", num
);
72 static void print_range(unsigned long long a
, unsigned long long b
)
76 printf("0x%08llx-0x%08llx", a
, b
);
78 printf("0x%04llx-0x%04llx", a
, b
);
80 printf("%llu-%llu", a
, b
);
83 static void print_free(unsigned long group
, char * bitmap
,
84 unsigned long num
, unsigned long offset
, int ratio
)
91 offset
+= group
* num
;
92 for (i
= 0; i
< num
; i
++)
93 if (!in_use (bitmap
, i
))
97 print_number((i
+ offset
) * ratio
);
98 for (j
= i
; j
< num
&& !in_use (bitmap
, j
); j
++)
102 print_number((j
+ offset
) * ratio
);
109 static void print_bg_opt(int bg_flags
, int mask
,
110 const char *str
, int *first
)
112 if (bg_flags
& mask
) {
121 static void print_bg_opts(ext2_filsys fs
, dgrp_t i
)
123 int first
= 1, bg_flags
= 0;
125 if (ext2fs_has_group_desc_csum(fs
))
126 bg_flags
= ext2fs_bg_flags(fs
, i
);
128 print_bg_opt(bg_flags
, EXT2_BG_INODE_UNINIT
, "INODE_UNINIT",
130 print_bg_opt(bg_flags
, EXT2_BG_BLOCK_UNINIT
, "BLOCK_UNINIT",
132 print_bg_opt(bg_flags
, EXT2_BG_INODE_ZEROED
, "ITABLE_ZEROED",
139 static void print_bg_rel_offset(ext2_filsys fs
, blk64_t block
, int itable
,
140 blk64_t first_block
, blk64_t last_block
)
142 if ((block
>= first_block
) && (block
<= last_block
)) {
143 if (itable
&& block
== first_block
)
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
)));
153 static void list_desc(ext2_filsys fs
, int grp_only
)
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
;
163 blk64_t blk_itr
= EXT2FS_B2C(fs
, fs
->super
->s_first_data_block
);
164 ext2_ino_t ino_itr
= 1;
167 if (ext2fs_has_feature_bigalloc(fs
->super
))
168 units
= _("clusters");
170 block_nbytes
= EXT2_CLUSTERS_PER_GROUP(fs
->super
) / 8;
171 inode_nbytes
= EXT2_INODES_PER_GROUP(fs
->super
) / 8;
174 block_bitmap
= malloc(block_nbytes
);
176 inode_bitmap
= malloc(inode_nbytes
);
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
;
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
;
188 old_desc_blocks
= fs
->desc_blocks
;
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
);
195 ext2fs_super_and_bgd_loc2(fs
, i
, &super_blk
,
196 &old_desc_blk
, &new_desc_blk
, 0);
199 printf("%lu:%llu:", i
, first_block
);
200 if (i
== 0 || super_blk
)
201 printf("%llu:", super_blk
);
205 print_range(old_desc_blk
,
206 old_desc_blk
+ old_desc_blocks
- 1);
208 } else if (new_desc_blk
)
209 printf("%llu:", new_desc_blk
);
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
));
219 printf(_("Group %lu: (Blocks "), i
);
220 print_range(first_block
, last_block
);
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
);
226 printf(_(" csum 0x%04x"), csum
);
227 if (csum
!= exp_csum
)
228 printf(_(" (EXPECTED 0x%04x)"), exp_csum
);
230 print_bg_opts(fs
, i
);
231 has_super
= ((i
==0) || super_blk
);
233 printf (_(" %s superblock at "),
234 i
== 0 ? _("Primary") : _("Backup"));
235 print_number(super_blk
);
238 printf("%s", _(", Group descriptors at "));
239 print_range(old_desc_blk
,
240 old_desc_blk
+ old_desc_blocks
- 1);
242 printf("%s", _("\n Reserved GDT blocks at "));
243 print_range(old_desc_blk
+ old_desc_blocks
,
244 old_desc_blk
+ old_desc_blocks
+
247 } else if (new_desc_blk
) {
248 fputc(has_super
? ',' : ' ', stdout
);
249 printf("%s", _(" Group descriptor at "));
250 print_number(new_desc_blk
);
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
);
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, "
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
));
289 fputs(_(" Free blocks: "), stdout
);
290 retval
= ext2fs_get_block_bitmap_range2(fs
->block_map
,
291 blk_itr
, block_nbytes
<< 3, block_bitmap
);
293 com_err("list_desc", retval
,
294 "while reading block bitmap");
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
));
301 blk_itr
+= fs
->super
->s_clusters_per_group
;
304 fputs(_(" Free inodes: "), stdout
);
305 retval
= ext2fs_get_inode_bitmap_range2(fs
->inode_map
,
306 ino_itr
, inode_nbytes
<< 3, inode_bitmap
);
308 com_err("list_desc", retval
,
309 "while reading inode bitmap");
311 print_free(i
, inode_bitmap
,
312 fs
->super
->s_inodes_per_group
,
315 ino_itr
+= fs
->super
->s_inodes_per_group
;
324 static void list_bad_blocks(ext2_filsys fs
, int dump
)
326 badblocks_list bb_list
= 0;
327 badblocks_iterate bb_iter
;
330 const char *header
, *fmt
;
332 retval
= ext2fs_read_bb_inode(fs
, &bb_list
);
334 com_err("ext2fs_read_bb_inode", retval
, 0);
337 retval
= ext2fs_badblocks_list_iterate_begin(bb_list
, &bb_iter
);
339 com_err("ext2fs_badblocks_list_iterate_begin", retval
,
340 "%s", _("while printing bad block list"));
344 header
= fmt
= "%u\n";
346 header
= _("Bad blocks: %u");
349 while (ext2fs_badblocks_list_iterate(bb_iter
, &blk
)) {
350 printf(header
? header
: fmt
, blk
);
353 ext2fs_badblocks_list_iterate_end(bb_iter
);
356 ext2fs_badblocks_list_free(bb_list
);
359 static void print_inline_journal_information(ext2_filsys fs
)
361 journal_superblock_t
*jsb
;
362 struct ext2_inode inode
;
363 ext2_file_t journal_file
;
365 ino_t ino
= fs
->super
->s_journal_inum
;
368 if (fs
->flags
& EXT2_FLAG_IMAGE_FILE
)
370 retval
= ext2fs_read_inode(fs
, ino
, &inode
);
372 com_err(program_name
, retval
, "%s",
373 _("while reading journal inode"));
376 retval
= ext2fs_file_open2(fs
, ino
, &inode
, 0, &journal_file
);
378 com_err(program_name
, retval
, "%s",
379 _("while opening journal inode"));
382 retval
= ext2fs_file_read(journal_file
, buf
, sizeof(buf
), 0);
384 com_err(program_name
, retval
, "%s",
385 _("while reading journal super block"));
388 ext2fs_file_close(journal_file
);
389 jsb
= (journal_superblock_t
*) buf
;
390 if (be32_to_cpu(jsb
->s_header
.h_magic
) != JFS_MAGIC_NUMBER
) {
391 fprintf(stderr
, "%s",
392 _("Journal superblock magic number invalid!\n"));
395 e2p_list_journal_super(stdout
, buf
, fs
->blocksize
, 0);
398 static void print_journal_information(ext2_filsys fs
)
402 journal_superblock_t
*jsb
;
404 /* Get the journal superblock */
405 if ((retval
= io_channel_read_blk64(fs
->io
,
406 fs
->super
->s_first_data_block
+ 1,
408 com_err(program_name
, retval
, "%s",
409 _("while reading journal superblock"));
412 jsb
= (journal_superblock_t
*) buf
;
413 if ((jsb
->s_header
.h_magic
!= (unsigned) ntohl(JFS_MAGIC_NUMBER
)) ||
414 (jsb
->s_header
.h_blocktype
!=
415 (unsigned) ntohl(JFS_SUPERBLOCK_V2
))) {
416 com_err(program_name
, 0, "%s",
417 _("Couldn't find journal superblock magic numbers"));
420 e2p_list_journal_super(stdout
, buf
, fs
->blocksize
, 0);
423 static int check_mmp(ext2_filsys fs
)
427 /* This won't actually start MMP on the filesystem, since fs is opened
428 * readonly, but it will do the proper activity checking for us. */
429 retval
= ext2fs_mmp_start(fs
);
431 com_err(program_name
, retval
, _("while trying to open %s"),
433 if (retval
== EXT2_ET_MMP_FAILED
||
434 retval
== EXT2_ET_MMP_FSCK_ON
||
435 retval
== EXT2_ET_MMP_CSUM_INVALID
||
436 retval
== EXT2_ET_MMP_UNKNOWN_SEQ
) {
438 struct mmp_struct
*mmp
= fs
->mmp_buf
;
439 time_t mmp_time
= mmp
->mmp_time
;
442 "%s: MMP update by '%.*s%.*s' at %s",
444 EXT2_LEN_STR(mmp
->mmp_nodename
),
445 EXT2_LEN_STR(mmp
->mmp_bdevname
),
453 printf("%s: it is safe to mount '%s', MMP is clean\n",
454 program_name
, fs
->device_name
);
460 static void print_mmp_block(ext2_filsys fs
)
462 struct mmp_struct
*mmp
;
466 if (fs
->mmp_buf
== NULL
) {
467 retval
= ext2fs_get_mem(fs
->blocksize
, &fs
->mmp_buf
);
469 com_err(program_name
, retval
,
470 _("failed to alloc MMP buffer\n"));
475 retval
= ext2fs_mmp_read(fs
, fs
->super
->s_mmp_block
, fs
->mmp_buf
);
476 /* this is only dumping, not checking status, so OK to skip this */
477 if (retval
== EXT2_ET_OP_NOT_SUPPORTED
)
480 com_err(program_name
, retval
,
481 _("reading MMP block %llu from '%s'\n"),
482 fs
->super
->s_mmp_block
, fs
->device_name
);
487 mmp_time
= mmp
->mmp_time
;
488 printf("MMP_block:\n");
489 printf(" mmp_magic: 0x%x\n", mmp
->mmp_magic
);
490 printf(" mmp_check_interval: %d\n", mmp
->mmp_check_interval
);
491 printf(" mmp_sequence: %#08x\n", mmp
->mmp_seq
);
492 printf(" mmp_update_date: %s", ctime(&mmp_time
));
493 printf(" mmp_update_time: %lld\n", mmp
->mmp_time
);
494 printf(" mmp_node_name: %.*s\n",
495 EXT2_LEN_STR(mmp
->mmp_nodename
));
496 printf(" mmp_device_name: %.*s\n",
497 EXT2_LEN_STR(mmp
->mmp_bdevname
));
500 static void parse_extended_opts(const char *opts
, blk64_t
*superblock
,
503 char *buf
, *token
, *next
, *p
, *arg
, *badopt
= 0;
510 fprintf(stderr
, "%s",
511 _("Couldn't allocate memory to parse options!\n"));
515 for (token
= buf
; token
&& *token
; token
= next
) {
516 p
= strchr(token
, ',');
522 arg
= strchr(token
, '=');
527 if (strcmp(token
, "superblock") == 0 ||
528 strcmp(token
, "sb") == 0) {
534 *superblock
= strtoul(arg
, &p
, 0);
537 _("Invalid superblock parameter: %s\n"),
542 } else if (strcmp(token
, "blocksize") == 0 ||
543 strcmp(token
, "bs") == 0) {
549 *blocksize
= strtoul(arg
, &p
, 0);
552 _("Invalid blocksize parameter: %s\n"),
563 fprintf(stderr
, _("\nBad extended option(s) specified: %s\n\n"
564 "Extended options are separated by commas, "
565 "and may take an argument which\n"
566 "\tis set off by an equals ('=') sign.\n\n"
567 "Valid extended options are:\n"
568 "\tsuperblock=<superblock number>\n"
569 "\tblocksize=<blocksize>\n"),
570 badopt
? badopt
: "");
577 int main (int argc
, char ** argv
)
580 errcode_t retval_csum
= 0;
581 const char *error_csum
= NULL
;
583 int print_badblocks
= 0;
584 blk64_t use_superblock
= 0;
585 int use_blocksize
= 0;
596 setlocale(LC_MESSAGES
, "");
597 setlocale(LC_CTYPE
, "");
598 bindtextdomain(NLS_CAT_NAME
, LOCALEDIR
);
599 textdomain(NLS_CAT_NAME
);
600 set_com_err_gettext(gettext
);
602 add_error_table(&et_ext2_error_table
);
604 if (strrchr(*argv
, '/'))
605 program_name
= strrchr(*argv
, '/') + 1;
607 program_name
= *argv
;
609 if (strstr(program_name
, "mmpstatus") != NULL
) {
616 fprintf(stderr
, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION
,
619 while ((c
= getopt(argc
, argv
, "bfghimxVo:")) != EOF
) {
643 mmp_info
= image_dump
;
648 parse_extended_opts(optarg
, &use_superblock
,
652 /* Print version number and exit */
653 fprintf(stderr
, _("\tUsing %s\n"),
654 error_message(EXT2_ET_BASE
));
663 if (optind
!= argc
- 1)
666 device_name
= argv
[optind
++];
667 flags
= EXT2_FLAG_JOURNAL_DEV_OK
| EXT2_FLAG_SOFTSUPP_FEATURES
|
670 flags
|= EXT2_FLAG_FORCE
;
672 flags
|= EXT2_FLAG_IMAGE_FILE
;
674 if (use_superblock
&& !use_blocksize
) {
675 for (use_blocksize
= EXT2_MIN_BLOCK_SIZE
;
676 use_blocksize
<= EXT2_MAX_BLOCK_SIZE
;
677 use_blocksize
*= 2) {
678 retval
= ext2fs_open (device_name
, flags
,
680 use_blocksize
, unix_io_manager
,
686 retval
= ext2fs_open(device_name
, flags
, use_superblock
,
687 use_blocksize
, unix_io_manager
, &fs
);
689 flags
|= EXT2_FLAG_IGNORE_CSUM_ERRORS
;
690 if (retval
&& !retval_csum
) {
691 retval_csum
= retval
;
692 error_csum
= _("while trying to open %s");
696 com_err(program_name
, retval
, _("while trying to open %s"),
698 printf("%s", _("Couldn't find valid filesystem superblock.\n"));
699 if (retval
== EXT2_ET_BAD_MAGIC
)
700 check_plausibility(device_name
, CHECK_FS_EXIST
, NULL
);
703 fs
->default_bitmap_type
= EXT2FS_BMAP64_RBTREE
;
704 if (ext2fs_has_feature_64bit(fs
->super
))
707 if (ext2fs_has_feature_mmp(fs
->super
) &&
708 fs
->super
->s_mmp_block
!= 0) {
711 printf(" mmp_block_number: ");
712 print_number(fs
->super
->s_mmp_block
);
715 retval
= check_mmp(fs
);
717 if (!retval
&& retval_csum
)
720 fprintf(stderr
, _("%s: MMP feature not enabled.\n"),
724 } else if (print_badblocks
) {
725 list_bad_blocks(fs
, 1);
728 goto just_descriptors
;
729 list_super(fs
->super
);
730 if (ext2fs_has_feature_journal_dev(fs
->super
)) {
731 print_journal_information(fs
);
735 if (ext2fs_has_feature_journal(fs
->super
) &&
736 (fs
->super
->s_journal_inum
!= 0))
737 print_inline_journal_information(fs
);
738 if (ext2fs_has_feature_mmp(fs
->super
) &&
739 fs
->super
->s_mmp_block
!= 0)
741 list_bad_blocks(fs
, 0);
745 fs
->flags
&= ~EXT2_FLAG_IGNORE_CSUM_ERRORS
;
747 retval
= ext2fs_read_bitmaps(fs
);
748 if (retval
&& !retval_csum
) {
749 fs
->flags
|= EXT2_FLAG_IGNORE_CSUM_ERRORS
;
750 retval_csum
= retval
;
751 error_csum
= _("while trying to read '%s' bitmaps\n");
752 goto try_bitmaps_again
;
755 list_desc(fs
, grp_only
);
759 com_err(program_name
, retval_csum
, error_csum
, device_name
);
760 printf("%s", _("*** Run e2fsck now!\n\n"));
762 retval
= retval_csum
;
764 ext2fs_close_free(&fs
);
765 remove_error_table(&et_ext2_error_table
);