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