From b3782b2e5bd0531a3113a2eb4233c874807e8c7c Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Fri, 16 Sep 2016 11:13:36 +0300 Subject: [PATCH] Add e2patch utility --- .gitignore | 2 + e2fsprogs.spec.in | 2 + misc/Makefile.in | 32 +++++++-- misc/e2patch.8.in | 31 +++++++++ misc/e2patch.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++ po/POTFILES.in | 1 + 6 files changed, 229 insertions(+), 5 deletions(-) create mode 100644 misc/e2patch.8.in create mode 100644 misc/e2patch.c diff --git a/.gitignore b/.gitignore index baf9b1a2..2e74c27f 100644 --- a/.gitignore +++ b/.gitignore @@ -161,6 +161,8 @@ misc/e2initrd_helper misc/e2label.8 misc/e2undo misc/e2undo.8 +misc/e2patch +misc/e2patch.8 misc/e4defrag misc/e4defrag.8 misc/ext4.5 diff --git a/e2fsprogs.spec.in b/e2fsprogs.spec.in index b188b751..dac0a1b9 100644 --- a/e2fsprogs.spec.in +++ b/e2fsprogs.spec.in @@ -117,6 +117,7 @@ exit 0 %{_root_sbindir}/e2image %{_root_sbindir}/e2label %{_root_sbindir}/e2undo +%{_root_sbindir}/e2patch %{_root_sbindir}/findfs %{_root_sbindir}/fsck %{_root_sbindir}/fsck.ext2 @@ -168,6 +169,7 @@ exit 0 %{_mandir}/man8/e2image.8* %{_mandir}/man8/e2label.8* %{_mandir}/man8/e2undo.8* +%{_mandir}/man8/e2patch.8* %{_mandir}/man8/fsck.8* %{_mandir}/man8/logsave.8* %{_mandir}/man8/mke2fs.8* diff --git a/misc/Makefile.in b/misc/Makefile.in index d6436c2a..8b2562f8 100644 --- a/misc/Makefile.in +++ b/misc/Makefile.in @@ -33,12 +33,12 @@ INSTALL = @INSTALL@ @FUSE_CMT@FUSE_PROG= fuse2fs SPROGS= mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \ - $(E2IMAGE_PROG) @FSCK_PROG@ e2undo + $(E2IMAGE_PROG) @FSCK_PROG@ e2undo e2patch USPROGS= mklost+found filefrag e2freefrag $(UUIDD_PROG) \ $(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG) SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \ e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \ - logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \ + logsave.8 filefrag.8 e2freefrag.8 e2undo.8 e2patch.8 \ $(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@ FMANPAGES= mke2fs.conf.5 ext4.5 @@ -63,6 +63,7 @@ FSCK_OBJS= fsck.o base_device.o ismounted.o BLKID_OBJS= blkid.o FILEFRAG_OBJS= filefrag.o E2UNDO_OBJS= e2undo.o +E2PATCH_OBJS= e2patch.o E4DEFRAG_OBJS= e4defrag.o E4CRYPT_OBJS= e4crypt.o E2FREEFRAG_OBJS= e2freefrag.o @@ -88,6 +89,7 @@ PROFILED_BLKID_OBJS= profiled/blkid.o PROFILED_FILEFRAG_OBJS= profiled/filefrag.o PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o PROFILED_E2UNDO_OBJS= profiled/e2undo.o +PROFILED_E2PATCH_OBJS= profiled/e2patch.o PROFILED_E4DEFRAG_OBJS= profiled/e4defrag.o PROFILED_E4CRYPT_OBJS= profiled/e4crypt.o PROFILED_FUSE2FS_OJBS= profiled/fuse2fs.o profiled/journal.o \ @@ -98,7 +100,7 @@ SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/ $(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)/e2undo.c \ + $(srcdir)/ismounted.c $(srcdir)/e2undo.c $(srcdir)/e2patch.c \ $(srcdir)/e2freefrag.c $(srcdir)/create_inode.c \ $(srcdir)/fuse2fs.c \ $(srcdir)/../debugfs/journal.c $(srcdir)/../e2fsck/revoke.c \ @@ -133,7 +135,7 @@ all:: profiled $(SPROGS) $(UPROGS) $(USPROGS) $(SMANPAGES) $(UMANPAGES) \ $(FMANPAGES) $(LPROGS) $(E4DEFRAG_PROG) $(E4CRYPT_PROGS) e2fuzz @PROFILE_CMT@all:: tune2fs.profiled blkid.profiled e2image.profiled \ - e2undo.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \ + e2undo.profiled e2patch.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \ logsave.profiled filefrag.profiled uuidgen.profiled $(UUIDD_PROFILED) \ e2image.profiled e4defrag.profiled e4crypt.profiled \ e2freefrag.profiled @@ -226,6 +228,16 @@ e2undo.profiled: $(E2UNDO_OBJS) $(PROFILED_DEPLIBS) $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2undo.profiled \ $(PROFILED_E2UNDO_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS) +e2patch: $(E2PATCH_OBJS) $(DEPLIBS) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -o e2patch $(E2PATCH_OBJS) $(LIBS) \ + $(LIBINTL) $(SYSLIBS) + +e2patch.profiled: $(E2PATCH_OBJS) $(PROFILED_DEPLIBS) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2patch.profiled \ + $(PROFILED_E2PATCH_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS) + e4defrag: $(E4DEFRAG_OBJS) $(DEPLIBS) $(E) " LD $@" $(Q) $(CC) $(ALL_LDFLAGS) -o e4defrag $(E4DEFRAG_OBJS) $(LIBS) \ @@ -439,6 +451,10 @@ e2undo.8: $(DEP_SUBSTITUTE) $(srcdir)/e2undo.8.in $(E) " SUBST $@" $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2undo.8.in e2undo.8 +e2patch.8: $(DEP_SUBSTITUTE) $(srcdir)/e2patch.8.in + $(E) " SUBST $@" + $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2patch.8.in e2patch.8 + findfs.8: $(DEP_SUBSTITUTE) $(srcdir)/findfs.8.in $(E) " SUBST $@" $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/findfs.8.in findfs.8 @@ -669,7 +685,7 @@ clean:: e2initrd_helper partinfo prof_err.[ch] default_profile.c \ uuidd e2image tune2fs.static tst_ismounted fsck.profiled \ blkid.profiled tune2fs.profiled e2image.profiled \ - e2undo.profiled mke2fs.profiled dumpe2fs.profiled \ + e2undo.profiled e2patch.profiled mke2fs.profiled dumpe2fs.profiled \ logsave.profiled filefrag.profiled uuidgen.profiled \ uuidd.profiled e2image.profiled e2fuzz mke2fs.conf \ profiled/*.o \#* *.s *.o *.a *~ core gmon.out @@ -792,6 +808,12 @@ e2undo.o: $(srcdir)/e2undo.c $(top_builddir)/lib/config.h \ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \ $(top_srcdir)/lib/support/nls-enable.h +e2patch.o: $(srcdir)/e2patch.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \ + $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ + $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \ + $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ + $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h e2freefrag.o: $(srcdir)/e2freefrag.c $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \ diff --git a/misc/e2patch.8.in b/misc/e2patch.8.in new file mode 100644 index 00000000..bc73475d --- /dev/null +++ b/misc/e2patch.8.in @@ -0,0 +1,31 @@ +.TH E2PATCH 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@" +.SH NAME +e2patch \- patch tool for safely applying libext2fs patch files to block devices +.SH SYNOPSIS +.B e2patch backup \fI\fR \fI\fR \fI\fR +.br +.B e2patch apply \fI\fR \fI\fR +.SH DESCRIPTION +.B e2patch +applies and restores "patches" produced by e2fsprogs with patch file option +(\fBresize2fs -T \fR) to block devices. +.PP +"Patch files" are sparse files containing overwritten device blocks and +a block bitmap. +.PP +"Patch files" are faster, safer and simpler to use than "undo files" +(\fBe2undo\fR and \fBresize2fs -z \fR), even though their original +design goal is similar. +.SH COMMANDS +.TP +.B e2patch backup \fI\fR \fI\fR \fI\fR +Creates a backup in for restoring after bad patch . +Backup can then also be applied with \fBe2patch apply\fR +.TP +.B e2patch apply \fI\fR \fI\fR +Apply to . +.SH AUTHOR +Written by Vitaliy Filippov +.SH SEE ALSO +.BR resize2fs (8), +.BR e2undo (8). diff --git a/misc/e2patch.c b/misc/e2patch.c new file mode 100644 index 00000000..18b1777b --- /dev/null +++ b/misc/e2patch.c @@ -0,0 +1,166 @@ +/** + * e2patch.c --- Utility to apply/restore patches created by patch_io_manager. + * + * Copyright (c) Vitaliy Filippov 2014 + * License: GNU GPLv2 or later + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ext2fs/ext2_fs.h" +#include "ext2fs/ext2fs.h" + +#include "ext2fs/patch.h" + +#define BUF 0x10000 +#define _(a) (a) + +errcode_t make_backup_patch(char *device, char *io_options, char *patch_file, char *backup_file) +{ + io_manager mgr = unix_io_manager; + io_channel io; + errcode_t retval; + blk64_t blk, start, buf_blocks; + int eq; + void *buf = NULL; + struct ext2fs_patch_file patch = { 0 }, backup = { 0 }; + retval = mgr->open(device, IO_FLAG_EXCLUSIVE, &io); + if (retval) goto out; + if (io_options && + (retval = io_channel_set_options(io, io_options))) + goto out; + retval = ext2fs_patch_open(&patch, patch_file, 0); + if (retval) goto out; + retval = ext2fs_patch_open(&backup, backup_file, O_CREAT); + if (retval) goto out; + backup.block_size = patch.block_size; + backup.size = patch.size; + ext2fs_patch_init_bmap(&backup, NULL); + buf_blocks = BUF/patch.block_size; + retval = mgr->set_blksize(io, patch.block_size); + if (retval) goto out; + buf = malloc(BUF); + for (start = 0, blk = 0; blk <= patch.size; blk++) + { + if ((eq = !ext2fs_test_generic_bitmap(patch.bmap, blk)) || blk >= patch.size || blk-start >= buf_blocks) + { + if (start != blk) + { + retval = io_channel_read_blk64(io, start, blk-start, buf); + if (retval) goto out; + retval = ext2fs_patch_write_blk64(&backup, start, blk-start, buf); + if (retval) goto out; + } + start = blk+eq; + } + } +out: + if (buf) + free(buf); + ext2fs_patch_close(&backup); + ext2fs_patch_close(&patch); + mgr->close(io); + return retval; +} + +errcode_t apply_patch(char *device, char *io_options, char *patch_file) +{ + io_manager mgr = unix_io_manager; + io_channel io; + errcode_t retval; + blk64_t blk, start, buf_blocks; + int eq; + void *buf = NULL; + struct ext2fs_patch_file patch = { 0 }; + retval = mgr->open(device, IO_FLAG_EXCLUSIVE|IO_FLAG_RW, &io); + if (retval) goto out; + if (io_options && + (retval = io_channel_set_options(io, io_options))) + goto out; + retval = ext2fs_patch_open(&patch, patch_file, 0); + if (retval) goto out; + buf_blocks = BUF/patch.block_size; + retval = mgr->set_blksize(io, patch.block_size); + if (retval) goto out; + buf = malloc(BUF); + for (start = 0, blk = 0; blk <= patch.size; blk++) + { + if ((eq = blk < patch.size && !ext2fs_test_generic_bitmap(patch.bmap, blk)) || blk >= patch.size || blk-start >= buf_blocks) + { + if (start != blk) + { + retval = ext2fs_patch_retry_read_at(patch.patch_fd, patch.offset + start*patch.block_size, (blk-start)*patch.block_size, buf); + if (retval) goto out; + retval = io_channel_write_blk64(io, start, blk-start, buf); + if (retval) goto out; + } + start = blk+eq; + } + } +out: + if (buf) + free(buf); + ext2fs_patch_close(&patch); + mgr->close(io); + return retval; +} + +int main(int narg, char **args) +{ + errcode_t retval; + char *io_options = NULL; + if (narg >= 5 && !strcmp(args[1], "backup")) + { + io_options = strchr(args[2], '?'); + if (io_options) + *io_options++ = 0; + retval = make_backup_patch(args[2], io_options, args[3], args[4]); + } + else if (narg >= 4 && !strcmp(args[1], "apply")) + { + io_options = strchr(args[2], '?'); + if (io_options) + *io_options++ = 0; + retval = apply_patch(args[2], io_options, args[3]); + } + else + { + printf( + "Patch tool for safely applying changes to block devices\n" + "License: GNU GPLv2 or later\n" + "Copyright (c) Vitaliy Filippov, 2014\n\n" + "To create a backup for restoring after bad patch:\n" + " e2patch backup \n" + "To apply a patch:\n" + " e2patch apply \n" + ); + return 0; + } + if (retval) + { + com_err("e2patch", retval, _("while trying to %s"), args[1]); + } + return 0; +} diff --git a/po/POTFILES.in b/po/POTFILES.in index d6b4f433..8665e8e2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -43,6 +43,7 @@ misc/e2image.c misc/e2initrd_helper.c misc/e2label.c misc/e2undo.c +misc/e2patch.c misc/e4crypt.c misc/e4defrag.c misc/filefrag.c