Commit | Line | Data |
---|---|---|
9ab15106 MD |
1 | /* |
2 | * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved. | |
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 | ||
bc8f6505 TK |
38 | #include <openssl/sha.h> |
39 | ||
aa2131f0 | 40 | #define GIG (1024LL*1024*1024) |
aa2131f0 | 41 | |
d490438f | 42 | static int show_all_volume_headers = 0; |
8ca87c4c | 43 | static int show_tab = 2; |
91e93d9f | 44 | static int show_depth = -1; |
71782ce3 TK |
45 | static hammer2_tid_t show_min_mirror_tid = 0; |
46 | static hammer2_tid_t show_min_modify_tid = 0; | |
bd878fc9 | 47 | |
1b8eded1 | 48 | static void shell_msghandler(dmsg_msg_t *msg, int unmanaged); |
0c3a8cd0 | 49 | static void shell_ttymsg(dmsg_iocom_t *iocom); |
6c129444 | 50 | static void count_blocks(hammer2_bmap_data_t *bmap, int value, |
5c37bf12 | 51 | hammer2_off_t *accum16, hammer2_off_t *accum64); |
bd878fc9 MD |
52 | |
53 | /************************************************************************ | |
54 | * SHELL * | |
55 | ************************************************************************/ | |
9ab15106 | 56 | |
1b8eded1 MD |
57 | int |
58 | cmd_shell(const char *hostname) | |
59 | { | |
60 | dmsg_master_service_info_t *info; | |
61 | pthread_t thread; | |
62 | int fd; | |
63 | ||
64 | fd = dmsg_connect(hostname); | |
65 | if (fd < 0) | |
66 | return 1; | |
67 | ||
68 | info = malloc(sizeof(*info)); | |
69 | bzero(info, sizeof(*info)); | |
70 | info->fd = fd; | |
71 | info->detachme = 0; | |
72 | info->usrmsg_callback = shell_msghandler; | |
73 | info->altmsg_callback = shell_ttymsg; | |
1b8eded1 MD |
74 | info->label = strdup("debug"); |
75 | pthread_create(&thread, NULL, dmsg_master_service, info); | |
76 | pthread_join(thread, NULL); | |
77 | ||
78 | return 0; | |
79 | } | |
80 | ||
81 | #if 0 | |
9ab15106 | 82 | int |
bd878fc9 | 83 | cmd_shell(const char *hostname) |
9ab15106 | 84 | { |
0c3a8cd0 MD |
85 | struct dmsg_iocom iocom; |
86 | dmsg_msg_t *msg; | |
9ab15106 MD |
87 | int fd; |
88 | ||
9ab15106 MD |
89 | /* |
90 | * Connect to the target | |
91 | */ | |
0c3a8cd0 | 92 | fd = dmsg_connect(hostname); |
02454b3e MD |
93 | if (fd < 0) |
94 | return 1; | |
9ab15106 MD |
95 | |
96 | /* | |
1b8eded1 MD |
97 | * Initialize the session and transmit an empty DMSG_DBG_SHELL |
98 | * to cause the remote end to generate a prompt. | |
9ab15106 | 99 | */ |
11f7caf4 MD |
100 | dmsg_iocom_init(&iocom, fd, 0, |
101 | NULL, | |
102 | shell_rcvmsg, | |
103 | hammer2_shell_parse, | |
104 | shell_ttymsg); | |
02454b3e | 105 | fcntl(0, F_SETFL, O_NONBLOCK); |
9ab15106 MD |
106 | printf("debug: connected\n"); |
107 | ||
1b8eded1 | 108 | msg = dmsg_msg_alloc(&iocom.state0, 0, DMSG_DBG_SHELL, NULL, NULL); |
0c3a8cd0 MD |
109 | dmsg_msg_write(msg); |
110 | dmsg_iocom_core(&iocom); | |
9ab15106 MD |
111 | fprintf(stderr, "debug: disconnected\n"); |
112 | close(fd); | |
113 | return 0; | |
114 | } | |
1b8eded1 | 115 | #endif |
9ab15106 MD |
116 | |
117 | /* | |
1b8eded1 MD |
118 | * Debug session front-end |
119 | * | |
0c3a8cd0 | 120 | * Callback from dmsg_iocom_core() when messages might be present |
9ab15106 MD |
121 | * on the socket. |
122 | */ | |
123 | static | |
124 | void | |
1b8eded1 | 125 | shell_msghandler(dmsg_msg_t *msg, int unmanaged) |
9ab15106 | 126 | { |
1b8eded1 MD |
127 | dmsg_msg_t *nmsg; |
128 | ||
063639ba | 129 | switch(msg->tcmd) { |
1b8eded1 | 130 | #if 0 |
5bc5bca2 MD |
131 | case DMSG_LNK_ERROR: |
132 | case DMSG_LNK_ERROR | DMSGF_REPLY: | |
81666e1b MD |
133 | /* |
134 | * One-way non-transactional LNK_ERROR messages typically | |
135 | * indicate a connection failure. Error code 0 is used by | |
136 | * the debug shell to indicate no more results from last cmd. | |
137 | */ | |
5903497c | 138 | if (msg->any.head.error) { |
81666e1b | 139 | fprintf(stderr, "Stream failure: %s\n", |
0c3a8cd0 | 140 | dmsg_msg_str(msg)); |
5903497c MD |
141 | } else { |
142 | write(1, "debug> ", 7); | |
9ab15106 | 143 | } |
5903497c | 144 | break; |
5bc5bca2 | 145 | case DMSG_LNK_ERROR | DMSGF_DELETE: |
81666e1b MD |
146 | /* ignore termination of LNK_CONN */ |
147 | break; | |
1b8eded1 | 148 | #endif |
5bc5bca2 | 149 | case DMSG_DBG_SHELL: |
5903497c MD |
150 | /* |
151 | * We send the commands, not accept them. | |
81666e1b | 152 | * (one-way message, not transactional) |
5903497c | 153 | */ |
1b8eded1 MD |
154 | if (unmanaged) |
155 | dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); | |
5903497c | 156 | break; |
5bc5bca2 | 157 | case DMSG_DBG_SHELL | DMSGF_REPLY: |
5903497c MD |
158 | /* |
159 | * A reply from the remote is data we copy to stdout. | |
81666e1b | 160 | * (one-way message, not transactional) |
5903497c MD |
161 | */ |
162 | if (msg->aux_size) { | |
163 | msg->aux_data[msg->aux_size - 1] = 0; | |
164 | write(1, msg->aux_data, strlen(msg->aux_data)); | |
165 | } | |
166 | break; | |
1b8eded1 | 167 | #if 1 |
5bc5bca2 | 168 | case DMSG_LNK_CONN | DMSGF_CREATE: |
1b8eded1 MD |
169 | fprintf(stderr, "Debug Shell received LNK_CONN\n"); |
170 | nmsg = dmsg_msg_alloc(&msg->state->iocom->state0, 0, | |
171 | DMSG_DBG_SHELL, | |
172 | NULL, NULL); | |
173 | dmsg_msg_write(nmsg); | |
0c3a8cd0 | 174 | dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); |
81666e1b | 175 | break; |
5bc5bca2 | 176 | case DMSG_LNK_CONN | DMSGF_DELETE: |
81666e1b | 177 | break; |
1b8eded1 | 178 | #endif |
5903497c | 179 | default: |
81666e1b MD |
180 | /* |
181 | * Ignore any unknown messages, Terminate any unknown | |
182 | * transactions with an error. | |
183 | */ | |
0c3a8cd0 | 184 | fprintf(stderr, "Unknown message: %s\n", dmsg_msg_str(msg)); |
1b8eded1 MD |
185 | if (unmanaged) { |
186 | if (msg->any.head.cmd & DMSGF_CREATE) | |
187 | dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); | |
188 | if (msg->any.head.cmd & DMSGF_DELETE) | |
189 | dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); | |
190 | } | |
5903497c | 191 | break; |
9ab15106 MD |
192 | } |
193 | } | |
194 | ||
1b8eded1 MD |
195 | /* |
196 | * Debug session front-end | |
197 | */ | |
9ab15106 MD |
198 | static |
199 | void | |
0c3a8cd0 | 200 | shell_ttymsg(dmsg_iocom_t *iocom) |
9ab15106 | 201 | { |
1b8eded1 | 202 | dmsg_state_t *pstate; |
0c3a8cd0 | 203 | dmsg_msg_t *msg; |
9ab15106 | 204 | char buf[256]; |
1b8eded1 | 205 | char *cmd; |
9ab15106 MD |
206 | size_t len; |
207 | ||
208 | if (fgets(buf, sizeof(buf), stdin) != NULL) { | |
1b8eded1 MD |
209 | if (buf[0] == '@') { |
210 | pstate = dmsg_findspan(strtok(buf + 1, " \t\n")); | |
211 | cmd = strtok(NULL, "\n"); | |
212 | } else { | |
213 | pstate = &iocom->state0; | |
214 | cmd = strtok(buf, "\n"); | |
215 | } | |
216 | if (cmd && pstate) { | |
217 | len = strlen(cmd) + 1; | |
218 | msg = dmsg_msg_alloc(pstate, len, DMSG_DBG_SHELL, | |
219 | NULL, NULL); | |
220 | bcopy(cmd, msg->aux_data, len); | |
221 | dmsg_msg_write(msg); | |
222 | } else if (cmd) { | |
223 | fprintf(stderr, "@msgid not found\n"); | |
224 | } else { | |
225 | /* | |
226 | * This should cause the remote end to generate | |
227 | * a debug> prompt (and thus shows that there is | |
228 | * connectivity). | |
229 | */ | |
230 | msg = dmsg_msg_alloc(pstate, 0, DMSG_DBG_SHELL, | |
231 | NULL, NULL); | |
232 | dmsg_msg_write(msg); | |
233 | } | |
02454b3e | 234 | } else if (feof(stdin)) { |
9ab15106 MD |
235 | /* |
236 | * Set EOF flag without setting any error code for normal | |
237 | * EOF. | |
238 | */ | |
0c3a8cd0 | 239 | iocom->flags |= DMSG_IOCOMF_EOF; |
02454b3e MD |
240 | } else { |
241 | clearerr(stdin); | |
9ab15106 MD |
242 | } |
243 | } | |
244 | ||
1b8eded1 MD |
245 | /* |
246 | * Debug session back-end (on remote side) | |
247 | */ | |
248 | static void shell_span(dmsg_msg_t *msg, char *cmdbuf); | |
5ab1caed | 249 | static void shell_ping(dmsg_msg_t *msg, char *cmdbuf); |
81666e1b | 250 | |
11f7caf4 | 251 | void |
b53e7c4f | 252 | hammer2_shell_parse(dmsg_msg_t *msg, int unmanaged) |
9ab15106 | 253 | { |
1b8eded1 | 254 | dmsg_iocom_t *iocom = msg->state->iocom; |
b53e7c4f MD |
255 | char *cmdbuf; |
256 | char *cmdp; | |
257 | uint32_t cmd; | |
9ab15106 | 258 | |
b53e7c4f | 259 | /* |
5ab1caed | 260 | * Filter on debug shell commands and ping responses only |
b53e7c4f MD |
261 | */ |
262 | cmd = msg->any.head.cmd; | |
5ab1caed MD |
263 | if ((cmd & DMSGF_CMDSWMASK) == (DMSG_LNK_PING | DMSGF_REPLY)) { |
264 | dmsg_printf(iocom, "ping reply\n"); | |
265 | return; | |
266 | } | |
267 | ||
b53e7c4f MD |
268 | if ((cmd & DMSGF_PROTOS) != DMSG_PROTO_DBG) { |
269 | if (unmanaged) | |
270 | dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); | |
271 | return; | |
272 | } | |
273 | if ((cmd & DMSGF_CMDSWMASK) != DMSG_DBG_SHELL) { | |
274 | if (unmanaged) | |
275 | dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); | |
276 | return; | |
277 | } | |
278 | ||
279 | /* | |
280 | * Debug shell command | |
281 | */ | |
b53e7c4f MD |
282 | cmdbuf = msg->aux_data; |
283 | cmdp = strsep(&cmdbuf, " \t"); | |
284 | ||
285 | if (cmdp == NULL || *cmdp == 0) { | |
9ab15106 | 286 | ; |
5ab1caed MD |
287 | } else if (strcmp(cmdp, "ping") == 0) { |
288 | shell_ping(msg, cmdbuf); | |
b53e7c4f | 289 | } else if (strcmp(cmdp, "span") == 0) { |
1b8eded1 | 290 | shell_span(msg, cmdbuf); |
b53e7c4f | 291 | } else if (strcmp(cmdp, "tree") == 0) { |
1b8eded1 | 292 | dmsg_shell_tree(iocom, cmdbuf); /* dump spanning tree */ |
b53e7c4f | 293 | } else if (strcmp(cmdp, "help") == 0 || strcmp(cmdp, "?") == 0) { |
1b8eded1 MD |
294 | dmsg_printf(iocom, "help Command help\n"); |
295 | dmsg_printf(iocom, "span <host> Span to target host\n"); | |
296 | dmsg_printf(iocom, "tree Dump spanning tree\n"); | |
297 | dmsg_printf(iocom, "@span <cmd> Issue via circuit\n"); | |
81666e1b | 298 | } else { |
1b8eded1 | 299 | dmsg_printf(iocom, "Unrecognized command: %s\n", cmdp); |
81666e1b | 300 | } |
1b8eded1 | 301 | dmsg_printf(iocom, "debug> "); |
81666e1b | 302 | } |
02454b3e | 303 | |
5ab1caed MD |
304 | static void |
305 | shell_ping(dmsg_msg_t *msg, char *cmdbuf __unused) | |
306 | { | |
307 | dmsg_iocom_t *iocom = msg->state->iocom; | |
308 | dmsg_msg_t *m2; | |
309 | ||
310 | dmsg_printf(iocom, "sending ping\n"); | |
311 | m2 = dmsg_msg_alloc(msg->state, 0, DMSG_LNK_PING, NULL, NULL); | |
312 | dmsg_msg_write(m2); | |
313 | } | |
314 | ||
81666e1b | 315 | static void |
1b8eded1 | 316 | shell_span(dmsg_msg_t *msg, char *cmdbuf) |
81666e1b | 317 | { |
1b8eded1 | 318 | dmsg_iocom_t *iocom = msg->state->iocom; |
ddfbb283 | 319 | dmsg_master_service_info_t *info; |
81666e1b MD |
320 | const char *hostname = strsep(&cmdbuf, " \t"); |
321 | pthread_t thread; | |
322 | int fd; | |
02454b3e | 323 | |
81666e1b MD |
324 | /* |
325 | * Connect to the target | |
326 | */ | |
327 | if (hostname == NULL) { | |
328 | fd = -1; | |
329 | } else { | |
0c3a8cd0 | 330 | fd = dmsg_connect(hostname); |
81666e1b MD |
331 | } |
332 | ||
333 | /* | |
334 | * Start master service | |
335 | */ | |
336 | if (fd < 0) { | |
1b8eded1 | 337 | dmsg_printf(iocom, "Connection to %s failed\n", hostname); |
9ab15106 | 338 | } else { |
1b8eded1 | 339 | dmsg_printf(iocom, "Connected to %s\n", hostname); |
ddfbb283 MD |
340 | |
341 | info = malloc(sizeof(*info)); | |
342 | bzero(info, sizeof(*info)); | |
343 | info->fd = fd; | |
344 | info->detachme = 1; | |
b53e7c4f | 345 | info->usrmsg_callback = hammer2_shell_parse; |
c3711753 | 346 | info->label = strdup("client"); |
ddfbb283 MD |
347 | |
348 | pthread_create(&thread, NULL, dmsg_master_service, info); | |
81666e1b | 349 | /*pthread_join(thread, &res);*/ |
9ab15106 MD |
350 | } |
351 | } | |
352 | ||
02454b3e MD |
353 | /************************************************************************ |
354 | * DEBUGSPAN * | |
355 | ************************************************************************ | |
356 | * | |
357 | * Connect to the target manually (not via the cluster list embedded in | |
358 | * a hammer2 filesystem) and initiate the SPAN protocol. | |
359 | */ | |
360 | int | |
361 | cmd_debugspan(const char *hostname) | |
362 | { | |
363 | pthread_t thread; | |
364 | int fd; | |
365 | void *res; | |
366 | ||
367 | /* | |
368 | * Connect to the target | |
369 | */ | |
0c3a8cd0 | 370 | fd = dmsg_connect(hostname); |
02454b3e MD |
371 | if (fd < 0) |
372 | return 1; | |
373 | ||
374 | printf("debugspan: connected to %s, starting CONN/SPAN\n", hostname); | |
0c3a8cd0 MD |
375 | pthread_create(&thread, NULL, |
376 | dmsg_master_service, (void *)(intptr_t)fd); | |
02454b3e MD |
377 | pthread_join(thread, &res); |
378 | return(0); | |
379 | } | |
380 | ||
bd878fc9 MD |
381 | /************************************************************************ |
382 | * SHOW * | |
383 | ************************************************************************/ | |
384 | ||
0b738157 TK |
385 | static void show_volhdr(hammer2_volume_data_t *voldata, int bi); |
386 | static void show_bref(hammer2_volume_data_t *voldata, int tab, | |
dc709019 | 387 | int bi, hammer2_blockref_t *bref, int norecurse); |
bd878fc9 MD |
388 | static void tabprintf(int tab, const char *ctl, ...); |
389 | ||
ce550745 TK |
390 | static hammer2_off_t TotalAccum16[4]; /* includes TotalAccum64 */ |
391 | static hammer2_off_t TotalAccum64[4]; | |
392 | static hammer2_off_t TotalUnavail; | |
393 | static hammer2_off_t TotalFreemap; | |
5c37bf12 | 394 | |
0b738157 TK |
395 | static |
396 | hammer2_off_t | |
397 | get_next_volume(hammer2_volume_data_t *voldata, hammer2_off_t volu_loff) | |
398 | { | |
399 | hammer2_off_t ret = -1; | |
400 | int i; | |
401 | ||
402 | for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { | |
403 | hammer2_off_t tmp = voldata->volu_loff[i]; | |
404 | if (tmp > volu_loff) { | |
405 | ret = tmp; | |
406 | break; | |
407 | } | |
408 | } | |
409 | return ret; | |
410 | } | |
411 | ||
bd878fc9 | 412 | int |
aa2131f0 | 413 | cmd_show(const char *devpath, int which) |
bd878fc9 MD |
414 | { |
415 | hammer2_blockref_t broot; | |
351eb452 MD |
416 | hammer2_blockref_t best; |
417 | hammer2_media_data_t media; | |
aa2131f0 | 418 | hammer2_media_data_t best_media; |
0b738157 | 419 | hammer2_off_t off, volu_loff, next_volu_loff = 0; |
bd878fc9 | 420 | int fd; |
9061bde5 | 421 | int i; |
351eb452 | 422 | int best_i; |
8ca87c4c | 423 | char *env; |
bd878fc9 | 424 | |
ce550745 TK |
425 | memset(TotalAccum16, 0, sizeof(TotalAccum16)); |
426 | memset(TotalAccum64, 0, sizeof(TotalAccum64)); | |
ea226b59 | 427 | TotalUnavail = TotalFreemap = 0; |
8ca87c4c | 428 | |
d490438f TK |
429 | env = getenv("HAMMER2_SHOW_ALL_VOLUME_HEADERS"); |
430 | if (env != NULL) { | |
431 | show_all_volume_headers = (int)strtol(env, NULL, 0); | |
432 | if (errno) | |
433 | show_all_volume_headers = 0; | |
434 | } | |
8ca87c4c TK |
435 | env = getenv("HAMMER2_SHOW_TAB"); |
436 | if (env != NULL) { | |
437 | show_tab = (int)strtol(env, NULL, 0); | |
438 | if (errno || show_tab < 0 || show_tab > 8) | |
439 | show_tab = 2; | |
440 | } | |
91e93d9f TK |
441 | env = getenv("HAMMER2_SHOW_DEPTH"); |
442 | if (env != NULL) { | |
443 | show_depth = (int)strtol(env, NULL, 0); | |
444 | if (errno || show_depth < 0) | |
445 | show_depth = -1; | |
446 | } | |
71782ce3 TK |
447 | env = getenv("HAMMER2_SHOW_MIN_MIRROR_TID"); |
448 | if (env != NULL) { | |
449 | show_min_mirror_tid = (hammer2_tid_t)strtoull(env, NULL, 16); | |
450 | if (errno) | |
451 | show_min_mirror_tid = 0; | |
452 | } | |
453 | env = getenv("HAMMER2_SHOW_MIN_MODIFY_TID"); | |
454 | if (env != NULL) { | |
455 | show_min_modify_tid = (hammer2_tid_t)strtoull(env, NULL, 16); | |
456 | if (errno) | |
457 | show_min_modify_tid = 0; | |
458 | } | |
8ca87c4c | 459 | |
0b738157 | 460 | hammer2_init_volumes(devpath, 1); |
d490438f | 461 | int all_volume_headers = VerboseOpt >= 3 || show_all_volume_headers; |
0b738157 TK |
462 | next_volume: |
463 | volu_loff = next_volu_loff; | |
464 | next_volu_loff = -1; | |
465 | printf("%s\n", hammer2_get_volume_path(volu_loff)); | |
351eb452 MD |
466 | /* |
467 | * Show the tree using the best volume header. | |
468 | * -vvv will show the tree for all four volume headers. | |
469 | */ | |
470 | best_i = -1; | |
471 | bzero(&best, sizeof(best)); | |
aa2131f0 | 472 | bzero(&best_media, sizeof(best_media)); |
95d182da | 473 | for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) { |
9061bde5 | 474 | bzero(&broot, sizeof(broot)); |
79e82fbc | 475 | broot.data_off = (i * HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX; |
0b738157 TK |
476 | off = broot.data_off & ~HAMMER2_OFF_MASK_RADIX; |
477 | fd = hammer2_get_volume_fd(volu_loff); | |
478 | lseek(fd, off, SEEK_SET); | |
351eb452 MD |
479 | if (read(fd, &media, HAMMER2_PBUFSIZE) == |
480 | (ssize_t)HAMMER2_PBUFSIZE) { | |
481 | broot.mirror_tid = media.voldata.mirror_tid; | |
482 | if (best_i < 0 || best.mirror_tid < broot.mirror_tid) { | |
483 | best_i = i; | |
484 | best = broot; | |
aa2131f0 MD |
485 | best_media = media; |
486 | } | |
487 | printf("Volume header %d: mirror_tid=%016jx\n", | |
488 | i, (intmax_t)broot.mirror_tid); | |
489 | ||
d490438f | 490 | if (all_volume_headers) { |
aa2131f0 MD |
491 | switch(which) { |
492 | case 0: | |
493 | broot.type = HAMMER2_BREF_TYPE_VOLUME; | |
0b738157 TK |
494 | show_bref(&media.voldata, 0, i, &broot, |
495 | 0); | |
aa2131f0 MD |
496 | break; |
497 | case 1: | |
498 | broot.type = HAMMER2_BREF_TYPE_FREEMAP; | |
0b738157 TK |
499 | show_bref(&media.voldata, 0, i, &broot, |
500 | 0); | |
aa2131f0 MD |
501 | break; |
502 | default: | |
0b738157 TK |
503 | show_volhdr(&media.voldata, i); |
504 | if (i == 0) | |
505 | next_volu_loff = get_next_volume(&media.voldata, volu_loff); | |
aa2131f0 MD |
506 | break; |
507 | } | |
660ecd92 TK |
508 | if (i != HAMMER2_NUM_VOLHDRS - 1) |
509 | printf("\n"); | |
351eb452 | 510 | } |
351eb452 | 511 | } |
9061bde5 | 512 | } |
0b738157 TK |
513 | if (next_volu_loff != (hammer2_off_t)-1) { |
514 | printf("---------------------------------------------\n"); | |
515 | goto next_volume; | |
516 | } | |
517 | ||
d490438f | 518 | if (!all_volume_headers) { |
aa2131f0 MD |
519 | switch(which) { |
520 | case 0: | |
521 | best.type = HAMMER2_BREF_TYPE_VOLUME; | |
0b738157 | 522 | show_bref(&best_media.voldata, 0, best_i, &best, 0); |
aa2131f0 MD |
523 | break; |
524 | case 1: | |
525 | best.type = HAMMER2_BREF_TYPE_FREEMAP; | |
0b738157 | 526 | show_bref(&best_media.voldata, 0, best_i, &best, 0); |
aa2131f0 MD |
527 | break; |
528 | default: | |
0b738157 TK |
529 | show_volhdr(&best_media.voldata, best_i); |
530 | next_volu_loff = get_next_volume(&best_media.voldata, volu_loff); | |
531 | if (next_volu_loff != (hammer2_off_t)-1) { | |
532 | printf("---------------------------------------------\n"); | |
533 | goto next_volume; | |
534 | } | |
aa2131f0 MD |
535 | break; |
536 | } | |
537 | } | |
bd878fc9 | 538 | |
aa2131f0 MD |
539 | if (which == 1 && VerboseOpt < 3) { |
540 | printf("Total unallocated storage: %6.3fGiB (%6.3fGiB in 64KB chunks)\n", | |
ce550745 TK |
541 | (double)TotalAccum16[0] / GIG, |
542 | (double)TotalAccum64[0] / GIG); | |
aa2131f0 | 543 | printf("Total possibly free storage: %6.3fGiB (%6.3fGiB in 64KB chunks)\n", |
ce550745 TK |
544 | (double)TotalAccum16[2] / GIG, |
545 | (double)TotalAccum64[2] / GIG); | |
aa2131f0 | 546 | printf("Total allocated storage: %6.3fGiB (%6.3fGiB in 64KB chunks)\n", |
ce550745 TK |
547 | (double)TotalAccum16[3] / GIG, |
548 | (double)TotalAccum64[3] / GIG); | |
aa2131f0 | 549 | printf("Total unavailable storage: %6.3fGiB\n", |
ce550745 | 550 | (double)TotalUnavail / GIG); |
aa2131f0 | 551 | printf("Total freemap storage: %6.3fGiB\n", |
ce550745 | 552 | (double)TotalFreemap / GIG); |
5c37bf12 | 553 | } |
0b738157 | 554 | hammer2_cleanup_volumes(); |
5c37bf12 | 555 | |
bd878fc9 MD |
556 | return 0; |
557 | } | |
558 | ||
aa2131f0 | 559 | static void |
0b738157 | 560 | show_volhdr(hammer2_volume_data_t *voldata, int bi) |
aa2131f0 MD |
561 | { |
562 | uint32_t status; | |
563 | uint32_t i; | |
564 | char *str; | |
565 | char *name; | |
0b738157 | 566 | char *buf; |
bc092eef | 567 | uuid_t uuid; |
aa2131f0 MD |
568 | |
569 | printf("\nVolume header %d {\n", bi); | |
570 | printf(" magic 0x%016jx\n", (intmax_t)voldata->magic); | |
571 | printf(" boot_beg 0x%016jx\n", (intmax_t)voldata->boot_beg); | |
572 | printf(" boot_end 0x%016jx (%6.2fMB)\n", | |
573 | (intmax_t)voldata->boot_end, | |
574 | (double)(voldata->boot_end - voldata->boot_beg) / | |
575 | (1024.0*1024.0)); | |
576 | printf(" aux_beg 0x%016jx\n", (intmax_t)voldata->aux_beg); | |
577 | printf(" aux_end 0x%016jx (%6.2fMB)\n", | |
578 | (intmax_t)voldata->aux_end, | |
579 | (double)(voldata->aux_end - voldata->aux_beg) / | |
580 | (1024.0*1024.0)); | |
581 | printf(" volu_size 0x%016jx (%6.2fGiB)\n", | |
582 | (intmax_t)voldata->volu_size, | |
583 | (double)voldata->volu_size / GIG); | |
584 | printf(" version %d\n", voldata->version); | |
585 | printf(" flags 0x%08x\n", voldata->flags); | |
586 | printf(" copyid %d\n", voldata->copyid); | |
587 | printf(" freemap_vers %d\n", voldata->freemap_version); | |
588 | printf(" peer_type %d\n", voldata->peer_type); | |
0b738157 TK |
589 | printf(" volu_id %d\n", voldata->volu_id); |
590 | printf(" nvolumes %d\n", voldata->nvolumes); | |
aa2131f0 MD |
591 | |
592 | str = NULL; | |
bc092eef TK |
593 | uuid = voldata->fsid; |
594 | hammer2_uuid_to_str(&uuid, &str); | |
aa2131f0 MD |
595 | printf(" fsid %s\n", str); |
596 | free(str); | |
597 | ||
598 | str = NULL; | |
599 | name = NULL; | |
bc092eef TK |
600 | uuid = voldata->fstype; |
601 | hammer2_uuid_to_str(&uuid, &str); | |
aa2131f0 MD |
602 | printf(" fstype %s\n", str); |
603 | uuid_addr_lookup(&voldata->fstype, &name, &status); | |
604 | if (name == NULL) | |
605 | name = strdup("?"); | |
606 | printf(" (%s)\n", name); | |
607 | free(name); | |
608 | free(str); | |
609 | ||
610 | printf(" allocator_size 0x%016jx (%6.2fGiB)\n", | |
611 | voldata->allocator_size, | |
612 | (double)voldata->allocator_size / GIG); | |
613 | printf(" allocator_free 0x%016jx (%6.2fGiB)\n", | |
614 | voldata->allocator_free, | |
615 | (double)voldata->allocator_free / GIG); | |
616 | printf(" allocator_beg 0x%016jx (%6.2fGiB)\n", | |
617 | voldata->allocator_beg, | |
618 | (double)voldata->allocator_beg / GIG); | |
619 | ||
620 | printf(" mirror_tid 0x%016jx\n", voldata->mirror_tid); | |
621 | printf(" reserved0080 0x%016jx\n", voldata->reserved0080); | |
622 | printf(" reserved0088 0x%016jx\n", voldata->reserved0088); | |
623 | printf(" freemap_tid 0x%016jx\n", voldata->freemap_tid); | |
ed383a46 | 624 | printf(" bulkfree_tid 0x%016jx\n", voldata->bulkfree_tid); |
4db52a5a | 625 | for (i = 0; i < nitems(voldata->reserved00A0); ++i) { |
aa2131f0 MD |
626 | printf(" reserved00A0/%u 0x%016jx\n", |
627 | i, voldata->reserved00A0[0]); | |
628 | } | |
0b738157 | 629 | printf(" total_size 0x%016jx\n", voldata->total_size); |
aa2131f0 MD |
630 | |
631 | printf(" copyexists "); | |
4db52a5a | 632 | for (i = 0; i < nitems(voldata->copyexists); ++i) |
aa2131f0 MD |
633 | printf(" 0x%02x", voldata->copyexists[i]); |
634 | printf("\n"); | |
635 | ||
636 | /* | |
637 | * NOTE: Index numbers and ICRC_SECTn definitions are not matched, | |
638 | * the ICRC for sector 0 actually uses the last index, for | |
639 | * example. | |
640 | * | |
641 | * NOTE: The whole voldata CRC does not have to match critically | |
642 | * as certain sub-areas of the volume header have their own | |
643 | * CRCs. | |
644 | */ | |
645 | printf("\n"); | |
4db52a5a | 646 | for (i = 0; i < nitems(voldata->icrc_sects); ++i) { |
aa2131f0 MD |
647 | printf(" icrc_sects[%u] ", i); |
648 | switch(i) { | |
649 | case HAMMER2_VOL_ICRC_SECT0: | |
650 | printf("0x%08x/0x%08x", | |
651 | hammer2_icrc32((char *)voldata + | |
652 | HAMMER2_VOLUME_ICRC0_OFF, | |
653 | HAMMER2_VOLUME_ICRC0_SIZE), | |
654 | voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT0]); | |
655 | if (hammer2_icrc32((char *)voldata + | |
656 | HAMMER2_VOLUME_ICRC0_OFF, | |
657 | HAMMER2_VOLUME_ICRC0_SIZE) == | |
658 | voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT0]) { | |
659 | printf(" (OK)"); | |
660 | } else { | |
661 | printf(" (FAILED)"); | |
662 | } | |
663 | break; | |
664 | case HAMMER2_VOL_ICRC_SECT1: | |
665 | printf("0x%08x/0x%08x", | |
666 | hammer2_icrc32((char *)voldata + | |
667 | HAMMER2_VOLUME_ICRC1_OFF, | |
668 | HAMMER2_VOLUME_ICRC1_SIZE), | |
669 | voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT1]); | |
670 | if (hammer2_icrc32((char *)voldata + | |
671 | HAMMER2_VOLUME_ICRC1_OFF, | |
672 | HAMMER2_VOLUME_ICRC1_SIZE) == | |
673 | voldata->icrc_sects[HAMMER2_VOL_ICRC_SECT1]) { | |
674 | printf(" (OK)"); | |
675 | } else { | |
676 | printf(" (FAILED)"); | |
677 | } | |
678 | ||
679 | break; | |
680 | default: | |
681 | printf("0x%08x (reserved)", voldata->icrc_sects[i]); | |
682 | break; | |
683 | } | |
684 | printf("\n"); | |
685 | } | |
686 | printf(" icrc_volhdr 0x%08x/0x%08x", | |
687 | hammer2_icrc32((char *)voldata + HAMMER2_VOLUME_ICRCVH_OFF, | |
688 | HAMMER2_VOLUME_ICRCVH_SIZE), | |
689 | voldata->icrc_volheader); | |
690 | if (hammer2_icrc32((char *)voldata + HAMMER2_VOLUME_ICRCVH_OFF, | |
691 | HAMMER2_VOLUME_ICRCVH_SIZE) == | |
692 | voldata->icrc_volheader) { | |
693 | printf(" (OK)\n"); | |
694 | } else { | |
695 | printf(" (FAILED - not a critical error)\n"); | |
696 | } | |
697 | ||
698 | /* | |
699 | * The super-root and freemap blocksets (not recursed) | |
700 | */ | |
701 | printf("\n"); | |
702 | printf(" sroot_blockset {\n"); | |
703 | for (i = 0; i < HAMMER2_SET_COUNT; ++i) { | |
0b738157 | 704 | show_bref(voldata, 16, i, |
aa2131f0 | 705 | &voldata->sroot_blockset.blockref[i], 2); |
aa2131f0 MD |
706 | } |
707 | printf(" }\n"); | |
708 | ||
709 | printf(" freemap_blockset {\n"); | |
710 | for (i = 0; i < HAMMER2_SET_COUNT; ++i) { | |
0b738157 | 711 | show_bref(voldata, 16, i, |
aa2131f0 | 712 | &voldata->freemap_blockset.blockref[i], 2); |
aa2131f0 MD |
713 | } |
714 | printf(" }\n"); | |
715 | ||
0b738157 TK |
716 | buf = calloc(1, sizeof(voldata->volu_loff)); |
717 | if (bcmp(buf, voldata->volu_loff, sizeof(voldata->volu_loff))) { | |
718 | printf("\n"); | |
719 | for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { | |
720 | hammer2_off_t loff = voldata->volu_loff[i]; | |
721 | if (loff != (hammer2_off_t)-1) | |
722 | printf(" volu_loff[%d] 0x%016jx\n", i, loff); | |
723 | } | |
724 | } | |
725 | free(buf); | |
726 | ||
aa2131f0 MD |
727 | printf("}\n"); |
728 | } | |
729 | ||
bd878fc9 | 730 | static void |
0b738157 TK |
731 | show_bref(hammer2_volume_data_t *voldata, int tab, int bi, |
732 | hammer2_blockref_t *bref, int norecurse) | |
bd878fc9 MD |
733 | { |
734 | hammer2_media_data_t media; | |
735 | hammer2_blockref_t *bscan; | |
906f9d76 | 736 | hammer2_off_t tmp; |
0b738157 | 737 | int i, bcount, namelen, failed, obrace, fd; |
aa2131f0 | 738 | int type_pad; |
bd878fc9 MD |
739 | size_t bytes; |
740 | const char *type_str; | |
741 | char *str = NULL; | |
d086b553 TK |
742 | char check_str[32], comp_str[32]; |
743 | uint8_t check_algo, comp_algo; | |
5a790ddf | 744 | uint32_t cv; |
7d565a4f | 745 | uint64_t cv64; |
91e93d9f | 746 | static int init_tab = -1; |
bc092eef | 747 | uuid_t uuid; |
bd878fc9 | 748 | |
bc8f6505 TK |
749 | SHA256_CTX hash_ctx; |
750 | union { | |
751 | uint8_t digest[SHA256_DIGEST_LENGTH]; | |
752 | uint64_t digest64[SHA256_DIGEST_LENGTH/8]; | |
753 | } u; | |
754 | ||
71782ce3 TK |
755 | /* omit if smaller than mininum mirror_tid threshold */ |
756 | if (bref->mirror_tid < show_min_mirror_tid) | |
757 | return; | |
758 | /* omit if smaller than mininum modify_tid threshold */ | |
759 | if (bref->modify_tid < show_min_modify_tid) { | |
760 | if (bref->modify_tid) | |
761 | return; | |
762 | else if (bref->type == HAMMER2_BREF_TYPE_INODE && !bref->leaf_count) | |
763 | return; | |
764 | } | |
765 | ||
91e93d9f TK |
766 | if (init_tab == -1) |
767 | init_tab = tab; | |
768 | ||
043b0b59 TK |
769 | bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX); |
770 | if (bytes) | |
771 | bytes = (size_t)1 << bytes; | |
772 | if (bytes) { | |
773 | hammer2_off_t io_off; | |
774 | hammer2_off_t io_base; | |
775 | size_t io_bytes; | |
776 | size_t boff; | |
777 | ||
778 | io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; | |
5dade8cf | 779 | io_base = io_off & ~(hammer2_off_t)(HAMMER2_LBUFSIZE - 1); |
043b0b59 TK |
780 | boff = io_off - io_base; |
781 | ||
5dade8cf | 782 | io_bytes = HAMMER2_LBUFSIZE; |
043b0b59 TK |
783 | while (io_bytes + boff < bytes) |
784 | io_bytes <<= 1; | |
785 | ||
786 | if (io_bytes > sizeof(media)) { | |
9317c2d0 | 787 | printf("(bad block size %zu)\n", bytes); |
043b0b59 TK |
788 | return; |
789 | } | |
790 | if (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1) { | |
0b738157 TK |
791 | fd = hammer2_get_volume_fd(io_off); |
792 | lseek(fd, io_base - hammer2_get_volume_offset(io_base), | |
793 | SEEK_SET); | |
043b0b59 TK |
794 | if (read(fd, &media, io_bytes) != (ssize_t)io_bytes) { |
795 | printf("(media read failed)\n"); | |
796 | return; | |
797 | } | |
798 | if (boff) | |
799 | bcopy((char *)&media + boff, &media, bytes); | |
800 | } | |
801 | } | |
802 | ||
803 | bscan = NULL; | |
804 | bcount = 0; | |
805 | namelen = 0; | |
806 | failed = 0; | |
047d51c8 | 807 | obrace = 1; |
043b0b59 | 808 | |
94a97128 | 809 | type_str = hammer2_breftype_to_str(bref->type); |
aa2131f0 MD |
810 | type_pad = 8 - strlen(type_str); |
811 | if (type_pad < 0) | |
812 | type_pad = 0; | |
bd878fc9 | 813 | |
043b0b59 TK |
814 | switch(bref->type) { |
815 | case HAMMER2_BREF_TYPE_INODE: | |
ae2f457f | 816 | assert(bytes); |
043b0b59 TK |
817 | if (!(media.ipdata.meta.op_flags & HAMMER2_OPFLAG_DIRECTDATA)) { |
818 | bscan = &media.ipdata.u.blockset.blockref[0]; | |
819 | bcount = HAMMER2_SET_COUNT; | |
820 | } | |
821 | break; | |
822 | case HAMMER2_BREF_TYPE_INDIRECT: | |
ae2f457f | 823 | assert(bytes); |
043b0b59 TK |
824 | bscan = &media.npdata[0]; |
825 | bcount = bytes / sizeof(hammer2_blockref_t); | |
826 | break; | |
827 | case HAMMER2_BREF_TYPE_VOLUME: | |
828 | bscan = &media.voldata.sroot_blockset.blockref[0]; | |
829 | bcount = HAMMER2_SET_COUNT; | |
830 | break; | |
831 | case HAMMER2_BREF_TYPE_FREEMAP: | |
832 | bscan = &media.voldata.freemap_blockset.blockref[0]; | |
833 | bcount = HAMMER2_SET_COUNT; | |
834 | break; | |
835 | case HAMMER2_BREF_TYPE_FREEMAP_NODE: | |
ae2f457f | 836 | assert(bytes); |
043b0b59 TK |
837 | bscan = &media.npdata[0]; |
838 | bcount = bytes / sizeof(hammer2_blockref_t); | |
839 | break; | |
840 | } | |
841 | ||
e3bf7c89 TK |
842 | if (QuietOpt > 0) { |
843 | tabprintf(tab, | |
844 | "%s.%-3d %016jx %016jx/%-2d " | |
0b738157 | 845 | "vol=%d mir=%016jx mod=%016jx leafcnt=%d ", |
e3bf7c89 TK |
846 | type_str, bi, (intmax_t)bref->data_off, |
847 | (intmax_t)bref->key, (intmax_t)bref->keybits, | |
0b738157 | 848 | hammer2_get_volume_id(bref->data_off), |
e3bf7c89 TK |
849 | (intmax_t)bref->mirror_tid, |
850 | (intmax_t)bref->modify_tid, | |
851 | bref->leaf_count); | |
e3bf7c89 | 852 | } else { |
0425627b | 853 | tabprintf(tab, "%s.%-3d%*.*s %016jx %016jx/%-2d ", |
e3bf7c89 TK |
854 | type_str, bi, type_pad, type_pad, "", |
855 | (intmax_t)bref->data_off, | |
856 | (intmax_t)bref->key, (intmax_t)bref->keybits); | |
857 | /*if (norecurse > 1)*/ { | |
858 | printf("\n"); | |
859 | tabprintf(tab + 13, ""); | |
860 | } | |
0b738157 TK |
861 | printf("vol=%d mir=%016jx mod=%016jx lfcnt=%d ", |
862 | hammer2_get_volume_id(bref->data_off), | |
e3bf7c89 TK |
863 | (intmax_t)bref->mirror_tid, (intmax_t)bref->modify_tid, |
864 | bref->leaf_count); | |
865 | if (/*norecurse > 1 && */ (bcount || bref->flags || | |
866 | bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE || | |
867 | bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF)) { | |
868 | printf("\n"); | |
869 | tabprintf(tab + 13, ""); | |
870 | } | |
aa2131f0 MD |
871 | } |
872 | ||
4d08bfeb TK |
873 | if (bcount) |
874 | printf("bcnt=%d ", bcount); | |
22dffc51 MD |
875 | if (bref->flags) |
876 | printf("flags=%02x ", bref->flags); | |
65cacacf MD |
877 | if (bref->type == HAMMER2_BREF_TYPE_FREEMAP_NODE || |
878 | bref->type == HAMMER2_BREF_TYPE_FREEMAP_LEAF) { | |
33b364a7 TK |
879 | printf("bigmask=%08x avail=%ju ", |
880 | bref->check.freemap.bigmask, | |
881 | (uintmax_t)bref->check.freemap.avail); | |
65cacacf | 882 | } |
bd878fc9 | 883 | |
5a790ddf MD |
884 | /* |
885 | * Check data integrity in verbose mode, otherwise we are just doing | |
886 | * a quick meta-data scan. Meta-data integrity is always checked. | |
887 | * (Also see the check above that ensures the media data is loaded, | |
888 | * otherwise there's no data to check!). | |
da0cdd33 MD |
889 | * |
890 | * WARNING! bref->check state may be used for other things when | |
891 | * bref has no data (bytes == 0). | |
5a790ddf | 892 | */ |
da0cdd33 MD |
893 | if (bytes && |
894 | (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1)) { | |
e3bf7c89 TK |
895 | if (!(QuietOpt > 0)) { |
896 | /*if (norecurse > 1)*/ { | |
897 | printf("\n"); | |
898 | tabprintf(tab + 13, ""); | |
899 | } | |
aa2131f0 MD |
900 | } |
901 | ||
d086b553 TK |
902 | check_algo = HAMMER2_DEC_CHECK(bref->methods); |
903 | strlcpy(check_str, hammer2_checkmode_to_str(check_algo), | |
904 | sizeof(check_str)); | |
905 | comp_algo = HAMMER2_DEC_COMP(bref->methods); | |
906 | strlcpy(comp_str, hammer2_compmode_to_str(comp_algo), | |
907 | sizeof(comp_str)); | |
908 | ||
909 | switch(check_algo) { | |
5a790ddf | 910 | case HAMMER2_CHECK_NONE: |
d086b553 | 911 | printf("meth=%s|%s ", check_str, comp_str); |
8adee7de MD |
912 | break; |
913 | case HAMMER2_CHECK_DISABLED: | |
d086b553 | 914 | printf("meth=%s|%s ", check_str, comp_str); |
5a790ddf MD |
915 | break; |
916 | case HAMMER2_CHECK_ISCSI32: | |
917 | cv = hammer2_icrc32(&media, bytes); | |
918 | if (bref->check.iscsi32.value != cv) { | |
d086b553 TK |
919 | printf("(icrc %s|%s %08x/%08x failed) ", |
920 | check_str, comp_str, | |
5a790ddf MD |
921 | bref->check.iscsi32.value, |
922 | cv); | |
62a2c422 | 923 | failed = 1; |
8adee7de | 924 | } else { |
d086b553 TK |
925 | printf("meth=%s|%s iscsi32=%08x ", |
926 | check_str, comp_str, cv); | |
5a790ddf MD |
927 | } |
928 | break; | |
7d565a4f MD |
929 | case HAMMER2_CHECK_XXHASH64: |
930 | cv64 = XXH64(&media, bytes, XXH_HAMMER2_SEED); | |
931 | if (bref->check.xxhash64.value != cv64) { | |
d086b553 TK |
932 | printf("(xxhash64 %s|%s %016jx/%016jx failed) ", |
933 | check_str, comp_str, | |
7d565a4f MD |
934 | bref->check.xxhash64.value, |
935 | cv64); | |
62a2c422 | 936 | failed = 1; |
7d565a4f | 937 | } else { |
d086b553 TK |
938 | printf("meth=%s|%s xxh=%016jx ", |
939 | check_str, comp_str, cv64); | |
7d565a4f | 940 | } |
5a790ddf MD |
941 | break; |
942 | case HAMMER2_CHECK_SHA192: | |
bc8f6505 TK |
943 | SHA256_Init(&hash_ctx); |
944 | SHA256_Update(&hash_ctx, &media, bytes); | |
945 | SHA256_Final(u.digest, &hash_ctx); | |
946 | u.digest64[2] ^= u.digest64[3]; | |
947 | if (memcmp(u.digest, bref->check.sha192.data, | |
948 | sizeof(bref->check.sha192.data))) { | |
d086b553 TK |
949 | printf("(sha192 %s:%s failed) ", |
950 | check_str, comp_str); | |
bc8f6505 TK |
951 | failed = 1; |
952 | } else { | |
d086b553 | 953 | printf("meth=%s|%s ", check_str, comp_str); |
bc8f6505 | 954 | } |
5a790ddf MD |
955 | break; |
956 | case HAMMER2_CHECK_FREEMAP: | |
957 | cv = hammer2_icrc32(&media, bytes); | |
958 | if (bref->check.freemap.icrc32 != cv) { | |
d086b553 TK |
959 | printf("(fcrc %s|%s %08x/%08x failed) ", |
960 | check_str, comp_str, | |
5a790ddf MD |
961 | bref->check.freemap.icrc32, |
962 | cv); | |
62a2c422 | 963 | failed = 1; |
8adee7de | 964 | } else { |
d086b553 TK |
965 | printf("meth=%s|%s fcrc=%08x ", |
966 | check_str, comp_str, cv); | |
5a790ddf MD |
967 | } |
968 | break; | |
969 | } | |
970 | } | |
971 | ||
aa2131f0 MD |
972 | tab += show_tab; |
973 | ||
dd5e52ca TK |
974 | if (QuietOpt > 0) { |
975 | obrace = 0; | |
976 | printf("\n"); | |
977 | goto skip_data; | |
978 | } | |
979 | ||
bd878fc9 MD |
980 | switch(bref->type) { |
981 | case HAMMER2_BREF_TYPE_EMPTY: | |
660ecd92 TK |
982 | if (norecurse) |
983 | printf("\n"); | |
bd878fc9 MD |
984 | obrace = 0; |
985 | break; | |
da0cdd33 MD |
986 | case HAMMER2_BREF_TYPE_DIRENT: |
987 | printf("{\n"); | |
988 | if (bref->embed.dirent.namlen <= sizeof(bref->check.buf)) { | |
989 | tabprintf(tab, "filename \"%*.*s\"\n", | |
990 | bref->embed.dirent.namlen, | |
991 | bref->embed.dirent.namlen, | |
992 | bref->check.buf); | |
993 | } else { | |
994 | tabprintf(tab, "filename \"%*.*s\"\n", | |
995 | bref->embed.dirent.namlen, | |
996 | bref->embed.dirent.namlen, | |
997 | media.buf); | |
998 | } | |
999 | tabprintf(tab, "inum 0x%016jx\n", | |
79e82fbc | 1000 | (uintmax_t)bref->embed.dirent.inum); |
f168e7f9 TK |
1001 | tabprintf(tab, "nlen %d\n", bref->embed.dirent.namlen); |
1002 | tabprintf(tab, "type %s\n", | |
da0cdd33 MD |
1003 | hammer2_iptype_to_str(bref->embed.dirent.type)); |
1004 | break; | |
bd878fc9 MD |
1005 | case HAMMER2_BREF_TYPE_INODE: |
1006 | printf("{\n"); | |
b0f58de8 | 1007 | namelen = media.ipdata.meta.name_len; |
ad7cf8ea MD |
1008 | if (namelen > HAMMER2_INODE_MAXNAME) |
1009 | namelen = 0; | |
1010 | tabprintf(tab, "filename \"%*.*s\"\n", | |
1011 | namelen, namelen, media.ipdata.filename); | |
b0f58de8 | 1012 | tabprintf(tab, "version %d\n", media.ipdata.meta.version); |
cac06d4e TK |
1013 | if ((media.ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) || |
1014 | media.ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) { | |
1015 | tabprintf(tab, "pfs_st %d (%s)\n", | |
1016 | media.ipdata.meta.pfs_subtype, | |
1017 | hammer2_pfssubtype_to_str(media.ipdata.meta.pfs_subtype)); | |
1018 | } | |
bd878fc9 | 1019 | tabprintf(tab, "uflags 0x%08x\n", |
b0f58de8 MD |
1020 | media.ipdata.meta.uflags); |
1021 | if (media.ipdata.meta.rmajor || media.ipdata.meta.rminor) { | |
bd878fc9 | 1022 | tabprintf(tab, "rmajor %d\n", |
b0f58de8 | 1023 | media.ipdata.meta.rmajor); |
bd878fc9 | 1024 | tabprintf(tab, "rminor %d\n", |
b0f58de8 | 1025 | media.ipdata.meta.rminor); |
bd878fc9 MD |
1026 | } |
1027 | tabprintf(tab, "ctime %s\n", | |
b0f58de8 | 1028 | hammer2_time64_to_str(media.ipdata.meta.ctime, &str)); |
bd878fc9 | 1029 | tabprintf(tab, "mtime %s\n", |
b0f58de8 | 1030 | hammer2_time64_to_str(media.ipdata.meta.mtime, &str)); |
bd878fc9 | 1031 | tabprintf(tab, "atime %s\n", |
b0f58de8 | 1032 | hammer2_time64_to_str(media.ipdata.meta.atime, &str)); |
bd878fc9 | 1033 | tabprintf(tab, "btime %s\n", |
b0f58de8 | 1034 | hammer2_time64_to_str(media.ipdata.meta.btime, &str)); |
bc092eef | 1035 | uuid = media.ipdata.meta.uid; |
bd878fc9 | 1036 | tabprintf(tab, "uid %s\n", |
bc092eef TK |
1037 | hammer2_uuid_to_str(&uuid, &str)); |
1038 | uuid = media.ipdata.meta.gid; | |
bd878fc9 | 1039 | tabprintf(tab, "gid %s\n", |
bc092eef | 1040 | hammer2_uuid_to_str(&uuid, &str)); |
da0cdd33 MD |
1041 | tabprintf(tab, "type %s\n", |
1042 | hammer2_iptype_to_str(media.ipdata.meta.type)); | |
bd878fc9 | 1043 | tabprintf(tab, "opflgs 0x%02x\n", |
b0f58de8 | 1044 | media.ipdata.meta.op_flags); |
bd878fc9 | 1045 | tabprintf(tab, "capflgs 0x%04x\n", |
b0f58de8 | 1046 | media.ipdata.meta.cap_flags); |
bd878fc9 | 1047 | tabprintf(tab, "mode %-7o\n", |
b0f58de8 | 1048 | media.ipdata.meta.mode); |
bd878fc9 | 1049 | tabprintf(tab, "inum 0x%016jx\n", |
b0f58de8 | 1050 | media.ipdata.meta.inum); |
12404a28 | 1051 | tabprintf(tab, "size %ju ", |
b0f58de8 | 1052 | (uintmax_t)media.ipdata.meta.size); |
12404a28 TK |
1053 | if (media.ipdata.meta.op_flags & HAMMER2_OPFLAG_DIRECTDATA && |
1054 | media.ipdata.meta.size <= HAMMER2_EMBEDDED_BYTES) | |
1055 | printf("(embedded data)\n"); | |
1056 | else | |
1057 | printf("\n"); | |
bd878fc9 | 1058 | tabprintf(tab, "nlinks %ju\n", |
b0f58de8 | 1059 | (uintmax_t)media.ipdata.meta.nlinks); |
bd878fc9 | 1060 | tabprintf(tab, "iparent 0x%016jx\n", |
b0f58de8 | 1061 | (uintmax_t)media.ipdata.meta.iparent); |
bd878fc9 | 1062 | tabprintf(tab, "name_key 0x%016jx\n", |
b0f58de8 | 1063 | (uintmax_t)media.ipdata.meta.name_key); |
bd878fc9 | 1064 | tabprintf(tab, "name_len %u\n", |
b0f58de8 | 1065 | media.ipdata.meta.name_len); |
bd878fc9 | 1066 | tabprintf(tab, "ncopies %u\n", |
b0f58de8 | 1067 | media.ipdata.meta.ncopies); |
2a98b0e0 TK |
1068 | tabprintf(tab, "compalg %s\n", |
1069 | hammer2_compmode_to_str(media.ipdata.meta.comp_algo)); | |
12404a28 TK |
1070 | tabprintf(tab, "target_t %u\n", |
1071 | media.ipdata.meta.target_type); | |
2a98b0e0 TK |
1072 | tabprintf(tab, "checkalg %s\n", |
1073 | hammer2_checkmode_to_str(media.ipdata.meta.check_algo)); | |
b7add675 MD |
1074 | if ((media.ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) || |
1075 | media.ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) { | |
12404a28 TK |
1076 | tabprintf(tab, "pfs_nmas %u\n", |
1077 | media.ipdata.meta.pfs_nmasters); | |
bd878fc9 | 1078 | tabprintf(tab, "pfs_type %u (%s)\n", |
b0f58de8 MD |
1079 | media.ipdata.meta.pfs_type, |
1080 | hammer2_pfstype_to_str(media.ipdata.meta.pfs_type)); | |
bd878fc9 | 1081 | tabprintf(tab, "pfs_inum 0x%016jx\n", |
b0f58de8 | 1082 | (uintmax_t)media.ipdata.meta.pfs_inum); |
bc092eef | 1083 | uuid = media.ipdata.meta.pfs_clid; |
8c280d5d | 1084 | tabprintf(tab, "pfs_clid %s\n", |
bc092eef TK |
1085 | hammer2_uuid_to_str(&uuid, &str)); |
1086 | uuid = media.ipdata.meta.pfs_fsid; | |
bd878fc9 | 1087 | tabprintf(tab, "pfs_fsid %s\n", |
bc092eef | 1088 | hammer2_uuid_to_str(&uuid, &str)); |
7866a0e7 MD |
1089 | tabprintf(tab, "pfs_lsnap_tid 0x%016jx\n", |
1090 | (uintmax_t)media.ipdata.meta.pfs_lsnap_tid); | |
bd878fc9 MD |
1091 | } |
1092 | tabprintf(tab, "data_quota %ju\n", | |
b0f58de8 | 1093 | (uintmax_t)media.ipdata.meta.data_quota); |
bd878fc9 | 1094 | tabprintf(tab, "data_count %ju\n", |
da0cdd33 | 1095 | (uintmax_t)bref->embed.stats.data_count); |
bd878fc9 | 1096 | tabprintf(tab, "inode_quota %ju\n", |
b0f58de8 | 1097 | (uintmax_t)media.ipdata.meta.inode_quota); |
bd878fc9 | 1098 | tabprintf(tab, "inode_count %ju\n", |
da0cdd33 | 1099 | (uintmax_t)bref->embed.stats.inode_count); |
bd878fc9 MD |
1100 | break; |
1101 | case HAMMER2_BREF_TYPE_INDIRECT: | |
bd878fc9 MD |
1102 | printf("{\n"); |
1103 | break; | |
1104 | case HAMMER2_BREF_TYPE_DATA: | |
79e82fbc TK |
1105 | printf("\n"); |
1106 | obrace = 0; | |
bd878fc9 MD |
1107 | break; |
1108 | case HAMMER2_BREF_TYPE_VOLUME: | |
50456506 MD |
1109 | printf("mirror_tid=%016jx freemap_tid=%016jx ", |
1110 | media.voldata.mirror_tid, | |
10136ab6 | 1111 | media.voldata.freemap_tid); |
208afee5 TK |
1112 | printf("{\n"); |
1113 | break; | |
1114 | case HAMMER2_BREF_TYPE_FREEMAP: | |
1115 | printf("mirror_tid=%016jx freemap_tid=%016jx ", | |
1116 | media.voldata.mirror_tid, | |
1117 | media.voldata.freemap_tid); | |
78ac5385 MD |
1118 | printf("{\n"); |
1119 | break; | |
1120 | case HAMMER2_BREF_TYPE_FREEMAP_LEAF: | |
93f3933a | 1121 | printf("{\n"); |
906f9d76 TK |
1122 | tmp = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; |
1123 | tmp &= HAMMER2_SEGMASK; | |
1124 | tmp /= HAMMER2_PBUFSIZE; | |
ae495466 | 1125 | assert(tmp >= HAMMER2_ZONE_FREEMAP_00); |
906f9d76 TK |
1126 | assert(tmp < HAMMER2_ZONE_FREEMAP_END); |
1127 | tmp -= HAMMER2_ZONE_FREEMAP_00; | |
1128 | tmp /= HAMMER2_ZONE_FREEMAP_INC; | |
1129 | tabprintf(tab, "rotation=%d\n", (int)tmp); | |
1130 | ||
93f3933a | 1131 | for (i = 0; i < HAMMER2_FREEMAP_COUNT; ++i) { |
79e82fbc | 1132 | hammer2_off_t data_off = bref->key + |
43c0f951 | 1133 | i * HAMMER2_FREEMAP_LEVEL0_SIZE; |
5cebbe36 MD |
1134 | #if HAMMER2_BMAP_ELEMENTS != 8 |
1135 | #error "cmd_debug.c: HAMMER2_BMAP_ELEMENTS expected to be 8" | |
1136 | #endif | |
66b8e023 | 1137 | tabprintf(tab + 4, "%016jx %04d.%04x linear=%06x avail=%06x " |
5cebbe36 MD |
1138 | "%016jx %016jx %016jx %016jx " |
1139 | "%016jx %016jx %016jx %016jx\n", | |
79e82fbc | 1140 | data_off, i, media.bmdata[i].class, |
66b8e023 | 1141 | media.bmdata[i].linear, |
93f3933a | 1142 | media.bmdata[i].avail, |
5cebbe36 MD |
1143 | media.bmdata[i].bitmapq[0], |
1144 | media.bmdata[i].bitmapq[1], | |
1145 | media.bmdata[i].bitmapq[2], | |
1146 | media.bmdata[i].bitmapq[3], | |
1147 | media.bmdata[i].bitmapq[4], | |
1148 | media.bmdata[i].bitmapq[5], | |
1149 | media.bmdata[i].bitmapq[6], | |
1150 | media.bmdata[i].bitmapq[7]); | |
78ac5385 | 1151 | } |
93f3933a | 1152 | tabprintf(tab, "}\n"); |
78ac5385 MD |
1153 | break; |
1154 | case HAMMER2_BREF_TYPE_FREEMAP_NODE: | |
bd878fc9 | 1155 | printf("{\n"); |
906f9d76 TK |
1156 | tmp = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; |
1157 | tmp &= HAMMER2_SEGMASK; | |
1158 | tmp /= HAMMER2_PBUFSIZE; | |
ae495466 | 1159 | assert(tmp >= HAMMER2_ZONE_FREEMAP_00); |
906f9d76 TK |
1160 | assert(tmp < HAMMER2_ZONE_FREEMAP_END); |
1161 | tmp -= HAMMER2_ZONE_FREEMAP_00; | |
1162 | tmp /= HAMMER2_ZONE_FREEMAP_INC; | |
1163 | tabprintf(tab, "rotation=%d\n", (int)tmp); | |
bd878fc9 MD |
1164 | break; |
1165 | default: | |
78ac5385 MD |
1166 | printf("\n"); |
1167 | obrace = 0; | |
bd878fc9 MD |
1168 | break; |
1169 | } | |
1170 | if (str) | |
1171 | free(str); | |
62a2c422 | 1172 | |
dd5e52ca | 1173 | skip_data: |
db2a354a TK |
1174 | /* |
1175 | * Update statistics. | |
1176 | */ | |
1177 | switch(bref->type) { | |
1178 | case HAMMER2_BREF_TYPE_FREEMAP_LEAF: | |
1179 | for (i = 0; i < HAMMER2_FREEMAP_COUNT; ++i) { | |
1180 | hammer2_off_t data_off = bref->key + | |
1181 | i * HAMMER2_FREEMAP_LEVEL0_SIZE; | |
1182 | if (data_off >= voldata->aux_end && | |
0b738157 | 1183 | data_off < hammer2_get_total_size()) { |
db2a354a TK |
1184 | int j; |
1185 | for (j = 0; j < 4; ++j) | |
6c129444 | 1186 | count_blocks(&media.bmdata[i], j, |
db2a354a TK |
1187 | &TotalAccum16[j], |
1188 | &TotalAccum64[j]); | |
1189 | } else | |
1190 | TotalUnavail += HAMMER2_FREEMAP_LEVEL0_SIZE; | |
1191 | } | |
1192 | TotalFreemap += HAMMER2_FREEMAP_LEVEL1_SIZE; | |
1193 | break; | |
1194 | default: | |
1195 | break; | |
1196 | } | |
1197 | ||
62a2c422 MD |
1198 | /* |
1199 | * Recurse if norecurse == 0. If the CRC failed, pass norecurse = 1. | |
1200 | * That is, if an indirect or inode fails we still try to list its | |
1201 | * direct children to help with debugging, but go no further than | |
1202 | * that because they are probably garbage. | |
1203 | */ | |
91e93d9f TK |
1204 | if (show_depth == -1 || ((tab - init_tab) / show_tab) < show_depth) { |
1205 | for (i = 0; norecurse == 0 && i < bcount; ++i) { | |
1206 | if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) { | |
0b738157 | 1207 | show_bref(voldata, tab, i, &bscan[i], |
91e93d9f TK |
1208 | failed); |
1209 | } | |
bd878fc9 MD |
1210 | } |
1211 | } | |
8ca87c4c | 1212 | tab -= show_tab; |
bd878fc9 MD |
1213 | if (obrace) { |
1214 | if (bref->type == HAMMER2_BREF_TYPE_INODE) | |
1fca819a | 1215 | tabprintf(tab, "} (%s.%d, \"%*.*s\")\n", |
79e82fbc TK |
1216 | type_str, bi, namelen, namelen, |
1217 | media.ipdata.filename); | |
bd878fc9 | 1218 | else |
047d51c8 | 1219 | tabprintf(tab, "} (%s.%d)\n", type_str, bi); |
bd878fc9 MD |
1220 | } |
1221 | } | |
1222 | ||
5c37bf12 MD |
1223 | static |
1224 | void | |
6c129444 TK |
1225 | count_blocks(hammer2_bmap_data_t *bmap, int value, |
1226 | hammer2_off_t *accum16, hammer2_off_t *accum64) | |
5c37bf12 | 1227 | { |
ce550745 TK |
1228 | int i, j, bits; |
1229 | hammer2_bitmap_t value16, value64; | |
1230 | ||
1231 | bits = (int)sizeof(hammer2_bitmap_t) * 8; | |
22f08f81 TK |
1232 | assert(bits == 64); |
1233 | ||
ce550745 TK |
1234 | value16 = value; |
1235 | assert(value16 < 4); | |
1236 | value64 = (value16 << 6) | (value16 << 4) | (value16 << 2) | value16; | |
1237 | assert(value64 < 256); | |
1238 | ||
22f08f81 TK |
1239 | for (i = 0; i < HAMMER2_BMAP_ELEMENTS; ++i) { |
1240 | hammer2_bitmap_t bm = bmap->bitmapq[i]; | |
1241 | hammer2_bitmap_t bm_save = bm; | |
1242 | hammer2_bitmap_t mask; | |
1243 | ||
1244 | mask = 0x03; /* 2 bits per 16KB */ | |
1245 | for (j = 0; j < bits; j += 2) { | |
ce550745 | 1246 | if ((bm & mask) == value16) |
5c37bf12 | 1247 | *accum16 += 16384; |
dfc6e32e | 1248 | bm >>= 2; |
5c37bf12 | 1249 | } |
dfc6e32e TK |
1250 | |
1251 | bm = bm_save; | |
22f08f81 TK |
1252 | mask = 0xFF; /* 8 bits per 64KB chunk */ |
1253 | for (j = 0; j < bits; j += 8) { | |
ce550745 | 1254 | if ((bm & mask) == value64) |
5c37bf12 | 1255 | *accum64 += 65536; |
dfc6e32e | 1256 | bm >>= 8; |
5c37bf12 MD |
1257 | } |
1258 | } | |
1259 | } | |
1260 | ||
775153c2 MD |
1261 | int |
1262 | cmd_hash(int ac, const char **av) | |
1263 | { | |
1264 | int i; | |
1265 | ||
1266 | for (i = 0; i < ac; ++i) { | |
7b6e3143 | 1267 | printf("%016jx %s\n", |
1d5238a4 | 1268 | dirhash(av[i], strlen(av[i])), |
7b6e3143 | 1269 | av[i]); |
775153c2 MD |
1270 | } |
1271 | return(0); | |
1272 | } | |
1273 | ||
0c41f055 MD |
1274 | int |
1275 | cmd_dhash(int ac, const char **av) | |
1276 | { | |
1277 | char buf[1024]; /* 1K extended directory record */ | |
1278 | uint64_t hash; | |
1279 | int i; | |
1280 | ||
1281 | for (i = 0; i < ac; ++i) { | |
1282 | bzero(buf, sizeof(buf)); | |
1283 | snprintf(buf, sizeof(buf), "%s", av[i]); | |
1284 | hash = XXH64(buf, sizeof(buf), XXH_HAMMER2_SEED); | |
1285 | printf("%016jx %s\n", hash, av[i]); | |
1286 | } | |
1287 | return(0); | |
1288 | } | |
1289 | ||
8f579e46 | 1290 | int |
40498d1c | 1291 | cmd_dumpchain(const char *path, u_int flags) |
8f579e46 | 1292 | { |
40498d1c | 1293 | int dummy = (int)flags; |
97ea1536 | 1294 | int ecode = 0; |
8f579e46 MD |
1295 | int fd; |
1296 | ||
1297 | fd = open(path, O_RDONLY); | |
1298 | if (fd >= 0) { | |
97ea1536 TK |
1299 | if (ioctl(fd, HAMMER2IOC_DEBUG_DUMP, &dummy) < 0) { |
1300 | fprintf(stderr, "%s: %s\n", path, strerror(errno)); | |
1301 | ecode = 1; | |
1302 | } | |
8f579e46 MD |
1303 | close(fd); |
1304 | } else { | |
1305 | fprintf(stderr, "unable to open %s\n", path); | |
97ea1536 | 1306 | ecode = 1; |
8f579e46 | 1307 | } |
97ea1536 | 1308 | return ecode; |
8f579e46 MD |
1309 | } |
1310 | ||
bd878fc9 MD |
1311 | static |
1312 | void | |
1313 | tabprintf(int tab, const char *ctl, ...) | |
1314 | { | |
1315 | va_list va; | |
1316 | ||
1317 | printf("%*.*s", tab, tab, ""); | |
1318 | va_start(va, ctl); | |
1319 | vprintf(ctl, va); | |
1320 | va_end(va); | |
1321 | } |