1*495db6fbSLori Alt /* 2*495db6fbSLori Alt * CDDL HEADER START 3*495db6fbSLori Alt * 4*495db6fbSLori Alt * The contents of this file are subject to the terms of the 5*495db6fbSLori Alt * Common Development and Distribution License (the "License"). 6*495db6fbSLori Alt * You may not use this file except in compliance with the License. 7*495db6fbSLori Alt * 8*495db6fbSLori Alt * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*495db6fbSLori Alt * or http://www.opensolaris.org/os/licensing. 10*495db6fbSLori Alt * See the License for the specific language governing permissions 11*495db6fbSLori Alt * and limitations under the License. 12*495db6fbSLori Alt * 13*495db6fbSLori Alt * When distributing Covered Code, include this CDDL HEADER in each 14*495db6fbSLori Alt * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*495db6fbSLori Alt * If applicable, add the following below this CDDL HEADER, with the 16*495db6fbSLori Alt * fields enclosed by brackets "[]" replaced with your own identifying 17*495db6fbSLori Alt * information: Portions Copyright [yyyy] [name of copyright owner] 18*495db6fbSLori Alt * 19*495db6fbSLori Alt * CDDL HEADER END 20*495db6fbSLori Alt */ 21*495db6fbSLori Alt 22*495db6fbSLori Alt /* 23*495db6fbSLori Alt * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*495db6fbSLori Alt * Use is subject to license terms. 25*495db6fbSLori Alt */ 26*495db6fbSLori Alt 27*495db6fbSLori Alt #include <libnvpair.h> 28*495db6fbSLori Alt #include <stdio.h> 29*495db6fbSLori Alt #include <stdlib.h> 30*495db6fbSLori Alt #include <strings.h> 31*495db6fbSLori Alt #include <unistd.h> 32*495db6fbSLori Alt 33*495db6fbSLori Alt #include <sys/dmu.h> 34*495db6fbSLori Alt #include <sys/zfs_ioctl.h> 35*495db6fbSLori Alt #include <zfs_fletcher.h> 36*495db6fbSLori Alt 37*495db6fbSLori Alt uint64_t drr_record_count[DRR_NUMTYPES]; 38*495db6fbSLori Alt uint64_t total_write_size = 0; 39*495db6fbSLori Alt uint64_t total_stream_len = 0; 40*495db6fbSLori Alt FILE *send_stream = 0; 41*495db6fbSLori Alt boolean_t do_byteswap = B_FALSE; 42*495db6fbSLori Alt boolean_t do_cksum = B_TRUE; 43*495db6fbSLori Alt #define INITIAL_BUFLEN (1<<20) 44*495db6fbSLori Alt 45*495db6fbSLori Alt static void 46*495db6fbSLori Alt usage(void) 47*495db6fbSLori Alt { 48*495db6fbSLori Alt (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] < file\n"); 49*495db6fbSLori Alt (void) fprintf(stderr, "\t -v -- verbose\n"); 50*495db6fbSLori Alt (void) fprintf(stderr, "\t -C -- suppress checksum verification\n"); 51*495db6fbSLori Alt exit(1); 52*495db6fbSLori Alt } 53*495db6fbSLori Alt 54*495db6fbSLori Alt /* 55*495db6fbSLori Alt * ssread - send stream read. 56*495db6fbSLori Alt * 57*495db6fbSLori Alt * Read while computing incremental checksum 58*495db6fbSLori Alt */ 59*495db6fbSLori Alt 60*495db6fbSLori Alt static size_t 61*495db6fbSLori Alt ssread(void *buf, size_t len, zio_cksum_t *cksum) 62*495db6fbSLori Alt { 63*495db6fbSLori Alt size_t outlen; 64*495db6fbSLori Alt 65*495db6fbSLori Alt if ((outlen = fread(buf, len, 1, send_stream)) == 0) 66*495db6fbSLori Alt return (0); 67*495db6fbSLori Alt 68*495db6fbSLori Alt if (do_cksum && cksum) { 69*495db6fbSLori Alt if (do_byteswap) 70*495db6fbSLori Alt fletcher_4_incremental_byteswap(buf, len, cksum); 71*495db6fbSLori Alt else 72*495db6fbSLori Alt fletcher_4_incremental_native(buf, len, cksum); 73*495db6fbSLori Alt } 74*495db6fbSLori Alt total_stream_len += len; 75*495db6fbSLori Alt return (outlen); 76*495db6fbSLori Alt } 77*495db6fbSLori Alt 78*495db6fbSLori Alt int 79*495db6fbSLori Alt main(int argc, char *argv[]) 80*495db6fbSLori Alt { 81*495db6fbSLori Alt char *buf = malloc(INITIAL_BUFLEN); 82*495db6fbSLori Alt dmu_replay_record_t thedrr; 83*495db6fbSLori Alt dmu_replay_record_t *drr = &thedrr; 84*495db6fbSLori Alt struct drr_begin *drrb = &thedrr.drr_u.drr_begin; 85*495db6fbSLori Alt struct drr_end *drre = &thedrr.drr_u.drr_end; 86*495db6fbSLori Alt struct drr_object *drro = &thedrr.drr_u.drr_object; 87*495db6fbSLori Alt struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects; 88*495db6fbSLori Alt struct drr_write *drrw = &thedrr.drr_u.drr_write; 89*495db6fbSLori Alt struct drr_free *drrf = &thedrr.drr_u.drr_free; 90*495db6fbSLori Alt char c; 91*495db6fbSLori Alt boolean_t verbose = B_FALSE; 92*495db6fbSLori Alt boolean_t first = B_TRUE; 93*495db6fbSLori Alt int i, err; 94*495db6fbSLori Alt zio_cksum_t zc = { 0 }; 95*495db6fbSLori Alt zio_cksum_t pcksum = { 0 }; 96*495db6fbSLori Alt 97*495db6fbSLori Alt while ((c = getopt(argc, argv, ":vC")) != -1) { 98*495db6fbSLori Alt switch (c) { 99*495db6fbSLori Alt case 'C': 100*495db6fbSLori Alt do_cksum = B_FALSE; 101*495db6fbSLori Alt break; 102*495db6fbSLori Alt case 'v': 103*495db6fbSLori Alt verbose = B_TRUE; 104*495db6fbSLori Alt break; 105*495db6fbSLori Alt case ':': 106*495db6fbSLori Alt (void) fprintf(stderr, 107*495db6fbSLori Alt "missing argument for '%c' option\n", optopt); 108*495db6fbSLori Alt usage(); 109*495db6fbSLori Alt break; 110*495db6fbSLori Alt case '?': 111*495db6fbSLori Alt (void) fprintf(stderr, "invalid option '%c'\n", 112*495db6fbSLori Alt optopt); 113*495db6fbSLori Alt usage(); 114*495db6fbSLori Alt } 115*495db6fbSLori Alt } 116*495db6fbSLori Alt 117*495db6fbSLori Alt if (isatty(STDIN_FILENO)) { 118*495db6fbSLori Alt (void) fprintf(stderr, 119*495db6fbSLori Alt "Error: Backup stream can not be read " 120*495db6fbSLori Alt "from a terminal.\n" 121*495db6fbSLori Alt "You must redirect standard input.\n"); 122*495db6fbSLori Alt exit(1); 123*495db6fbSLori Alt } 124*495db6fbSLori Alt 125*495db6fbSLori Alt send_stream = stdin; 126*495db6fbSLori Alt pcksum = zc; 127*495db6fbSLori Alt while (ssread(drr, sizeof (dmu_replay_record_t), &zc)) { 128*495db6fbSLori Alt 129*495db6fbSLori Alt if (first) { 130*495db6fbSLori Alt if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { 131*495db6fbSLori Alt do_byteswap = B_TRUE; 132*495db6fbSLori Alt if (do_cksum) { 133*495db6fbSLori Alt ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); 134*495db6fbSLori Alt /* 135*495db6fbSLori Alt * recalculate header checksum now 136*495db6fbSLori Alt * that we know it needs to be 137*495db6fbSLori Alt * byteswapped. 138*495db6fbSLori Alt */ 139*495db6fbSLori Alt fletcher_4_incremental_byteswap(drr, 140*495db6fbSLori Alt sizeof (dmu_replay_record_t), &zc); 141*495db6fbSLori Alt } 142*495db6fbSLori Alt } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) { 143*495db6fbSLori Alt (void) fprintf(stderr, "Invalid stream " 144*495db6fbSLori Alt "(bad magic number)\n"); 145*495db6fbSLori Alt exit(1); 146*495db6fbSLori Alt } 147*495db6fbSLori Alt first = B_FALSE; 148*495db6fbSLori Alt } 149*495db6fbSLori Alt if (do_byteswap) { 150*495db6fbSLori Alt drr->drr_type = BSWAP_32(drr->drr_type); 151*495db6fbSLori Alt drr->drr_payloadlen = 152*495db6fbSLori Alt BSWAP_32(drr->drr_payloadlen); 153*495db6fbSLori Alt } 154*495db6fbSLori Alt 155*495db6fbSLori Alt /* 156*495db6fbSLori Alt * At this point, the leading fields of the replay record 157*495db6fbSLori Alt * (drr_type and drr_payloadlen) have been byte-swapped if 158*495db6fbSLori Alt * necessary, but the rest of the data structure (the 159*495db6fbSLori Alt * union of type-specific structures) is still in its 160*495db6fbSLori Alt * original state. 161*495db6fbSLori Alt */ 162*495db6fbSLori Alt if (drr->drr_type >= DRR_NUMTYPES) { 163*495db6fbSLori Alt (void) printf("INVALID record found: type 0x%x\n", 164*495db6fbSLori Alt drr->drr_type); 165*495db6fbSLori Alt (void) printf("Aborting.\n"); 166*495db6fbSLori Alt exit(1); 167*495db6fbSLori Alt } 168*495db6fbSLori Alt 169*495db6fbSLori Alt drr_record_count[drr->drr_type]++; 170*495db6fbSLori Alt 171*495db6fbSLori Alt switch (drr->drr_type) { 172*495db6fbSLori Alt case DRR_BEGIN: 173*495db6fbSLori Alt if (do_byteswap) { 174*495db6fbSLori Alt drrb->drr_magic = BSWAP_64(drrb->drr_magic); 175*495db6fbSLori Alt drrb->drr_version = BSWAP_64(drrb->drr_version); 176*495db6fbSLori Alt drrb->drr_creation_time = 177*495db6fbSLori Alt BSWAP_64(drrb->drr_creation_time); 178*495db6fbSLori Alt drrb->drr_type = BSWAP_32(drrb->drr_type); 179*495db6fbSLori Alt drrb->drr_flags = BSWAP_32(drrb->drr_flags); 180*495db6fbSLori Alt drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 181*495db6fbSLori Alt drrb->drr_fromguid = 182*495db6fbSLori Alt BSWAP_64(drrb->drr_fromguid); 183*495db6fbSLori Alt } 184*495db6fbSLori Alt 185*495db6fbSLori Alt (void) printf("BEGIN record\n"); 186*495db6fbSLori Alt (void) printf("\tversion = %llx\n", 187*495db6fbSLori Alt (u_longlong_t)drrb->drr_version); 188*495db6fbSLori Alt (void) printf("\tmagic = %llx\n", 189*495db6fbSLori Alt (u_longlong_t)drrb->drr_magic); 190*495db6fbSLori Alt (void) printf("\tcreation_time = %llx\n", 191*495db6fbSLori Alt (u_longlong_t)drrb->drr_creation_time); 192*495db6fbSLori Alt (void) printf("\ttype = %u\n", drrb->drr_type); 193*495db6fbSLori Alt (void) printf("\tflags = 0x%x\n", drrb->drr_flags); 194*495db6fbSLori Alt (void) printf("\ttoguid = %llx\n", 195*495db6fbSLori Alt (u_longlong_t)drrb->drr_toguid); 196*495db6fbSLori Alt (void) printf("\tfromguid = %llx\n", 197*495db6fbSLori Alt (u_longlong_t)drrb->drr_fromguid); 198*495db6fbSLori Alt (void) printf("\ttoname = %s\n", drrb->drr_toname); 199*495db6fbSLori Alt if (verbose) 200*495db6fbSLori Alt (void) printf("\n"); 201*495db6fbSLori Alt 202*495db6fbSLori Alt if (drrb->drr_version == 2 && 203*495db6fbSLori Alt drr->drr_payloadlen != 0) { 204*495db6fbSLori Alt nvlist_t *nv; 205*495db6fbSLori Alt int sz = drr->drr_payloadlen; 206*495db6fbSLori Alt 207*495db6fbSLori Alt if (sz > 1<<20) { 208*495db6fbSLori Alt free(buf); 209*495db6fbSLori Alt buf = malloc(sz); 210*495db6fbSLori Alt } 211*495db6fbSLori Alt (void) ssread(buf, sz, &zc); 212*495db6fbSLori Alt if (ferror(send_stream)) 213*495db6fbSLori Alt perror("fread"); 214*495db6fbSLori Alt err = nvlist_unpack(buf, sz, &nv, 0); 215*495db6fbSLori Alt if (err) 216*495db6fbSLori Alt perror(strerror(err)); 217*495db6fbSLori Alt nvlist_print(stdout, nv); 218*495db6fbSLori Alt nvlist_free(nv); 219*495db6fbSLori Alt } 220*495db6fbSLori Alt break; 221*495db6fbSLori Alt 222*495db6fbSLori Alt case DRR_END: 223*495db6fbSLori Alt if (do_byteswap) { 224*495db6fbSLori Alt drre->drr_checksum.zc_word[0] = 225*495db6fbSLori Alt BSWAP_64(drre->drr_checksum.zc_word[0]); 226*495db6fbSLori Alt drre->drr_checksum.zc_word[1] = 227*495db6fbSLori Alt BSWAP_64(drre->drr_checksum.zc_word[1]); 228*495db6fbSLori Alt drre->drr_checksum.zc_word[2] = 229*495db6fbSLori Alt BSWAP_64(drre->drr_checksum.zc_word[2]); 230*495db6fbSLori Alt drre->drr_checksum.zc_word[3] = 231*495db6fbSLori Alt BSWAP_64(drre->drr_checksum.zc_word[3]); 232*495db6fbSLori Alt } 233*495db6fbSLori Alt /* 234*495db6fbSLori Alt * We compare against the *previous* checksum 235*495db6fbSLori Alt * value, because the stored checksum is of 236*495db6fbSLori Alt * everything before the DRR_END record. 237*495db6fbSLori Alt */ 238*495db6fbSLori Alt if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum, 239*495db6fbSLori Alt pcksum)) { 240*495db6fbSLori Alt (void) printf("Expected checksum differs from " 241*495db6fbSLori Alt "checksum in stream.\n"); 242*495db6fbSLori Alt (void) printf("Expected checksum = " 243*495db6fbSLori Alt "%llx/%llx/%llx/%llx\n", 244*495db6fbSLori Alt pcksum.zc_word[0], 245*495db6fbSLori Alt pcksum.zc_word[1], 246*495db6fbSLori Alt pcksum.zc_word[2], 247*495db6fbSLori Alt pcksum.zc_word[3]); 248*495db6fbSLori Alt } 249*495db6fbSLori Alt (void) printf("END checksum = %llx/%llx/%llx/%llx\n", 250*495db6fbSLori Alt drre->drr_checksum.zc_word[0], 251*495db6fbSLori Alt drre->drr_checksum.zc_word[1], 252*495db6fbSLori Alt drre->drr_checksum.zc_word[2], 253*495db6fbSLori Alt drre->drr_checksum.zc_word[3]); 254*495db6fbSLori Alt 255*495db6fbSLori Alt ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0); 256*495db6fbSLori Alt break; 257*495db6fbSLori Alt 258*495db6fbSLori Alt case DRR_OBJECT: 259*495db6fbSLori Alt if (do_byteswap) { 260*495db6fbSLori Alt drro->drr_object = BSWAP_64(drro->drr_object); 261*495db6fbSLori Alt drro->drr_type = BSWAP_32(drro->drr_type); 262*495db6fbSLori Alt drro->drr_bonustype = 263*495db6fbSLori Alt BSWAP_32(drro->drr_bonustype); 264*495db6fbSLori Alt drro->drr_blksz = BSWAP_32(drro->drr_blksz); 265*495db6fbSLori Alt drro->drr_bonuslen = 266*495db6fbSLori Alt BSWAP_32(drro->drr_bonuslen); 267*495db6fbSLori Alt } 268*495db6fbSLori Alt if (verbose) { 269*495db6fbSLori Alt (void) printf("OBJECT object = %llu type = %u " 270*495db6fbSLori Alt "bonustype = %u blksz = %u bonuslen = %u\n", 271*495db6fbSLori Alt (u_longlong_t)drro->drr_object, 272*495db6fbSLori Alt drro->drr_type, 273*495db6fbSLori Alt drro->drr_bonustype, 274*495db6fbSLori Alt drro->drr_blksz, 275*495db6fbSLori Alt drro->drr_bonuslen); 276*495db6fbSLori Alt } 277*495db6fbSLori Alt if (drro->drr_bonuslen > 0) { 278*495db6fbSLori Alt (void) ssread(buf, P2ROUNDUP(drro->drr_bonuslen, 279*495db6fbSLori Alt 8), &zc); 280*495db6fbSLori Alt } 281*495db6fbSLori Alt break; 282*495db6fbSLori Alt 283*495db6fbSLori Alt case DRR_FREEOBJECTS: 284*495db6fbSLori Alt if (do_byteswap) { 285*495db6fbSLori Alt drrfo->drr_firstobj = 286*495db6fbSLori Alt BSWAP_64(drrfo->drr_firstobj); 287*495db6fbSLori Alt drrfo->drr_numobjs = 288*495db6fbSLori Alt BSWAP_64(drrfo->drr_numobjs); 289*495db6fbSLori Alt } 290*495db6fbSLori Alt if (verbose) { 291*495db6fbSLori Alt (void) printf("FREEOBJECTS firstobj = %llu " 292*495db6fbSLori Alt "numobjs = %llu\n", 293*495db6fbSLori Alt (u_longlong_t)drrfo->drr_firstobj, 294*495db6fbSLori Alt (u_longlong_t)drrfo->drr_numobjs); 295*495db6fbSLori Alt } 296*495db6fbSLori Alt break; 297*495db6fbSLori Alt 298*495db6fbSLori Alt case DRR_WRITE: 299*495db6fbSLori Alt if (do_byteswap) { 300*495db6fbSLori Alt drrw->drr_object = BSWAP_64(drrw->drr_object); 301*495db6fbSLori Alt drrw->drr_type = BSWAP_32(drrw->drr_type); 302*495db6fbSLori Alt drrw->drr_offset = BSWAP_64(drrw->drr_offset); 303*495db6fbSLori Alt drrw->drr_length = BSWAP_64(drrw->drr_length); 304*495db6fbSLori Alt } 305*495db6fbSLori Alt if (verbose) { 306*495db6fbSLori Alt (void) printf("WRITE object = %llu type = %u " 307*495db6fbSLori Alt "offset = %llu length = %llu\n", 308*495db6fbSLori Alt (u_longlong_t)drrw->drr_object, 309*495db6fbSLori Alt drrw->drr_type, 310*495db6fbSLori Alt (u_longlong_t)drrw->drr_offset, 311*495db6fbSLori Alt (u_longlong_t)drrw->drr_length); 312*495db6fbSLori Alt } 313*495db6fbSLori Alt (void) ssread(buf, drrw->drr_length, &zc); 314*495db6fbSLori Alt total_write_size += drrw->drr_length; 315*495db6fbSLori Alt break; 316*495db6fbSLori Alt 317*495db6fbSLori Alt case DRR_FREE: 318*495db6fbSLori Alt if (do_byteswap) { 319*495db6fbSLori Alt drrf->drr_object = BSWAP_64(drrf->drr_object); 320*495db6fbSLori Alt drrf->drr_offset = BSWAP_64(drrf->drr_offset); 321*495db6fbSLori Alt drrf->drr_length = BSWAP_64(drrf->drr_length); 322*495db6fbSLori Alt } 323*495db6fbSLori Alt if (verbose) { 324*495db6fbSLori Alt (void) printf("FREE object = %llu " 325*495db6fbSLori Alt "offset = %llu length = %lld\n", 326*495db6fbSLori Alt (u_longlong_t)drrf->drr_object, 327*495db6fbSLori Alt (u_longlong_t)drrf->drr_offset, 328*495db6fbSLori Alt (longlong_t)drrf->drr_length); 329*495db6fbSLori Alt } 330*495db6fbSLori Alt break; 331*495db6fbSLori Alt } 332*495db6fbSLori Alt pcksum = zc; 333*495db6fbSLori Alt } 334*495db6fbSLori Alt free(buf); 335*495db6fbSLori Alt 336*495db6fbSLori Alt /* Print final summary */ 337*495db6fbSLori Alt 338*495db6fbSLori Alt (void) printf("SUMMARY:\n"); 339*495db6fbSLori Alt (void) printf("\tTotal DRR_BEGIN records = %lld\n", 340*495db6fbSLori Alt (u_longlong_t)drr_record_count[DRR_BEGIN]); 341*495db6fbSLori Alt (void) printf("\tTotal DRR_END records = %lld\n", 342*495db6fbSLori Alt (u_longlong_t)drr_record_count[DRR_END]); 343*495db6fbSLori Alt (void) printf("\tTotal DRR_OBJECT records = %lld\n", 344*495db6fbSLori Alt (u_longlong_t)drr_record_count[DRR_OBJECT]); 345*495db6fbSLori Alt (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n", 346*495db6fbSLori Alt (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]); 347*495db6fbSLori Alt (void) printf("\tTotal DRR_WRITE records = %lld\n", 348*495db6fbSLori Alt (u_longlong_t)drr_record_count[DRR_WRITE]); 349*495db6fbSLori Alt (void) printf("\tTotal DRR_FREE records = %lld\n", 350*495db6fbSLori Alt (u_longlong_t)drr_record_count[DRR_FREE]); 351*495db6fbSLori Alt (void) printf("\tTotal records = %lld\n", 352*495db6fbSLori Alt (u_longlong_t)(drr_record_count[DRR_BEGIN] + 353*495db6fbSLori Alt drr_record_count[DRR_OBJECT] + 354*495db6fbSLori Alt drr_record_count[DRR_FREEOBJECTS] + 355*495db6fbSLori Alt drr_record_count[DRR_WRITE] + 356*495db6fbSLori Alt drr_record_count[DRR_FREE] + 357*495db6fbSLori Alt drr_record_count[DRR_END])); 358*495db6fbSLori Alt (void) printf("\tTotal write size = %lld (0x%llx)\n", 359*495db6fbSLori Alt (u_longlong_t)total_write_size, (u_longlong_t)total_write_size); 360*495db6fbSLori Alt (void) printf("\tTotal stream length = %lld (0x%llx)\n", 361*495db6fbSLori Alt (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len); 362*495db6fbSLori Alt return (0); 363*495db6fbSLori Alt } 364