zstreamdump.c revision 7c5a457e2a179dbaf12f243b90fdb520254e0c18
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013, 2014 by Delphix. All rights reserved.
*/
#include <ctype.h>
#include <libnvpair.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/zfs_ioctl.h>
#include <zfs_fletcher.h>
/*
* If dump mode is enabled, the number of bytes to print per line
*/
#define BYTES_PER_LINE 16
/*
* If dump mode is enabled, the number of bytes to group together, separated
* by newlines or spaces
*/
#define DUMP_GROUPING 4
uint64_t total_write_size = 0;
uint64_t total_stream_len = 0;
FILE *send_stream = 0;
static void
usage(void)
{
"implies verbose\n");
exit(1);
}
static void *
{
size);
abort();
}
return (rv);
}
/*
* ssread - send stream read.
*
* Read while computing incremental checksum
*/
static size_t
{
return (0);
if (do_cksum) {
if (do_byteswap)
else
}
total_stream_len += len;
return (outlen);
}
static size_t
{
==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
if (r == 0)
return (0);
sizeof (zio_cksum_t), cksum);
if (r == 0)
return (0);
(void) printf("Incorrect checksum in record header.\n");
(void) printf("Expected checksum = %llx/%llx/%llx/%llx\n",
saved_cksum.zc_word[0],
return (0);
}
return (sizeof (*drr));
}
/*
* Print part of a block in ASCII characters
*/
static void
{
int i;
for (i = 0; i < length; i++) {
if (i != 0 && i % DUMP_GROUPING == 0) {
(void) printf(" ");
}
}
(void) printf("\n");
}
/*
* print_block - Dump the contents of a modified block to STDOUT
*
* Assume that buf has capacity evenly divisible by BYTES_PER_LINE
*/
static void
{
int i;
/*
* Start printing ASCII characters at a constant offset, after
* the hex prints. Leave 3 characters per byte on a line (2 digit
* hex number plus 1 space) plus spaces between characters and
* groupings.
*/
for (i = 0; i < length; i += BYTES_PER_LINE) {
int j;
int print_offset = 0;
for (j = 0; j < this_line_length; j++) {
int buf_offset = i + j;
/*
* Separate every DUMP_GROUPING bytes by a space.
*/
if (buf_offset % DUMP_GROUPING == 0) {
}
/*
* Print the two-digit hex value for this byte.
*/
}
}
}
int
{
uint64_t total_records = 0;
char c;
/*
* dump flag controls whether the contents of any modified data blocks
* are printed to the console during processing of the stream. Warning:
* for large streams, this can obviously lead to massive prints.
*/
int err;
zio_cksum_t zc = { 0 };
zio_cksum_t pcksum = { 0 };
switch (c) {
case 'C':
break;
case 'v':
if (verbose)
break;
case 'd':
break;
case ':':
"missing argument for '%c' option\n", optopt);
usage();
break;
case '?':
optopt);
usage();
}
}
if (isatty(STDIN_FILENO)) {
"Error: Backup stream can not be read "
"from a terminal.\n"
"You must redirect standard input.\n");
exit(1);
}
send_stream = stdin;
/*
* If this is the first DMU record being processed, check for
* the magic bytes and figure out the endian-ness based on them.
*/
if (first) {
if (do_cksum) {
ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
/*
* recalculate header checksum now
* that we know it needs to be
* byteswapped.
*/
sizeof (dmu_replay_record_t), &zc);
}
"(bad magic number)\n");
exit(1);
}
}
if (do_byteswap) {
}
/*
* At this point, the leading fields of the replay record
* (drr_type and drr_payloadlen) have been byte-swapped if
* necessary, but the rest of the data structure (the
* union of type-specific structures) is still in its
* original state.
*/
(void) printf("INVALID record found: type 0x%x\n",
(void) printf("Aborting.\n");
exit(1);
}
case DRR_BEGIN:
if (do_byteswap) {
drrb->drr_fromguid =
}
(void) printf("BEGIN record\n");
(void) printf("\thdrtype = %lld\n",
(void) printf("\tfeatures = %llx\n",
(void) printf("\tmagic = %llx\n",
(void) printf("\tcreation_time = %llx\n",
(void) printf("\ttoguid = %llx\n",
(void) printf("\tfromguid = %llx\n",
if (verbose)
(void) printf("\n");
if (drr->drr_payloadlen != 0) {
if (sz > SPA_MAXBLOCKSIZE) {
}
if (ferror(send_stream))
perror("fread");
if (err)
}
break;
case DRR_END:
if (do_byteswap) {
}
/*
* We compare against the *previous* checksum
* value, because the stored checksum is of
* everything before the DRR_END record.
*/
pcksum)) {
(void) printf("Expected checksum differs from "
"checksum in stream.\n");
(void) printf("Expected checksum = "
"%llx/%llx/%llx/%llx\n",
}
(void) printf("END checksum = %llx/%llx/%llx/%llx\n",
ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
break;
case DRR_OBJECT:
if (do_byteswap) {
drro->drr_bonuslen =
}
if (verbose) {
(void) printf("OBJECT object = %llu type = %u "
"bonustype = %u blksz = %u bonuslen = %u\n",
drro->drr_bonuslen);
}
if (drro->drr_bonuslen > 0) {
if (dump) {
}
}
break;
case DRR_FREEOBJECTS:
if (do_byteswap) {
drrfo->drr_numobjs =
}
if (verbose) {
(void) printf("FREEOBJECTS firstobj = %llu "
"numobjs = %llu\n",
}
break;
case DRR_WRITE:
if (do_byteswap) {
}
/*
* print info on the modified block
*/
if (verbose) {
(void) printf("WRITE object = %llu type = %u "
"checksum type = %u\n"
" offset = %llu length = %llu "
"props = %llx\n",
}
/*
* Read the contents of the block in from STDIN to buf
*/
/*
* If in dump mode
*/
if (dump) {
}
break;
case DRR_WRITE_BYREF:
if (do_byteswap) {
drrwbr->drr_object =
drrwbr->drr_offset =
drrwbr->drr_length =
drrwbr->drr_toguid =
}
if (verbose) {
(void) printf("WRITE_BYREF object = %llu "
"checksum type = %u props = %llx\n"
" offset = %llu length = %llu\n"
"toguid = %llx refguid = %llx\n"
" refobject = %llu refoffset = %llu\n",
}
break;
case DRR_FREE:
if (do_byteswap) {
}
if (verbose) {
(void) printf("FREE object = %llu "
"offset = %llu length = %lld\n",
}
break;
case DRR_SPILL:
if (do_byteswap) {
}
if (verbose) {
(void) printf("SPILL block for object = %llu "
drrs->drr_length);
}
if (dump) {
}
break;
case DRR_WRITE_EMBEDDED:
if (do_byteswap) {
drrwe->drr_object =
drrwe->drr_offset =
drrwe->drr_length =
drrwe->drr_toguid =
}
if (verbose) {
(void) printf("WRITE_EMBEDDED object = %llu "
"offset = %llu length = %llu\n"
" toguid = %llx comp = %u etype = %u "
"lsize = %u psize = %u\n",
}
break;
}
(void) printf(" checksum = %llx/%llx/%llx/%llx\n",
}
}
/* Print final summary */
(void) printf("SUMMARY:\n");
(void) printf("\tTotal DRR_BEGIN records = %lld\n",
(void) printf("\tTotal DRR_END records = %lld\n",
(void) printf("\tTotal DRR_OBJECT records = %lld\n",
(void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n",
(void) printf("\tTotal DRR_WRITE records = %lld\n",
(void) printf("\tTotal DRR_WRITE_BYREF records = %lld\n",
(void) printf("\tTotal DRR_WRITE_EMBEDDED records = %lld\n",
(void) printf("\tTotal DRR_FREE records = %lld\n",
(void) printf("\tTotal DRR_SPILL records = %lld\n",
(void) printf("\tTotal records = %lld\n",
(void) printf("\tTotal write size = %lld (0x%llx)\n",
(void) printf("\tTotal stream length = %lld (0x%llx)\n",
return (0);
}