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