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