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