• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
usage(void)32 static void usage(void)
33 {
34 	fprintf(stderr,
35 		_("Usage: %s <transaction file> <filesystem>\n"), prg_name);
36 	exit(1);
37 }
38 
check_filesystem(TDB_CONTEXT * tdb,io_channel channel)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 
set_blk_size(TDB_CONTEXT * tdb,io_channel channel)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 
main(int argc,char * argv[])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