]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - mdrestore/xfs_mdrestore.c
xfsprogs: simplify internal includes
[thirdparty/xfsprogs-dev.git] / mdrestore / xfs_mdrestore.c
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
19 #include "libxfs.h"
20 #include "xfs_metadump.h"
21
22 char *progname;
23 int show_progress = 0;
24 int progress_since_warning = 0;
25
26 static void
27 fatal(const char *msg, ...)
28 {
29 va_list args;
30
31 va_start(args, msg);
32 fprintf(stderr, "%s: ", progname);
33 vfprintf(stderr, msg, args);
34 exit(1);
35 }
36
37 static void
38 print_progress(const char *fmt, ...)
39 {
40 char buf[60];
41 va_list ap;
42
43 va_start(ap, fmt);
44 vsnprintf(buf, sizeof(buf), fmt, ap);
45 va_end(ap);
46 buf[sizeof(buf)-1] = '\0';
47
48 printf("\r%-59s", buf);
49 fflush(stdout);
50 progress_since_warning = 1;
51 }
52
53 static void
54 perform_restore(
55 FILE *src_f,
56 int dst_fd,
57 int is_target_file)
58 {
59 xfs_metablock_t *metablock; /* header + index + blocks */
60 __be64 *block_index;
61 char *block_buffer;
62 int block_size;
63 int max_indicies;
64 int cur_index;
65 int mb_count;
66 xfs_metablock_t tmb;
67 xfs_sb_t sb;
68 __int64_t bytes_read;
69
70 /*
71 * read in first blocks (superblock 0), set "inprogress" flag for it,
72 * read in the rest of the file, and if complete, clear SB 0's
73 * "inprogress flag"
74 */
75
76 if (fread(&tmb, sizeof(tmb), 1, src_f) != 1)
77 fatal("error reading from file: %s\n", strerror(errno));
78
79 if (be32_to_cpu(tmb.mb_magic) != XFS_MD_MAGIC)
80 fatal("specified file is not a metadata dump\n");
81
82 block_size = 1 << tmb.mb_blocklog;
83 max_indicies = (block_size - sizeof(xfs_metablock_t)) / sizeof(__be64);
84
85 metablock = (xfs_metablock_t *)calloc(max_indicies + 1, block_size);
86 if (metablock == NULL)
87 fatal("memory allocation failure\n");
88
89 mb_count = be16_to_cpu(tmb.mb_count);
90 if (mb_count == 0 || mb_count > max_indicies)
91 fatal("bad block count: %u\n", mb_count);
92
93 block_index = (__be64 *)((char *)metablock + sizeof(xfs_metablock_t));
94 block_buffer = (char *)metablock + block_size;
95
96 if (fread(block_index, block_size - sizeof(tmb), 1, src_f) != 1)
97 fatal("error reading from file: %s\n", strerror(errno));
98
99 if (block_index[0] != 0)
100 fatal("first block is not the primary superblock\n");
101
102
103 if (fread(block_buffer, mb_count << tmb.mb_blocklog,
104 1, src_f) != 1)
105 fatal("error reading from file: %s\n", strerror(errno));
106
107 libxfs_sb_from_disk(&sb, (xfs_dsb_t *)block_buffer);
108
109 if (sb.sb_magicnum != XFS_SB_MAGIC)
110 fatal("bad magic number for primary superblock\n");
111
112 ((xfs_dsb_t*)block_buffer)->sb_inprogress = 1;
113
114 if (is_target_file) {
115 /* ensure regular files are correctly sized */
116
117 if (ftruncate64(dst_fd, sb.sb_dblocks * sb.sb_blocksize))
118 fatal("cannot set filesystem image size: %s\n",
119 strerror(errno));
120 } else {
121 /* ensure device is sufficiently large enough */
122
123 char *lb[XFS_MAX_SECTORSIZE] = { NULL };
124 off64_t off;
125
126 off = sb.sb_dblocks * sb.sb_blocksize - sizeof(lb);
127 if (pwrite64(dst_fd, lb, sizeof(lb), off) < 0)
128 fatal("failed to write last block, is target too "
129 "small? (error: %s)\n", strerror(errno));
130 }
131
132 bytes_read = 0;
133
134 for (;;) {
135 if (show_progress && (bytes_read & ((1 << 20) - 1)) == 0)
136 print_progress("%lld MB read\n", bytes_read >> 20);
137
138 for (cur_index = 0; cur_index < mb_count; cur_index++) {
139 if (pwrite64(dst_fd, &block_buffer[cur_index <<
140 tmb.mb_blocklog], block_size,
141 be64_to_cpu(block_index[cur_index]) <<
142 BBSHIFT) < 0)
143 fatal("error writing block %llu: %s\n",
144 be64_to_cpu(block_index[cur_index]) << BBSHIFT,
145 strerror(errno));
146 }
147 if (mb_count < max_indicies)
148 break;
149
150 if (fread(metablock, block_size, 1, src_f) != 1)
151 fatal("error reading from file: %s\n", strerror(errno));
152
153 mb_count = be16_to_cpu(metablock->mb_count);
154 if (mb_count == 0)
155 break;
156 if (mb_count > max_indicies)
157 fatal("bad block count: %u\n", mb_count);
158
159 if (fread(block_buffer, mb_count << tmb.mb_blocklog,
160 1, src_f) != 1)
161 fatal("error reading from file: %s\n", strerror(errno));
162
163 bytes_read += block_size;
164 }
165
166 if (progress_since_warning)
167 putchar('\n');
168
169 memset(block_buffer, 0, sb.sb_sectsize);
170 sb.sb_inprogress = 0;
171 libxfs_sb_to_disk((xfs_dsb_t *)block_buffer, &sb);
172 if (xfs_sb_version_hascrc(&sb)) {
173 xfs_update_cksum(block_buffer, sb.sb_sectsize,
174 offsetof(struct xfs_sb, sb_crc));
175 }
176
177 if (pwrite(dst_fd, block_buffer, sb.sb_sectsize, 0) < 0)
178 fatal("error writing primary superblock: %s\n", strerror(errno));
179
180 free(metablock);
181 }
182
183 static void
184 usage(void)
185 {
186 fprintf(stderr, "Usage: %s [-V] [-g] source target\n", progname);
187 exit(1);
188 }
189
190 extern int platform_check_ismounted(char *, char *, struct stat64 *, int);
191
192 int
193 main(
194 int argc,
195 char **argv)
196 {
197 FILE *src_f;
198 int dst_fd;
199 int c;
200 int open_flags;
201 struct stat64 statbuf;
202 int is_target_file;
203
204 progname = basename(argv[0]);
205
206 while ((c = getopt(argc, argv, "gV")) != EOF) {
207 switch (c) {
208 case 'g':
209 show_progress = 1;
210 break;
211 case 'V':
212 printf("%s version %s\n", progname, VERSION);
213 exit(0);
214 default:
215 usage();
216 }
217 }
218
219 if (argc - optind != 2)
220 usage();
221
222 /* open source */
223 if (strcmp(argv[optind], "-") == 0) {
224 src_f = stdin;
225 if (isatty(fileno(stdin)))
226 fatal("cannot read from a terminal\n");
227 } else {
228 src_f = fopen(argv[optind], "rb");
229 if (src_f == NULL)
230 fatal("cannot open source dump file\n");
231 }
232 optind++;
233
234 /* check and open target */
235 open_flags = O_RDWR;
236 is_target_file = 0;
237 if (stat64(argv[optind], &statbuf) < 0) {
238 /* ok, assume it's a file and create it */
239 open_flags |= O_CREAT;
240 is_target_file = 1;
241 } else if (S_ISREG(statbuf.st_mode)) {
242 open_flags |= O_TRUNC;
243 is_target_file = 1;
244 } else {
245 /*
246 * check to make sure a filesystem isn't mounted on the device
247 */
248 if (platform_check_ismounted(argv[optind], NULL, &statbuf, 0))
249 fatal("a filesystem is mounted on target device \"%s\","
250 " cannot restore to a mounted filesystem.\n",
251 argv[optind]);
252 }
253
254 dst_fd = open(argv[optind], open_flags, 0644);
255 if (dst_fd < 0)
256 fatal("couldn't open target \"%s\"\n", argv[optind]);
257
258 perform_restore(src_f, dst_fd, is_target_file);
259
260 close(dst_fd);
261 if (src_f != stdin)
262 fclose(src_f);
263
264 return 0;
265 }