Home | History | Annotate | Download | only in misc
      1 /*
      2  * e2undo.c - Replay an undo log onto an ext2/3/4 filesystem
      3  *
      4  * Copyright IBM Corporation, 2007
      5  * Author Aneesh Kumar K.V <aneesh.kumar (at) linux.vnet.ibm.com>
      6  *
      7  * %Begin-Header%
      8  * This file may be redistributed under the terms of the GNU Public
      9  * License.
     10  * %End-Header%
     11  */
     12 
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #ifdef HAVE_GETOPT_H
     16 #include <getopt.h>
     17 #endif
     18 #include <fcntl.h>
     19 #if HAVE_ERRNO_H
     20 #include <errno.h>
     21 #endif
     22 #include "ext2fs/tdb.h"
     23 #include "ext2fs/ext2fs.h"
     24 #include "nls-enable.h"
     25 
     26 static unsigned char mtime_key[] = "filesystem MTIME";
     27 static unsigned char uuid_key[] = "filesystem UUID";
     28 static unsigned char blksize_key[] = "filesystem BLKSIZE";
     29 
     30 static char *prg_name;
     31 
     32 static void usage(void)
     33 {
     34 	fprintf(stderr,
     35 		_("Usage: %s <transaction file> <filesystem>\n"), prg_name);
     36 	exit(1);
     37 }
     38 
     39 static int check_filesystem(TDB_CONTEXT *tdb, io_channel channel)
     40 {
     41 	__u32   s_mtime;
     42 	__u8    s_uuid[16];
     43 	errcode_t retval;
     44 	TDB_DATA tdb_key, tdb_data;
     45 	struct ext2_super_block super;
     46 
     47 	io_channel_set_blksize(channel, SUPERBLOCK_OFFSET);
     48 	retval = io_channel_read_blk64(channel, 1, -SUPERBLOCK_SIZE, &super);
     49 	if (retval) {
     50 		com_err(prg_name, retval,
     51 			"%s", _("Failed to read the file system data \n"));
     52 		return retval;
     53 	}
     54 
     55 	tdb_key.dptr = mtime_key;
     56 	tdb_key.dsize = sizeof(mtime_key);
     57 	tdb_data = tdb_fetch(tdb, tdb_key);
     58 	if (!tdb_data.dptr) {
     59 		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
     60 		com_err(prg_name, retval,
     61 			_("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
     62 		return retval;
     63 	}
     64 
     65 	s_mtime = *(__u32 *)tdb_data.dptr;
     66 	if (super.s_mtime != s_mtime) {
     67 
     68 		com_err(prg_name, 0,
     69 			_("The file system Mount time didn't match %u\n"),
     70 			s_mtime);
     71 
     72 		return  -1;
     73 	}
     74 
     75 
     76 	tdb_key.dptr = uuid_key;
     77 	tdb_key.dsize = sizeof(uuid_key);
     78 	tdb_data = tdb_fetch(tdb, tdb_key);
     79 	if (!tdb_data.dptr) {
     80 		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
     81 		com_err(prg_name, retval,
     82 			_("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
     83 		return retval;
     84 	}
     85 	memcpy(s_uuid, tdb_data.dptr, sizeof(s_uuid));
     86 	if (memcmp(s_uuid, super.s_uuid, sizeof(s_uuid))) {
     87 		com_err(prg_name, 0, "%s",
     88 			_("The file system UUID didn't match \n"));
     89 		return -1;
     90 	}
     91 
     92 	return 0;
     93 }
     94 
     95 static int set_blk_size(TDB_CONTEXT *tdb, io_channel channel)
     96 {
     97 	int block_size;
     98 	errcode_t retval;
     99 	TDB_DATA tdb_key, tdb_data;
    100 
    101 	tdb_key.dptr = blksize_key;
    102 	tdb_key.dsize = sizeof(blksize_key);
    103 	tdb_data = tdb_fetch(tdb, tdb_key);
    104 	if (!tdb_data.dptr) {
    105 		retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb);
    106 		com_err(prg_name, retval,
    107 			_("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
    108 		return retval;
    109 	}
    110 
    111 	block_size = *(int *)tdb_data.dptr;
    112 #ifdef DEBUG
    113 	printf("Block size %d\n", block_size);
    114 #endif
    115 	io_channel_set_blksize(channel, block_size);
    116 
    117 	return 0;
    118 }
    119 
    120 int main(int argc, char *argv[])
    121 {
    122 	int c,force = 0;
    123 	TDB_CONTEXT *tdb;
    124 	TDB_DATA key, data;
    125 	io_channel channel;
    126 	errcode_t retval;
    127 	int  mount_flags;
    128 	blk64_t  blk_num;
    129 	char *device_name, *tdb_file;
    130 	io_manager manager = unix_io_manager;
    131 
    132 #ifdef ENABLE_NLS
    133 	setlocale(LC_MESSAGES, "");
    134 	setlocale(LC_CTYPE, "");
    135 	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
    136 	textdomain(NLS_CAT_NAME);
    137 	set_com_err_gettext(gettext);
    138 #endif
    139 	add_error_table(&et_ext2_error_table);
    140 
    141 	prg_name = argv[0];
    142 	while((c = getopt(argc, argv, "f")) != EOF) {
    143 		switch (c) {
    144 			case 'f':
    145 				force = 1;
    146 				break;
    147 			default:
    148 				usage();
    149 		}
    150 	}
    151 
    152 	if (argc != optind + 2)
    153 		usage();
    154 
    155 	tdb_file = argv[optind];
    156 	device_name = argv[optind+1];
    157 
    158 	tdb = tdb_open(tdb_file, 0, 0, O_RDONLY, 0600);
    159 
    160 	if (!tdb) {
    161 		com_err(prg_name, errno,
    162 				_("Failed tdb_open %s\n"), tdb_file);
    163 		exit(1);
    164 	}
    165 
    166 	retval = ext2fs_check_if_mounted(device_name, &mount_flags);
    167 	if (retval) {
    168 		com_err(prg_name, retval, _("Error while determining whether "
    169 				"%s is mounted.\n"), device_name);
    170 		exit(1);
    171 	}
    172 
    173 	if (mount_flags & EXT2_MF_MOUNTED) {
    174 		com_err(prg_name, retval, "%s", _("e2undo should only be run "
    175 						"on unmounted file system\n"));
    176 		exit(1);
    177 	}
    178 
    179 	retval = manager->open(device_name,
    180 				IO_FLAG_EXCLUSIVE | IO_FLAG_RW,  &channel);
    181 	if (retval) {
    182 		com_err(prg_name, retval,
    183 				_("Failed to open %s\n"), device_name);
    184 		exit(1);
    185 	}
    186 
    187 	if (!force && check_filesystem(tdb, channel)) {
    188 		exit(1);
    189 	}
    190 
    191 	if (set_blk_size(tdb, channel)) {
    192 		exit(1);
    193 	}
    194 
    195 	for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key)) {
    196 		if (!strcmp((char *) key.dptr, (char *) mtime_key) ||
    197 		    !strcmp((char *) key.dptr, (char *) uuid_key) ||
    198 		    !strcmp((char *) key.dptr, (char *) blksize_key)) {
    199 			continue;
    200 		}
    201 
    202 		data = tdb_fetch(tdb, key);
    203 		if (!data.dptr) {
    204 			com_err(prg_name, 0,
    205 				_("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
    206 			exit(1);
    207 		}
    208 		blk_num = *(blk64_t *)key.dptr;
    209 		printf(_("Replayed transaction of size %zd at location %llu\n"),
    210 							data.dsize, blk_num);
    211 		retval = io_channel_write_blk64(channel, blk_num,
    212 						-data.dsize, data.dptr);
    213 		if (retval == -1) {
    214 			com_err(prg_name, retval,
    215 					_("Failed write %s\n"),
    216 					strerror(errno));
    217 			exit(1);
    218 		}
    219 	}
    220 	io_channel_close(channel);
    221 	tdb_close(tdb);
    222 
    223 	return 0;
    224 }
    225