xref: /dflybsd-src/sbin/hammer2/main.c (revision 6cd7b6532631428e69a83c882781e039f88550f6)
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