2 * e2undo.c - Replay an undo log onto an ext2/3/4 filesystem
4 * Copyright IBM Corporation, 2007
5 * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
8 * This file may be redistributed under the terms of the GNU Public
25 #include "ext2fs/ext2fs.h"
26 #include "support/nls-enable.h"
31 # define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0)
33 # define dbg_printf(f, a...)
37 * Undo file format: The file is cut up into undo_header.block_size blocks.
38 * The first block contains the header.
39 * The second block contains the superblock.
40 * There is then a repeating series of blocks as follows:
41 * A key block, which contains undo_keys to map the following data blocks.
43 * (Note that there are pointers to the first key block and the sb, so this
44 * order isn't strictly necessary.)
46 #define E2UNDO_MAGIC "E2UNDO02"
47 #define KEYBLOCK_MAGIC 0xCADECADE
49 #define E2UNDO_STATE_FINISHED 0x1 /* undo file is complete */
51 #define E2UNDO_MIN_BLOCK_SIZE 1024 /* undo blocks are no less than 1KB */
52 #define E2UNDO_MAX_BLOCK_SIZE 1048576 /* undo blocks are no more than 1MB */
55 char magic
[8]; /* "E2UNDO02" */
56 __le64 num_keys
; /* how many keys? */
57 __le64 super_offset
; /* where in the file is the superblock copy? */
58 __le64 key_offset
; /* where do the key/data block chunks start? */
59 __le32 block_size
; /* block size of the undo file */
60 __le32 fs_block_size
; /* block size of the target device */
61 __le32 sb_crc
; /* crc32c of the superblock */
62 __le32 state
; /* e2undo state flags */
63 __le32 f_compat
; /* compatible features (none so far) */
64 __le32 f_incompat
; /* incompatible features (none so far) */
65 __le32 f_rocompat
; /* ro compatible features (none so far) */
66 __le32 pad32
; /* padding for fs_offset */
67 __le64 fs_offset
; /* filesystem offset */
68 __u8 padding
[436]; /* padding */
69 __le32 header_crc
; /* crc32c of the header (but not this field) */
72 #define E2UNDO_MAX_EXTENT_BLOCKS 512 /* max extent size, in blocks */
75 __le64 fsblk
; /* where in the fs does the block go */
76 __le32 blk_crc
; /* crc32c of the block */
77 __le32 size
; /* how many bytes in this block? */
80 struct undo_key_block
{
81 __le32 magic
; /* KEYBLOCK_MAGIC number */
82 __le32 crc
; /* block checksum */
83 __le64 reserved
; /* zero */
85 struct undo_key keys
[0]; /* keys, which come immediately after */
88 struct undo_key_info
{
96 struct undo_header hdr
;
98 unsigned int blocksize
, fs_blocksize
;
101 struct undo_key_info
*keys
;
103 #define KEYS_PER_BLOCK(d) (((d)->blocksize / sizeof(struct undo_key)) - 1)
105 #define E2UNDO_FEATURE_COMPAT_FS_OFFSET 0x1 /* the filesystem offset */
107 static inline int e2undo_has_feature_fs_offset(struct undo_header
*header
) {
108 return ext2fs_le32_to_cpu(header
->f_compat
) &
109 E2UNDO_FEATURE_COMPAT_FS_OFFSET
;
112 static char *prg_name
;
113 static char *undo_file
;
115 static void usage(void)
118 _("Usage: %s [-f] [-h] [-n] [-o offset] [-v] [-z undo_file] <transaction file> <filesystem>\n"), prg_name
);
122 static void dump_header(struct undo_header
*hdr
)
124 printf("nr keys:\t%llu\n", ext2fs_le64_to_cpu(hdr
->num_keys
));
125 printf("super block:\t%llu\n", ext2fs_le64_to_cpu(hdr
->super_offset
));
126 printf("key block:\t%llu\n", ext2fs_le64_to_cpu(hdr
->key_offset
));
127 printf("block size:\t%u\n", ext2fs_le32_to_cpu(hdr
->block_size
));
128 printf("fs block size:\t%u\n", ext2fs_le32_to_cpu(hdr
->fs_block_size
));
129 printf("super crc:\t0x%x\n", ext2fs_le32_to_cpu(hdr
->sb_crc
));
130 printf("state:\t\t0x%x\n", ext2fs_le32_to_cpu(hdr
->state
));
131 printf("compat:\t\t0x%x\n", ext2fs_le32_to_cpu(hdr
->f_compat
));
132 printf("incompat:\t0x%x\n", ext2fs_le32_to_cpu(hdr
->f_incompat
));
133 printf("rocompat:\t0x%x\n", ext2fs_le32_to_cpu(hdr
->f_rocompat
));
134 if (e2undo_has_feature_fs_offset(hdr
))
135 printf("fs offset:\t%llu\n", ext2fs_le64_to_cpu(hdr
->fs_offset
));
136 printf("header crc:\t0x%x\n", ext2fs_le32_to_cpu(hdr
->header_crc
));
139 static void print_undo_mismatch(struct ext2_super_block
*fs_super
,
140 struct ext2_super_block
*undo_super
)
143 _("The file system superblock doesn't match the undo file.\n"));
144 if (memcmp(fs_super
->s_uuid
, undo_super
->s_uuid
,
145 sizeof(fs_super
->s_uuid
)))
146 printf("%s", _("UUID does not match.\n"));
147 if (fs_super
->s_mtime
!= undo_super
->s_mtime
)
148 printf("%s", _("Last mount time does not match.\n"));
149 if (fs_super
->s_wtime
!= undo_super
->s_wtime
)
150 printf("%s", _("Last write time does not match.\n"));
151 if (fs_super
->s_kbytes_written
!= undo_super
->s_kbytes_written
)
152 printf("%s", _("Lifetime write counter does not match.\n"));
155 static int check_filesystem(struct undo_context
*ctx
, io_channel channel
)
157 struct ext2_super_block super
, *sb
;
162 io_channel_set_blksize(channel
, SUPERBLOCK_OFFSET
);
163 retval
= io_channel_read_blk64(channel
, 1, -SUPERBLOCK_SIZE
, &super
);
165 com_err(prg_name
, retval
,
166 "%s", _("while reading filesystem superblock."));
171 * Compare the FS and the undo file superblock so that we can't apply
172 * e2undo "patches" out of order.
174 retval
= ext2fs_get_mem(ctx
->blocksize
, &buf
);
176 com_err(prg_name
, retval
, "%s", _("while allocating memory"));
179 retval
= io_channel_read_blk64(ctx
->undo_file
, ctx
->super_block
,
180 -SUPERBLOCK_SIZE
, buf
);
182 com_err(prg_name
, retval
, "%s", _("while fetching superblock"));
185 sb
= (struct ext2_super_block
*)buf
;
186 sb
->s_magic
= ~sb
->s_magic
;
187 if (memcmp(&super
, buf
, sizeof(super
))) {
188 print_undo_mismatch(&super
, (struct ext2_super_block
*)buf
);
192 sb_crc
= ext2fs_crc32c_le(~0, (unsigned char *)buf
, SUPERBLOCK_SIZE
);
193 if (ext2fs_le32_to_cpu(ctx
->hdr
.sb_crc
) != sb_crc
) {
195 _("Undo file superblock checksum doesn't match.\n"));
201 ext2fs_free_mem(&buf
);
205 static int key_compare(const void *a
, const void *b
)
207 const struct undo_key_info
*ka
, *kb
;
211 return ka
->fsblk
- kb
->fsblk
;
214 static int e2undo_setup_tdb(const char *name
, io_manager
*io_ptr
)
216 errcode_t retval
= 0;
218 char *tdb_file
= NULL
;
219 char *dev_name
, *tmp_name
;
221 /* (re)open a specific undo file */
222 if (undo_file
&& undo_file
[0] != 0) {
223 retval
= set_undo_io_backing_manager(*io_ptr
);
226 *io_ptr
= undo_io_manager
;
227 retval
= set_undo_io_backup_file(undo_file
);
230 printf(_("Overwriting existing filesystem; this can be undone "
231 "using the command:\n"
232 " e2undo %s %s\n\n"),
238 * Configuration via a conf file would be
241 tdb_dir
= getenv("E2FSPROGS_UNDO_DIR");
243 tdb_dir
= "/var/lib/e2fsprogs";
245 if (!strcmp(tdb_dir
, "none") || (tdb_dir
[0] == 0) ||
246 access(tdb_dir
, W_OK
))
249 tmp_name
= strdup(name
);
252 dev_name
= basename(tmp_name
);
253 tdb_file
= malloc(strlen(tdb_dir
) + 8 + strlen(dev_name
) + 7 + 1);
258 sprintf(tdb_file
, "%s/e2undo-%s.e2undo", tdb_dir
, dev_name
);
261 if ((unlink(tdb_file
) < 0) && (errno
!= ENOENT
)) {
263 com_err(prg_name
, retval
,
264 _("while trying to delete %s"), tdb_file
);
268 retval
= set_undo_io_backing_manager(*io_ptr
);
271 *io_ptr
= undo_io_manager
;
272 retval
= set_undo_io_backup_file(tdb_file
);
275 printf(_("Overwriting existing filesystem; this can be undone "
276 "using the command:\n"
277 " e2undo %s %s\n\n"),
285 com_err(prg_name
, retval
, "while trying to setup undo file\n");
289 int main(int argc
, char *argv
[])
291 int c
, force
= 0, dry_run
= 0, verbose
= 0, dump
= 0;
294 int mount_flags
, csum_error
= 0, io_error
= 0;
295 size_t i
, keys_per_block
;
296 char *device_name
, *tdb_file
;
297 io_manager manager
= unix_io_manager
;
298 struct undo_context undo_ctx
;
300 struct undo_key_block
*keyb
;
301 struct undo_key
*dkey
;
302 struct undo_key_info
*ikey
;
303 __u32 key_crc
, blk_crc
, hdr_crc
;
307 char opt_offset_string
[40] = { 0 };
310 setlocale(LC_MESSAGES
, "");
311 setlocale(LC_CTYPE
, "");
312 bindtextdomain(NLS_CAT_NAME
, LOCALEDIR
);
313 textdomain(NLS_CAT_NAME
);
314 set_com_err_gettext(gettext
);
316 add_error_table(&et_ext2_error_table
);
319 while ((c
= getopt(argc
, argv
, "fhno:vz:")) != EOF
) {
331 offset
= strtoull(optarg
, &buf
, 0);
334 _("illegal offset - %s"), optarg
);
337 /* used to indicate that an offset was specified */
338 opt_offset_string
[0] = 1;
351 if (argc
!= optind
+ 2)
354 tdb_file
= argv
[optind
];
355 device_name
= argv
[optind
+1];
357 if (undo_file
&& strcmp(tdb_file
, undo_file
) == 0) {
358 printf(_("Will not write to an undo file while replaying it.\n"));
362 /* Interpret the undo file */
363 retval
= manager
->open(tdb_file
, IO_FLAG_EXCLUSIVE
,
364 &undo_ctx
.undo_file
);
366 com_err(prg_name
, errno
,
367 _("while opening undo file `%s'\n"), tdb_file
);
370 retval
= io_channel_read_blk64(undo_ctx
.undo_file
, 0,
371 -(int)sizeof(undo_ctx
.hdr
),
374 com_err(prg_name
, retval
, _("while reading undo file"));
377 if (memcmp(undo_ctx
.hdr
.magic
, E2UNDO_MAGIC
,
378 sizeof(undo_ctx
.hdr
.magic
))) {
379 fprintf(stderr
, _("%s: Not an undo file.\n"), tdb_file
);
383 dump_header(&undo_ctx
.hdr
);
386 hdr_crc
= ext2fs_crc32c_le(~0, (unsigned char *)&undo_ctx
.hdr
,
387 sizeof(struct undo_header
) -
389 if (!force
&& ext2fs_le32_to_cpu(undo_ctx
.hdr
.header_crc
) != hdr_crc
) {
390 fprintf(stderr
, _("%s: Header checksum doesn't match.\n"),
394 undo_ctx
.blocksize
= ext2fs_le32_to_cpu(undo_ctx
.hdr
.block_size
);
395 undo_ctx
.fs_blocksize
= ext2fs_le32_to_cpu(undo_ctx
.hdr
.fs_block_size
);
396 if (undo_ctx
.blocksize
== 0 || undo_ctx
.fs_blocksize
== 0) {
397 fprintf(stderr
, _("%s: Corrupt undo file header.\n"), tdb_file
);
400 if (!force
&& undo_ctx
.blocksize
> E2UNDO_MAX_BLOCK_SIZE
) {
401 fprintf(stderr
, _("%s: Undo block size too large.\n"),
405 if (!force
&& undo_ctx
.blocksize
< E2UNDO_MIN_BLOCK_SIZE
) {
406 fprintf(stderr
, _("%s: Undo block size too small.\n"),
410 undo_ctx
.super_block
= ext2fs_le64_to_cpu(undo_ctx
.hdr
.super_offset
);
411 undo_ctx
.num_keys
= ext2fs_le64_to_cpu(undo_ctx
.hdr
.num_keys
);
412 io_channel_set_blksize(undo_ctx
.undo_file
, undo_ctx
.blocksize
);
414 * Do not compare undo_ctx.hdr.f_compat with the available compatible
415 * features set, because a "missing" compatible feature should
416 * not cause any problems.
418 if (!force
&& (undo_ctx
.hdr
.f_incompat
|| undo_ctx
.hdr
.f_rocompat
)) {
419 fprintf(stderr
, _("%s: Unknown undo file feature set.\n"),
425 retval
= ext2fs_check_if_mounted(device_name
, &mount_flags
);
427 com_err(prg_name
, retval
, _("Error while determining whether "
428 "%s is mounted."), device_name
);
432 if (mount_flags
& EXT2_MF_MOUNTED
) {
433 com_err(prg_name
, retval
, "%s", _("e2undo should only be run "
434 "on unmounted filesystems"));
439 retval
= e2undo_setup_tdb(device_name
, &manager
);
444 retval
= manager
->open(device_name
,
445 IO_FLAG_EXCLUSIVE
| (dry_run
? 0 : IO_FLAG_RW
),
448 com_err(prg_name
, retval
,
449 _("while opening `%s'"), device_name
);
453 if (*opt_offset_string
|| e2undo_has_feature_fs_offset(&undo_ctx
.hdr
)) {
454 if (!*opt_offset_string
)
455 offset
= ext2fs_le64_to_cpu(undo_ctx
.hdr
.fs_offset
);
456 retval
= snprintf(opt_offset_string
, sizeof(opt_offset_string
),
457 "offset=%llu", offset
);
458 if ((size_t) retval
>= sizeof(opt_offset_string
)) {
459 /* should not happen... */
460 com_err(prg_name
, 0, _("specified offset is too large"));
463 io_channel_set_options(channel
, opt_offset_string
);
466 if (!force
&& check_filesystem(&undo_ctx
, channel
))
469 /* prepare to read keys */
470 retval
= ext2fs_get_mem(sizeof(struct undo_key_info
) * undo_ctx
.num_keys
,
473 com_err(prg_name
, retval
, "%s", _("while allocating memory"));
476 ikey
= undo_ctx
.keys
;
477 retval
= ext2fs_get_mem(undo_ctx
.blocksize
, &keyb
);
479 com_err(prg_name
, retval
, "%s", _("while allocating memory"));
482 retval
= ext2fs_get_mem(E2UNDO_MAX_EXTENT_BLOCKS
* undo_ctx
.blocksize
,
485 com_err(prg_name
, retval
, "%s", _("while allocating memory"));
490 keys_per_block
= KEYS_PER_BLOCK(&undo_ctx
);
491 lblk
= ext2fs_le64_to_cpu(undo_ctx
.hdr
.key_offset
);
492 dbg_printf("nr_keys=%lu, kpb=%zu, blksz=%u\n",
493 undo_ctx
.num_keys
, keys_per_block
, undo_ctx
.blocksize
);
494 for (i
= 0; i
< undo_ctx
.num_keys
; i
+= keys_per_block
) {
498 retval
= io_channel_read_blk64(undo_ctx
.undo_file
,
501 com_err(prg_name
, retval
, "%s", _("while reading keys"));
504 undo_ctx
.num_keys
= i
- 1;
512 ext2fs_le32_to_cpu(keyb
->magic
) != KEYBLOCK_MAGIC
) {
513 fprintf(stderr
, _("%s: wrong key magic at %llu\n"),
519 key_crc
= ext2fs_crc32c_le(~0, (unsigned char *)keyb
,
521 if (!force
&& ext2fs_le32_to_cpu(crc
) != key_crc
) {
523 _("%s: key block checksum error at %llu.\n"),
528 /* load keys from key block */
530 max_j
= undo_ctx
.num_keys
- i
;
531 if (max_j
> keys_per_block
)
532 max_j
= keys_per_block
;
533 for (j
= 0, dkey
= keyb
->keys
;
535 j
++, ikey
++, dkey
++) {
536 ikey
->fsblk
= ext2fs_le64_to_cpu(dkey
->fsblk
);
537 ikey
->fileblk
= lblk
;
538 ikey
->blk_crc
= ext2fs_le32_to_cpu(dkey
->blk_crc
);
539 ikey
->size
= ext2fs_le32_to_cpu(dkey
->size
);
540 lblk
+= (ikey
->size
+ undo_ctx
.blocksize
- 1) /
543 if (E2UNDO_MAX_EXTENT_BLOCKS
* undo_ctx
.blocksize
<
545 com_err(prg_name
, retval
,
546 _("%s: block %llu is too long."),
547 tdb_file
, ikey
->fsblk
);
551 /* check each block's crc */
552 retval
= io_channel_read_blk64(undo_ctx
.undo_file
,
557 com_err(prg_name
, retval
,
558 _("while fetching block %llu."),
566 blk_crc
= ext2fs_crc32c_le(~0, (unsigned char *)buf
,
568 if (blk_crc
!= ikey
->blk_crc
) {
570 _("checksum error in filesystem block "
571 "%llu (undo blk %llu)\n"),
572 ikey
->fsblk
, ikey
->fileblk
);
579 ext2fs_free_mem(&keyb
);
581 /* sort keys in fs block order */
582 qsort(undo_ctx
.keys
, undo_ctx
.num_keys
, sizeof(struct undo_key_info
),
586 io_channel_set_blksize(channel
, undo_ctx
.fs_blocksize
);
587 for (i
= 0, ikey
= undo_ctx
.keys
; i
< undo_ctx
.num_keys
; i
++, ikey
++) {
588 retval
= io_channel_read_blk64(undo_ctx
.undo_file
,
593 com_err(prg_name
, retval
,
594 _("while fetching block %llu."),
601 printf("Replayed block of size %u from %llu to %llu\n",
602 ikey
->size
, ikey
->fileblk
, ikey
->fsblk
);
605 retval
= io_channel_write_blk64(channel
, ikey
->fsblk
,
606 -(int)ikey
->size
, buf
);
608 com_err(prg_name
, retval
,
609 _("while writing block %llu."), ikey
->fsblk
);
615 fprintf(stderr
, _("Undo file corruption; run e2fsck NOW!\n"));
617 fprintf(stderr
, _("IO error during replay; run e2fsck NOW!\n"));
618 if (!(ext2fs_le32_to_cpu(undo_ctx
.hdr
.state
) & E2UNDO_STATE_FINISHED
)) {
620 fprintf(stderr
, _("Incomplete undo record; run e2fsck.\n"));
622 ext2fs_free_mem(&buf
);
623 ext2fs_free_mem(&undo_ctx
.keys
);
624 io_channel_close(channel
);
626 /* If there were problems, try to force a fsck */
627 if (!dry_run
&& (force
|| csum_error
|| io_error
)) {
628 retval
= ext2fs_open2(device_name
, NULL
,
629 EXT2_FLAG_RW
| EXT2_FLAG_64BITS
, 0, 0,
633 fs
->super
->s_state
&= ~EXT2_VALID_FS
;
634 if (csum_error
|| io_error
)
635 fs
->super
->s_state
|= EXT2_ERROR_FS
;
636 ext2fs_mark_super_dirty(fs
);
637 ext2fs_close_free(&fs
);
641 io_channel_close(undo_ctx
.undo_file
);