@UUIDD_CMT@UUIDD_MAN= uuidd.8
SPROGS= mke2fs badblocks tune2fs dumpe2fs blkid logsave \
- $(E2IMAGE_PROG) @FSCK_PROG@
+ $(E2IMAGE_PROG) @FSCK_PROG@ e2undo
USPROGS= mklost+found filefrag $(UUIDD_PROG)
SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
e2label.8 findfs.8 blkid.8 $(E2IMAGE_MAN) \
- logsave.8 filefrag.8 $(UUIDD_MAN) @FSCK_MAN@
+ logsave.8 filefrag.8 e2undo.8 $(UUIDD_MAN) @FSCK_MAN@
FMANPAGES= mke2fs.conf.5
UPROGS= chattr lsattr uuidgen
FSCK_OBJS= fsck.o base_device.o ismounted.o
BLKID_OBJS= blkid.o
FILEFRAG_OBJS= filefrag.o
+E2UNDO_OBJS= e2undo.o
XTRA_CFLAGS= -I$(srcdir)/../e2fsck -I.
$(srcdir)/badblocks.c $(srcdir)/fsck.c $(srcdir)/util.c \
$(srcdir)/uuidgen.c $(srcdir)/blkid.c $(srcdir)/logsave.c \
$(srcdir)/filefrag.c $(srcdir)/base_device.c \
- $(srcdir)/ismounted.c $(srcdir)/../e2fsck/profile.c
+ $(srcdir)/ismounted.c $(srcdir)/../e2fsck/profile.c \
+ $(srcdir)/e2undo.c
LIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
DEPLIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
@echo " LD $@"
@$(CC) $(ALL_LDFLAGS) -o e2image $(E2IMAGE_OBJS) $(LIBS) $(LIBINTL)
+e2undo: $(E2UNDO_OBJS) $(DEPLIBS)
+ @echo " LD $@"
+ @$(CC) $(ALL_LDFLAGS) -o e2undo $(E2UNDO_OBJS) $(LIBS)
+
base_device: base_device.c
@echo " LD $@"
@$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(srcdir)/base_device.c \
@echo " SUBST $@"
@$(SUBSTITUTE_UPTIME) $(srcdir)/e2label.8.in e2label.8
+e2undo.8: $(DEP_SUBSTITUTE) $(srcdir)/e2undo.8.in
+ @echo " SUBST $@"
+ @$(SUBSTITUTE_UPTIME) $(srcdir)/e2undo.8.in e2undo.8
+
findfs.8: $(DEP_SUBSTITUTE) $(srcdir)/findfs.8.in
@echo " SUBST $@"
@$(SUBSTITUTE_UPTIME) $(srcdir)/findfs.8.in findfs.8
ismounted.o: $(srcdir)/ismounted.c $(top_srcdir)/lib/et/com_err.h
profile.o: $(srcdir)/../e2fsck/profile.c $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/../e2fsck/profile.h prof_err.h
+e2undo.o: $(srcdir)/e2undo.c $(top_srcdir)/lib/ext2fs/tdb.h
--- /dev/null
+/*
+ * e2undo.c - Replay an undo log onto an ext2/3/4 filesystem
+ *
+ * Copyright IBM Corporation, 2007
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#include <fcntl.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include "ext2fs/tdb.h"
+#include "ext2fs/ext2fs.h"
+#include "nls-enable.h"
+
+unsigned char mtime_key[] = "filesystem MTIME";
+unsigned char uuid_key[] = "filesystem UUID";
+unsigned char blksize_key[] = "filesystem BLKSIZE";
+
+static void usage(char *prg_name)
+{
+ fprintf(stderr,
+ _("Usage: %s <transaction file> <filesystem>\n"), prg_name);
+ exit(1);
+
+}
+
+static int check_filesystem(TDB_CONTEXT *tdb, io_channel channel)
+{
+ __u32 s_mtime;
+ __u8 s_uuid[16];
+ errcode_t retval;
+ TDB_DATA tdb_key, tdb_data;
+ struct ext2_super_block super;
+
+ io_channel_set_blksize(channel, SUPERBLOCK_OFFSET);
+ retval = io_channel_read_blk(channel, 1, -SUPERBLOCK_SIZE, &super);
+ if (retval) {
+ com_err(__FUNCTION__,
+ retval, _("Failed to read the file system data \n"));
+ return retval;
+ }
+
+ tdb_key.dptr = mtime_key;
+ tdb_key.dsize = sizeof(mtime_key);
+ tdb_data = tdb_fetch(tdb, tdb_key);
+ if (!tdb_data.dptr) {
+ retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+ com_err(__FUNCTION__, retval,
+ _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+ return retval;
+ }
+
+ s_mtime = *(__u32 *)tdb_data.dptr;
+ if (super.s_mtime != s_mtime) {
+
+ com_err(__FUNCTION__, 0,
+ _("The file system Mount time didn't match %u\n"),
+ s_mtime);
+
+ return -1;
+ }
+
+
+ tdb_key.dptr = uuid_key;
+ tdb_key.dsize = sizeof(uuid_key);
+ tdb_data = tdb_fetch(tdb, tdb_key);
+ if (!tdb_data.dptr) {
+ retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+ com_err(__FUNCTION__, retval,
+ _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+ return retval;
+ }
+ memcpy(s_uuid, tdb_data.dptr, sizeof(s_uuid));
+ if (memcmp(s_uuid, super.s_uuid, sizeof(s_uuid))) {
+ com_err(__FUNCTION__, 0,
+ _("The file system UUID didn't match \n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int set_blk_size(TDB_CONTEXT *tdb, io_channel channel)
+{
+ int block_size;
+ errcode_t retval;
+ TDB_DATA tdb_key, tdb_data;
+
+ tdb_key.dptr = blksize_key;
+ tdb_key.dsize = sizeof(blksize_key);
+ tdb_data = tdb_fetch(tdb, tdb_key);
+ if (!tdb_data.dptr) {
+ retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
+ com_err(__FUNCTION__, retval,
+ _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+ return retval;
+ }
+
+ block_size = *(int *)tdb_data.dptr;
+#ifdef DEBUG
+ printf("Block size %d\n", block_size);
+#endif
+ io_channel_set_blksize(channel, block_size);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int c,force = 0;
+ TDB_CONTEXT *tdb;
+ TDB_DATA key, data;
+ io_channel channel;
+ errcode_t retval;
+ int mount_flags;
+ unsigned long blk_num;
+ char *device_name, *tdb_file, *prg_name;
+ io_manager manager = unix_io_manager;
+
+ prg_name = argv[0];
+ while((c = getopt(argc, argv, "f")) != EOF) {
+ switch (c) {
+ case 'f':
+ force = 1;
+ break;
+ default:
+ usage(prg_name);
+ }
+ }
+
+ if (argc != optind+2)
+ usage(prg_name);
+
+ tdb_file = argv[optind];
+ device_name = argv[optind+1];
+
+ tdb = tdb_open(tdb_file, 0, 0, O_RDONLY, 0600);
+
+ if (!tdb) {
+ com_err(prg_name, errno,
+ _("Failed tdb_open %s\n"), tdb_file);
+ exit(1);
+ }
+
+ retval = ext2fs_check_if_mounted(device_name, &mount_flags);
+ if (retval) {
+ com_err(prg_name, retval, _("Error while determining whether "
+ "%s is mounted.\n"), device_name);
+ exit(1);
+ }
+
+ if (mount_flags & EXT2_MF_MOUNTED) {
+ com_err(prg_name, retval, _("undoe2fs should only be run on "
+ "unmounted file system\n"));
+ exit(1);
+ }
+
+ retval = manager->open(device_name,
+ IO_FLAG_EXCLUSIVE | IO_FLAG_RW, &channel);
+ if (retval) {
+ com_err(prg_name, retval,
+ _("Failed to open %s\n"), device_name);
+ exit(1);
+ }
+
+ if (!force && check_filesystem(tdb, channel)) {
+ exit(1);
+ }
+
+ if (set_blk_size(tdb, channel)) {
+ exit(1);
+ }
+
+ for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key)) {
+ if (!strcmp((char *) key.dptr, (char *) mtime_key) ||
+ !strcmp((char *) key.dptr, (char *) uuid_key) ||
+ !strcmp((char *) key.dptr, (char *) blksize_key)) {
+ continue;
+ }
+
+ data = tdb_fetch(tdb, key);
+ if (!data.dptr) {
+ com_err(prg_name, 0,
+ _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
+ exit(1);
+ }
+ blk_num = *(unsigned long *)key.dptr;
+ printf(_("Replayed transaction of size %d at location %ld\n"),
+ data.dsize, blk_num);
+ retval = io_channel_write_blk(channel, blk_num,
+ -data.dsize, data.dptr);
+ if (retval == -1) {
+ com_err(prg_name, retval,
+ _("Failed write %s\n"),
+ strerror(errno));
+ exit(1);
+ }
+ }
+ io_channel_close(channel);
+ tdb_close(tdb);
+
+}