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 char 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 send_stream = stdin; 290 while (read_hdr(drr, &zc)) { 291 292 /* 293 * If this is the first DMU record being processed, check for 294 * the magic bytes and figure out the endian-ness based on them. 295 */ 296 if (first) { 297 if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { 298 do_byteswap = B_TRUE; 299 if (do_cksum) { 300 ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); 301 /* 302 * recalculate header checksum now 303 * that we know it needs to be 304 * byteswapped. 305 */ 306 fletcher_4_incremental_byteswap(drr, 307 sizeof (dmu_replay_record_t), &zc); 308 } 309 } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) { 310 (void) fprintf(stderr, "Invalid stream " 311 "(bad magic number)\n"); 312 exit(1); 313 } 314 first = B_FALSE; 315 } 316 if (do_byteswap) { 317 drr->drr_type = BSWAP_32(drr->drr_type); 318 drr->drr_payloadlen = 319 BSWAP_32(drr->drr_payloadlen); 320 } 321 322 /* 323 * At this point, the leading fields of the replay record 324 * (drr_type and drr_payloadlen) have been byte-swapped if 325 * necessary, but the rest of the data structure (the 326 * union of type-specific structures) is still in its 327 * original state. 328 */ 329 if (drr->drr_type >= DRR_NUMTYPES) { 330 (void) printf("INVALID record found: type 0x%x\n", 331 drr->drr_type); 332 (void) printf("Aborting.\n"); 333 exit(1); 334 } 335 336 drr_record_count[drr->drr_type]++; 337 total_records++; 338 339 switch (drr->drr_type) { 340 case DRR_BEGIN: 341 if (do_byteswap) { 342 drrb->drr_magic = BSWAP_64(drrb->drr_magic); 343 drrb->drr_versioninfo = 344 BSWAP_64(drrb->drr_versioninfo); 345 drrb->drr_creation_time = 346 BSWAP_64(drrb->drr_creation_time); 347 drrb->drr_type = BSWAP_32(drrb->drr_type); 348 drrb->drr_flags = BSWAP_32(drrb->drr_flags); 349 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 350 drrb->drr_fromguid = 351 BSWAP_64(drrb->drr_fromguid); 352 } 353 354 (void) printf("BEGIN record\n"); 355 (void) printf("\thdrtype = %lld\n", 356 DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo)); 357 (void) printf("\tfeatures = %llx\n", 358 DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo)); 359 (void) printf("\tmagic = %llx\n", 360 (u_longlong_t)drrb->drr_magic); 361 (void) printf("\tcreation_time = %llx\n", 362 (u_longlong_t)drrb->drr_creation_time); 363 (void) printf("\ttype = %u\n", drrb->drr_type); 364 (void) printf("\tflags = 0x%x\n", drrb->drr_flags); 365 (void) printf("\ttoguid = %llx\n", 366 (u_longlong_t)drrb->drr_toguid); 367 (void) printf("\tfromguid = %llx\n", 368 (u_longlong_t)drrb->drr_fromguid); 369 (void) printf("\ttoname = %s\n", drrb->drr_toname); 370 if (verbose) 371 (void) printf("\n"); 372 373 if (drr->drr_payloadlen != 0) { 374 nvlist_t *nv; 375 int sz = drr->drr_payloadlen; 376 377 if (sz > SPA_MAXBLOCKSIZE) { 378 free(buf); 379 buf = safe_malloc(sz); 380 } 381 (void) ssread(buf, sz, &zc); 382 if (ferror(send_stream)) 383 perror("fread"); 384 err = nvlist_unpack(buf, sz, &nv, 0); 385 if (err) 386 perror(strerror(err)); 387 nvlist_print(stdout, nv); 388 nvlist_free(nv); 389 } 390 break; 391 392 case DRR_END: 393 if (do_byteswap) { 394 drre->drr_checksum.zc_word[0] = 395 BSWAP_64(drre->drr_checksum.zc_word[0]); 396 drre->drr_checksum.zc_word[1] = 397 BSWAP_64(drre->drr_checksum.zc_word[1]); 398 drre->drr_checksum.zc_word[2] = 399 BSWAP_64(drre->drr_checksum.zc_word[2]); 400 drre->drr_checksum.zc_word[3] = 401 BSWAP_64(drre->drr_checksum.zc_word[3]); 402 } 403 /* 404 * We compare against the *previous* checksum 405 * value, because the stored checksum is of 406 * everything before the DRR_END record. 407 */ 408 if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum, 409 pcksum)) { 410 (void) printf("Expected checksum differs from " 411 "checksum in stream.\n"); 412 (void) printf("Expected checksum = " 413 "%llx/%llx/%llx/%llx\n", 414 pcksum.zc_word[0], 415 pcksum.zc_word[1], 416 pcksum.zc_word[2], 417 pcksum.zc_word[3]); 418 } 419 (void) printf("END checksum = %llx/%llx/%llx/%llx\n", 420 drre->drr_checksum.zc_word[0], 421 drre->drr_checksum.zc_word[1], 422 drre->drr_checksum.zc_word[2], 423 drre->drr_checksum.zc_word[3]); 424 425 ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); 426 break; 427 428 case DRR_OBJECT: 429 if (do_byteswap) { 430 drro->drr_object = BSWAP_64(drro->drr_object); 431 drro->drr_type = BSWAP_32(drro->drr_type); 432 drro->drr_bonustype = 433 BSWAP_32(drro->drr_bonustype); 434 drro->drr_blksz = BSWAP_32(drro->drr_blksz); 435 drro->drr_bonuslen = 436 BSWAP_32(drro->drr_bonuslen); 437 drro->drr_raw_bonuslen = 438 BSWAP_32(drro->drr_raw_bonuslen); 439 drro->drr_toguid = BSWAP_64(drro->drr_toguid); 440 } 441 442 payload_size = DRR_OBJECT_PAYLOAD_SIZE(drro); 443 444 if (verbose) { 445 (void) printf("OBJECT object = %" PRIu64 446 "type = %u bonustype = %u blksz = %u " 447 "bonuslen = %u " 448 "raw_bonuslen = %u flags = %u maxblkid " 449 "= %llu " 450 "indblkshift = %u nlevels = %u " 451 "nblkptr = %u\n", 452 (u_longlong_t)drro->drr_object, 453 drro->drr_type, 454 drro->drr_bonustype, 455 drro->drr_blksz, 456 drro->drr_bonuslen, 457 drro->drr_raw_bonuslen, 458 drro->drr_flags, 459 (u_longlong_t)drro->drr_maxblkid, 460 drro->drr_indblkshift, 461 drro->drr_nlevels, 462 drro->drr_nblkptr); 463 } 464 if (drro->drr_bonuslen > 0) { 465 (void) ssread(buf, payload_size, &zc); 466 if (dump) 467 print_block(buf, payload_size); 468 } 469 break; 470 471 case DRR_FREEOBJECTS: 472 if (do_byteswap) { 473 drrfo->drr_firstobj = 474 BSWAP_64(drrfo->drr_firstobj); 475 drrfo->drr_numobjs = 476 BSWAP_64(drrfo->drr_numobjs); 477 drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid); 478 } 479 if (verbose) { 480 (void) printf("FREEOBJECTS firstobj = %llu " 481 "numobjs = %llu\n", 482 (u_longlong_t)drrfo->drr_firstobj, 483 (u_longlong_t)drrfo->drr_numobjs); 484 } 485 break; 486 487 case DRR_WRITE: 488 if (do_byteswap) { 489 drrw->drr_object = BSWAP_64(drrw->drr_object); 490 drrw->drr_type = BSWAP_32(drrw->drr_type); 491 drrw->drr_offset = BSWAP_64(drrw->drr_offset); 492 drrw->drr_logical_size = 493 BSWAP_64(drrw->drr_logical_size); 494 drrw->drr_toguid = BSWAP_64(drrw->drr_toguid); 495 drrw->drr_key.ddk_prop = 496 BSWAP_64(drrw->drr_key.ddk_prop); 497 drrw->drr_compressed_size = 498 BSWAP_64(drrw->drr_compressed_size); 499 } 500 501 payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw); 502 503 /* 504 * If this is verbose and/or dump output, 505 * print info on the modified block 506 */ 507 if (verbose) { 508 sprintf_bytes(salt, drrw->drr_salt, 509 ZIO_DATA_SALT_LEN); 510 sprintf_bytes(iv, drrw->drr_iv, 511 ZIO_DATA_IV_LEN); 512 sprintf_bytes(mac, drrw->drr_mac, 513 ZIO_DATA_MAC_LEN); 514 515 (void) printf("WRITE object = %llu type = %u " 516 "checksum type = %u compression type = %u\n" 517 " flags = %u offset = %llu " 518 "logical_size = %llu " 519 "compressed_size = %llu " 520 "payload_size = %llu props = %llx " 521 "salt = %s iv = %s mac = %s\n", 522 (u_longlong_t)drrw->drr_object, 523 drrw->drr_type, 524 drrw->drr_checksumtype, 525 drrw->drr_compressiontype, 526 drrw->drr_flags, 527 (u_longlong_t)drrw->drr_offset, 528 (u_longlong_t)drrw->drr_logical_size, 529 (u_longlong_t)drrw->drr_compressed_size, 530 (u_longlong_t)payload_size, 531 (u_longlong_t)drrw->drr_key.ddk_prop, 532 salt, 533 iv, 534 mac); 535 } 536 537 /* 538 * Read the contents of the block in from STDIN to buf 539 */ 540 (void) ssread(buf, payload_size, &zc); 541 /* 542 * If in dump mode 543 */ 544 if (dump) { 545 print_block(buf, payload_size); 546 } 547 total_write_size += payload_size; 548 break; 549 550 case DRR_WRITE_BYREF: 551 if (do_byteswap) { 552 drrwbr->drr_object = 553 BSWAP_64(drrwbr->drr_object); 554 drrwbr->drr_offset = 555 BSWAP_64(drrwbr->drr_offset); 556 drrwbr->drr_length = 557 BSWAP_64(drrwbr->drr_length); 558 drrwbr->drr_toguid = 559 BSWAP_64(drrwbr->drr_toguid); 560 drrwbr->drr_refguid = 561 BSWAP_64(drrwbr->drr_refguid); 562 drrwbr->drr_refobject = 563 BSWAP_64(drrwbr->drr_refobject); 564 drrwbr->drr_refoffset = 565 BSWAP_64(drrwbr->drr_refoffset); 566 drrwbr->drr_key.ddk_prop = 567 BSWAP_64(drrwbr->drr_key.ddk_prop); 568 } 569 if (verbose) { 570 (void) printf("WRITE_BYREF object = %llu " 571 "checksum type = %u props = %llx\n" 572 " offset = %llu length = %llu\n" 573 "toguid = %llx refguid = %llx\n" 574 " refobject = %llu refoffset = %llu\n", 575 (u_longlong_t)drrwbr->drr_object, 576 drrwbr->drr_checksumtype, 577 (u_longlong_t)drrwbr->drr_key.ddk_prop, 578 (u_longlong_t)drrwbr->drr_offset, 579 (u_longlong_t)drrwbr->drr_length, 580 (u_longlong_t)drrwbr->drr_toguid, 581 (u_longlong_t)drrwbr->drr_refguid, 582 (u_longlong_t)drrwbr->drr_refobject, 583 (u_longlong_t)drrwbr->drr_refoffset); 584 } 585 break; 586 587 case DRR_FREE: 588 if (do_byteswap) { 589 drrf->drr_object = BSWAP_64(drrf->drr_object); 590 drrf->drr_offset = BSWAP_64(drrf->drr_offset); 591 drrf->drr_length = BSWAP_64(drrf->drr_length); 592 } 593 if (verbose) { 594 (void) printf("FREE object = %llu " 595 "offset = %llu length = %lld\n", 596 (u_longlong_t)drrf->drr_object, 597 (u_longlong_t)drrf->drr_offset, 598 (longlong_t)drrf->drr_length); 599 } 600 break; 601 case DRR_SPILL: 602 if (do_byteswap) { 603 drrs->drr_object = BSWAP_64(drrs->drr_object); 604 drrs->drr_length = BSWAP_64(drrs->drr_length); 605 drrs->drr_compressed_size = 606 BSWAP_64(drrs->drr_compressed_size); 607 drrs->drr_type = BSWAP_32(drrs->drr_type); 608 } 609 610 payload_size = DRR_SPILL_PAYLOAD_SIZE(drrs); 611 612 if (verbose) { 613 sprintf_bytes(salt, drrs->drr_salt, 614 ZIO_DATA_SALT_LEN); 615 sprintf_bytes(iv, drrs->drr_iv, 616 ZIO_DATA_IV_LEN); 617 sprintf_bytes(mac, drrs->drr_mac, 618 ZIO_DATA_MAC_LEN); 619 620 (void) printf("SPILL block for object = %llu " 621 "length = %llu flags = %u " 622 "compression type = %u " 623 "compressed_size = %llu " 624 "payload_size = %llu " 625 "salt = %s iv = %s mac = %s\n", 626 (u_longlong_t)drrs->drr_object, 627 (u_longlong_t)drrs->drr_length, 628 drrs->drr_flags, 629 drrs->drr_compressiontype, 630 (u_longlong_t)drrs->drr_compressed_size, 631 (u_longlong_t)payload_size, 632 salt, 633 iv, 634 mac); 635 } 636 (void) ssread(buf, payload_size, &zc); 637 if (dump) { 638 print_block(buf, payload_size); 639 } 640 break; 641 case DRR_WRITE_EMBEDDED: 642 if (do_byteswap) { 643 drrwe->drr_object = 644 BSWAP_64(drrwe->drr_object); 645 drrwe->drr_offset = 646 BSWAP_64(drrwe->drr_offset); 647 drrwe->drr_length = 648 BSWAP_64(drrwe->drr_length); 649 drrwe->drr_toguid = 650 BSWAP_64(drrwe->drr_toguid); 651 drrwe->drr_lsize = 652 BSWAP_32(drrwe->drr_lsize); 653 drrwe->drr_psize = 654 BSWAP_32(drrwe->drr_psize); 655 } 656 if (verbose) { 657 (void) printf("WRITE_EMBEDDED object = %llu " 658 "offset = %llu length = %llu\n" 659 " toguid = %llx comp = %u etype = %u " 660 "lsize = %u psize = %u\n", 661 (u_longlong_t)drrwe->drr_object, 662 (u_longlong_t)drrwe->drr_offset, 663 (u_longlong_t)drrwe->drr_length, 664 (u_longlong_t)drrwe->drr_toguid, 665 drrwe->drr_compression, 666 drrwe->drr_etype, 667 drrwe->drr_lsize, 668 drrwe->drr_psize); 669 } 670 (void) ssread(buf, 671 P2ROUNDUP(drrwe->drr_psize, 8), &zc); 672 break; 673 case DRR_OBJECT_RANGE: 674 if (do_byteswap) { 675 drror->drr_firstobj = 676 BSWAP_64(drror->drr_firstobj); 677 drror->drr_numslots = 678 BSWAP_64(drror->drr_numslots); 679 drror->drr_toguid = BSWAP_64(drror->drr_toguid); 680 } 681 if (verbose) { 682 sprintf_bytes(salt, drror->drr_salt, 683 ZIO_DATA_SALT_LEN); 684 sprintf_bytes(iv, drror->drr_iv, 685 ZIO_DATA_IV_LEN); 686 sprintf_bytes(mac, drror->drr_mac, 687 ZIO_DATA_MAC_LEN); 688 689 (void) printf("OBJECT_RANGE firstobj = %llu " 690 "numslots = %llu flags = %u " 691 "salt = %s iv = %s mac = %s\n", 692 (u_longlong_t)drror->drr_firstobj, 693 (u_longlong_t)drror->drr_numslots, 694 drror->drr_flags, 695 salt, 696 iv, 697 mac); 698 } 699 break; 700 case DRR_NUMTYPES: 701 /* should never be reached */ 702 exit(1); 703 } 704 if (drr->drr_type != DRR_BEGIN && very_verbose) { 705 (void) printf(" checksum = %llx/%llx/%llx/%llx\n", 706 (longlong_t)drrc->drr_checksum.zc_word[0], 707 (longlong_t)drrc->drr_checksum.zc_word[1], 708 (longlong_t)drrc->drr_checksum.zc_word[2], 709 (longlong_t)drrc->drr_checksum.zc_word[3]); 710 } 711 pcksum = zc; 712 } 713 free(buf); 714 715 /* Print final summary */ 716 717 (void) printf("SUMMARY:\n"); 718 (void) printf("\tTotal DRR_BEGIN records = %lld\n", 719 (u_longlong_t)drr_record_count[DRR_BEGIN]); 720 (void) printf("\tTotal DRR_END records = %lld\n", 721 (u_longlong_t)drr_record_count[DRR_END]); 722 (void) printf("\tTotal DRR_OBJECT records = %lld\n", 723 (u_longlong_t)drr_record_count[DRR_OBJECT]); 724 (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n", 725 (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]); 726 (void) printf("\tTotal DRR_WRITE records = %lld\n", 727 (u_longlong_t)drr_record_count[DRR_WRITE]); 728 (void) printf("\tTotal DRR_WRITE_BYREF records = %lld\n", 729 (u_longlong_t)drr_record_count[DRR_WRITE_BYREF]); 730 (void) printf("\tTotal DRR_WRITE_EMBEDDED records = %lld\n", 731 (u_longlong_t)drr_record_count[DRR_WRITE_EMBEDDED]); 732 (void) printf("\tTotal DRR_FREE records = %lld\n", 733 (u_longlong_t)drr_record_count[DRR_FREE]); 734 (void) printf("\tTotal DRR_SPILL records = %lld\n", 735 (u_longlong_t)drr_record_count[DRR_SPILL]); 736 (void) printf("\tTotal records = %lld\n", 737 (u_longlong_t)total_records); 738 (void) printf("\tTotal write size = %lld (0x%llx)\n", 739 (u_longlong_t)total_write_size, (u_longlong_t)total_write_size); 740 (void) printf("\tTotal stream length = %lld (0x%llx)\n", 741 (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len); 742 return (0); 743 } 744