Whamcloud - gitweb
build: quiet LLVM non-literal string format warning
[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 "config.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #ifdef HAVE_GETOPT_H
17 #include <getopt.h>
18 #endif
19 #include <fcntl.h>
20 #if HAVE_ERRNO_H
21 #include <errno.h>
22 #endif
23 #include "ext2fs/tdb.h"
24 #include "ext2fs/ext2fs.h"
25 #include "nls-enable.h"
26
27 unsigned char mtime_key[] = "filesystem MTIME";
28 unsigned char uuid_key[] = "filesystem UUID";
29 unsigned char blksize_key[] = "filesystem BLKSIZE";
30
31 char *prg_name;
32
33 static void usage(void)
34 {
35         fprintf(stderr,
36                 _("Usage: %s <transaction file> <filesystem>\n"), prg_name);
37         exit(1);
38 }
39
40 static 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_blk64(channel, 1, -SUPERBLOCK_SIZE, &super);
50         if (retval) {
51                 com_err(prg_name, retval,
52                         "%s", _("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, "%s",
89                         _("The file system UUID didn't match \n"));
90                 return -1;
91         }
92
93         return 0;
94 }
95
96 static 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
121 int 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         blk64_t  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         set_com_err_gettext(gettext);
139 #endif
140         add_error_table(&et_ext2_error_table);
141
142         prg_name = argv[0];
143         while((c = getopt(argc, argv, "f")) != EOF) {
144                 switch (c) {
145                         case 'f':
146                                 force = 1;
147                                 break;
148                         default:
149                                 usage();
150                 }
151         }
152
153         if (argc != optind + 2)
154                 usage();
155
156         tdb_file = argv[optind];
157         device_name = argv[optind+1];
158
159         tdb = tdb_open(tdb_file, 0, 0, O_RDONLY, 0600);
160
161         if (!tdb) {
162                 com_err(prg_name, errno,
163                                 _("Failed tdb_open %s\n"), tdb_file);
164                 exit(1);
165         }
166
167         retval = ext2fs_check_if_mounted(device_name, &mount_flags);
168         if (retval) {
169                 com_err(prg_name, retval, _("Error while determining whether "
170                                 "%s is mounted.\n"), device_name);
171                 exit(1);
172         }
173
174         if (mount_flags & EXT2_MF_MOUNTED) {
175                 com_err(prg_name, retval, "%s", _("e2undo should only be run "
176                                                 "on unmounted file system\n"));
177                 exit(1);
178         }
179
180         retval = manager->open(device_name,
181                                 IO_FLAG_EXCLUSIVE | IO_FLAG_RW,  &channel);
182         if (retval) {
183                 com_err(prg_name, retval,
184                                 _("Failed to open %s\n"), device_name);
185                 exit(1);
186         }
187
188         if (!force && check_filesystem(tdb, channel)) {
189                 exit(1);
190         }
191
192         if (set_blk_size(tdb, channel)) {
193                 exit(1);
194         }
195
196         for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key)) {
197                 if (!strcmp((char *) key.dptr, (char *) mtime_key) ||
198                     !strcmp((char *) key.dptr, (char *) uuid_key) ||
199                     !strcmp((char *) key.dptr, (char *) blksize_key)) {
200                         continue;
201                 }
202
203                 data = tdb_fetch(tdb, key);
204                 if (!data.dptr) {
205                         com_err(prg_name, 0,
206                                 _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb));
207                         exit(1);
208                 }
209                 blk_num = *(blk64_t *)key.dptr;
210                 printf(_("Replayed transaction of size %zd at location %llu\n"),
211                                                         data.dsize, blk_num);
212                 retval = io_channel_write_blk64(channel, blk_num,
213                                                 -data.dsize, data.dptr);
214                 if (retval == -1) {
215                         com_err(prg_name, retval,
216                                         _("Failed write %s\n"),
217                                         strerror(errno));
218                         exit(1);
219                 }
220         }
221         io_channel_close(channel);
222         tdb_close(tdb);
223
224         return 0;
225 }