]>
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 | 198 | if (grp_only) { |
33b9a60c | 199 | printf("%lu:%llu:", i, (unsigned long long) first_block); |
0858268d | 200 | if (i == 0 || super_blk) |
33b9a60c | 201 | printf("%llu:", (unsigned long long) super_blk); |
0858268d DW |
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) | |
33b9a60c | 209 | printf("%llu:", (unsigned long long) new_desc_blk); |
0858268d DW |
210 | else |
211 | printf("-1:"); | |
212 | printf("%llu:%llu:%llu\n", | |
33b9a60c TT |
213 | (unsigned long long) ext2fs_block_bitmap_loc(fs, i), |
214 | (unsigned long long) ext2fs_inode_bitmap_loc(fs, i), | |
215 | (unsigned long long) ext2fs_inode_table_loc(fs, i)); | |
0858268d DW |
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 | 364 | errcode_t retval; |
382ed4a1 | 365 | ext2_ino_t ino = fs->super->s_journal_inum; |
1d9b8183 | 366 | char buf[1024]; |
06def17e | 367 | int flags; |
efc6f628 | 368 | |
7fcaabf8 TT |
369 | if (fs->flags & EXT2_FLAG_IMAGE_FILE) |
370 | return; | |
6515a6f1 TT |
371 | retval = ext2fs_read_inode(fs, ino, &inode); |
372 | if (retval) { | |
45ff69ff | 373 | com_err(program_name, retval, "%s", |
6515a6f1 TT |
374 | _("while reading journal inode")); |
375 | exit(1); | |
376 | } | |
1d9b8183 TT |
377 | retval = ext2fs_file_open2(fs, ino, &inode, 0, &journal_file); |
378 | if (retval) { | |
45ff69ff | 379 | com_err(program_name, retval, "%s", |
1d9b8183 TT |
380 | _("while opening journal inode")); |
381 | exit(1); | |
382 | } | |
383 | retval = ext2fs_file_read(journal_file, buf, sizeof(buf), 0); | |
384 | if (retval) { | |
45ff69ff | 385 | com_err(program_name, retval, "%s", |
1d9b8183 TT |
386 | _("while reading journal super block")); |
387 | exit(1); | |
388 | } | |
389 | ext2fs_file_close(journal_file); | |
390 | jsb = (journal_superblock_t *) buf; | |
8335d3c5 | 391 | if (be32_to_cpu(jsb->s_header.h_magic) != JBD2_MAGIC_NUMBER) { |
45ff69ff AD |
392 | fprintf(stderr, "%s", |
393 | _("Journal superblock magic number invalid!\n")); | |
1d9b8183 TT |
394 | exit(1); |
395 | } | |
06def17e HS |
396 | flags = ext2fs_has_feature_fast_commit(fs->super) ? |
397 | E2P_LIST_JOURNAL_FLAG_FC : 0; | |
398 | e2p_list_journal_super(stdout, buf, fs->blocksize, flags); | |
6515a6f1 TT |
399 | } |
400 | ||
16ed5b3a TT |
401 | static void print_journal_information(ext2_filsys fs) |
402 | { | |
403 | errcode_t retval; | |
404 | char buf[1024]; | |
16ed5b3a | 405 | journal_superblock_t *jsb; |
06def17e | 406 | int flags; |
16ed5b3a TT |
407 | |
408 | /* Get the journal superblock */ | |
45ff69ff AD |
409 | if ((retval = io_channel_read_blk64(fs->io, |
410 | fs->super->s_first_data_block + 1, | |
411 | -1024, buf))) { | |
412 | com_err(program_name, retval, "%s", | |
16ed5b3a TT |
413 | _("while reading journal superblock")); |
414 | exit(1); | |
415 | } | |
416 | jsb = (journal_superblock_t *) buf; | |
8335d3c5 | 417 | if ((jsb->s_header.h_magic != (unsigned) ntohl(JBD2_MAGIC_NUMBER)) || |
16ed5b3a | 418 | (jsb->s_header.h_blocktype != |
8335d3c5 | 419 | (unsigned) ntohl(JBD2_SUPERBLOCK_V2))) { |
45ff69ff | 420 | com_err(program_name, 0, "%s", |
16ed5b3a TT |
421 | _("Couldn't find journal superblock magic numbers")); |
422 | exit(1); | |
423 | } | |
06def17e HS |
424 | flags = ext2fs_has_feature_fast_commit(fs->super) ? |
425 | E2P_LIST_JOURNAL_FLAG_FC : 0; | |
426 | e2p_list_journal_super(stdout, buf, fs->blocksize, flags); | |
16ed5b3a TT |
427 | } |
428 | ||
32b8802a SI |
429 | static int check_mmp(ext2_filsys fs) |
430 | { | |
431 | int retval; | |
432 | ||
433 | /* This won't actually start MMP on the filesystem, since fs is opened | |
434 | * readonly, but it will do the proper activity checking for us. */ | |
435 | retval = ext2fs_mmp_start(fs); | |
436 | if (retval) { | |
437 | com_err(program_name, retval, _("while trying to open %s"), | |
438 | fs->device_name); | |
439 | if (retval == EXT2_ET_MMP_FAILED || | |
440 | retval == EXT2_ET_MMP_FSCK_ON || | |
441 | retval == EXT2_ET_MMP_CSUM_INVALID || | |
442 | retval == EXT2_ET_MMP_UNKNOWN_SEQ) { | |
443 | if (fs->mmp_buf) { | |
444 | struct mmp_struct *mmp = fs->mmp_buf; | |
445 | time_t mmp_time = mmp->mmp_time; | |
446 | ||
447 | fprintf(stderr, | |
6b430d60 AD |
448 | "%s: MMP update by '%.*s%.*s' at %s", |
449 | program_name, | |
bc562273 AD |
450 | EXT2_LEN_STR(mmp->mmp_nodename), |
451 | EXT2_LEN_STR(mmp->mmp_bdevname), | |
32b8802a SI |
452 | ctime(&mmp_time)); |
453 | } | |
454 | retval = 1; | |
455 | } else { | |
456 | retval = 2; | |
457 | } | |
458 | } else { | |
459 | printf("%s: it is safe to mount '%s', MMP is clean\n", | |
460 | program_name, fs->device_name); | |
461 | } | |
462 | ||
463 | return retval; | |
464 | } | |
465 | ||
466 | static void print_mmp_block(ext2_filsys fs) | |
467 | { | |
468 | struct mmp_struct *mmp; | |
469 | time_t mmp_time; | |
470 | errcode_t retval; | |
471 | ||
472 | if (fs->mmp_buf == NULL) { | |
473 | retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf); | |
474 | if (retval) { | |
475 | com_err(program_name, retval, | |
476 | _("failed to alloc MMP buffer\n")); | |
477 | return; | |
478 | } | |
479 | } | |
480 | ||
481 | retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); | |
482 | /* this is only dumping, not checking status, so OK to skip this */ | |
483 | if (retval == EXT2_ET_OP_NOT_SUPPORTED) | |
484 | return; | |
485 | if (retval) { | |
486 | com_err(program_name, retval, | |
487 | _("reading MMP block %llu from '%s'\n"), | |
33b9a60c TT |
488 | (unsigned long long) fs->super->s_mmp_block, |
489 | fs->device_name); | |
32b8802a SI |
490 | return; |
491 | } | |
492 | ||
493 | mmp = fs->mmp_buf; | |
494 | mmp_time = mmp->mmp_time; | |
495 | printf("MMP_block:\n"); | |
496 | printf(" mmp_magic: 0x%x\n", mmp->mmp_magic); | |
497 | printf(" mmp_check_interval: %d\n", mmp->mmp_check_interval); | |
498 | printf(" mmp_sequence: %#08x\n", mmp->mmp_seq); | |
499 | printf(" mmp_update_date: %s", ctime(&mmp_time)); | |
33b9a60c TT |
500 | printf(" mmp_update_time: %llu\n", |
501 | (unsigned long long) mmp->mmp_time); | |
6b430d60 | 502 | printf(" mmp_node_name: %.*s\n", |
bc562273 | 503 | EXT2_LEN_STR(mmp->mmp_nodename)); |
6b430d60 | 504 | printf(" mmp_device_name: %.*s\n", |
bc562273 | 505 | EXT2_LEN_STR(mmp->mmp_bdevname)); |
32b8802a SI |
506 | } |
507 | ||
295c3e03 | 508 | static void parse_extended_opts(const char *opts, blk64_t *superblock, |
db197a81 TT |
509 | int *blocksize) |
510 | { | |
2d328bb7 | 511 | char *buf, *token, *next, *p, *arg, *badopt = 0; |
db197a81 | 512 | int len; |
2d328bb7 | 513 | int do_usage = 0; |
db197a81 TT |
514 | |
515 | len = strlen(opts); | |
516 | buf = malloc(len+1); | |
517 | if (!buf) { | |
45ff69ff | 518 | fprintf(stderr, "%s", |
db197a81 TT |
519 | _("Couldn't allocate memory to parse options!\n")); |
520 | exit(1); | |
521 | } | |
522 | strcpy(buf, opts); | |
523 | for (token = buf; token && *token; token = next) { | |
524 | p = strchr(token, ','); | |
525 | next = 0; | |
526 | if (p) { | |
527 | *p = 0; | |
528 | next = p+1; | |
529 | } | |
530 | arg = strchr(token, '='); | |
531 | if (arg) { | |
532 | *arg = 0; | |
533 | arg++; | |
534 | } | |
535 | if (strcmp(token, "superblock") == 0 || | |
536 | strcmp(token, "sb") == 0) { | |
537 | if (!arg) { | |
2d328bb7 | 538 | do_usage++; |
db197a81 TT |
539 | badopt = token; |
540 | continue; | |
541 | } | |
542 | *superblock = strtoul(arg, &p, 0); | |
543 | if (*p) { | |
544 | fprintf(stderr, | |
545 | _("Invalid superblock parameter: %s\n"), | |
546 | arg); | |
2d328bb7 | 547 | do_usage++; |
db197a81 TT |
548 | continue; |
549 | } | |
550 | } else if (strcmp(token, "blocksize") == 0 || | |
551 | strcmp(token, "bs") == 0) { | |
552 | if (!arg) { | |
2d328bb7 | 553 | do_usage++; |
db197a81 TT |
554 | badopt = token; |
555 | continue; | |
556 | } | |
557 | *blocksize = strtoul(arg, &p, 0); | |
558 | if (*p) { | |
559 | fprintf(stderr, | |
560 | _("Invalid blocksize parameter: %s\n"), | |
561 | arg); | |
2d328bb7 | 562 | do_usage++; |
db197a81 TT |
563 | continue; |
564 | } | |
565 | } else { | |
2d328bb7 | 566 | do_usage++; |
db197a81 TT |
567 | badopt = token; |
568 | } | |
569 | } | |
2d328bb7 | 570 | if (do_usage) { |
db197a81 TT |
571 | fprintf(stderr, _("\nBad extended option(s) specified: %s\n\n" |
572 | "Extended options are separated by commas, " | |
573 | "and may take an argument which\n" | |
574 | "\tis set off by an equals ('=') sign.\n\n" | |
575 | "Valid extended options are:\n" | |
576 | "\tsuperblock=<superblock number>\n" | |
577 | "\tblocksize=<blocksize>\n"), | |
2d328bb7 | 578 | badopt ? badopt : ""); |
db197a81 TT |
579 | free(buf); |
580 | exit(1); | |
581 | } | |
582 | free(buf); | |
efc6f628 | 583 | } |
db197a81 | 584 | |
00e5433e | 585 | int main (int argc, char ** argv) |
3839e657 TT |
586 | { |
587 | errcode_t retval; | |
32b8802a SI |
588 | errcode_t retval_csum = 0; |
589 | const char *error_csum = NULL; | |
3839e657 | 590 | ext2_filsys fs; |
f3db3566 | 591 | int print_badblocks = 0; |
295c3e03 | 592 | blk64_t use_superblock = 0; |
02e7dd9a | 593 | int use_blocksize = 0; |
348e43dc | 594 | int image_dump = 0; |
32b8802a SI |
595 | int mmp_check = 0; |
596 | int mmp_info = 0; | |
2740156b | 597 | int force = 0; |
16ed5b3a | 598 | int flags; |
2740156b | 599 | int header_only = 0; |
519149fb | 600 | int c; |
0858268d | 601 | int grp_only = 0; |
3839e657 | 602 | |
d9c56d3c TT |
603 | #ifdef ENABLE_NLS |
604 | setlocale(LC_MESSAGES, ""); | |
14308a53 | 605 | setlocale(LC_CTYPE, ""); |
d9c56d3c TT |
606 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); |
607 | textdomain(NLS_CAT_NAME); | |
9d4507c5 | 608 | set_com_err_gettext(gettext); |
d9c56d3c | 609 | #endif |
a6d8302b | 610 | add_error_table(&et_ext2_error_table); |
32b8802a SI |
611 | if (argc && *argv) { |
612 | if (strrchr(*argv, '/')) | |
613 | program_name = strrchr(*argv, '/') + 1; | |
614 | else | |
615 | program_name = *argv; | |
616 | ||
617 | if (strstr(program_name, "mmpstatus") != NULL) { | |
618 | mmp_check = 1; | |
619 | header_only = 1; | |
620 | } | |
621 | } | |
efc6f628 | 622 | |
32b8802a SI |
623 | if (!mmp_check) |
624 | fprintf(stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION, | |
625 | E2FSPROGS_DATE); | |
626 | ||
627 | while ((c = getopt(argc, argv, "bfghimxVo:")) != EOF) { | |
f3db3566 TT |
628 | switch (c) { |
629 | case 'b': | |
630 | print_badblocks++; | |
631 | break; | |
2740156b TT |
632 | case 'f': |
633 | force++; | |
634 | break; | |
0858268d DW |
635 | case 'g': |
636 | grp_only++; | |
637 | break; | |
2740156b TT |
638 | case 'h': |
639 | header_only++; | |
640 | break; | |
348e43dc | 641 | case 'i': |
32b8802a SI |
642 | if (mmp_check) |
643 | mmp_info++; | |
644 | else | |
645 | image_dump++; | |
646 | break; | |
647 | case 'm': | |
648 | mmp_check++; | |
649 | header_only++; | |
650 | if (image_dump) { | |
651 | mmp_info = image_dump; | |
652 | image_dump = 0; | |
653 | } | |
348e43dc | 654 | break; |
02e7dd9a | 655 | case 'o': |
efc6f628 | 656 | parse_extended_opts(optarg, &use_superblock, |
db197a81 | 657 | &use_blocksize); |
02e7dd9a | 658 | break; |
5c576477 TT |
659 | case 'V': |
660 | /* Print version number and exit */ | |
d9c56d3c | 661 | fprintf(stderr, _("\tUsing %s\n"), |
5c576477 TT |
662 | error_message(EXT2_ET_BASE)); |
663 | exit(0); | |
80c22c90 | 664 | case 'x': |
9b9a780f | 665 | hex_format++; |
80c22c90 | 666 | break; |
f3db3566 | 667 | default: |
818180cd | 668 | usage(); |
f3db3566 TT |
669 | } |
670 | } | |
32b8802a | 671 | if (optind != argc - 1) |
818180cd | 672 | usage(); |
32b8802a | 673 | |
f3db3566 | 674 | device_name = argv[optind++]; |
32b8802a | 675 | flags = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES | |
37d56864 | 676 | EXT2_FLAG_64BITS | EXT2_FLAG_THREADS; |
16ed5b3a TT |
677 | if (force) |
678 | flags |= EXT2_FLAG_FORCE; | |
348e43dc TT |
679 | if (image_dump) |
680 | flags |= EXT2_FLAG_IMAGE_FILE; | |
e6069a05 TT |
681 | if (header_only) |
682 | flags |= EXT2_FLAG_SUPER_ONLY; | |
3466e95f | 683 | try_open_again: |
db197a81 TT |
684 | if (use_superblock && !use_blocksize) { |
685 | for (use_blocksize = EXT2_MIN_BLOCK_SIZE; | |
686 | use_blocksize <= EXT2_MAX_BLOCK_SIZE; | |
687 | use_blocksize *= 2) { | |
688 | retval = ext2fs_open (device_name, flags, | |
689 | use_superblock, | |
690 | use_blocksize, unix_io_manager, | |
691 | &fs); | |
692 | if (!retval) | |
693 | break; | |
694 | } | |
32b8802a SI |
695 | } else { |
696 | retval = ext2fs_open(device_name, flags, use_superblock, | |
697 | use_blocksize, unix_io_manager, &fs); | |
3466e95f | 698 | } |
3466e95f | 699 | flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; |
32b8802a SI |
700 | if (retval && !retval_csum) { |
701 | retval_csum = retval; | |
702 | error_csum = _("while trying to open %s"); | |
703 | goto try_open_again; | |
704 | } | |
f3db3566 | 705 | if (retval) { |
32b8802a SI |
706 | com_err(program_name, retval, _("while trying to open %s"), |
707 | device_name); | |
45ff69ff | 708 | printf("%s", _("Couldn't find valid filesystem superblock.\n")); |
c8b20b40 DW |
709 | if (retval == EXT2_ET_BAD_MAGIC) |
710 | check_plausibility(device_name, CHECK_FS_EXIST, NULL); | |
32b8802a | 711 | goto out; |
3839e657 | 712 | } |
24dea554 | 713 | fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; |
7889640d | 714 | if (ext2fs_has_feature_64bit(fs->super)) |
ce10c313 | 715 | blocks64 = 1; |
32b8802a SI |
716 | if (mmp_check) { |
717 | if (ext2fs_has_feature_mmp(fs->super) && | |
718 | fs->super->s_mmp_block != 0) { | |
719 | if (mmp_info) { | |
720 | print_mmp_block(fs); | |
721 | printf(" mmp_block_number: "); | |
722 | print_number(fs->super->s_mmp_block); | |
723 | printf("\n"); | |
724 | } else { | |
725 | retval = check_mmp(fs); | |
726 | } | |
727 | if (!retval && retval_csum) | |
728 | retval = 2; | |
729 | } else { | |
730 | fprintf(stderr, _("%s: MMP feature not enabled.\n"), | |
731 | program_name); | |
732 | retval = 2; | |
733 | } | |
734 | } else if (print_badblocks) { | |
0655b104 | 735 | list_bad_blocks(fs, 1); |
f3db3566 | 736 | } else { |
0858268d DW |
737 | if (grp_only) |
738 | goto just_descriptors; | |
32b8802a | 739 | list_super(fs->super); |
7889640d | 740 | if (ext2fs_has_feature_journal_dev(fs->super)) { |
16ed5b3a | 741 | print_journal_information(fs); |
32b8802a SI |
742 | |
743 | goto out_close; | |
16ed5b3a | 744 | } |
7889640d | 745 | if (ext2fs_has_feature_journal(fs->super) && |
a11d0746 | 746 | (fs->super->s_journal_inum != 0)) |
6515a6f1 | 747 | print_inline_journal_information(fs); |
32b8802a SI |
748 | if (ext2fs_has_feature_mmp(fs->super) && |
749 | fs->super->s_mmp_block != 0) | |
750 | print_mmp_block(fs); | |
0655b104 | 751 | list_bad_blocks(fs, 0); |
32b8802a SI |
752 | if (header_only) |
753 | goto out_close; | |
754 | ||
3466e95f DW |
755 | fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS; |
756 | try_bitmaps_again: | |
32b8802a SI |
757 | retval = ext2fs_read_bitmaps(fs); |
758 | if (retval && !retval_csum) { | |
3466e95f | 759 | fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; |
32b8802a SI |
760 | retval_csum = retval; |
761 | error_csum = _("while trying to read '%s' bitmaps\n"); | |
3466e95f DW |
762 | goto try_bitmaps_again; |
763 | } | |
0858268d DW |
764 | just_descriptors: |
765 | list_desc(fs, grp_only); | |
32b8802a SI |
766 | } |
767 | out_close: | |
768 | if (retval_csum) { | |
769 | com_err(program_name, retval_csum, error_csum, device_name); | |
770 | printf("%s", _("*** Run e2fsck now!\n\n")); | |
771 | if (!retval) | |
772 | retval = retval_csum; | |
3839e657 | 773 | } |
47fee2ef | 774 | ext2fs_close_free(&fs); |
a6d8302b | 775 | remove_error_table(&et_ext2_error_table); |
32b8802a SI |
776 | out: |
777 | return retval; | |
3839e657 | 778 | } |