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