blob: a43c26fd074e13c691dd426ccff862b2dc6948c9 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
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
27static unsigned char mtime_key[] = "filesystem MTIME";
28static unsigned char uuid_key[] = "filesystem UUID";
29static unsigned char blksize_key[] = "filesystem BLKSIZE";
30
31static char *prg_name;
32
33static void usage(void)
34{
35 fprintf(stderr,
36 _("Usage: %s <transaction file> <filesystem>\n"), prg_name);
37 exit(1);
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_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
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 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}