]>
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 | ||
a418d3ad | 23 | #ifdef HAVE_GETOPT_H |
3839e657 | 24 | #include <getopt.h> |
373b8337 TT |
25 | #else |
26 | extern char *optarg; | |
27 | extern int optind; | |
a418d3ad | 28 | #endif |
3839e657 TT |
29 | #include <fcntl.h> |
30 | #include <stdio.h> | |
31 | #include <stdlib.h> | |
32 | #include <string.h> | |
33 | #include <unistd.h> | |
34 | ||
54c637d4 | 35 | #include "ext2fs/ext2_fs.h" |
3839e657 TT |
36 | |
37 | #include "ext2fs/ext2fs.h" | |
38 | #include "e2p/e2p.h" | |
16ed5b3a | 39 | #include "jfs_user.h" |
4ea7bd04 | 40 | #include <uuid/uuid.h> |
3839e657 TT |
41 | |
42 | #include "../version.h" | |
d9c56d3c | 43 | #include "nls-enable.h" |
3839e657 | 44 | |
74becf3c | 45 | #define in_use(m, x) (ext2fs_test_bit ((x), (m))) |
3839e657 TT |
46 | |
47 | const char * program_name = "dumpe2fs"; | |
48 | char * device_name = NULL; | |
9b9a780f | 49 | int hex_format = 0; |
3839e657 | 50 | |
818180cd | 51 | static void usage(void) |
3839e657 | 52 | { |
348e43dc | 53 | fprintf (stderr, _("Usage: %s [-bfhixV] [-ob superblock] " |
d9c56d3c | 54 | "[-oB blocksize] device\n"), program_name); |
3839e657 TT |
55 | exit (1); |
56 | } | |
57 | ||
9b9a780f | 58 | static void print_number(unsigned long num) |
54434927 | 59 | { |
9b9a780f TT |
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); | |
54434927 TT |
72 | } |
73 | ||
3839e657 TT |
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 | ||
a5f0bb9d | 81 | offset += group * nbytes; |
3839e657 TT |
82 | for (i = 0; i < nbytes; i++) |
83 | if (!in_use (bitmap, i)) | |
84 | { | |
85 | if (p) | |
86 | printf (", "); | |
54434927 | 87 | print_number(i + offset); |
a5f0bb9d TT |
88 | for (j = i; j < nbytes && !in_use (bitmap, j); j++) |
89 | ; | |
90 | if (--j != i) { | |
91 | fputc('-', stdout); | |
54434927 | 92 | print_number(j + offset); |
a5f0bb9d | 93 | i = j; |
3839e657 TT |
94 | } |
95 | p = 1; | |
96 | } | |
97 | } | |
98 | ||
f5fa2007 TT |
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 | ||
3839e657 TT |
129 | static void list_desc (ext2_filsys fs) |
130 | { | |
131 | unsigned long i; | |
a5f0bb9d | 132 | long diff; |
521e3685 | 133 | blk_t group_blk, next_blk; |
ef344e13 | 134 | blk_t super_blk, old_desc_blk, new_desc_blk; |
d90a23e2 | 135 | char *block_bitmap=NULL, *inode_bitmap=NULL; |
35238dd1 | 136 | int inode_blocks_per_group, old_desc_blocks, reserved_gdt; |
ef344e13 | 137 | int has_super; |
80c22c90 | 138 | |
d90a23e2 TT |
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 | ||
80c22c90 TT |
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); | |
35238dd1 | 148 | reserved_gdt = fs->super->s_reserved_gdt_blocks; |
a5f0bb9d | 149 | fputc('\n', stdout); |
521e3685 | 150 | group_blk = fs->super->s_first_data_block; |
76dd5e5c TT |
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; | |
521e3685 | 155 | for (i = 0; i < fs->group_desc_count; i++) { |
ef344e13 TT |
156 | ext2fs_super_and_bgd_loc(fs, i, &super_blk, |
157 | &old_desc_blk, &new_desc_blk, 0); | |
521e3685 TT |
158 | next_blk = group_blk + fs->super->s_blocks_per_group; |
159 | if (next_blk > fs->super->s_blocks_count) | |
160 | next_blk = fs->super->s_blocks_count; | |
a5f0bb9d | 161 | printf (_("Group %lu: (Blocks "), i); |
9b9a780f | 162 | print_range(group_blk, next_blk - 1); |
f5fa2007 TT |
163 | fputs(")", stdout); |
164 | print_bg_opts(fs, i); | |
ef344e13 | 165 | has_super = ((i==0) || super_blk); |
c046ac7f TT |
166 | if (has_super) { |
167 | printf (_(" %s superblock at "), | |
a5f0bb9d | 168 | i == 0 ? _("Primary") : _("Backup")); |
54434927 | 169 | print_number(super_blk); |
c046ac7f | 170 | } |
ef344e13 TT |
171 | if (old_desc_blk) { |
172 | printf(_(", Group descriptors at ")); | |
9b9a780f TT |
173 | print_range(old_desc_blk, |
174 | old_desc_blk + old_desc_blocks - 1); | |
35238dd1 TT |
175 | if (reserved_gdt) { |
176 | printf(_("\n Reserved GDT blocks at ")); | |
9b9a780f TT |
177 | print_range(old_desc_blk + old_desc_blocks, |
178 | old_desc_blk + old_desc_blocks + | |
179 | reserved_gdt - 1); | |
35238dd1 | 180 | } |
ef344e13 TT |
181 | } else if (new_desc_blk) { |
182 | fputc(has_super ? ',' : ' ', stdout); | |
183 | printf(_(" Group descriptor at ")); | |
54434927 | 184 | print_number(new_desc_blk); |
ef344e13 | 185 | has_super++; |
a5f0bb9d | 186 | } |
ef344e13 TT |
187 | if (has_super) |
188 | fputc('\n', stdout); | |
a5f0bb9d | 189 | fputs(_(" Block bitmap at "), stdout); |
54434927 | 190 | print_number(fs->group_desc[i].bg_block_bitmap); |
a5f0bb9d TT |
191 | diff = fs->group_desc[i].bg_block_bitmap - group_blk; |
192 | if (diff >= 0) | |
4ea7bd04 | 193 | printf(" (+%ld)", diff); |
a5f0bb9d | 194 | fputs(_(", Inode bitmap at "), stdout); |
54434927 | 195 | print_number(fs->group_desc[i].bg_inode_bitmap); |
a5f0bb9d TT |
196 | diff = fs->group_desc[i].bg_inode_bitmap - group_blk; |
197 | if (diff >= 0) | |
4ea7bd04 | 198 | printf(" (+%ld)", diff); |
a5f0bb9d | 199 | fputs(_("\n Inode table at "), stdout); |
9b9a780f TT |
200 | print_range(fs->group_desc[i].bg_inode_table, |
201 | fs->group_desc[i].bg_inode_table + | |
202 | inode_blocks_per_group - 1); | |
a5f0bb9d TT |
203 | diff = fs->group_desc[i].bg_inode_table - group_blk; |
204 | if (diff > 0) | |
4ea7bd04 | 205 | printf(" (+%ld)", diff); |
a5f0bb9d | 206 | printf (_("\n %d free blocks, %d free inodes, " |
d90a23e2 | 207 | "%d directories\n"), |
3839e657 TT |
208 | fs->group_desc[i].bg_free_blocks_count, |
209 | fs->group_desc[i].bg_free_inodes_count, | |
210 | fs->group_desc[i].bg_used_dirs_count); | |
d90a23e2 TT |
211 | if (block_bitmap) { |
212 | fputs(_(" Free blocks: "), stdout); | |
213 | print_free (i, block_bitmap, | |
214 | fs->super->s_blocks_per_group, | |
215 | fs->super->s_first_data_block); | |
216 | fputc('\n', stdout); | |
217 | block_bitmap += fs->super->s_blocks_per_group / 8; | |
218 | } | |
219 | if (inode_bitmap) { | |
220 | fputs(_(" Free inodes: "), stdout); | |
221 | print_free (i, inode_bitmap, | |
222 | fs->super->s_inodes_per_group, 1); | |
223 | fputc('\n', stdout); | |
224 | inode_bitmap += fs->super->s_inodes_per_group / 8; | |
225 | } | |
521e3685 | 226 | group_blk = next_blk; |
3839e657 TT |
227 | } |
228 | } | |
229 | ||
0655b104 | 230 | static void list_bad_blocks(ext2_filsys fs, int dump) |
3839e657 TT |
231 | { |
232 | badblocks_list bb_list = 0; | |
233 | badblocks_iterate bb_iter; | |
234 | blk_t blk; | |
235 | errcode_t retval; | |
0655b104 | 236 | const char *header, *fmt; |
3839e657 TT |
237 | |
238 | retval = ext2fs_read_bb_inode(fs, &bb_list); | |
239 | if (retval) { | |
9b9a780f | 240 | com_err("ext2fs_read_bb_inode", retval, 0); |
0655b104 | 241 | return; |
3839e657 | 242 | } |
cbbf031b | 243 | retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter); |
3839e657 | 244 | if (retval) { |
cbbf031b | 245 | com_err("ext2fs_badblocks_list_iterate_begin", retval, |
d9c56d3c | 246 | _("while printing bad block list")); |
0655b104 | 247 | return; |
3839e657 | 248 | } |
0655b104 TT |
249 | if (dump) { |
250 | header = fmt = "%d\n"; | |
251 | } else { | |
252 | header = _("Bad blocks: %d"); | |
253 | fmt = ", %d"; | |
f3db3566 | 254 | } |
0655b104 TT |
255 | while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) { |
256 | printf(header ? header : fmt, blk); | |
257 | header = 0; | |
f3db3566 | 258 | } |
cbbf031b | 259 | ext2fs_badblocks_list_iterate_end(bb_iter); |
0655b104 TT |
260 | if (!dump) |
261 | fputc('\n', stdout); | |
1e3472c5 | 262 | } |
f3db3566 | 263 | |
6515a6f1 TT |
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 | ||
16ed5b3a TT |
285 | static void print_journal_information(ext2_filsys fs) |
286 | { | |
287 | errcode_t retval; | |
288 | char buf[1024]; | |
289 | char str[80]; | |
54434927 | 290 | unsigned int i; |
16ed5b3a TT |
291 | journal_superblock_t *jsb; |
292 | ||
293 | /* Get the journal superblock */ | |
02088862 | 294 | if ((retval = io_channel_read_blk(fs->io, fs->super->s_first_data_block+1, -1024, buf))) { |
16ed5b3a TT |
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 | ||
8deb80a5 TS |
308 | printf(_("\nJournal block size: %u\n" |
309 | "Journal length: %u\n" | |
310 | "Journal first block: %u\n" | |
a5f0bb9d | 311 | "Journal sequence: 0x%08x\n" |
8deb80a5 | 312 | "Journal start: %u\n" |
f6567a88 MA |
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)); | |
a5f0bb9d | 317 | |
16ed5b3a | 318 | for (i=0; i < ntohl(jsb->s_nr_users); i++) { |
16ed5b3a | 319 | uuid_unparse(&jsb->s_users[i*16], str); |
a5f0bb9d | 320 | printf(i ? " %s\n" |
bb145b01 | 321 | : _("Journal users: %s\n"), |
a5f0bb9d | 322 | str); |
16ed5b3a TT |
323 | } |
324 | } | |
325 | ||
00e5433e | 326 | int main (int argc, char ** argv) |
3839e657 TT |
327 | { |
328 | errcode_t retval; | |
329 | ext2_filsys fs; | |
f3db3566 | 330 | int print_badblocks = 0; |
02e7dd9a TT |
331 | int use_superblock = 0; |
332 | int use_blocksize = 0; | |
348e43dc | 333 | int image_dump = 0; |
2740156b | 334 | int force = 0; |
16ed5b3a | 335 | int flags; |
2740156b | 336 | int header_only = 0; |
1e3472c5 | 337 | int big_endian; |
519149fb | 338 | int c; |
3839e657 | 339 | |
d9c56d3c TT |
340 | #ifdef ENABLE_NLS |
341 | setlocale(LC_MESSAGES, ""); | |
14308a53 | 342 | setlocale(LC_CTYPE, ""); |
d9c56d3c TT |
343 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); |
344 | textdomain(NLS_CAT_NAME); | |
345 | #endif | |
5c576477 | 346 | initialize_ext2_error_table(); |
0f8973fb TT |
347 | fprintf (stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION, |
348 | E2FSPROGS_DATE); | |
3839e657 TT |
349 | if (argc && *argv) |
350 | program_name = *argv; | |
f3db3566 | 351 | |
348e43dc | 352 | while ((c = getopt (argc, argv, "bfhixVo:")) != EOF) { |
f3db3566 TT |
353 | switch (c) { |
354 | case 'b': | |
355 | print_badblocks++; | |
356 | break; | |
2740156b TT |
357 | case 'f': |
358 | force++; | |
359 | break; | |
360 | case 'h': | |
361 | header_only++; | |
362 | break; | |
348e43dc TT |
363 | case 'i': |
364 | image_dump++; | |
365 | break; | |
02e7dd9a TT |
366 | case 'o': |
367 | if (optarg[0] == 'b') | |
368 | use_superblock = atoi(optarg+1); | |
369 | else if (optarg[0] == 'B') | |
370 | use_blocksize = atoi(optarg+1); | |
371 | else | |
372 | usage(); | |
373 | break; | |
5c576477 TT |
374 | case 'V': |
375 | /* Print version number and exit */ | |
d9c56d3c | 376 | fprintf(stderr, _("\tUsing %s\n"), |
5c576477 TT |
377 | error_message(EXT2_ET_BASE)); |
378 | exit(0); | |
80c22c90 | 379 | case 'x': |
9b9a780f | 380 | hex_format++; |
80c22c90 | 381 | break; |
f3db3566 | 382 | default: |
818180cd | 383 | usage(); |
f3db3566 TT |
384 | } |
385 | } | |
386 | if (optind > argc - 1) | |
818180cd | 387 | usage(); |
f3db3566 | 388 | device_name = argv[optind++]; |
02e7dd9a TT |
389 | if (use_superblock && !use_blocksize) |
390 | use_blocksize = 1024; | |
16ed5b3a TT |
391 | flags = EXT2_FLAG_JOURNAL_DEV_OK; |
392 | if (force) | |
393 | flags |= EXT2_FLAG_FORCE; | |
348e43dc TT |
394 | if (image_dump) |
395 | flags |= EXT2_FLAG_IMAGE_FILE; | |
396 | ||
16ed5b3a TT |
397 | retval = ext2fs_open (device_name, flags, use_superblock, |
398 | use_blocksize, unix_io_manager, &fs); | |
f3db3566 | 399 | if (retval) { |
d9c56d3c | 400 | com_err (program_name, retval, _("while trying to open %s"), |
3839e657 | 401 | device_name); |
d9c56d3c | 402 | printf (_("Couldn't find valid filesystem superblock.\n")); |
3839e657 TT |
403 | exit (1); |
404 | } | |
f3db3566 | 405 | if (print_badblocks) { |
0655b104 | 406 | list_bad_blocks(fs, 1); |
f3db3566 | 407 | } else { |
2740156b | 408 | big_endian = ((fs->flags & EXT2_FLAG_SWAP_BYTES) != 0); |
cbbf031b TT |
409 | #ifdef WORDS_BIGENDIAN |
410 | big_endian = !big_endian; | |
411 | #endif | |
2740156b | 412 | if (big_endian) |
d9c56d3c | 413 | printf(_("Note: This is a byte-swapped filesystem\n")); |
2740156b | 414 | list_super (fs->super); |
16ed5b3a TT |
415 | if (fs->super->s_feature_incompat & |
416 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { | |
417 | print_journal_information(fs); | |
418 | ext2fs_close(fs); | |
419 | exit(0); | |
420 | } | |
6515a6f1 TT |
421 | if (fs->super->s_feature_compat & |
422 | EXT3_FEATURE_COMPAT_HAS_JOURNAL) | |
423 | print_inline_journal_information(fs); | |
0655b104 | 424 | list_bad_blocks(fs, 0); |
2740156b TT |
425 | if (header_only) { |
426 | ext2fs_close (fs); | |
427 | exit (0); | |
428 | } | |
f3db3566 | 429 | retval = ext2fs_read_bitmaps (fs); |
d90a23e2 | 430 | list_desc (fs); |
f3db3566 | 431 | if (retval) { |
d90a23e2 TT |
432 | printf(_("\n%s: %s: error reading bitmaps: %s\n"), |
433 | program_name, device_name, | |
434 | error_message(retval)); | |
f3db3566 | 435 | } |
3839e657 | 436 | } |
3839e657 TT |
437 | ext2fs_close (fs); |
438 | exit (0); | |
439 | } |