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