]> git.proxmox.com Git - mirror_zfs.git/blob - cmd/zstreamdump/zstreamdump.c
zstreamdump: include embedded writes when dumping raw data (-d)
[mirror_zfs.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 /*
30 * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
31 */
32
33 #include <ctype.h>
34 #include <libnvpair.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include <unistd.h>
39 #include <stddef.h>
40
41 #include <sys/dmu.h>
42 #include <sys/zfs_ioctl.h>
43 #include <sys/zio.h>
44 #include <zfs_fletcher.h>
45
46 /*
47 * If dump mode is enabled, the number of bytes to print per line
48 */
49 #define BYTES_PER_LINE 16
50 /*
51 * If dump mode is enabled, the number of bytes to group together, separated
52 * by newlines or spaces
53 */
54 #define DUMP_GROUPING 4
55
56 uint64_t total_write_size = 0;
57 uint64_t total_stream_len = 0;
58 FILE *send_stream = 0;
59 boolean_t do_byteswap = B_FALSE;
60 boolean_t do_cksum = B_TRUE;
61
62 static void
63 usage(void)
64 {
65 (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] [-d] < file\n");
66 (void) fprintf(stderr, "\t -v -- verbose\n");
67 (void) fprintf(stderr, "\t -C -- suppress checksum verification\n");
68 (void) fprintf(stderr, "\t -d -- dump contents of blocks modified, "
69 "implies verbose\n");
70 exit(1);
71 }
72
73 static void *
74 safe_malloc(size_t size)
75 {
76 void *rv = malloc(size);
77 if (rv == NULL) {
78 (void) fprintf(stderr, "ERROR; failed to allocate %zu bytes\n",
79 size);
80 abort();
81 }
82 return (rv);
83 }
84
85 /*
86 * ssread - send stream read.
87 *
88 * Read while computing incremental checksum
89 */
90 static size_t
91 ssread(void *buf, size_t len, zio_cksum_t *cksum)
92 {
93 size_t outlen;
94
95 if ((outlen = fread(buf, len, 1, send_stream)) == 0)
96 return (0);
97
98 if (do_cksum) {
99 if (do_byteswap)
100 fletcher_4_incremental_byteswap(buf, len, cksum);
101 else
102 fletcher_4_incremental_native(buf, len, cksum);
103 }
104 total_stream_len += len;
105 return (outlen);
106 }
107
108 static size_t
109 read_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum)
110 {
111 ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
112 ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
113 size_t r = ssread(drr, sizeof (*drr) - sizeof (zio_cksum_t), cksum);
114 if (r == 0)
115 return (0);
116 zio_cksum_t saved_cksum = *cksum;
117 r = ssread(&drr->drr_u.drr_checksum.drr_checksum,
118 sizeof (zio_cksum_t), cksum);
119 if (r == 0)
120 return (0);
121 if (!ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.drr_checksum.drr_checksum) &&
122 !ZIO_CHECKSUM_EQUAL(saved_cksum,
123 drr->drr_u.drr_checksum.drr_checksum)) {
124 fprintf(stderr, "invalid checksum\n");
125 (void) printf("Incorrect checksum in record header.\n");
126 (void) printf("Expected checksum = %llx/%llx/%llx/%llx\n",
127 (longlong_t)saved_cksum.zc_word[0],
128 (longlong_t)saved_cksum.zc_word[1],
129 (longlong_t)saved_cksum.zc_word[2],
130 (longlong_t)saved_cksum.zc_word[3]);
131 return (0);
132 }
133 return (sizeof (*drr));
134 }
135
136 /*
137 * Print part of a block in ASCII characters
138 */
139 static void
140 print_ascii_block(char *subbuf, int length)
141 {
142 int i;
143
144 for (i = 0; i < length; i++) {
145 char char_print = isprint(subbuf[i]) ? subbuf[i] : '.';
146 if (i != 0 && i % DUMP_GROUPING == 0) {
147 (void) printf(" ");
148 }
149 (void) printf("%c", char_print);
150 }
151 (void) printf("\n");
152 }
153
154 /*
155 * print_block - Dump the contents of a modified block to STDOUT
156 *
157 * Assume that buf has capacity evenly divisible by BYTES_PER_LINE
158 */
159 static void
160 print_block(char *buf, int length)
161 {
162 int i;
163 /*
164 * Start printing ASCII characters at a constant offset, after
165 * the hex prints. Leave 3 characters per byte on a line (2 digit
166 * hex number plus 1 space) plus spaces between characters and
167 * groupings.
168 */
169 int ascii_start = BYTES_PER_LINE * 3 +
170 BYTES_PER_LINE / DUMP_GROUPING + 2;
171
172 for (i = 0; i < length; i += BYTES_PER_LINE) {
173 int j;
174 int this_line_length = MIN(BYTES_PER_LINE, length - i);
175 int print_offset = 0;
176
177 for (j = 0; j < this_line_length; j++) {
178 int buf_offset = i + j;
179
180 /*
181 * Separate every DUMP_GROUPING bytes by a space.
182 */
183 if (buf_offset % DUMP_GROUPING == 0) {
184 print_offset += printf(" ");
185 }
186
187 /*
188 * Print the two-digit hex value for this byte.
189 */
190 unsigned char hex_print = buf[buf_offset];
191 print_offset += printf("%02x ", hex_print);
192 }
193
194 (void) printf("%*s", ascii_start - print_offset, " ");
195
196 print_ascii_block(buf + i, this_line_length);
197 }
198 }
199
200 /*
201 * Print an array of bytes to stdout as hexidecimal characters. str must
202 * have buf_len * 2 + 1 bytes of space.
203 */
204 static void
205 sprintf_bytes(char *str, uint8_t *buf, uint_t buf_len)
206 {
207 int i, n;
208
209 for (i = 0; i < buf_len; i++) {
210 n = sprintf(str, "%02x", buf[i] & 0xff);
211 str += n;
212 }
213
214 str[0] = '\0';
215 }
216
217 int
218 main(int argc, char *argv[])
219 {
220 char *buf = safe_malloc(SPA_MAXBLOCKSIZE);
221 uint64_t drr_record_count[DRR_NUMTYPES] = { 0 };
222 char salt[ZIO_DATA_SALT_LEN * 2 + 1];
223 char iv[ZIO_DATA_IV_LEN * 2 + 1];
224 char mac[ZIO_DATA_MAC_LEN * 2 + 1];
225 uint64_t total_records = 0;
226 uint64_t payload_size;
227 dmu_replay_record_t thedrr;
228 dmu_replay_record_t *drr = &thedrr;
229 struct drr_begin *drrb = &thedrr.drr_u.drr_begin;
230 struct drr_end *drre = &thedrr.drr_u.drr_end;
231 struct drr_object *drro = &thedrr.drr_u.drr_object;
232 struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects;
233 struct drr_write *drrw = &thedrr.drr_u.drr_write;
234 struct drr_write_byref *drrwbr = &thedrr.drr_u.drr_write_byref;
235 struct drr_free *drrf = &thedrr.drr_u.drr_free;
236 struct drr_spill *drrs = &thedrr.drr_u.drr_spill;
237 struct drr_write_embedded *drrwe = &thedrr.drr_u.drr_write_embedded;
238 struct drr_object_range *drror = &thedrr.drr_u.drr_object_range;
239 struct drr_checksum *drrc = &thedrr.drr_u.drr_checksum;
240 char c;
241 boolean_t verbose = B_FALSE;
242 boolean_t very_verbose = B_FALSE;
243 boolean_t first = B_TRUE;
244 /*
245 * dump flag controls whether the contents of any modified data blocks
246 * are printed to the console during processing of the stream. Warning:
247 * for large streams, this can obviously lead to massive prints.
248 */
249 boolean_t dump = B_FALSE;
250 int err;
251 zio_cksum_t zc = { { 0 } };
252 zio_cksum_t pcksum = { { 0 } };
253
254 while ((c = getopt(argc, argv, ":vCd")) != -1) {
255 switch (c) {
256 case 'C':
257 do_cksum = B_FALSE;
258 break;
259 case 'v':
260 if (verbose)
261 very_verbose = B_TRUE;
262 verbose = B_TRUE;
263 break;
264 case 'd':
265 dump = B_TRUE;
266 verbose = B_TRUE;
267 very_verbose = B_TRUE;
268 break;
269 case ':':
270 (void) fprintf(stderr,
271 "missing argument for '%c' option\n", optopt);
272 usage();
273 break;
274 case '?':
275 (void) fprintf(stderr, "invalid option '%c'\n",
276 optopt);
277 usage();
278 break;
279 }
280 }
281
282 if (isatty(STDIN_FILENO)) {
283 (void) fprintf(stderr,
284 "Error: Backup stream can not be read "
285 "from a terminal.\n"
286 "You must redirect standard input.\n");
287 exit(1);
288 }
289
290 fletcher_4_init();
291 send_stream = stdin;
292 while (read_hdr(drr, &zc)) {
293
294 /*
295 * If this is the first DMU record being processed, check for
296 * the magic bytes and figure out the endian-ness based on them.
297 */
298 if (first) {
299 if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
300 do_byteswap = B_TRUE;
301 if (do_cksum) {
302 ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
303 /*
304 * recalculate header checksum now
305 * that we know it needs to be
306 * byteswapped.
307 */
308 fletcher_4_incremental_byteswap(drr,
309 sizeof (dmu_replay_record_t), &zc);
310 }
311 } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) {
312 (void) fprintf(stderr, "Invalid stream "
313 "(bad magic number)\n");
314 exit(1);
315 }
316 first = B_FALSE;
317 }
318 if (do_byteswap) {
319 drr->drr_type = BSWAP_32(drr->drr_type);
320 drr->drr_payloadlen =
321 BSWAP_32(drr->drr_payloadlen);
322 }
323
324 /*
325 * At this point, the leading fields of the replay record
326 * (drr_type and drr_payloadlen) have been byte-swapped if
327 * necessary, but the rest of the data structure (the
328 * union of type-specific structures) is still in its
329 * original state.
330 */
331 if (drr->drr_type >= DRR_NUMTYPES) {
332 (void) printf("INVALID record found: type 0x%x\n",
333 drr->drr_type);
334 (void) printf("Aborting.\n");
335 exit(1);
336 }
337
338 drr_record_count[drr->drr_type]++;
339 total_records++;
340
341 switch (drr->drr_type) {
342 case DRR_BEGIN:
343 if (do_byteswap) {
344 drrb->drr_magic = BSWAP_64(drrb->drr_magic);
345 drrb->drr_versioninfo =
346 BSWAP_64(drrb->drr_versioninfo);
347 drrb->drr_creation_time =
348 BSWAP_64(drrb->drr_creation_time);
349 drrb->drr_type = BSWAP_32(drrb->drr_type);
350 drrb->drr_flags = BSWAP_32(drrb->drr_flags);
351 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
352 drrb->drr_fromguid =
353 BSWAP_64(drrb->drr_fromguid);
354 }
355
356 (void) printf("BEGIN record\n");
357 (void) printf("\thdrtype = %lld\n",
358 DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo));
359 (void) printf("\tfeatures = %llx\n",
360 DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo));
361 (void) printf("\tmagic = %llx\n",
362 (u_longlong_t)drrb->drr_magic);
363 (void) printf("\tcreation_time = %llx\n",
364 (u_longlong_t)drrb->drr_creation_time);
365 (void) printf("\ttype = %u\n", drrb->drr_type);
366 (void) printf("\tflags = 0x%x\n", drrb->drr_flags);
367 (void) printf("\ttoguid = %llx\n",
368 (u_longlong_t)drrb->drr_toguid);
369 (void) printf("\tfromguid = %llx\n",
370 (u_longlong_t)drrb->drr_fromguid);
371 (void) printf("\ttoname = %s\n", drrb->drr_toname);
372 if (verbose)
373 (void) printf("\n");
374
375 if (drr->drr_payloadlen != 0) {
376 nvlist_t *nv;
377 int sz = drr->drr_payloadlen;
378
379 if (sz > SPA_MAXBLOCKSIZE) {
380 free(buf);
381 buf = safe_malloc(sz);
382 }
383 (void) ssread(buf, sz, &zc);
384 if (ferror(send_stream))
385 perror("fread");
386 err = nvlist_unpack(buf, sz, &nv, 0);
387 if (err) {
388 perror(strerror(err));
389 } else {
390 nvlist_print(stdout, nv);
391 nvlist_free(nv);
392 }
393 }
394 break;
395
396 case DRR_END:
397 if (do_byteswap) {
398 drre->drr_checksum.zc_word[0] =
399 BSWAP_64(drre->drr_checksum.zc_word[0]);
400 drre->drr_checksum.zc_word[1] =
401 BSWAP_64(drre->drr_checksum.zc_word[1]);
402 drre->drr_checksum.zc_word[2] =
403 BSWAP_64(drre->drr_checksum.zc_word[2]);
404 drre->drr_checksum.zc_word[3] =
405 BSWAP_64(drre->drr_checksum.zc_word[3]);
406 }
407 /*
408 * We compare against the *previous* checksum
409 * value, because the stored checksum is of
410 * everything before the DRR_END record.
411 */
412 if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum,
413 pcksum)) {
414 (void) printf("Expected checksum differs from "
415 "checksum in stream.\n");
416 (void) printf("Expected checksum = "
417 "%llx/%llx/%llx/%llx\n",
418 (long long unsigned int)pcksum.zc_word[0],
419 (long long unsigned int)pcksum.zc_word[1],
420 (long long unsigned int)pcksum.zc_word[2],
421 (long long unsigned int)pcksum.zc_word[3]);
422 }
423 (void) printf("END checksum = %llx/%llx/%llx/%llx\n",
424 (long long unsigned int)
425 drre->drr_checksum.zc_word[0],
426 (long long unsigned int)
427 drre->drr_checksum.zc_word[1],
428 (long long unsigned int)
429 drre->drr_checksum.zc_word[2],
430 (long long unsigned int)
431 drre->drr_checksum.zc_word[3]);
432
433 ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
434 break;
435
436 case DRR_OBJECT:
437 if (do_byteswap) {
438 drro->drr_object = BSWAP_64(drro->drr_object);
439 drro->drr_type = BSWAP_32(drro->drr_type);
440 drro->drr_bonustype =
441 BSWAP_32(drro->drr_bonustype);
442 drro->drr_blksz = BSWAP_32(drro->drr_blksz);
443 drro->drr_bonuslen =
444 BSWAP_32(drro->drr_bonuslen);
445 drro->drr_raw_bonuslen =
446 BSWAP_32(drro->drr_raw_bonuslen);
447 drro->drr_toguid = BSWAP_64(drro->drr_toguid);
448 drro->drr_maxblkid =
449 BSWAP_64(drro->drr_maxblkid);
450 }
451
452 payload_size = DRR_OBJECT_PAYLOAD_SIZE(drro);
453
454 if (verbose) {
455 (void) printf("OBJECT object = %llu type = %u "
456 "bonustype = %u blksz = %u bonuslen = %u "
457 "dn_slots = %u raw_bonuslen = %u "
458 "flags = %u maxblkid = %llu "
459 "indblkshift = %u nlevels = %u "
460 "nblkptr = %u\n",
461 (u_longlong_t)drro->drr_object,
462 drro->drr_type,
463 drro->drr_bonustype,
464 drro->drr_blksz,
465 drro->drr_bonuslen,
466 drro->drr_dn_slots,
467 drro->drr_raw_bonuslen,
468 drro->drr_flags,
469 (u_longlong_t)drro->drr_maxblkid,
470 drro->drr_indblkshift,
471 drro->drr_nlevels,
472 drro->drr_nblkptr);
473 }
474 if (drro->drr_bonuslen > 0) {
475 (void) ssread(buf, payload_size, &zc);
476 if (dump)
477 print_block(buf, payload_size);
478 }
479 break;
480
481 case DRR_FREEOBJECTS:
482 if (do_byteswap) {
483 drrfo->drr_firstobj =
484 BSWAP_64(drrfo->drr_firstobj);
485 drrfo->drr_numobjs =
486 BSWAP_64(drrfo->drr_numobjs);
487 drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid);
488 }
489 if (verbose) {
490 (void) printf("FREEOBJECTS firstobj = %llu "
491 "numobjs = %llu\n",
492 (u_longlong_t)drrfo->drr_firstobj,
493 (u_longlong_t)drrfo->drr_numobjs);
494 }
495 break;
496
497 case DRR_WRITE:
498 if (do_byteswap) {
499 drrw->drr_object = BSWAP_64(drrw->drr_object);
500 drrw->drr_type = BSWAP_32(drrw->drr_type);
501 drrw->drr_offset = BSWAP_64(drrw->drr_offset);
502 drrw->drr_logical_size =
503 BSWAP_64(drrw->drr_logical_size);
504 drrw->drr_toguid = BSWAP_64(drrw->drr_toguid);
505 drrw->drr_key.ddk_prop =
506 BSWAP_64(drrw->drr_key.ddk_prop);
507 drrw->drr_compressed_size =
508 BSWAP_64(drrw->drr_compressed_size);
509 }
510
511 payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw);
512
513 /*
514 * If this is verbose and/or dump output,
515 * print info on the modified block
516 */
517 if (verbose) {
518 sprintf_bytes(salt, drrw->drr_salt,
519 ZIO_DATA_SALT_LEN);
520 sprintf_bytes(iv, drrw->drr_iv,
521 ZIO_DATA_IV_LEN);
522 sprintf_bytes(mac, drrw->drr_mac,
523 ZIO_DATA_MAC_LEN);
524
525 (void) printf("WRITE object = %llu type = %u "
526 "checksum type = %u compression type = %u\n"
527 " flags = %u offset = %llu "
528 "logical_size = %llu "
529 "compressed_size = %llu "
530 "payload_size = %llu props = %llx "
531 "salt = %s iv = %s mac = %s\n",
532 (u_longlong_t)drrw->drr_object,
533 drrw->drr_type,
534 drrw->drr_checksumtype,
535 drrw->drr_compressiontype,
536 drrw->drr_flags,
537 (u_longlong_t)drrw->drr_offset,
538 (u_longlong_t)drrw->drr_logical_size,
539 (u_longlong_t)drrw->drr_compressed_size,
540 (u_longlong_t)payload_size,
541 (u_longlong_t)drrw->drr_key.ddk_prop,
542 salt,
543 iv,
544 mac);
545 }
546
547 /*
548 * Read the contents of the block in from STDIN to buf
549 */
550 (void) ssread(buf, payload_size, &zc);
551 /*
552 * If in dump mode
553 */
554 if (dump) {
555 print_block(buf, payload_size);
556 }
557 total_write_size += payload_size;
558 break;
559
560 case DRR_WRITE_BYREF:
561 if (do_byteswap) {
562 drrwbr->drr_object =
563 BSWAP_64(drrwbr->drr_object);
564 drrwbr->drr_offset =
565 BSWAP_64(drrwbr->drr_offset);
566 drrwbr->drr_length =
567 BSWAP_64(drrwbr->drr_length);
568 drrwbr->drr_toguid =
569 BSWAP_64(drrwbr->drr_toguid);
570 drrwbr->drr_refguid =
571 BSWAP_64(drrwbr->drr_refguid);
572 drrwbr->drr_refobject =
573 BSWAP_64(drrwbr->drr_refobject);
574 drrwbr->drr_refoffset =
575 BSWAP_64(drrwbr->drr_refoffset);
576 drrwbr->drr_key.ddk_prop =
577 BSWAP_64(drrwbr->drr_key.ddk_prop);
578 }
579 if (verbose) {
580 (void) printf("WRITE_BYREF object = %llu "
581 "checksum type = %u props = %llx\n"
582 " offset = %llu length = %llu\n"
583 "toguid = %llx refguid = %llx\n"
584 " refobject = %llu refoffset = %llu\n",
585 (u_longlong_t)drrwbr->drr_object,
586 drrwbr->drr_checksumtype,
587 (u_longlong_t)drrwbr->drr_key.ddk_prop,
588 (u_longlong_t)drrwbr->drr_offset,
589 (u_longlong_t)drrwbr->drr_length,
590 (u_longlong_t)drrwbr->drr_toguid,
591 (u_longlong_t)drrwbr->drr_refguid,
592 (u_longlong_t)drrwbr->drr_refobject,
593 (u_longlong_t)drrwbr->drr_refoffset);
594 }
595 break;
596
597 case DRR_FREE:
598 if (do_byteswap) {
599 drrf->drr_object = BSWAP_64(drrf->drr_object);
600 drrf->drr_offset = BSWAP_64(drrf->drr_offset);
601 drrf->drr_length = BSWAP_64(drrf->drr_length);
602 }
603 if (verbose) {
604 (void) printf("FREE object = %llu "
605 "offset = %llu length = %lld\n",
606 (u_longlong_t)drrf->drr_object,
607 (u_longlong_t)drrf->drr_offset,
608 (longlong_t)drrf->drr_length);
609 }
610 break;
611 case DRR_SPILL:
612 if (do_byteswap) {
613 drrs->drr_object = BSWAP_64(drrs->drr_object);
614 drrs->drr_length = BSWAP_64(drrs->drr_length);
615 drrs->drr_compressed_size =
616 BSWAP_64(drrs->drr_compressed_size);
617 drrs->drr_type = BSWAP_32(drrs->drr_type);
618 }
619
620 payload_size = DRR_SPILL_PAYLOAD_SIZE(drrs);
621
622 if (verbose) {
623 sprintf_bytes(salt, drrs->drr_salt,
624 ZIO_DATA_SALT_LEN);
625 sprintf_bytes(iv, drrs->drr_iv,
626 ZIO_DATA_IV_LEN);
627 sprintf_bytes(mac, drrs->drr_mac,
628 ZIO_DATA_MAC_LEN);
629
630 (void) printf("SPILL block for object = %llu "
631 "length = %llu flags = %u "
632 "compression type = %u "
633 "compressed_size = %llu "
634 "payload_size = %llu "
635 "salt = %s iv = %s mac = %s\n",
636 (u_longlong_t)drrs->drr_object,
637 (u_longlong_t)drrs->drr_length,
638 drrs->drr_flags,
639 drrs->drr_compressiontype,
640 (u_longlong_t)drrs->drr_compressed_size,
641 (u_longlong_t)payload_size,
642 salt,
643 iv,
644 mac);
645 }
646 (void) ssread(buf, payload_size, &zc);
647 if (dump) {
648 print_block(buf, payload_size);
649 }
650 break;
651 case DRR_WRITE_EMBEDDED:
652 if (do_byteswap) {
653 drrwe->drr_object =
654 BSWAP_64(drrwe->drr_object);
655 drrwe->drr_offset =
656 BSWAP_64(drrwe->drr_offset);
657 drrwe->drr_length =
658 BSWAP_64(drrwe->drr_length);
659 drrwe->drr_toguid =
660 BSWAP_64(drrwe->drr_toguid);
661 drrwe->drr_lsize =
662 BSWAP_32(drrwe->drr_lsize);
663 drrwe->drr_psize =
664 BSWAP_32(drrwe->drr_psize);
665 }
666 if (verbose) {
667 (void) printf("WRITE_EMBEDDED object = %llu "
668 "offset = %llu length = %llu\n"
669 " toguid = %llx comp = %u etype = %u "
670 "lsize = %u psize = %u\n",
671 (u_longlong_t)drrwe->drr_object,
672 (u_longlong_t)drrwe->drr_offset,
673 (u_longlong_t)drrwe->drr_length,
674 (u_longlong_t)drrwe->drr_toguid,
675 drrwe->drr_compression,
676 drrwe->drr_etype,
677 drrwe->drr_lsize,
678 drrwe->drr_psize);
679 }
680 (void) ssread(buf,
681 P2ROUNDUP(drrwe->drr_psize, 8), &zc);
682 if (dump) {
683 print_block(buf,
684 P2ROUNDUP(drrwe->drr_psize, 8));
685 }
686 break;
687 case DRR_OBJECT_RANGE:
688 if (do_byteswap) {
689 drror->drr_firstobj =
690 BSWAP_64(drror->drr_firstobj);
691 drror->drr_numslots =
692 BSWAP_64(drror->drr_numslots);
693 drror->drr_toguid = BSWAP_64(drror->drr_toguid);
694 }
695 if (verbose) {
696 sprintf_bytes(salt, drror->drr_salt,
697 ZIO_DATA_SALT_LEN);
698 sprintf_bytes(iv, drror->drr_iv,
699 ZIO_DATA_IV_LEN);
700 sprintf_bytes(mac, drror->drr_mac,
701 ZIO_DATA_MAC_LEN);
702
703 (void) printf("OBJECT_RANGE firstobj = %llu "
704 "numslots = %llu flags = %u "
705 "salt = %s iv = %s mac = %s\n",
706 (u_longlong_t)drror->drr_firstobj,
707 (u_longlong_t)drror->drr_numslots,
708 drror->drr_flags,
709 salt,
710 iv,
711 mac);
712 }
713 break;
714 case DRR_NUMTYPES:
715 /* should never be reached */
716 exit(1);
717 }
718 if (drr->drr_type != DRR_BEGIN && very_verbose) {
719 (void) printf(" checksum = %llx/%llx/%llx/%llx\n",
720 (longlong_t)drrc->drr_checksum.zc_word[0],
721 (longlong_t)drrc->drr_checksum.zc_word[1],
722 (longlong_t)drrc->drr_checksum.zc_word[2],
723 (longlong_t)drrc->drr_checksum.zc_word[3]);
724 }
725 pcksum = zc;
726 }
727 free(buf);
728 fletcher_4_fini();
729
730 /* Print final summary */
731
732 (void) printf("SUMMARY:\n");
733 (void) printf("\tTotal DRR_BEGIN records = %lld\n",
734 (u_longlong_t)drr_record_count[DRR_BEGIN]);
735 (void) printf("\tTotal DRR_END records = %lld\n",
736 (u_longlong_t)drr_record_count[DRR_END]);
737 (void) printf("\tTotal DRR_OBJECT records = %lld\n",
738 (u_longlong_t)drr_record_count[DRR_OBJECT]);
739 (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n",
740 (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]);
741 (void) printf("\tTotal DRR_WRITE records = %lld\n",
742 (u_longlong_t)drr_record_count[DRR_WRITE]);
743 (void) printf("\tTotal DRR_WRITE_BYREF records = %lld\n",
744 (u_longlong_t)drr_record_count[DRR_WRITE_BYREF]);
745 (void) printf("\tTotal DRR_WRITE_EMBEDDED records = %lld\n",
746 (u_longlong_t)drr_record_count[DRR_WRITE_EMBEDDED]);
747 (void) printf("\tTotal DRR_FREE records = %lld\n",
748 (u_longlong_t)drr_record_count[DRR_FREE]);
749 (void) printf("\tTotal DRR_SPILL records = %lld\n",
750 (u_longlong_t)drr_record_count[DRR_SPILL]);
751 (void) printf("\tTotal records = %lld\n",
752 (u_longlong_t)total_records);
753 (void) printf("\tTotal write size = %lld (0x%llx)\n",
754 (u_longlong_t)total_write_size, (u_longlong_t)total_write_size);
755 (void) printf("\tTotal stream length = %lld (0x%llx)\n",
756 (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len);
757 return (0);
758 }