]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - mdrestore/xfs_mdrestore.c
xfs_metadump: properly handle obfuscation of all remote attribute blocks
[thirdparty/xfsprogs-dev.git] / mdrestore / xfs_mdrestore.c
CommitLineData
61983f67
BN
1/*
2 * Copyright (c) 2007 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
6b803e5a 19#include "libxfs.h"
61983f67
BN
20#include "xfs_metadump.h"
21
22char *progname;
23int show_progress = 0;
2291c68b 24int show_info = 0;
61983f67
BN
25int progress_since_warning = 0;
26
27static void
28fatal(const char *msg, ...)
29{
30 va_list args;
31
32 va_start(args, msg);
33 fprintf(stderr, "%s: ", progname);
34 vfprintf(stderr, msg, args);
35 exit(1);
36}
37
38static void
39print_progress(const char *fmt, ...)
40{
41 char buf[60];
42 va_list ap;
43
44 va_start(ap, fmt);
45 vsnprintf(buf, sizeof(buf), fmt, ap);
46 va_end(ap);
47 buf[sizeof(buf)-1] = '\0';
48
49 printf("\r%-59s", buf);
50 fflush(stdout);
51 progress_since_warning = 1;
52}
53
54static void
55perform_restore(
56 FILE *src_f,
57 int dst_fd,
58 int is_target_file)
59{
60 xfs_metablock_t *metablock; /* header + index + blocks */
61 __be64 *block_index;
62 char *block_buffer;
63 int block_size;
d7006beb 64 int max_indices;
61983f67 65 int cur_index;
5e656dbb 66 int mb_count;
61983f67
BN
67 xfs_metablock_t tmb;
68 xfs_sb_t sb;
69 __int64_t bytes_read;
70
71 /*
72 * read in first blocks (superblock 0), set "inprogress" flag for it,
73 * read in the rest of the file, and if complete, clear SB 0's
74 * "inprogress flag"
75 */
76
77 if (fread(&tmb, sizeof(tmb), 1, src_f) != 1)
78 fatal("error reading from file: %s\n", strerror(errno));
79
80 if (be32_to_cpu(tmb.mb_magic) != XFS_MD_MAGIC)
81 fatal("specified file is not a metadata dump\n");
82
83 block_size = 1 << tmb.mb_blocklog;
d7006beb 84 max_indices = (block_size - sizeof(xfs_metablock_t)) / sizeof(__be64);
61983f67 85
d7006beb 86 metablock = (xfs_metablock_t *)calloc(max_indices + 1, block_size);
61983f67
BN
87 if (metablock == NULL)
88 fatal("memory allocation failure\n");
89
5e656dbb 90 mb_count = be16_to_cpu(tmb.mb_count);
d7006beb 91 if (mb_count == 0 || mb_count > max_indices)
5e656dbb 92 fatal("bad block count: %u\n", mb_count);
61983f67
BN
93
94 block_index = (__be64 *)((char *)metablock + sizeof(xfs_metablock_t));
95 block_buffer = (char *)metablock + block_size;
96
97 if (fread(block_index, block_size - sizeof(tmb), 1, src_f) != 1)
98 fatal("error reading from file: %s\n", strerror(errno));
99
100 if (block_index[0] != 0)
101 fatal("first block is not the primary superblock\n");
102
103
5e656dbb 104 if (fread(block_buffer, mb_count << tmb.mb_blocklog,
61983f67
BN
105 1, src_f) != 1)
106 fatal("error reading from file: %s\n", strerror(errno));
107
5e656dbb 108 libxfs_sb_from_disk(&sb, (xfs_dsb_t *)block_buffer);
61983f67
BN
109
110 if (sb.sb_magicnum != XFS_SB_MAGIC)
111 fatal("bad magic number for primary superblock\n");
112
d7006beb
ES
113 /*
114 * Normally the upper bound would be simply XFS_MAX_SECTORSIZE
115 * but the metadump format has a maximum number of BBSIZE blocks
116 * it can store in a single metablock.
117 */
118 if (sb.sb_sectsize < XFS_MIN_SECTORSIZE ||
119 sb.sb_sectsize > XFS_MAX_SECTORSIZE ||
120 sb.sb_sectsize > max_indices * block_size)
121 fatal("bad sector size %u in metadump image\n", sb.sb_sectsize);
122
5e656dbb 123 ((xfs_dsb_t*)block_buffer)->sb_inprogress = 1;
61983f67
BN
124
125 if (is_target_file) {
126 /* ensure regular files are correctly sized */
127
dde67673 128 if (ftruncate(dst_fd, sb.sb_dblocks * sb.sb_blocksize))
61983f67
BN
129 fatal("cannot set filesystem image size: %s\n",
130 strerror(errno));
131 } else {
132 /* ensure device is sufficiently large enough */
133
5e656dbb 134 char *lb[XFS_MAX_SECTORSIZE] = { NULL };
61983f67
BN
135 off64_t off;
136
137 off = sb.sb_dblocks * sb.sb_blocksize - sizeof(lb);
2f9a125c 138 if (pwrite(dst_fd, lb, sizeof(lb), off) < 0)
61983f67
BN
139 fatal("failed to write last block, is target too "
140 "small? (error: %s)\n", strerror(errno));
141 }
142
143 bytes_read = 0;
144
145 for (;;) {
146 if (show_progress && (bytes_read & ((1 << 20) - 1)) == 0)
c1c3d921 147 print_progress("%lld MB read", bytes_read >> 20);
61983f67 148
5e656dbb 149 for (cur_index = 0; cur_index < mb_count; cur_index++) {
2f9a125c 150 if (pwrite(dst_fd, &block_buffer[cur_index <<
5e656dbb 151 tmb.mb_blocklog], block_size,
61983f67
BN
152 be64_to_cpu(block_index[cur_index]) <<
153 BBSHIFT) < 0)
154 fatal("error writing block %llu: %s\n",
155 be64_to_cpu(block_index[cur_index]) << BBSHIFT,
156 strerror(errno));
157 }
d7006beb 158 if (mb_count < max_indices)
61983f67
BN
159 break;
160
161 if (fread(metablock, block_size, 1, src_f) != 1)
162 fatal("error reading from file: %s\n", strerror(errno));
163
5e656dbb
BN
164 mb_count = be16_to_cpu(metablock->mb_count);
165 if (mb_count == 0)
61983f67 166 break;
d7006beb 167 if (mb_count > max_indices)
5e656dbb 168 fatal("bad block count: %u\n", mb_count);
61983f67 169
f8149110 170 if (fread(block_buffer, mb_count << tmb.mb_blocklog,
5e656dbb 171 1, src_f) != 1)
61983f67
BN
172 fatal("error reading from file: %s\n", strerror(errno));
173
c1c3d921 174 bytes_read += block_size + (mb_count << tmb.mb_blocklog);
61983f67
BN
175 }
176
177 if (progress_since_warning)
178 putchar('\n');
179
180 memset(block_buffer, 0, sb.sb_sectsize);
181 sb.sb_inprogress = 0;
19ebedcf 182 libxfs_sb_to_disk((xfs_dsb_t *)block_buffer, &sb);
f3ece211
DC
183 if (xfs_sb_version_hascrc(&sb)) {
184 xfs_update_cksum(block_buffer, sb.sb_sectsize,
185 offsetof(struct xfs_sb, sb_crc));
186 }
187
61983f67
BN
188 if (pwrite(dst_fd, block_buffer, sb.sb_sectsize, 0) < 0)
189 fatal("error writing primary superblock: %s\n", strerror(errno));
190
191 free(metablock);
192}
193
194static void
195usage(void)
196{
30626ef6 197 fprintf(stderr, "Usage: %s [-V] [-g] source target\n", progname);
61983f67
BN
198 exit(1);
199}
200
f594a0d1 201extern int platform_check_ismounted(char *, char *, struct stat *, int);
61983f67
BN
202
203int
204main(
205 int argc,
206 char **argv)
207{
208 FILE *src_f;
209 int dst_fd;
210 int c;
211 int open_flags;
f594a0d1 212 struct stat statbuf;
61983f67
BN
213 int is_target_file;
214
215 progname = basename(argv[0]);
216
2291c68b 217 while ((c = getopt(argc, argv, "giV")) != EOF) {
61983f67
BN
218 switch (c) {
219 case 'g':
220 show_progress = 1;
221 break;
2291c68b
ES
222 case 'i':
223 show_info = 1;
224 break;
61983f67
BN
225 case 'V':
226 printf("%s version %s\n", progname, VERSION);
227 exit(0);
228 default:
229 usage();
230 }
231 }
232
2291c68b
ES
233 if (argc - optind < 1 || argc - optind > 2)
234 usage();
235
236 /* show_info without a target is ok */
237 if (!show_info && argc - optind != 2)
61983f67
BN
238 usage();
239
240 /* open source */
241 if (strcmp(argv[optind], "-") == 0) {
242 src_f = stdin;
243 if (isatty(fileno(stdin)))
244 fatal("cannot read from a terminal\n");
245 } else {
246 src_f = fopen(argv[optind], "rb");
247 if (src_f == NULL)
248 fatal("cannot open source dump file\n");
249 }
2291c68b
ES
250
251 if (show_info) {
252 xfs_metablock_t mb;
253
254 if (fread(&mb, sizeof(mb), 1, src_f) != 1)
255 fatal("error reading from file: %s\n", strerror(errno));
256
257 if (be32_to_cpu(mb.mb_magic) != XFS_MD_MAGIC)
258 fatal("specified file is not a metadata dump\n");
259
260 if (mb.mb_info & XFS_METADUMP_INFO_FLAGS) {
261 printf("%s: %sobfuscated, %s log, %s metadata blocks\n",
262 argv[optind],
263 mb.mb_info & XFS_METADUMP_OBFUSCATED ? "":"not ",
264 mb.mb_info & XFS_METADUMP_DIRTYLOG ? "dirty":"clean",
265 mb.mb_info & XFS_METADUMP_FULLBLOCKS ? "full":"zeroed");
266 } else {
267 printf("%s: no informational flags present\n",
268 argv[optind]);
269 }
270
271 if (argc - optind == 1)
272 exit(0);
273
274 /* Go back to the beginning for the restore function */
275 fseek(src_f, 0L, SEEK_SET);
276 }
277
61983f67
BN
278 optind++;
279
280 /* check and open target */
281 open_flags = O_RDWR;
282 is_target_file = 0;
f594a0d1 283 if (stat(argv[optind], &statbuf) < 0) {
61983f67
BN
284 /* ok, assume it's a file and create it */
285 open_flags |= O_CREAT;
286 is_target_file = 1;
287 } else if (S_ISREG(statbuf.st_mode)) {
288 open_flags |= O_TRUNC;
289 is_target_file = 1;
290 } else {
291 /*
292 * check to make sure a filesystem isn't mounted on the device
293 */
294 if (platform_check_ismounted(argv[optind], NULL, &statbuf, 0))
295 fatal("a filesystem is mounted on target device \"%s\","
296 " cannot restore to a mounted filesystem.\n",
297 argv[optind]);
298 }
299
300 dst_fd = open(argv[optind], open_flags, 0644);
301 if (dst_fd < 0)
302 fatal("couldn't open target \"%s\"\n", argv[optind]);
303
304 perform_restore(src_f, dst_fd, is_target_file);
305
306 close(dst_fd);
307 if (src_f != stdin)
308 fclose(src_f);
309
310 return 0;
311}