1 /* 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "hammer.h" 36 37 static void hammer_parsedevs(const char *blkdevs); 38 static void sigalrm(int signo); 39 static void sigintr(int signo); 40 static void usage(int exit_code); 41 42 int RecurseOpt; 43 int VerboseOpt; 44 int QuietOpt; 45 int NoSyncOpt; 46 int TwoWayPipeOpt; 47 int TimeoutOpt; 48 int DelayOpt = 5; 49 char *SshPort; 50 int ForceYesOpt; 51 int CompressOpt; 52 int ForceOpt; 53 int RunningIoctl; 54 int DidInterrupt; 55 int BulkOpt; 56 int AllPFS; 57 uint64_t BandwidthOpt; 58 uint64_t SplitupOpt = 4ULL * 1024ULL * 1024ULL * 1024ULL; 59 uint64_t MemoryLimit = 1024LLU * 1024 * 1024; 60 const char *SplitupOptStr; 61 const char *CyclePath; 62 63 int 64 main(int ac, char **av) 65 { 66 char *blkdevs = NULL; 67 char *ptr; 68 char *restrictcmd = NULL; 69 uint32_t status; 70 int ch; 71 72 while ((ch = getopt(ac, av, 73 "b:c:de:hf:i:m:p:qrt:v2yABC:FR:S:T:X")) != -1) { 74 switch(ch) { 75 case '2': 76 TwoWayPipeOpt = 1; 77 break; 78 case 'y': 79 ForceYesOpt = 1; 80 break; 81 case 'b': 82 BandwidthOpt = strtoull(optarg, &ptr, 0); 83 switch(*ptr) { 84 case 'g': 85 case 'G': 86 BandwidthOpt *= 1024; 87 /* fall through */ 88 case 'm': 89 case 'M': 90 BandwidthOpt *= 1024; 91 /* fall through */ 92 case 'k': 93 case 'K': 94 BandwidthOpt *= 1024; 95 break; 96 case '\0': 97 /* bytes per second if no suffix */ 98 break; 99 default: 100 usage(1); 101 } 102 break; 103 case 'S': 104 SplitupOptStr = strdup(optarg); 105 SplitupOpt = strtoull(optarg, &ptr, 0); 106 switch(*ptr) { 107 case 'g': 108 case 'G': 109 SplitupOpt *= 1024; 110 /* fall through */ 111 case 'm': 112 case 'M': 113 SplitupOpt *= 1024; 114 /* fall through */ 115 case 'k': 116 case 'K': 117 SplitupOpt *= 1024; 118 break; 119 case '\0': 120 /* bytes per second if no suffix */ 121 break; 122 default: 123 usage(1); 124 } 125 break; 126 case 'c': 127 CyclePath = optarg; 128 break; 129 case 'd': 130 ++DebugOpt; 131 break; 132 case 'e': 133 ScoreBoardFile = optarg; 134 break; 135 case 'h': 136 usage(0); 137 /* not reached */ 138 case 'i': 139 DelayOpt = strtol(optarg, NULL, 0); 140 break; 141 case 'm': 142 MemoryLimit = strtouq(optarg, &ptr, 0); 143 switch(*ptr) { 144 case 't': 145 case 'T': 146 MemoryLimit *= 1024; 147 /* fall through */ 148 case 'g': 149 case 'G': 150 MemoryLimit *= 1024; 151 /* fall through */ 152 case 'm': 153 case 'M': 154 MemoryLimit *= 1024; 155 /* fall through */ 156 case 'k': 157 case 'K': 158 MemoryLimit *= 1024; 159 /* fall through */ 160 default: 161 break; 162 } 163 164 /* minimum limit */ 165 if (MemoryLimit < 1024 * 1024) 166 MemoryLimit = 1024 * 1024; 167 break; 168 case 'p': 169 SshPort = optarg; 170 break; 171 case 'r': 172 RecurseOpt = 1; 173 break; 174 case 'f': 175 blkdevs = optarg; 176 break; 177 case 't': 178 TimeoutOpt = strtol(optarg, NULL, 0); 179 break; 180 case 'v': 181 if (QuietOpt > 0) 182 --QuietOpt; 183 else 184 ++VerboseOpt; 185 break; 186 case 'q': 187 if (VerboseOpt > 0) 188 --VerboseOpt; 189 else 190 ++QuietOpt; 191 break; 192 case 'A': 193 AllPFS = 1; 194 break; 195 case 'B': 196 BulkOpt = 1; 197 break; 198 case 'C': 199 if (hammer_parse_cache_size(optarg) == -1) 200 usage(1); 201 break; 202 case 'F': 203 ForceOpt = 1; 204 break; 205 case 'R': 206 if (restrictcmd == NULL) 207 restrictcmd = optarg; 208 break; 209 case 'T': 210 if (RestrictTarget == NULL) 211 RestrictTarget = optarg; 212 break; 213 case 'X': 214 CompressOpt = 1; 215 break; 216 default: 217 usage(1); 218 /* not reached */ 219 } 220 } 221 ac -= optind; 222 av += optind; 223 if (ac < 1) { 224 usage(1); 225 /* not reached */ 226 } 227 228 signal(SIGALRM, sigalrm); 229 signal(SIGINT, sigintr); 230 231 /* 232 * Check command restriction (used by hammer ssh-remote). Several 233 * commands may be iterated with a comma. 234 */ 235 if (restrictcmd) { 236 char *elm, *dup; 237 238 dup = ptr = strdup(restrictcmd); 239 while ((elm = strsep(&ptr, ",")) != NULL) { 240 if (strcmp(av[0], elm) == 0) 241 break; 242 } 243 if (elm == NULL) { 244 fprintf(stderr, "hammer-remote: request does not match " 245 "restricted command\n"); 246 exit(1); 247 } 248 free(dup); 249 } 250 251 uuid_name_lookup(&Hammer_FSType, "DragonFly HAMMER", &status); 252 if (status != uuid_s_ok) { 253 errx(1, "uuids file does not have the DragonFly " 254 "HAMMER filesystem type"); 255 } 256 257 /* 258 * Parse commands 259 */ 260 if (strcmp(av[0], "synctid") == 0) { 261 hammer_cmd_synctid(av + 1, ac - 1); 262 exit(0); 263 } 264 if (strcmp(av[0], "namekey2") == 0) { 265 int64_t key; 266 int32_t crcx; 267 int len; 268 const char *aname = av[1]; 269 270 if (aname == NULL) 271 usage(1); 272 len = strlen(aname); 273 key = (uint32_t)crc32(aname, len) & 0xFFFFFFFEU; 274 275 switch(len) { 276 default: 277 crcx = crc32(aname + 3, len - 5); 278 crcx = crcx ^ (crcx >> 6) ^ (crcx >> 12); 279 key |= (int64_t)(crcx & 0x3F) << 42; 280 /* fall through */ 281 case 5: 282 case 4: 283 /* fall through */ 284 case 3: 285 key |= ((int64_t)(aname[2] & 0x1F) << 48); 286 /* fall through */ 287 case 2: 288 key |= ((int64_t)(aname[1] & 0x1F) << 53) | 289 ((int64_t)(aname[len-2] & 0x1F) << 37); 290 /* fall through */ 291 case 1: 292 key |= ((int64_t)(aname[0] & 0x1F) << 58) | 293 ((int64_t)(aname[len-1] & 0x1F) << 32); 294 /* fall through */ 295 case 0: 296 break; 297 } 298 if (key == 0) 299 key |= 0x100000000LL; 300 printf("0x%016jx\n", (uintmax_t)key); 301 exit(0); 302 } 303 if (strcmp(av[0], "namekey1") == 0) { 304 int64_t key; 305 306 if (av[1] == NULL) 307 usage(1); 308 key = (int64_t)(crc32(av[1], strlen(av[1])) & 0x7FFFFFFF) << 32; 309 if (key == 0) 310 key |= 0x100000000LL; 311 printf("0x%016jx\n", (uintmax_t)key); 312 exit(0); 313 } 314 if (strcmp(av[0], "namekey32") == 0) { 315 int32_t key; 316 317 if (av[1] == NULL) 318 usage(1); 319 key = crc32(av[1], strlen(av[1])) & 0x7FFFFFFF; 320 if (key == 0) 321 ++key; 322 printf("0x%08x\n", key); 323 exit(0); 324 } 325 if (strcmp(av[0], "pfs-status") == 0) { 326 hammer_cmd_pseudofs_status(av + 1, ac - 1); 327 exit(0); 328 } 329 if (strcmp(av[0], "pfs-master") == 0) { 330 hammer_cmd_pseudofs_create(av + 1, ac - 1, 0); 331 exit(0); 332 } 333 if (strcmp(av[0], "pfs-slave") == 0) { 334 hammer_cmd_pseudofs_create(av + 1, ac - 1, 1); 335 exit(0); 336 } 337 if (strcmp(av[0], "pfs-update") == 0) { 338 hammer_cmd_pseudofs_update(av + 1, ac - 1); 339 exit(0); 340 } 341 if (strcmp(av[0], "pfs-upgrade") == 0) { 342 hammer_cmd_pseudofs_upgrade(av + 1, ac - 1); 343 exit(0); 344 } 345 if (strcmp(av[0], "pfs-downgrade") == 0) { 346 hammer_cmd_pseudofs_downgrade(av + 1, ac - 1); 347 exit(0); 348 } 349 if (strcmp(av[0], "pfs-destroy") == 0) { 350 hammer_cmd_pseudofs_destroy(av + 1, ac - 1); 351 exit(0); 352 } 353 if (strcmp(av[0], "prune") == 0) { 354 hammer_cmd_softprune(av + 1, ac - 1, 0); 355 exit(0); 356 } 357 if (strcmp(av[0], "config") == 0) { 358 hammer_cmd_config(av + 1, ac - 1); 359 exit(0); 360 } 361 if (strcmp(av[0], "viconfig") == 0) { 362 hammer_cmd_viconfig(av + 1, ac - 1); 363 exit(0); 364 } 365 if (strcmp(av[0], "cleanup") == 0) { 366 hammer_cmd_cleanup(av + 1, ac - 1); 367 exit(0); 368 } 369 if (strcmp(av[0], "abort-cleanup") == 0) { 370 hammer_cmd_abort_cleanup(av + 1, ac - 1); 371 exit(0); 372 } 373 if (strcmp(av[0], "info") == 0) { 374 hammer_cmd_info(av + 1, ac - 1); 375 exit(0); 376 } 377 if (strcmp(av[0], "prune-everything") == 0) { 378 hammer_cmd_softprune(av + 1, ac - 1, 1); 379 exit(0); 380 } 381 if (strcmp(av[0], "ssh-remote") == 0) { 382 if (ac != 3) 383 usage(1); 384 hammer_cmd_sshremote(av[1], av[2]); 385 exit(0); 386 } 387 if (strcmp(av[0], "snap") == 0) { 388 hammer_cmd_snap(av + 1, ac - 1, 0, 1); 389 exit(0); 390 } 391 if (strcmp(av[0], "snaplo") == 0) { 392 hammer_cmd_snap(av + 1, ac - 1, 0, 0); 393 exit(0); 394 } 395 if (strcmp(av[0], "snapq") == 0) { 396 hammer_cmd_snap(av + 1, ac - 1, 1, 0); 397 exit(0); 398 } 399 if (strcmp(av[0], "snapls") == 0) { 400 hammer_cmd_snapls(av + 1, ac - 1); 401 exit(0); 402 } 403 if (strcmp(av[0], "snaprm") == 0) { 404 hammer_cmd_snaprm(av + 1, ac - 1); 405 exit(0); 406 } 407 if (strcmp(av[0], "snapshot") == 0) { 408 hammer_cmd_snapshot(av + 1, ac - 1); 409 exit(0); 410 } 411 if (strcmp(av[0], "bstats") == 0) { 412 hammer_cmd_bstats(av + 1, ac - 1); 413 exit(0); 414 } 415 if (strcmp(av[0], "iostats") == 0) { 416 hammer_cmd_iostats(av + 1, ac - 1); 417 exit(0); 418 } 419 if (strcmp(av[0], "stats") == 0) { 420 hammer_cmd_stats(av + 1, ac - 1); 421 exit(0); 422 } 423 424 if (strncmp(av[0], "history", 7) == 0) { 425 hammer_cmd_history(av[0] + 7, av + 1, ac - 1); 426 exit(0); 427 } 428 if (strcmp(av[0], "rebalance") == 0) { 429 signal(SIGINT, sigalrm); 430 hammer_cmd_rebalance(av + 1, ac - 1); 431 exit(0); 432 } 433 if (strncmp(av[0], "reblock", 7) == 0) { 434 signal(SIGINT, sigalrm); 435 if (strcmp(av[0], "reblock") == 0) 436 hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_FLAGS); 437 else if (strcmp(av[0], "reblock-btree") == 0) 438 hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_BTREE); 439 else if (strcmp(av[0], "reblock-inodes") == 0) 440 hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_INODES); 441 else if (strcmp(av[0], "reblock-dirs") == 0) 442 hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_DIRS); 443 else if (strcmp(av[0], "reblock-data") == 0) 444 hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_DATA); 445 else 446 usage(1); 447 exit(0); 448 } 449 if (strncmp(av[0], "mirror", 6) == 0) { 450 if (strcmp(av[0], "mirror-read") == 0) 451 hammer_cmd_mirror_read(av + 1, ac - 1, 0); 452 else if (strcmp(av[0], "mirror-read-stream") == 0) 453 hammer_cmd_mirror_read(av + 1, ac - 1, 1); 454 else if (strcmp(av[0], "mirror-write") == 0) 455 hammer_cmd_mirror_write(av + 1, ac - 1); 456 else if (strcmp(av[0], "mirror-copy") == 0) 457 hammer_cmd_mirror_copy(av + 1, ac - 1, 0); 458 else if (strcmp(av[0], "mirror-stream") == 0) 459 hammer_cmd_mirror_copy(av + 1, ac - 1, 1); 460 else if (strcmp(av[0], "mirror-dump") == 0) 461 hammer_cmd_mirror_dump(av + 1, ac - 1); 462 else 463 usage(1); 464 exit(0); 465 } 466 if (strcmp(av[0], "dedup-simulate") == 0) { 467 hammer_cmd_dedup_simulate(av + 1, ac - 1); 468 exit(0); 469 } 470 if (strcmp(av[0], "dedup") == 0) { 471 hammer_cmd_dedup(av + 1, ac - 1); 472 exit(0); 473 } 474 if (strcmp(av[0], "version") == 0) { 475 hammer_cmd_get_version(av + 1, ac - 1); 476 exit(0); 477 } 478 if (strcmp(av[0], "version-upgrade") == 0) { 479 hammer_cmd_set_version(av + 1, ac - 1); 480 exit(0); 481 } 482 if (strcmp(av[0], "volume-add") == 0) { 483 hammer_cmd_volume_add(av + 1, ac - 1); 484 exit(0); 485 } 486 if (strcmp(av[0], "volume-del") == 0) { 487 hammer_cmd_volume_del(av + 1, ac - 1); 488 exit(0); 489 } 490 if (strcmp(av[0], "volume-list") == 0) { 491 hammer_cmd_volume_list(av + 1, ac - 1); 492 exit(0); 493 } 494 if (strcmp(av[0], "volume-blkdevs") == 0) { 495 hammer_cmd_volume_blkdevs(av + 1, ac - 1); 496 exit(0); 497 } 498 499 if (strcmp(av[0], "show") == 0) { 500 const char *arg = NULL; 501 char *p, *dup; 502 int filter = -1; 503 int obfuscate = 0; 504 int indent = 0; 505 506 hammer_parsedevs(blkdevs); 507 if (ac > 3) 508 errx(1, "Too many options specified"); 509 if (ac > 1) 510 arg = av[1]; 511 if (ac > 2) { 512 dup = ptr = strdup(av[2]); 513 while ((p = strsep(&ptr, ",")) != NULL) { 514 if (strcmp(p, "filter") == 0) { 515 filter = 1; 516 } else if (strcmp(p, "nofilter") == 0) { 517 filter = 0; 518 } else if (strcmp(p, "obfuscate") == 0) { 519 obfuscate = 1; 520 } else if (strcmp(p, "indent") == 0) { 521 indent = 1; 522 } 523 } 524 free(dup); 525 } 526 hammer_cmd_show(arg, filter, obfuscate, indent); 527 exit(0); 528 } 529 if (strcmp(av[0], "show-undo") == 0) { 530 hammer_parsedevs(blkdevs); 531 hammer_cmd_show_undo(); 532 exit(0); 533 } 534 if (strcmp(av[0], "recover") == 0) { 535 hammer_parsedevs(blkdevs); 536 if (ac <= 1) 537 errx(1, "hammer recover required target directory"); 538 hammer_cmd_recover(av[1]); 539 exit(0); 540 } 541 if (strcmp(av[0], "blockmap") == 0) { 542 hammer_parsedevs(blkdevs); 543 hammer_cmd_blockmap(); 544 exit(0); 545 } 546 if (strcmp(av[0], "checkmap") == 0) { 547 hammer_parsedevs(blkdevs); 548 hammer_cmd_checkmap(); 549 exit(0); 550 } 551 usage(1); 552 /* not reached */ 553 return(0); 554 } 555 556 /* 557 * Parse the device specification. 558 * 559 * Multi-volume hammer devices are colon-separated. Each element 560 * may be further expanded via /etc/devtab. One may also specify 561 * a single element which is expanded into multiple elements via 562 * /etc/devtab. 563 */ 564 static 565 void 566 hammer_parsedevs(const char *blkdevs) 567 { 568 struct volume_info *vol = NULL; 569 char *copy; 570 char *volname; 571 int volnum = 0; 572 573 if (blkdevs == NULL) { 574 errx(1, "A -f blkdevs specification is required " 575 "for this command"); 576 } 577 578 copy = strdup(blkdevs); 579 while ((volname = copy) != NULL) { 580 if ((copy = strchr(copy, ':')) != NULL) 581 *copy++ = 0; 582 volname = getdevpath(volname, 0); 583 if (strchr(volname, ':')) 584 hammer_parsedevs(volname); 585 else { 586 vol = load_volume(volname, O_RDONLY); 587 assert(vol); 588 ++volnum; 589 } 590 free(volname); 591 } 592 free(copy); 593 594 /* 595 * All volumes have the same vol_count. 596 */ 597 assert(vol); 598 if (volnum != vol->ondisk->vol_count) 599 errx(1, "Volume header says %d volumes, but %d specified.", 600 vol->ondisk->vol_count, volnum); 601 602 if (get_root_volume() == NULL) 603 errx(1, "No root volume found"); 604 } 605 606 static 607 void 608 sigalrm(int signo __unused) 609 { 610 /* do nothing (interrupts HAMMER ioctl) */ 611 } 612 613 static 614 void 615 sigintr(int signo __unused) 616 { 617 if (RunningIoctl == 0) 618 _exit(1); 619 DidInterrupt = 1; 620 /* do nothing (interrupts HAMMER ioctl) */ 621 } 622 623 static 624 void 625 usage(int exit_code) 626 { 627 fprintf(stderr, 628 "hammer -h\n" 629 "hammer [-2ABFqrvXy] [-b bandwidth] [-C cachesize[:readahead]] \n" 630 " [-R restrictcmd] [-T restrictpath] [-c cyclefile]\n" 631 " [-e scoreboardfile] [-f blkdevs] [-i delay] [-p ssh-port]\n" 632 " [-S splitsize] [-t seconds] [-m memlimit] command [argument ...]\n" 633 "hammer synctid <filesystem> [quick]\n" 634 "hammer bstats [interval]\n" 635 "hammer iostats [interval]\n" 636 "hammer stats [interval]\n" 637 "hammer history[@offset[,len]] <file> ...\n" 638 "hammer namekey1 <path>\n" 639 "hammer namekey2 <path>\n" 640 "hammer namekey32 <path>\n" 641 "hammer cleanup [<filesystem> ...]\n" 642 "hammer abort-cleanup\n" 643 "hammer info [<dirpath> ...]\n" 644 "hammer snapshot [<filesystem>] <snapshot-dir>\n" 645 "hammer snapshot <filesystem> <snapshot-dir> [<note>]\n" 646 "hammer prune <softlink-dir>\n" 647 "hammer prune-everything <filesystem>\n" 648 "hammer rebalance <filesystem> [saturation_percentage]\n" 649 "hammer reblock[-btree|-inodes|-dirs|-data] " 650 "<filesystem> [fill_percentage]\n" 651 "hammer pfs-status <dirpath> ...\n" 652 "hammer pfs-master <dirpath> [options]\n" 653 "hammer pfs-slave <dirpath> [options]\n" 654 "hammer pfs-update <dirpath> [options]\n" 655 "hammer pfs-upgrade <dirpath>\n" 656 "hammer pfs-downgrade <dirpath>\n" 657 "hammer pfs-destroy <dirpath>\n" 658 "hammer mirror-read <filesystem> [begin-tid]\n" 659 "hammer mirror-read-stream <filesystem> [begin-tid]\n" 660 "hammer mirror-write <filesystem>\n" 661 "hammer mirror-dump [header]\n" 662 "hammer mirror-copy [[user@]host:]<filesystem>" 663 " [[user@]host:]<filesystem>\n" 664 "hammer mirror-stream [[user@]host:]<filesystem>" 665 " [[user@]host:]<filesystem>\n" 666 "hammer ssh-remote command filesystem\n" 667 "hammer version <filesystem>\n" 668 "hammer version-upgrade <filesystem> <version> [force]\n" 669 "hammer volume-add <device> <filesystem>\n" 670 "hammer volume-del <device> <filesystem>\n" 671 "hammer volume-list <filesystem>\n" 672 "hammer volume-blkdevs <filesystem>\n" 673 ); 674 675 fprintf(stderr, "\nHAMMER utility version 3+ commands:\n"); 676 677 fprintf(stderr, 678 "hammer config [<filesystem> [<configfile>]]\n" 679 "hammer viconfig [<filesystem>]\n" 680 "hammer snap <path> [<note>]\n" 681 "hammer snaplo <path> [<note>]\n" 682 "hammer snapq <dir> [<note>]\n" 683 "hammer snaprm <path> ...\n" 684 "hammer snaprm <transid> ...\n" 685 "hammer snaprm <filesystem> <transid> ...\n" 686 "hammer snapls [<path> ...]\n" 687 ); 688 689 fprintf(stderr, "\nHAMMER utility version 4+ commands:\n"); 690 691 fprintf(stderr, 692 "hammer -f blkdevs blockmap\n" 693 "hammer -f blkdevs checkmap\n" 694 "hammer -f blkdevs [-qqq] show [lo:objid]\n" 695 "hammer -f blkdevs show-undo\n" 696 "hammer -f blkdevs recover <target_dir>\n" 697 ); 698 699 fprintf(stderr, "\nHAMMER utility version 5+ commands:\n"); 700 701 fprintf(stderr, 702 "hammer dedup-simulate <filesystem>\n" 703 "hammer dedup <filesystem>\n" 704 ); 705 706 exit(exit_code); 707 } 708 709