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