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