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 #define SHOW_TAB 2 39 40 static void shell_msghandler(dmsg_msg_t *msg, int unmanaged); 41 static void shell_ttymsg(dmsg_iocom_t *iocom); 42 43 /************************************************************************ 44 * SHELL * 45 ************************************************************************/ 46 47 int 48 cmd_shell(const char *hostname) 49 { 50 dmsg_master_service_info_t *info; 51 pthread_t thread; 52 int fd; 53 54 fd = dmsg_connect(hostname); 55 if (fd < 0) 56 return 1; 57 58 info = malloc(sizeof(*info)); 59 bzero(info, sizeof(*info)); 60 info->fd = fd; 61 info->detachme = 0; 62 info->usrmsg_callback = shell_msghandler; 63 info->altmsg_callback = shell_ttymsg; 64 info->node_handler = NULL; 65 info->label = strdup("debug"); 66 pthread_create(&thread, NULL, dmsg_master_service, info); 67 pthread_join(thread, NULL); 68 69 return 0; 70 } 71 72 #if 0 73 int 74 cmd_shell(const char *hostname) 75 { 76 struct dmsg_iocom iocom; 77 dmsg_msg_t *msg; 78 int fd; 79 80 /* 81 * Connect to the target 82 */ 83 fd = dmsg_connect(hostname); 84 if (fd < 0) 85 return 1; 86 87 /* 88 * Initialize the session and transmit an empty DMSG_DBG_SHELL 89 * to cause the remote end to generate a prompt. 90 */ 91 dmsg_iocom_init(&iocom, fd, 0, 92 NULL, 93 shell_rcvmsg, 94 hammer2_shell_parse, 95 shell_ttymsg); 96 fcntl(0, F_SETFL, O_NONBLOCK); 97 printf("debug: connected\n"); 98 99 msg = dmsg_msg_alloc(&iocom.state0, 0, DMSG_DBG_SHELL, NULL, NULL); 100 dmsg_msg_write(msg); 101 dmsg_iocom_core(&iocom); 102 fprintf(stderr, "debug: disconnected\n"); 103 close(fd); 104 return 0; 105 } 106 #endif 107 108 /* 109 * Debug session front-end 110 * 111 * Callback from dmsg_iocom_core() when messages might be present 112 * on the socket. 113 */ 114 static 115 void 116 shell_msghandler(dmsg_msg_t *msg, int unmanaged) 117 { 118 dmsg_msg_t *nmsg; 119 120 switch(msg->tcmd) { 121 #if 0 122 case DMSG_LNK_ERROR: 123 case DMSG_LNK_ERROR | DMSGF_REPLY: 124 /* 125 * One-way non-transactional LNK_ERROR messages typically 126 * indicate a connection failure. Error code 0 is used by 127 * the debug shell to indicate no more results from last cmd. 128 */ 129 if (msg->any.head.error) { 130 fprintf(stderr, "Stream failure: %s\n", 131 dmsg_msg_str(msg)); 132 } else { 133 write(1, "debug> ", 7); 134 } 135 break; 136 case DMSG_LNK_ERROR | DMSGF_DELETE: 137 /* ignore termination of LNK_CONN */ 138 break; 139 #endif 140 case DMSG_DBG_SHELL: 141 /* 142 * We send the commands, not accept them. 143 * (one-way message, not transactional) 144 */ 145 if (unmanaged) 146 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 147 break; 148 case DMSG_DBG_SHELL | DMSGF_REPLY: 149 /* 150 * A reply from the remote is data we copy to stdout. 151 * (one-way message, not transactional) 152 */ 153 if (msg->aux_size) { 154 msg->aux_data[msg->aux_size - 1] = 0; 155 write(1, msg->aux_data, strlen(msg->aux_data)); 156 } 157 break; 158 #if 1 159 case DMSG_LNK_CONN | DMSGF_CREATE: 160 fprintf(stderr, "Debug Shell received LNK_CONN\n"); 161 nmsg = dmsg_msg_alloc(&msg->state->iocom->state0, 0, 162 DMSG_DBG_SHELL, 163 NULL, NULL); 164 dmsg_msg_write(nmsg); 165 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 166 break; 167 case DMSG_LNK_CONN | DMSGF_DELETE: 168 break; 169 #endif 170 default: 171 /* 172 * Ignore any unknown messages, Terminate any unknown 173 * transactions with an error. 174 */ 175 fprintf(stderr, "Unknown message: %s\n", dmsg_msg_str(msg)); 176 if (unmanaged) { 177 if (msg->any.head.cmd & DMSGF_CREATE) 178 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 179 if (msg->any.head.cmd & DMSGF_DELETE) 180 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 181 } 182 break; 183 } 184 } 185 186 /* 187 * Debug session front-end 188 */ 189 static 190 void 191 shell_ttymsg(dmsg_iocom_t *iocom) 192 { 193 dmsg_state_t *pstate; 194 dmsg_msg_t *msg; 195 char buf[256]; 196 char *cmd; 197 size_t len; 198 199 if (fgets(buf, sizeof(buf), stdin) != NULL) { 200 if (buf[0] == '@') { 201 pstate = dmsg_findspan(strtok(buf + 1, " \t\n")); 202 cmd = strtok(NULL, "\n"); 203 } else { 204 pstate = &iocom->state0; 205 cmd = strtok(buf, "\n"); 206 } 207 if (cmd && pstate) { 208 len = strlen(cmd) + 1; 209 msg = dmsg_msg_alloc(pstate, len, DMSG_DBG_SHELL, 210 NULL, NULL); 211 bcopy(cmd, msg->aux_data, len); 212 dmsg_msg_write(msg); 213 } else if (cmd) { 214 fprintf(stderr, "@msgid not found\n"); 215 } else { 216 /* 217 * This should cause the remote end to generate 218 * a debug> prompt (and thus shows that there is 219 * connectivity). 220 */ 221 msg = dmsg_msg_alloc(pstate, 0, DMSG_DBG_SHELL, 222 NULL, NULL); 223 dmsg_msg_write(msg); 224 } 225 } else if (feof(stdin)) { 226 /* 227 * Set EOF flag without setting any error code for normal 228 * EOF. 229 */ 230 iocom->flags |= DMSG_IOCOMF_EOF; 231 } else { 232 clearerr(stdin); 233 } 234 } 235 236 /* 237 * Debug session back-end (on remote side) 238 */ 239 static void shell_span(dmsg_msg_t *msg, char *cmdbuf); 240 241 void 242 hammer2_shell_parse(dmsg_msg_t *msg, int unmanaged) 243 { 244 dmsg_iocom_t *iocom = msg->state->iocom; 245 char *cmdbuf; 246 char *cmdp; 247 uint32_t cmd; 248 249 /* 250 * Filter on debug shell commands only 251 */ 252 cmd = msg->any.head.cmd; 253 if ((cmd & DMSGF_PROTOS) != DMSG_PROTO_DBG) { 254 if (unmanaged) 255 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 256 return; 257 } 258 if ((cmd & DMSGF_CMDSWMASK) != DMSG_DBG_SHELL) { 259 if (unmanaged) 260 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 261 return; 262 } 263 264 /* 265 * Debug shell command 266 */ 267 cmdbuf = msg->aux_data; 268 cmdp = strsep(&cmdbuf, " \t"); 269 270 if (cmdp == NULL || *cmdp == 0) { 271 ; 272 } else if (strcmp(cmdp, "span") == 0) { 273 shell_span(msg, cmdbuf); 274 } else if (strcmp(cmdp, "tree") == 0) { 275 dmsg_shell_tree(iocom, cmdbuf); /* dump spanning tree */ 276 } else if (strcmp(cmdp, "help") == 0 || strcmp(cmdp, "?") == 0) { 277 dmsg_printf(iocom, "help Command help\n"); 278 dmsg_printf(iocom, "span <host> Span to target host\n"); 279 dmsg_printf(iocom, "tree Dump spanning tree\n"); 280 dmsg_printf(iocom, "@span <cmd> Issue via circuit\n"); 281 } else { 282 dmsg_printf(iocom, "Unrecognized command: %s\n", cmdp); 283 } 284 dmsg_printf(iocom, "debug> "); 285 } 286 287 static void 288 shell_span(dmsg_msg_t *msg, char *cmdbuf) 289 { 290 dmsg_iocom_t *iocom = msg->state->iocom; 291 dmsg_master_service_info_t *info; 292 const char *hostname = strsep(&cmdbuf, " \t"); 293 pthread_t thread; 294 int fd; 295 296 /* 297 * Connect to the target 298 */ 299 if (hostname == NULL) { 300 fd = -1; 301 } else { 302 fd = dmsg_connect(hostname); 303 } 304 305 /* 306 * Start master service 307 */ 308 if (fd < 0) { 309 dmsg_printf(iocom, "Connection to %s failed\n", hostname); 310 } else { 311 dmsg_printf(iocom, "Connected to %s\n", hostname); 312 313 info = malloc(sizeof(*info)); 314 bzero(info, sizeof(*info)); 315 info->fd = fd; 316 info->detachme = 1; 317 info->usrmsg_callback = hammer2_shell_parse; 318 info->label = strdup("client"); 319 320 pthread_create(&thread, NULL, dmsg_master_service, info); 321 /*pthread_join(thread, &res);*/ 322 } 323 } 324 325 /************************************************************************ 326 * DEBUGSPAN * 327 ************************************************************************ 328 * 329 * Connect to the target manually (not via the cluster list embedded in 330 * a hammer2 filesystem) and initiate the SPAN protocol. 331 */ 332 int 333 cmd_debugspan(const char *hostname) 334 { 335 pthread_t thread; 336 int fd; 337 void *res; 338 339 /* 340 * Connect to the target 341 */ 342 fd = dmsg_connect(hostname); 343 if (fd < 0) 344 return 1; 345 346 printf("debugspan: connected to %s, starting CONN/SPAN\n", hostname); 347 pthread_create(&thread, NULL, 348 dmsg_master_service, (void *)(intptr_t)fd); 349 pthread_join(thread, &res); 350 return(0); 351 } 352 353 /************************************************************************ 354 * SHOW * 355 ************************************************************************/ 356 357 static void show_bref(int fd, int tab, int bi, hammer2_blockref_t *bref, 358 int dofreemap); 359 static void tabprintf(int tab, const char *ctl, ...); 360 361 int 362 cmd_show(const char *devpath, int dofreemap) 363 { 364 hammer2_blockref_t broot; 365 hammer2_blockref_t best; 366 hammer2_media_data_t media; 367 int fd; 368 int i; 369 int best_i; 370 371 fd = open(devpath, O_RDONLY); 372 if (fd < 0) { 373 perror("open"); 374 return 1; 375 } 376 377 /* 378 * Show the tree using the best volume header. 379 * -vvv will show the tree for all four volume headers. 380 */ 381 best_i = -1; 382 bzero(&best, sizeof(best)); 383 for (i = 0; i < 4; ++i) { 384 bzero(&broot, sizeof(broot)); 385 broot.type = HAMMER2_BREF_TYPE_VOLUME; 386 broot.data_off = (i * HAMMER2_ZONE_BYTES64) | 387 HAMMER2_PBUFRADIX; 388 lseek(fd, broot.data_off & ~HAMMER2_OFF_MASK_RADIX, 0); 389 if (read(fd, &media, HAMMER2_PBUFSIZE) == 390 (ssize_t)HAMMER2_PBUFSIZE) { 391 broot.mirror_tid = media.voldata.mirror_tid; 392 if (best_i < 0 || best.mirror_tid < broot.mirror_tid) { 393 best_i = i; 394 best = broot; 395 } 396 if (VerboseOpt >= 3) 397 show_bref(fd, 0, i, &broot, dofreemap); 398 } 399 } 400 if (VerboseOpt < 3) 401 show_bref(fd, 0, best_i, &best, dofreemap); 402 close(fd); 403 404 return 0; 405 } 406 407 static void 408 show_bref(int fd, int tab, int bi, hammer2_blockref_t *bref, int dofreemap) 409 { 410 hammer2_media_data_t media; 411 hammer2_blockref_t *bscan; 412 int bcount; 413 int i; 414 int didnl; 415 int namelen; 416 int obrace = 1; 417 size_t bytes; 418 const char *type_str; 419 char *str = NULL; 420 421 switch(bref->type) { 422 case HAMMER2_BREF_TYPE_EMPTY: 423 type_str = "empty"; 424 break; 425 case HAMMER2_BREF_TYPE_INODE: 426 type_str = "inode"; 427 break; 428 case HAMMER2_BREF_TYPE_INDIRECT: 429 type_str = "indblk"; 430 break; 431 case HAMMER2_BREF_TYPE_DATA: 432 type_str = "data"; 433 break; 434 case HAMMER2_BREF_TYPE_VOLUME: 435 type_str = "volume"; 436 break; 437 case HAMMER2_BREF_TYPE_FREEMAP: 438 type_str = "freemap"; 439 break; 440 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 441 type_str = "fmapnode"; 442 break; 443 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 444 type_str = "fbitmap"; 445 break; 446 default: 447 type_str = "unknown"; 448 break; 449 } 450 451 tabprintf(tab, "%s.%-3d %016jx %016jx/%-2d mir=%016jx mod=%016jx ", 452 type_str, bi, (intmax_t)bref->data_off, 453 (intmax_t)bref->key, (intmax_t)bref->keybits, 454 (intmax_t)bref->mirror_tid, (intmax_t)bref->modify_tid); 455 tab += SHOW_TAB; 456 457 bytes = (size_t)1 << (bref->data_off & HAMMER2_OFF_MASK_RADIX); 458 459 { 460 hammer2_off_t io_off; 461 hammer2_off_t io_base; 462 size_t io_bytes; 463 size_t boff; 464 465 io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; 466 io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1); 467 io_bytes = bytes; 468 boff = io_off - io_base; 469 470 io_bytes = HAMMER2_MINIOSIZE; 471 while (io_bytes + boff < bytes) 472 io_bytes <<= 1; 473 474 if (io_bytes > sizeof(media)) { 475 printf("(bad block size %zd)\n", bytes); 476 return; 477 } 478 if (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1) { 479 lseek(fd, io_base, 0); 480 if (read(fd, &media, io_bytes) != (ssize_t)io_bytes) { 481 printf("(media read failed)\n"); 482 return; 483 } 484 if (boff) 485 bcopy((char *)&media + boff, &media, bytes); 486 } 487 } 488 489 bscan = NULL; 490 bcount = 0; 491 didnl = 1; 492 namelen = 0; 493 494 switch(bref->type) { 495 case HAMMER2_BREF_TYPE_EMPTY: 496 obrace = 0; 497 break; 498 case HAMMER2_BREF_TYPE_INODE: 499 printf("{\n"); 500 if (media.ipdata.op_flags & HAMMER2_OPFLAG_DIRECTDATA) { 501 /* no blockrefs */ 502 } else { 503 bscan = &media.ipdata.u.blockset.blockref[0]; 504 bcount = HAMMER2_SET_COUNT; 505 } 506 namelen = media.ipdata.name_len; 507 if (namelen > HAMMER2_INODE_MAXNAME) 508 namelen = 0; 509 tabprintf(tab, "filename \"%*.*s\"\n", 510 namelen, namelen, media.ipdata.filename); 511 tabprintf(tab, "version %d\n", media.ipdata.version); 512 tabprintf(tab, "uflags 0x%08x\n", 513 media.ipdata.uflags); 514 if (media.ipdata.rmajor || media.ipdata.rminor) { 515 tabprintf(tab, "rmajor %d\n", 516 media.ipdata.rmajor); 517 tabprintf(tab, "rminor %d\n", 518 media.ipdata.rminor); 519 } 520 tabprintf(tab, "ctime %s\n", 521 hammer2_time64_to_str(media.ipdata.ctime, &str)); 522 tabprintf(tab, "mtime %s\n", 523 hammer2_time64_to_str(media.ipdata.mtime, &str)); 524 tabprintf(tab, "atime %s\n", 525 hammer2_time64_to_str(media.ipdata.atime, &str)); 526 tabprintf(tab, "btime %s\n", 527 hammer2_time64_to_str(media.ipdata.btime, &str)); 528 tabprintf(tab, "uid %s\n", 529 hammer2_uuid_to_str(&media.ipdata.uid, &str)); 530 tabprintf(tab, "gid %s\n", 531 hammer2_uuid_to_str(&media.ipdata.gid, &str)); 532 if (media.ipdata.type == HAMMER2_OBJTYPE_HARDLINK) 533 tabprintf(tab, "type %s (%s)\n", 534 hammer2_iptype_to_str(media.ipdata.type), 535 hammer2_iptype_to_str(media.ipdata.target_type)); 536 else 537 tabprintf(tab, "type %s\n", 538 hammer2_iptype_to_str(media.ipdata.type)); 539 tabprintf(tab, "opflgs 0x%02x\n", 540 media.ipdata.op_flags); 541 tabprintf(tab, "capflgs 0x%04x\n", 542 media.ipdata.cap_flags); 543 tabprintf(tab, "mode %-7o\n", 544 media.ipdata.mode); 545 tabprintf(tab, "inum 0x%016jx\n", 546 media.ipdata.inum); 547 tabprintf(tab, "size %ju\n", 548 (uintmax_t)media.ipdata.size); 549 tabprintf(tab, "nlinks %ju\n", 550 (uintmax_t)media.ipdata.nlinks); 551 tabprintf(tab, "iparent 0x%016jx\n", 552 (uintmax_t)media.ipdata.iparent); 553 tabprintf(tab, "name_key 0x%016jx\n", 554 (uintmax_t)media.ipdata.name_key); 555 tabprintf(tab, "name_len %u\n", 556 media.ipdata.name_len); 557 tabprintf(tab, "ncopies %u\n", 558 media.ipdata.ncopies); 559 tabprintf(tab, "compalg %u\n", 560 media.ipdata.comp_algo); 561 if (media.ipdata.op_flags & HAMMER2_OPFLAG_PFSROOT) { 562 tabprintf(tab, "pfs_type %u (%s)\n", 563 media.ipdata.pfs_type, 564 hammer2_pfstype_to_str(media.ipdata.pfs_type)); 565 tabprintf(tab, "pfs_inum 0x%016jx\n", 566 (uintmax_t)media.ipdata.pfs_inum); 567 tabprintf(tab, "pfs_clid %s\n", 568 hammer2_uuid_to_str(&media.ipdata.pfs_clid, 569 &str)); 570 tabprintf(tab, "pfs_fsid %s\n", 571 hammer2_uuid_to_str(&media.ipdata.pfs_fsid, 572 &str)); 573 } 574 tabprintf(tab, "data_quota %ju\n", 575 (uintmax_t)media.ipdata.data_quota); 576 tabprintf(tab, "data_count %ju\n", 577 (uintmax_t)media.ipdata.data_count); 578 tabprintf(tab, "inode_quota %ju\n", 579 (uintmax_t)media.ipdata.inode_quota); 580 tabprintf(tab, "inode_count %ju\n", 581 (uintmax_t)media.ipdata.inode_count); 582 tabprintf(tab, "attr_tid 0x%016jx\n", 583 (uintmax_t)media.ipdata.attr_tid); 584 if (media.ipdata.type == HAMMER2_OBJTYPE_DIRECTORY) { 585 tabprintf(tab, "dirent_tid %016jx\n", 586 (uintmax_t)media.ipdata.dirent_tid); 587 } 588 break; 589 case HAMMER2_BREF_TYPE_INDIRECT: 590 bscan = &media.npdata[0]; 591 bcount = bytes / sizeof(hammer2_blockref_t); 592 didnl = 1; 593 printf("{\n"); 594 break; 595 case HAMMER2_BREF_TYPE_DATA: 596 if (VerboseOpt >= 2) { 597 printf("{\n"); 598 } else { 599 printf("\n"); 600 obrace = 0; 601 } 602 break; 603 case HAMMER2_BREF_TYPE_VOLUME: 604 printf("mirror_tid=%016jx freemap_tid=%016jx ", 605 media.voldata.mirror_tid, 606 media.voldata.freemap_tid); 607 if (dofreemap) { 608 bscan = &media.voldata.freemap_blockset.blockref[0]; 609 bcount = HAMMER2_SET_COUNT; 610 } else { 611 bscan = &media.voldata.sroot_blockset.blockref[0]; 612 bcount = HAMMER2_SET_COUNT; 613 } 614 printf("{\n"); 615 break; 616 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 617 printf("{\n"); 618 for (i = 0; i < HAMMER2_FREEMAP_COUNT; ++i) { 619 if (media.bmdata[i].class == 0 && 620 media.bmdata[i].avail == 0) { 621 continue; 622 } 623 tabprintf(tab + 4, "%04d.%04x (avail=%5d) " 624 "%08x %08x %08x %08x %08x %08x %08x %08x\n", 625 i, media.bmdata[i].class, 626 media.bmdata[i].avail, 627 media.bmdata[i].bitmap[0], 628 media.bmdata[i].bitmap[1], 629 media.bmdata[i].bitmap[2], 630 media.bmdata[i].bitmap[3], 631 media.bmdata[i].bitmap[4], 632 media.bmdata[i].bitmap[5], 633 media.bmdata[i].bitmap[6], 634 media.bmdata[i].bitmap[7]); 635 } 636 tabprintf(tab, "}\n"); 637 break; 638 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 639 printf("{\n"); 640 bscan = &media.npdata[0]; 641 bcount = bytes / sizeof(hammer2_blockref_t); 642 break; 643 default: 644 printf("\n"); 645 obrace = 0; 646 break; 647 } 648 if (str) 649 free(str); 650 for (i = 0; i < bcount; ++i) { 651 if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) { 652 if (didnl == 0) { 653 printf("\n"); 654 didnl = 1; 655 } 656 show_bref(fd, tab, i, &bscan[i], dofreemap); 657 } 658 } 659 tab -= SHOW_TAB; 660 if (obrace) { 661 if (bref->type == HAMMER2_BREF_TYPE_INODE) 662 tabprintf(tab, "} (%s.%d, \"%*.*s\")\n", 663 type_str, bi, 664 namelen, namelen, media.ipdata.filename); 665 else 666 tabprintf(tab, "} (%s.%d)\n", type_str,bi); 667 } 668 } 669 670 int 671 cmd_hash(int ac, const char **av) 672 { 673 int i; 674 675 for (i = 0; i < ac; ++i) { 676 printf("%016jx %s\n", dirhash(av[i], strlen(av[i])), av[i]); 677 } 678 return(0); 679 } 680 681 int 682 cmd_chaindump(const char *path) 683 { 684 int dummy = 0; 685 int fd; 686 687 fd = open(path, O_RDONLY); 688 if (fd >= 0) { 689 ioctl(fd, HAMMER2IOC_DEBUG_DUMP, &dummy); 690 close(fd); 691 } else { 692 fprintf(stderr, "unable to open %s\n", path); 693 } 694 return 0; 695 } 696 697 698 static 699 void 700 tabprintf(int tab, const char *ctl, ...) 701 { 702 va_list va; 703 704 printf("%*.*s", tab, tab, ""); 705 va_start(va, ctl); 706 vprintf(ctl, va); 707 va_end(va); 708 } 709