MFV r258972:

4373 add block contents print to zstreamdump

illumos/illumos-gate@994fb6b8a9

MFC after:	2 weeks
This commit is contained in:
Xin LI 2013-12-31 21:37:24 +00:00
commit f86b34932a
2 changed files with 123 additions and 4 deletions

View File

@ -18,10 +18,11 @@
.\" information: Portions Copyright [yyyy] [name of copyright owner] .\" information: Portions Copyright [yyyy] [name of copyright owner]
.\" .\"
.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved. .\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright (c) 2013, Delphix. All Rights Reserved.
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd November 26, 2011 .Dd December 31, 2013
.Dt ZSTREAMDUMP 8 .Dt ZSTREAMDUMP 8
.Os .Os
.Sh NAME .Sh NAME
@ -30,6 +31,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl C .Op Fl C
.Op Fl d
.Op Fl v .Op Fl v
.Sh DESCRIPTION .Sh DESCRIPTION
The The
@ -43,6 +45,8 @@ The following options are supported:
.Bl -tag -width indent .Bl -tag -width indent
.It Fl C .It Fl C
Suppress the validation of checksums. Suppress the validation of checksums.
.It Fl d
Dump contents of blocks modified, implies verbose.
.It Fl v .It Fl v
Verbose. Dump all headers, not only begin and end headers. Verbose. Dump all headers, not only begin and end headers.
.El .El

View File

@ -24,6 +24,11 @@
* Use is subject to license terms. * Use is subject to license terms.
*/ */
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
#include <ctype.h>
#include <libnvpair.h> #include <libnvpair.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -34,6 +39,16 @@
#include <sys/zfs_ioctl.h> #include <sys/zfs_ioctl.h>
#include <zfs_fletcher.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 drr_record_count[DRR_NUMTYPES]; uint64_t drr_record_count[DRR_NUMTYPES];
uint64_t total_write_size = 0; uint64_t total_write_size = 0;
uint64_t total_stream_len = 0; uint64_t total_stream_len = 0;
@ -45,9 +60,11 @@ boolean_t do_cksum = B_TRUE;
static void static void
usage(void) usage(void)
{ {
(void) fprintf(stderr, "usage: zstreamdump [-v] [-C] < file\n"); (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] [-d] < file\n");
(void) fprintf(stderr, "\t -v -- verbose\n"); (void) fprintf(stderr, "\t -v -- verbose\n");
(void) fprintf(stderr, "\t -C -- suppress checksum verification\n"); (void) fprintf(stderr, "\t -C -- suppress checksum verification\n");
(void) fprintf(stderr, "\t -d -- dump contents of blocks modified, "
"implies verbose\n");
exit(1); exit(1);
} }
@ -75,6 +92,70 @@ ssread(void *buf, size_t len, zio_cksum_t *cksum)
return (outlen); return (outlen);
} }
/*
* Print part of a block in ASCII characters
*/
static void
print_ascii_block(char *subbuf, int length)
{
int i;
for (i = 0; i < length; i++) {
char char_print = isprint(subbuf[i]) ? subbuf[i] : '.';
if (i != 0 && i % DUMP_GROUPING == 0) {
(void) printf(" ");
}
(void) printf("%c", char_print);
}
(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
print_block(char *buf, int length)
{
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
*/
int ascii_start = BYTES_PER_LINE * 3 +
BYTES_PER_LINE / DUMP_GROUPING + 2;
for (i = 0; i < length; i += BYTES_PER_LINE) {
int j;
int this_line_length = MIN(BYTES_PER_LINE, length - i);
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_offset += printf(" ");
}
/*
* Print the two-digit hex value for this byte.
*/
unsigned char hex_print = buf[buf_offset];
print_offset += printf("%02x ", hex_print);
}
(void) printf("%*s", ascii_start - print_offset, " ");
print_ascii_block(buf + i, this_line_length);
}
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
@ -92,11 +173,17 @@ main(int argc, char *argv[])
char c; char c;
boolean_t verbose = B_FALSE; boolean_t verbose = B_FALSE;
boolean_t first = B_TRUE; boolean_t first = B_TRUE;
/*
* 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.
*/
boolean_t dump = B_FALSE;
int err; int err;
zio_cksum_t zc = { 0 }; zio_cksum_t zc = { 0 };
zio_cksum_t pcksum = { 0 }; zio_cksum_t pcksum = { 0 };
while ((c = getopt(argc, argv, ":vC")) != -1) { while ((c = getopt(argc, argv, ":vCd")) != -1) {
switch (c) { switch (c) {
case 'C': case 'C':
do_cksum = B_FALSE; do_cksum = B_FALSE;
@ -104,6 +191,10 @@ main(int argc, char *argv[])
case 'v': case 'v':
verbose = B_TRUE; verbose = B_TRUE;
break; break;
case 'd':
dump = B_TRUE;
verbose = B_TRUE;
break;
case ':': case ':':
(void) fprintf(stderr, (void) fprintf(stderr,
"missing argument for '%c' option\n", optopt); "missing argument for '%c' option\n", optopt);
@ -128,6 +219,10 @@ main(int argc, char *argv[])
pcksum = zc; pcksum = zc;
while (ssread(drr, sizeof (dmu_replay_record_t), &zc)) { while (ssread(drr, sizeof (dmu_replay_record_t), &zc)) {
/*
* 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 (first) {
if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
do_byteswap = B_TRUE; do_byteswap = B_TRUE;
@ -209,7 +304,7 @@ main(int argc, char *argv[])
nvlist_t *nv; nvlist_t *nv;
int sz = drr->drr_payloadlen; int sz = drr->drr_payloadlen;
if (sz > 1<<20) { if (sz > INITIAL_BUFLEN) {
free(buf); free(buf);
buf = malloc(sz); buf = malloc(sz);
} }
@ -283,6 +378,10 @@ main(int argc, char *argv[])
if (drro->drr_bonuslen > 0) { if (drro->drr_bonuslen > 0) {
(void) ssread(buf, P2ROUNDUP(drro->drr_bonuslen, (void) ssread(buf, P2ROUNDUP(drro->drr_bonuslen,
8), &zc); 8), &zc);
if (dump) {
print_block(buf,
P2ROUNDUP(drro->drr_bonuslen, 8));
}
} }
break; break;
@ -312,6 +411,10 @@ main(int argc, char *argv[])
drrw->drr_key.ddk_prop = drrw->drr_key.ddk_prop =
BSWAP_64(drrw->drr_key.ddk_prop); BSWAP_64(drrw->drr_key.ddk_prop);
} }
/*
* If this is verbose and/or dump output,
* print info on the modified block
*/
if (verbose) { if (verbose) {
(void) printf("WRITE object = %llu type = %u " (void) printf("WRITE object = %llu type = %u "
"checksum type = %u\n" "checksum type = %u\n"
@ -324,7 +427,16 @@ main(int argc, char *argv[])
(u_longlong_t)drrw->drr_length, (u_longlong_t)drrw->drr_length,
(u_longlong_t)drrw->drr_key.ddk_prop); (u_longlong_t)drrw->drr_key.ddk_prop);
} }
/*
* Read the contents of the block in from STDIN to buf
*/
(void) ssread(buf, drrw->drr_length, &zc); (void) ssread(buf, drrw->drr_length, &zc);
/*
* If in dump mode
*/
if (dump) {
print_block(buf, drrw->drr_length);
}
total_write_size += drrw->drr_length; total_write_size += drrw->drr_length;
break; break;
@ -390,6 +502,9 @@ main(int argc, char *argv[])
drrs->drr_length); drrs->drr_length);
} }
(void) ssread(buf, drrs->drr_length, &zc); (void) ssread(buf, drrs->drr_length, &zc);
if (dump) {
print_block(buf, drrs->drr_length);
}
break; break;
} }
pcksum = zc; pcksum = zc;