diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2007-08-13 15:56:22 +0530 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2008-04-27 19:42:05 -0400 |
commit | 5f8a5ae6b8f7c273d678cbdaf56ec35cdb1b3587 (patch) | |
tree | 8ea342a7898feff16ea5e37aaef40ecbe1fee496 | |
parent | 72a168b59cbabdcfb1fe9db30f3d63f6f9731324 (diff) | |
download | e2fsprogs-5f8a5ae6b8f7c273d678cbdaf56ec35cdb1b3587.tar.gz |
Add e2undo command
The e2undo command can be used to replay the transaction saved in the
transaction file using undo I/O Manager.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r-- | misc/Makefile.in | 17 | ||||
-rw-r--r-- | misc/e2undo.8.in | 44 | ||||
-rw-r--r-- | misc/e2undo.c | 213 |
3 files changed, 271 insertions, 3 deletions
diff --git a/misc/Makefile.in b/misc/Makefile.in index bf04e658..b31f5c3e 100644 --- a/misc/Makefile.in +++ b/misc/Makefile.in @@ -18,11 +18,11 @@ INSTALL = @INSTALL@ @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 @@ -43,6 +43,7 @@ E2IMAGE_OBJS= e2image.o 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. @@ -51,7 +52,8 @@ SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c \ $(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) @@ -112,6 +114,10 @@ e2image: $(E2IMAGE_OBJS) $(DEPLIBS) @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 \ @@ -197,6 +203,10 @@ e2label.8: $(DEP_SUBSTITUTE) $(srcdir)/e2label.8.in @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 @@ -451,3 +461,4 @@ base_device.o: $(srcdir)/base_device.c $(srcdir)/fsck.h 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 diff --git a/misc/e2undo.8.in b/misc/e2undo.8.in new file mode 100644 index 00000000..4bf07985 --- /dev/null +++ b/misc/e2undo.8.in @@ -0,0 +1,44 @@ +.\" -*- nroff -*- +.\" Copyright 2008 by Theodore Ts'o. All Rights Reserved. +.\" This file may be copied under the terms of the GNU Public License. +.\" +.TH E2UNDO 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@" +.SH NAME +e2undo \- Replay an undo log for an ext2/ext3/ext4 filesystem +.SH SYNOPSIS +.B e2undo +[ +.B \-f +] +.I undo_log device +.SH DESCRIPTION +.B e2undo +will replay the undo log +.I undo_log +for an ext2/ext3/ext4 filesystem found on +.IR device . +This can be +used to undo a failed operation by an e2fsprogs program. +.SH OPTIONS +.TP +.B \-f +Normally, +.B e2undo +will check the filesystem UUID and last modified time to make sure the +undo log matches with the filesystem on the device. If they do not +match, +.B e2undo +will refuse to apply the undo log as a safety mechanism. The +.B \-f +option disables this safety mechanism. +.SH AUTHOR +.B e2undo +was written by Aneesh Kumar K.V. (aneesh.kumar@linux.vnet.ibm.com) +.SH AVAILABILITY +.B e2undo +is part of the e2fsprogs package and is available from +http://e2fsprogs.sourceforge.net. +.SH SEE ALSO +.BR mke2fs (8), +.BR tune2fs (8) + diff --git a/misc/e2undo.c b/misc/e2undo.c new file mode 100644 index 00000000..ca24303f --- /dev/null +++ b/misc/e2undo.c @@ -0,0 +1,213 @@ +/* + * 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); + +} |