]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/io.c
db: don't claim unchecked CRCs are correct
[thirdparty/xfsprogs-dev.git] / db / io.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 4 *
da23017d
NS
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
2bd0ea18 7 * published by the Free Software Foundation.
dfc130f3 8 *
da23017d
NS
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
dfc130f3 13 *
da23017d
NS
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
17 */
18
1d7e80ee 19#include <xfs/libxfs.h>
2bd0ea18 20#include "command.h"
2bd0ea18
NS
21#include "type.h"
22#include "faddr.h"
23#include "fprint.h"
24#include "field.h"
25#include "inode.h"
26#include "io.h"
27#include "output.h"
4ca431fc 28#include "init.h"
2bd0ea18
NS
29#include "malloc.h"
30
31static int pop_f(int argc, char **argv);
32static void pop_help(void);
33static int push_f(int argc, char **argv);
34static void push_help(void);
35static int stack_f(int argc, char **argv);
36static void stack_help(void);
37static int forward_f(int argc, char **argv);
38static void forward_help(void);
39static int back_f(int argc, char **argv);
40static void back_help(void);
41static int ring_f(int argc, char **argv);
42static void ring_help(void);
43
44static const cmdinfo_t pop_cmd =
45 { "pop", NULL, pop_f, 0, 0, 0, NULL,
9ee7055c 46 N_("pop location from the stack"), pop_help };
2bd0ea18 47static const cmdinfo_t push_cmd =
9ee7055c
AM
48 { "push", NULL, push_f, 0, 2, 0, N_("[command]"),
49 N_("push location to the stack"), push_help };
2bd0ea18
NS
50static const cmdinfo_t stack_cmd =
51 { "stack", NULL, stack_f, 0, 0, 0, NULL,
9ee7055c 52 N_("view the location stack"), stack_help };
dfc130f3 53static const cmdinfo_t forward_cmd =
2bd0ea18 54 { "forward", "f", forward_f, 0, 0, 0, NULL,
9ee7055c 55 N_("move forward to next entry in the position ring"), forward_help };
dfc130f3 56static const cmdinfo_t back_cmd =
2bd0ea18 57 { "back", "b", back_f, 0, 0, 0, NULL,
9ee7055c 58 N_("move to the previous location in the position ring"), back_help };
dfc130f3 59static const cmdinfo_t ring_cmd =
2bd0ea18 60 { "ring", NULL, ring_f, 0, 1, 0, NULL,
9ee7055c 61 N_("show position ring or move to a specific entry"), ring_help };
2bd0ea18
NS
62
63iocur_t *iocur_base;
64iocur_t *iocur_top;
65int iocur_sp = -1;
66int iocur_len;
67
68#define RING_ENTRIES 20
69static iocur_t iocur_ring[RING_ENTRIES];
70static int ring_head = -1;
71static int ring_tail = -1;
72static int ring_current = -1;
73
74void
75io_init(void)
76{
77 add_command(&pop_cmd);
78 add_command(&push_cmd);
79 add_command(&stack_cmd);
80 add_command(&forward_cmd);
81 add_command(&back_cmd);
82 add_command(&ring_cmd);
83}
84
85void
86off_cur(
87 int off,
88 int len)
89{
90 if (iocur_top == NULL || off + len > BBTOB(iocur_top->blen))
9ee7055c 91 dbprintf(_("can't set block offset to %d\n"), off);
2bd0ea18
NS
92 else {
93 iocur_top->boff = off;
94 iocur_top->off = ((xfs_off_t)iocur_top->bb << BBSHIFT) + off;
95 iocur_top->len = len;
96 iocur_top->data = (void *)((char *)iocur_top->buf + off);
97 }
98}
99
100void
101pop_cur(void)
102{
103 if (iocur_sp < 0) {
9ee7055c 104 dbprintf(_("can't pop anything from I/O stack\n"));
2bd0ea18
NS
105 return;
106 }
72298d16
DC
107 if (iocur_top->bp) {
108 libxfs_putbuf(iocur_top->bp);
109 iocur_top->bp = NULL;
110 }
111 if (iocur_top->bbmap) {
112 free(iocur_top->bbmap);
113 iocur_top->bbmap = NULL;
114 }
2bd0ea18
NS
115 if (--iocur_sp >= 0) {
116 iocur_top = iocur_base + iocur_sp;
117 cur_typ = iocur_top->typ;
118 } else {
119 iocur_top = iocur_base;
120 iocur_sp = 0;
121 }
122}
123
124/*ARGSUSED*/
125static int
126pop_f(
127 int argc,
128 char **argv)
129{
130 pop_cur();
131 return 0;
132}
133
134static void
135pop_help(void)
136{
9ee7055c 137 dbprintf(_(
2bd0ea18
NS
138"\n"
139" Changes the address and data type to the first entry on the stack.\n"
140"\n"
9ee7055c 141 ));
2bd0ea18
NS
142}
143
144void
145print_iocur(
146 char *tag,
147 iocur_t *ioc)
148{
149 int i;
150
151 dbprintf("%s\n", tag);
9ee7055c
AM
152 dbprintf(_("\tbyte offset %lld, length %d\n"), ioc->off, ioc->len);
153 dbprintf(_("\tbuffer block %lld (fsbno %lld), %d bb%s\n"), ioc->bb,
2bd0ea18
NS
154 (xfs_dfsbno_t)XFS_DADDR_TO_FSB(mp, ioc->bb), ioc->blen,
155 ioc->blen == 1 ? "" : "s");
72298d16 156 if (ioc->bbmap) {
9ee7055c 157 dbprintf(_("\tblock map"));
72298d16
DC
158 for (i = 0; i < ioc->bbmap->nmaps; i++)
159 dbprintf(" %lld:%d", ioc->bbmap->b[i].bm_bn,
160 ioc->bbmap->b[i].bm_len);
2bd0ea18
NS
161 dbprintf("\n");
162 }
9ee7055c
AM
163 dbprintf(_("\tinode %lld, dir inode %lld, type %s\n"), ioc->ino,
164 ioc->dirino, ioc->typ == NULL ? _("none") : ioc->typ->name);
2bd0ea18
NS
165}
166
167void
168print_ring(void)
169{
170 int i;
171 iocur_t *ioc;
172
173 if (ring_current == -1) {
9ee7055c 174 dbprintf(_("no entries in location ring.\n"));
2bd0ea18
NS
175 return;
176 }
177
9ee7055c 178 dbprintf(_(" type bblock bblen fsbno inode\n"));
2bd0ea18
NS
179
180 i = ring_head;
181 for (;;) {
182 ioc = &iocur_ring[i];
183 if (i == ring_current)
184 printf("*%2d: ", i);
185 else
186 printf(" %2d: ", i);
187
188 dbprintf("%-7.7s %8lld %5d %8lld %9lld\n",
189 ioc->typ == NULL ? "none" : ioc->typ->name,
190 ioc->bb,
191 ioc->blen,
192 (xfs_dfsbno_t)XFS_DADDR_TO_FSB(mp, ioc->bb),
193 ioc->ino
194 );
195
196 if (i == ring_tail)
197 break;
198
199 i = (i+(RING_ENTRIES-1))%RING_ENTRIES;
200 }
201}
202
203
204void
205push_cur(void)
206{
207 if (iocur_sp + 1 >= iocur_len) {
208 iocur_base = xrealloc(iocur_base,
209 sizeof(*iocur_base) * (iocur_len + 1));
210 iocur_len++;
211 }
212 iocur_sp++;
213 iocur_top = iocur_base + iocur_sp;
214 memset(iocur_top, 0, sizeof(*iocur_base));
215 iocur_top->ino = iocur_sp > 0 ? iocur_top[-1].ino : NULLFSINO;
216 iocur_top->dirino = iocur_sp > 0 ? iocur_top[-1].dirino : NULLFSINO;
217 iocur_top->mode = iocur_sp > 0 ? iocur_top[-1].mode : 0;
218 cur_typ = NULL;
219}
220
221static int
222push_f(
223 int argc,
224 char **argv)
225{
226 const cmdinfo_t *ct;
227
228 if (argc > 1) {
dfc130f3
RC
229 /* check we can execute command */
230 ct = find_command(argv[1]);
231 if (ct == NULL) {
9ee7055c 232 dbprintf(_("no such command %s\n"), argv[1]);
dfc130f3
RC
233 return 0;
234 }
235 if (!ct->canpush) {
9ee7055c 236 dbprintf(_("no push form allowed for %s\n"), argv[1]);
dfc130f3
RC
237 return 0;
238 }
239 }
240
241 /* save current state */
242 push_cur();
2bd0ea18
NS
243 if (iocur_top[-1].typ && iocur_top[-1].typ->typnm == TYP_INODE)
244 set_cur_inode(iocur_top[-1].ino);
245 else
246 set_cur(iocur_top[-1].typ, iocur_top[-1].bb,
dfc130f3 247 iocur_top[-1].blen, DB_RING_IGN,
72298d16 248 iocur_top[-1].bbmap);
2bd0ea18 249
dfc130f3
RC
250 /* run requested command */
251 if (argc>1)
252 (void)command(argc-1, argv+1);
2bd0ea18
NS
253 return 0;
254}
255
256static void
257push_help(void)
258{
9ee7055c 259 dbprintf(_(
2bd0ea18
NS
260"\n"
261" Allows you to push the current address and data type on the stack for\n"
262" later return. 'push' also accepts an additional command to execute after\n"
263" storing the current address (ex: 'push a rootino' from the superblock).\n"
264"\n"
9ee7055c 265 ));
2bd0ea18
NS
266}
267
268/* move forward through the ring */
269/* ARGSUSED */
270static int
271forward_f(
272 int argc,
273 char **argv)
274{
275 if (ring_current == -1) {
9ee7055c 276 dbprintf(_("ring is empty\n"));
2bd0ea18
NS
277 return 0;
278 }
279 if (ring_current == ring_head) {
9ee7055c 280 dbprintf(_("no further entries\n"));
2bd0ea18
NS
281 return 0;
282 }
283
284 ring_current = (ring_current+1)%RING_ENTRIES;
285
286 set_cur(iocur_ring[ring_current].typ,
287 iocur_ring[ring_current].bb,
288 iocur_ring[ring_current].blen,
289 DB_RING_IGN,
72298d16 290 iocur_ring[ring_current].bbmap);
2bd0ea18
NS
291
292 return 0;
293}
294
295static void
296forward_help(void)
297{
9ee7055c 298 dbprintf(_(
2bd0ea18
NS
299"\n"
300" The 'forward' ('f') command moves to the next location in the position\n"
301" ring, updating the current position and data type. If the current location\n"
302" is the top entry in the ring, then the 'forward' command will have\n"
303" no effect.\n"
304"\n"
9ee7055c 305 ));
2bd0ea18
NS
306}
307
308/* move backwards through the ring */
309/* ARGSUSED */
310static int
311back_f(
312 int argc,
313 char **argv)
314{
315 if (ring_current == -1) {
9ee7055c 316 dbprintf(_("ring is empty\n"));
2bd0ea18
NS
317 return 0;
318 }
319 if (ring_current == ring_tail) {
9ee7055c 320 dbprintf(_("no previous entries\n"));
2bd0ea18
NS
321 return 0;
322 }
323
324 ring_current = (ring_current+(RING_ENTRIES-1))%RING_ENTRIES;
325
326 set_cur(iocur_ring[ring_current].typ,
327 iocur_ring[ring_current].bb,
328 iocur_ring[ring_current].blen,
329 DB_RING_IGN,
72298d16 330 iocur_ring[ring_current].bbmap);
2bd0ea18
NS
331
332 return 0;
333}
334
335static void
336back_help(void)
337{
9ee7055c 338 dbprintf(_(
2bd0ea18
NS
339"\n"
340" The 'back' ('b') command moves to the previous location in the position\n"
341" ring, updating the current position and data type. If the current location\n"
342" is the last entry in the ring, then the 'back' command will have no effect.\n"
343"\n"
9ee7055c 344 ));
2bd0ea18
NS
345}
346
347/* show or go to specific point in ring */
348static int
349ring_f(
350 int argc,
351 char **argv)
352{
353 int index;
354
355 if (argc == 1) {
356 print_ring();
357 return 0;
358 }
359
b3d6b800 360 index = (int)strtoul(argv[1], NULL, 0);
d15f7cfb 361 if (index < 0 || index >= RING_ENTRIES) {
9ee7055c 362 dbprintf(_("invalid entry: %d\n"), index);
d15f7cfb
ES
363 return 0;
364 }
2bd0ea18
NS
365
366 ring_current = index;
367
368 set_cur(iocur_ring[index].typ,
369 iocur_ring[index].bb,
370 iocur_ring[index].blen,
371 DB_RING_IGN,
72298d16 372 iocur_ring[index].bbmap);
2bd0ea18
NS
373
374 return 0;
375}
376
377static void
378ring_help(void)
379{
9ee7055c 380 dbprintf(_(
2bd0ea18
NS
381"\n"
382" The position ring automatically keeps track of each disk location and\n"
383" structure type for each change of position you make during your xfs_db\n"
384" session. The last %d most recent entries are kept in the ring.\n"
385"\n"
386" To display the current list of ring entries type 'ring' by itself on\n"
387" the command line. The entry highlighted by an asterisk ('*') is the\n"
388" current entry.\n"
389"\n"
390" To move to another entry in the ring type 'ring <num>' where <num> is\n"
391" your desired entry from the ring position list.\n"
392"\n"
393" You may also use the 'forward' ('f') or 'back' ('b') commands to move\n"
394" to the previous or next entry in the ring, respectively.\n"
395"\n"
396" Note: Unlike the 'stack', 'push' and 'pop' commands, the ring tracks your\n"
397" location implicitly. Use the 'push' and 'pop' commands if you wish to\n"
398" store a specific location explicitly for later return.\n"
9ee7055c 399"\n"),
2bd0ea18
NS
400 RING_ENTRIES);
401}
402
403
404void
405ring_add(void)
406{
407 if (ring_head == -1) {
408 /* only get here right after startup */
409 ring_head = 0;
410 ring_tail = 0;
411 ring_current = 0;
412 iocur_ring[0] = *iocur_top;
413 } else {
414 if (ring_current == ring_head) {
415 ring_head = (ring_head+1)%RING_ENTRIES;
416 iocur_ring[ring_head] = *iocur_top;
417 if (ring_head == ring_tail)
418 ring_tail = (ring_tail+1)%RING_ENTRIES;
419 ring_current = ring_head;
420 } else {
421 ring_current = (ring_current+1)%RING_ENTRIES;
422 iocur_ring[ring_current] = *iocur_top;
423 }
424 }
425}
426
2a8b3fdf
DC
427static void
428write_cur_buf(void)
429{
430 int ret;
431
72298d16
DC
432 ret = libxfs_writebufr(iocur_top->bp);
433 if (ret != 0)
2a8b3fdf
DC
434 dbprintf(_("write error: %s\n"), strerror(ret));
435
436 /* re-read buffer from disk */
72298d16
DC
437 ret = libxfs_readbufr(mp->m_ddev_targp, iocur_top->bb, iocur_top->bp,
438 iocur_top->blen, 0);
439 if (ret != 0)
2a8b3fdf
DC
440 dbprintf(_("read error: %s\n"), strerror(ret));
441}
442
2a8b3fdf
DC
443static void
444write_cur_bbs(void)
2bd0ea18
NS
445{
446 int ret;
447
72298d16
DC
448 ret = libxfs_writebufr(iocur_top->bp);
449 if (ret != 0)
9ee7055c 450 dbprintf(_("write error: %s\n"), strerror(ret));
2a8b3fdf 451
72298d16 452
2bd0ea18 453 /* re-read buffer from disk */
6d5e5ee0 454 ret = libxfs_readbufr_map(mp->m_ddev_targp, iocur_top->bp, 0);
72298d16 455 if (ret != 0)
9ee7055c 456 dbprintf(_("read error: %s\n"), strerror(ret));
2bd0ea18
NS
457}
458
2a8b3fdf
DC
459void
460write_cur(void)
461{
462 if (iocur_sp < 0) {
463 dbprintf(_("nothing to write\n"));
464 return;
465 }
466
a73b88f2
DC
467 if (iocur_top->ino_buf)
468 libxfs_dinode_calc_crc(mp, iocur_top->data);
66a40d02
DC
469 if (iocur_top->dquot_buf)
470 xfs_update_cksum(iocur_top->data, sizeof(struct xfs_dqblk),
471 XFS_DQUOT_CRC_OFF);
72298d16 472 if (iocur_top->bbmap)
2a8b3fdf
DC
473 write_cur_bbs();
474 else
475 write_cur_buf();
476}
477
2bd0ea18
NS
478void
479set_cur(
480 const typ_t *t,
dfc130f3 481 __int64_t d,
2bd0ea18
NS
482 int c,
483 int ring_flag,
484 bbmap_t *bbmap)
485{
72298d16 486 struct xfs_buf *bp;
2bd0ea18
NS
487 xfs_ino_t dirino;
488 xfs_ino_t ino;
489 __uint16_t mode;
6fea8f83 490 const struct xfs_buf_ops *ops = t ? t->bops : NULL;
2bd0ea18
NS
491
492 if (iocur_sp < 0) {
9ee7055c 493 dbprintf(_("set_cur no stack element to set\n"));
2bd0ea18
NS
494 return;
495 }
496
6fea8f83 497
2bd0ea18
NS
498 ino = iocur_top->ino;
499 dirino = iocur_top->dirino;
500 mode = iocur_top->mode;
501 pop_cur();
502 push_cur();
2a8b3fdf
DC
503
504 if (bbmap) {
857592d2 505#ifdef DEBUG_BBMAP
72298d16 506 int i;
2a8b3fdf 507 printf(_("xfs_db got a bbmap for %lld\n"), (long long)d);
72298d16
DC
508 printf(_("\tblock map"));
509 for (i = 0; i < bbmap->nmaps; i++)
510 printf(" %lld:%d", (long long)bbmap->b[i].bm_bn,
511 bbmap->b[i].bm_len);
512 printf("\n");
2a8b3fdf 513#endif
72298d16
DC
514 iocur_top->bbmap = malloc(sizeof(struct bbmap));
515 if (!iocur_top->bbmap)
2a8b3fdf 516 return;
72298d16
DC
517 memcpy(iocur_top->bbmap, bbmap, sizeof(struct bbmap));
518 bp = libxfs_readbuf_map(mp->m_ddev_targp, bbmap->b,
6fea8f83 519 bbmap->nmaps, 0, ops);
2a8b3fdf 520 } else {
6fea8f83 521 bp = libxfs_readbuf(mp->m_ddev_targp, d, c, 0, ops);
72298d16 522 iocur_top->bbmap = NULL;
2a8b3fdf 523 }
6fea8f83
DC
524
525 /*
9c0a86ed 526 * Keep the buffer even if the verifier says it is corrupted.
6fea8f83
DC
527 * We're a diagnostic tool, after all.
528 */
9c0a86ed
DC
529 if (!bp || (bp->b_error && bp->b_error != EFSCORRUPTED &&
530 bp->b_error != EFSBADCRC))
72298d16
DC
531 return;
532 iocur_top->buf = bp->b_addr;
533 iocur_top->bp = bp;
b511ff41
DC
534 if (!ops)
535 bp->b_flags |= LIBXFS_B_UNCHECKED;
2a8b3fdf 536
2bd0ea18
NS
537 iocur_top->bb = d;
538 iocur_top->blen = c;
539 iocur_top->boff = 0;
540 iocur_top->data = iocur_top->buf;
541 iocur_top->len = BBTOB(c);
542 iocur_top->off = d << BBSHIFT;
543 iocur_top->typ = cur_typ = t;
544 iocur_top->ino = ino;
545 iocur_top->dirino = dirino;
546 iocur_top->mode = mode;
a73b88f2 547 iocur_top->ino_buf = 0;
66a40d02 548 iocur_top->dquot_buf = 0;
2bd0ea18
NS
549
550 /* store location in ring */
551 if (ring_flag)
552 ring_add();
553}
554
555static void
556stack_help(void)
557{
9ee7055c 558 dbprintf(_(
2bd0ea18
NS
559"\n"
560" The stack is used to explicitly store your location and data type\n"
561" for later return. The 'push' operation stores the current address\n"
562" and type on the stack, the 'pop' operation returns you to the\n"
563" position and datatype of the top entry on the stack.\n"
564"\n"
565" The 'stack' allows explicit location saves, see 'ring' for implicit\n"
566" position tracking.\n"
567"\n"
9ee7055c 568 ));
2bd0ea18
NS
569}
570
571/*ARGSUSED*/
572static int
573stack_f(
574 int argc,
575 char **argv)
576{
577 int i;
578 char tagbuf[8];
579
2d9475a4
NS
580 for (i = iocur_sp; i > 0; i--) {
581 snprintf(tagbuf, sizeof(tagbuf), "%d: ", i);
2bd0ea18
NS
582 print_iocur(tagbuf, &iocur_base[i]);
583 }
584 return 0;
585}