]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - debugfs/logdump.c
Fix clang warnings on architectures with a 64-bit long
[thirdparty/e2fsprogs.git] / debugfs / logdump.c
CommitLineData
da81e3fc
TT
1/*
2 * logdump.c --- dump the contents of the journal out to a file
efc6f628 3 *
055866d8 4 * Author: Stephen C. Tweedie, 2001 <sct@redhat.com>
da81e3fc 5 * Copyright (C) 2001 Red Hat, Inc.
efc6f628 6 * Based on portions Copyright (C) 1994 Theodore Ts'o.
da81e3fc 7 *
efc6f628 8 * This file may be redistributed under the terms of the GNU Public
da81e3fc
TT
9 * License.
10 */
11
d1154eb4 12#include "config.h"
da81e3fc
TT
13#include <stdio.h>
14#include <unistd.h>
15#include <stdlib.h>
16#include <ctype.h>
17#include <string.h>
18#include <time.h>
19#ifdef HAVE_ERRNO_H
20#include <errno.h>
21#endif
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <fcntl.h>
25#include <utime.h>
26#ifdef HAVE_GETOPT_H
27#include <getopt.h>
efc6f628 28#else
da81e3fc
TT
29extern int optind;
30extern char *optarg;
31#endif
da81e3fc
TT
32
33#include "debugfs.h"
f364093b 34#include "blkid/blkid.h"
da81e3fc 35#include "jfs_user.h"
8968289b 36#include "ext2fs/fast_commit.h"
4ea7bd04 37#include <uuid/uuid.h>
da81e3fc
TT
38
39enum journal_location {JOURNAL_IS_INTERNAL, JOURNAL_IS_EXTERNAL};
40
4dbfd79d 41#define ANY_BLOCK ((blk64_t) -1)
54434927 42
03a179a1 43static int dump_all, dump_super, dump_old, dump_contents, dump_descriptors;
f404167d
TT
44static blk64_t block_to_dump, bitmap_to_dump, inode_block_to_dump;
45static unsigned int group_to_dump, inode_offset_to_dump;
46static ext2_ino_t inode_to_dump;
da81e3fc 47
efc6f628 48struct journal_source
da81e3fc
TT
49{
50 enum journal_location where;
51 int fd;
52 ext2_file_t file;
53};
54
55static void dump_journal(char *, FILE *, struct journal_source *);
56
57static void dump_descriptor_block(FILE *, struct journal_source *,
58 char *, journal_superblock_t *,
59 unsigned int *, int, tid_t);
60
61static void dump_revoke_block(FILE *, char *, journal_superblock_t *,
62 unsigned int, int, tid_t);
63
64static void dump_metadata_block(FILE *, struct journal_source *,
efc6f628 65 journal_superblock_t*,
98446d73
TT
66 unsigned int, unsigned int, unsigned int,
67 int, tid_t);
da81e3fc 68
8968289b
HS
69static void dump_fc_block(FILE *out_file, char *buf, int blocksize,
70 int transaction, int *fc_done, int dump_old);
71
da81e3fc
TT
72static void do_hexdump (FILE *, char *, int);
73
74#define WRAP(jsb, blocknr) \
75 if (blocknr >= be32_to_cpu((jsb)->s_maxlen)) \
76 blocknr -= (be32_to_cpu((jsb)->s_maxlen) - \
77 be32_to_cpu((jsb)->s_first));
78
2fcbcb1b
TT
79void do_logdump(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
80 void *infop EXT2FS_ATTR((unused)))
da81e3fc 81{
da81e3fc 82 int c;
da81e3fc
TT
83 int retval;
84 char *out_fn;
85 FILE *out_file;
efc6f628 86
da81e3fc
TT
87 char *inode_spec = NULL;
88 char *journal_fn = NULL;
89 int journal_fd = 0;
a435ec34 90 int use_sb = 0;
da81e3fc
TT
91 ext2_ino_t journal_inum;
92 struct ext2_inode journal_inode;
93 ext2_file_t journal_file;
da81e3fc 94 char *tmp;
5e4f0709 95 struct journal_source journal_source;
f364093b 96 struct ext2_super_block *es = NULL;
efc6f628 97
c5977630 98 journal_source.where = JOURNAL_IS_INTERNAL;
5e4f0709
TT
99 journal_source.fd = 0;
100 journal_source.file = 0;
da81e3fc 101 dump_all = 0;
46272d5a 102 dump_old = 0;
da81e3fc 103 dump_contents = 0;
03a179a1 104 dump_super = 0;
da81e3fc 105 dump_descriptors = 1;
54434927 106 block_to_dump = ANY_BLOCK;
da81e3fc 107 bitmap_to_dump = -1;
54434927 108 inode_block_to_dump = ANY_BLOCK;
da81e3fc 109 inode_to_dump = -1;
efc6f628 110
88494bb6 111 reset_getopt();
03a179a1 112 while ((c = getopt (argc, argv, "ab:ci:f:OsS")) != EOF) {
da81e3fc
TT
113 switch (c) {
114 case 'a':
115 dump_all++;
116 break;
117 case 'b':
118 block_to_dump = strtoul(optarg, &tmp, 0);
119 if (*tmp) {
120 com_err(argv[0], 0,
121 "Bad block number - %s", optarg);
122 return;
123 }
124 dump_descriptors = 0;
125 break;
126 case 'c':
127 dump_contents++;
128 break;
129 case 'f':
130 journal_fn = optarg;
131 break;
132 case 'i':
133 inode_spec = optarg;
134 dump_descriptors = 0;
135 break;
46272d5a
DW
136 case 'O':
137 dump_old++;
138 break;
a435ec34
TT
139 case 's':
140 use_sb++;
141 break;
03a179a1
TT
142 case 'S':
143 dump_super++;
144 break;
da81e3fc 145 default:
9b9a780f 146 goto print_usage;
da81e3fc
TT
147 }
148 }
149 if (optind != argc && optind != argc-1) {
9b9a780f 150 goto print_usage;
da81e3fc
TT
151 }
152
f364093b
TT
153 if (current_fs)
154 es = current_fs->super;
155
da81e3fc
TT
156 if (inode_spec) {
157 int inode_group, group_offset, inodes_per_block;
f364093b 158
da81e3fc
TT
159 if (check_fs_open(argv[0]))
160 return;
161
162 inode_to_dump = string_to_inode(inode_spec);
163 if (!inode_to_dump)
164 return;
165
166 inode_group = ((inode_to_dump - 1)
f364093b 167 / es->s_inodes_per_group);
da81e3fc 168 group_offset = ((inode_to_dump - 1)
f364093b 169 % es->s_inodes_per_group);
efc6f628 170 inodes_per_block = (current_fs->blocksize
da81e3fc 171 / sizeof(struct ext2_inode));
efc6f628
TT
172
173 inode_block_to_dump =
048786d7 174 ext2fs_inode_table_loc(current_fs, inode_group) +
da81e3fc
TT
175 (group_offset / inodes_per_block);
176 inode_offset_to_dump = ((group_offset % inodes_per_block)
177 * sizeof(struct ext2_inode));
4dbfd79d 178 printf("Inode %u is at group %u, block %llu, offset %u\n",
da81e3fc 179 inode_to_dump, inode_group,
33b9a60c
TT
180 (unsigned long long) inode_block_to_dump,
181 inode_offset_to_dump);
da81e3fc
TT
182 }
183
184 if (optind == argc) {
185 out_file = stdout;
186 } else {
187 out_fn = argv[optind];
188 out_file = fopen(out_fn, "w");
0bed54fd 189 if (!out_file) {
da81e3fc
TT
190 com_err(argv[0], errno, "while opening %s for logdump",
191 out_fn);
0bed54fd 192 goto errout;
da81e3fc
TT
193 }
194 }
195
54434927 196 if (block_to_dump != ANY_BLOCK && current_fs != NULL) {
efc6f628 197 group_to_dump = ((block_to_dump -
f364093b
TT
198 es->s_first_data_block)
199 / es->s_blocks_per_group);
048786d7 200 bitmap_to_dump = ext2fs_block_bitmap_loc(current_fs, group_to_dump);
da81e3fc 201 }
da81e3fc 202
5faba3ac 203 if (!journal_fn && check_fs_open(argv[0]))
0bed54fd 204 goto errout;
5faba3ac
TT
205
206 if (journal_fn) {
da81e3fc
TT
207 /* Set up to read journal from a regular file somewhere */
208 journal_fd = open(journal_fn, O_RDONLY, 0);
209 if (journal_fd < 0) {
210 com_err(argv[0], errno, "while opening %s for logdump",
211 journal_fn);
0bed54fd 212 goto errout;
da81e3fc 213 }
efc6f628 214
da81e3fc
TT
215 journal_source.where = JOURNAL_IS_EXTERNAL;
216 journal_source.fd = journal_fd;
f364093b 217 } else if ((journal_inum = es->s_journal_inum)) {
a435ec34
TT
218 if (use_sb) {
219 if (es->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS) {
220 com_err(argv[0], 0,
221 "no journal backup in super block\n");
0bed54fd 222 goto errout;
a435ec34
TT
223 }
224 memset(&journal_inode, 0, sizeof(struct ext2_inode));
efc6f628 225 memcpy(&journal_inode.i_block[0], es->s_jnl_blocks,
a435ec34 226 EXT2_N_BLOCKS*4);
931b58e1 227 journal_inode.i_size_high = es->s_jnl_blocks[15];
a435ec34
TT
228 journal_inode.i_size = es->s_jnl_blocks[16];
229 journal_inode.i_links_count = 1;
230 journal_inode.i_mode = LINUX_S_IFREG | 0600;
231 } else {
efc6f628 232 if (debugfs_read_inode(journal_inum, &journal_inode,
a435ec34 233 argv[0]))
0bed54fd 234 goto errout;
a435ec34 235 }
efc6f628 236
a435ec34
TT
237 retval = ext2fs_file_open2(current_fs, journal_inum,
238 &journal_inode, 0, &journal_file);
da81e3fc
TT
239 if (retval) {
240 com_err(argv[0], retval, "while opening ext2 file");
0bed54fd 241 goto errout;
da81e3fc 242 }
da81e3fc
TT
243 journal_source.where = JOURNAL_IS_INTERNAL;
244 journal_source.file = journal_file;
f364093b
TT
245 } else {
246 char uuid[37];
efc6f628 247
f364093b
TT
248 uuid_unparse(es->s_journal_uuid, uuid);
249 journal_fn = blkid_get_devname(NULL, "UUID", uuid);
250 if (!journal_fn)
251 journal_fn = blkid_devno_to_devname(es->s_journal_dev);
252 if (!journal_fn) {
253 com_err(argv[0], 0, "filesystem has no journal");
0bed54fd 254 goto errout;
f364093b 255 }
5faba3ac
TT
256 journal_fd = open(journal_fn, O_RDONLY, 0);
257 if (journal_fd < 0) {
258 com_err(argv[0], errno, "while opening %s for logdump",
259 journal_fn);
260 free(journal_fn);
0bed54fd 261 goto errout;
5faba3ac
TT
262 }
263 fprintf(out_file, "Using external journal found at %s\n",
264 journal_fn);
265 free(journal_fn);
266 journal_source.where = JOURNAL_IS_EXTERNAL;
267 journal_source.fd = journal_fd;
da81e3fc
TT
268 }
269
270 dump_journal(argv[0], out_file, &journal_source);
271
272 if (journal_source.where == JOURNAL_IS_INTERNAL)
273 ext2fs_file_close(journal_file);
274 else
275 close(journal_fd);
276
0bed54fd 277errout:
dad0bab2 278 if (out_file && (out_file != stdout))
da81e3fc
TT
279 fclose(out_file);
280
281 return;
9b9a780f
TT
282
283print_usage:
7600aa0f 284 fprintf(stderr, "%s: Usage: logdump [-acsOS] [-b<block>] [-i<filespec>]\n\t"
9b9a780f 285 "[-f<journal_file>] [output_file]\n", argv[0]);
da81e3fc
TT
286}
287
288
efc6f628 289static int read_journal_block(const char *cmd, struct journal_source *source,
5eca88c1 290 ext2_loff_t offset, char *buf, unsigned int size)
da81e3fc
TT
291{
292 int retval;
b34b94d5 293 unsigned int got;
efc6f628 294
da81e3fc 295 if (source->where == JOURNAL_IS_EXTERNAL) {
4bb0c043
TT
296 if (lseek(source->fd, offset, SEEK_SET) < 0) {
297 retval = errno;
b34b94d5 298 goto seek_err;
4bb0c043
TT
299 }
300 retval = read(source->fd, buf, size);
b34b94d5 301 if (retval < 0) {
5faba3ac 302 retval = errno;
b34b94d5
TT
303 goto read_err;
304 }
305 got = retval;
306 retval = 0;
da81e3fc 307 } else {
5eca88c1
TT
308 retval = ext2fs_file_llseek(source->file, offset,
309 EXT2_SEEK_SET, NULL);
da81e3fc 310 if (retval) {
b34b94d5 311 seek_err:
da81e3fc
TT
312 com_err(cmd, retval, "while seeking in reading journal");
313 return retval;
314 }
b34b94d5
TT
315 retval = ext2fs_file_read(source->file, buf, size, &got);
316 if (retval) {
317 read_err:
318 com_err(cmd, retval, "while reading journal");
319 return retval;
320 }
da81e3fc 321 }
b34b94d5
TT
322 if (got != size) {
323 com_err(cmd, 0, "short read (read %u, expected %u) "
324 "while reading journal", got, size);
da81e3fc
TT
325 retval = -1;
326 }
da81e3fc
TT
327 return retval;
328}
329
5e4f0709 330static const char *type_to_name(int btype)
da81e3fc
TT
331{
332 switch (btype) {
8335d3c5 333 case JBD2_DESCRIPTOR_BLOCK:
da81e3fc 334 return "descriptor block";
8335d3c5 335 case JBD2_COMMIT_BLOCK:
da81e3fc 336 return "commit block";
8335d3c5 337 case JBD2_SUPERBLOCK_V1:
da81e3fc 338 return "V1 superblock";
8335d3c5 339 case JBD2_SUPERBLOCK_V2:
da81e3fc 340 return "V2 superblock";
8335d3c5 341 case JBD2_REVOKE_BLOCK:
da81e3fc 342 return "revoke table";
da81e3fc
TT
343 }
344 return "unrecognised type";
345}
346
347
efc6f628 348static void dump_journal(char *cmdname, FILE *out_file,
da81e3fc
TT
349 struct journal_source *source)
350{
5faba3ac 351 struct ext2_super_block *sb;
da81e3fc
TT
352 char jsb_buffer[1024];
353 char buf[8192];
354 journal_superblock_t *jsb;
54434927 355 unsigned int blocksize = 1024;
da81e3fc
TT
356 int retval;
357 __u32 magic, sequence, blocktype;
358 journal_header_t *header;
da81e3fc 359 tid_t transaction;
5faba3ac 360 unsigned int blocknr = 0;
8968289b 361 int fc_done;
efc6f628 362
5faba3ac 363 /* First, check to see if there's an ext2 superblock header */
b34b94d5 364 retval = read_journal_block(cmdname, source, 0, buf, 2048);
da81e3fc
TT
365 if (retval)
366 return;
5faba3ac
TT
367
368 jsb = (journal_superblock_t *) buf;
369 sb = (struct ext2_super_block *) (buf+1024);
2eae0930 370#ifdef WORDS_BIGENDIAN
efc6f628 371 if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
5faba3ac 372 ext2fs_swap_super(sb);
ff63f268 373#endif
efc6f628 374
8335d3c5 375 if ((be32_to_cpu(jsb->s_header.h_magic) != JBD2_MAGIC_NUMBER) &&
5faba3ac 376 (sb->s_magic == EXT2_SUPER_MAGIC) &&
4ee26699 377 ext2fs_has_feature_journal_dev(sb)) {
5faba3ac
TT
378 blocksize = EXT2_BLOCK_SIZE(sb);
379 blocknr = (blocksize == 1024) ? 2 : 1;
4ea7bd04 380 uuid_unparse(sb->s_uuid, jsb_buffer);
5faba3ac
TT
381 fprintf(out_file, "Ext2 superblock header found.\n");
382 if (dump_all) {
383 fprintf(out_file, "\tuuid=%s\n", jsb_buffer);
384 fprintf(out_file, "\tblocksize=%d\n", blocksize);
5d38ef1d 385 fprintf(out_file, "\tjournal data size %lu\n",
4efbac6f 386 (unsigned long) ext2fs_blocks_count(sb));
5faba3ac
TT
387 }
388 }
efc6f628 389
5faba3ac 390 /* Next, read the journal superblock */
5eca88c1
TT
391 retval = read_journal_block(cmdname, source,
392 ((ext2_loff_t) blocknr) * blocksize,
b34b94d5 393 jsb_buffer, 1024);
5faba3ac
TT
394 if (retval)
395 return;
396
03a179a1
TT
397 if (dump_super) {
398 e2p_list_journal_super(out_file, jsb_buffer,
399 current_fs->blocksize, 0);
400 fputc('\n', out_file);
401 }
402
da81e3fc 403 jsb = (journal_superblock_t *) jsb_buffer;
8335d3c5 404 if (be32_to_cpu(jsb->s_header.h_magic) != JBD2_MAGIC_NUMBER) {
5faba3ac
TT
405 fprintf(out_file,
406 "Journal superblock magic number invalid!\n");
407 return;
408 }
da81e3fc
TT
409 blocksize = be32_to_cpu(jsb->s_blocksize);
410 transaction = be32_to_cpu(jsb->s_sequence);
411 blocknr = be32_to_cpu(jsb->s_start);
412
413 fprintf(out_file, "Journal starts at block %u, transaction %u\n",
414 blocknr, transaction);
415
46272d5a 416 if (!blocknr) {
da81e3fc 417 /* Empty journal, nothing to do. */
46272d5a 418 if (!dump_old)
8968289b 419 goto fc;
46272d5a
DW
420 else
421 blocknr = 1;
422 }
efc6f628 423
da81e3fc 424 while (1) {
efc6f628 425 retval = read_journal_block(cmdname, source,
5eca88c1
TT
426 ((ext2_loff_t) blocknr) * blocksize,
427 buf, blocksize);
b34b94d5 428 if (retval)
8968289b 429 break;
efc6f628 430
da81e3fc
TT
431 header = (journal_header_t *) buf;
432
433 magic = be32_to_cpu(header->h_magic);
434 sequence = be32_to_cpu(header->h_sequence);
435 blocktype = be32_to_cpu(header->h_blocktype);
efc6f628 436
8335d3c5 437 if (magic != JBD2_MAGIC_NUMBER) {
da81e3fc
TT
438 fprintf (out_file, "No magic number at block %u: "
439 "end of journal.\n", blocknr);
8968289b 440 break;
da81e3fc 441 }
efc6f628 442
da81e3fc
TT
443 if (sequence != transaction) {
444 fprintf (out_file, "Found sequence %u (not %u) at "
efc6f628 445 "block %u: end of journal.\n",
da81e3fc 446 sequence, transaction, blocknr);
46272d5a 447 if (!dump_old)
8968289b 448 break;
da81e3fc
TT
449 }
450
451 if (dump_descriptors) {
452 fprintf (out_file, "Found expected sequence %u, "
453 "type %u (%s) at block %u\n",
efc6f628 454 sequence, blocktype,
da81e3fc
TT
455 type_to_name(blocktype), blocknr);
456 }
efc6f628 457
da81e3fc 458 switch (blocktype) {
8335d3c5 459 case JBD2_DESCRIPTOR_BLOCK:
efc6f628 460 dump_descriptor_block(out_file, source, buf, jsb,
da81e3fc
TT
461 &blocknr, blocksize,
462 transaction);
463 continue;
464
8335d3c5 465 case JBD2_COMMIT_BLOCK:
da81e3fc
TT
466 transaction++;
467 blocknr++;
468 WRAP(jsb, blocknr);
469 continue;
efc6f628 470
8335d3c5 471 case JBD2_REVOKE_BLOCK:
da81e3fc 472 dump_revoke_block(out_file, buf, jsb,
efc6f628 473 blocknr, blocksize,
da81e3fc
TT
474 transaction);
475 blocknr++;
476 WRAP(jsb, blocknr);
477 continue;
478
479 default:
480 fprintf (out_file, "Unexpected block type %u at "
481 "block %u.\n", blocktype, blocknr);
8968289b 482 break;
da81e3fc
TT
483 }
484 }
8968289b
HS
485
486fc:
487 blocknr = be32_to_cpu(jsb->s_maxlen) - jbd2_journal_get_num_fc_blks(jsb) + 1;
488 while (blocknr <= be32_to_cpu(jsb->s_maxlen)) {
489 retval = read_journal_block(cmdname, source,
490 ((ext2_loff_t) blocknr) * blocksize,
491 buf, blocksize);
492 if (retval)
493 return;
494
495 dump_fc_block(out_file, buf, blocksize, transaction, &fc_done,
496 dump_old);
497 if (!dump_old && fc_done)
498 break;
499 blocknr++;
500 }
da81e3fc
TT
501}
502
df0b907e
TT
503static inline size_t journal_super_tag_bytes(journal_superblock_t *jsb)
504{
505 size_t sz;
506
8335d3c5 507 if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_CSUM_V3))
df0b907e
TT
508 return sizeof(journal_block_tag3_t);
509
510 sz = sizeof(journal_block_tag_t);
511
8335d3c5 512 if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_CSUM_V2))
df0b907e
TT
513 sz += sizeof(__u16);
514
8335d3c5 515 if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_64BIT))
df0b907e
TT
516 return sz;
517
518 return sz - sizeof(__u32);
519}
da81e3fc 520
8968289b
HS
521static void dump_fc_block(FILE *out_file, char *buf, int blocksize,
522 int transaction, int *fc_done, int dump_old)
523{
524 struct ext4_fc_tl *tl;
525 struct ext4_fc_head *head;
526 struct ext4_fc_add_range *add_range;
527 struct ext4_fc_del_range *del_range;
528 struct ext4_fc_dentry_info *dentry_info;
529 struct ext4_fc_tail *tail;
530 struct ext3_extent *ex;
531
532 *fc_done = 0;
533 fc_for_each_tl(buf, buf + blocksize, tl) {
534 switch (le16_to_cpu(tl->fc_tag)) {
535 case EXT4_FC_TAG_ADD_RANGE:
536 add_range =
537 (struct ext4_fc_add_range *)ext4_fc_tag_val(tl);
538 ex = (struct ext3_extent *)add_range->fc_ex;
539 fprintf(out_file,
f41c7da2 540 "tag %s, inode %d, lblk %u, pblk %llu, len %lu\n",
8968289b
HS
541 tag2str(tl->fc_tag),
542 le32_to_cpu(add_range->fc_ino),
543 le32_to_cpu(ex->ee_block),
544 le32_to_cpu(ex->ee_start) +
33b9a60c 545 (((unsigned long long) le16_to_cpu(ex->ee_start_hi)) << 32),
8968289b
HS
546 le16_to_cpu(ex->ee_len) > EXT_INIT_MAX_LEN ?
547 le16_to_cpu(ex->ee_len) - EXT_INIT_MAX_LEN :
548 le16_to_cpu(ex->ee_len));
549 break;
550 case EXT4_FC_TAG_DEL_RANGE:
551 del_range =
552 (struct ext4_fc_del_range *)ext4_fc_tag_val(tl);
553 fprintf(out_file, "tag %s, inode %d, lblk %d, len %d\n",
554 tag2str(tl->fc_tag),
555 le32_to_cpu(del_range->fc_ino),
556 le32_to_cpu(del_range->fc_lblk),
557 le32_to_cpu(del_range->fc_len));
558 break;
559 case EXT4_FC_TAG_LINK:
560 case EXT4_FC_TAG_UNLINK:
561 case EXT4_FC_TAG_CREAT:
562 dentry_info =
563 (struct ext4_fc_dentry_info *)
564 ext4_fc_tag_val(tl);
565 fprintf(out_file,
566 "tag %s, parent %d, ino %d, name \"%s\"\n",
567 tag2str(tl->fc_tag),
568 le32_to_cpu(dentry_info->fc_parent_ino),
569 le32_to_cpu(dentry_info->fc_ino),
570 dentry_info->fc_dname);
571 break;
572 case EXT4_FC_TAG_INODE:
573 fprintf(out_file, "tag %s, inode %d\n",
574 tag2str(tl->fc_tag),
575 le32_to_cpu(((struct ext4_fc_inode *)
576 ext4_fc_tag_val(tl))->fc_ino));
577 break;
578 case EXT4_FC_TAG_PAD:
579 fprintf(out_file, "tag %s\n", tag2str(tl->fc_tag));
580 break;
581 case EXT4_FC_TAG_TAIL:
582 tail = (struct ext4_fc_tail *)ext4_fc_tag_val(tl);
583 fprintf(out_file, "tag %s, tid %d\n",
584 tag2str(tl->fc_tag),
585 le32_to_cpu(tail->fc_tid));
586 if (!dump_old &&
587 le32_to_cpu(tail->fc_tid) < transaction) {
588 *fc_done = 1;
589 return;
590 }
591 break;
592 case EXT4_FC_TAG_HEAD:
593 fprintf(out_file, "\n*** Fast Commit Area ***\n");
594 head = (struct ext4_fc_head *)ext4_fc_tag_val(tl);
595 fprintf(out_file, "tag %s, features 0x%x, tid %d\n",
596 tag2str(tl->fc_tag),
597 le32_to_cpu(head->fc_features),
598 le32_to_cpu(head->fc_tid));
599 if (!dump_old &&
600 le32_to_cpu(head->fc_tid) < transaction) {
601 *fc_done = 1;
602 return;
603 }
604 break;
605 default:
606 *fc_done = 1;
607 break;
608 }
609 }
610}
611
efc6f628
TT
612static void dump_descriptor_block(FILE *out_file,
613 struct journal_source *source,
da81e3fc 614 char *buf,
efc6f628 615 journal_superblock_t *jsb,
da81e3fc
TT
616 unsigned int *blockp, int blocksize,
617 tid_t transaction)
618{
38d5adf3 619 int offset, tag_size, csum_size = 0;
da81e3fc
TT
620 char *tagp;
621 journal_block_tag_t *tag;
622 unsigned int blocknr;
623 __u32 tag_block;
624 __u32 tag_flags;
efc6f628 625
38d5adf3 626 tag_size = journal_super_tag_bytes(jsb);
da81e3fc
TT
627 offset = sizeof(journal_header_t);
628 blocknr = *blockp;
629
8335d3c5
TT
630 if (JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_CSUM_V3) ||
631 JSB_HAS_INCOMPAT_FEATURE(jsb, JBD2_FEATURE_INCOMPAT_CSUM_V2))
632 csum_size = sizeof(struct jbd2_journal_block_tail);
38d5adf3 633
efc6f628 634 if (dump_all)
da81e3fc
TT
635 fprintf(out_file, "Dumping descriptor block, sequence %u, at "
636 "block %u:\n", transaction, blocknr);
efc6f628 637
da81e3fc
TT
638 ++blocknr;
639 WRAP(jsb, blocknr);
efc6f628 640
da81e3fc 641 do {
efc6f628 642 /* Work out the location of the current tag, and skip to
da81e3fc
TT
643 * the next one... */
644 tagp = &buf[offset];
645 tag = (journal_block_tag_t *) tagp;
98446d73 646 offset += tag_size;
da81e3fc
TT
647
648 /* ... and if we have gone too far, then we've reached the
649 end of this block. */
38d5adf3 650 if (offset > blocksize - csum_size)
da81e3fc 651 break;
efc6f628 652
da81e3fc 653 tag_block = be32_to_cpu(tag->t_blocknr);
2556373a 654 tag_flags = be16_to_cpu(tag->t_flags);
da81e3fc 655
8335d3c5 656 if (!(tag_flags & JBD2_FLAG_SAME_UUID))
da81e3fc
TT
657 offset += 16;
658
efc6f628 659 dump_metadata_block(out_file, source, jsb,
98446d73 660 blocknr, tag_block, tag_flags, blocksize,
da81e3fc
TT
661 transaction);
662
663 ++blocknr;
664 WRAP(jsb, blocknr);
efc6f628 665
8335d3c5 666 } while (!(tag_flags & JBD2_FLAG_LAST_TAG));
efc6f628 667
da81e3fc
TT
668 *blockp = blocknr;
669}
670
671
672static void dump_revoke_block(FILE *out_file, char *buf,
efc6f628
TT
673 journal_superblock_t *jsb EXT2FS_ATTR((unused)),
674 unsigned int blocknr,
54434927
TT
675 int blocksize EXT2FS_ATTR((unused)),
676 tid_t transaction)
da81e3fc
TT
677{
678 int offset, max;
8335d3c5 679 jbd2_journal_revoke_header_t *header;
a1ff15f8
DW
680 unsigned long long rblock;
681 int tag_size = sizeof(__u32);
efc6f628
TT
682
683 if (dump_all)
da81e3fc
TT
684 fprintf(out_file, "Dumping revoke block, sequence %u, at "
685 "block %u:\n", transaction, blocknr);
efc6f628 686
8335d3c5 687 if (be32_to_cpu(jsb->s_feature_incompat) & JBD2_FEATURE_INCOMPAT_64BIT)
a1ff15f8
DW
688 tag_size = sizeof(__u64);
689
8335d3c5
TT
690 header = (jbd2_journal_revoke_header_t *) buf;
691 offset = sizeof(jbd2_journal_revoke_header_t);
da81e3fc
TT
692 max = be32_to_cpu(header->r_count);
693
694 while (offset < max) {
a1ff15f8
DW
695 if (tag_size == sizeof(__u32)) {
696 __u32 *entry = (__u32 *) (buf + offset);
697 rblock = be32_to_cpu(*entry);
698 } else {
699 __u64 *entry = (__u64 *) (buf + offset);
700 rblock = ext2fs_be64_to_cpu(*entry);
701 }
da81e3fc 702 if (dump_all || rblock == block_to_dump) {
33b9a60c
TT
703 fprintf(out_file, " Revoke FS block %llu",
704 (unsigned long long) rblock);
da81e3fc
TT
705 if (dump_all)
706 fprintf(out_file, "\n");
707 else
708 fprintf(out_file," at block %u, sequence %u\n",
709 blocknr, transaction);
710 }
a1ff15f8 711 offset += tag_size;
da81e3fc
TT
712 }
713}
714
715
716static void show_extent(FILE *out_file, int start_extent, int end_extent,
717 __u32 first_block)
718{
719 if (start_extent >= 0 && first_block != 0)
efc6f628 720 fprintf(out_file, "(%d+%u): %u ",
da81e3fc
TT
721 start_extent, end_extent-start_extent, first_block);
722}
723
5e4f0709 724static void show_indirect(FILE *out_file, const char *name, __u32 where)
da81e3fc
TT
725{
726 if (where)
727 fprintf(out_file, "(%s): %u ", name, where);
728}
729
730
731static void dump_metadata_block(FILE *out_file, struct journal_source *source,
54434927 732 journal_superblock_t *jsb EXT2FS_ATTR((unused)),
efc6f628
TT
733 unsigned int log_blocknr,
734 unsigned int fs_blocknr,
98446d73 735 unsigned int log_tag_flags,
da81e3fc
TT
736 int blocksize,
737 tid_t transaction)
738{
5e4f0709
TT
739 int retval;
740 char buf[8192];
efc6f628 741
da81e3fc
TT
742 if (!(dump_all
743 || (fs_blocknr == block_to_dump)
744 || (fs_blocknr == inode_block_to_dump)
745 || (fs_blocknr == bitmap_to_dump)))
746 return;
efc6f628 747
da81e3fc 748 fprintf(out_file, " FS block %u logged at ", fs_blocknr);
efc6f628 749 if (!dump_all)
da81e3fc 750 fprintf(out_file, "sequence %u, ", transaction);
98446d73
TT
751 fprintf(out_file, "journal block %u (flags 0x%x)\n", log_blocknr,
752 log_tag_flags);
efc6f628 753
da81e3fc 754 /* There are two major special cases to parse:
efc6f628 755 *
da81e3fc
TT
756 * If this block is a block
757 * bitmap block, we need to give it special treatment so that we
758 * can log any allocates and deallocates which affect the
efc6f628
TT
759 * block_to_dump query block.
760 *
da81e3fc
TT
761 * If the block is an inode block for the inode being searched
762 * for, then we need to dump the contents of that inode
efc6f628 763 * structure symbolically.
da81e3fc 764 */
efc6f628 765
da81e3fc
TT
766 if (!(dump_contents && dump_all)
767 && fs_blocknr != block_to_dump
efc6f628 768 && fs_blocknr != bitmap_to_dump
da81e3fc
TT
769 && fs_blocknr != inode_block_to_dump)
770 return;
efc6f628
TT
771
772 retval = read_journal_block("logdump", source,
5eca88c1 773 ((ext2_loff_t) log_blocknr) * blocksize,
b34b94d5 774 buf, blocksize);
da81e3fc
TT
775 if (retval)
776 return;
efc6f628 777
da81e3fc
TT
778 if (fs_blocknr == bitmap_to_dump) {
779 struct ext2_super_block *super;
780 int offset;
efc6f628 781
da81e3fc 782 super = current_fs->super;
de2c4778 783 offset = ((block_to_dump - super->s_first_data_block) %
da81e3fc 784 super->s_blocks_per_group);
efc6f628 785
4dbfd79d 786 fprintf(out_file, " (block bitmap for block %llu: "
efc6f628 787 "block is %s)\n",
33b9a60c 788 (unsigned long long) block_to_dump,
da81e3fc
TT
789 ext2fs_test_bit(offset, buf) ? "SET" : "CLEAR");
790 }
efc6f628 791
da81e3fc
TT
792 if (fs_blocknr == inode_block_to_dump) {
793 struct ext2_inode *inode;
794 int first, prev, this, start_extent, i;
efc6f628 795
da81e3fc
TT
796 fprintf(out_file, " (inode block for inode %u):\n",
797 inode_to_dump);
efc6f628 798
da81e3fc
TT
799 inode = (struct ext2_inode *) (buf + inode_offset_to_dump);
800 internal_dump_inode(out_file, " ", inode_to_dump, inode, 0);
efc6f628 801
da81e3fc
TT
802 /* Dump out the direct/indirect blocks here:
803 * internal_dump_inode can only dump them from the main
804 * on-disk inode, not from the journaled copy of the
805 * inode. */
efc6f628 806
da81e3fc 807 fprintf (out_file, " Blocks: ");
5e4f0709 808 first = prev = start_extent = -1;
da81e3fc
TT
809
810 for (i=0; i<EXT2_NDIR_BLOCKS; i++) {
811 this = inode->i_block[i];
812 if (start_extent >= 0 && this == prev+1) {
813 prev = this;
814 continue;
815 } else {
816 show_extent(out_file, start_extent, i, first);
817 start_extent = i;
818 first = prev = this;
819 }
820 }
821 show_extent(out_file, start_extent, i, first);
822 show_indirect(out_file, "IND", inode->i_block[i++]);
823 show_indirect(out_file, "DIND", inode->i_block[i++]);
824 show_indirect(out_file, "TIND", inode->i_block[i++]);
efc6f628 825
da81e3fc
TT
826 fprintf(out_file, "\n");
827 }
828
829 if (dump_contents)
830 do_hexdump(out_file, buf, blocksize);
efc6f628 831
da81e3fc
TT
832}
833
834static void do_hexdump (FILE *out_file, char *buf, int blocksize)
835{
836 int i,j;
837 int *intp;
838 char *charp;
839 unsigned char c;
efc6f628 840
da81e3fc
TT
841 intp = (int *) buf;
842 charp = (char *) buf;
efc6f628 843
da81e3fc
TT
844 for (i=0; i<blocksize; i+=16) {
845 fprintf(out_file, " %04x: ", i);
846 for (j=0; j<16; j+=4)
847 fprintf(out_file, "%08x ", *intp++);
848 for (j=0; j<16; j++) {
849 c = *charp++;
850 if (c < ' ' || c >= 127)
851 c = '.';
852 fprintf(out_file, "%c", c);
853 }
854 fprintf(out_file, "\n");
855 }
856}
857