Commit | Line | Data |
---|---|---|
2910a90c | 1 | /* |
0c41f055 | 2 | * Copyright (c) 2011-2019 The DragonFly Project. All rights reserved. |
2910a90c MD |
3 | * |
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> | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
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 | |
17 | * distribution. | |
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. | |
21 | * | |
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 | |
33 | * SUCH DAMAGE. | |
34 | */ | |
35 | ||
36 | #include "hammer2.h" | |
37 | ||
5ba65e34 | 38 | int DebugOpt; |
bd878fc9 | 39 | int VerboseOpt; |
9b8b748f | 40 | int QuietOpt; |
f481450f | 41 | int ForceOpt; |
8deaf180 TK |
42 | int RecurseOpt; |
43 | int NormalExit = 1; /* if set to 0 main() has to pthread_exit() */ | |
944ddad0 | 44 | size_t MemOpt; |
f481450f MD |
45 | |
46 | static void usage(int code); | |
5ba65e34 | 47 | |
2910a90c MD |
48 | int |
49 | main(int ac, char **av) | |
50 | { | |
cef49084 | 51 | char *sel_path = NULL; |
2910a90c | 52 | const char *uuid_str = NULL; |
62efe6ec | 53 | const char *arg; |
944ddad0 | 54 | char *opt; |
7750fd72 | 55 | int pfs_type = HAMMER2_PFSTYPE_NONE; |
2910a90c MD |
56 | int all_opt = 0; |
57 | int ecode = 0; | |
58 | int ch; | |
59 | ||
62efe6ec | 60 | srandomdev(); |
7dc0f844 | 61 | signal(SIGPIPE, SIG_IGN); |
0c3a8cd0 | 62 | dmsg_crypto_setup(); |
62efe6ec | 63 | |
2910a90c MD |
64 | /* |
65 | * Core options | |
66 | */ | |
8deaf180 | 67 | while ((ch = getopt(ac, av, "adfm:rs:t:u:vq")) != -1) { |
2910a90c MD |
68 | switch(ch) { |
69 | case 'a': | |
70 | all_opt = 1; | |
71 | break; | |
bd878fc9 | 72 | case 'd': |
78b00acd | 73 | if (DebugOpt) |
d157d4dc | 74 | ++DMsgDebugOpt; |
bd878fc9 MD |
75 | DebugOpt = 1; |
76 | break; | |
f481450f MD |
77 | case 'f': |
78 | ForceOpt = 1; | |
79 | break; | |
944ddad0 MD |
80 | case 'm': |
81 | MemOpt = strtoul(optarg, &opt, 0); | |
82 | switch(*opt) { | |
83 | case 'g': | |
84 | case 'G': | |
85 | MemOpt *= 1024; | |
86 | /* FALLTHROUGH */ | |
87 | case 'm': | |
88 | case 'M': | |
89 | MemOpt *= 1024; | |
90 | /* FALLTHROUGH */ | |
91 | case 'k': | |
92 | case 'K': | |
93 | MemOpt *= 1024; | |
94 | break; | |
95 | case 0: | |
96 | break; | |
97 | default: | |
e03500ee | 98 | fprintf(stderr, "-m: Unrecognized suffix\n"); |
944ddad0 MD |
99 | usage(1); |
100 | break; | |
101 | } | |
102 | break; | |
f481450f MD |
103 | case 'r': |
104 | RecurseOpt = 1; | |
105 | break; | |
2910a90c | 106 | case 's': |
cef49084 | 107 | sel_path = strdup(optarg); |
2910a90c MD |
108 | break; |
109 | case 't': | |
110 | /* | |
ee886e77 | 111 | * set node type for pfs-create |
2910a90c | 112 | */ |
afa78c43 | 113 | if (strcasecmp(optarg, "CACHE") == 0) { |
2910a90c | 114 | pfs_type = HAMMER2_PFSTYPE_CACHE; |
b93cc2e0 MD |
115 | } else if (strcasecmp(optarg, "DUMMY") == 0) { |
116 | pfs_type = HAMMER2_PFSTYPE_DUMMY; | |
2910a90c MD |
117 | } else if (strcasecmp(optarg, "SLAVE") == 0) { |
118 | pfs_type = HAMMER2_PFSTYPE_SLAVE; | |
119 | } else if (strcasecmp(optarg, "SOFT_SLAVE") == 0) { | |
120 | pfs_type = HAMMER2_PFSTYPE_SOFT_SLAVE; | |
121 | } else if (strcasecmp(optarg, "SOFT_MASTER") == 0) { | |
122 | pfs_type = HAMMER2_PFSTYPE_SOFT_MASTER; | |
123 | } else if (strcasecmp(optarg, "MASTER") == 0) { | |
124 | pfs_type = HAMMER2_PFSTYPE_MASTER; | |
125 | } else { | |
126 | fprintf(stderr, "-t: Unrecognized node type\n"); | |
127 | usage(1); | |
128 | } | |
129 | break; | |
130 | case 'u': | |
131 | /* | |
ee886e77 | 132 | * set uuid for pfs-create, else one will be generated |
2910a90c MD |
133 | * (required for all except the MASTER node_type) |
134 | */ | |
135 | uuid_str = optarg; | |
136 | break; | |
bd878fc9 | 137 | case 'v': |
9b8b748f MD |
138 | if (QuietOpt) |
139 | --QuietOpt; | |
140 | else | |
141 | ++VerboseOpt; | |
142 | break; | |
143 | case 'q': | |
144 | if (VerboseOpt) | |
145 | --VerboseOpt; | |
146 | else | |
147 | ++QuietOpt; | |
5ba65e34 | 148 | break; |
2910a90c MD |
149 | default: |
150 | fprintf(stderr, "Unknown option: %c\n", ch); | |
151 | usage(1); | |
152 | /* not reached */ | |
153 | break; | |
154 | } | |
155 | } | |
156 | ||
157 | /* | |
158 | * Adjust, then process the command | |
159 | */ | |
160 | ac -= optind; | |
161 | av += optind; | |
162 | if (ac < 1) { | |
163 | fprintf(stderr, "Missing command\n"); | |
164 | usage(1); | |
165 | /* not reached */ | |
166 | } | |
167 | ||
168 | if (strcmp(av[0], "connect") == 0) { | |
169 | /* | |
170 | * Add cluster connection | |
171 | */ | |
172 | if (ac < 2) { | |
173 | fprintf(stderr, "connect: missing argument\n"); | |
174 | usage(1); | |
175 | } | |
176 | ecode = cmd_remote_connect(sel_path, av[1]); | |
40498d1c | 177 | } else if (strcmp(av[0], "dumpchain") == 0) { |
8f579e46 | 178 | if (ac < 2) |
40498d1c MD |
179 | ecode = cmd_dumpchain(".", (u_int)-1); |
180 | else if (ac < 3) | |
181 | ecode = cmd_dumpchain(av[1], (u_int)-1); | |
8f579e46 | 182 | else |
40498d1c MD |
183 | ecode = cmd_dumpchain(av[1], |
184 | (u_int)strtoul(av[2], NULL, 0)); | |
02454b3e MD |
185 | } else if (strcmp(av[0], "debugspan") == 0) { |
186 | /* | |
187 | * Debug connection to the target hammer2 service and run | |
188 | * the CONN/SPAN protocol. | |
189 | */ | |
190 | if (ac < 2) { | |
191 | fprintf(stderr, "debugspan: requires hostname\n"); | |
192 | usage(1); | |
193 | } | |
194 | ecode = cmd_debugspan(av[1]); | |
2910a90c MD |
195 | } else if (strcmp(av[0], "disconnect") == 0) { |
196 | /* | |
197 | * Remove cluster connection | |
198 | */ | |
199 | if (ac < 2) { | |
200 | fprintf(stderr, "disconnect: missing argument\n"); | |
201 | usage(1); | |
202 | } | |
203 | ecode = cmd_remote_disconnect(sel_path, av[1]); | |
f6aebb44 MD |
204 | } else if (strcmp(av[0], "destroy") == 0) { |
205 | if (ac < 2) { | |
206 | fprintf(stderr, | |
e03500ee TK |
207 | "destroy: specify one or more paths to " |
208 | "destroy\n"); | |
a0b6913c | 209 | usage(1); |
f6aebb44 MD |
210 | } |
211 | ecode = cmd_destroy_path(ac - 1, (const char **)(void *)&av[1]); | |
ead47bfa MD |
212 | } else if (strcmp(av[0], "destroy-inum") == 0) { |
213 | if (ac < 2) { | |
214 | fprintf(stderr, | |
e03500ee TK |
215 | "destroy-inum: specify one or more inode " |
216 | "numbers to destroy\n"); | |
a0b6913c | 217 | usage(1); |
ead47bfa | 218 | } |
a0b6913c TK |
219 | ecode = cmd_destroy_inum(sel_path, ac - 1, |
220 | (const char **)(void *)&av[1]); | |
acbbd0ef MD |
221 | } else if (strcmp(av[0], "emergency-mode-enable") == 0) { |
222 | ecode = cmd_emergency_mode(sel_path, 1, ac - 1, | |
223 | (const char **)(void *)&av[1]); | |
224 | } else if (strcmp(av[0], "emergency-mode-disable") == 0) { | |
225 | ecode = cmd_emergency_mode(sel_path, 0, ac - 1, | |
226 | (const char **)(void *)&av[1]); | |
4599d71e MD |
227 | } else if (strcmp(av[0], "growfs") == 0) { |
228 | ecode = cmd_growfs(sel_path, ac - 1, | |
229 | (const char **)(void *)&av[1]); | |
775153c2 MD |
230 | } else if (strcmp(av[0], "hash") == 0) { |
231 | ecode = cmd_hash(ac - 1, (const char **)(void *)&av[1]); | |
0c41f055 MD |
232 | } else if (strcmp(av[0], "dhash") == 0) { |
233 | ecode = cmd_dhash(ac - 1, (const char **)(void *)&av[1]); | |
b92bfd39 MD |
234 | } else if (strcmp(av[0], "info") == 0) { |
235 | ecode = cmd_info(ac - 1, (const char **)(void *)&av[1]); | |
236 | } else if (strcmp(av[0], "mountall") == 0) { | |
237 | ecode = cmd_mountall(ac - 1, (const char **)(void *)&av[1]); | |
2910a90c MD |
238 | } else if (strcmp(av[0], "status") == 0) { |
239 | /* | |
240 | * Get status of PFS and its connections (-a for all PFSs) | |
241 | */ | |
3c198419 MD |
242 | if (ac < 2) { |
243 | ecode = cmd_remote_status(sel_path, all_opt); | |
244 | } else { | |
245 | int i; | |
3c198419 MD |
246 | for (i = 1; i < ac; ++i) |
247 | ecode = cmd_remote_status(av[i], all_opt); | |
248 | } | |
7dc0f844 MD |
249 | } else if (strcmp(av[0], "pfs-clid") == 0) { |
250 | /* | |
251 | * Print cluster id (uuid) for specific PFS | |
252 | */ | |
253 | if (ac < 2) { | |
254 | fprintf(stderr, "pfs-clid: requires name\n"); | |
255 | usage(1); | |
256 | } | |
257 | ecode = cmd_pfs_getid(sel_path, av[1], 0); | |
258 | } else if (strcmp(av[0], "pfs-fsid") == 0) { | |
259 | /* | |
260 | * Print private id (uuid) for specific PFS | |
261 | */ | |
262 | if (ac < 2) { | |
263 | fprintf(stderr, "pfs-fsid: requires name\n"); | |
264 | usage(1); | |
265 | } | |
266 | ecode = cmd_pfs_getid(sel_path, av[1], 1); | |
bd878fc9 | 267 | } else if (strcmp(av[0], "pfs-list") == 0) { |
ae183399 MD |
268 | /* |
269 | * List all PFSs | |
270 | */ | |
b92bfd39 MD |
271 | if (ac >= 2) { |
272 | ecode = cmd_pfs_list(ac - 1, | |
cef49084 | 273 | (char **)(void *)&av[1]); |
b92bfd39 MD |
274 | } else { |
275 | ecode = cmd_pfs_list(1, &sel_path); | |
d0ceb671 | 276 | } |
bd878fc9 | 277 | } else if (strcmp(av[0], "pfs-create") == 0) { |
2910a90c MD |
278 | /* |
279 | * Create new PFS using pfs_type | |
280 | */ | |
ae183399 | 281 | if (ac < 2) { |
bd878fc9 | 282 | fprintf(stderr, "pfs-create: requires name\n"); |
ae183399 MD |
283 | usage(1); |
284 | } | |
285 | ecode = cmd_pfs_create(sel_path, av[1], pfs_type, uuid_str); | |
bd878fc9 | 286 | } else if (strcmp(av[0], "pfs-delete") == 0) { |
ae183399 MD |
287 | /* |
288 | * Delete a PFS by name | |
289 | */ | |
290 | if (ac < 2) { | |
bd878fc9 | 291 | fprintf(stderr, "pfs-delete: requires name\n"); |
ae183399 MD |
292 | usage(1); |
293 | } | |
83d90983 | 294 | ecode = cmd_pfs_delete(sel_path, av, ac); |
f2bb8def TK |
295 | } else if (strcmp(av[0], "recover") == 0 || |
296 | strcmp(av[0], "recover-relaxed") == 0 || | |
297 | strcmp(av[0], "recover-file") == 0) | |
298 | { | |
299 | /* | |
300 | * Recover a relative path (unanchored match), absolute path, | |
301 | * specific file, or directory sub-tree. File restorals are | |
302 | * fully validated. | |
303 | */ | |
304 | if (ac != 4) { | |
305 | fprintf(stderr, "recover device [/]path destdir\n"); | |
306 | usage(1); | |
307 | } else { | |
308 | int strict = (strcmp(av[0], "recover-relaxed") != 0); | |
309 | int isafile = (strcmp(av[0], "recover-file") == 0); | |
310 | cmd_recover(av[1], av[2], av[3], strict, isafile); | |
311 | } | |
54796644 MD |
312 | } else if (strcmp(av[0], "snapshot") == 0 || |
313 | strcmp(av[0], "snapshot-debug") == 0) { | |
2910a90c | 314 | /* |
bd878fc9 | 315 | * Create snapshot with optional pfs-type and optional |
2910a90c MD |
316 | * label override. |
317 | */ | |
54796644 MD |
318 | uint32_t flags = 0; |
319 | ||
320 | if (strcmp(av[0], "snapshot-debug") == 0) | |
321 | flags = HAMMER2_PFSFLAGS_NOSYNC; | |
322 | ||
d0ceb671 | 323 | if (ac > 3) { |
e03500ee | 324 | fprintf(stderr, "%s: too many arguments\n", av[0]); |
87b1094e MD |
325 | usage(1); |
326 | } | |
d0ceb671 MD |
327 | switch(ac) { |
328 | case 1: | |
54796644 | 329 | ecode = cmd_pfs_snapshot(sel_path, NULL, NULL, flags); |
d0ceb671 MD |
330 | break; |
331 | case 2: | |
54796644 | 332 | ecode = cmd_pfs_snapshot(sel_path, av[1], NULL, flags); |
d0ceb671 MD |
333 | break; |
334 | case 3: | |
54796644 | 335 | ecode = cmd_pfs_snapshot(sel_path, av[1], av[2], flags); |
d0ceb671 MD |
336 | break; |
337 | } | |
62efe6ec | 338 | } else if (strcmp(av[0], "service") == 0) { |
2910a90c | 339 | /* |
62efe6ec MD |
340 | * Start the service daemon. This daemon accepts |
341 | * connections from local and remote clients, handles | |
342 | * the security handshake, and manages the core messaging | |
343 | * protocol. | |
2910a90c | 344 | */ |
62efe6ec | 345 | ecode = cmd_service(); |
ad7cf8ea | 346 | } else if (strcmp(av[0], "stat") == 0) { |
a1b07447 | 347 | ecode = cmd_stat(ac - 1, (const char **)(void *)&av[1]); |
9ab15106 MD |
348 | } else if (strcmp(av[0], "leaf") == 0) { |
349 | /* | |
350 | * Start the management daemon for a specific PFS. | |
351 | * | |
352 | * This will typically connect to the local master node | |
353 | * daemon, register the PFS, and then pass its side of | |
354 | * the socket descriptor to the kernel HAMMER2 VFS via an | |
355 | * ioctl(). The process and/or thread context remains in the | |
356 | * kernel until the PFS is unmounted or the connection is | |
357 | * lost, then returns from the ioctl. | |
358 | * | |
359 | * It is possible to connect directly to a remote master node | |
360 | * instead of the local master node in situations where | |
361 | * encryption is not desired or no local master node is | |
362 | * desired. This is not recommended because it represents | |
363 | * a single point of failure for the PFS's communications. | |
364 | * | |
365 | * Direct kernel<->kernel communication between HAMMER2 VFSs | |
366 | * is theoretically possible for directly-connected | |
367 | * registrations (i.e. where the spanning tree is degenerate), | |
368 | * but not recommended. We specifically try to reduce the | |
369 | * complexity of the HAMMER2 VFS kernel code. | |
370 | */ | |
371 | ecode = cmd_leaf(sel_path); | |
bd878fc9 | 372 | } else if (strcmp(av[0], "shell") == 0) { |
9ab15106 MD |
373 | /* |
374 | * Connect to the command line monitor in the hammer2 master | |
375 | * node for the machine using HAMMER2_DBG_SHELL messages. | |
376 | */ | |
bd878fc9 | 377 | ecode = cmd_shell((ac < 2) ? NULL : av[1]); |
62efe6ec MD |
378 | } else if (strcmp(av[0], "rsainit") == 0) { |
379 | /* | |
380 | * Initialize a RSA keypair. If no target directory is | |
381 | * specified we default to "/etc/hammer2". | |
382 | */ | |
383 | arg = (ac < 2) ? HAMMER2_DEFAULT_DIR : av[1]; | |
384 | ecode = cmd_rsainit(arg); | |
385 | } else if (strcmp(av[0], "rsaenc") == 0) { | |
386 | /* | |
387 | * Encrypt the input symmetrically by running it through | |
388 | * the specified public and/or private key files. | |
389 | * | |
390 | * If no key files are specified data is encoded using | |
391 | * "/etc/hammer2/rsa.pub". | |
392 | * | |
393 | * WARNING: no padding is added, data stream must contain | |
394 | * random padding for this to be secure. | |
395 | * | |
396 | * Used for debugging only | |
397 | */ | |
398 | if (ac == 1) { | |
399 | const char *rsapath = HAMMER2_DEFAULT_DIR "/rsa.pub"; | |
400 | ecode = cmd_rsaenc(&rsapath, 1); | |
401 | } else { | |
a1b07447 MD |
402 | ecode = cmd_rsaenc((const char **)(void *)&av[1], |
403 | ac - 1); | |
62efe6ec MD |
404 | } |
405 | } else if (strcmp(av[0], "rsadec") == 0) { | |
406 | /* | |
407 | * Decrypt the input symmetrically by running it through | |
408 | * the specified public and/or private key files. | |
409 | * | |
410 | * If no key files are specified data is decoded using | |
411 | * "/etc/hammer2/rsa.prv". | |
412 | * | |
413 | * WARNING: no padding is added, data stream must contain | |
414 | * random padding for this to be secure. | |
415 | * | |
416 | * Used for debugging only | |
417 | */ | |
418 | if (ac == 1) { | |
419 | const char *rsapath = HAMMER2_DEFAULT_DIR "/rsa.prv"; | |
420 | ecode = cmd_rsadec(&rsapath, 1); | |
421 | } else { | |
a1b07447 MD |
422 | ecode = cmd_rsadec((const char **)(void *)&av[1], |
423 | ac - 1); | |
62efe6ec | 424 | } |
bd878fc9 MD |
425 | } else if (strcmp(av[0], "show") == 0) { |
426 | /* | |
427 | * Raw dump of filesystem. Use -v to check all crc's, and | |
428 | * -vv to dump bulk file data. | |
429 | */ | |
430 | if (ac != 2) { | |
431 | fprintf(stderr, "show: requires device path\n"); | |
432 | usage(1); | |
433 | } else { | |
78ac5385 MD |
434 | cmd_show(av[1], 0); |
435 | } | |
436 | } else if (strcmp(av[0], "freemap") == 0) { | |
437 | /* | |
438 | * Raw dump of freemap. Use -v to check all crc's, and | |
439 | * -vv to dump bulk file data. | |
440 | */ | |
441 | if (ac != 2) { | |
442 | fprintf(stderr, "freemap: requires device path\n"); | |
443 | usage(1); | |
444 | } else { | |
445 | cmd_show(av[1], 1); | |
bd878fc9 | 446 | } |
5cf632c7 TK |
447 | } else if (strcmp(av[0], "volhdr") == 0) { |
448 | /* | |
449 | * Dump the volume header. | |
450 | */ | |
451 | if (ac != 2) { | |
452 | fprintf(stderr, "volhdr: requires device path\n"); | |
453 | usage(1); | |
454 | } else { | |
455 | cmd_show(av[1], 2); | |
456 | } | |
0b738157 TK |
457 | } else if (strcmp(av[0], "volume-list") == 0) { |
458 | /* | |
459 | * List all volumes | |
460 | */ | |
461 | if (ac >= 2) { | |
462 | ecode = cmd_volume_list(ac - 1, | |
463 | (char **)(void *)&av[1]); | |
464 | } else { | |
465 | ecode = cmd_volume_list(1, &sel_path); | |
466 | } | |
355d67fc | 467 | } else if (strcmp(av[0], "setcomp") == 0) { |
f481450f MD |
468 | if (ac < 3) { |
469 | /* | |
470 | * Missing compression method and at least one | |
471 | * path. | |
472 | */ | |
473 | fprintf(stderr, | |
e03500ee | 474 | "setcomp: requires compression method and " |
355d67fc MD |
475 | "directory/file path\n"); |
476 | usage(1); | |
477 | } else { | |
f481450f MD |
478 | /* |
479 | * Multiple paths may be specified | |
480 | */ | |
481 | ecode = cmd_setcomp(av[1], &av[2]); | |
355d67fc | 482 | } |
8adee7de MD |
483 | } else if (strcmp(av[0], "setcheck") == 0) { |
484 | if (ac < 3) { | |
485 | /* | |
486 | * Missing compression method and at least one | |
487 | * path. | |
488 | */ | |
489 | fprintf(stderr, | |
e03500ee | 490 | "setcheck: requires check code method and " |
8adee7de MD |
491 | "directory/file path\n"); |
492 | usage(1); | |
493 | } else { | |
494 | /* | |
495 | * Multiple paths may be specified | |
496 | */ | |
497 | ecode = cmd_setcheck(av[1], &av[2]); | |
498 | } | |
499 | } else if (strcmp(av[0], "clrcheck") == 0) { | |
500 | ecode = cmd_setcheck("none", &av[1]); | |
501 | } else if (strcmp(av[0], "setcrc32") == 0) { | |
502 | ecode = cmd_setcheck("crc32", &av[1]); | |
b83c55fc MD |
503 | } else if (strcmp(av[0], "setxxhash64") == 0) { |
504 | ecode = cmd_setcheck("xxhash64", &av[1]); | |
8adee7de MD |
505 | } else if (strcmp(av[0], "setsha192") == 0) { |
506 | ecode = cmd_setcheck("sha192", &av[1]); | |
355d67fc MD |
507 | } else if (strcmp(av[0], "printinode") == 0) { |
508 | if (ac != 2) { | |
f481450f MD |
509 | fprintf(stderr, |
510 | "printinode: requires directory/file path\n"); | |
355d67fc | 511 | usage(1); |
00261fe0 | 512 | } else { |
355d67fc | 513 | print_inode(av[1]); |
00261fe0 MD |
514 | } |
515 | } else if (strcmp(av[0], "bulkfree") == 0) { | |
516 | if (ac != 2) { | |
e03500ee | 517 | fprintf(stderr, "bulkfree: requires path to mount\n"); |
00261fe0 MD |
518 | usage(1); |
519 | } else { | |
520 | ecode = cmd_bulkfree(av[1]); | |
521 | } | |
b83c55fc | 522 | #if 0 |
9dca9515 MD |
523 | } else if (strcmp(av[0], "bulkfree-async") == 0) { |
524 | if (ac != 2) { | |
525 | fprintf(stderr, | |
526 | "bulkfree-async: requires path to mount\n"); | |
527 | usage(1); | |
528 | } else { | |
529 | ecode = cmd_bulkfree_async(av[1]); | |
530 | } | |
b83c55fc | 531 | #endif |
30ce27d4 MD |
532 | } else if (strcmp(av[0], "cleanup") == 0) { |
533 | ecode = cmd_cleanup(av[1]); /* can be NULL */ | |
2910a90c MD |
534 | } else { |
535 | fprintf(stderr, "Unrecognized command: %s\n", av[0]); | |
536 | usage(1); | |
537 | } | |
5ba65e34 MD |
538 | |
539 | /* | |
540 | * In DebugMode we may wind up starting several pthreads in the | |
541 | * original process, in which case we have to let them run and | |
542 | * not actually exit. | |
543 | */ | |
544 | if (NormalExit) { | |
545 | return (ecode); | |
546 | } else { | |
547 | pthread_exit(NULL); | |
548 | _exit(2); /* NOT REACHED */ | |
549 | } | |
2910a90c MD |
550 | } |
551 | ||
552 | static | |
553 | void | |
554 | usage(int code) | |
555 | { | |
556 | fprintf(stderr, | |
d371ccd2 | 557 | "hammer2 [options] command [argument ...]\n" |
2910a90c | 558 | " -s path Select filesystem\n" |
bd878fc9 MD |
559 | " -t type PFS type for pfs-create\n" |
560 | " -u uuid uuid for pfs-create\n" | |
d371ccd2 | 561 | " -m mem[k,m,g] buffer memory (bulkfree)\n" |
bd878fc9 | 562 | "\n" |
f16e1562 | 563 | " cleanup [<path>] " |
4aedc17b | 564 | "Run cleanup passes\n" |
f16e1562 | 565 | " connect <target> " |
f481450f | 566 | "Add cluster link\n" |
f16e1562 | 567 | " destroy <path>... " |
ead47bfa | 568 | "Destroy directory entries (only use if inode bad)\n" |
f16e1562 | 569 | " destroy-inum <inum>... " |
ead47bfa | 570 | "Destroy inodes (only use if inode bad)\n" |
f16e1562 | 571 | " disconnect <target> " |
f481450f | 572 | "Del cluster link\n" |
acbbd0ef MD |
573 | " emergency-mode-enable <target> " |
574 | "Enable emergency operations mode on filesystem\n" | |
575 | " " | |
576 | "THIS IS A VERY DANGEROUS MODE\n" | |
1e790cd2 | 577 | " emergency-mode-disable <target> " |
acbbd0ef | 578 | "Disable emergency operations mode on filesystem\n" |
f16e1562 | 579 | " info [<devpath>...] " |
b92bfd39 | 580 | "Info on all offline or online H2 partitions\n" |
f16e1562 | 581 | " mountall [<devpath>...] " |
b92bfd39 | 582 | "Mount @LOCAL for all H2 partitions\n" |
f16e1562 | 583 | " status [<path>...] " |
b92bfd39 | 584 | "Report active cluster status\n" |
f16e1562 | 585 | " hash [<filename>...] " |
d371ccd2 | 586 | "Print directory hash (key) for name\n" |
f16e1562 | 587 | " dhash [<filename>...] " |
d371ccd2 | 588 | "Print data hash for long directory entry\n" |
f16e1562 | 589 | " pfs-list [<path>...] " |
f481450f | 590 | "List PFSs\n" |
f16e1562 | 591 | " pfs-clid <label> " |
f481450f | 592 | "Print cluster id for specific PFS\n" |
f16e1562 | 593 | " pfs-fsid <label> " |
f481450f | 594 | "Print private id for specific PFS\n" |
f16e1562 | 595 | " pfs-create <label> " |
f481450f | 596 | "Create a PFS\n" |
f16e1562 | 597 | " pfs-delete <label> " |
f481450f | 598 | "Destroy a PFS\n" |
5627cde5 MD |
599 | " recover <devpath> <path> <destdir> " |
600 | "Recover deleted or corrupt files or trees\n" | |
ddc249f6 MD |
601 | " recover-relaxed <devpath> <path> <destdir> " |
602 | "Recover deleted or corrupt files or trees\n" | |
603 | " recover-file <devpath> <path> <destdir> " | |
604 | "Recover, target is explicitly a regular file\n" | |
f16e1562 | 605 | " snapshot <path> [<label>] " |
d0ceb671 | 606 | "Snapshot a PFS or directory\n" |
f16e1562 | 607 | " snapshot-debug <path> [<label>] " |
54796644 | 608 | "Snapshot without filesystem sync\n" |
f16e1562 | 609 | " service " |
f481450f | 610 | "Start service daemon\n" |
f16e1562 | 611 | " stat [<path>...] " |
f481450f | 612 | "Return inode quota & config\n" |
f16e1562 | 613 | " leaf " |
f481450f | 614 | "Start pfs leaf daemon\n" |
f16e1562 | 615 | " shell [<host>] " |
f481450f | 616 | "Connect to debug shell\n" |
f16e1562 | 617 | " debugspan <target> " |
f481450f | 618 | "Connect to target, run CONN/SPAN\n" |
4599d71e MD |
619 | " growfs [<path...] " |
620 | "Grow a filesystem into resized partition\n" | |
f16e1562 | 621 | " rsainit [<path>] " |
f481450f | 622 | "Initialize rsa fields\n" |
f16e1562 | 623 | " show <devpath> " |
d371ccd2 | 624 | "Raw hammer2 media dump for topology\n" |
f16e1562 | 625 | " freemap <devpath> " |
d371ccd2 | 626 | "Raw hammer2 media dump for freemap\n" |
5cf632c7 | 627 | " volhdr <devpath> " |
aa2131f0 | 628 | "Raw hammer2 media dump for the volume header(s)\n" |
0b738157 TK |
629 | " volume-list [<path>...] " |
630 | "List volumes\n" | |
f16e1562 | 631 | " setcomp <comp[:level]> <path>... " |
8adee7de | 632 | "Set comp algo {none, autozero, lz4, zlib} & level\n" |
f16e1562 | 633 | " setcheck <check> <path>... " |
b83c55fc | 634 | "Set check algo {none, crc32, xxhash64, sha192}\n" |
f16e1562 | 635 | " clrcheck [<path>...] " |
3c198419 | 636 | "Clear check code override\n" |
f16e1562 | 637 | " setcrc32 [<path>...] " |
8adee7de | 638 | "Set check algo to crc32\n" |
f16e1562 | 639 | " setxxhash64 [<path>...] " |
b83c55fc | 640 | "Set check algo to xxhash64\n" |
f16e1562 | 641 | " setsha192 [<path>...] " |
8adee7de | 642 | "Set check algo to sha192\n" |
f16e1562 | 643 | " bulkfree <path> " |
00261fe0 | 644 | "Run bulkfree pass\n" |
f16e1562 | 645 | " printinode <path> " |
d371ccd2 | 646 | "Dump inode\n" |
f16e1562 | 647 | " dumpchain [<path> [<chnflags>]] " |
d371ccd2 | 648 | "Dump in-memory chain topology (ONFLUSH flag is 0x200)\n" |
b83c55fc | 649 | #if 0 |
f16e1562 | 650 | " bulkfree-async path " |
9dca9515 | 651 | "Run bulkfree pass asynchronously\n" |
b83c55fc | 652 | #endif |
2910a90c MD |
653 | ); |
654 | exit(code); | |
655 | } |