1 /* 2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@dragonflybsd.org> 6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "hammer2.h" 37 38 #include <openssl/sha.h> 39 40 #define GIG (1024LL*1024*1024) 41 42 static int show_all_volume_headers = 0; 43 static int show_tab = 2; 44 static int show_depth = -1; 45 static hammer2_tid_t show_min_mirror_tid = 0; 46 static hammer2_tid_t show_min_modify_tid = 0; 47 48 static void shell_msghandler(dmsg_msg_t *msg, int unmanaged); 49 static void shell_ttymsg(dmsg_iocom_t *iocom); 50 static void count_blocks(hammer2_bmap_data_t *bmap, int value, 51 hammer2_off_t *accum16, hammer2_off_t *accum64); 52 53 /************************************************************************ 54 * SHELL * 55 ************************************************************************/ 56 57 int 58 cmd_shell(const char *hostname) 59 { 60 dmsg_master_service_info_t *info; 61 pthread_t thread; 62 int fd; 63 64 fd = dmsg_connect(hostname); 65 if (fd < 0) 66 return 1; 67 68 info = malloc(sizeof(*info)); 69 bzero(info, sizeof(*info)); 70 info->fd = fd; 71 info->detachme = 0; 72 info->usrmsg_callback = shell_msghandler; 73 info->altmsg_callback = shell_ttymsg; 74 info->label = strdup("debug"); 75 pthread_create(&thread, NULL, dmsg_master_service, info); 76 pthread_join(thread, NULL); 77 78 return 0; 79 } 80 81 #if 0 82 int 83 cmd_shell(const char *hostname) 84 { 85 struct dmsg_iocom iocom; 86 dmsg_msg_t *msg; 87 int fd; 88 89 /* 90 * Connect to the target 91 */ 92 fd = dmsg_connect(hostname); 93 if (fd < 0) 94 return 1; 95 96 /* 97 * Initialize the session and transmit an empty DMSG_DBG_SHELL 98 * to cause the remote end to generate a prompt. 99 */ 100 dmsg_iocom_init(&iocom, fd, 0, 101 NULL, 102 shell_rcvmsg, 103 hammer2_shell_parse, 104 shell_ttymsg); 105 fcntl(0, F_SETFL, O_NONBLOCK); 106 printf("debug: connected\n"); 107 108 msg = dmsg_msg_alloc(&iocom.state0, 0, DMSG_DBG_SHELL, NULL, NULL); 109 dmsg_msg_write(msg); 110 dmsg_iocom_core(&iocom); 111 fprintf(stderr, "debug: disconnected\n"); 112 close(fd); 113 return 0; 114 } 115 #endif 116 117 /* 118 * Debug session front-end 119 * 120 * Callback from dmsg_iocom_core() when messages might be present 121 * on the socket. 122 */ 123 static 124 void 125 shell_msghandler(dmsg_msg_t *msg, int unmanaged) 126 { 127 dmsg_msg_t *nmsg; 128 129 switch(msg->tcmd) { 130 #if 0 131 case DMSG_LNK_ERROR: 132 case DMSG_LNK_ERROR | DMSGF_REPLY: 133 /* 134 * One-way non-transactional LNK_ERROR messages typically 135 * indicate a connection failure. Error code 0 is used by 136 * the debug shell to indicate no more results from last cmd. 137 */ 138 if (msg->any.head.error) { 139 fprintf(stderr, "Stream failure: %s\n", 140 dmsg_msg_str(msg)); 141 } else { 142 write(1, "debug> ", 7); 143 } 144 break; 145 case DMSG_LNK_ERROR | DMSGF_DELETE: 146 /* ignore termination of LNK_CONN */ 147 break; 148 #endif 149 case DMSG_DBG_SHELL: 150 /* 151 * We send the commands, not accept them. 152 * (one-way message, not transactional) 153 */ 154 if (unmanaged) 155 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 156 break; 157 case DMSG_DBG_SHELL | DMSGF_REPLY: 158 /* 159 * A reply from the remote is data we copy to stdout. 160 * (one-way message, not transactional) 161 */ 162 if (msg->aux_size) { 163 msg->aux_data[msg->aux_size - 1] = 0; 164 write(1, msg->aux_data, strlen(msg->aux_data)); 165 } 166 break; 167 #if 1 168 case DMSG_LNK_CONN | DMSGF_CREATE: 169 fprintf(stderr, "Debug Shell received LNK_CONN\n"); 170 nmsg = dmsg_msg_alloc(&msg->state->iocom->state0, 0, 171 DMSG_DBG_SHELL, 172 NULL, NULL); 173 dmsg_msg_write(nmsg); 174 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 175 break; 176 case DMSG_LNK_CONN | DMSGF_DELETE: 177 break; 178 #endif 179 default: 180 /* 181 * Ignore any unknown messages, Terminate any unknown 182 * transactions with an error. 183 */ 184 fprintf(stderr, "Unknown message: %s\n", dmsg_msg_str(msg)); 185 if (unmanaged) { 186 if (msg->any.head.cmd & DMSGF_CREATE) 187 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 188 if (msg->any.head.cmd & DMSGF_DELETE) 189 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 190 } 191 break; 192 } 193 } 194 195 /* 196 * Debug session front-end 197 */ 198 static 199 void 200 shell_ttymsg(dmsg_iocom_t *iocom) 201 { 202 dmsg_state_t *pstate; 203 dmsg_msg_t *msg; 204 char buf[256]; 205 char *cmd; 206 size_t len; 207 208 if (fgets(buf, sizeof(buf), stdin) != NULL) { 209 if (buf[0] == '@') { 210 pstate = dmsg_findspan(strtok(buf + 1, " \t\n")); 211 cmd = strtok(NULL, "\n"); 212 } else { 213 pstate = &iocom->state0; 214 cmd = strtok(buf, "\n"); 215 } 216 if (cmd && pstate) { 217 len = strlen(cmd) + 1; 218 msg = dmsg_msg_alloc(pstate, len, DMSG_DBG_SHELL, 219 NULL, NULL); 220 bcopy(cmd, msg->aux_data, len); 221 dmsg_msg_write(msg); 222 } else if (cmd) { 223 fprintf(stderr, "@msgid not found\n"); 224 } else { 225 /* 226 * This should cause the remote end to generate 227 * a debug> prompt (and thus shows that there is 228 * connectivity). 229 */ 230 msg = dmsg_msg_alloc(pstate, 0, DMSG_DBG_SHELL, 231 NULL, NULL); 232 dmsg_msg_write(msg); 233 } 234 } else if (feof(stdin)) { 235 /* 236 * Set EOF flag without setting any error code for normal 237 * EOF. 238 */ 239 iocom->flags |= DMSG_IOCOMF_EOF; 240 } else { 241 clearerr(stdin); 242 } 243 } 244 245 /* 246 * Debug session back-end (on remote side) 247 */ 248 static void shell_span(dmsg_msg_t *msg, char *cmdbuf); 249 static void shell_ping(dmsg_msg_t *msg, char *cmdbuf); 250 251 void 252 hammer2_shell_parse(dmsg_msg_t *msg, int unmanaged) 253 { 254 dmsg_iocom_t *iocom = msg->state->iocom; 255 char *cmdbuf; 256 char *cmdp; 257 uint32_t cmd; 258 259 /* 260 * Filter on debug shell commands and ping responses only 261 */ 262 cmd = msg->any.head.cmd; 263 if ((cmd & DMSGF_CMDSWMASK) == (DMSG_LNK_PING | DMSGF_REPLY)) { 264 dmsg_printf(iocom, "ping reply\n"); 265 return; 266 } 267 268 if ((cmd & DMSGF_PROTOS) != DMSG_PROTO_DBG) { 269 if (unmanaged) 270 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 271 return; 272 } 273 if ((cmd & DMSGF_CMDSWMASK) != DMSG_DBG_SHELL) { 274 if (unmanaged) 275 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 276 return; 277 } 278 279 /* 280 * Debug shell command 281 */ 282 cmdbuf = msg->aux_data; 283 cmdp = strsep(&cmdbuf, " \t"); 284 285 if (cmdp == NULL || *cmdp == 0) { 286 ; 287 } else if (strcmp(cmdp, "ping") == 0) { 288 shell_ping(msg, cmdbuf); 289 } else if (strcmp(cmdp, "span") == 0) { 290 shell_span(msg, cmdbuf); 291 } else if (strcmp(cmdp, "tree") == 0) { 292 dmsg_shell_tree(iocom, cmdbuf); /* dump spanning tree */ 293 } else if (strcmp(cmdp, "help") == 0 || strcmp(cmdp, "?") == 0) { 294 dmsg_printf(iocom, "help Command help\n"); 295 dmsg_printf(iocom, "span <host> Span to target host\n"); 296 dmsg_printf(iocom, "tree Dump spanning tree\n"); 297 dmsg_printf(iocom, "@span <cmd> Issue via circuit\n"); 298 } else { 299 dmsg_printf(iocom, "Unrecognized command: %s\n", cmdp); 300 } 301 dmsg_printf(iocom, "debug> "); 302 } 303 304 static void 305 shell_ping(dmsg_msg_t *msg, char *cmdbuf __unused) 306 { 307 dmsg_iocom_t *iocom = msg->state->iocom; 308 dmsg_msg_t *m2; 309 310 dmsg_printf(iocom, "sending ping\n"); 311 m2 = dmsg_msg_alloc(msg->state, 0, DMSG_LNK_PING, NULL, NULL); 312 dmsg_msg_write(m2); 313 } 314 315 static void 316 shell_span(dmsg_msg_t *msg, char *cmdbuf) 317 { 318 dmsg_iocom_t *iocom = msg->state->iocom; 319 dmsg_master_service_info_t *info; 320 const char *hostname = strsep(&cmdbuf, " \t"); 321 pthread_t thread; 322 int fd; 323 324 /* 325 * Connect to the target 326 */ 327 if (hostname == NULL) { 328 fd = -1; 329 } else { 330 fd = dmsg_connect(hostname); 331 } 332 333 /* 334 * Start master service 335 */ 336 if (fd < 0) { 337 dmsg_printf(iocom, "Connection to %s failed\n", hostname); 338 } else { 339 dmsg_printf(iocom, "Connected to %s\n", hostname); 340 341 info = malloc(sizeof(*info)); 342 bzero(info, sizeof(*info)); 343 info->fd = fd; 344 info->detachme = 1; 345 info->usrmsg_callback = hammer2_shell_parse; 346 info->label = strdup("client"); 347 348 pthread_create(&thread, NULL, dmsg_master_service, info); 349 /*pthread_join(thread, &res);*/ 350 } 351 } 352 353 /************************************************************************ 354 * DEBUGSPAN * 355 ************************************************************************ 356 * 357 * Connect to the target manually (not via the cluster list embedded in 358 * a hammer2 filesystem) and initiate the SPAN protocol. 359 */ 360 int 361 cmd_debugspan(const char *hostname) 362 { 363 pthread_t thread; 364 int fd; 365 void *res; 366 367 /* 368 * Connect to the target 369 */ 370 fd = dmsg_connect(hostname); 371 if (fd < 0) 372 return 1; 373 374 printf("debugspan: connected to %s, starting CONN/SPAN\n", hostname); 375 pthread_create(&thread, NULL, 376 dmsg_master_service, (void *)(intptr_t)fd); 377 pthread_join(thread, &res); 378 return(0); 379 } 380 381 /************************************************************************ 382 * SHOW * 383 ************************************************************************/ 384 385 static void show_volhdr(hammer2_volume_data_t *voldata, int bi); 386 static void show_bref(hammer2_volume_data_t *voldata, int tab, 387 int bi, hammer2_blockref_t *bref, int norecurse); 388 static void tabprintf(int tab, const char *ctl, ...); 389 390 static hammer2_off_t TotalAccum16[4]; /* includes TotalAccum64 */ 391 static hammer2_off_t TotalAccum64[4]; 392 static hammer2_off_t TotalUnavail; 393 static hammer2_off_t TotalFreemap; 394 395 static 396 hammer2_off_t 397 get_next_volume(hammer2_volume_data_t *voldata, hammer2_off_t volu_loff) 398 { 399 hammer2_off_t ret = -1; 400 int i; 401 402 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 403 hammer2_off_t tmp = voldata->volu_loff[i]; 404 if (tmp > volu_loff) { 405 ret = tmp; 406 break; 407 } 408 } 409 return ret; 410 } 411 412 int 413 cmd_show(const char *devpath, int which) 414 { 415 hammer2_blockref_t broot; 416 hammer2_blockref_t best; 417 hammer2_media_data_t media; 418 hammer2_media_data_t best_media; 419 hammer2_off_t off, volu_loff, next_volu_loff = 0; 420 int fd; 421 int i; 422 int best_i; 423 char *env; 424 425 memset(TotalAccum16, 0, sizeof(TotalAccum16)); 426 memset(TotalAccum64, 0, sizeof(TotalAccum64)); 427 TotalUnavail = TotalFreemap = 0; 428 429 env = getenv("HAMMER2_SHOW_ALL_VOLUME_HEADERS"); 430 if (env != NULL) { 431 show_all_volume_headers = (int)strtol(env, NULL, 0); 432 if (errno) 433 show_all_volume_headers = 0; 434 errno = 0; 435 } 436 env = getenv("HAMMER2_SHOW_TAB"); 437 if (env != NULL) { 438 show_tab = (int)strtol(env, NULL, 0); 439 if (errno || show_tab < 0 || show_tab > 8) 440 show_tab = 2; 441 errno = 0; 442 } 443 env = getenv("HAMMER2_SHOW_DEPTH"); 444 if (env != NULL) { 445 show_depth = (int)strtol(env, NULL, 0); 446 if (errno || show_depth < 0) 447 show_depth = -1; 448 errno = 0; 449 } 450 env = getenv("HAMMER2_SHOW_MIN_MIRROR_TID"); 451 if (env != NULL) { 452 show_min_mirror_tid = (hammer2_tid_t)strtoull(env, NULL, 16); 453 if (errno) 454 show_min_mirror_tid = 0; 455 errno = 0; 456 } 457 env = getenv("HAMMER2_SHOW_MIN_MODIFY_TID"); 458 if (env != NULL) { 459 show_min_modify_tid = (hammer2_tid_t)strtoull(env, NULL, 16); 460 if (errno) 461 show_min_modify_tid = 0; 462 errno = 0; 463 } 464 465 hammer2_init_volumes(devpath, 1); 466 int all_volume_headers = VerboseOpt >= 3 || show_all_volume_headers; 467 next_volume: 468 volu_loff = next_volu_loff; 469 next_volu_loff = -1; 470 printf("%s\n", hammer2_get_volume_path(volu_loff)); 471 /* 472 * Show the tree using the best volume header. 473 * -vvv will show the tree for all four volume headers. 474 */ 475 best_i = -1; 476 bzero(&best, sizeof(best)); 477 bzero(&best_media, sizeof(best_media)); 478 for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) { 479 bzero(&broot, sizeof(broot)); 480 broot.data_off = (i * HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX; 481 off = broot.data_off & ~HAMMER2_OFF_MASK_RADIX; 482 fd = hammer2_get_volume_fd(volu_loff); 483 lseek(fd, off, SEEK_SET); 484 if (read(fd, &media, HAMMER2_PBUFSIZE) == 485 (ssize_t)HAMMER2_PBUFSIZE) { 486 broot.mirror_tid = media.voldata.mirror_tid; 487 if (best_i < 0 || best.mirror_tid < broot.mirror_tid) { 488 best_i = i; 489 best = broot; 490 best_media = media; 491 } 492 printf("Volume %d header %d: mirror_tid=%016jx\n", 493 media.voldata.volu_id, i, 494 (intmax_t)broot.mirror_tid); 495 496 if (all_volume_headers) { 497 switch(which) { 498 case 0: 499 broot.type = HAMMER2_BREF_TYPE_VOLUME; 500 show_bref(&media.voldata, 0, i, &broot, 501 0); 502 break; 503 case 1: 504 broot.type = HAMMER2_BREF_TYPE_FREEMAP; 505 show_bref(&media.voldata, 0, i, &broot, 506 0); 507 break; 508 default: 509 show_volhdr(&media.voldata, i); 510 if (i == 0) 511 next_volu_loff = get_next_volume(&media.voldata, volu_loff); 512 break; 513 } 514 if (i != HAMMER2_NUM_VOLHDRS - 1) 515 printf("\n"); 516 } 517 } 518 } 519 if (next_volu_loff != (hammer2_off_t)-1) { 520 printf("---------------------------------------------\n"); 521 goto next_volume; 522 } 523 524 if (!all_volume_headers) { 525 switch(which) { 526 case 0: 527 best.type = HAMMER2_BREF_TYPE_VOLUME; 528 show_bref(&best_media.voldata, 0, best_i, &best, 0); 529 break; 530 case 1: 531 best.type = HAMMER2_BREF_TYPE_FREEMAP; 532 show_bref(&best_media.voldata, 0, best_i, &best, 0); 533 break; 534 default: 535 show_volhdr(&best_media.voldata, best_i); 536 next_volu_loff = get_next_volume(&best_media.voldata, volu_loff); 537 if (next_volu_loff != (hammer2_off_t)-1) { 538 printf("---------------------------------------------\n"); 539 goto next_volume; 540 } 541 break; 542 } 543 } 544 545 if (which == 1 && VerboseOpt < 3) { 546 printf("Total unallocated storage: %6.3fGB (%6.3fGB in 64KB chunks)\n", 547 (double)TotalAccum16[0] / GIG, 548 (double)TotalAccum64[0] / GIG); 549 printf("Total possibly free storage: %6.3fGB (%6.3fGB in 64KB chunks)\n", 550 (double)TotalAccum16[2] / GIG, 551 (double)TotalAccum64[2] / GIG); 552 printf("Total allocated storage: %6.3fGB (%6.3fGB in 64KB chunks)\n", 553 (double)TotalAccum16[3] / GIG, 554 (double)TotalAccum64[3] / GIG); 555 printf("Total unavailable storage: %6.3fGB\n", 556 (double)TotalUnavail / GIG); 557 printf("Total freemap storage: %6.3fGB\n", 558 (double)TotalFreemap / GIG); 559 } 560 hammer2_cleanup_volumes(); 561 562 return 0; 563 } 564 565 static void 566 show_volhdr(hammer2_volume_data_t *voldata, int bi) 567 { 568 uint32_t status; 569 uint32_t i; 570 char *str; 571 char *name; 572 char *buf; 573 uuid_t uuid; 574 575 printf("\nVolume %d header %d {\n", voldata->volu_id, bi); 576 printf(" magic 0x%016jx\n", (intmax_t)voldata->magic); 577 printf(" boot_beg 0x%016jx\n", (intmax_t)voldata->boot_beg); 578 printf(" boot_end 0x%016jx (%6.2fMB)\n", 579 (intmax_t)voldata->boot_end, 580 (double)(voldata->boot_end - voldata->boot_beg) / 581 (1024.0*1024.0)); 582 printf(" aux_beg 0x%016jx\n", (intmax_t)voldata->aux_beg); 583 printf(" aux_end 0x%016jx (%6.2fMB)\n", 584 (intmax_t)voldata->aux_end, 585 (double)(voldata->aux_end - voldata->aux_beg) / 586 (1024.0*1024.0)); 587 printf(" volu_size 0x%016jx (%6.2fGB)\n", 588 (intmax_t)voldata->volu_size, 589 (double)voldata->volu_size / GIG); 590 printf(" version %d\n", voldata->version); 591 printf(" flags 0x%08x\n", voldata->flags); 592 printf(" copyid %d\n", voldata->copyid); 593 printf(" freemap_vers %d\n", voldata->freemap_version); 594 printf(" peer_type %d\n", voldata->peer_type); 595 printf(" volu_id %d\n", voldata->volu_id); 596 printf(" nvolumes %d\n", voldata->nvolumes); 597 598 str = NULL; 599 uuid = voldata->fsid; 600 hammer2_uuid_to_str(&uuid, &str); 601 printf(" fsid %s\n", str); 602 free(str); 603 604 str = NULL; 605 name = NULL; 606 uuid = voldata->fstype; 607 hammer2_uuid_to_str(&uuid, &str); 608 printf(" fstype %s\n", str); 609 uuid_addr_lookup(&voldata->fstype, &name, &status); 610 if (name == NULL) 611 name = strdup("?"); 612 printf(" (%s)\n", name); 613 free(name); 614 free(str); 615 616 printf(" allocator_size 0x%016jx (%6.2fGB)\n", 617 voldata->allocator_size, 618 (double)voldata->allocator_size / GIG); 619 printf(" allocator_free 0x%016jx (%6.2fGB)\n", 620 voldata->allocator_free, 621 (double)voldata->allocator_free / GIG); 622 printf(" allocator_beg 0x%016jx (%6.2fGB)\n", 623 voldata->allocator_beg, 624 (double)voldata->allocator_beg / GIG); 625 626 printf(" mirror_tid 0x%016jx\n", voldata->mirror_tid); 627 printf(" reserved0080 0x%016jx\n", voldata->reserved0080); 628 printf(" reserved0088 0x%016jx\n", voldata->reserved0088); 629 printf(" freemap_tid 0x%016jx\n", voldata->freemap_tid); 630 printf(" bulkfree_tid 0x%016jx\n", voldata->bulkfree_tid); 631 for (i = 0; i < nitems(voldata->reserved00A0); ++i) { 632 printf(" reserved00A0/%u 0x%016jx\n", 633 i, voldata->reserved00A0[0]); 634 } 635 printf(" total_size 0x%016jx\n", voldata->total_size); 636 637 printf(" copyexists "); 638 for (i = 0; i < nitems(voldata->copyexists); ++i) 639 printf(" 0x%02x", voldata->copyexists[i]); 640 printf("\n"); 641 642 /* 643 * NOTE: Index numbers and ICRC_SECTn definitions are not matched, 644 * the ICRC for sector 0 actually uses the last index, for 645 * example. 646 * 647 * NOTE: The whole voldata CRC does not have to match critically 648 * as certain sub-areas of the volume header have their own 649 * CRCs. 650 */ 651 printf("\n"); 652 for (i = 0; i < nitems(voldata->icrc_sects); ++i) { 653 printf(" icrc_sects[%u] ", i); 654 switch(i) { 655 case HAMMER2_VOL_ICRC_SECT0: 656 printf("0x%08x/0x%08x", 657 hammer2_icrc32((char *)voldata + 658 HAMMER2_VOLUME_ICRC0_OFF, 659 HAMMER2_VOLUME_ICRC0_SIZE), 660 voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT0]); 661 if (hammer2_icrc32((char *)voldata + 662 HAMMER2_VOLUME_ICRC0_OFF, 663 HAMMER2_VOLUME_ICRC0_SIZE) == 664 voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT0]) { 665 printf(" (OK)"); 666 } else { 667 printf(" (FAILED)"); 668 } 669 break; 670 case HAMMER2_VOL_ICRC_SECT1: 671 printf("0x%08x/0x%08x", 672 hammer2_icrc32((char *)voldata + 673 HAMMER2_VOLUME_ICRC1_OFF, 674 HAMMER2_VOLUME_ICRC1_SIZE), 675 voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT1]); 676 if (hammer2_icrc32((char *)voldata + 677 HAMMER2_VOLUME_ICRC1_OFF, 678 HAMMER2_VOLUME_ICRC1_SIZE) == 679 voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT1]) { 680 printf(" (OK)"); 681 } else { 682 printf(" (FAILED)"); 683 } 684 685 break; 686 default: 687 printf("0x%08x (reserved)", voldata->icrc_sects[i]); 688 break; 689 } 690 printf("\n"); 691 } 692 printf(" icrc_volhdr 0x%08x/0x%08x", 693 hammer2_icrc32((char *)voldata + HAMMER2_VOLUME_ICRCVH_OFF, 694 HAMMER2_VOLUME_ICRCVH_SIZE), 695 voldata->icrc_volheader); 696 if (hammer2_icrc32((char *)voldata + HAMMER2_VOLUME_ICRCVH_OFF, 697 HAMMER2_VOLUME_ICRCVH_SIZE) == 698 voldata->icrc_volheader) { 699 printf(" (OK)\n"); 700 } else { 701 printf(" (FAILED - not a critical error)\n"); 702 } 703 704 /* 705 * The super-root and freemap blocksets (not recursed) 706 */ 707 printf("\n"); 708 printf(" sroot_blockset {\n"); 709 for (i = 0; i < HAMMER2_SET_COUNT; ++i) { 710 show_bref(voldata, 16, i, 711 &voldata->sroot_blockset.blockref[i], 2); 712 } 713 printf(" }\n"); 714 715 printf(" freemap_blockset {\n"); 716 for (i = 0; i < HAMMER2_SET_COUNT; ++i) { 717 show_bref(voldata, 16, i, 718 &voldata->freemap_blockset.blockref[i], 2); 719 } 720 printf(" }\n"); 721 722 buf = calloc(1, sizeof(voldata->volu_loff)); 723 if (bcmp(buf, voldata->volu_loff, sizeof(voldata->volu_loff))) { 724 printf("\n"); 725 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 726 hammer2_off_t loff = voldata->volu_loff[i]; 727 if (loff != (hammer2_off_t)-1) 728 printf(" volu_loff[%d] 0x%016jx\n", i, loff); 729 } 730 } 731 free(buf); 732 733 printf("}\n"); 734 } 735 736 static void 737 show_bref(hammer2_volume_data_t *voldata, int tab, int bi, 738 hammer2_blockref_t *bref, int norecurse) 739 { 740 hammer2_media_data_t media; 741 hammer2_blockref_t *bscan; 742 hammer2_off_t tmp; 743 int i, bcount, namelen, failed, obrace, fd; 744 int type_pad; 745 size_t bytes; 746 const char *type_str; 747 char *str = NULL; 748 char check_str[32], comp_str[32]; 749 uint8_t check_algo, comp_algo; 750 uint32_t cv; 751 uint64_t cv64; 752 static int init_tab = -1; 753 uuid_t uuid; 754 755 SHA256_CTX hash_ctx; 756 union { 757 uint8_t digest[SHA256_DIGEST_LENGTH]; 758 uint64_t digest64[SHA256_DIGEST_LENGTH/8]; 759 } u; 760 761 /* omit if smaller than mininum mirror_tid threshold */ 762 if (bref->mirror_tid < show_min_mirror_tid) 763 return; 764 /* omit if smaller than mininum modify_tid threshold */ 765 if (bref->modify_tid < show_min_modify_tid) { 766 if (bref->modify_tid) 767 return; 768 else if (bref->type == HAMMER2_BREF_TYPE_INODE && !bref->leaf_count) 769 return; 770 } 771 772 if (init_tab == -1) 773 init_tab = tab; 774 775 bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX); 776 if (bytes) 777 bytes = (size_t)1 << bytes; 778 if (bytes) { 779 hammer2_off_t io_off; 780 hammer2_off_t io_base; 781 size_t io_bytes; 782 size_t boff; 783 784 io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; 785 io_base = io_off & ~(hammer2_off_t)(HAMMER2_LBUFSIZE - 1); 786 boff = io_off - io_base; 787 788 io_bytes = HAMMER2_LBUFSIZE; 789 while (io_bytes + boff < bytes) 790 io_bytes <<= 1; 791 792 if (io_bytes > sizeof(media)) { 793 printf("(bad block size %zu)\n", bytes); 794 return; 795 } 796 if (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1) { 797 fd = hammer2_get_volume_fd(io_off); 798 lseek(fd, io_base - hammer2_get_volume_offset(io_base), 799 SEEK_SET); 800 if (read(fd, &media, io_bytes) != (ssize_t)io_bytes) { 801 printf("(media read failed)\n"); 802 return; 803 } 804 if (boff) 805 bcopy((char *)&media + boff, &media, bytes); 806 } 807 } 808 809 bscan = NULL; 810 bcount = 0; 811 namelen = 0; 812 failed = 0; 813 obrace = 1; 814 815 type_str = hammer2_breftype_to_str(bref->type); 816 type_pad = 8 - strlen(type_str); 817 if (type_pad < 0) 818 type_pad = 0; 819 820 switch(bref->type) { 821 case HAMMER2_BREF_TYPE_INODE: 822 assert(bytes); 823 if (!(media.ipdata.meta.op_flags & HAMMER2_OPFLAG_DIRECTDATA)) { 824 bscan = &media.ipdata.u.blockset.blockref[0]; 825 bcount = HAMMER2_SET_COUNT; 826 } 827 break; 828 case HAMMER2_BREF_TYPE_INDIRECT: 829 assert(bytes); 830 bscan = &media.npdata[0]; 831 bcount = bytes / sizeof(hammer2_blockref_t); 832 break; 833 case HAMMER2_BREF_TYPE_VOLUME: 834 bscan = &media.voldata.sroot_blockset.blockref[0]; 835 bcount = HAMMER2_SET_COUNT; 836 break; 837 case HAMMER2_BREF_TYPE_FREEMAP: 838 bscan = &media.voldata.freemap_blockset.blockref[0]; 839 bcount = HAMMER2_SET_COUNT; 840 break; 841 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 842 assert(bytes); 843 bscan = &media.npdata[0]; 844 bcount = bytes / sizeof(hammer2_blockref_t); 845 break; 846 } 847 848 if (QuietOpt > 0) { 849 tabprintf(tab, 850 "%s.%-3d %016jx %016jx/%-2d " 851 "vol=%d mir=%016jx mod=%016jx leafcnt=%d ", 852 type_str, bi, (intmax_t)bref->data_off, 853 (intmax_t)bref->key, (intmax_t)bref->keybits, 854 hammer2_get_volume_id(bref->data_off), 855 (intmax_t)bref->mirror_tid, 856 (intmax_t)bref->modify_tid, 857 bref->leaf_count); 858 } else { 859 tabprintf(tab, "%s.%-3d%*.*s %016jx %016jx/%-2d ", 860 type_str, bi, type_pad, type_pad, "", 861 (intmax_t)bref->data_off, 862 (intmax_t)bref->key, (intmax_t)bref->keybits); 863 /*if (norecurse > 1)*/ { 864 printf("\n"); 865 tabprintf(tab + 13, ""); 866 } 867 printf("vol=%d mir=%016jx mod=%016jx lfcnt=%d ", 868 hammer2_get_volume_id(bref->data_off), 869 (intmax_t)bref->mirror_tid, (intmax_t)bref->modify_tid, 870 bref->leaf_count); 871 if (/*norecurse > 1 && */ (bcount || bref->flags || 872 bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE || 873 bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF)) { 874 printf("\n"); 875 tabprintf(tab + 13, ""); 876 } 877 } 878 879 if (bcount) 880 printf("bcnt=%d ", bcount); 881 if (bref->flags) 882 printf("flags=%02x ", bref->flags); 883 if (bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE || 884 bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF) { 885 printf("bigmask=%08x avail=%ju ", 886 bref->check.freemap.bigmask, 887 (uintmax_t)bref->check.freemap.avail); 888 } 889 890 /* 891 * Check data integrity in verbose mode, otherwise we are just doing 892 * a quick meta-data scan. Meta-data integrity is always checked. 893 * (Also see the check above that ensures the media data is loaded, 894 * otherwise there's no data to check!). 895 * 896 * WARNING! bref->check state may be used for other things when 897 * bref has no data (bytes == 0). 898 */ 899 if (bytes && 900 (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1)) { 901 if (!(QuietOpt > 0)) { 902 /*if (norecurse > 1)*/ { 903 printf("\n"); 904 tabprintf(tab + 13, ""); 905 } 906 } 907 908 check_algo = HAMMER2_DEC_CHECK(bref->methods); 909 strlcpy(check_str, hammer2_checkmode_to_str(check_algo), 910 sizeof(check_str)); 911 comp_algo = HAMMER2_DEC_COMP(bref->methods); 912 strlcpy(comp_str, hammer2_compmode_to_str(comp_algo), 913 sizeof(comp_str)); 914 915 switch(check_algo) { 916 case HAMMER2_CHECK_NONE: 917 printf("meth=%s|%s ", check_str, comp_str); 918 break; 919 case HAMMER2_CHECK_DISABLED: 920 printf("meth=%s|%s ", check_str, comp_str); 921 break; 922 case HAMMER2_CHECK_ISCSI32: 923 cv = hammer2_icrc32(&media, bytes); 924 if (bref->check.iscsi32.value != cv) { 925 printf("(icrc %s|%s %08x/%08x failed) ", 926 check_str, comp_str, 927 bref->check.iscsi32.value, 928 cv); 929 failed = 1; 930 } else { 931 printf("meth=%s|%s iscsi32=%08x ", 932 check_str, comp_str, cv); 933 } 934 break; 935 case HAMMER2_CHECK_XXHASH64: 936 cv64 = XXH64(&media, bytes, XXH_HAMMER2_SEED); 937 if (bref->check.xxhash64.value != cv64) { 938 printf("(xxhash64 %s|%s %016jx/%016jx failed) ", 939 check_str, comp_str, 940 bref->check.xxhash64.value, 941 cv64); 942 failed = 1; 943 } else { 944 printf("meth=%s|%s xxh=%016jx ", 945 check_str, comp_str, cv64); 946 } 947 break; 948 case HAMMER2_CHECK_SHA192: 949 SHA256_Init(&hash_ctx); 950 SHA256_Update(&hash_ctx, &media, bytes); 951 SHA256_Final(u.digest, &hash_ctx); 952 u.digest64[2] ^= u.digest64[3]; 953 if (memcmp(u.digest, bref->check.sha192.data, 954 sizeof(bref->check.sha192.data))) { 955 printf("(sha192 %s:%s failed) ", 956 check_str, comp_str); 957 failed = 1; 958 } else { 959 printf("meth=%s|%s ", check_str, comp_str); 960 } 961 break; 962 case HAMMER2_CHECK_FREEMAP: 963 cv = hammer2_icrc32(&media, bytes); 964 if (bref->check.freemap.icrc32 != cv) { 965 printf("(fcrc %s|%s %08x/%08x failed) ", 966 check_str, comp_str, 967 bref->check.freemap.icrc32, 968 cv); 969 failed = 1; 970 } else { 971 printf("meth=%s|%s fcrc=%08x ", 972 check_str, comp_str, cv); 973 } 974 break; 975 } 976 } 977 978 tab += show_tab; 979 980 if (QuietOpt > 0) { 981 obrace = 0; 982 printf("\n"); 983 goto skip_data; 984 } 985 986 switch(bref->type) { 987 case HAMMER2_BREF_TYPE_EMPTY: 988 if (norecurse) 989 printf("\n"); 990 obrace = 0; 991 break; 992 case HAMMER2_BREF_TYPE_DIRENT: 993 printf("{\n"); 994 if (bref->embed.dirent.namlen <= sizeof(bref->check.buf)) { 995 tabprintf(tab, "filename \"%*.*s\"\n", 996 bref->embed.dirent.namlen, 997 bref->embed.dirent.namlen, 998 bref->check.buf); 999 } else { 1000 tabprintf(tab, "filename \"%*.*s\"\n", 1001 bref->embed.dirent.namlen, 1002 bref->embed.dirent.namlen, 1003 media.buf); 1004 } 1005 tabprintf(tab, "inum 0x%016jx\n", 1006 (uintmax_t)bref->embed.dirent.inum); 1007 tabprintf(tab, "nlen %d\n", bref->embed.dirent.namlen); 1008 tabprintf(tab, "type %s\n", 1009 hammer2_iptype_to_str(bref->embed.dirent.type)); 1010 break; 1011 case HAMMER2_BREF_TYPE_INODE: 1012 printf("{\n"); 1013 namelen = media.ipdata.meta.name_len; 1014 if (namelen > HAMMER2_INODE_MAXNAME) 1015 namelen = 0; 1016 tabprintf(tab, "filename \"%*.*s\"\n", 1017 namelen, namelen, media.ipdata.filename); 1018 tabprintf(tab, "version %d\n", media.ipdata.meta.version); 1019 if ((media.ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) || 1020 media.ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) { 1021 tabprintf(tab, "pfs_st %d (%s)\n", 1022 media.ipdata.meta.pfs_subtype, 1023 hammer2_pfssubtype_to_str(media.ipdata.meta.pfs_subtype)); 1024 } 1025 tabprintf(tab, "uflags 0x%08x\n", 1026 media.ipdata.meta.uflags); 1027 if (media.ipdata.meta.rmajor || media.ipdata.meta.rminor) { 1028 tabprintf(tab, "rmajor %d\n", 1029 media.ipdata.meta.rmajor); 1030 tabprintf(tab, "rminor %d\n", 1031 media.ipdata.meta.rminor); 1032 } 1033 tabprintf(tab, "ctime %s\n", 1034 hammer2_time64_to_str(media.ipdata.meta.ctime, &str)); 1035 tabprintf(tab, "mtime %s\n", 1036 hammer2_time64_to_str(media.ipdata.meta.mtime, &str)); 1037 tabprintf(tab, "atime %s\n", 1038 hammer2_time64_to_str(media.ipdata.meta.atime, &str)); 1039 tabprintf(tab, "btime %s\n", 1040 hammer2_time64_to_str(media.ipdata.meta.btime, &str)); 1041 uuid = media.ipdata.meta.uid; 1042 tabprintf(tab, "uid %s\n", 1043 hammer2_uuid_to_str(&uuid, &str)); 1044 uuid = media.ipdata.meta.gid; 1045 tabprintf(tab, "gid %s\n", 1046 hammer2_uuid_to_str(&uuid, &str)); 1047 tabprintf(tab, "type %s\n", 1048 hammer2_iptype_to_str(media.ipdata.meta.type)); 1049 tabprintf(tab, "opflgs 0x%02x\n", 1050 media.ipdata.meta.op_flags); 1051 tabprintf(tab, "capflgs 0x%04x\n", 1052 media.ipdata.meta.cap_flags); 1053 tabprintf(tab, "mode %-7o\n", 1054 media.ipdata.meta.mode); 1055 tabprintf(tab, "inum 0x%016jx\n", 1056 media.ipdata.meta.inum); 1057 tabprintf(tab, "size %ju ", 1058 (uintmax_t)media.ipdata.meta.size); 1059 if (media.ipdata.meta.op_flags & HAMMER2_OPFLAG_DIRECTDATA && 1060 media.ipdata.meta.size <= HAMMER2_EMBEDDED_BYTES) 1061 printf("(embedded data)\n"); 1062 else 1063 printf("\n"); 1064 tabprintf(tab, "nlinks %ju\n", 1065 (uintmax_t)media.ipdata.meta.nlinks); 1066 tabprintf(tab, "iparent 0x%016jx\n", 1067 (uintmax_t)media.ipdata.meta.iparent); 1068 tabprintf(tab, "name_key 0x%016jx\n", 1069 (uintmax_t)media.ipdata.meta.name_key); 1070 tabprintf(tab, "name_len %u\n", 1071 media.ipdata.meta.name_len); 1072 tabprintf(tab, "ncopies %u\n", 1073 media.ipdata.meta.ncopies); 1074 tabprintf(tab, "compalg %s\n", 1075 hammer2_compmode_to_str(media.ipdata.meta.comp_algo)); 1076 tabprintf(tab, "checkalg %s\n", 1077 hammer2_checkmode_to_str(media.ipdata.meta.check_algo)); 1078 if ((media.ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) || 1079 media.ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) { 1080 tabprintf(tab, "pfs_nmas %u\n", 1081 media.ipdata.meta.pfs_nmasters); 1082 tabprintf(tab, "pfs_type %u (%s)\n", 1083 media.ipdata.meta.pfs_type, 1084 hammer2_pfstype_to_str(media.ipdata.meta.pfs_type)); 1085 tabprintf(tab, "pfs_inum 0x%016jx\n", 1086 (uintmax_t)media.ipdata.meta.pfs_inum); 1087 uuid = media.ipdata.meta.pfs_clid; 1088 tabprintf(tab, "pfs_clid %s\n", 1089 hammer2_uuid_to_str(&uuid, &str)); 1090 uuid = media.ipdata.meta.pfs_fsid; 1091 tabprintf(tab, "pfs_fsid %s\n", 1092 hammer2_uuid_to_str(&uuid, &str)); 1093 tabprintf(tab, "pfs_lsnap_tid 0x%016jx\n", 1094 (uintmax_t)media.ipdata.meta.pfs_lsnap_tid); 1095 } 1096 tabprintf(tab, "data_quota %ju\n", 1097 (uintmax_t)media.ipdata.meta.data_quota); 1098 tabprintf(tab, "data_count %ju\n", 1099 (uintmax_t)bref->embed.stats.data_count); 1100 tabprintf(tab, "inode_quota %ju\n", 1101 (uintmax_t)media.ipdata.meta.inode_quota); 1102 tabprintf(tab, "inode_count %ju\n", 1103 (uintmax_t)bref->embed.stats.inode_count); 1104 break; 1105 case HAMMER2_BREF_TYPE_INDIRECT: 1106 printf("{\n"); 1107 break; 1108 case HAMMER2_BREF_TYPE_DATA: 1109 printf("\n"); 1110 obrace = 0; 1111 break; 1112 case HAMMER2_BREF_TYPE_VOLUME: 1113 printf("mirror_tid=%016jx freemap_tid=%016jx ", 1114 media.voldata.mirror_tid, 1115 media.voldata.freemap_tid); 1116 printf("{\n"); 1117 break; 1118 case HAMMER2_BREF_TYPE_FREEMAP: 1119 printf("mirror_tid=%016jx freemap_tid=%016jx ", 1120 media.voldata.mirror_tid, 1121 media.voldata.freemap_tid); 1122 printf("{\n"); 1123 break; 1124 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 1125 printf("{\n"); 1126 tmp = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; 1127 tmp &= HAMMER2_SEGMASK; 1128 tmp /= HAMMER2_PBUFSIZE; 1129 assert(tmp >= HAMMER2_ZONE_FREEMAP_00); 1130 assert(tmp < HAMMER2_ZONE_FREEMAP_END); 1131 tmp -= HAMMER2_ZONE_FREEMAP_00; 1132 tmp /= HAMMER2_ZONE_FREEMAP_INC; 1133 tabprintf(tab, "rotation=%d\n", (int)tmp); 1134 1135 for (i = 0; i < HAMMER2_FREEMAP_COUNT; ++i) { 1136 hammer2_off_t data_off = bref->key + 1137 i * HAMMER2_FREEMAP_LEVEL0_SIZE; 1138 #if HAMMER2_BMAP_ELEMENTS != 8 1139 #error "cmd_debug.c: HAMMER2_BMAP_ELEMENTS expected to be 8" 1140 #endif 1141 tabprintf(tab + 4, "%016jx %04d.%04x linear=%06x avail=%06x " 1142 "%016jx %016jx %016jx %016jx " 1143 "%016jx %016jx %016jx %016jx\n", 1144 data_off, i, media.bmdata[i].class, 1145 media.bmdata[i].linear, 1146 media.bmdata[i].avail, 1147 media.bmdata[i].bitmapq[0], 1148 media.bmdata[i].bitmapq[1], 1149 media.bmdata[i].bitmapq[2], 1150 media.bmdata[i].bitmapq[3], 1151 media.bmdata[i].bitmapq[4], 1152 media.bmdata[i].bitmapq[5], 1153 media.bmdata[i].bitmapq[6], 1154 media.bmdata[i].bitmapq[7]); 1155 } 1156 tabprintf(tab, "}\n"); 1157 break; 1158 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 1159 printf("{\n"); 1160 tmp = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; 1161 tmp &= HAMMER2_SEGMASK; 1162 tmp /= HAMMER2_PBUFSIZE; 1163 assert(tmp >= HAMMER2_ZONE_FREEMAP_00); 1164 assert(tmp < HAMMER2_ZONE_FREEMAP_END); 1165 tmp -= HAMMER2_ZONE_FREEMAP_00; 1166 tmp /= HAMMER2_ZONE_FREEMAP_INC; 1167 tabprintf(tab, "rotation=%d\n", (int)tmp); 1168 break; 1169 default: 1170 printf("\n"); 1171 obrace = 0; 1172 break; 1173 } 1174 if (str) 1175 free(str); 1176 1177 skip_data: 1178 /* 1179 * Update statistics. 1180 */ 1181 switch(bref->type) { 1182 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 1183 for (i = 0; i < HAMMER2_FREEMAP_COUNT; ++i) { 1184 hammer2_off_t data_off = bref->key + 1185 i * HAMMER2_FREEMAP_LEVEL0_SIZE; 1186 if (data_off >= voldata->aux_end && 1187 data_off < hammer2_get_total_size()) { 1188 int j; 1189 for (j = 0; j < 4; ++j) 1190 count_blocks(&media.bmdata[i], j, 1191 &TotalAccum16[j], 1192 &TotalAccum64[j]); 1193 } else 1194 TotalUnavail += HAMMER2_FREEMAP_LEVEL0_SIZE; 1195 } 1196 TotalFreemap += HAMMER2_FREEMAP_LEVEL1_SIZE; 1197 break; 1198 default: 1199 break; 1200 } 1201 1202 /* 1203 * Recurse if norecurse == 0. If the CRC failed, pass norecurse = 1. 1204 * That is, if an indirect or inode fails we still try to list its 1205 * direct children to help with debugging, but go no further than 1206 * that because they are probably garbage. 1207 */ 1208 if (show_depth == -1 || ((tab - init_tab) / show_tab) < show_depth) { 1209 for (i = 0; norecurse == 0 && i < bcount; ++i) { 1210 if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) { 1211 show_bref(voldata, tab, i, &bscan[i], 1212 failed); 1213 } 1214 } 1215 } 1216 tab -= show_tab; 1217 if (obrace) { 1218 if (bref->type == HAMMER2_BREF_TYPE_INODE) 1219 tabprintf(tab, "} (%s.%d, \"%*.*s\")\n", 1220 type_str, bi, namelen, namelen, 1221 media.ipdata.filename); 1222 else 1223 tabprintf(tab, "} (%s.%d)\n", type_str, bi); 1224 } 1225 } 1226 1227 static 1228 void 1229 count_blocks(hammer2_bmap_data_t *bmap, int value, 1230 hammer2_off_t *accum16, hammer2_off_t *accum64) 1231 { 1232 int i, j, bits; 1233 hammer2_bitmap_t value16, value64; 1234 1235 bits = (int)sizeof(hammer2_bitmap_t) * 8; 1236 assert(bits == 64); 1237 1238 value16 = value; 1239 assert(value16 < 4); 1240 value64 = (value16 << 6) | (value16 << 4) | (value16 << 2) | value16; 1241 assert(value64 < 256); 1242 1243 for (i = 0; i < HAMMER2_BMAP_ELEMENTS; ++i) { 1244 hammer2_bitmap_t bm = bmap->bitmapq[i]; 1245 hammer2_bitmap_t bm_save = bm; 1246 hammer2_bitmap_t mask; 1247 1248 mask = 0x03; /* 2 bits per 16KB */ 1249 for (j = 0; j < bits; j += 2) { 1250 if ((bm & mask) == value16) 1251 *accum16 += 16384; 1252 bm >>= 2; 1253 } 1254 1255 bm = bm_save; 1256 mask = 0xFF; /* 8 bits per 64KB chunk */ 1257 for (j = 0; j < bits; j += 8) { 1258 if ((bm & mask) == value64) 1259 *accum64 += 65536; 1260 bm >>= 8; 1261 } 1262 } 1263 } 1264 1265 int 1266 cmd_hash(int ac, const char **av) 1267 { 1268 int i; 1269 1270 for (i = 0; i < ac; ++i) { 1271 printf("%016jx %s\n", 1272 dirhash(av[i], strlen(av[i])), 1273 av[i]); 1274 } 1275 return(0); 1276 } 1277 1278 int 1279 cmd_dhash(int ac, const char **av) 1280 { 1281 char buf[1024]; /* 1K extended directory record */ 1282 uint64_t hash; 1283 int i; 1284 1285 for (i = 0; i < ac; ++i) { 1286 bzero(buf, sizeof(buf)); 1287 snprintf(buf, sizeof(buf), "%s", av[i]); 1288 hash = XXH64(buf, sizeof(buf), XXH_HAMMER2_SEED); 1289 printf("%016jx %s\n", hash, av[i]); 1290 } 1291 return(0); 1292 } 1293 1294 int 1295 cmd_dumpchain(const char *path, u_int flags) 1296 { 1297 int dummy = (int)flags; 1298 int ecode = 0; 1299 int fd; 1300 1301 fd = open(path, O_RDONLY); 1302 if (fd >= 0) { 1303 if (ioctl(fd, HAMMER2IOC_DEBUG_DUMP, &dummy) < 0) { 1304 fprintf(stderr, "%s: %s\n", path, strerror(errno)); 1305 ecode = 1; 1306 } 1307 close(fd); 1308 } else { 1309 fprintf(stderr, "unable to open %s\n", path); 1310 ecode = 1; 1311 } 1312 return ecode; 1313 } 1314 1315 static 1316 void 1317 tabprintf(int tab, const char *ctl, ...) 1318 { 1319 va_list va; 1320 1321 printf("%*.*s", tab, tab, ""); 1322 va_start(va, ctl); 1323 vprintf(ctl, va); 1324 va_end(va); 1325 } 1326