]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
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 | * | |
19c78dc0 TT |
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% | |
3839e657 TT |
15 | */ |
16 | ||
17 | /* | |
18 | * History: | |
19 | * 94/01/09 - Creation | |
20 | * 94/02/27 - Ported to use the ext2fs library | |
21 | */ | |
22 | ||
d1154eb4 | 23 | #include "config.h" |
a418d3ad | 24 | #ifdef HAVE_GETOPT_H |
3839e657 | 25 | #include <getopt.h> |
373b8337 TT |
26 | #else |
27 | extern char *optarg; | |
28 | extern int optind; | |
a418d3ad | 29 | #endif |
3839e657 TT |
30 | #include <fcntl.h> |
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
33 | #include <string.h> | |
34 | #include <unistd.h> | |
35 | ||
54c637d4 | 36 | #include "ext2fs/ext2_fs.h" |
3839e657 TT |
37 | |
38 | #include "ext2fs/ext2fs.h" | |
39 | #include "e2p/e2p.h" | |
81f95d43 | 40 | #include "ext2fs/kernel-jbd.h" |
4ea7bd04 | 41 | #include <uuid/uuid.h> |
3839e657 | 42 | |
99ceb8ec TT |
43 | #include "support/nls-enable.h" |
44 | #include "support/plausible.h" | |
3839e657 TT |
45 | #include "../version.h" |
46 | ||
74becf3c | 47 | #define in_use(m, x) (ext2fs_test_bit ((x), (m))) |
3839e657 | 48 | |
f404167d TT |
49 | static const char * program_name = "dumpe2fs"; |
50 | static char * device_name = NULL; | |
51 | static int hex_format = 0; | |
52 | static int blocks64 = 0; | |
3839e657 | 53 | |
818180cd | 54 | static void usage(void) |
3839e657 | 55 | { |
32b8802a | 56 | fprintf(stderr, _("Usage: %s [-bfghimxV] [-o superblock=<num>] " |
77f464fb | 57 | "[-o blocksize=<num>] device\n"), program_name); |
0858268d | 58 | exit(1); |
3839e657 TT |
59 | } |
60 | ||
ce10c313 | 61 | static void print_number(unsigned long long num) |
54434927 | 62 | { |
ce10c313 TT |
63 | if (hex_format) { |
64 | if (blocks64) | |
65 | printf("0x%08llx", num); | |
66 | else | |
67 | printf("0x%04llx", num); | |
68 | } else | |
69 | printf("%llu", num); | |
9b9a780f TT |
70 | } |
71 | ||
295c3e03 | 72 | static void print_range(unsigned long long a, unsigned long long b) |
9b9a780f | 73 | { |
ce10c313 TT |
74 | if (hex_format) { |
75 | if (blocks64) | |
76 | printf("0x%08llx-0x%08llx", a, b); | |
77 | else | |
78 | printf("0x%04llx-0x%04llx", a, b); | |
79 | } else | |
295c3e03 | 80 | printf("%llu-%llu", a, b); |
54434927 TT |
81 | } |
82 | ||
bcb942c2 TT |
83 | static void print_free(unsigned long group, char * bitmap, |
84 | unsigned long num, unsigned long offset, int ratio) | |
3839e657 TT |
85 | { |
86 | int p = 0; | |
87 | unsigned long i; | |
88 | unsigned long j; | |
89 | ||
bcb942c2 TT |
90 | offset /= ratio; |
91 | offset += group * num; | |
92 | for (i = 0; i < num; i++) | |
3839e657 TT |
93 | if (!in_use (bitmap, i)) |
94 | { | |
95 | if (p) | |
96 | printf (", "); | |
bcb942c2 TT |
97 | print_number((i + offset) * ratio); |
98 | for (j = i; j < num && !in_use (bitmap, j); j++) | |
a5f0bb9d TT |
99 | ; |
100 | if (--j != i) { | |
101 | fputc('-', stdout); | |
bcb942c2 | 102 | print_number((j + offset) * ratio); |
a5f0bb9d | 103 | i = j; |
3839e657 TT |
104 | } |
105 | p = 1; | |
106 | } | |
107 | } | |
108 | ||
f5fa2007 TT |
109 | static void print_bg_opt(int bg_flags, int mask, |
110 | const char *str, int *first) | |
111 | { | |
112 | if (bg_flags & mask) { | |
113 | if (*first) { | |
114 | fputs(" [", stdout); | |
115 | *first = 0; | |
116 | } else | |
117 | fputs(", ", stdout); | |
118 | fputs(str, stdout); | |
119 | } | |
120 | } | |
121 | static void print_bg_opts(ext2_filsys fs, dgrp_t i) | |
122 | { | |
16b851cd | 123 | int first = 1, bg_flags = 0; |
f5fa2007 | 124 | |
5b58dc23 | 125 | if (ext2fs_has_group_desc_csum(fs)) |
732c8cd5 | 126 | bg_flags = ext2fs_bg_flags(fs, i); |
f5fa2007 | 127 | |
b89fc30d | 128 | print_bg_opt(bg_flags, EXT2_BG_INODE_UNINIT, "INODE_UNINIT", |
f5fa2007 | 129 | &first); |
b89fc30d TT |
130 | print_bg_opt(bg_flags, EXT2_BG_BLOCK_UNINIT, "BLOCK_UNINIT", |
131 | &first); | |
132 | print_bg_opt(bg_flags, EXT2_BG_INODE_ZEROED, "ITABLE_ZEROED", | |
f5fa2007 TT |
133 | &first); |
134 | if (!first) | |
135 | fputc(']', stdout); | |
136 | fputc('\n', stdout); | |
137 | } | |
138 | ||
0e2afdba AD |
139 | static void print_bg_rel_offset(ext2_filsys fs, blk64_t block, int itable, |
140 | blk64_t first_block, blk64_t last_block) | |
141 | { | |
142 | if ((block >= first_block) && (block <= last_block)) { | |
143 | if (itable && block == first_block) | |
144 | return; | |
145 | printf(" (+%u)", (unsigned)(block - first_block)); | |
7889640d | 146 | } else if (ext2fs_has_feature_flex_bg(fs->super)) { |
4dbfd79d | 147 | dgrp_t flex_grp = ext2fs_group_of_blk2(fs, block); |
0e2afdba | 148 | printf(" (bg #%u + %u)", flex_grp, |
26da6614 | 149 | (unsigned)(block-ext2fs_group_first_block2(fs,flex_grp))); |
0e2afdba AD |
150 | } |
151 | } | |
152 | ||
0858268d | 153 | static void list_desc(ext2_filsys fs, int grp_only) |
3839e657 TT |
154 | { |
155 | unsigned long i; | |
295c3e03 TT |
156 | blk64_t first_block, last_block; |
157 | blk64_t super_blk, old_desc_blk, new_desc_blk; | |
d90a23e2 | 158 | char *block_bitmap=NULL, *inode_bitmap=NULL; |
2418dfd7 | 159 | const char *units = _("blocks"); |
35238dd1 | 160 | int inode_blocks_per_group, old_desc_blocks, reserved_gdt; |
f1f115a7 | 161 | int block_nbytes, inode_nbytes; |
ef344e13 | 162 | int has_super; |
6a6337c3 | 163 | blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); |
f1f115a7 | 164 | ext2_ino_t ino_itr = 1; |
6908c0c3 | 165 | errcode_t retval; |
f1f115a7 | 166 | |
7889640d | 167 | if (ext2fs_has_feature_bigalloc(fs->super)) |
2418dfd7 TT |
168 | units = _("clusters"); |
169 | ||
bcb942c2 | 170 | block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; |
f1f115a7 | 171 | inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; |
80c22c90 | 172 | |
d90a23e2 | 173 | if (fs->block_map) |
f1f115a7 | 174 | block_bitmap = malloc(block_nbytes); |
d90a23e2 | 175 | if (fs->inode_map) |
f1f115a7 | 176 | inode_bitmap = malloc(inode_nbytes); |
d90a23e2 | 177 | |
80c22c90 TT |
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); | |
35238dd1 | 182 | reserved_gdt = fs->super->s_reserved_gdt_blocks; |
a5f0bb9d | 183 | fputc('\n', stdout); |
bb1a46a4 | 184 | first_block = fs->super->s_first_data_block; |
7889640d | 185 | if (ext2fs_has_feature_meta_bg(fs->super)) |
76dd5e5c TT |
186 | old_desc_blocks = fs->super->s_first_meta_bg; |
187 | else | |
188 | old_desc_blocks = fs->desc_blocks; | |
0858268d DW |
189 | if (grp_only) |
190 | printf("group:block:super:gdt:bbitmap:ibitmap:itable\n"); | |
521e3685 | 191 | for (i = 0; i < fs->group_desc_count; i++) { |
b49f78fe TT |
192 | first_block = ext2fs_group_first_block2(fs, i); |
193 | last_block = ext2fs_group_last_block2(fs, i); | |
abf23439 | 194 | |
295c3e03 TT |
195 | ext2fs_super_and_bgd_loc2(fs, i, &super_blk, |
196 | &old_desc_blk, &new_desc_blk, 0); | |
bb1a46a4 | 197 | |
0858268d DW |
198 | if (grp_only) { |
199 | printf("%lu:%llu:", i, first_block); | |
200 | if (i == 0 || super_blk) | |
201 | printf("%llu:", super_blk); | |
202 | else | |
203 | printf("-1:"); | |
204 | if (old_desc_blk) { | |
205 | print_range(old_desc_blk, | |
206 | old_desc_blk + old_desc_blocks - 1); | |
207 | printf(":"); | |
208 | } else if (new_desc_blk) | |
209 | printf("%llu:", new_desc_blk); | |
210 | else | |
211 | printf("-1:"); | |
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)); | |
216 | continue; | |
217 | } | |
218 | ||
492084ff | 219 | printf(_("Group %lu: (Blocks "), i); |
bb1a46a4 | 220 | print_range(first_block, last_block); |
f5fa2007 | 221 | fputs(")", stdout); |
5b58dc23 | 222 | if (ext2fs_has_group_desc_csum(fs)) { |
87141781 TT |
223 | unsigned csum = ext2fs_bg_checksum(fs, i); |
224 | unsigned exp_csum = ext2fs_group_desc_csum(fs, i); | |
225 | ||
492084ff | 226 | printf(_(" csum 0x%04x"), csum); |
87141781 TT |
227 | if (csum != exp_csum) |
228 | printf(_(" (EXPECTED 0x%04x)"), exp_csum); | |
87141781 | 229 | } |
492084ff | 230 | print_bg_opts(fs, i); |
ef344e13 | 231 | has_super = ((i==0) || super_blk); |
c046ac7f TT |
232 | if (has_super) { |
233 | printf (_(" %s superblock at "), | |
a5f0bb9d | 234 | i == 0 ? _("Primary") : _("Backup")); |
54434927 | 235 | print_number(super_blk); |
c046ac7f | 236 | } |
ef344e13 | 237 | if (old_desc_blk) { |
45ff69ff | 238 | printf("%s", _(", Group descriptors at ")); |
efc6f628 | 239 | print_range(old_desc_blk, |
9b9a780f | 240 | old_desc_blk + old_desc_blocks - 1); |
35238dd1 | 241 | if (reserved_gdt) { |
45ff69ff | 242 | printf("%s", _("\n Reserved GDT blocks at ")); |
9b9a780f | 243 | print_range(old_desc_blk + old_desc_blocks, |
efc6f628 | 244 | old_desc_blk + old_desc_blocks + |
9b9a780f | 245 | reserved_gdt - 1); |
35238dd1 | 246 | } |
ef344e13 TT |
247 | } else if (new_desc_blk) { |
248 | fputc(has_super ? ',' : ' ', stdout); | |
45ff69ff | 249 | printf("%s", _(" Group descriptor at ")); |
54434927 | 250 | print_number(new_desc_blk); |
ef344e13 | 251 | has_super++; |
a5f0bb9d | 252 | } |
ef344e13 TT |
253 | if (has_super) |
254 | fputc('\n', stdout); | |
a5f0bb9d | 255 | fputs(_(" Block bitmap at "), stdout); |
d7cca6b0 | 256 | print_number(ext2fs_block_bitmap_loc(fs, i)); |
0358c9f9 | 257 | print_bg_rel_offset(fs, ext2fs_block_bitmap_loc(fs, i), 0, |
0e2afdba | 258 | first_block, last_block); |
7889640d | 259 | if (ext2fs_has_feature_metadata_csum(fs->super)) |
24c6c8b6 DW |
260 | printf(_(", csum 0x%08x"), |
261 | ext2fs_block_bitmap_checksum(fs, i)); | |
6aa8cff3 DW |
262 | if (getenv("DUMPE2FS_IGNORE_80COL")) |
263 | fputs(_(","), stdout); | |
264 | else | |
265 | fputs(_("\n "), stdout); | |
266 | fputs(_(" Inode bitmap at "), stdout); | |
d7cca6b0 | 267 | print_number(ext2fs_inode_bitmap_loc(fs, i)); |
0358c9f9 | 268 | print_bg_rel_offset(fs, ext2fs_inode_bitmap_loc(fs, i), 0, |
0e2afdba | 269 | first_block, last_block); |
7889640d | 270 | if (ext2fs_has_feature_metadata_csum(fs->super)) |
62039172 DW |
271 | printf(_(", csum 0x%08x"), |
272 | ext2fs_inode_bitmap_checksum(fs, i)); | |
a5f0bb9d | 273 | fputs(_("\n Inode table at "), stdout); |
d7cca6b0 VAH |
274 | print_range(ext2fs_inode_table_loc(fs, i), |
275 | ext2fs_inode_table_loc(fs, i) + | |
9b9a780f | 276 | inode_blocks_per_group - 1); |
0358c9f9 | 277 | print_bg_rel_offset(fs, ext2fs_inode_table_loc(fs, i), 1, |
0e2afdba | 278 | first_block, last_block); |
2418dfd7 | 279 | printf (_("\n %u free %s, %u free inodes, " |
777a8c1b | 280 | "%u directories%s"), |
2418dfd7 | 281 | ext2fs_bg_free_blocks_count(fs, i), units, |
d7cca6b0 VAH |
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)) | |
777a8c1b | 286 | printf (_(", %u unused inodes\n"), |
d7cca6b0 | 287 | ext2fs_bg_itable_unused(fs, i)); |
d90a23e2 TT |
288 | if (block_bitmap) { |
289 | fputs(_(" Free blocks: "), stdout); | |
6908c0c3 | 290 | retval = ext2fs_get_block_bitmap_range2(fs->block_map, |
f1f115a7 | 291 | blk_itr, block_nbytes << 3, block_bitmap); |
6908c0c3 DW |
292 | if (retval) |
293 | com_err("list_desc", retval, | |
294 | "while reading block bitmap"); | |
295 | else | |
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)); | |
d90a23e2 | 300 | fputc('\n', stdout); |
bcb942c2 | 301 | blk_itr += fs->super->s_clusters_per_group; |
d90a23e2 TT |
302 | } |
303 | if (inode_bitmap) { | |
304 | fputs(_(" Free inodes: "), stdout); | |
6908c0c3 | 305 | retval = ext2fs_get_inode_bitmap_range2(fs->inode_map, |
f1f115a7 | 306 | ino_itr, inode_nbytes << 3, inode_bitmap); |
6908c0c3 DW |
307 | if (retval) |
308 | com_err("list_desc", retval, | |
309 | "while reading inode bitmap"); | |
310 | else | |
311 | print_free(i, inode_bitmap, | |
312 | fs->super->s_inodes_per_group, | |
313 | 1, 1); | |
d90a23e2 | 314 | fputc('\n', stdout); |
f1f115a7 | 315 | ino_itr += fs->super->s_inodes_per_group; |
d90a23e2 | 316 | } |
3839e657 | 317 | } |
1acde2b2 TT |
318 | if (block_bitmap) |
319 | free(block_bitmap); | |
320 | if (inode_bitmap) | |
321 | free(inode_bitmap); | |
3839e657 TT |
322 | } |
323 | ||
0655b104 | 324 | static void list_bad_blocks(ext2_filsys fs, int dump) |
3839e657 TT |
325 | { |
326 | badblocks_list bb_list = 0; | |
327 | badblocks_iterate bb_iter; | |
328 | blk_t blk; | |
329 | errcode_t retval; | |
0655b104 | 330 | const char *header, *fmt; |
3839e657 TT |
331 | |
332 | retval = ext2fs_read_bb_inode(fs, &bb_list); | |
333 | if (retval) { | |
9b9a780f | 334 | com_err("ext2fs_read_bb_inode", retval, 0); |
0655b104 | 335 | return; |
3839e657 | 336 | } |
cbbf031b | 337 | retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter); |
3839e657 | 338 | if (retval) { |
cbbf031b | 339 | com_err("ext2fs_badblocks_list_iterate_begin", retval, |
45ff69ff | 340 | "%s", _("while printing bad block list")); |
0655b104 | 341 | return; |
3839e657 | 342 | } |
0655b104 | 343 | if (dump) { |
d0ff90d5 | 344 | header = fmt = "%u\n"; |
0655b104 | 345 | } else { |
d0ff90d5 ES |
346 | header = _("Bad blocks: %u"); |
347 | fmt = ", %u"; | |
f3db3566 | 348 | } |
0655b104 TT |
349 | while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) { |
350 | printf(header ? header : fmt, blk); | |
351 | header = 0; | |
f3db3566 | 352 | } |
cbbf031b | 353 | ext2fs_badblocks_list_iterate_end(bb_iter); |
0655b104 TT |
354 | if (!dump) |
355 | fputc('\n', stdout); | |
1acde2b2 | 356 | ext2fs_badblocks_list_free(bb_list); |
1e3472c5 | 357 | } |
f3db3566 | 358 | |
6515a6f1 TT |
359 | static void print_inline_journal_information(ext2_filsys fs) |
360 | { | |
1d9b8183 | 361 | journal_superblock_t *jsb; |
6515a6f1 | 362 | struct ext2_inode inode; |
1d9b8183 | 363 | ext2_file_t journal_file; |
6515a6f1 TT |
364 | errcode_t retval; |
365 | ino_t ino = fs->super->s_journal_inum; | |
1d9b8183 | 366 | char buf[1024]; |
efc6f628 | 367 | |
7fcaabf8 TT |
368 | if (fs->flags & EXT2_FLAG_IMAGE_FILE) |
369 | return; | |
6515a6f1 TT |
370 | retval = ext2fs_read_inode(fs, ino, &inode); |
371 | if (retval) { | |
45ff69ff | 372 | com_err(program_name, retval, "%s", |
6515a6f1 TT |
373 | _("while reading journal inode")); |
374 | exit(1); | |
375 | } | |
1d9b8183 TT |
376 | retval = ext2fs_file_open2(fs, ino, &inode, 0, &journal_file); |
377 | if (retval) { | |
45ff69ff | 378 | com_err(program_name, retval, "%s", |
1d9b8183 TT |
379 | _("while opening journal inode")); |
380 | exit(1); | |
381 | } | |
382 | retval = ext2fs_file_read(journal_file, buf, sizeof(buf), 0); | |
383 | if (retval) { | |
45ff69ff | 384 | com_err(program_name, retval, "%s", |
1d9b8183 TT |
385 | _("while reading journal super block")); |
386 | exit(1); | |
387 | } | |
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) { | |
45ff69ff AD |
391 | fprintf(stderr, "%s", |
392 | _("Journal superblock magic number invalid!\n")); | |
1d9b8183 TT |
393 | exit(1); |
394 | } | |
03a179a1 | 395 | e2p_list_journal_super(stdout, buf, fs->blocksize, 0); |
6515a6f1 TT |
396 | } |
397 | ||
16ed5b3a TT |
398 | static void print_journal_information(ext2_filsys fs) |
399 | { | |
400 | errcode_t retval; | |
401 | char buf[1024]; | |
16ed5b3a TT |
402 | journal_superblock_t *jsb; |
403 | ||
404 | /* Get the journal superblock */ | |
45ff69ff AD |
405 | if ((retval = io_channel_read_blk64(fs->io, |
406 | fs->super->s_first_data_block + 1, | |
407 | -1024, buf))) { | |
408 | com_err(program_name, retval, "%s", | |
16ed5b3a TT |
409 | _("while reading journal superblock")); |
410 | exit(1); | |
411 | } | |
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))) { | |
45ff69ff | 416 | com_err(program_name, 0, "%s", |
16ed5b3a TT |
417 | _("Couldn't find journal superblock magic numbers")); |
418 | exit(1); | |
419 | } | |
03a179a1 | 420 | e2p_list_journal_super(stdout, buf, fs->blocksize, 0); |
16ed5b3a TT |
421 | } |
422 | ||
32b8802a SI |
423 | static int check_mmp(ext2_filsys fs) |
424 | { | |
425 | int retval; | |
426 | ||
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); | |
430 | if (retval) { | |
431 | com_err(program_name, retval, _("while trying to open %s"), | |
432 | fs->device_name); | |
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) { | |
437 | if (fs->mmp_buf) { | |
438 | struct mmp_struct *mmp = fs->mmp_buf; | |
439 | time_t mmp_time = mmp->mmp_time; | |
440 | ||
441 | fprintf(stderr, | |
442 | "%s: MMP last updated by '%s' on %s", | |
443 | program_name, mmp->mmp_nodename, | |
444 | ctime(&mmp_time)); | |
445 | } | |
446 | retval = 1; | |
447 | } else { | |
448 | retval = 2; | |
449 | } | |
450 | } else { | |
451 | printf("%s: it is safe to mount '%s', MMP is clean\n", | |
452 | program_name, fs->device_name); | |
453 | } | |
454 | ||
455 | return retval; | |
456 | } | |
457 | ||
458 | static void print_mmp_block(ext2_filsys fs) | |
459 | { | |
460 | struct mmp_struct *mmp; | |
461 | time_t mmp_time; | |
462 | errcode_t retval; | |
463 | ||
464 | if (fs->mmp_buf == NULL) { | |
465 | retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf); | |
466 | if (retval) { | |
467 | com_err(program_name, retval, | |
468 | _("failed to alloc MMP buffer\n")); | |
469 | return; | |
470 | } | |
471 | } | |
472 | ||
473 | retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); | |
474 | /* this is only dumping, not checking status, so OK to skip this */ | |
475 | if (retval == EXT2_ET_OP_NOT_SUPPORTED) | |
476 | return; | |
477 | if (retval) { | |
478 | com_err(program_name, retval, | |
479 | _("reading MMP block %llu from '%s'\n"), | |
480 | fs->super->s_mmp_block, fs->device_name); | |
481 | return; | |
482 | } | |
483 | ||
484 | mmp = fs->mmp_buf; | |
485 | mmp_time = mmp->mmp_time; | |
486 | printf("MMP_block:\n"); | |
487 | printf(" mmp_magic: 0x%x\n", mmp->mmp_magic); | |
488 | printf(" mmp_check_interval: %d\n", mmp->mmp_check_interval); | |
489 | printf(" mmp_sequence: %#08x\n", mmp->mmp_seq); | |
490 | printf(" mmp_update_date: %s", ctime(&mmp_time)); | |
491 | printf(" mmp_update_time: %lld\n", mmp->mmp_time); | |
492 | printf(" mmp_node_name: %s\n", mmp->mmp_nodename); | |
493 | printf(" mmp_device_name: %s\n", mmp->mmp_bdevname); | |
494 | } | |
495 | ||
295c3e03 | 496 | static void parse_extended_opts(const char *opts, blk64_t *superblock, |
db197a81 TT |
497 | int *blocksize) |
498 | { | |
2d328bb7 | 499 | char *buf, *token, *next, *p, *arg, *badopt = 0; |
db197a81 | 500 | int len; |
2d328bb7 | 501 | int do_usage = 0; |
db197a81 TT |
502 | |
503 | len = strlen(opts); | |
504 | buf = malloc(len+1); | |
505 | if (!buf) { | |
45ff69ff | 506 | fprintf(stderr, "%s", |
db197a81 TT |
507 | _("Couldn't allocate memory to parse options!\n")); |
508 | exit(1); | |
509 | } | |
510 | strcpy(buf, opts); | |
511 | for (token = buf; token && *token; token = next) { | |
512 | p = strchr(token, ','); | |
513 | next = 0; | |
514 | if (p) { | |
515 | *p = 0; | |
516 | next = p+1; | |
517 | } | |
518 | arg = strchr(token, '='); | |
519 | if (arg) { | |
520 | *arg = 0; | |
521 | arg++; | |
522 | } | |
523 | if (strcmp(token, "superblock") == 0 || | |
524 | strcmp(token, "sb") == 0) { | |
525 | if (!arg) { | |
2d328bb7 | 526 | do_usage++; |
db197a81 TT |
527 | badopt = token; |
528 | continue; | |
529 | } | |
530 | *superblock = strtoul(arg, &p, 0); | |
531 | if (*p) { | |
532 | fprintf(stderr, | |
533 | _("Invalid superblock parameter: %s\n"), | |
534 | arg); | |
2d328bb7 | 535 | do_usage++; |
db197a81 TT |
536 | continue; |
537 | } | |
538 | } else if (strcmp(token, "blocksize") == 0 || | |
539 | strcmp(token, "bs") == 0) { | |
540 | if (!arg) { | |
2d328bb7 | 541 | do_usage++; |
db197a81 TT |
542 | badopt = token; |
543 | continue; | |
544 | } | |
545 | *blocksize = strtoul(arg, &p, 0); | |
546 | if (*p) { | |
547 | fprintf(stderr, | |
548 | _("Invalid blocksize parameter: %s\n"), | |
549 | arg); | |
2d328bb7 | 550 | do_usage++; |
db197a81 TT |
551 | continue; |
552 | } | |
553 | } else { | |
2d328bb7 | 554 | do_usage++; |
db197a81 TT |
555 | badopt = token; |
556 | } | |
557 | } | |
2d328bb7 | 558 | if (do_usage) { |
db197a81 TT |
559 | fprintf(stderr, _("\nBad extended option(s) specified: %s\n\n" |
560 | "Extended options are separated by commas, " | |
561 | "and may take an argument which\n" | |
562 | "\tis set off by an equals ('=') sign.\n\n" | |
563 | "Valid extended options are:\n" | |
564 | "\tsuperblock=<superblock number>\n" | |
565 | "\tblocksize=<blocksize>\n"), | |
2d328bb7 | 566 | badopt ? badopt : ""); |
db197a81 TT |
567 | free(buf); |
568 | exit(1); | |
569 | } | |
570 | free(buf); | |
efc6f628 | 571 | } |
db197a81 | 572 | |
00e5433e | 573 | int main (int argc, char ** argv) |
3839e657 TT |
574 | { |
575 | errcode_t retval; | |
32b8802a SI |
576 | errcode_t retval_csum = 0; |
577 | const char *error_csum = NULL; | |
3839e657 | 578 | ext2_filsys fs; |
f3db3566 | 579 | int print_badblocks = 0; |
295c3e03 | 580 | blk64_t use_superblock = 0; |
02e7dd9a | 581 | int use_blocksize = 0; |
348e43dc | 582 | int image_dump = 0; |
32b8802a SI |
583 | int mmp_check = 0; |
584 | int mmp_info = 0; | |
2740156b | 585 | int force = 0; |
16ed5b3a | 586 | int flags; |
2740156b | 587 | int header_only = 0; |
519149fb | 588 | int c; |
0858268d | 589 | int grp_only = 0; |
3839e657 | 590 | |
d9c56d3c TT |
591 | #ifdef ENABLE_NLS |
592 | setlocale(LC_MESSAGES, ""); | |
14308a53 | 593 | setlocale(LC_CTYPE, ""); |
d9c56d3c TT |
594 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); |
595 | textdomain(NLS_CAT_NAME); | |
9d4507c5 | 596 | set_com_err_gettext(gettext); |
d9c56d3c | 597 | #endif |
a6d8302b | 598 | add_error_table(&et_ext2_error_table); |
32b8802a SI |
599 | if (argc && *argv) { |
600 | if (strrchr(*argv, '/')) | |
601 | program_name = strrchr(*argv, '/') + 1; | |
602 | else | |
603 | program_name = *argv; | |
604 | ||
605 | if (strstr(program_name, "mmpstatus") != NULL) { | |
606 | mmp_check = 1; | |
607 | header_only = 1; | |
608 | } | |
609 | } | |
efc6f628 | 610 | |
32b8802a SI |
611 | if (!mmp_check) |
612 | fprintf(stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION, | |
613 | E2FSPROGS_DATE); | |
614 | ||
615 | while ((c = getopt(argc, argv, "bfghimxVo:")) != EOF) { | |
f3db3566 TT |
616 | switch (c) { |
617 | case 'b': | |
618 | print_badblocks++; | |
619 | break; | |
2740156b TT |
620 | case 'f': |
621 | force++; | |
622 | break; | |
0858268d DW |
623 | case 'g': |
624 | grp_only++; | |
625 | break; | |
2740156b TT |
626 | case 'h': |
627 | header_only++; | |
628 | break; | |
348e43dc | 629 | case 'i': |
32b8802a SI |
630 | if (mmp_check) |
631 | mmp_info++; | |
632 | else | |
633 | image_dump++; | |
634 | break; | |
635 | case 'm': | |
636 | mmp_check++; | |
637 | header_only++; | |
638 | if (image_dump) { | |
639 | mmp_info = image_dump; | |
640 | image_dump = 0; | |
641 | } | |
348e43dc | 642 | break; |
02e7dd9a | 643 | case 'o': |
efc6f628 | 644 | parse_extended_opts(optarg, &use_superblock, |
db197a81 | 645 | &use_blocksize); |
02e7dd9a | 646 | break; |
5c576477 TT |
647 | case 'V': |
648 | /* Print version number and exit */ | |
d9c56d3c | 649 | fprintf(stderr, _("\tUsing %s\n"), |
5c576477 TT |
650 | error_message(EXT2_ET_BASE)); |
651 | exit(0); | |
80c22c90 | 652 | case 'x': |
9b9a780f | 653 | hex_format++; |
80c22c90 | 654 | break; |
f3db3566 | 655 | default: |
818180cd | 656 | usage(); |
f3db3566 TT |
657 | } |
658 | } | |
32b8802a | 659 | if (optind != argc - 1) |
818180cd | 660 | usage(); |
32b8802a | 661 | |
f3db3566 | 662 | device_name = argv[optind++]; |
32b8802a SI |
663 | flags = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES | |
664 | EXT2_FLAG_64BITS; | |
16ed5b3a TT |
665 | if (force) |
666 | flags |= EXT2_FLAG_FORCE; | |
348e43dc TT |
667 | if (image_dump) |
668 | flags |= EXT2_FLAG_IMAGE_FILE; | |
3466e95f | 669 | try_open_again: |
db197a81 TT |
670 | if (use_superblock && !use_blocksize) { |
671 | for (use_blocksize = EXT2_MIN_BLOCK_SIZE; | |
672 | use_blocksize <= EXT2_MAX_BLOCK_SIZE; | |
673 | use_blocksize *= 2) { | |
674 | retval = ext2fs_open (device_name, flags, | |
675 | use_superblock, | |
676 | use_blocksize, unix_io_manager, | |
677 | &fs); | |
678 | if (!retval) | |
679 | break; | |
680 | } | |
32b8802a SI |
681 | } else { |
682 | retval = ext2fs_open(device_name, flags, use_superblock, | |
683 | use_blocksize, unix_io_manager, &fs); | |
3466e95f | 684 | } |
3466e95f | 685 | flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; |
32b8802a SI |
686 | if (retval && !retval_csum) { |
687 | retval_csum = retval; | |
688 | error_csum = _("while trying to open %s"); | |
689 | goto try_open_again; | |
690 | } | |
f3db3566 | 691 | if (retval) { |
32b8802a SI |
692 | com_err(program_name, retval, _("while trying to open %s"), |
693 | device_name); | |
45ff69ff | 694 | printf("%s", _("Couldn't find valid filesystem superblock.\n")); |
c8b20b40 DW |
695 | if (retval == EXT2_ET_BAD_MAGIC) |
696 | check_plausibility(device_name, CHECK_FS_EXIST, NULL); | |
32b8802a | 697 | goto out; |
3839e657 | 698 | } |
24dea554 | 699 | fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; |
7889640d | 700 | if (ext2fs_has_feature_64bit(fs->super)) |
ce10c313 | 701 | blocks64 = 1; |
32b8802a SI |
702 | if (mmp_check) { |
703 | if (ext2fs_has_feature_mmp(fs->super) && | |
704 | fs->super->s_mmp_block != 0) { | |
705 | if (mmp_info) { | |
706 | print_mmp_block(fs); | |
707 | printf(" mmp_block_number: "); | |
708 | print_number(fs->super->s_mmp_block); | |
709 | printf("\n"); | |
710 | } else { | |
711 | retval = check_mmp(fs); | |
712 | } | |
713 | if (!retval && retval_csum) | |
714 | retval = 2; | |
715 | } else { | |
716 | fprintf(stderr, _("%s: MMP feature not enabled.\n"), | |
717 | program_name); | |
718 | retval = 2; | |
719 | } | |
720 | } else if (print_badblocks) { | |
0655b104 | 721 | list_bad_blocks(fs, 1); |
f3db3566 | 722 | } else { |
0858268d DW |
723 | if (grp_only) |
724 | goto just_descriptors; | |
32b8802a | 725 | list_super(fs->super); |
7889640d | 726 | if (ext2fs_has_feature_journal_dev(fs->super)) { |
16ed5b3a | 727 | print_journal_information(fs); |
32b8802a SI |
728 | |
729 | goto out_close; | |
16ed5b3a | 730 | } |
7889640d | 731 | if (ext2fs_has_feature_journal(fs->super) && |
a11d0746 | 732 | (fs->super->s_journal_inum != 0)) |
6515a6f1 | 733 | print_inline_journal_information(fs); |
32b8802a SI |
734 | if (ext2fs_has_feature_mmp(fs->super) && |
735 | fs->super->s_mmp_block != 0) | |
736 | print_mmp_block(fs); | |
0655b104 | 737 | list_bad_blocks(fs, 0); |
32b8802a SI |
738 | if (header_only) |
739 | goto out_close; | |
740 | ||
3466e95f DW |
741 | fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS; |
742 | try_bitmaps_again: | |
32b8802a SI |
743 | retval = ext2fs_read_bitmaps(fs); |
744 | if (retval && !retval_csum) { | |
3466e95f | 745 | fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; |
32b8802a SI |
746 | retval_csum = retval; |
747 | error_csum = _("while trying to read '%s' bitmaps\n"); | |
3466e95f DW |
748 | goto try_bitmaps_again; |
749 | } | |
0858268d DW |
750 | just_descriptors: |
751 | list_desc(fs, grp_only); | |
32b8802a SI |
752 | } |
753 | out_close: | |
754 | if (retval_csum) { | |
755 | com_err(program_name, retval_csum, error_csum, device_name); | |
756 | printf("%s", _("*** Run e2fsck now!\n\n")); | |
757 | if (!retval) | |
758 | retval = retval_csum; | |
3839e657 | 759 | } |
47fee2ef | 760 | ext2fs_close_free(&fs); |
a6d8302b | 761 | remove_error_table(&et_ext2_error_table); |
32b8802a SI |
762 | out: |
763 | return retval; | |
3839e657 | 764 | } |