12910a90cSMatthew Dillon /*
20c41f055SMatthew Dillon * Copyright (c) 2011-2019 The DragonFly Project. All rights reserved.
32910a90cSMatthew Dillon *
42910a90cSMatthew Dillon * This code is derived from software contributed to The DragonFly Project
52910a90cSMatthew Dillon * by Matthew Dillon <dillon@dragonflybsd.org>
62910a90cSMatthew Dillon * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
72910a90cSMatthew Dillon *
82910a90cSMatthew Dillon * Redistribution and use in source and binary forms, with or without
92910a90cSMatthew Dillon * modification, are permitted provided that the following conditions
102910a90cSMatthew Dillon * are met:
112910a90cSMatthew Dillon *
122910a90cSMatthew Dillon * 1. Redistributions of source code must retain the above copyright
132910a90cSMatthew Dillon * notice, this list of conditions and the following disclaimer.
142910a90cSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
152910a90cSMatthew Dillon * notice, this list of conditions and the following disclaimer in
162910a90cSMatthew Dillon * the documentation and/or other materials provided with the
172910a90cSMatthew Dillon * distribution.
182910a90cSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its
192910a90cSMatthew Dillon * contributors may be used to endorse or promote products derived
202910a90cSMatthew Dillon * from this software without specific, prior written permission.
212910a90cSMatthew Dillon *
222910a90cSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
232910a90cSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
242910a90cSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
252910a90cSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
262910a90cSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
272910a90cSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
282910a90cSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
292910a90cSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
302910a90cSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
312910a90cSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
322910a90cSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
332910a90cSMatthew Dillon * SUCH DAMAGE.
342910a90cSMatthew Dillon */
352910a90cSMatthew Dillon
362910a90cSMatthew Dillon #include "hammer2.h"
372910a90cSMatthew Dillon
385ba65e34SMatthew Dillon int DebugOpt;
39bd878fc9SMatthew Dillon int VerboseOpt;
409b8b748fSMatthew Dillon int QuietOpt;
41f481450fSMatthew Dillon int ForceOpt;
428deaf180STomohiro Kusumi int RecurseOpt;
438deaf180STomohiro Kusumi int NormalExit = 1; /* if set to 0 main() has to pthread_exit() */
44944ddad0SMatthew Dillon size_t MemOpt;
45f481450fSMatthew Dillon
46f481450fSMatthew Dillon static void usage(int code);
475ba65e34SMatthew Dillon
482910a90cSMatthew Dillon int
main(int ac,char ** av)492910a90cSMatthew Dillon main(int ac, char **av)
502910a90cSMatthew Dillon {
51cef49084SMatthew Dillon char *sel_path = NULL;
522910a90cSMatthew Dillon const char *uuid_str = NULL;
5362efe6ecSMatthew Dillon const char *arg;
54944ddad0SMatthew Dillon char *opt;
557750fd72SMatthew Dillon int pfs_type = HAMMER2_PFSTYPE_NONE;
562910a90cSMatthew Dillon int all_opt = 0;
572910a90cSMatthew Dillon int ecode = 0;
582910a90cSMatthew Dillon int ch;
592910a90cSMatthew Dillon
6062efe6ecSMatthew Dillon srandomdev();
617dc0f844SMatthew Dillon signal(SIGPIPE, SIG_IGN);
620c3a8cd0SMatthew Dillon dmsg_crypto_setup();
6362efe6ecSMatthew Dillon
642910a90cSMatthew Dillon /*
652910a90cSMatthew Dillon * Core options
662910a90cSMatthew Dillon */
678deaf180STomohiro Kusumi while ((ch = getopt(ac, av, "adfm:rs:t:u:vq")) != -1) {
682910a90cSMatthew Dillon switch(ch) {
692910a90cSMatthew Dillon case 'a':
702910a90cSMatthew Dillon all_opt = 1;
712910a90cSMatthew Dillon break;
72bd878fc9SMatthew Dillon case 'd':
7378b00acdSMatthew Dillon if (DebugOpt)
74d157d4dcSMatthew Dillon ++DMsgDebugOpt;
75bd878fc9SMatthew Dillon DebugOpt = 1;
76bd878fc9SMatthew Dillon break;
77f481450fSMatthew Dillon case 'f':
78f481450fSMatthew Dillon ForceOpt = 1;
79f481450fSMatthew Dillon break;
80944ddad0SMatthew Dillon case 'm':
81944ddad0SMatthew Dillon MemOpt = strtoul(optarg, &opt, 0);
82944ddad0SMatthew Dillon switch(*opt) {
83944ddad0SMatthew Dillon case 'g':
84944ddad0SMatthew Dillon case 'G':
85944ddad0SMatthew Dillon MemOpt *= 1024;
86944ddad0SMatthew Dillon /* FALLTHROUGH */
87944ddad0SMatthew Dillon case 'm':
88944ddad0SMatthew Dillon case 'M':
89944ddad0SMatthew Dillon MemOpt *= 1024;
90944ddad0SMatthew Dillon /* FALLTHROUGH */
91944ddad0SMatthew Dillon case 'k':
92944ddad0SMatthew Dillon case 'K':
93944ddad0SMatthew Dillon MemOpt *= 1024;
94944ddad0SMatthew Dillon break;
95944ddad0SMatthew Dillon case 0:
96944ddad0SMatthew Dillon break;
97944ddad0SMatthew Dillon default:
98e03500eeSTomohiro Kusumi fprintf(stderr, "-m: Unrecognized suffix\n");
99944ddad0SMatthew Dillon usage(1);
100944ddad0SMatthew Dillon break;
101944ddad0SMatthew Dillon }
102944ddad0SMatthew Dillon break;
103f481450fSMatthew Dillon case 'r':
104f481450fSMatthew Dillon RecurseOpt = 1;
105f481450fSMatthew Dillon break;
1062910a90cSMatthew Dillon case 's':
107cef49084SMatthew Dillon sel_path = strdup(optarg);
1082910a90cSMatthew Dillon break;
1092910a90cSMatthew Dillon case 't':
1102910a90cSMatthew Dillon /*
111ee886e77STomohiro Kusumi * set node type for pfs-create
1122910a90cSMatthew Dillon */
113afa78c43SMatthew Dillon if (strcasecmp(optarg, "CACHE") == 0) {
1142910a90cSMatthew Dillon pfs_type = HAMMER2_PFSTYPE_CACHE;
115b93cc2e0SMatthew Dillon } else if (strcasecmp(optarg, "DUMMY") == 0) {
116b93cc2e0SMatthew Dillon pfs_type = HAMMER2_PFSTYPE_DUMMY;
1172910a90cSMatthew Dillon } else if (strcasecmp(optarg, "SLAVE") == 0) {
1182910a90cSMatthew Dillon pfs_type = HAMMER2_PFSTYPE_SLAVE;
1192910a90cSMatthew Dillon } else if (strcasecmp(optarg, "SOFT_SLAVE") == 0) {
1202910a90cSMatthew Dillon pfs_type = HAMMER2_PFSTYPE_SOFT_SLAVE;
1212910a90cSMatthew Dillon } else if (strcasecmp(optarg, "SOFT_MASTER") == 0) {
1222910a90cSMatthew Dillon pfs_type = HAMMER2_PFSTYPE_SOFT_MASTER;
1232910a90cSMatthew Dillon } else if (strcasecmp(optarg, "MASTER") == 0) {
1242910a90cSMatthew Dillon pfs_type = HAMMER2_PFSTYPE_MASTER;
1252910a90cSMatthew Dillon } else {
1262910a90cSMatthew Dillon fprintf(stderr, "-t: Unrecognized node type\n");
1272910a90cSMatthew Dillon usage(1);
1282910a90cSMatthew Dillon }
1292910a90cSMatthew Dillon break;
1302910a90cSMatthew Dillon case 'u':
1312910a90cSMatthew Dillon /*
132ee886e77STomohiro Kusumi * set uuid for pfs-create, else one will be generated
1332910a90cSMatthew Dillon * (required for all except the MASTER node_type)
1342910a90cSMatthew Dillon */
1352910a90cSMatthew Dillon uuid_str = optarg;
1362910a90cSMatthew Dillon break;
137bd878fc9SMatthew Dillon case 'v':
1389b8b748fSMatthew Dillon if (QuietOpt)
1399b8b748fSMatthew Dillon --QuietOpt;
1409b8b748fSMatthew Dillon else
141bd878fc9SMatthew Dillon ++VerboseOpt;
1425ba65e34SMatthew Dillon break;
1439b8b748fSMatthew Dillon case 'q':
1449b8b748fSMatthew Dillon if (VerboseOpt)
1459b8b748fSMatthew Dillon --VerboseOpt;
1469b8b748fSMatthew Dillon else
1479b8b748fSMatthew Dillon ++QuietOpt;
1489b8b748fSMatthew Dillon break;
1492910a90cSMatthew Dillon default:
1502910a90cSMatthew Dillon fprintf(stderr, "Unknown option: %c\n", ch);
1512910a90cSMatthew Dillon usage(1);
1522910a90cSMatthew Dillon /* not reached */
1532910a90cSMatthew Dillon break;
1542910a90cSMatthew Dillon }
1552910a90cSMatthew Dillon }
1562910a90cSMatthew Dillon
1572910a90cSMatthew Dillon /*
1582910a90cSMatthew Dillon * Adjust, then process the command
1592910a90cSMatthew Dillon */
1602910a90cSMatthew Dillon ac -= optind;
1612910a90cSMatthew Dillon av += optind;
1622910a90cSMatthew Dillon if (ac < 1) {
1632910a90cSMatthew Dillon fprintf(stderr, "Missing command\n");
1642910a90cSMatthew Dillon usage(1);
1652910a90cSMatthew Dillon /* not reached */
1662910a90cSMatthew Dillon }
1672910a90cSMatthew Dillon
1682910a90cSMatthew Dillon if (strcmp(av[0], "connect") == 0) {
1692910a90cSMatthew Dillon /*
1702910a90cSMatthew Dillon * Add cluster connection
1712910a90cSMatthew Dillon */
1722910a90cSMatthew Dillon if (ac < 2) {
1732910a90cSMatthew Dillon fprintf(stderr, "connect: missing argument\n");
1742910a90cSMatthew Dillon usage(1);
1752910a90cSMatthew Dillon }
1762910a90cSMatthew Dillon ecode = cmd_remote_connect(sel_path, av[1]);
17740498d1cSMatthew Dillon } else if (strcmp(av[0], "dumpchain") == 0) {
1788f579e46SMatthew Dillon if (ac < 2)
17940498d1cSMatthew Dillon ecode = cmd_dumpchain(".", (u_int)-1);
18040498d1cSMatthew Dillon else if (ac < 3)
18140498d1cSMatthew Dillon ecode = cmd_dumpchain(av[1], (u_int)-1);
1828f579e46SMatthew Dillon else
18340498d1cSMatthew Dillon ecode = cmd_dumpchain(av[1],
18440498d1cSMatthew Dillon (u_int)strtoul(av[2], NULL, 0));
18502454b3eSMatthew Dillon } else if (strcmp(av[0], "debugspan") == 0) {
18602454b3eSMatthew Dillon /*
18702454b3eSMatthew Dillon * Debug connection to the target hammer2 service and run
18802454b3eSMatthew Dillon * the CONN/SPAN protocol.
18902454b3eSMatthew Dillon */
19002454b3eSMatthew Dillon if (ac < 2) {
19102454b3eSMatthew Dillon fprintf(stderr, "debugspan: requires hostname\n");
19202454b3eSMatthew Dillon usage(1);
19302454b3eSMatthew Dillon }
19402454b3eSMatthew Dillon ecode = cmd_debugspan(av[1]);
1952910a90cSMatthew Dillon } else if (strcmp(av[0], "disconnect") == 0) {
1962910a90cSMatthew Dillon /*
1972910a90cSMatthew Dillon * Remove cluster connection
1982910a90cSMatthew Dillon */
1992910a90cSMatthew Dillon if (ac < 2) {
2002910a90cSMatthew Dillon fprintf(stderr, "disconnect: missing argument\n");
2012910a90cSMatthew Dillon usage(1);
2022910a90cSMatthew Dillon }
2032910a90cSMatthew Dillon ecode = cmd_remote_disconnect(sel_path, av[1]);
204f6aebb44SMatthew Dillon } else if (strcmp(av[0], "destroy") == 0) {
205f6aebb44SMatthew Dillon if (ac < 2) {
206f6aebb44SMatthew Dillon fprintf(stderr,
207e03500eeSTomohiro Kusumi "destroy: specify one or more paths to "
208e03500eeSTomohiro Kusumi "destroy\n");
209a0b6913cSTomohiro Kusumi usage(1);
210f6aebb44SMatthew Dillon }
211f6aebb44SMatthew Dillon ecode = cmd_destroy_path(ac - 1, (const char **)(void *)&av[1]);
212ead47bfaSMatthew Dillon } else if (strcmp(av[0], "destroy-inum") == 0) {
213ead47bfaSMatthew Dillon if (ac < 2) {
214ead47bfaSMatthew Dillon fprintf(stderr,
215e03500eeSTomohiro Kusumi "destroy-inum: specify one or more inode "
216e03500eeSTomohiro Kusumi "numbers to destroy\n");
217a0b6913cSTomohiro Kusumi usage(1);
218ead47bfaSMatthew Dillon }
219a0b6913cSTomohiro Kusumi ecode = cmd_destroy_inum(sel_path, ac - 1,
220a0b6913cSTomohiro Kusumi (const char **)(void *)&av[1]);
221acbbd0efSMatthew Dillon } else if (strcmp(av[0], "emergency-mode-enable") == 0) {
222acbbd0efSMatthew Dillon ecode = cmd_emergency_mode(sel_path, 1, ac - 1,
223acbbd0efSMatthew Dillon (const char **)(void *)&av[1]);
224acbbd0efSMatthew Dillon } else if (strcmp(av[0], "emergency-mode-disable") == 0) {
225acbbd0efSMatthew Dillon ecode = cmd_emergency_mode(sel_path, 0, ac - 1,
226acbbd0efSMatthew Dillon (const char **)(void *)&av[1]);
2274599d71eSMatthew Dillon } else if (strcmp(av[0], "growfs") == 0) {
2284599d71eSMatthew Dillon ecode = cmd_growfs(sel_path, ac - 1,
2294599d71eSMatthew Dillon (const char **)(void *)&av[1]);
230775153c2SMatthew Dillon } else if (strcmp(av[0], "hash") == 0) {
231775153c2SMatthew Dillon ecode = cmd_hash(ac - 1, (const char **)(void *)&av[1]);
2320c41f055SMatthew Dillon } else if (strcmp(av[0], "dhash") == 0) {
2330c41f055SMatthew Dillon ecode = cmd_dhash(ac - 1, (const char **)(void *)&av[1]);
234b92bfd39SMatthew Dillon } else if (strcmp(av[0], "info") == 0) {
235b92bfd39SMatthew Dillon ecode = cmd_info(ac - 1, (const char **)(void *)&av[1]);
236b92bfd39SMatthew Dillon } else if (strcmp(av[0], "mountall") == 0) {
237b92bfd39SMatthew Dillon ecode = cmd_mountall(ac - 1, (const char **)(void *)&av[1]);
2382910a90cSMatthew Dillon } else if (strcmp(av[0], "status") == 0) {
2392910a90cSMatthew Dillon /*
2402910a90cSMatthew Dillon * Get status of PFS and its connections (-a for all PFSs)
2412910a90cSMatthew Dillon */
2423c198419SMatthew Dillon if (ac < 2) {
2432910a90cSMatthew Dillon ecode = cmd_remote_status(sel_path, all_opt);
2443c198419SMatthew Dillon } else {
2453c198419SMatthew Dillon int i;
2463c198419SMatthew Dillon for (i = 1; i < ac; ++i)
2473c198419SMatthew Dillon ecode = cmd_remote_status(av[i], all_opt);
2483c198419SMatthew Dillon }
2497dc0f844SMatthew Dillon } else if (strcmp(av[0], "pfs-clid") == 0) {
2507dc0f844SMatthew Dillon /*
2517dc0f844SMatthew Dillon * Print cluster id (uuid) for specific PFS
2527dc0f844SMatthew Dillon */
2537dc0f844SMatthew Dillon if (ac < 2) {
2547dc0f844SMatthew Dillon fprintf(stderr, "pfs-clid: requires name\n");
2557dc0f844SMatthew Dillon usage(1);
2567dc0f844SMatthew Dillon }
2577dc0f844SMatthew Dillon ecode = cmd_pfs_getid(sel_path, av[1], 0);
2587dc0f844SMatthew Dillon } else if (strcmp(av[0], "pfs-fsid") == 0) {
2597dc0f844SMatthew Dillon /*
2607dc0f844SMatthew Dillon * Print private id (uuid) for specific PFS
2617dc0f844SMatthew Dillon */
2627dc0f844SMatthew Dillon if (ac < 2) {
2637dc0f844SMatthew Dillon fprintf(stderr, "pfs-fsid: requires name\n");
2647dc0f844SMatthew Dillon usage(1);
2657dc0f844SMatthew Dillon }
2667dc0f844SMatthew Dillon ecode = cmd_pfs_getid(sel_path, av[1], 1);
267bd878fc9SMatthew Dillon } else if (strcmp(av[0], "pfs-list") == 0) {
268ae183399SMatthew Dillon /*
269ae183399SMatthew Dillon * List all PFSs
270ae183399SMatthew Dillon */
271b92bfd39SMatthew Dillon if (ac >= 2) {
272b92bfd39SMatthew Dillon ecode = cmd_pfs_list(ac - 1,
273cef49084SMatthew Dillon (char **)(void *)&av[1]);
274b92bfd39SMatthew Dillon } else {
275b92bfd39SMatthew Dillon ecode = cmd_pfs_list(1, &sel_path);
276d0ceb671SMatthew Dillon }
277bd878fc9SMatthew Dillon } else if (strcmp(av[0], "pfs-create") == 0) {
2782910a90cSMatthew Dillon /*
2792910a90cSMatthew Dillon * Create new PFS using pfs_type
2802910a90cSMatthew Dillon */
281ae183399SMatthew Dillon if (ac < 2) {
282bd878fc9SMatthew Dillon fprintf(stderr, "pfs-create: requires name\n");
283ae183399SMatthew Dillon usage(1);
284ae183399SMatthew Dillon }
285ae183399SMatthew Dillon ecode = cmd_pfs_create(sel_path, av[1], pfs_type, uuid_str);
286bd878fc9SMatthew Dillon } else if (strcmp(av[0], "pfs-delete") == 0) {
287ae183399SMatthew Dillon /*
288ae183399SMatthew Dillon * Delete a PFS by name
289ae183399SMatthew Dillon */
290ae183399SMatthew Dillon if (ac < 2) {
291bd878fc9SMatthew Dillon fprintf(stderr, "pfs-delete: requires name\n");
292ae183399SMatthew Dillon usage(1);
293ae183399SMatthew Dillon }
29483d90983SMatthew Dillon ecode = cmd_pfs_delete(sel_path, av, ac);
295f2bb8defSTomohiro Kusumi } else if (strcmp(av[0], "recover") == 0 ||
296f2bb8defSTomohiro Kusumi strcmp(av[0], "recover-relaxed") == 0 ||
297f2bb8defSTomohiro Kusumi strcmp(av[0], "recover-file") == 0)
298f2bb8defSTomohiro Kusumi {
299f2bb8defSTomohiro Kusumi /*
300f2bb8defSTomohiro Kusumi * Recover a relative path (unanchored match), absolute path,
301f2bb8defSTomohiro Kusumi * specific file, or directory sub-tree. File restorals are
302f2bb8defSTomohiro Kusumi * fully validated.
303f2bb8defSTomohiro Kusumi */
304f2bb8defSTomohiro Kusumi if (ac != 4) {
305f2bb8defSTomohiro Kusumi fprintf(stderr, "recover device [/]path destdir\n");
306f2bb8defSTomohiro Kusumi usage(1);
307f2bb8defSTomohiro Kusumi } else {
308f2bb8defSTomohiro Kusumi int strict = (strcmp(av[0], "recover-relaxed") != 0);
309f2bb8defSTomohiro Kusumi int isafile = (strcmp(av[0], "recover-file") == 0);
310f2bb8defSTomohiro Kusumi cmd_recover(av[1], av[2], av[3], strict, isafile);
311f2bb8defSTomohiro Kusumi }
31254796644SMatthew Dillon } else if (strcmp(av[0], "snapshot") == 0 ||
31354796644SMatthew Dillon strcmp(av[0], "snapshot-debug") == 0) {
3142910a90cSMatthew Dillon /*
315bd878fc9SMatthew Dillon * Create snapshot with optional pfs-type and optional
3162910a90cSMatthew Dillon * label override.
3172910a90cSMatthew Dillon */
31854796644SMatthew Dillon uint32_t flags = 0;
31954796644SMatthew Dillon
32054796644SMatthew Dillon if (strcmp(av[0], "snapshot-debug") == 0)
32154796644SMatthew Dillon flags = HAMMER2_PFSFLAGS_NOSYNC;
32254796644SMatthew Dillon
323d0ceb671SMatthew Dillon if (ac > 3) {
324e03500eeSTomohiro Kusumi fprintf(stderr, "%s: too many arguments\n", av[0]);
32587b1094eSMatthew Dillon usage(1);
32687b1094eSMatthew Dillon }
327d0ceb671SMatthew Dillon switch(ac) {
328d0ceb671SMatthew Dillon case 1:
32954796644SMatthew Dillon ecode = cmd_pfs_snapshot(sel_path, NULL, NULL, flags);
330d0ceb671SMatthew Dillon break;
331d0ceb671SMatthew Dillon case 2:
33254796644SMatthew Dillon ecode = cmd_pfs_snapshot(sel_path, av[1], NULL, flags);
333d0ceb671SMatthew Dillon break;
334d0ceb671SMatthew Dillon case 3:
33554796644SMatthew Dillon ecode = cmd_pfs_snapshot(sel_path, av[1], av[2], flags);
336d0ceb671SMatthew Dillon break;
337d0ceb671SMatthew Dillon }
33862efe6ecSMatthew Dillon } else if (strcmp(av[0], "service") == 0) {
3392910a90cSMatthew Dillon /*
34062efe6ecSMatthew Dillon * Start the service daemon. This daemon accepts
34162efe6ecSMatthew Dillon * connections from local and remote clients, handles
34262efe6ecSMatthew Dillon * the security handshake, and manages the core messaging
34362efe6ecSMatthew Dillon * protocol.
3442910a90cSMatthew Dillon */
34562efe6ecSMatthew Dillon ecode = cmd_service();
346ad7cf8eaSMatthew Dillon } else if (strcmp(av[0], "stat") == 0) {
347a1b07447SMatthew Dillon ecode = cmd_stat(ac - 1, (const char **)(void *)&av[1]);
3489ab15106SMatthew Dillon } else if (strcmp(av[0], "leaf") == 0) {
3499ab15106SMatthew Dillon /*
3509ab15106SMatthew Dillon * Start the management daemon for a specific PFS.
3519ab15106SMatthew Dillon *
3529ab15106SMatthew Dillon * This will typically connect to the local master node
3539ab15106SMatthew Dillon * daemon, register the PFS, and then pass its side of
3549ab15106SMatthew Dillon * the socket descriptor to the kernel HAMMER2 VFS via an
3559ab15106SMatthew Dillon * ioctl(). The process and/or thread context remains in the
3569ab15106SMatthew Dillon * kernel until the PFS is unmounted or the connection is
3579ab15106SMatthew Dillon * lost, then returns from the ioctl.
3589ab15106SMatthew Dillon *
3599ab15106SMatthew Dillon * It is possible to connect directly to a remote master node
3609ab15106SMatthew Dillon * instead of the local master node in situations where
3619ab15106SMatthew Dillon * encryption is not desired or no local master node is
3629ab15106SMatthew Dillon * desired. This is not recommended because it represents
3639ab15106SMatthew Dillon * a single point of failure for the PFS's communications.
3649ab15106SMatthew Dillon *
3659ab15106SMatthew Dillon * Direct kernel<->kernel communication between HAMMER2 VFSs
3669ab15106SMatthew Dillon * is theoretically possible for directly-connected
3679ab15106SMatthew Dillon * registrations (i.e. where the spanning tree is degenerate),
3689ab15106SMatthew Dillon * but not recommended. We specifically try to reduce the
3699ab15106SMatthew Dillon * complexity of the HAMMER2 VFS kernel code.
3709ab15106SMatthew Dillon */
3719ab15106SMatthew Dillon ecode = cmd_leaf(sel_path);
372bd878fc9SMatthew Dillon } else if (strcmp(av[0], "shell") == 0) {
3739ab15106SMatthew Dillon /*
3749ab15106SMatthew Dillon * Connect to the command line monitor in the hammer2 master
3759ab15106SMatthew Dillon * node for the machine using HAMMER2_DBG_SHELL messages.
3769ab15106SMatthew Dillon */
377bd878fc9SMatthew Dillon ecode = cmd_shell((ac < 2) ? NULL : av[1]);
37862efe6ecSMatthew Dillon } else if (strcmp(av[0], "rsainit") == 0) {
37962efe6ecSMatthew Dillon /*
38062efe6ecSMatthew Dillon * Initialize a RSA keypair. If no target directory is
38162efe6ecSMatthew Dillon * specified we default to "/etc/hammer2".
38262efe6ecSMatthew Dillon */
38362efe6ecSMatthew Dillon arg = (ac < 2) ? HAMMER2_DEFAULT_DIR : av[1];
38462efe6ecSMatthew Dillon ecode = cmd_rsainit(arg);
38562efe6ecSMatthew Dillon } else if (strcmp(av[0], "rsaenc") == 0) {
38662efe6ecSMatthew Dillon /*
38762efe6ecSMatthew Dillon * Encrypt the input symmetrically by running it through
38862efe6ecSMatthew Dillon * the specified public and/or private key files.
38962efe6ecSMatthew Dillon *
39062efe6ecSMatthew Dillon * If no key files are specified data is encoded using
39162efe6ecSMatthew Dillon * "/etc/hammer2/rsa.pub".
39262efe6ecSMatthew Dillon *
39362efe6ecSMatthew Dillon * WARNING: no padding is added, data stream must contain
39462efe6ecSMatthew Dillon * random padding for this to be secure.
39562efe6ecSMatthew Dillon *
39662efe6ecSMatthew Dillon * Used for debugging only
39762efe6ecSMatthew Dillon */
39862efe6ecSMatthew Dillon if (ac == 1) {
39962efe6ecSMatthew Dillon const char *rsapath = HAMMER2_DEFAULT_DIR "/rsa.pub";
40062efe6ecSMatthew Dillon ecode = cmd_rsaenc(&rsapath, 1);
40162efe6ecSMatthew Dillon } else {
402a1b07447SMatthew Dillon ecode = cmd_rsaenc((const char **)(void *)&av[1],
403a1b07447SMatthew Dillon ac - 1);
40462efe6ecSMatthew Dillon }
40562efe6ecSMatthew Dillon } else if (strcmp(av[0], "rsadec") == 0) {
40662efe6ecSMatthew Dillon /*
40762efe6ecSMatthew Dillon * Decrypt the input symmetrically by running it through
40862efe6ecSMatthew Dillon * the specified public and/or private key files.
40962efe6ecSMatthew Dillon *
41062efe6ecSMatthew Dillon * If no key files are specified data is decoded using
41162efe6ecSMatthew Dillon * "/etc/hammer2/rsa.prv".
41262efe6ecSMatthew Dillon *
41362efe6ecSMatthew Dillon * WARNING: no padding is added, data stream must contain
41462efe6ecSMatthew Dillon * random padding for this to be secure.
41562efe6ecSMatthew Dillon *
41662efe6ecSMatthew Dillon * Used for debugging only
41762efe6ecSMatthew Dillon */
41862efe6ecSMatthew Dillon if (ac == 1) {
41962efe6ecSMatthew Dillon const char *rsapath = HAMMER2_DEFAULT_DIR "/rsa.prv";
42062efe6ecSMatthew Dillon ecode = cmd_rsadec(&rsapath, 1);
42162efe6ecSMatthew Dillon } else {
422a1b07447SMatthew Dillon ecode = cmd_rsadec((const char **)(void *)&av[1],
423a1b07447SMatthew Dillon ac - 1);
42462efe6ecSMatthew Dillon }
425bd878fc9SMatthew Dillon } else if (strcmp(av[0], "show") == 0) {
426bd878fc9SMatthew Dillon /*
427bd878fc9SMatthew Dillon * Raw dump of filesystem. Use -v to check all crc's, and
428bd878fc9SMatthew Dillon * -vv to dump bulk file data.
429bd878fc9SMatthew Dillon */
430bd878fc9SMatthew Dillon if (ac != 2) {
431bd878fc9SMatthew Dillon fprintf(stderr, "show: requires device path\n");
432bd878fc9SMatthew Dillon usage(1);
433bd878fc9SMatthew Dillon } else {
43478ac5385SMatthew Dillon cmd_show(av[1], 0);
43578ac5385SMatthew Dillon }
43678ac5385SMatthew Dillon } else if (strcmp(av[0], "freemap") == 0) {
43778ac5385SMatthew Dillon /*
43878ac5385SMatthew Dillon * Raw dump of freemap. Use -v to check all crc's, and
43978ac5385SMatthew Dillon * -vv to dump bulk file data.
44078ac5385SMatthew Dillon */
44178ac5385SMatthew Dillon if (ac != 2) {
44278ac5385SMatthew Dillon fprintf(stderr, "freemap: requires device path\n");
44378ac5385SMatthew Dillon usage(1);
44478ac5385SMatthew Dillon } else {
44578ac5385SMatthew Dillon cmd_show(av[1], 1);
446bd878fc9SMatthew Dillon }
4475cf632c7STomohiro Kusumi } else if (strcmp(av[0], "volhdr") == 0) {
4485cf632c7STomohiro Kusumi /*
4495cf632c7STomohiro Kusumi * Dump the volume header.
4505cf632c7STomohiro Kusumi */
4515cf632c7STomohiro Kusumi if (ac != 2) {
4525cf632c7STomohiro Kusumi fprintf(stderr, "volhdr: requires device path\n");
4535cf632c7STomohiro Kusumi usage(1);
4545cf632c7STomohiro Kusumi } else {
4555cf632c7STomohiro Kusumi cmd_show(av[1], 2);
4565cf632c7STomohiro Kusumi }
4570b738157STomohiro Kusumi } else if (strcmp(av[0], "volume-list") == 0) {
4580b738157STomohiro Kusumi /*
4590b738157STomohiro Kusumi * List all volumes
4600b738157STomohiro Kusumi */
4610b738157STomohiro Kusumi if (ac >= 2) {
4620b738157STomohiro Kusumi ecode = cmd_volume_list(ac - 1,
4630b738157STomohiro Kusumi (char **)(void *)&av[1]);
4640b738157STomohiro Kusumi } else {
4650b738157STomohiro Kusumi ecode = cmd_volume_list(1, &sel_path);
4660b738157STomohiro Kusumi }
467355d67fcSMatthew Dillon } else if (strcmp(av[0], "setcomp") == 0) {
468f481450fSMatthew Dillon if (ac < 3) {
469f481450fSMatthew Dillon /*
470f481450fSMatthew Dillon * Missing compression method and at least one
471f481450fSMatthew Dillon * path.
472f481450fSMatthew Dillon */
473f481450fSMatthew Dillon fprintf(stderr,
474f481450fSMatthew Dillon "setcomp: requires compression method and "
475355d67fcSMatthew Dillon "directory/file path\n");
476355d67fcSMatthew Dillon usage(1);
477355d67fcSMatthew Dillon } else {
478f481450fSMatthew Dillon /*
479f481450fSMatthew Dillon * Multiple paths may be specified
480f481450fSMatthew Dillon */
481f481450fSMatthew Dillon ecode = cmd_setcomp(av[1], &av[2]);
482355d67fcSMatthew Dillon }
4838adee7deSMatthew Dillon } else if (strcmp(av[0], "setcheck") == 0) {
4848adee7deSMatthew Dillon if (ac < 3) {
4858adee7deSMatthew Dillon /*
4868adee7deSMatthew Dillon * Missing compression method and at least one
4878adee7deSMatthew Dillon * path.
4888adee7deSMatthew Dillon */
4898adee7deSMatthew Dillon fprintf(stderr,
4908adee7deSMatthew Dillon "setcheck: requires check code method and "
4918adee7deSMatthew Dillon "directory/file path\n");
4928adee7deSMatthew Dillon usage(1);
4938adee7deSMatthew Dillon } else {
4948adee7deSMatthew Dillon /*
4958adee7deSMatthew Dillon * Multiple paths may be specified
4968adee7deSMatthew Dillon */
4978adee7deSMatthew Dillon ecode = cmd_setcheck(av[1], &av[2]);
4988adee7deSMatthew Dillon }
4998adee7deSMatthew Dillon } else if (strcmp(av[0], "clrcheck") == 0) {
5008adee7deSMatthew Dillon ecode = cmd_setcheck("none", &av[1]);
5018adee7deSMatthew Dillon } else if (strcmp(av[0], "setcrc32") == 0) {
5028adee7deSMatthew Dillon ecode = cmd_setcheck("crc32", &av[1]);
503b83c55fcSMatthew Dillon } else if (strcmp(av[0], "setxxhash64") == 0) {
504b83c55fcSMatthew Dillon ecode = cmd_setcheck("xxhash64", &av[1]);
5058adee7deSMatthew Dillon } else if (strcmp(av[0], "setsha192") == 0) {
5068adee7deSMatthew Dillon ecode = cmd_setcheck("sha192", &av[1]);
507355d67fcSMatthew Dillon } else if (strcmp(av[0], "printinode") == 0) {
508355d67fcSMatthew Dillon if (ac != 2) {
509f481450fSMatthew Dillon fprintf(stderr,
510f481450fSMatthew Dillon "printinode: requires directory/file path\n");
511355d67fcSMatthew Dillon usage(1);
51200261fe0SMatthew Dillon } else {
513355d67fcSMatthew Dillon print_inode(av[1]);
51400261fe0SMatthew Dillon }
51500261fe0SMatthew Dillon } else if (strcmp(av[0], "bulkfree") == 0) {
51600261fe0SMatthew Dillon if (ac != 2) {
517e03500eeSTomohiro Kusumi fprintf(stderr, "bulkfree: requires path to mount\n");
51800261fe0SMatthew Dillon usage(1);
51900261fe0SMatthew Dillon } else {
52000261fe0SMatthew Dillon ecode = cmd_bulkfree(av[1]);
52100261fe0SMatthew Dillon }
522b83c55fcSMatthew Dillon #if 0
5239dca9515SMatthew Dillon } else if (strcmp(av[0], "bulkfree-async") == 0) {
5249dca9515SMatthew Dillon if (ac != 2) {
5259dca9515SMatthew Dillon fprintf(stderr,
5269dca9515SMatthew Dillon "bulkfree-async: requires path to mount\n");
5279dca9515SMatthew Dillon usage(1);
5289dca9515SMatthew Dillon } else {
5299dca9515SMatthew Dillon ecode = cmd_bulkfree_async(av[1]);
5309dca9515SMatthew Dillon }
531b83c55fcSMatthew Dillon #endif
53230ce27d4SMatthew Dillon } else if (strcmp(av[0], "cleanup") == 0) {
53330ce27d4SMatthew Dillon ecode = cmd_cleanup(av[1]); /* can be NULL */
5342910a90cSMatthew Dillon } else {
5352910a90cSMatthew Dillon fprintf(stderr, "Unrecognized command: %s\n", av[0]);
5362910a90cSMatthew Dillon usage(1);
5372910a90cSMatthew Dillon }
5385ba65e34SMatthew Dillon
5395ba65e34SMatthew Dillon /*
5405ba65e34SMatthew Dillon * In DebugMode we may wind up starting several pthreads in the
5415ba65e34SMatthew Dillon * original process, in which case we have to let them run and
5425ba65e34SMatthew Dillon * not actually exit.
5435ba65e34SMatthew Dillon */
5445ba65e34SMatthew Dillon if (NormalExit) {
5452910a90cSMatthew Dillon return (ecode);
5465ba65e34SMatthew Dillon } else {
5475ba65e34SMatthew Dillon pthread_exit(NULL);
5485ba65e34SMatthew Dillon _exit(2); /* NOT REACHED */
5495ba65e34SMatthew Dillon }
5502910a90cSMatthew Dillon }
5512910a90cSMatthew Dillon
5522910a90cSMatthew Dillon static
5532910a90cSMatthew Dillon void
usage(int code)5542910a90cSMatthew Dillon usage(int code)
5552910a90cSMatthew Dillon {
5562910a90cSMatthew Dillon fprintf(stderr,
557d371ccd2STomohiro Kusumi "hammer2 [options] command [argument ...]\n"
5582910a90cSMatthew Dillon " -s path Select filesystem\n"
559bd878fc9SMatthew Dillon " -t type PFS type for pfs-create\n"
560bd878fc9SMatthew Dillon " -u uuid uuid for pfs-create\n"
561944ddad0SMatthew Dillon " -m mem[k,m,g] buffer memory (bulkfree)\n"
562bd878fc9SMatthew Dillon "\n"
563d371ccd2STomohiro Kusumi " cleanup [<path>] "
5644aedc17bSzrj "Run cleanup passes\n"
565f481450fSMatthew Dillon " connect <target> "
566f481450fSMatthew Dillon "Add cluster link\n"
567d371ccd2STomohiro Kusumi " destroy <path>... "
568ead47bfaSMatthew Dillon "Destroy directory entries (only use if inode bad)\n"
569d371ccd2STomohiro Kusumi " destroy-inum <inum>... "
570ead47bfaSMatthew Dillon "Destroy inodes (only use if inode bad)\n"
571f481450fSMatthew Dillon " disconnect <target> "
572f481450fSMatthew Dillon "Del cluster link\n"
573acbbd0efSMatthew Dillon " emergency-mode-enable <target> "
574acbbd0efSMatthew Dillon "Enable emergency operations mode on filesystem\n"
575acbbd0efSMatthew Dillon " "
576acbbd0efSMatthew Dillon "THIS IS A VERY DANGEROUS MODE\n"
577acbbd0efSMatthew Dillon " emergency-mode-disable <target> "
578acbbd0efSMatthew Dillon "Disable emergency operations mode on filesystem\n"
579d371ccd2STomohiro Kusumi " info [<devpath>...] "
580b92bfd39SMatthew Dillon "Info on all offline or online H2 partitions\n"
581d371ccd2STomohiro Kusumi " mountall [<devpath>...] "
582b92bfd39SMatthew Dillon "Mount @LOCAL for all H2 partitions\n"
5833c198419SMatthew Dillon " status [<path>...] "
584b92bfd39SMatthew Dillon "Report active cluster status\n"
585d371ccd2STomohiro Kusumi " hash [<filename>...] "
586d371ccd2STomohiro Kusumi "Print directory hash (key) for name\n"
587d371ccd2STomohiro Kusumi " dhash [<filename>...] "
588d371ccd2STomohiro Kusumi "Print data hash for long directory entry\n"
589b92bfd39SMatthew Dillon " pfs-list [<path>...] "
590f481450fSMatthew Dillon "List PFSs\n"
591f481450fSMatthew Dillon " pfs-clid <label> "
592f481450fSMatthew Dillon "Print cluster id for specific PFS\n"
593f481450fSMatthew Dillon " pfs-fsid <label> "
594f481450fSMatthew Dillon "Print private id for specific PFS\n"
595f481450fSMatthew Dillon " pfs-create <label> "
596f481450fSMatthew Dillon "Create a PFS\n"
597f481450fSMatthew Dillon " pfs-delete <label> "
598f481450fSMatthew Dillon "Destroy a PFS\n"
5995627cde5SMatthew Dillon " recover <devpath> <path> <destdir> "
6005627cde5SMatthew Dillon "Recover deleted or corrupt files or trees\n"
601ddc249f6SMatthew Dillon " recover-relaxed <devpath> <path> <destdir> "
602ddc249f6SMatthew Dillon "Recover deleted or corrupt files or trees\n"
603ddc249f6SMatthew Dillon " recover-file <devpath> <path> <destdir> "
604ddc249f6SMatthew Dillon "Recover, target is explicitly a regular file\n"
605d0ceb671SMatthew Dillon " snapshot <path> [<label>] "
606d0ceb671SMatthew Dillon "Snapshot a PFS or directory\n"
60754796644SMatthew Dillon " snapshot-debug <path> [<label>] "
60854796644SMatthew Dillon "Snapshot without filesystem sync\n"
609f481450fSMatthew Dillon " service "
610f481450fSMatthew Dillon "Start service daemon\n"
611d371ccd2STomohiro Kusumi " stat [<path>...] "
612f481450fSMatthew Dillon "Return inode quota & config\n"
613f481450fSMatthew Dillon " leaf "
614f481450fSMatthew Dillon "Start pfs leaf daemon\n"
615f481450fSMatthew Dillon " shell [<host>] "
616f481450fSMatthew Dillon "Connect to debug shell\n"
617f481450fSMatthew Dillon " debugspan <target> "
618f481450fSMatthew Dillon "Connect to target, run CONN/SPAN\n"
619*6cd7b653STomohiro Kusumi " growfs [<path>...] "
6204599d71eSMatthew Dillon "Grow a filesystem into resized partition\n"
621d371ccd2STomohiro Kusumi " rsainit [<path>] "
622f481450fSMatthew Dillon "Initialize rsa fields\n"
623d371ccd2STomohiro Kusumi " show <devpath> "
624d371ccd2STomohiro Kusumi "Raw hammer2 media dump for topology\n"
625d371ccd2STomohiro Kusumi " freemap <devpath> "
626d371ccd2STomohiro Kusumi "Raw hammer2 media dump for freemap\n"
627aa2131f0SMatthew Dillon " volhdr <devpath> "
628aa2131f0SMatthew Dillon "Raw hammer2 media dump for the volume header(s)\n"
6290b738157STomohiro Kusumi " volume-list [<path>...] "
6300b738157STomohiro Kusumi "List volumes\n"
631d371ccd2STomohiro Kusumi " setcomp <comp[:level]> <path>... "
6328adee7deSMatthew Dillon "Set comp algo {none, autozero, lz4, zlib} & level\n"
633d371ccd2STomohiro Kusumi " setcheck <check> <path>... "
634b83c55fcSMatthew Dillon "Set check algo {none, crc32, xxhash64, sha192}\n"
635d371ccd2STomohiro Kusumi " clrcheck [<path>...] "
6363c198419SMatthew Dillon "Clear check code override\n"
637d371ccd2STomohiro Kusumi " setcrc32 [<path>...] "
6388adee7deSMatthew Dillon "Set check algo to crc32\n"
639d371ccd2STomohiro Kusumi " setxxhash64 [<path>...] "
640b83c55fcSMatthew Dillon "Set check algo to xxhash64\n"
641d371ccd2STomohiro Kusumi " setsha192 [<path>...] "
6428adee7deSMatthew Dillon "Set check algo to sha192\n"
643d371ccd2STomohiro Kusumi " bulkfree <path> "
64400261fe0SMatthew Dillon "Run bulkfree pass\n"
645d371ccd2STomohiro Kusumi " printinode <path> "
646d371ccd2STomohiro Kusumi "Dump inode\n"
647d371ccd2STomohiro Kusumi " dumpchain [<path> [<chnflags>]] "
648d371ccd2STomohiro Kusumi "Dump in-memory chain topology (ONFLUSH flag is 0x200)\n"
649b83c55fcSMatthew Dillon #if 0
650d371ccd2STomohiro Kusumi " bulkfree-async path "
6519dca9515SMatthew Dillon "Run bulkfree pass asynchronously\n"
652b83c55fcSMatthew Dillon #endif
6532910a90cSMatthew Dillon );
6542910a90cSMatthew Dillon exit(code);
6552910a90cSMatthew Dillon }
656