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