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