nrelease - fix/improve livecd
[dragonfly.git] / sbin / hammer2 / cmd_debug.c
CommitLineData
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 42static int show_all_volume_headers = 0;
8ca87c4c 43static int show_tab = 2;
91e93d9f 44static int show_depth = -1;
71782ce3
TK
45static hammer2_tid_t show_min_mirror_tid = 0;
46static hammer2_tid_t show_min_modify_tid = 0;
bd878fc9 47
1b8eded1 48static void shell_msghandler(dmsg_msg_t *msg, int unmanaged);
0c3a8cd0 49static void shell_ttymsg(dmsg_iocom_t *iocom);
6c129444 50static 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
57int
58cmd_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 82int
bd878fc9 83cmd_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 */
123static
124void
1b8eded1 125shell_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
198static
199void
0c3a8cd0 200shell_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 */
248static void shell_span(dmsg_msg_t *msg, char *cmdbuf);
5ab1caed 249static void shell_ping(dmsg_msg_t *msg, char *cmdbuf);
81666e1b 250
11f7caf4 251void
b53e7c4f 252hammer2_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
304static void
305shell_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 315static void
1b8eded1 316shell_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 */
360int
361cmd_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
385static void show_volhdr(hammer2_volume_data_t *voldata, int bi);
386static void show_bref(hammer2_volume_data_t *voldata, int tab,
dc709019 387 int bi, hammer2_blockref_t *bref, int norecurse);
bd878fc9
MD
388static void tabprintf(int tab, const char *ctl, ...);
389
ce550745
TK
390static hammer2_off_t TotalAccum16[4]; /* includes TotalAccum64 */
391static hammer2_off_t TotalAccum64[4];
392static hammer2_off_t TotalUnavail;
393static hammer2_off_t TotalFreemap;
5c37bf12 394
0b738157
TK
395static
396hammer2_off_t
397get_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 412int
aa2131f0 413cmd_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
462next_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 559static void
0b738157 560show_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 730static void
0b738157
TK
731show_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 1173skip_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
1223static
1224void
6c129444
TK
1225count_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
1261int
1262cmd_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
1274int
1275cmd_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 1290int
40498d1c 1291cmd_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
1311static
1312void
1313tabprintf(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}