26
26
* Portions Copyright 2012 Martin Matuska <martin@matuska.org>
27
27
*/
28
28
29
+ /*
30
+ * Copyright (c) 2013 by Delphix. All rights reserved.
31
+ */
32
+
33
+ #include <ctype.h>
29
34
#include <libnvpair.h>
30
35
#include <stdio.h>
31
36
#include <stdlib.h>
36
41
#include <sys/zfs_ioctl.h>
37
42
#include <zfs_fletcher.h>
38
43
44
+ /*
45
+ * If dump mode is enabled, the number of bytes to print per line
46
+ */
47
+ #define BYTES_PER_LINE 16
48
+ /*
49
+ * If dump mode is enabled, the number of bytes to group together, separated
50
+ * by newlines or spaces
51
+ */
52
+ #define DUMP_GROUPING 4
53
+
39
54
uint64_t total_write_size = 0 ;
40
55
uint64_t total_stream_len = 0 ;
41
56
FILE * send_stream = 0 ;
@@ -46,9 +61,11 @@ boolean_t do_cksum = B_TRUE;
46
61
static void
47
62
usage (void )
48
63
{
49
- (void ) fprintf (stderr , "usage: zstreamdump [-v] [-C] < file\n" );
64
+ (void ) fprintf (stderr , "usage: zstreamdump [-v] [-C] [-d] < file\n" );
50
65
(void ) fprintf (stderr , "\t -v -- verbose\n" );
51
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" );
52
69
exit (1 );
53
70
}
54
71
@@ -76,6 +93,70 @@ ssread(void *buf, size_t len, zio_cksum_t *cksum)
76
93
return (outlen );
77
94
}
78
95
96
+ /*
97
+ * Print part of a block in ASCII characters
98
+ */
99
+ static void
100
+ print_ascii_block (char * subbuf , int length )
101
+ {
102
+ int i ;
103
+
104
+ for (i = 0 ; i < length ; i ++ ) {
105
+ char char_print = isprint (subbuf [i ]) ? subbuf [i ] : '.' ;
106
+ if (i != 0 && i % DUMP_GROUPING == 0 ) {
107
+ (void ) printf (" " );
108
+ }
109
+ (void ) printf ("%c" , char_print );
110
+ }
111
+ (void ) printf ("\n" );
112
+ }
113
+
114
+ /*
115
+ * print_block - Dump the contents of a modified block to STDOUT
116
+ *
117
+ * Assume that buf has capacity evenly divisible by BYTES_PER_LINE
118
+ */
119
+ static void
120
+ print_block (char * buf , int length )
121
+ {
122
+ int i ;
123
+ /*
124
+ * Start printing ASCII characters at a constant offset, after
125
+ * the hex prints. Leave 3 characters per byte on a line (2 digit
126
+ * hex number plus 1 space) plus spaces between characters and
127
+ * groupings
128
+ */
129
+ int ascii_start = BYTES_PER_LINE * 3 +
130
+ BYTES_PER_LINE / DUMP_GROUPING + 2 ;
131
+
132
+ for (i = 0 ; i < length ; i += BYTES_PER_LINE ) {
133
+ int j ;
134
+ int this_line_length = MIN (BYTES_PER_LINE , length - i );
135
+ int print_offset = 0 ;
136
+
137
+ for (j = 0 ; j < this_line_length ; j ++ ) {
138
+ int buf_offset = i + j ;
139
+
140
+ /*
141
+ * Separate every DUMP_GROUPING bytes by a space.
142
+ */
143
+ if (buf_offset % DUMP_GROUPING == 0 ) {
144
+ print_offset += printf (" " );
145
+ }
146
+
147
+ /*
148
+ * Print the two-digit hex value for this byte.
149
+ */
150
+ unsigned char hex_print = buf [buf_offset ];
151
+ print_offset += printf ("%02x " , hex_print );
152
+ }
153
+
154
+ (void ) printf ("%*s" , ascii_start - print_offset , " " );
155
+
156
+ print_ascii_block (buf + i , this_line_length );
157
+ }
158
+ }
159
+
79
160
int
80
161
main (int argc , char * argv [])
81
162
{
@@ -96,18 +177,28 @@ main(int argc, char *argv[])
96
177
char c ;
97
178
boolean_t verbose = B_FALSE ;
98
179
boolean_t first = B_TRUE ;
180
+ /*
181
+ * dump flag controls whether the contents of any modified data blocks
182
+ * are printed to the console during processing of the stream. Warning:
183
+ * for large streams, this can obviously lead to massive prints.
184
+ */
185
+ boolean_t dump = B_FALSE ;
99
186
int err ;
100
187
zio_cksum_t zc = { { 0 } };
101
188
zio_cksum_t pcksum = { { 0 } };
102
189
103
- while ((c = getopt (argc , argv , ":vC " )) != -1 ) {
190
+ while ((c = getopt (argc , argv , ":vCd " )) != -1 ) {
104
191
switch (c ) {
105
192
case 'C' :
106
193
do_cksum = B_FALSE ;
107
194
break ;
108
195
case 'v' :
109
196
verbose = B_TRUE ;
110
197
break ;
198
+ case 'd' :
199
+ dump = B_TRUE ;
200
+ verbose = B_TRUE ;
201
+ break ;
111
202
case ':' :
112
203
(void ) fprintf (stderr ,
113
204
"missing argument for '%c' option\n" , optopt );
@@ -131,6 +222,10 @@ main(int argc, char *argv[])
131
222
send_stream = stdin ;
132
223
while (ssread (drr , sizeof (dmu_replay_record_t ), & zc )) {
133
224
225
+ /*
226
+ * If this is the first DMU record being processed, check for
227
+ * the magic bytes and figure out the endian-ness based on them.
228
+ */
134
229
if (first ) {
135
230
if (drrb -> drr_magic == BSWAP_64 (DMU_BACKUP_MAGIC )) {
136
231
do_byteswap = B_TRUE ;
@@ -213,7 +308,7 @@ main(int argc, char *argv[])
213
308
nvlist_t * nv ;
214
309
int sz = drr -> drr_payloadlen ;
215
310
216
- if (sz > 1 << 20 ) {
311
+ if (sz > INITIAL_BUFLEN ) {
217
312
free (buf );
218
313
buf = malloc (sz );
219
314
}
@@ -289,8 +384,12 @@ main(int argc, char *argv[])
289
384
drro -> drr_bonuslen );
290
385
}
291
386
if (drro -> drr_bonuslen > 0 ) {
292
- (void ) ssread (buf ,
293
- P2ROUNDUP (drro -> drr_bonuslen , 8 ), & zc );
387
+ (void ) ssread (buf , P2ROUNDUP (drro -> drr_bonuslen ,
388
+ 8 ), & zc );
389
+ if (dump ) {
390
+ print_block (buf ,
391
+ P2ROUNDUP (drro -> drr_bonuslen , 8 ));
392
+ }
294
393
}
295
394
break ;
296
395
@@ -320,6 +419,10 @@ main(int argc, char *argv[])
320
419
drrw -> drr_key .ddk_prop =
321
420
BSWAP_64 (drrw -> drr_key .ddk_prop );
322
421
}
422
+ /*
423
+ * If this is verbose and/or dump output,
424
+ * print info on the modified block
425
+ */
323
426
if (verbose ) {
324
427
(void ) printf ("WRITE object = %llu type = %u "
325
428
"checksum type = %u\n"
@@ -332,7 +435,16 @@ main(int argc, char *argv[])
332
435
(u_longlong_t )drrw -> drr_length ,
333
436
(u_longlong_t )drrw -> drr_key .ddk_prop );
334
437
}
438
+ /*
439
+ * Read the contents of the block in from STDIN to buf
440
+ */
335
441
(void ) ssread (buf , drrw -> drr_length , & zc );
442
+ /*
443
+ * If in dump mode
444
+ */
445
+ if (dump ) {
446
+ print_block (buf , drrw -> drr_length );
447
+ }
336
448
total_write_size += drrw -> drr_length ;
337
449
break ;
338
450
@@ -399,6 +511,9 @@ main(int argc, char *argv[])
399
511
(long long unsigned int )drrs -> drr_length );
400
512
}
401
513
(void ) ssread (buf , drrs -> drr_length , & zc );
514
+ if (dump ) {
515
+ print_block (buf , drrs -> drr_length );
516
+ }
402
517
break ;
403
518
case DRR_WRITE_EMBEDDED :
404
519
if (do_byteswap ) {
0 commit comments