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