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