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