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
= DMSG_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
, "COPY") == 0) {
91 pfs_type
= HAMMER2_PFSTYPE_COPY
;
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)
182 ecode
= cmd_remote_status(sel_path
, all_opt
);
183 } else if (strcmp(av
[0], "pfs-clid") == 0) {
185 * Print cluster id (uuid) for specific PFS
188 fprintf(stderr
, "pfs-clid: requires name\n");
191 ecode
= cmd_pfs_getid(sel_path
, av
[1], 0);
192 } else if (strcmp(av
[0], "pfs-fsid") == 0) {
194 * Print private id (uuid) for specific PFS
197 fprintf(stderr
, "pfs-fsid: requires name\n");
200 ecode
= cmd_pfs_getid(sel_path
, av
[1], 1);
201 } else if (strcmp(av
[0], "pfs-list") == 0) {
206 fprintf(stderr
, "pfs-list: too many arguments\n");
209 ecode
= cmd_pfs_list((ac
== 2) ? av
[1] : sel_path
);
210 } else if (strcmp(av
[0], "pfs-create") == 0) {
212 * Create new PFS using pfs_type
215 fprintf(stderr
, "pfs-create: requires name\n");
218 ecode
= cmd_pfs_create(sel_path
, av
[1], pfs_type
, uuid_str
);
219 } else if (strcmp(av
[0], "pfs-delete") == 0) {
221 * Delete a PFS by name
224 fprintf(stderr
, "pfs-delete: requires name\n");
227 ecode
= cmd_pfs_delete(sel_path
, av
[1]);
228 } else if (strcmp(av
[0], "snapshot") == 0) {
230 * Create snapshot with optional pfs-type and optional
234 fprintf(stderr
, "pfs-snapshot: too many arguments\n");
239 ecode
= cmd_pfs_snapshot(sel_path
, NULL
, NULL
);
242 ecode
= cmd_pfs_snapshot(sel_path
, av
[1], NULL
);
245 ecode
= cmd_pfs_snapshot(sel_path
, av
[1], av
[2]);
248 } else if (strcmp(av
[0], "service") == 0) {
250 * Start the service daemon. This daemon accepts
251 * connections from local and remote clients, handles
252 * the security handshake, and manages the core messaging
255 ecode
= cmd_service();
256 } else if (strcmp(av
[0], "stat") == 0) {
257 ecode
= cmd_stat(ac
- 1, (const char **)(void *)&av
[1]);
258 } else if (strcmp(av
[0], "leaf") == 0) {
260 * Start the management daemon for a specific PFS.
262 * This will typically connect to the local master node
263 * daemon, register the PFS, and then pass its side of
264 * the socket descriptor to the kernel HAMMER2 VFS via an
265 * ioctl(). The process and/or thread context remains in the
266 * kernel until the PFS is unmounted or the connection is
267 * lost, then returns from the ioctl.
269 * It is possible to connect directly to a remote master node
270 * instead of the local master node in situations where
271 * encryption is not desired or no local master node is
272 * desired. This is not recommended because it represents
273 * a single point of failure for the PFS's communications.
275 * Direct kernel<->kernel communication between HAMMER2 VFSs
276 * is theoretically possible for directly-connected
277 * registrations (i.e. where the spanning tree is degenerate),
278 * but not recommended. We specifically try to reduce the
279 * complexity of the HAMMER2 VFS kernel code.
281 ecode
= cmd_leaf(sel_path
);
282 } else if (strcmp(av
[0], "shell") == 0) {
284 * Connect to the command line monitor in the hammer2 master
285 * node for the machine using HAMMER2_DBG_SHELL messages.
287 ecode
= cmd_shell((ac
< 2) ? NULL
: av
[1]);
288 } else if (strcmp(av
[0], "rsainit") == 0) {
290 * Initialize a RSA keypair. If no target directory is
291 * specified we default to "/etc/hammer2".
293 arg
= (ac
< 2) ? HAMMER2_DEFAULT_DIR
: av
[1];
294 ecode
= cmd_rsainit(arg
);
295 } else if (strcmp(av
[0], "rsaenc") == 0) {
297 * Encrypt the input symmetrically by running it through
298 * the specified public and/or private key files.
300 * If no key files are specified data is encoded using
301 * "/etc/hammer2/rsa.pub".
303 * WARNING: no padding is added, data stream must contain
304 * random padding for this to be secure.
306 * Used for debugging only
309 const char *rsapath
= HAMMER2_DEFAULT_DIR
"/rsa.pub";
310 ecode
= cmd_rsaenc(&rsapath
, 1);
312 ecode
= cmd_rsaenc((const char **)(void *)&av
[1],
315 } else if (strcmp(av
[0], "rsadec") == 0) {
317 * Decrypt the input symmetrically by running it through
318 * the specified public and/or private key files.
320 * If no key files are specified data is decoded using
321 * "/etc/hammer2/rsa.prv".
323 * WARNING: no padding is added, data stream must contain
324 * random padding for this to be secure.
326 * Used for debugging only
329 const char *rsapath
= HAMMER2_DEFAULT_DIR
"/rsa.prv";
330 ecode
= cmd_rsadec(&rsapath
, 1);
332 ecode
= cmd_rsadec((const char **)(void *)&av
[1],
335 } else if (strcmp(av
[0], "show") == 0) {
337 * Raw dump of filesystem. Use -v to check all crc's, and
338 * -vv to dump bulk file data.
341 fprintf(stderr
, "show: requires device path\n");
346 } else if (strcmp(av
[0], "freemap") == 0) {
348 * Raw dump of freemap. Use -v to check all crc's, and
349 * -vv to dump bulk file data.
352 fprintf(stderr
, "freemap: requires device path\n");
357 } else if (strcmp(av
[0], "setcomp") == 0) {
360 * Missing compression method and at least one
364 "setcomp: requires compression method and"
365 "directory/file path\n");
369 * Multiple paths may be specified
371 ecode
= cmd_setcomp(av
[1], &av
[2]);
373 } else if (strcmp(av
[0], "setcheck") == 0) {
376 * Missing compression method and at least one
380 "setcheck: requires check code method and"
381 "directory/file path\n");
385 * Multiple paths may be specified
387 ecode
= cmd_setcheck(av
[1], &av
[2]);
389 } else if (strcmp(av
[0], "clrcheck") == 0) {
390 ecode
= cmd_setcheck("none", &av
[1]);
391 } else if (strcmp(av
[0], "setcrc32") == 0) {
392 ecode
= cmd_setcheck("crc32", &av
[1]);
393 } else if (strcmp(av
[0], "setcrc64") == 0) {
394 ecode
= cmd_setcheck("crc64", &av
[1]);
395 } else if (strcmp(av
[0], "setsha192") == 0) {
396 ecode
= cmd_setcheck("sha192", &av
[1]);
397 } else if (strcmp(av
[0], "printinode") == 0) {
400 "printinode: requires directory/file path\n");
405 } else if (strcmp(av
[0], "bulkfree") == 0) {
408 "bulkfree: requires path to mount\n");
411 ecode
= cmd_bulkfree(av
[1]);
414 fprintf(stderr
, "Unrecognized command: %s\n", av
[0]);
419 * In DebugMode we may wind up starting several pthreads in the
420 * original process, in which case we have to let them run and
427 _exit(2); /* NOT REACHED */
436 "hammer2 [options] command...\n"
437 " -s path Select filesystem\n"
438 " -t type PFS type for pfs-create\n"
439 " -u uuid uuid for pfs-create\n"
443 " disconnect <target> "
446 "Print directory hash\n"
448 "Report cluster status\n"
449 " pfs-list [<path>] "
452 "Print cluster id for specific PFS\n"
454 "Print private id for specific PFS\n"
455 " pfs-create <label> "
457 " pfs-delete <label> "
459 " snapshot <path> [<label>] "
460 "Snapshot a PFS or directory\n"
462 "Start service daemon\n"
464 "Return inode quota & config\n"
466 "Start pfs leaf daemon\n"
468 "Connect to debug shell\n"
469 " debugspan <target> "
470 "Connect to target, run CONN/SPAN\n"
472 "Initialize rsa fields\n"
474 "Raw hammer2 media dump\n"
476 "Raw hammer2 media dump\n"
477 " setcomp comp[:level] path... "
478 "Set comp algo {none, autozero, lz4, zlib} & level\n"
479 " setcheck check path... "
480 "Set check algo {none, crc32, crc64, sha192}\n"
482 "Set check algo to crc32\n"
484 "Set check algo to crc64\n"
485 " setsha192 path... "
486 "Set check algo to sha192\n"
488 "Run bulkfree pass\n"