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