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], "status") == 0) {
180 * Get status of PFS and its connections (-a for all PFSs)
183 ecode
= cmd_remote_status(sel_path
, all_opt
);
187 for (i
= 1; i
< ac
; ++i
)
188 ecode
= cmd_remote_status(av
[i
], all_opt
);
190 } else if (strcmp(av
[0], "pfs-clid") == 0) {
192 * Print cluster id (uuid) for specific PFS
195 fprintf(stderr
, "pfs-clid: requires name\n");
198 ecode
= cmd_pfs_getid(sel_path
, av
[1], 0);
199 } else if (strcmp(av
[0], "pfs-fsid") == 0) {
201 * Print private id (uuid) for specific PFS
204 fprintf(stderr
, "pfs-fsid: requires name\n");
207 ecode
= cmd_pfs_getid(sel_path
, av
[1], 1);
208 } else if (strcmp(av
[0], "pfs-list") == 0) {
213 fprintf(stderr
, "pfs-list: too many arguments\n");
216 ecode
= cmd_pfs_list((ac
== 2) ? av
[1] : sel_path
);
217 } else if (strcmp(av
[0], "pfs-create") == 0) {
219 * Create new PFS using pfs_type
222 fprintf(stderr
, "pfs-create: requires name\n");
225 ecode
= cmd_pfs_create(sel_path
, av
[1], pfs_type
, uuid_str
);
226 } else if (strcmp(av
[0], "pfs-delete") == 0) {
228 * Delete a PFS by name
231 fprintf(stderr
, "pfs-delete: requires name\n");
234 ecode
= cmd_pfs_delete(sel_path
, av
[1]);
235 } else if (strcmp(av
[0], "snapshot") == 0) {
237 * Create snapshot with optional pfs-type and optional
241 fprintf(stderr
, "pfs-snapshot: too many arguments\n");
246 ecode
= cmd_pfs_snapshot(sel_path
, NULL
, NULL
);
249 ecode
= cmd_pfs_snapshot(sel_path
, av
[1], NULL
);
252 ecode
= cmd_pfs_snapshot(sel_path
, av
[1], av
[2]);
255 } else if (strcmp(av
[0], "service") == 0) {
257 * Start the service daemon. This daemon accepts
258 * connections from local and remote clients, handles
259 * the security handshake, and manages the core messaging
262 ecode
= cmd_service();
263 } else if (strcmp(av
[0], "stat") == 0) {
264 ecode
= cmd_stat(ac
- 1, (const char **)(void *)&av
[1]);
265 } else if (strcmp(av
[0], "leaf") == 0) {
267 * Start the management daemon for a specific PFS.
269 * This will typically connect to the local master node
270 * daemon, register the PFS, and then pass its side of
271 * the socket descriptor to the kernel HAMMER2 VFS via an
272 * ioctl(). The process and/or thread context remains in the
273 * kernel until the PFS is unmounted or the connection is
274 * lost, then returns from the ioctl.
276 * It is possible to connect directly to a remote master node
277 * instead of the local master node in situations where
278 * encryption is not desired or no local master node is
279 * desired. This is not recommended because it represents
280 * a single point of failure for the PFS's communications.
282 * Direct kernel<->kernel communication between HAMMER2 VFSs
283 * is theoretically possible for directly-connected
284 * registrations (i.e. where the spanning tree is degenerate),
285 * but not recommended. We specifically try to reduce the
286 * complexity of the HAMMER2 VFS kernel code.
288 ecode
= cmd_leaf(sel_path
);
289 } else if (strcmp(av
[0], "shell") == 0) {
291 * Connect to the command line monitor in the hammer2 master
292 * node for the machine using HAMMER2_DBG_SHELL messages.
294 ecode
= cmd_shell((ac
< 2) ? NULL
: av
[1]);
295 } else if (strcmp(av
[0], "rsainit") == 0) {
297 * Initialize a RSA keypair. If no target directory is
298 * specified we default to "/etc/hammer2".
300 arg
= (ac
< 2) ? HAMMER2_DEFAULT_DIR
: av
[1];
301 ecode
= cmd_rsainit(arg
);
302 } else if (strcmp(av
[0], "rsaenc") == 0) {
304 * Encrypt the input symmetrically by running it through
305 * the specified public and/or private key files.
307 * If no key files are specified data is encoded using
308 * "/etc/hammer2/rsa.pub".
310 * WARNING: no padding is added, data stream must contain
311 * random padding for this to be secure.
313 * Used for debugging only
316 const char *rsapath
= HAMMER2_DEFAULT_DIR
"/rsa.pub";
317 ecode
= cmd_rsaenc(&rsapath
, 1);
319 ecode
= cmd_rsaenc((const char **)(void *)&av
[1],
322 } else if (strcmp(av
[0], "rsadec") == 0) {
324 * Decrypt the input symmetrically by running it through
325 * the specified public and/or private key files.
327 * If no key files are specified data is decoded using
328 * "/etc/hammer2/rsa.prv".
330 * WARNING: no padding is added, data stream must contain
331 * random padding for this to be secure.
333 * Used for debugging only
336 const char *rsapath
= HAMMER2_DEFAULT_DIR
"/rsa.prv";
337 ecode
= cmd_rsadec(&rsapath
, 1);
339 ecode
= cmd_rsadec((const char **)(void *)&av
[1],
342 } else if (strcmp(av
[0], "show") == 0) {
344 * Raw dump of filesystem. Use -v to check all crc's, and
345 * -vv to dump bulk file data.
348 fprintf(stderr
, "show: requires device path\n");
353 } else if (strcmp(av
[0], "freemap") == 0) {
355 * Raw dump of freemap. Use -v to check all crc's, and
356 * -vv to dump bulk file data.
359 fprintf(stderr
, "freemap: requires device path\n");
364 } else if (strcmp(av
[0], "setcomp") == 0) {
367 * Missing compression method and at least one
371 "setcomp: requires compression method and"
372 "directory/file path\n");
376 * Multiple paths may be specified
378 ecode
= cmd_setcomp(av
[1], &av
[2]);
380 } else if (strcmp(av
[0], "setcheck") == 0) {
383 * Missing compression method and at least one
387 "setcheck: requires check code method and"
388 "directory/file path\n");
392 * Multiple paths may be specified
394 ecode
= cmd_setcheck(av
[1], &av
[2]);
396 } else if (strcmp(av
[0], "clrcheck") == 0) {
397 ecode
= cmd_setcheck("none", &av
[1]);
398 } else if (strcmp(av
[0], "setcrc32") == 0) {
399 ecode
= cmd_setcheck("crc32", &av
[1]);
400 } else if (strcmp(av
[0], "setcrc64") == 0) {
401 ecode
= cmd_setcheck("crc64", &av
[1]);
402 } else if (strcmp(av
[0], "setsha192") == 0) {
403 ecode
= cmd_setcheck("sha192", &av
[1]);
404 } else if (strcmp(av
[0], "printinode") == 0) {
407 "printinode: requires directory/file path\n");
412 } else if (strcmp(av
[0], "bulkfree") == 0) {
415 "bulkfree: requires path to mount\n");
418 ecode
= cmd_bulkfree(av
[1]);
421 fprintf(stderr
, "Unrecognized command: %s\n", av
[0]);
426 * In DebugMode we may wind up starting several pthreads in the
427 * original process, in which case we have to let them run and
434 _exit(2); /* NOT REACHED */
443 "hammer2 [options] command...\n"
444 " -s path Select filesystem\n"
445 " -t type PFS type for pfs-create\n"
446 " -u uuid uuid for pfs-create\n"
450 " disconnect <target> "
453 "Print directory hash\n"
454 " status [<path>...] "
455 "Report cluster status\n"
456 " pfs-list [<path>] "
459 "Print cluster id for specific PFS\n"
461 "Print private id for specific PFS\n"
462 " pfs-create <label> "
464 " pfs-delete <label> "
466 " snapshot <path> [<label>] "
467 "Snapshot a PFS or directory\n"
469 "Start service daemon\n"
471 "Return inode quota & config\n"
473 "Start pfs leaf daemon\n"
475 "Connect to debug shell\n"
476 " debugspan <target> "
477 "Connect to target, run CONN/SPAN\n"
479 "Initialize rsa fields\n"
481 "Raw hammer2 media dump\n"
483 "Raw hammer2 media dump\n"
484 " setcomp comp[:level] path... "
485 "Set comp algo {none, autozero, lz4, zlib} & level\n"
486 " setcheck check path... "
487 "Set check algo {none, crc32, crc64, sha192}\n"
489 "Clear check code override\n"
491 "Set check algo to crc32\n"
493 "Set check algo to crc64\n"
494 " setsha192 path... "
495 "Set check algo to sha192\n"
497 "Run bulkfree pass\n"