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 static void shell_ping(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 and ping responses only 251 */ 252 cmd = msg->any.head.cmd; 253 if ((cmd & DMSGF_CMDSWMASK) == (DMSG_LNK_PING | DMSGF_REPLY)) { 254 dmsg_printf(iocom, "ping reply\n"); 255 return; 256 } 257 258 if ((cmd & DMSGF_PROTOS) != DMSG_PROTO_DBG) { 259 if (unmanaged) 260 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 261 return; 262 } 263 if ((cmd & DMSGF_CMDSWMASK) != DMSG_DBG_SHELL) { 264 if (unmanaged) 265 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 266 return; 267 } 268 269 /* 270 * Debug shell command 271 */ 272 cmdbuf = msg->aux_data; 273 cmdp = strsep(&cmdbuf, " \t"); 274 275 if (cmdp == NULL || *cmdp == 0) { 276 ; 277 } else if (strcmp(cmdp, "ping") == 0) { 278 shell_ping(msg, cmdbuf); 279 } else if (strcmp(cmdp, "span") == 0) { 280 shell_span(msg, cmdbuf); 281 } else if (strcmp(cmdp, "tree") == 0) { 282 dmsg_shell_tree(iocom, cmdbuf); /* dump spanning tree */ 283 } else if (strcmp(cmdp, "help") == 0 || strcmp(cmdp, "?") == 0) { 284 dmsg_printf(iocom, "help Command help\n"); 285 dmsg_printf(iocom, "span <host> Span to target host\n"); 286 dmsg_printf(iocom, "tree Dump spanning tree\n"); 287 dmsg_printf(iocom, "@span <cmd> Issue via circuit\n"); 288 } else { 289 dmsg_printf(iocom, "Unrecognized command: %s\n", cmdp); 290 } 291 dmsg_printf(iocom, "debug> "); 292 } 293 294 static void 295 shell_ping(dmsg_msg_t *msg, char *cmdbuf __unused) 296 { 297 dmsg_iocom_t *iocom = msg->state->iocom; 298 dmsg_msg_t *m2; 299 300 dmsg_printf(iocom, "sending ping\n"); 301 m2 = dmsg_msg_alloc(msg->state, 0, DMSG_LNK_PING, NULL, NULL); 302 dmsg_msg_write(m2); 303 } 304 305 static void 306 shell_span(dmsg_msg_t *msg, char *cmdbuf) 307 { 308 dmsg_iocom_t *iocom = msg->state->iocom; 309 dmsg_master_service_info_t *info; 310 const char *hostname = strsep(&cmdbuf, " \t"); 311 pthread_t thread; 312 int fd; 313 314 /* 315 * Connect to the target 316 */ 317 if (hostname == NULL) { 318 fd = -1; 319 } else { 320 fd = dmsg_connect(hostname); 321 } 322 323 /* 324 * Start master service 325 */ 326 if (fd < 0) { 327 dmsg_printf(iocom, "Connection to %s failed\n", hostname); 328 } else { 329 dmsg_printf(iocom, "Connected to %s\n", hostname); 330 331 info = malloc(sizeof(*info)); 332 bzero(info, sizeof(*info)); 333 info->fd = fd; 334 info->detachme = 1; 335 info->usrmsg_callback = hammer2_shell_parse; 336 info->label = strdup("client"); 337 338 pthread_create(&thread, NULL, dmsg_master_service, info); 339 /*pthread_join(thread, &res);*/ 340 } 341 } 342 343 /************************************************************************ 344 * DEBUGSPAN * 345 ************************************************************************ 346 * 347 * Connect to the target manually (not via the cluster list embedded in 348 * a hammer2 filesystem) and initiate the SPAN protocol. 349 */ 350 int 351 cmd_debugspan(const char *hostname) 352 { 353 pthread_t thread; 354 int fd; 355 void *res; 356 357 /* 358 * Connect to the target 359 */ 360 fd = dmsg_connect(hostname); 361 if (fd < 0) 362 return 1; 363 364 printf("debugspan: connected to %s, starting CONN/SPAN\n", hostname); 365 pthread_create(&thread, NULL, 366 dmsg_master_service, (void *)(intptr_t)fd); 367 pthread_join(thread, &res); 368 return(0); 369 } 370 371 /************************************************************************ 372 * SHOW * 373 ************************************************************************/ 374 375 static void show_bref(int fd, int tab, int bi, hammer2_blockref_t *bref, 376 int dofreemap, int norecurse); 377 static void tabprintf(int tab, const char *ctl, ...); 378 379 int 380 cmd_show(const char *devpath, int dofreemap) 381 { 382 hammer2_blockref_t broot; 383 hammer2_blockref_t best; 384 hammer2_media_data_t media; 385 int fd; 386 int i; 387 int best_i; 388 389 fd = open(devpath, O_RDONLY); 390 if (fd < 0) { 391 perror("open"); 392 return 1; 393 } 394 395 /* 396 * Show the tree using the best volume header. 397 * -vvv will show the tree for all four volume headers. 398 */ 399 best_i = -1; 400 bzero(&best, sizeof(best)); 401 for (i = 0; i < 4; ++i) { 402 bzero(&broot, sizeof(broot)); 403 broot.type = HAMMER2_BREF_TYPE_VOLUME; 404 broot.data_off = (i * HAMMER2_ZONE_BYTES64) | 405 HAMMER2_PBUFRADIX; 406 lseek(fd, broot.data_off & ~HAMMER2_OFF_MASK_RADIX, 0); 407 if (read(fd, &media, HAMMER2_PBUFSIZE) == 408 (ssize_t)HAMMER2_PBUFSIZE) { 409 broot.mirror_tid = media.voldata.mirror_tid; 410 if (best_i < 0 || best.mirror_tid < broot.mirror_tid) { 411 best_i = i; 412 best = broot; 413 } 414 if (VerboseOpt >= 3) 415 show_bref(fd, 0, i, &broot, dofreemap, 0); 416 } 417 } 418 if (VerboseOpt < 3) 419 show_bref(fd, 0, best_i, &best, dofreemap, 0); 420 close(fd); 421 422 return 0; 423 } 424 425 extern uint32_t iscsi_crc32(const void *buf, size_t size); 426 static void 427 show_bref(int fd, int tab, int bi, hammer2_blockref_t *bref, int dofreemap, 428 int norecurse) 429 { 430 hammer2_media_data_t media; 431 hammer2_blockref_t *bscan; 432 int bcount; 433 int i; 434 int didnl; 435 int namelen; 436 int obrace = 1; 437 int failed; 438 size_t bytes; 439 const char *type_str; 440 char *str = NULL; 441 uint32_t cv; 442 uint64_t cv64; 443 444 switch(bref->type) { 445 case HAMMER2_BREF_TYPE_EMPTY: 446 type_str = "empty"; 447 break; 448 case HAMMER2_BREF_TYPE_DIRENT: 449 type_str = "dirent"; 450 break; 451 case HAMMER2_BREF_TYPE_INODE: 452 type_str = "inode"; 453 break; 454 case HAMMER2_BREF_TYPE_INDIRECT: 455 type_str = "indblk"; 456 break; 457 case HAMMER2_BREF_TYPE_DATA: 458 type_str = "data"; 459 break; 460 case HAMMER2_BREF_TYPE_VOLUME: 461 type_str = "volume"; 462 break; 463 case HAMMER2_BREF_TYPE_FREEMAP: 464 type_str = "freemap"; 465 break; 466 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 467 type_str = "fmapnode"; 468 break; 469 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 470 type_str = "fbitmap"; 471 break; 472 default: 473 type_str = "unknown"; 474 break; 475 } 476 477 tabprintf(tab, "%s.%-3d %016jx %016jx/%-2d mir=%016jx mod=%016jx ", 478 type_str, bi, (intmax_t)bref->data_off, 479 (intmax_t)bref->key, (intmax_t)bref->keybits, 480 (intmax_t)bref->mirror_tid, (intmax_t)bref->modify_tid); 481 tab += SHOW_TAB; 482 if (bref->flags) 483 printf("flags=%02x ", bref->flags); 484 if (bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE || 485 bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF) { 486 printf("bigmask=%08x avail=%ld ", 487 bref->check.freemap.bigmask, bref->check.freemap.avail); 488 } 489 490 bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX); 491 if (bytes) 492 bytes = (size_t)1 << bytes; 493 if (bytes) { 494 hammer2_off_t io_off; 495 hammer2_off_t io_base; 496 size_t io_bytes; 497 size_t boff; 498 499 io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; 500 io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1); 501 io_bytes = bytes; 502 boff = io_off - io_base; 503 504 io_bytes = HAMMER2_MINIOSIZE; 505 while (io_bytes + boff < bytes) 506 io_bytes <<= 1; 507 508 if (io_bytes > sizeof(media)) { 509 printf("(bad block size %zd)\n", bytes); 510 return; 511 } 512 if (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1) { 513 lseek(fd, io_base, 0); 514 if (read(fd, &media, io_bytes) != (ssize_t)io_bytes) { 515 printf("(media read failed)\n"); 516 return; 517 } 518 if (boff) 519 bcopy((char *)&media + boff, &media, bytes); 520 } 521 } 522 523 bscan = NULL; 524 bcount = 0; 525 didnl = 1; 526 namelen = 0; 527 failed = 0; 528 529 /* 530 * Check data integrity in verbose mode, otherwise we are just doing 531 * a quick meta-data scan. Meta-data integrity is always checked. 532 * (Also see the check above that ensures the media data is loaded, 533 * otherwise there's no data to check!). 534 * 535 * WARNING! bref->check state may be used for other things when 536 * bref has no data (bytes == 0). 537 */ 538 if (bytes && 539 (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1)) { 540 switch(HAMMER2_DEC_CHECK(bref->methods)) { 541 case HAMMER2_CHECK_NONE: 542 printf("(meth %02x) ", bref->methods); 543 break; 544 case HAMMER2_CHECK_DISABLED: 545 printf("(meth %02x) ", bref->methods); 546 break; 547 case HAMMER2_CHECK_ISCSI32: 548 cv = hammer2_icrc32(&media, bytes); 549 if (bref->check.iscsi32.value != cv) { 550 printf("(icrc %02x:%08x/%08x failed) ", 551 bref->methods, 552 bref->check.iscsi32.value, 553 cv); 554 failed = 1; 555 } else { 556 printf("(meth %02x, iscsi32=%08x) ", 557 bref->methods, cv); 558 } 559 break; 560 case HAMMER2_CHECK_XXHASH64: 561 cv64 = XXH64(&media, bytes, XXH_HAMMER2_SEED); 562 if (bref->check.xxhash64.value != cv64) { 563 printf("(xxhash64 %02x:%016jx/%016jx failed) ", 564 bref->methods, 565 bref->check.xxhash64.value, 566 cv64); 567 failed = 1; 568 } else { 569 printf("(meth %02x, xxh=%016jx) ", 570 bref->methods, cv64); 571 } 572 break; 573 case HAMMER2_CHECK_SHA192: 574 printf("(meth %02x) ", bref->methods); 575 break; 576 case HAMMER2_CHECK_FREEMAP: 577 cv = hammer2_icrc32(&media, bytes); 578 if (bref->check.freemap.icrc32 != cv) { 579 printf("(fcrc %02x:%08x/%08x failed) ", 580 bref->methods, 581 bref->check.freemap.icrc32, 582 cv); 583 failed = 1; 584 } else { 585 printf("(meth %02x, fcrc=%08x) ", 586 bref->methods, cv); 587 } 588 break; 589 } 590 } 591 592 switch(bref->type) { 593 case HAMMER2_BREF_TYPE_EMPTY: 594 obrace = 0; 595 break; 596 case HAMMER2_BREF_TYPE_DIRENT: 597 printf("{\n"); 598 if (bref->embed.dirent.namlen <= sizeof(bref->check.buf)) { 599 tabprintf(tab, "filename \"%*.*s\"\n", 600 bref->embed.dirent.namlen, 601 bref->embed.dirent.namlen, 602 bref->check.buf); 603 } else { 604 tabprintf(tab, "filename \"%*.*s\"\n", 605 bref->embed.dirent.namlen, 606 bref->embed.dirent.namlen, 607 media.buf); 608 } 609 tabprintf(tab, "inum 0x%016jx\n", 610 (uintmax_t)bref->embed.dirent.inum); 611 tabprintf(tab, "type %s\n", 612 hammer2_iptype_to_str(bref->embed.dirent.type)); 613 break; 614 case HAMMER2_BREF_TYPE_INODE: 615 printf("{\n"); 616 if (media.ipdata.meta.op_flags & HAMMER2_OPFLAG_DIRECTDATA) { 617 /* no blockrefs */ 618 } else { 619 bscan = &media.ipdata.u.blockset.blockref[0]; 620 bcount = HAMMER2_SET_COUNT; 621 } 622 namelen = media.ipdata.meta.name_len; 623 if (namelen > HAMMER2_INODE_MAXNAME) 624 namelen = 0; 625 tabprintf(tab, "filename \"%*.*s\"\n", 626 namelen, namelen, media.ipdata.filename); 627 tabprintf(tab, "version %d\n", media.ipdata.meta.version); 628 tabprintf(tab, "uflags 0x%08x\n", 629 media.ipdata.meta.uflags); 630 if (media.ipdata.meta.rmajor || media.ipdata.meta.rminor) { 631 tabprintf(tab, "rmajor %d\n", 632 media.ipdata.meta.rmajor); 633 tabprintf(tab, "rminor %d\n", 634 media.ipdata.meta.rminor); 635 } 636 tabprintf(tab, "ctime %s\n", 637 hammer2_time64_to_str(media.ipdata.meta.ctime, &str)); 638 tabprintf(tab, "mtime %s\n", 639 hammer2_time64_to_str(media.ipdata.meta.mtime, &str)); 640 tabprintf(tab, "atime %s\n", 641 hammer2_time64_to_str(media.ipdata.meta.atime, &str)); 642 tabprintf(tab, "btime %s\n", 643 hammer2_time64_to_str(media.ipdata.meta.btime, &str)); 644 tabprintf(tab, "uid %s\n", 645 hammer2_uuid_to_str(&media.ipdata.meta.uid, &str)); 646 tabprintf(tab, "gid %s\n", 647 hammer2_uuid_to_str(&media.ipdata.meta.gid, &str)); 648 tabprintf(tab, "type %s\n", 649 hammer2_iptype_to_str(media.ipdata.meta.type)); 650 tabprintf(tab, "opflgs 0x%02x\n", 651 media.ipdata.meta.op_flags); 652 tabprintf(tab, "capflgs 0x%04x\n", 653 media.ipdata.meta.cap_flags); 654 tabprintf(tab, "mode %-7o\n", 655 media.ipdata.meta.mode); 656 tabprintf(tab, "inum 0x%016jx\n", 657 media.ipdata.meta.inum); 658 tabprintf(tab, "size %ju\n", 659 (uintmax_t)media.ipdata.meta.size); 660 tabprintf(tab, "nlinks %ju\n", 661 (uintmax_t)media.ipdata.meta.nlinks); 662 tabprintf(tab, "iparent 0x%016jx\n", 663 (uintmax_t)media.ipdata.meta.iparent); 664 tabprintf(tab, "name_key 0x%016jx\n", 665 (uintmax_t)media.ipdata.meta.name_key); 666 tabprintf(tab, "name_len %u\n", 667 media.ipdata.meta.name_len); 668 tabprintf(tab, "ncopies %u\n", 669 media.ipdata.meta.ncopies); 670 tabprintf(tab, "compalg %u\n", 671 media.ipdata.meta.comp_algo); 672 tabprintf(tab, "checkalg %u\n", 673 media.ipdata.meta.check_algo); 674 if ((media.ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) || 675 media.ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) { 676 tabprintf(tab, "pfs_type %u (%s)\n", 677 media.ipdata.meta.pfs_type, 678 hammer2_pfstype_to_str(media.ipdata.meta.pfs_type)); 679 tabprintf(tab, "pfs_inum 0x%016jx\n", 680 (uintmax_t)media.ipdata.meta.pfs_inum); 681 tabprintf(tab, "pfs_clid %s\n", 682 hammer2_uuid_to_str(&media.ipdata.meta.pfs_clid, 683 &str)); 684 tabprintf(tab, "pfs_fsid %s\n", 685 hammer2_uuid_to_str(&media.ipdata.meta.pfs_fsid, 686 &str)); 687 tabprintf(tab, "pfs_lsnap_tid 0x%016jx\n", 688 (uintmax_t)media.ipdata.meta.pfs_lsnap_tid); 689 } 690 tabprintf(tab, "data_quota %ju\n", 691 (uintmax_t)media.ipdata.meta.data_quota); 692 tabprintf(tab, "data_count %ju\n", 693 (uintmax_t)bref->embed.stats.data_count); 694 tabprintf(tab, "inode_quota %ju\n", 695 (uintmax_t)media.ipdata.meta.inode_quota); 696 tabprintf(tab, "inode_count %ju\n", 697 (uintmax_t)bref->embed.stats.inode_count); 698 break; 699 case HAMMER2_BREF_TYPE_INDIRECT: 700 bscan = &media.npdata[0]; 701 bcount = bytes / sizeof(hammer2_blockref_t); 702 didnl = 1; 703 printf("{\n"); 704 break; 705 case HAMMER2_BREF_TYPE_DATA: 706 #if 0 707 if (VerboseOpt >= 2) { 708 printf("{\n"); 709 } else 710 #endif 711 { 712 printf("\n"); 713 obrace = 0; 714 } 715 break; 716 case HAMMER2_BREF_TYPE_VOLUME: 717 printf("mirror_tid=%016jx freemap_tid=%016jx ", 718 media.voldata.mirror_tid, 719 media.voldata.freemap_tid); 720 if (dofreemap) { 721 bscan = &media.voldata.freemap_blockset.blockref[0]; 722 bcount = HAMMER2_SET_COUNT; 723 } else { 724 bscan = &media.voldata.sroot_blockset.blockref[0]; 725 bcount = HAMMER2_SET_COUNT; 726 } 727 printf("{\n"); 728 break; 729 case HAMMER2_BREF_TYPE_FREEMAP_LEAF: 730 printf("{\n"); 731 for (i = 0; i < HAMMER2_FREEMAP_COUNT; ++i) { 732 /* 733 if (media.bmdata[i].class == 0 && 734 media.bmdata[i].avail == 0) { 735 continue; 736 } 737 */ 738 #if HAMMER2_BMAP_ELEMENTS != 8 739 #error "cmd_debug.c: HAMMER2_BMAP_ELEMENTS expected to be 8" 740 #endif 741 742 tabprintf(tab + 4, "%016jx %04d.%04x (avail=%7d) " 743 "%016jx %016jx %016jx %016jx " 744 "%016jx %016jx %016jx %016jx\n", 745 bref->key + 746 i * 256 * HAMMER2_FREEMAP_BLOCK_SIZE, 747 i, media.bmdata[i].class, 748 media.bmdata[i].avail, 749 media.bmdata[i].bitmapq[0], 750 media.bmdata[i].bitmapq[1], 751 media.bmdata[i].bitmapq[2], 752 media.bmdata[i].bitmapq[3], 753 media.bmdata[i].bitmapq[4], 754 media.bmdata[i].bitmapq[5], 755 media.bmdata[i].bitmapq[6], 756 media.bmdata[i].bitmapq[7]); 757 } 758 tabprintf(tab, "}\n"); 759 break; 760 case HAMMER2_BREF_TYPE_FREEMAP_NODE: 761 printf("{\n"); 762 bscan = &media.npdata[0]; 763 bcount = bytes / sizeof(hammer2_blockref_t); 764 break; 765 default: 766 printf("\n"); 767 obrace = 0; 768 break; 769 } 770 if (str) 771 free(str); 772 773 /* 774 * Recurse if norecurse == 0. If the CRC failed, pass norecurse = 1. 775 * That is, if an indirect or inode fails we still try to list its 776 * direct children to help with debugging, but go no further than 777 * that because they are probably garbage. 778 */ 779 for (i = 0; norecurse == 0 && i < bcount; ++i) { 780 if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) { 781 if (didnl == 0) { 782 printf("\n"); 783 didnl = 1; 784 } 785 show_bref(fd, tab, i, &bscan[i], dofreemap, failed); 786 } 787 } 788 tab -= SHOW_TAB; 789 if (obrace) { 790 if (bref->type == HAMMER2_BREF_TYPE_INODE) 791 tabprintf(tab, "} (%s.%d, \"%*.*s\")\n", 792 type_str, bi, 793 namelen, namelen, media.ipdata.filename); 794 else 795 tabprintf(tab, "} (%s.%d)\n", type_str,bi); 796 } 797 } 798 799 int 800 cmd_hash(int ac, const char **av) 801 { 802 int i; 803 804 for (i = 0; i < ac; ++i) { 805 printf("%016jx %s\n", dirhash(av[i], strlen(av[i])), av[i]); 806 } 807 return(0); 808 } 809 810 int 811 cmd_chaindump(const char *path) 812 { 813 int dummy = 0; 814 int fd; 815 816 fd = open(path, O_RDONLY); 817 if (fd >= 0) { 818 ioctl(fd, HAMMER2IOC_DEBUG_DUMP, &dummy); 819 close(fd); 820 } else { 821 fprintf(stderr, "unable to open %s\n", path); 822 } 823 return 0; 824 } 825 826 827 static 828 void 829 tabprintf(int tab, const char *ctl, ...) 830 { 831 va_list va; 832 833 printf("%*.*s", tab, tab, ""); 834 va_start(va, ctl); 835 vprintf(ctl, va); 836 va_end(va); 837 } 838