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. 29297112Smav * Copyright (c) 2014 Integros [integros.com] 30268648Sdelphij */ 31268648Sdelphij 32268648Sdelphij#include <ctype.h> 33219089Spjd#include <libnvpair.h> 34219089Spjd#include <stdio.h> 35219089Spjd#include <stdlib.h> 36219089Spjd#include <strings.h> 37219089Spjd#include <unistd.h> 38288553Smav#include <stddef.h> 39219089Spjd 40219089Spjd#include <sys/dmu.h> 41219089Spjd#include <sys/zfs_ioctl.h> 42219089Spjd#include <zfs_fletcher.h> 43219089Spjd 44268648Sdelphij/* 45268648Sdelphij * If dump mode is enabled, the number of bytes to print per line 46268648Sdelphij */ 47268648Sdelphij#define BYTES_PER_LINE 16 48268648Sdelphij/* 49268648Sdelphij * If dump mode is enabled, the number of bytes to group together, separated 50268648Sdelphij * by newlines or spaces 51268648Sdelphij */ 52268648Sdelphij#define DUMP_GROUPING 4 53268648Sdelphij 54219089Spjduint64_t total_write_size = 0; 55219089Spjduint64_t total_stream_len = 0; 56219089SpjdFILE *send_stream = 0; 57219089Spjdboolean_t do_byteswap = B_FALSE; 58219089Spjdboolean_t do_cksum = B_TRUE; 59219089Spjd 60219089Spjdstatic void 61219089Spjdusage(void) 62219089Spjd{ 63268648Sdelphij (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] [-d] < file\n"); 64219089Spjd (void) fprintf(stderr, "\t -v -- verbose\n"); 65219089Spjd (void) fprintf(stderr, "\t -C -- suppress checksum verification\n"); 66268648Sdelphij (void) fprintf(stderr, "\t -d -- dump contents of blocks modified, " 67268648Sdelphij "implies verbose\n"); 68219089Spjd exit(1); 69219089Spjd} 70219089Spjd 71276081Sdelphijstatic void * 72276081Sdelphijsafe_malloc(size_t size) 73276081Sdelphij{ 74276081Sdelphij void *rv = malloc(size); 75276081Sdelphij if (rv == NULL) { 76276081Sdelphij (void) fprintf(stderr, "ERROR; failed to allocate %zu bytes\n", 77276081Sdelphij size); 78276081Sdelphij abort(); 79276081Sdelphij } 80276081Sdelphij return (rv); 81276081Sdelphij} 82276081Sdelphij 83219089Spjd/* 84219089Spjd * ssread - send stream read. 85219089Spjd * 86219089Spjd * Read while computing incremental checksum 87219089Spjd */ 88219089Spjdstatic size_t 89219089Spjdssread(void *buf, size_t len, zio_cksum_t *cksum) 90219089Spjd{ 91219089Spjd size_t outlen; 92219089Spjd 93219089Spjd if ((outlen = fread(buf, len, 1, send_stream)) == 0) 94219089Spjd return (0); 95219089Spjd 96288553Smav if (do_cksum) { 97219089Spjd if (do_byteswap) 98219089Spjd fletcher_4_incremental_byteswap(buf, len, cksum); 99219089Spjd else 100219089Spjd fletcher_4_incremental_native(buf, len, cksum); 101219089Spjd } 102219089Spjd total_stream_len += len; 103219089Spjd return (outlen); 104219089Spjd} 105219089Spjd 106288553Smavstatic size_t 107288553Smavread_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum) 108288553Smav{ 109288553Smav ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), 110288553Smav ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t)); 111288553Smav size_t r = ssread(drr, sizeof (*drr) - sizeof (zio_cksum_t), cksum); 112288553Smav if (r == 0) 113288553Smav return (0); 114288553Smav zio_cksum_t saved_cksum = *cksum; 115288553Smav r = ssread(&drr->drr_u.drr_checksum.drr_checksum, 116288553Smav sizeof (zio_cksum_t), cksum); 117288553Smav if (r == 0) 118288553Smav return (0); 119288553Smav if (!ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.drr_checksum.drr_checksum) && 120288553Smav !ZIO_CHECKSUM_EQUAL(saved_cksum, 121288553Smav drr->drr_u.drr_checksum.drr_checksum)) { 122288553Smav fprintf(stderr, "invalid checksum\n"); 123288553Smav (void) printf("Incorrect checksum in record header.\n"); 124288553Smav (void) printf("Expected checksum = %llx/%llx/%llx/%llx\n", 125288553Smav saved_cksum.zc_word[0], 126288553Smav saved_cksum.zc_word[1], 127288553Smav saved_cksum.zc_word[2], 128288553Smav saved_cksum.zc_word[3]); 129290756Smav return (0); 130288553Smav } 131288553Smav return (sizeof (*drr)); 132288553Smav} 133288553Smav 134268648Sdelphij/* 135268648Sdelphij * Print part of a block in ASCII characters 136268648Sdelphij */ 137268648Sdelphijstatic void 138268648Sdelphijprint_ascii_block(char *subbuf, int length) 139268648Sdelphij{ 140268648Sdelphij int i; 141268648Sdelphij 142268648Sdelphij for (i = 0; i < length; i++) { 143268648Sdelphij char char_print = isprint(subbuf[i]) ? subbuf[i] : '.'; 144268648Sdelphij if (i != 0 && i % DUMP_GROUPING == 0) { 145268648Sdelphij (void) printf(" "); 146268648Sdelphij } 147268648Sdelphij (void) printf("%c", char_print); 148268648Sdelphij } 149268648Sdelphij (void) printf("\n"); 150268648Sdelphij} 151268648Sdelphij 152268648Sdelphij/* 153268648Sdelphij * print_block - Dump the contents of a modified block to STDOUT 154268648Sdelphij * 155268648Sdelphij * Assume that buf has capacity evenly divisible by BYTES_PER_LINE 156268648Sdelphij */ 157268648Sdelphijstatic void 158268648Sdelphijprint_block(char *buf, int length) 159268648Sdelphij{ 160268648Sdelphij int i; 161268648Sdelphij /* 162268648Sdelphij * Start printing ASCII characters at a constant offset, after 163268648Sdelphij * the hex prints. Leave 3 characters per byte on a line (2 digit 164268648Sdelphij * hex number plus 1 space) plus spaces between characters and 165268649Sdelphij * groupings. 166268648Sdelphij */ 167268648Sdelphij int ascii_start = BYTES_PER_LINE * 3 + 168268648Sdelphij BYTES_PER_LINE / DUMP_GROUPING + 2; 169268648Sdelphij 170268648Sdelphij for (i = 0; i < length; i += BYTES_PER_LINE) { 171268648Sdelphij int j; 172268648Sdelphij int this_line_length = MIN(BYTES_PER_LINE, length - i); 173268648Sdelphij int print_offset = 0; 174268648Sdelphij 175268648Sdelphij for (j = 0; j < this_line_length; j++) { 176268648Sdelphij int buf_offset = i + j; 177268648Sdelphij 178268648Sdelphij /* 179268648Sdelphij * Separate every DUMP_GROUPING bytes by a space. 180268648Sdelphij */ 181268648Sdelphij if (buf_offset % DUMP_GROUPING == 0) { 182268648Sdelphij print_offset += printf(" "); 183268648Sdelphij } 184268648Sdelphij 185268648Sdelphij /* 186268648Sdelphij * Print the two-digit hex value for this byte. 187268648Sdelphij */ 188268648Sdelphij unsigned char hex_print = buf[buf_offset]; 189268648Sdelphij print_offset += printf("%02x ", hex_print); 190268648Sdelphij } 191268648Sdelphij 192268648Sdelphij (void) printf("%*s", ascii_start - print_offset, " "); 193268648Sdelphij 194268648Sdelphij print_ascii_block(buf + i, this_line_length); 195268648Sdelphij } 196268648Sdelphij} 197268648Sdelphij 198219089Spjdint 199219089Spjdmain(int argc, char *argv[]) 200219089Spjd{ 201276081Sdelphij char *buf = safe_malloc(SPA_MAXBLOCKSIZE); 202268649Sdelphij uint64_t drr_record_count[DRR_NUMTYPES] = { 0 }; 203268649Sdelphij uint64_t total_records = 0; 204219089Spjd dmu_replay_record_t thedrr; 205219089Spjd dmu_replay_record_t *drr = &thedrr; 206219089Spjd struct drr_begin *drrb = &thedrr.drr_u.drr_begin; 207219089Spjd struct drr_end *drre = &thedrr.drr_u.drr_end; 208219089Spjd struct drr_object *drro = &thedrr.drr_u.drr_object; 209219089Spjd struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects; 210219089Spjd struct drr_write *drrw = &thedrr.drr_u.drr_write; 211219089Spjd struct drr_write_byref *drrwbr = &thedrr.drr_u.drr_write_byref; 212219089Spjd struct drr_free *drrf = &thedrr.drr_u.drr_free; 213219089Spjd struct drr_spill *drrs = &thedrr.drr_u.drr_spill; 214268649Sdelphij struct drr_write_embedded *drrwe = &thedrr.drr_u.drr_write_embedded; 215288553Smav struct drr_checksum *drrc = &thedrr.drr_u.drr_checksum; 216219089Spjd char c; 217219089Spjd boolean_t verbose = B_FALSE; 218288553Smav boolean_t very_verbose = B_FALSE; 219219089Spjd boolean_t first = B_TRUE; 220268648Sdelphij /* 221268648Sdelphij * dump flag controls whether the contents of any modified data blocks 222268648Sdelphij * are printed to the console during processing of the stream. Warning: 223268648Sdelphij * for large streams, this can obviously lead to massive prints. 224268648Sdelphij */ 225268648Sdelphij boolean_t dump = B_FALSE; 226219089Spjd int err; 227219089Spjd zio_cksum_t zc = { 0 }; 228219089Spjd zio_cksum_t pcksum = { 0 }; 229219089Spjd 230268648Sdelphij while ((c = getopt(argc, argv, ":vCd")) != -1) { 231219089Spjd switch (c) { 232219089Spjd case 'C': 233219089Spjd do_cksum = B_FALSE; 234219089Spjd break; 235219089Spjd case 'v': 236288553Smav if (verbose) 237288553Smav very_verbose = B_TRUE; 238219089Spjd verbose = B_TRUE; 239219089Spjd break; 240268648Sdelphij case 'd': 241268648Sdelphij dump = B_TRUE; 242268648Sdelphij verbose = B_TRUE; 243288553Smav very_verbose = B_TRUE; 244268648Sdelphij break; 245219089Spjd case ':': 246219089Spjd (void) fprintf(stderr, 247219089Spjd "missing argument for '%c' option\n", optopt); 248219089Spjd usage(); 249219089Spjd break; 250219089Spjd case '?': 251219089Spjd (void) fprintf(stderr, "invalid option '%c'\n", 252219089Spjd optopt); 253219089Spjd usage(); 254219089Spjd } 255219089Spjd } 256219089Spjd 257219089Spjd if (isatty(STDIN_FILENO)) { 258219089Spjd (void) fprintf(stderr, 259219089Spjd "Error: Backup stream can not be read " 260219089Spjd "from a terminal.\n" 261219089Spjd "You must redirect standard input.\n"); 262219089Spjd exit(1); 263219089Spjd } 264219089Spjd 265219089Spjd send_stream = stdin; 266219089Spjd pcksum = zc; 267288553Smav while (read_hdr(drr, &zc)) { 268219089Spjd 269268648Sdelphij /* 270268648Sdelphij * If this is the first DMU record being processed, check for 271268648Sdelphij * the magic bytes and figure out the endian-ness based on them. 272268648Sdelphij */ 273219089Spjd if (first) { 274219089Spjd if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { 275219089Spjd do_byteswap = B_TRUE; 276219089Spjd if (do_cksum) { 277219089Spjd ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); 278219089Spjd /* 279219089Spjd * recalculate header checksum now 280219089Spjd * that we know it needs to be 281219089Spjd * byteswapped. 282219089Spjd */ 283219089Spjd fletcher_4_incremental_byteswap(drr, 284219089Spjd sizeof (dmu_replay_record_t), &zc); 285219089Spjd } 286219089Spjd } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) { 287219089Spjd (void) fprintf(stderr, "Invalid stream " 288219089Spjd "(bad magic number)\n"); 289219089Spjd exit(1); 290219089Spjd } 291219089Spjd first = B_FALSE; 292219089Spjd } 293219089Spjd if (do_byteswap) { 294219089Spjd drr->drr_type = BSWAP_32(drr->drr_type); 295219089Spjd drr->drr_payloadlen = 296219089Spjd BSWAP_32(drr->drr_payloadlen); 297219089Spjd } 298219089Spjd 299219089Spjd /* 300219089Spjd * At this point, the leading fields of the replay record 301219089Spjd * (drr_type and drr_payloadlen) have been byte-swapped if 302219089Spjd * necessary, but the rest of the data structure (the 303219089Spjd * union of type-specific structures) is still in its 304219089Spjd * original state. 305219089Spjd */ 306219089Spjd if (drr->drr_type >= DRR_NUMTYPES) { 307219089Spjd (void) printf("INVALID record found: type 0x%x\n", 308219089Spjd drr->drr_type); 309219089Spjd (void) printf("Aborting.\n"); 310219089Spjd exit(1); 311219089Spjd } 312219089Spjd 313219089Spjd drr_record_count[drr->drr_type]++; 314268649Sdelphij total_records++; 315219089Spjd 316219089Spjd switch (drr->drr_type) { 317219089Spjd case DRR_BEGIN: 318219089Spjd if (do_byteswap) { 319219089Spjd drrb->drr_magic = BSWAP_64(drrb->drr_magic); 320219089Spjd drrb->drr_versioninfo = 321219089Spjd BSWAP_64(drrb->drr_versioninfo); 322219089Spjd drrb->drr_creation_time = 323219089Spjd BSWAP_64(drrb->drr_creation_time); 324219089Spjd drrb->drr_type = BSWAP_32(drrb->drr_type); 325219089Spjd drrb->drr_flags = BSWAP_32(drrb->drr_flags); 326219089Spjd drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 327219089Spjd drrb->drr_fromguid = 328219089Spjd BSWAP_64(drrb->drr_fromguid); 329219089Spjd } 330219089Spjd 331219089Spjd (void) printf("BEGIN record\n"); 332219089Spjd (void) printf("\thdrtype = %lld\n", 333219089Spjd DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo)); 334219089Spjd (void) printf("\tfeatures = %llx\n", 335219089Spjd DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo)); 336219089Spjd (void) printf("\tmagic = %llx\n", 337219089Spjd (u_longlong_t)drrb->drr_magic); 338219089Spjd (void) printf("\tcreation_time = %llx\n", 339219089Spjd (u_longlong_t)drrb->drr_creation_time); 340219089Spjd (void) printf("\ttype = %u\n", drrb->drr_type); 341219089Spjd (void) printf("\tflags = 0x%x\n", drrb->drr_flags); 342219089Spjd (void) printf("\ttoguid = %llx\n", 343219089Spjd (u_longlong_t)drrb->drr_toguid); 344219089Spjd (void) printf("\tfromguid = %llx\n", 345219089Spjd (u_longlong_t)drrb->drr_fromguid); 346219089Spjd (void) printf("\ttoname = %s\n", drrb->drr_toname); 347219089Spjd if (verbose) 348219089Spjd (void) printf("\n"); 349219089Spjd 350290756Smav if (drr->drr_payloadlen != 0) { 351219089Spjd nvlist_t *nv; 352219089Spjd int sz = drr->drr_payloadlen; 353219089Spjd 354276081Sdelphij if (sz > SPA_MAXBLOCKSIZE) { 355219089Spjd free(buf); 356276081Sdelphij buf = safe_malloc(sz); 357219089Spjd } 358219089Spjd (void) ssread(buf, sz, &zc); 359219089Spjd if (ferror(send_stream)) 360219089Spjd perror("fread"); 361219089Spjd err = nvlist_unpack(buf, sz, &nv, 0); 362219089Spjd if (err) 363219089Spjd perror(strerror(err)); 364219089Spjd nvlist_print(stdout, nv); 365219089Spjd nvlist_free(nv); 366219089Spjd } 367219089Spjd break; 368219089Spjd 369219089Spjd case DRR_END: 370219089Spjd if (do_byteswap) { 371219089Spjd drre->drr_checksum.zc_word[0] = 372219089Spjd BSWAP_64(drre->drr_checksum.zc_word[0]); 373219089Spjd drre->drr_checksum.zc_word[1] = 374219089Spjd BSWAP_64(drre->drr_checksum.zc_word[1]); 375219089Spjd drre->drr_checksum.zc_word[2] = 376219089Spjd BSWAP_64(drre->drr_checksum.zc_word[2]); 377219089Spjd drre->drr_checksum.zc_word[3] = 378219089Spjd BSWAP_64(drre->drr_checksum.zc_word[3]); 379219089Spjd } 380219089Spjd /* 381219089Spjd * We compare against the *previous* checksum 382219089Spjd * value, because the stored checksum is of 383219089Spjd * everything before the DRR_END record. 384219089Spjd */ 385219089Spjd if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum, 386219089Spjd pcksum)) { 387219089Spjd (void) printf("Expected checksum differs from " 388219089Spjd "checksum in stream.\n"); 389219089Spjd (void) printf("Expected checksum = " 390219089Spjd "%llx/%llx/%llx/%llx\n", 391219089Spjd pcksum.zc_word[0], 392219089Spjd pcksum.zc_word[1], 393219089Spjd pcksum.zc_word[2], 394219089Spjd pcksum.zc_word[3]); 395219089Spjd } 396219089Spjd (void) printf("END checksum = %llx/%llx/%llx/%llx\n", 397219089Spjd drre->drr_checksum.zc_word[0], 398219089Spjd drre->drr_checksum.zc_word[1], 399219089Spjd drre->drr_checksum.zc_word[2], 400219089Spjd drre->drr_checksum.zc_word[3]); 401219089Spjd 402219089Spjd ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); 403219089Spjd break; 404219089Spjd 405219089Spjd case DRR_OBJECT: 406219089Spjd if (do_byteswap) { 407219089Spjd drro->drr_object = BSWAP_64(drro->drr_object); 408219089Spjd drro->drr_type = BSWAP_32(drro->drr_type); 409219089Spjd drro->drr_bonustype = 410219089Spjd BSWAP_32(drro->drr_bonustype); 411219089Spjd drro->drr_blksz = BSWAP_32(drro->drr_blksz); 412219089Spjd drro->drr_bonuslen = 413219089Spjd BSWAP_32(drro->drr_bonuslen); 414219089Spjd drro->drr_toguid = BSWAP_64(drro->drr_toguid); 415219089Spjd } 416219089Spjd if (verbose) { 417219089Spjd (void) printf("OBJECT object = %llu type = %u " 418219089Spjd "bonustype = %u blksz = %u bonuslen = %u\n", 419219089Spjd (u_longlong_t)drro->drr_object, 420219089Spjd drro->drr_type, 421219089Spjd drro->drr_bonustype, 422219089Spjd drro->drr_blksz, 423219089Spjd drro->drr_bonuslen); 424219089Spjd } 425219089Spjd if (drro->drr_bonuslen > 0) { 426268649Sdelphij (void) ssread(buf, 427268649Sdelphij P2ROUNDUP(drro->drr_bonuslen, 8), &zc); 428268648Sdelphij if (dump) { 429268648Sdelphij print_block(buf, 430268648Sdelphij P2ROUNDUP(drro->drr_bonuslen, 8)); 431268648Sdelphij } 432219089Spjd } 433219089Spjd break; 434219089Spjd 435219089Spjd case DRR_FREEOBJECTS: 436219089Spjd if (do_byteswap) { 437219089Spjd drrfo->drr_firstobj = 438219089Spjd BSWAP_64(drrfo->drr_firstobj); 439219089Spjd drrfo->drr_numobjs = 440219089Spjd BSWAP_64(drrfo->drr_numobjs); 441219089Spjd drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid); 442219089Spjd } 443219089Spjd if (verbose) { 444219089Spjd (void) printf("FREEOBJECTS firstobj = %llu " 445219089Spjd "numobjs = %llu\n", 446219089Spjd (u_longlong_t)drrfo->drr_firstobj, 447219089Spjd (u_longlong_t)drrfo->drr_numobjs); 448219089Spjd } 449219089Spjd break; 450219089Spjd 451219089Spjd case DRR_WRITE: 452219089Spjd if (do_byteswap) { 453219089Spjd drrw->drr_object = BSWAP_64(drrw->drr_object); 454219089Spjd drrw->drr_type = BSWAP_32(drrw->drr_type); 455219089Spjd drrw->drr_offset = BSWAP_64(drrw->drr_offset); 456219089Spjd drrw->drr_length = BSWAP_64(drrw->drr_length); 457219089Spjd drrw->drr_toguid = BSWAP_64(drrw->drr_toguid); 458219089Spjd drrw->drr_key.ddk_prop = 459219089Spjd BSWAP_64(drrw->drr_key.ddk_prop); 460219089Spjd } 461268648Sdelphij /* 462268648Sdelphij * If this is verbose and/or dump output, 463268648Sdelphij * print info on the modified block 464268648Sdelphij */ 465219089Spjd if (verbose) { 466219089Spjd (void) printf("WRITE object = %llu type = %u " 467219089Spjd "checksum type = %u\n" 468288553Smav " offset = %llu length = %llu " 469219089Spjd "props = %llx\n", 470219089Spjd (u_longlong_t)drrw->drr_object, 471219089Spjd drrw->drr_type, 472219089Spjd drrw->drr_checksumtype, 473219089Spjd (u_longlong_t)drrw->drr_offset, 474219089Spjd (u_longlong_t)drrw->drr_length, 475219089Spjd (u_longlong_t)drrw->drr_key.ddk_prop); 476219089Spjd } 477268648Sdelphij /* 478268648Sdelphij * Read the contents of the block in from STDIN to buf 479268648Sdelphij */ 480219089Spjd (void) ssread(buf, drrw->drr_length, &zc); 481268648Sdelphij /* 482268648Sdelphij * If in dump mode 483268648Sdelphij */ 484268648Sdelphij if (dump) { 485268648Sdelphij print_block(buf, drrw->drr_length); 486268648Sdelphij } 487219089Spjd total_write_size += drrw->drr_length; 488219089Spjd break; 489219089Spjd 490219089Spjd case DRR_WRITE_BYREF: 491219089Spjd if (do_byteswap) { 492219089Spjd drrwbr->drr_object = 493219089Spjd BSWAP_64(drrwbr->drr_object); 494219089Spjd drrwbr->drr_offset = 495219089Spjd BSWAP_64(drrwbr->drr_offset); 496219089Spjd drrwbr->drr_length = 497219089Spjd BSWAP_64(drrwbr->drr_length); 498219089Spjd drrwbr->drr_toguid = 499219089Spjd BSWAP_64(drrwbr->drr_toguid); 500219089Spjd drrwbr->drr_refguid = 501219089Spjd BSWAP_64(drrwbr->drr_refguid); 502219089Spjd drrwbr->drr_refobject = 503219089Spjd BSWAP_64(drrwbr->drr_refobject); 504219089Spjd drrwbr->drr_refoffset = 505219089Spjd BSWAP_64(drrwbr->drr_refoffset); 506219089Spjd drrwbr->drr_key.ddk_prop = 507219089Spjd BSWAP_64(drrwbr->drr_key.ddk_prop); 508219089Spjd } 509219089Spjd if (verbose) { 510219089Spjd (void) printf("WRITE_BYREF object = %llu " 511219089Spjd "checksum type = %u props = %llx\n" 512288553Smav " offset = %llu length = %llu\n" 513219089Spjd "toguid = %llx refguid = %llx\n" 514288553Smav " refobject = %llu refoffset = %llu\n", 515219089Spjd (u_longlong_t)drrwbr->drr_object, 516219089Spjd drrwbr->drr_checksumtype, 517219089Spjd (u_longlong_t)drrwbr->drr_key.ddk_prop, 518219089Spjd (u_longlong_t)drrwbr->drr_offset, 519219089Spjd (u_longlong_t)drrwbr->drr_length, 520219089Spjd (u_longlong_t)drrwbr->drr_toguid, 521219089Spjd (u_longlong_t)drrwbr->drr_refguid, 522219089Spjd (u_longlong_t)drrwbr->drr_refobject, 523219089Spjd (u_longlong_t)drrwbr->drr_refoffset); 524219089Spjd } 525219089Spjd break; 526219089Spjd 527219089Spjd case DRR_FREE: 528219089Spjd if (do_byteswap) { 529219089Spjd drrf->drr_object = BSWAP_64(drrf->drr_object); 530219089Spjd drrf->drr_offset = BSWAP_64(drrf->drr_offset); 531219089Spjd drrf->drr_length = BSWAP_64(drrf->drr_length); 532219089Spjd } 533219089Spjd if (verbose) { 534219089Spjd (void) printf("FREE object = %llu " 535219089Spjd "offset = %llu length = %lld\n", 536219089Spjd (u_longlong_t)drrf->drr_object, 537219089Spjd (u_longlong_t)drrf->drr_offset, 538219089Spjd (longlong_t)drrf->drr_length); 539219089Spjd } 540219089Spjd break; 541219089Spjd case DRR_SPILL: 542219089Spjd if (do_byteswap) { 543219089Spjd drrs->drr_object = BSWAP_64(drrs->drr_object); 544219089Spjd drrs->drr_length = BSWAP_64(drrs->drr_length); 545219089Spjd } 546219089Spjd if (verbose) { 547219089Spjd (void) printf("SPILL block for object = %llu " 548219089Spjd "length = %llu\n", drrs->drr_object, 549219089Spjd drrs->drr_length); 550219089Spjd } 551219089Spjd (void) ssread(buf, drrs->drr_length, &zc); 552268648Sdelphij if (dump) { 553268648Sdelphij print_block(buf, drrs->drr_length); 554268648Sdelphij } 555219089Spjd break; 556268649Sdelphij case DRR_WRITE_EMBEDDED: 557268649Sdelphij if (do_byteswap) { 558268649Sdelphij drrwe->drr_object = 559268649Sdelphij BSWAP_64(drrwe->drr_object); 560268649Sdelphij drrwe->drr_offset = 561268649Sdelphij BSWAP_64(drrwe->drr_offset); 562268649Sdelphij drrwe->drr_length = 563268649Sdelphij BSWAP_64(drrwe->drr_length); 564268649Sdelphij drrwe->drr_toguid = 565268649Sdelphij BSWAP_64(drrwe->drr_toguid); 566268649Sdelphij drrwe->drr_lsize = 567268649Sdelphij BSWAP_32(drrwe->drr_lsize); 568268649Sdelphij drrwe->drr_psize = 569268649Sdelphij BSWAP_32(drrwe->drr_psize); 570268649Sdelphij } 571268649Sdelphij if (verbose) { 572268649Sdelphij (void) printf("WRITE_EMBEDDED object = %llu " 573268649Sdelphij "offset = %llu length = %llu\n" 574288553Smav " toguid = %llx comp = %u etype = %u " 575268649Sdelphij "lsize = %u psize = %u\n", 576268649Sdelphij (u_longlong_t)drrwe->drr_object, 577268649Sdelphij (u_longlong_t)drrwe->drr_offset, 578268649Sdelphij (u_longlong_t)drrwe->drr_length, 579268649Sdelphij (u_longlong_t)drrwe->drr_toguid, 580268649Sdelphij drrwe->drr_compression, 581268649Sdelphij drrwe->drr_etype, 582268649Sdelphij drrwe->drr_lsize, 583268649Sdelphij drrwe->drr_psize); 584268649Sdelphij } 585268649Sdelphij (void) ssread(buf, 586268649Sdelphij P2ROUNDUP(drrwe->drr_psize, 8), &zc); 587268649Sdelphij break; 588219089Spjd } 589288553Smav if (drr->drr_type != DRR_BEGIN && very_verbose) { 590288553Smav (void) printf(" checksum = %llx/%llx/%llx/%llx\n", 591288553Smav (longlong_t)drrc->drr_checksum.zc_word[0], 592288553Smav (longlong_t)drrc->drr_checksum.zc_word[1], 593288553Smav (longlong_t)drrc->drr_checksum.zc_word[2], 594288553Smav (longlong_t)drrc->drr_checksum.zc_word[3]); 595288553Smav } 596219089Spjd pcksum = zc; 597219089Spjd } 598219089Spjd free(buf); 599219089Spjd 600219089Spjd /* Print final summary */ 601219089Spjd 602219089Spjd (void) printf("SUMMARY:\n"); 603219089Spjd (void) printf("\tTotal DRR_BEGIN records = %lld\n", 604219089Spjd (u_longlong_t)drr_record_count[DRR_BEGIN]); 605219089Spjd (void) printf("\tTotal DRR_END records = %lld\n", 606219089Spjd (u_longlong_t)drr_record_count[DRR_END]); 607219089Spjd (void) printf("\tTotal DRR_OBJECT records = %lld\n", 608219089Spjd (u_longlong_t)drr_record_count[DRR_OBJECT]); 609219089Spjd (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n", 610219089Spjd (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]); 611219089Spjd (void) printf("\tTotal DRR_WRITE records = %lld\n", 612219089Spjd (u_longlong_t)drr_record_count[DRR_WRITE]); 613268649Sdelphij (void) printf("\tTotal DRR_WRITE_BYREF records = %lld\n", 614268649Sdelphij (u_longlong_t)drr_record_count[DRR_WRITE_BYREF]); 615268649Sdelphij (void) printf("\tTotal DRR_WRITE_EMBEDDED records = %lld\n", 616268649Sdelphij (u_longlong_t)drr_record_count[DRR_WRITE_EMBEDDED]); 617219089Spjd (void) printf("\tTotal DRR_FREE records = %lld\n", 618219089Spjd (u_longlong_t)drr_record_count[DRR_FREE]); 619219089Spjd (void) printf("\tTotal DRR_SPILL records = %lld\n", 620219089Spjd (u_longlong_t)drr_record_count[DRR_SPILL]); 621219089Spjd (void) printf("\tTotal records = %lld\n", 622268649Sdelphij (u_longlong_t)total_records); 623219089Spjd (void) printf("\tTotal write size = %lld (0x%llx)\n", 624219089Spjd (u_longlong_t)total_write_size, (u_longlong_t)total_write_size); 625219089Spjd (void) printf("\tTotal stream length = %lld (0x%llx)\n", 626219089Spjd (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len); 627219089Spjd return (0); 628219089Spjd} 629