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