1219089Spjd/* 2219089Spjd * CDDL HEADER START 3219089Spjd * 4219089Spjd * The contents of this file are subject to the terms of the 5219089Spjd * Common Development and Distribution License (the "License"). 6219089Spjd * You may not use this file except in compliance with the License. 7219089Spjd * 8219089Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9219089Spjd * or http://www.opensolaris.org/os/licensing. 10219089Spjd * See the License for the specific language governing permissions 11219089Spjd * and limitations under the License. 12219089Spjd * 13219089Spjd * When distributing Covered Code, include this CDDL HEADER in each 14219089Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15219089Spjd * If applicable, add the following below this CDDL HEADER, with the 16219089Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17219089Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18219089Spjd * 19219089Spjd * CDDL HEADER END 20219089Spjd */ 21219089Spjd 22219089Spjd/* 23219089Spjd * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24219089Spjd * Use is subject to license terms. 25219089Spjd */ 26219089Spjd 27268648Sdelphij/* 28288553Smav * Copyright (c) 2013, 2014 by Delphix. All rights reserved. 29268648Sdelphij */ 30268648Sdelphij 31268648Sdelphij#include <ctype.h> 32219089Spjd#include <libnvpair.h> 33219089Spjd#include <stdio.h> 34219089Spjd#include <stdlib.h> 35219089Spjd#include <strings.h> 36219089Spjd#include <unistd.h> 37288553Smav#include <stddef.h> 38219089Spjd 39219089Spjd#include <sys/dmu.h> 40219089Spjd#include <sys/zfs_ioctl.h> 41219089Spjd#include <zfs_fletcher.h> 42219089Spjd 43268648Sdelphij/* 44268648Sdelphij * If dump mode is enabled, the number of bytes to print per line 45268648Sdelphij */ 46268648Sdelphij#define BYTES_PER_LINE 16 47268648Sdelphij/* 48268648Sdelphij * If dump mode is enabled, the number of bytes to group together, separated 49268648Sdelphij * by newlines or spaces 50268648Sdelphij */ 51268648Sdelphij#define DUMP_GROUPING 4 52268648Sdelphij 53219089Spjduint64_t total_write_size = 0; 54219089Spjduint64_t total_stream_len = 0; 55219089SpjdFILE *send_stream = 0; 56219089Spjdboolean_t do_byteswap = B_FALSE; 57219089Spjdboolean_t do_cksum = B_TRUE; 58219089Spjd 59219089Spjdstatic void 60219089Spjdusage(void) 61219089Spjd{ 62268648Sdelphij (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] [-d] < file\n"); 63219089Spjd (void) fprintf(stderr, "\t -v -- verbose\n"); 64219089Spjd (void) fprintf(stderr, "\t -C -- suppress checksum verification\n"); 65268648Sdelphij (void) fprintf(stderr, "\t -d -- dump contents of blocks modified, " 66268648Sdelphij "implies verbose\n"); 67219089Spjd exit(1); 68219089Spjd} 69219089Spjd 70276081Sdelphijstatic void * 71276081Sdelphijsafe_malloc(size_t size) 72276081Sdelphij{ 73276081Sdelphij void *rv = malloc(size); 74276081Sdelphij if (rv == NULL) { 75276081Sdelphij (void) fprintf(stderr, "ERROR; failed to allocate %zu bytes\n", 76276081Sdelphij size); 77276081Sdelphij abort(); 78276081Sdelphij } 79276081Sdelphij return (rv); 80276081Sdelphij} 81276081Sdelphij 82219089Spjd/* 83219089Spjd * ssread - send stream read. 84219089Spjd * 85219089Spjd * Read while computing incremental checksum 86219089Spjd */ 87219089Spjdstatic size_t 88219089Spjdssread(void *buf, size_t len, zio_cksum_t *cksum) 89219089Spjd{ 90219089Spjd size_t outlen; 91219089Spjd 92219089Spjd if ((outlen = fread(buf, len, 1, send_stream)) == 0) 93219089Spjd return (0); 94219089Spjd 95288553Smav if (do_cksum) { 96219089Spjd if (do_byteswap) 97219089Spjd fletcher_4_incremental_byteswap(buf, len, cksum); 98219089Spjd else 99219089Spjd fletcher_4_incremental_native(buf, len, cksum); 100219089Spjd } 101219089Spjd total_stream_len += len; 102219089Spjd return (outlen); 103219089Spjd} 104219089Spjd 105288553Smavstatic size_t 106288553Smavread_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum) 107288553Smav{ 108288553Smav ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), 109288553Smav ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t)); 110288553Smav size_t r = ssread(drr, sizeof (*drr) - sizeof (zio_cksum_t), cksum); 111288553Smav if (r == 0) 112288553Smav return (0); 113288553Smav zio_cksum_t saved_cksum = *cksum; 114288553Smav r = ssread(&drr->drr_u.drr_checksum.drr_checksum, 115288553Smav sizeof (zio_cksum_t), cksum); 116288553Smav if (r == 0) 117288553Smav return (0); 118288553Smav if (!ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.drr_checksum.drr_checksum) && 119288553Smav !ZIO_CHECKSUM_EQUAL(saved_cksum, 120288553Smav drr->drr_u.drr_checksum.drr_checksum)) { 121288553Smav fprintf(stderr, "invalid checksum\n"); 122288553Smav (void) printf("Incorrect checksum in record header.\n"); 123288553Smav (void) printf("Expected checksum = %llx/%llx/%llx/%llx\n", 124288553Smav saved_cksum.zc_word[0], 125288553Smav saved_cksum.zc_word[1], 126288553Smav saved_cksum.zc_word[2], 127288553Smav saved_cksum.zc_word[3]); 128290756Smav return (0); 129288553Smav } 130288553Smav return (sizeof (*drr)); 131288553Smav} 132288553Smav 133268648Sdelphij/* 134268648Sdelphij * Print part of a block in ASCII characters 135268648Sdelphij */ 136268648Sdelphijstatic void 137268648Sdelphijprint_ascii_block(char *subbuf, int length) 138268648Sdelphij{ 139268648Sdelphij int i; 140268648Sdelphij 141268648Sdelphij for (i = 0; i < length; i++) { 142268648Sdelphij char char_print = isprint(subbuf[i]) ? subbuf[i] : '.'; 143268648Sdelphij if (i != 0 && i % DUMP_GROUPING == 0) { 144268648Sdelphij (void) printf(" "); 145268648Sdelphij } 146268648Sdelphij (void) printf("%c", char_print); 147268648Sdelphij } 148268648Sdelphij (void) printf("\n"); 149268648Sdelphij} 150268648Sdelphij 151268648Sdelphij/* 152268648Sdelphij * print_block - Dump the contents of a modified block to STDOUT 153268648Sdelphij * 154268648Sdelphij * Assume that buf has capacity evenly divisible by BYTES_PER_LINE 155268648Sdelphij */ 156268648Sdelphijstatic void 157268648Sdelphijprint_block(char *buf, int length) 158268648Sdelphij{ 159268648Sdelphij int i; 160268648Sdelphij /* 161268648Sdelphij * Start printing ASCII characters at a constant offset, after 162268648Sdelphij * the hex prints. Leave 3 characters per byte on a line (2 digit 163268648Sdelphij * hex number plus 1 space) plus spaces between characters and 164268649Sdelphij * groupings. 165268648Sdelphij */ 166268648Sdelphij int ascii_start = BYTES_PER_LINE * 3 + 167268648Sdelphij BYTES_PER_LINE / DUMP_GROUPING + 2; 168268648Sdelphij 169268648Sdelphij for (i = 0; i < length; i += BYTES_PER_LINE) { 170268648Sdelphij int j; 171268648Sdelphij int this_line_length = MIN(BYTES_PER_LINE, length - i); 172268648Sdelphij int print_offset = 0; 173268648Sdelphij 174268648Sdelphij for (j = 0; j < this_line_length; j++) { 175268648Sdelphij int buf_offset = i + j; 176268648Sdelphij 177268648Sdelphij /* 178268648Sdelphij * Separate every DUMP_GROUPING bytes by a space. 179268648Sdelphij */ 180268648Sdelphij if (buf_offset % DUMP_GROUPING == 0) { 181268648Sdelphij print_offset += printf(" "); 182268648Sdelphij } 183268648Sdelphij 184268648Sdelphij /* 185268648Sdelphij * Print the two-digit hex value for this byte. 186268648Sdelphij */ 187268648Sdelphij unsigned char hex_print = buf[buf_offset]; 188268648Sdelphij print_offset += printf("%02x ", hex_print); 189268648Sdelphij } 190268648Sdelphij 191268648Sdelphij (void) printf("%*s", ascii_start - print_offset, " "); 192268648Sdelphij 193268648Sdelphij print_ascii_block(buf + i, this_line_length); 194268648Sdelphij } 195268648Sdelphij} 196268648Sdelphij 197219089Spjdint 198219089Spjdmain(int argc, char *argv[]) 199219089Spjd{ 200276081Sdelphij char *buf = safe_malloc(SPA_MAXBLOCKSIZE); 201268649Sdelphij uint64_t drr_record_count[DRR_NUMTYPES] = { 0 }; 202268649Sdelphij uint64_t total_records = 0; 203219089Spjd dmu_replay_record_t thedrr; 204219089Spjd dmu_replay_record_t *drr = &thedrr; 205219089Spjd struct drr_begin *drrb = &thedrr.drr_u.drr_begin; 206219089Spjd struct drr_end *drre = &thedrr.drr_u.drr_end; 207219089Spjd struct drr_object *drro = &thedrr.drr_u.drr_object; 208219089Spjd struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects; 209219089Spjd struct drr_write *drrw = &thedrr.drr_u.drr_write; 210219089Spjd struct drr_write_byref *drrwbr = &thedrr.drr_u.drr_write_byref; 211219089Spjd struct drr_free *drrf = &thedrr.drr_u.drr_free; 212219089Spjd struct drr_spill *drrs = &thedrr.drr_u.drr_spill; 213268649Sdelphij struct drr_write_embedded *drrwe = &thedrr.drr_u.drr_write_embedded; 214288553Smav struct drr_checksum *drrc = &thedrr.drr_u.drr_checksum; 215219089Spjd char c; 216219089Spjd boolean_t verbose = B_FALSE; 217288553Smav boolean_t very_verbose = B_FALSE; 218219089Spjd boolean_t first = B_TRUE; 219268648Sdelphij /* 220268648Sdelphij * dump flag controls whether the contents of any modified data blocks 221268648Sdelphij * are printed to the console during processing of the stream. Warning: 222268648Sdelphij * for large streams, this can obviously lead to massive prints. 223268648Sdelphij */ 224268648Sdelphij boolean_t dump = B_FALSE; 225219089Spjd int err; 226219089Spjd zio_cksum_t zc = { 0 }; 227219089Spjd zio_cksum_t pcksum = { 0 }; 228219089Spjd 229268648Sdelphij while ((c = getopt(argc, argv, ":vCd")) != -1) { 230219089Spjd switch (c) { 231219089Spjd case 'C': 232219089Spjd do_cksum = B_FALSE; 233219089Spjd break; 234219089Spjd case 'v': 235288553Smav if (verbose) 236288553Smav very_verbose = B_TRUE; 237219089Spjd verbose = B_TRUE; 238219089Spjd break; 239268648Sdelphij case 'd': 240268648Sdelphij dump = B_TRUE; 241268648Sdelphij verbose = B_TRUE; 242288553Smav very_verbose = B_TRUE; 243268648Sdelphij break; 244219089Spjd case ':': 245219089Spjd (void) fprintf(stderr, 246219089Spjd "missing argument for '%c' option\n", optopt); 247219089Spjd usage(); 248219089Spjd break; 249219089Spjd case '?': 250219089Spjd (void) fprintf(stderr, "invalid option '%c'\n", 251219089Spjd optopt); 252219089Spjd usage(); 253219089Spjd } 254219089Spjd } 255219089Spjd 256219089Spjd if (isatty(STDIN_FILENO)) { 257219089Spjd (void) fprintf(stderr, 258219089Spjd "Error: Backup stream can not be read " 259219089Spjd "from a terminal.\n" 260219089Spjd "You must redirect standard input.\n"); 261219089Spjd exit(1); 262219089Spjd } 263219089Spjd 264219089Spjd send_stream = stdin; 265219089Spjd pcksum = zc; 266288553Smav while (read_hdr(drr, &zc)) { 267219089Spjd 268268648Sdelphij /* 269268648Sdelphij * If this is the first DMU record being processed, check for 270268648Sdelphij * the magic bytes and figure out the endian-ness based on them. 271268648Sdelphij */ 272219089Spjd if (first) { 273219089Spjd if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { 274219089Spjd do_byteswap = B_TRUE; 275219089Spjd if (do_cksum) { 276219089Spjd ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); 277219089Spjd /* 278219089Spjd * recalculate header checksum now 279219089Spjd * that we know it needs to be 280219089Spjd * byteswapped. 281219089Spjd */ 282219089Spjd fletcher_4_incremental_byteswap(drr, 283219089Spjd sizeof (dmu_replay_record_t), &zc); 284219089Spjd } 285219089Spjd } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) { 286219089Spjd (void) fprintf(stderr, "Invalid stream " 287219089Spjd "(bad magic number)\n"); 288219089Spjd exit(1); 289219089Spjd } 290219089Spjd first = B_FALSE; 291219089Spjd } 292219089Spjd if (do_byteswap) { 293219089Spjd drr->drr_type = BSWAP_32(drr->drr_type); 294219089Spjd drr->drr_payloadlen = 295219089Spjd BSWAP_32(drr->drr_payloadlen); 296219089Spjd } 297219089Spjd 298219089Spjd /* 299219089Spjd * At this point, the leading fields of the replay record 300219089Spjd * (drr_type and drr_payloadlen) have been byte-swapped if 301219089Spjd * necessary, but the rest of the data structure (the 302219089Spjd * union of type-specific structures) is still in its 303219089Spjd * original state. 304219089Spjd */ 305219089Spjd if (drr->drr_type >= DRR_NUMTYPES) { 306219089Spjd (void) printf("INVALID record found: type 0x%x\n", 307219089Spjd drr->drr_type); 308219089Spjd (void) printf("Aborting.\n"); 309219089Spjd exit(1); 310219089Spjd } 311219089Spjd 312219089Spjd drr_record_count[drr->drr_type]++; 313268649Sdelphij total_records++; 314219089Spjd 315219089Spjd switch (drr->drr_type) { 316219089Spjd case DRR_BEGIN: 317219089Spjd if (do_byteswap) { 318219089Spjd drrb->drr_magic = BSWAP_64(drrb->drr_magic); 319219089Spjd drrb->drr_versioninfo = 320219089Spjd BSWAP_64(drrb->drr_versioninfo); 321219089Spjd drrb->drr_creation_time = 322219089Spjd BSWAP_64(drrb->drr_creation_time); 323219089Spjd drrb->drr_type = BSWAP_32(drrb->drr_type); 324219089Spjd drrb->drr_flags = BSWAP_32(drrb->drr_flags); 325219089Spjd drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 326219089Spjd drrb->drr_fromguid = 327219089Spjd BSWAP_64(drrb->drr_fromguid); 328219089Spjd } 329219089Spjd 330219089Spjd (void) printf("BEGIN record\n"); 331219089Spjd (void) printf("\thdrtype = %lld\n", 332219089Spjd DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo)); 333219089Spjd (void) printf("\tfeatures = %llx\n", 334219089Spjd DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo)); 335219089Spjd (void) printf("\tmagic = %llx\n", 336219089Spjd (u_longlong_t)drrb->drr_magic); 337219089Spjd (void) printf("\tcreation_time = %llx\n", 338219089Spjd (u_longlong_t)drrb->drr_creation_time); 339219089Spjd (void) printf("\ttype = %u\n", drrb->drr_type); 340219089Spjd (void) printf("\tflags = 0x%x\n", drrb->drr_flags); 341219089Spjd (void) printf("\ttoguid = %llx\n", 342219089Spjd (u_longlong_t)drrb->drr_toguid); 343219089Spjd (void) printf("\tfromguid = %llx\n", 344219089Spjd (u_longlong_t)drrb->drr_fromguid); 345219089Spjd (void) printf("\ttoname = %s\n", drrb->drr_toname); 346219089Spjd if (verbose) 347219089Spjd (void) printf("\n"); 348219089Spjd 349290756Smav if (drr->drr_payloadlen != 0) { 350219089Spjd nvlist_t *nv; 351219089Spjd int sz = drr->drr_payloadlen; 352219089Spjd 353276081Sdelphij if (sz > SPA_MAXBLOCKSIZE) { 354219089Spjd free(buf); 355276081Sdelphij buf = safe_malloc(sz); 356219089Spjd } 357219089Spjd (void) ssread(buf, sz, &zc); 358219089Spjd if (ferror(send_stream)) 359219089Spjd perror("fread"); 360219089Spjd err = nvlist_unpack(buf, sz, &nv, 0); 361219089Spjd if (err) 362219089Spjd perror(strerror(err)); 363219089Spjd nvlist_print(stdout, nv); 364219089Spjd nvlist_free(nv); 365219089Spjd } 366219089Spjd break; 367219089Spjd 368219089Spjd case DRR_END: 369219089Spjd if (do_byteswap) { 370219089Spjd drre->drr_checksum.zc_word[0] = 371219089Spjd BSWAP_64(drre->drr_checksum.zc_word[0]); 372219089Spjd drre->drr_checksum.zc_word[1] = 373219089Spjd BSWAP_64(drre->drr_checksum.zc_word[1]); 374219089Spjd drre->drr_checksum.zc_word[2] = 375219089Spjd BSWAP_64(drre->drr_checksum.zc_word[2]); 376219089Spjd drre->drr_checksum.zc_word[3] = 377219089Spjd BSWAP_64(drre->drr_checksum.zc_word[3]); 378219089Spjd } 379219089Spjd /* 380219089Spjd * We compare against the *previous* checksum 381219089Spjd * value, because the stored checksum is of 382219089Spjd * everything before the DRR_END record. 383219089Spjd */ 384219089Spjd if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum, 385219089Spjd pcksum)) { 386219089Spjd (void) printf("Expected checksum differs from " 387219089Spjd "checksum in stream.\n"); 388219089Spjd (void) printf("Expected checksum = " 389219089Spjd "%llx/%llx/%llx/%llx\n", 390219089Spjd pcksum.zc_word[0], 391219089Spjd pcksum.zc_word[1], 392219089Spjd pcksum.zc_word[2], 393219089Spjd pcksum.zc_word[3]); 394219089Spjd } 395219089Spjd (void) printf("END checksum = %llx/%llx/%llx/%llx\n", 396219089Spjd drre->drr_checksum.zc_word[0], 397219089Spjd drre->drr_checksum.zc_word[1], 398219089Spjd drre->drr_checksum.zc_word[2], 399219089Spjd drre->drr_checksum.zc_word[3]); 400219089Spjd 401219089Spjd ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); 402219089Spjd break; 403219089Spjd 404219089Spjd case DRR_OBJECT: 405219089Spjd if (do_byteswap) { 406219089Spjd drro->drr_object = BSWAP_64(drro->drr_object); 407219089Spjd drro->drr_type = BSWAP_32(drro->drr_type); 408219089Spjd drro->drr_bonustype = 409219089Spjd BSWAP_32(drro->drr_bonustype); 410219089Spjd drro->drr_blksz = BSWAP_32(drro->drr_blksz); 411219089Spjd drro->drr_bonuslen = 412219089Spjd BSWAP_32(drro->drr_bonuslen); 413219089Spjd drro->drr_toguid = BSWAP_64(drro->drr_toguid); 414219089Spjd } 415219089Spjd if (verbose) { 416219089Spjd (void) printf("OBJECT object = %llu type = %u " 417219089Spjd "bonustype = %u blksz = %u bonuslen = %u\n", 418219089Spjd (u_longlong_t)drro->drr_object, 419219089Spjd drro->drr_type, 420219089Spjd drro->drr_bonustype, 421219089Spjd drro->drr_blksz, 422219089Spjd drro->drr_bonuslen); 423219089Spjd } 424219089Spjd if (drro->drr_bonuslen > 0) { 425268649Sdelphij (void) ssread(buf, 426268649Sdelphij P2ROUNDUP(drro->drr_bonuslen, 8), &zc); 427268648Sdelphij if (dump) { 428268648Sdelphij print_block(buf, 429268648Sdelphij P2ROUNDUP(drro->drr_bonuslen, 8)); 430268648Sdelphij } 431219089Spjd } 432219089Spjd break; 433219089Spjd 434219089Spjd case DRR_FREEOBJECTS: 435219089Spjd if (do_byteswap) { 436219089Spjd drrfo->drr_firstobj = 437219089Spjd BSWAP_64(drrfo->drr_firstobj); 438219089Spjd drrfo->drr_numobjs = 439219089Spjd BSWAP_64(drrfo->drr_numobjs); 440219089Spjd drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid); 441219089Spjd } 442219089Spjd if (verbose) { 443219089Spjd (void) printf("FREEOBJECTS firstobj = %llu " 444219089Spjd "numobjs = %llu\n", 445219089Spjd (u_longlong_t)drrfo->drr_firstobj, 446219089Spjd (u_longlong_t)drrfo->drr_numobjs); 447219089Spjd } 448219089Spjd break; 449219089Spjd 450219089Spjd case DRR_WRITE: 451219089Spjd if (do_byteswap) { 452219089Spjd drrw->drr_object = BSWAP_64(drrw->drr_object); 453219089Spjd drrw->drr_type = BSWAP_32(drrw->drr_type); 454219089Spjd drrw->drr_offset = BSWAP_64(drrw->drr_offset); 455219089Spjd drrw->drr_length = BSWAP_64(drrw->drr_length); 456219089Spjd drrw->drr_toguid = BSWAP_64(drrw->drr_toguid); 457219089Spjd drrw->drr_key.ddk_prop = 458219089Spjd BSWAP_64(drrw->drr_key.ddk_prop); 459219089Spjd } 460268648Sdelphij /* 461268648Sdelphij * If this is verbose and/or dump output, 462268648Sdelphij * print info on the modified block 463268648Sdelphij */ 464219089Spjd if (verbose) { 465219089Spjd (void) printf("WRITE object = %llu type = %u " 466219089Spjd "checksum type = %u\n" 467288553Smav " offset = %llu length = %llu " 468219089Spjd "props = %llx\n", 469219089Spjd (u_longlong_t)drrw->drr_object, 470219089Spjd drrw->drr_type, 471219089Spjd drrw->drr_checksumtype, 472219089Spjd (u_longlong_t)drrw->drr_offset, 473219089Spjd (u_longlong_t)drrw->drr_length, 474219089Spjd (u_longlong_t)drrw->drr_key.ddk_prop); 475219089Spjd } 476268648Sdelphij /* 477268648Sdelphij * Read the contents of the block in from STDIN to buf 478268648Sdelphij */ 479219089Spjd (void) ssread(buf, drrw->drr_length, &zc); 480268648Sdelphij /* 481268648Sdelphij * If in dump mode 482268648Sdelphij */ 483268648Sdelphij if (dump) { 484268648Sdelphij print_block(buf, drrw->drr_length); 485268648Sdelphij } 486219089Spjd total_write_size += drrw->drr_length; 487219089Spjd break; 488219089Spjd 489219089Spjd case DRR_WRITE_BYREF: 490219089Spjd if (do_byteswap) { 491219089Spjd drrwbr->drr_object = 492219089Spjd BSWAP_64(drrwbr->drr_object); 493219089Spjd drrwbr->drr_offset = 494219089Spjd BSWAP_64(drrwbr->drr_offset); 495219089Spjd drrwbr->drr_length = 496219089Spjd BSWAP_64(drrwbr->drr_length); 497219089Spjd drrwbr->drr_toguid = 498219089Spjd BSWAP_64(drrwbr->drr_toguid); 499219089Spjd drrwbr->drr_refguid = 500219089Spjd BSWAP_64(drrwbr->drr_refguid); 501219089Spjd drrwbr->drr_refobject = 502219089Spjd BSWAP_64(drrwbr->drr_refobject); 503219089Spjd drrwbr->drr_refoffset = 504219089Spjd BSWAP_64(drrwbr->drr_refoffset); 505219089Spjd drrwbr->drr_key.ddk_prop = 506219089Spjd BSWAP_64(drrwbr->drr_key.ddk_prop); 507219089Spjd } 508219089Spjd if (verbose) { 509219089Spjd (void) printf("WRITE_BYREF object = %llu " 510219089Spjd "checksum type = %u props = %llx\n" 511288553Smav " offset = %llu length = %llu\n" 512219089Spjd "toguid = %llx refguid = %llx\n" 513288553Smav " refobject = %llu refoffset = %llu\n", 514219089Spjd (u_longlong_t)drrwbr->drr_object, 515219089Spjd drrwbr->drr_checksumtype, 516219089Spjd (u_longlong_t)drrwbr->drr_key.ddk_prop, 517219089Spjd (u_longlong_t)drrwbr->drr_offset, 518219089Spjd (u_longlong_t)drrwbr->drr_length, 519219089Spjd (u_longlong_t)drrwbr->drr_toguid, 520219089Spjd (u_longlong_t)drrwbr->drr_refguid, 521219089Spjd (u_longlong_t)drrwbr->drr_refobject, 522219089Spjd (u_longlong_t)drrwbr->drr_refoffset); 523219089Spjd } 524219089Spjd break; 525219089Spjd 526219089Spjd case DRR_FREE: 527219089Spjd if (do_byteswap) { 528219089Spjd drrf->drr_object = BSWAP_64(drrf->drr_object); 529219089Spjd drrf->drr_offset = BSWAP_64(drrf->drr_offset); 530219089Spjd drrf->drr_length = BSWAP_64(drrf->drr_length); 531219089Spjd } 532219089Spjd if (verbose) { 533219089Spjd (void) printf("FREE object = %llu " 534219089Spjd "offset = %llu length = %lld\n", 535219089Spjd (u_longlong_t)drrf->drr_object, 536219089Spjd (u_longlong_t)drrf->drr_offset, 537219089Spjd (longlong_t)drrf->drr_length); 538219089Spjd } 539219089Spjd break; 540219089Spjd case DRR_SPILL: 541219089Spjd if (do_byteswap) { 542219089Spjd drrs->drr_object = BSWAP_64(drrs->drr_object); 543219089Spjd drrs->drr_length = BSWAP_64(drrs->drr_length); 544219089Spjd } 545219089Spjd if (verbose) { 546219089Spjd (void) printf("SPILL block for object = %llu " 547219089Spjd "length = %llu\n", drrs->drr_object, 548219089Spjd drrs->drr_length); 549219089Spjd } 550219089Spjd (void) ssread(buf, drrs->drr_length, &zc); 551268648Sdelphij if (dump) { 552268648Sdelphij print_block(buf, drrs->drr_length); 553268648Sdelphij } 554219089Spjd break; 555268649Sdelphij case DRR_WRITE_EMBEDDED: 556268649Sdelphij if (do_byteswap) { 557268649Sdelphij drrwe->drr_object = 558268649Sdelphij BSWAP_64(drrwe->drr_object); 559268649Sdelphij drrwe->drr_offset = 560268649Sdelphij BSWAP_64(drrwe->drr_offset); 561268649Sdelphij drrwe->drr_length = 562268649Sdelphij BSWAP_64(drrwe->drr_length); 563268649Sdelphij drrwe->drr_toguid = 564268649Sdelphij BSWAP_64(drrwe->drr_toguid); 565268649Sdelphij drrwe->drr_lsize = 566268649Sdelphij BSWAP_32(drrwe->drr_lsize); 567268649Sdelphij drrwe->drr_psize = 568268649Sdelphij BSWAP_32(drrwe->drr_psize); 569268649Sdelphij } 570268649Sdelphij if (verbose) { 571268649Sdelphij (void) printf("WRITE_EMBEDDED object = %llu " 572268649Sdelphij "offset = %llu length = %llu\n" 573288553Smav " toguid = %llx comp = %u etype = %u " 574268649Sdelphij "lsize = %u psize = %u\n", 575268649Sdelphij (u_longlong_t)drrwe->drr_object, 576268649Sdelphij (u_longlong_t)drrwe->drr_offset, 577268649Sdelphij (u_longlong_t)drrwe->drr_length, 578268649Sdelphij (u_longlong_t)drrwe->drr_toguid, 579268649Sdelphij drrwe->drr_compression, 580268649Sdelphij drrwe->drr_etype, 581268649Sdelphij drrwe->drr_lsize, 582268649Sdelphij drrwe->drr_psize); 583268649Sdelphij } 584268649Sdelphij (void) ssread(buf, 585268649Sdelphij P2ROUNDUP(drrwe->drr_psize, 8), &zc); 586268649Sdelphij break; 587219089Spjd } 588288553Smav if (drr->drr_type != DRR_BEGIN && very_verbose) { 589288553Smav (void) printf(" checksum = %llx/%llx/%llx/%llx\n", 590288553Smav (longlong_t)drrc->drr_checksum.zc_word[0], 591288553Smav (longlong_t)drrc->drr_checksum.zc_word[1], 592288553Smav (longlong_t)drrc->drr_checksum.zc_word[2], 593288553Smav (longlong_t)drrc->drr_checksum.zc_word[3]); 594288553Smav } 595219089Spjd pcksum = zc; 596219089Spjd } 597219089Spjd free(buf); 598219089Spjd 599219089Spjd /* Print final summary */ 600219089Spjd 601219089Spjd (void) printf("SUMMARY:\n"); 602219089Spjd (void) printf("\tTotal DRR_BEGIN records = %lld\n", 603219089Spjd (u_longlong_t)drr_record_count[DRR_BEGIN]); 604219089Spjd (void) printf("\tTotal DRR_END records = %lld\n", 605219089Spjd (u_longlong_t)drr_record_count[DRR_END]); 606219089Spjd (void) printf("\tTotal DRR_OBJECT records = %lld\n", 607219089Spjd (u_longlong_t)drr_record_count[DRR_OBJECT]); 608219089Spjd (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n", 609219089Spjd (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]); 610219089Spjd (void) printf("\tTotal DRR_WRITE records = %lld\n", 611219089Spjd (u_longlong_t)drr_record_count[DRR_WRITE]); 612268649Sdelphij (void) printf("\tTotal DRR_WRITE_BYREF records = %lld\n", 613268649Sdelphij (u_longlong_t)drr_record_count[DRR_WRITE_BYREF]); 614268649Sdelphij (void) printf("\tTotal DRR_WRITE_EMBEDDED records = %lld\n", 615268649Sdelphij (u_longlong_t)drr_record_count[DRR_WRITE_EMBEDDED]); 616219089Spjd (void) printf("\tTotal DRR_FREE records = %lld\n", 617219089Spjd (u_longlong_t)drr_record_count[DRR_FREE]); 618219089Spjd (void) printf("\tTotal DRR_SPILL records = %lld\n", 619219089Spjd (u_longlong_t)drr_record_count[DRR_SPILL]); 620219089Spjd (void) printf("\tTotal records = %lld\n", 621268649Sdelphij (u_longlong_t)total_records); 622219089Spjd (void) printf("\tTotal write size = %lld (0x%llx)\n", 623219089Spjd (u_longlong_t)total_write_size, (u_longlong_t)total_write_size); 624219089Spjd (void) printf("\tTotal stream length = %lld (0x%llx)\n", 625219089Spjd (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len); 626219089Spjd return (0); 627219089Spjd} 628