]> git.proxmox.com Git - mirror_zfs-debian.git/blob - cmd/zstreamdump/zstreamdump.c
Imported Upstream version 0.6.4.2
[mirror_zfs-debian.git] / cmd / zstreamdump / zstreamdump.c
1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Portions Copyright 2012 Martin Matuska <martin@matuska.org>
27 */
28
29 #include <libnvpair.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <strings.h>
33 #include <unistd.h>
34
35 #include <sys/dmu.h>
36 #include <sys/zfs_ioctl.h>
37 #include <zfs_fletcher.h>
38
39 uint64_t total_write_size = 0;
40 uint64_t total_stream_len = 0;
41 FILE *send_stream = 0;
42 boolean_t do_byteswap = B_FALSE;
43 boolean_t do_cksum = B_TRUE;
44 #define INITIAL_BUFLEN (1<<20)
45
46 static void
47 usage(void)
48 {
49 (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] < file\n");
50 (void) fprintf(stderr, "\t -v -- verbose\n");
51 (void) fprintf(stderr, "\t -C -- suppress checksum verification\n");
52 exit(1);
53 }
54
55 /*
56 * ssread - send stream read.
57 *
58 * Read while computing incremental checksum
59 */
60
61 static size_t
62 ssread(void *buf, size_t len, zio_cksum_t *cksum)
63 {
64 size_t outlen;
65
66 if ((outlen = fread(buf, len, 1, send_stream)) == 0)
67 return (0);
68
69 if (do_cksum && cksum) {
70 if (do_byteswap)
71 fletcher_4_incremental_byteswap(buf, len, cksum);
72 else
73 fletcher_4_incremental_native(buf, len, cksum);
74 }
75 total_stream_len += len;
76 return (outlen);
77 }
78
79 int
80 main(int argc, char *argv[])
81 {
82 char *buf = malloc(INITIAL_BUFLEN);
83 uint64_t drr_record_count[DRR_NUMTYPES] = { 0 };
84 uint64_t total_records = 0;
85 dmu_replay_record_t thedrr;
86 dmu_replay_record_t *drr = &thedrr;
87 struct drr_begin *drrb = &thedrr.drr_u.drr_begin;
88 struct drr_end *drre = &thedrr.drr_u.drr_end;
89 struct drr_object *drro = &thedrr.drr_u.drr_object;
90 struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects;
91 struct drr_write *drrw = &thedrr.drr_u.drr_write;
92 struct drr_write_byref *drrwbr = &thedrr.drr_u.drr_write_byref;
93 struct drr_free *drrf = &thedrr.drr_u.drr_free;
94 struct drr_spill *drrs = &thedrr.drr_u.drr_spill;
95 struct drr_write_embedded *drrwe = &thedrr.drr_u.drr_write_embedded;
96 char c;
97 boolean_t verbose = B_FALSE;
98 boolean_t first = B_TRUE;
99 int err;
100 zio_cksum_t zc = { { 0 } };
101 zio_cksum_t pcksum = { { 0 } };
102
103 while ((c = getopt(argc, argv, ":vC")) != -1) {
104 switch (c) {
105 case 'C':
106 do_cksum = B_FALSE;
107 break;
108 case 'v':
109 verbose = B_TRUE;
110 break;
111 case ':':
112 (void) fprintf(stderr,
113 "missing argument for '%c' option\n", optopt);
114 usage();
115 break;
116 case '?':
117 (void) fprintf(stderr, "invalid option '%c'\n",
118 optopt);
119 usage();
120 }
121 }
122
123 if (isatty(STDIN_FILENO)) {
124 (void) fprintf(stderr,
125 "Error: Backup stream can not be read "
126 "from a terminal.\n"
127 "You must redirect standard input.\n");
128 exit(1);
129 }
130
131 send_stream = stdin;
132 while (ssread(drr, sizeof (dmu_replay_record_t), &zc)) {
133
134 if (first) {
135 if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
136 do_byteswap = B_TRUE;
137 if (do_cksum) {
138 ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
139 /*
140 * recalculate header checksum now
141 * that we know it needs to be
142 * byteswapped.
143 */
144 fletcher_4_incremental_byteswap(drr,
145 sizeof (dmu_replay_record_t), &zc);
146 }
147 } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) {
148 (void) fprintf(stderr, "Invalid stream "
149 "(bad magic number)\n");
150 exit(1);
151 }
152 first = B_FALSE;
153 }
154 if (do_byteswap) {
155 drr->drr_type = BSWAP_32(drr->drr_type);
156 drr->drr_payloadlen =
157 BSWAP_32(drr->drr_payloadlen);
158 }
159
160 /*
161 * At this point, the leading fields of the replay record
162 * (drr_type and drr_payloadlen) have been byte-swapped if
163 * necessary, but the rest of the data structure (the
164 * union of type-specific structures) is still in its
165 * original state.
166 */
167 if (drr->drr_type >= DRR_NUMTYPES) {
168 (void) printf("INVALID record found: type 0x%x\n",
169 drr->drr_type);
170 (void) printf("Aborting.\n");
171 exit(1);
172 }
173
174 drr_record_count[drr->drr_type]++;
175 total_records++;
176
177 switch (drr->drr_type) {
178 case DRR_BEGIN:
179 if (do_byteswap) {
180 drrb->drr_magic = BSWAP_64(drrb->drr_magic);
181 drrb->drr_versioninfo =
182 BSWAP_64(drrb->drr_versioninfo);
183 drrb->drr_creation_time =
184 BSWAP_64(drrb->drr_creation_time);
185 drrb->drr_type = BSWAP_32(drrb->drr_type);
186 drrb->drr_flags = BSWAP_32(drrb->drr_flags);
187 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
188 drrb->drr_fromguid =
189 BSWAP_64(drrb->drr_fromguid);
190 }
191
192 (void) printf("BEGIN record\n");
193 (void) printf("\thdrtype = %lld\n",
194 DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo));
195 (void) printf("\tfeatures = %llx\n",
196 DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo));
197 (void) printf("\tmagic = %llx\n",
198 (u_longlong_t)drrb->drr_magic);
199 (void) printf("\tcreation_time = %llx\n",
200 (u_longlong_t)drrb->drr_creation_time);
201 (void) printf("\ttype = %u\n", drrb->drr_type);
202 (void) printf("\tflags = 0x%x\n", drrb->drr_flags);
203 (void) printf("\ttoguid = %llx\n",
204 (u_longlong_t)drrb->drr_toguid);
205 (void) printf("\tfromguid = %llx\n",
206 (u_longlong_t)drrb->drr_fromguid);
207 (void) printf("\ttoname = %s\n", drrb->drr_toname);
208 if (verbose)
209 (void) printf("\n");
210
211 if ((DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
212 DMU_COMPOUNDSTREAM) && drr->drr_payloadlen != 0) {
213 nvlist_t *nv;
214 int sz = drr->drr_payloadlen;
215
216 if (sz > 1<<20) {
217 free(buf);
218 buf = malloc(sz);
219 }
220 (void) ssread(buf, sz, &zc);
221 if (ferror(send_stream))
222 perror("fread");
223 err = nvlist_unpack(buf, sz, &nv, 0);
224 if (err)
225 perror(strerror(err));
226 nvlist_print(stdout, nv);
227 nvlist_free(nv);
228 }
229 break;
230
231 case DRR_END:
232 if (do_byteswap) {
233 drre->drr_checksum.zc_word[0] =
234 BSWAP_64(drre->drr_checksum.zc_word[0]);
235 drre->drr_checksum.zc_word[1] =
236 BSWAP_64(drre->drr_checksum.zc_word[1]);
237 drre->drr_checksum.zc_word[2] =
238 BSWAP_64(drre->drr_checksum.zc_word[2]);
239 drre->drr_checksum.zc_word[3] =
240 BSWAP_64(drre->drr_checksum.zc_word[3]);
241 }
242 /*
243 * We compare against the *previous* checksum
244 * value, because the stored checksum is of
245 * everything before the DRR_END record.
246 */
247 if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum,
248 pcksum)) {
249 (void) printf("Expected checksum differs from "
250 "checksum in stream.\n");
251 (void) printf("Expected checksum = "
252 "%llx/%llx/%llx/%llx\n",
253 (long long unsigned int)pcksum.zc_word[0],
254 (long long unsigned int)pcksum.zc_word[1],
255 (long long unsigned int)pcksum.zc_word[2],
256 (long long unsigned int)pcksum.zc_word[3]);
257 }
258 (void) printf("END checksum = %llx/%llx/%llx/%llx\n",
259 (long long unsigned int)
260 drre->drr_checksum.zc_word[0],
261 (long long unsigned int)
262 drre->drr_checksum.zc_word[1],
263 (long long unsigned int)
264 drre->drr_checksum.zc_word[2],
265 (long long unsigned int)
266 drre->drr_checksum.zc_word[3]);
267
268 ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
269 break;
270
271 case DRR_OBJECT:
272 if (do_byteswap) {
273 drro->drr_object = BSWAP_64(drro->drr_object);
274 drro->drr_type = BSWAP_32(drro->drr_type);
275 drro->drr_bonustype =
276 BSWAP_32(drro->drr_bonustype);
277 drro->drr_blksz = BSWAP_32(drro->drr_blksz);
278 drro->drr_bonuslen =
279 BSWAP_32(drro->drr_bonuslen);
280 drro->drr_toguid = BSWAP_64(drro->drr_toguid);
281 }
282 if (verbose) {
283 (void) printf("OBJECT object = %llu type = %u "
284 "bonustype = %u blksz = %u bonuslen = %u\n",
285 (u_longlong_t)drro->drr_object,
286 drro->drr_type,
287 drro->drr_bonustype,
288 drro->drr_blksz,
289 drro->drr_bonuslen);
290 }
291 if (drro->drr_bonuslen > 0) {
292 (void) ssread(buf,
293 P2ROUNDUP(drro->drr_bonuslen, 8), &zc);
294 }
295 break;
296
297 case DRR_FREEOBJECTS:
298 if (do_byteswap) {
299 drrfo->drr_firstobj =
300 BSWAP_64(drrfo->drr_firstobj);
301 drrfo->drr_numobjs =
302 BSWAP_64(drrfo->drr_numobjs);
303 drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid);
304 }
305 if (verbose) {
306 (void) printf("FREEOBJECTS firstobj = %llu "
307 "numobjs = %llu\n",
308 (u_longlong_t)drrfo->drr_firstobj,
309 (u_longlong_t)drrfo->drr_numobjs);
310 }
311 break;
312
313 case DRR_WRITE:
314 if (do_byteswap) {
315 drrw->drr_object = BSWAP_64(drrw->drr_object);
316 drrw->drr_type = BSWAP_32(drrw->drr_type);
317 drrw->drr_offset = BSWAP_64(drrw->drr_offset);
318 drrw->drr_length = BSWAP_64(drrw->drr_length);
319 drrw->drr_toguid = BSWAP_64(drrw->drr_toguid);
320 drrw->drr_key.ddk_prop =
321 BSWAP_64(drrw->drr_key.ddk_prop);
322 }
323 if (verbose) {
324 (void) printf("WRITE object = %llu type = %u "
325 "checksum type = %u\n"
326 "offset = %llu length = %llu "
327 "props = %llx\n",
328 (u_longlong_t)drrw->drr_object,
329 drrw->drr_type,
330 drrw->drr_checksumtype,
331 (u_longlong_t)drrw->drr_offset,
332 (u_longlong_t)drrw->drr_length,
333 (u_longlong_t)drrw->drr_key.ddk_prop);
334 }
335 (void) ssread(buf, drrw->drr_length, &zc);
336 total_write_size += drrw->drr_length;
337 break;
338
339 case DRR_WRITE_BYREF:
340 if (do_byteswap) {
341 drrwbr->drr_object =
342 BSWAP_64(drrwbr->drr_object);
343 drrwbr->drr_offset =
344 BSWAP_64(drrwbr->drr_offset);
345 drrwbr->drr_length =
346 BSWAP_64(drrwbr->drr_length);
347 drrwbr->drr_toguid =
348 BSWAP_64(drrwbr->drr_toguid);
349 drrwbr->drr_refguid =
350 BSWAP_64(drrwbr->drr_refguid);
351 drrwbr->drr_refobject =
352 BSWAP_64(drrwbr->drr_refobject);
353 drrwbr->drr_refoffset =
354 BSWAP_64(drrwbr->drr_refoffset);
355 drrwbr->drr_key.ddk_prop =
356 BSWAP_64(drrwbr->drr_key.ddk_prop);
357 }
358 if (verbose) {
359 (void) printf("WRITE_BYREF object = %llu "
360 "checksum type = %u props = %llx\n"
361 "offset = %llu length = %llu\n"
362 "toguid = %llx refguid = %llx\n"
363 "refobject = %llu refoffset = %llu\n",
364 (u_longlong_t)drrwbr->drr_object,
365 drrwbr->drr_checksumtype,
366 (u_longlong_t)drrwbr->drr_key.ddk_prop,
367 (u_longlong_t)drrwbr->drr_offset,
368 (u_longlong_t)drrwbr->drr_length,
369 (u_longlong_t)drrwbr->drr_toguid,
370 (u_longlong_t)drrwbr->drr_refguid,
371 (u_longlong_t)drrwbr->drr_refobject,
372 (u_longlong_t)drrwbr->drr_refoffset);
373 }
374 break;
375
376 case DRR_FREE:
377 if (do_byteswap) {
378 drrf->drr_object = BSWAP_64(drrf->drr_object);
379 drrf->drr_offset = BSWAP_64(drrf->drr_offset);
380 drrf->drr_length = BSWAP_64(drrf->drr_length);
381 }
382 if (verbose) {
383 (void) printf("FREE object = %llu "
384 "offset = %llu length = %lld\n",
385 (u_longlong_t)drrf->drr_object,
386 (u_longlong_t)drrf->drr_offset,
387 (longlong_t)drrf->drr_length);
388 }
389 break;
390 case DRR_SPILL:
391 if (do_byteswap) {
392 drrs->drr_object = BSWAP_64(drrs->drr_object);
393 drrs->drr_length = BSWAP_64(drrs->drr_length);
394 }
395 if (verbose) {
396 (void) printf("SPILL block for object = %llu "
397 "length = %llu\n",
398 (long long unsigned int)drrs->drr_object,
399 (long long unsigned int)drrs->drr_length);
400 }
401 (void) ssread(buf, drrs->drr_length, &zc);
402 break;
403 case DRR_WRITE_EMBEDDED:
404 if (do_byteswap) {
405 drrwe->drr_object =
406 BSWAP_64(drrwe->drr_object);
407 drrwe->drr_offset =
408 BSWAP_64(drrwe->drr_offset);
409 drrwe->drr_length =
410 BSWAP_64(drrwe->drr_length);
411 drrwe->drr_toguid =
412 BSWAP_64(drrwe->drr_toguid);
413 drrwe->drr_lsize =
414 BSWAP_32(drrwe->drr_lsize);
415 drrwe->drr_psize =
416 BSWAP_32(drrwe->drr_psize);
417 }
418 if (verbose) {
419 (void) printf("WRITE_EMBEDDED object = %llu "
420 "offset = %llu length = %llu\n"
421 "toguid = %llx comp = %u etype = %u "
422 "lsize = %u psize = %u\n",
423 (u_longlong_t)drrwe->drr_object,
424 (u_longlong_t)drrwe->drr_offset,
425 (u_longlong_t)drrwe->drr_length,
426 (u_longlong_t)drrwe->drr_toguid,
427 drrwe->drr_compression,
428 drrwe->drr_etype,
429 drrwe->drr_lsize,
430 drrwe->drr_psize);
431 }
432 (void) ssread(buf,
433 P2ROUNDUP(drrwe->drr_psize, 8), &zc);
434 break;
435 case DRR_NUMTYPES:
436 /* should never be reached */
437 exit(1);
438 }
439 pcksum = zc;
440 }
441 free(buf);
442
443 /* Print final summary */
444
445 (void) printf("SUMMARY:\n");
446 (void) printf("\tTotal DRR_BEGIN records = %lld\n",
447 (u_longlong_t)drr_record_count[DRR_BEGIN]);
448 (void) printf("\tTotal DRR_END records = %lld\n",
449 (u_longlong_t)drr_record_count[DRR_END]);
450 (void) printf("\tTotal DRR_OBJECT records = %lld\n",
451 (u_longlong_t)drr_record_count[DRR_OBJECT]);
452 (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n",
453 (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]);
454 (void) printf("\tTotal DRR_WRITE records = %lld\n",
455 (u_longlong_t)drr_record_count[DRR_WRITE]);
456 (void) printf("\tTotal DRR_WRITE_BYREF records = %lld\n",
457 (u_longlong_t)drr_record_count[DRR_WRITE_BYREF]);
458 (void) printf("\tTotal DRR_WRITE_EMBEDDED records = %lld\n",
459 (u_longlong_t)drr_record_count[DRR_WRITE_EMBEDDED]);
460 (void) printf("\tTotal DRR_FREE records = %lld\n",
461 (u_longlong_t)drr_record_count[DRR_FREE]);
462 (void) printf("\tTotal DRR_SPILL records = %lld\n",
463 (u_longlong_t)drr_record_count[DRR_SPILL]);
464 (void) printf("\tTotal records = %lld\n",
465 (u_longlong_t)total_records);
466 (void) printf("\tTotal write size = %lld (0x%llx)\n",
467 (u_longlong_t)total_write_size, (u_longlong_t)total_write_size);
468 (void) printf("\tTotal stream length = %lld (0x%llx)\n",
469 (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len);
470 return (0);
471 }