2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
18 * 3. Neither the name of The DragonFly Project nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific, prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 int NormalExit
= 1; /* if set to 0 main() has to pthread_exit() */
45 static void usage(int code
);
48 main(int ac
, char **av
)
50 const char *sel_path
= NULL
;
51 const char *uuid_str
= NULL
;
53 int pfs_type
= HAMMER2_PFSTYPE_NONE
;
59 signal(SIGPIPE
, SIG_IGN
);
65 while ((ch
= getopt(ac
, av
, "adfrqs:t:u:v")) != -1) {
86 * set node type for mkpfs
88 if (strcasecmp(optarg
, "CACHE") == 0) {
89 pfs_type
= HAMMER2_PFSTYPE_CACHE
;
90 } else if (strcasecmp(optarg
, "DUMMY") == 0) {
91 pfs_type
= HAMMER2_PFSTYPE_DUMMY
;
92 } else if (strcasecmp(optarg
, "SLAVE") == 0) {
93 pfs_type
= HAMMER2_PFSTYPE_SLAVE
;
94 } else if (strcasecmp(optarg
, "SOFT_SLAVE") == 0) {
95 pfs_type
= HAMMER2_PFSTYPE_SOFT_SLAVE
;
96 } else if (strcasecmp(optarg
, "SOFT_MASTER") == 0) {
97 pfs_type
= HAMMER2_PFSTYPE_SOFT_MASTER
;
98 } else if (strcasecmp(optarg
, "MASTER") == 0) {
99 pfs_type
= HAMMER2_PFSTYPE_MASTER
;
101 fprintf(stderr
, "-t: Unrecognized node type\n");
107 * set uuid for mkpfs, else one will be generated
108 * (required for all except the MASTER node_type)
125 fprintf(stderr
, "Unknown option: %c\n", ch
);
133 * Adjust, then process the command
138 fprintf(stderr
, "Missing command\n");
143 if (strcmp(av
[0], "connect") == 0) {
145 * Add cluster connection
148 fprintf(stderr
, "connect: missing argument\n");
151 ecode
= cmd_remote_connect(sel_path
, av
[1]);
152 } else if (strcmp(av
[0], "chaindump") == 0) {
154 ecode
= cmd_chaindump(".");
156 ecode
= cmd_chaindump(av
[1]);
157 } else if (strcmp(av
[0], "debugspan") == 0) {
159 * Debug connection to the target hammer2 service and run
160 * the CONN/SPAN protocol.
163 fprintf(stderr
, "debugspan: requires hostname\n");
166 ecode
= cmd_debugspan(av
[1]);
167 } else if (strcmp(av
[0], "disconnect") == 0) {
169 * Remove cluster connection
172 fprintf(stderr
, "disconnect: missing argument\n");
175 ecode
= cmd_remote_disconnect(sel_path
, av
[1]);
176 } else if (strcmp(av
[0], "hash") == 0) {
177 ecode
= cmd_hash(ac
- 1, (const char **)(void *)&av
[1]);
178 } else if (strcmp(av
[0], "info") == 0) {
179 ecode
= cmd_info(ac
- 1, (const char **)(void *)&av
[1]);
180 } else if (strcmp(av
[0], "mountall") == 0) {
181 ecode
= cmd_mountall(ac
- 1, (const char **)(void *)&av
[1]);
182 } else if (strcmp(av
[0], "status") == 0) {
184 * Get status of PFS and its connections (-a for all PFSs)
187 ecode
= cmd_remote_status(sel_path
, all_opt
);
191 for (i
= 1; i
< ac
; ++i
)
192 ecode
= cmd_remote_status(av
[i
], all_opt
);
194 } else if (strcmp(av
[0], "pfs-clid") == 0) {
196 * Print cluster id (uuid) for specific PFS
199 fprintf(stderr
, "pfs-clid: requires name\n");
202 ecode
= cmd_pfs_getid(sel_path
, av
[1], 0);
203 } else if (strcmp(av
[0], "pfs-fsid") == 0) {
205 * Print private id (uuid) for specific PFS
208 fprintf(stderr
, "pfs-fsid: requires name\n");
211 ecode
= cmd_pfs_getid(sel_path
, av
[1], 1);
212 } else if (strcmp(av
[0], "pfs-list") == 0) {
217 ecode
= cmd_pfs_list(ac
- 1,
218 (const char **)(void *)&av
[1]);
220 ecode
= cmd_pfs_list(1, &sel_path
);
222 } else if (strcmp(av
[0], "pfs-create") == 0) {
224 * Create new PFS using pfs_type
227 fprintf(stderr
, "pfs-create: requires name\n");
230 ecode
= cmd_pfs_create(sel_path
, av
[1], pfs_type
, uuid_str
);
231 } else if (strcmp(av
[0], "pfs-delete") == 0) {
233 * Delete a PFS by name
236 fprintf(stderr
, "pfs-delete: requires name\n");
239 ecode
= cmd_pfs_delete(sel_path
, av
[1]);
240 } else if (strcmp(av
[0], "snapshot") == 0) {
242 * Create snapshot with optional pfs-type and optional
246 fprintf(stderr
, "pfs-snapshot: too many arguments\n");
251 ecode
= cmd_pfs_snapshot(sel_path
, NULL
, NULL
);
254 ecode
= cmd_pfs_snapshot(sel_path
, av
[1], NULL
);
257 ecode
= cmd_pfs_snapshot(sel_path
, av
[1], av
[2]);
260 } else if (strcmp(av
[0], "service") == 0) {
262 * Start the service daemon. This daemon accepts
263 * connections from local and remote clients, handles
264 * the security handshake, and manages the core messaging
267 ecode
= cmd_service();
268 } else if (strcmp(av
[0], "stat") == 0) {
269 ecode
= cmd_stat(ac
- 1, (const char **)(void *)&av
[1]);
270 } else if (strcmp(av
[0], "leaf") == 0) {
272 * Start the management daemon for a specific PFS.
274 * This will typically connect to the local master node
275 * daemon, register the PFS, and then pass its side of
276 * the socket descriptor to the kernel HAMMER2 VFS via an
277 * ioctl(). The process and/or thread context remains in the
278 * kernel until the PFS is unmounted or the connection is
279 * lost, then returns from the ioctl.
281 * It is possible to connect directly to a remote master node
282 * instead of the local master node in situations where
283 * encryption is not desired or no local master node is
284 * desired. This is not recommended because it represents
285 * a single point of failure for the PFS's communications.
287 * Direct kernel<->kernel communication between HAMMER2 VFSs
288 * is theoretically possible for directly-connected
289 * registrations (i.e. where the spanning tree is degenerate),
290 * but not recommended. We specifically try to reduce the
291 * complexity of the HAMMER2 VFS kernel code.
293 ecode
= cmd_leaf(sel_path
);
294 } else if (strcmp(av
[0], "shell") == 0) {
296 * Connect to the command line monitor in the hammer2 master
297 * node for the machine using HAMMER2_DBG_SHELL messages.
299 ecode
= cmd_shell((ac
< 2) ? NULL
: av
[1]);
300 } else if (strcmp(av
[0], "rsainit") == 0) {
302 * Initialize a RSA keypair. If no target directory is
303 * specified we default to "/etc/hammer2".
305 arg
= (ac
< 2) ? HAMMER2_DEFAULT_DIR
: av
[1];
306 ecode
= cmd_rsainit(arg
);
307 } else if (strcmp(av
[0], "rsaenc") == 0) {
309 * Encrypt the input symmetrically by running it through
310 * the specified public and/or private key files.
312 * If no key files are specified data is encoded using
313 * "/etc/hammer2/rsa.pub".
315 * WARNING: no padding is added, data stream must contain
316 * random padding for this to be secure.
318 * Used for debugging only
321 const char *rsapath
= HAMMER2_DEFAULT_DIR
"/rsa.pub";
322 ecode
= cmd_rsaenc(&rsapath
, 1);
324 ecode
= cmd_rsaenc((const char **)(void *)&av
[1],
327 } else if (strcmp(av
[0], "rsadec") == 0) {
329 * Decrypt the input symmetrically by running it through
330 * the specified public and/or private key files.
332 * If no key files are specified data is decoded using
333 * "/etc/hammer2/rsa.prv".
335 * WARNING: no padding is added, data stream must contain
336 * random padding for this to be secure.
338 * Used for debugging only
341 const char *rsapath
= HAMMER2_DEFAULT_DIR
"/rsa.prv";
342 ecode
= cmd_rsadec(&rsapath
, 1);
344 ecode
= cmd_rsadec((const char **)(void *)&av
[1],
347 } else if (strcmp(av
[0], "show") == 0) {
349 * Raw dump of filesystem. Use -v to check all crc's, and
350 * -vv to dump bulk file data.
353 fprintf(stderr
, "show: requires device path\n");
358 } else if (strcmp(av
[0], "freemap") == 0) {
360 * Raw dump of freemap. Use -v to check all crc's, and
361 * -vv to dump bulk file data.
364 fprintf(stderr
, "freemap: requires device path\n");
369 } else if (strcmp(av
[0], "setcomp") == 0) {
372 * Missing compression method and at least one
376 "setcomp: requires compression method and"
377 "directory/file path\n");
381 * Multiple paths may be specified
383 ecode
= cmd_setcomp(av
[1], &av
[2]);
385 } else if (strcmp(av
[0], "setcheck") == 0) {
388 * Missing compression method and at least one
392 "setcheck: requires check code method and"
393 "directory/file path\n");
397 * Multiple paths may be specified
399 ecode
= cmd_setcheck(av
[1], &av
[2]);
401 } else if (strcmp(av
[0], "clrcheck") == 0) {
402 ecode
= cmd_setcheck("none", &av
[1]);
403 } else if (strcmp(av
[0], "setcrc32") == 0) {
404 ecode
= cmd_setcheck("crc32", &av
[1]);
405 } else if (strcmp(av
[0], "setxxhash64") == 0) {
406 ecode
= cmd_setcheck("xxhash64", &av
[1]);
407 } else if (strcmp(av
[0], "setsha192") == 0) {
408 ecode
= cmd_setcheck("sha192", &av
[1]);
409 } else if (strcmp(av
[0], "printinode") == 0) {
412 "printinode: requires directory/file path\n");
417 } else if (strcmp(av
[0], "bulkfree") == 0) {
420 "bulkfree: requires path to mount\n");
423 ecode
= cmd_bulkfree(av
[1]);
426 } else if (strcmp(av
[0], "bulkfree-async") == 0) {
429 "bulkfree-async: requires path to mount\n");
432 ecode
= cmd_bulkfree_async(av
[1]);
436 fprintf(stderr
, "Unrecognized command: %s\n", av
[0]);
441 * In DebugMode we may wind up starting several pthreads in the
442 * original process, in which case we have to let them run and
449 _exit(2); /* NOT REACHED */
458 "hammer2 [options] command...\n"
459 " -s path Select filesystem\n"
460 " -t type PFS type for pfs-create\n"
461 " -u uuid uuid for pfs-create\n"
465 " debugspan <target> "
466 "Debug spanning tree\n"
468 "Dump in-memory chain topo at\n"
469 " disconnect <target> "
472 "Print directory hash\n"
473 " info [devpath...] "
474 "Info on all offline or online H2 partitions\n"
475 " mountall [devpath...] "
476 "Mount @LOCAL for all H2 partitions\n"
477 " status [<path>...] "
478 "Report active cluster status\n"
479 " pfs-list [<path>...] "
482 "Print cluster id for specific PFS\n"
484 "Print private id for specific PFS\n"
485 " pfs-create <label> "
487 " pfs-delete <label> "
489 " snapshot <path> [<label>] "
490 "Snapshot a PFS or directory\n"
492 "Start service daemon\n"
494 "Return inode quota & config\n"
496 "Start pfs leaf daemon\n"
498 "Connect to debug shell\n"
499 " debugspan <target> "
500 "Connect to target, run CONN/SPAN\n"
502 "Initialize rsa fields\n"
504 "Raw hammer2 media dump\n"
506 "Raw hammer2 media dump\n"
507 " setcomp comp[:level] path... "
508 "Set comp algo {none, autozero, lz4, zlib} & level\n"
509 " setcheck check path... "
510 "Set check algo {none, crc32, xxhash64, sha192}\n"
512 "Clear check code override\n"
514 "Set check algo to crc32\n"
515 " setxxhash64 path... "
516 "Set check algo to xxhash64\n"
517 " setsha192 path... "
518 "Set check algo to sha192\n"
520 "Run bulkfree pass\n"
522 " bulkfree-async path... "
523 "Run bulkfree pass asynchronously\n"