Whamcloud - gitweb
misc: clean up compiler warnings
[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 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,
51                         retval, _("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,
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 #endif
138         add_error_table(&et_ext2_error_table);
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();
148                 }
149         }
150
151         if (argc != optind + 2)
152                 usage();
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 %llu\n"),
209                                                         data.dsize, blk_num);
210                 retval = io_channel_write_blk64(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 }