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