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