]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/io.c
xfs: cache last bitmap block in realtime allocator
[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
0d376f6c
AA
76static inline void set_cur_boff(int off)
77{
78 iocur_top->boff = off;
79 iocur_top->off = ((xfs_off_t)iocur_top->bb << BBSHIFT) + off;
80 iocur_top->data = (void *)((char *)iocur_top->buf + off);
81}
82
2bd0ea18
NS
83void
84off_cur(
85 int off,
86 int len)
87{
88 if (iocur_top == NULL || off + len > BBTOB(iocur_top->blen))
9ee7055c 89 dbprintf(_("can't set block offset to %d\n"), off);
2bd0ea18 90 else {
0d376f6c 91 set_cur_boff(off);
2bd0ea18 92 iocur_top->len = len;
2bd0ea18
NS
93 }
94}
95
96void
97pop_cur(void)
98{
99 if (iocur_sp < 0) {
9ee7055c 100 dbprintf(_("can't pop anything from I/O stack\n"));
2bd0ea18
NS
101 return;
102 }
72298d16 103 if (iocur_top->bp) {
e02ba985 104 libxfs_buf_relse(iocur_top->bp);
72298d16
DC
105 iocur_top->bp = NULL;
106 }
107 if (iocur_top->bbmap) {
108 free(iocur_top->bbmap);
109 iocur_top->bbmap = NULL;
110 }
2bd0ea18
NS
111 if (--iocur_sp >= 0) {
112 iocur_top = iocur_base + iocur_sp;
113 cur_typ = iocur_top->typ;
114 } else {
115 iocur_top = iocur_base;
116 iocur_sp = 0;
117 }
118}
119
120/*ARGSUSED*/
121static int
122pop_f(
123 int argc,
124 char **argv)
125{
126 pop_cur();
127 return 0;
128}
129
130static void
131pop_help(void)
132{
9ee7055c 133 dbprintf(_(
2bd0ea18
NS
134"\n"
135" Changes the address and data type to the first entry on the stack.\n"
136"\n"
9ee7055c 137 ));
2bd0ea18
NS
138}
139
1665923a
DW
140bool
141iocur_is_ddev(const struct iocur *ioc)
142{
143 if (!ioc->bp)
144 return false;
145
146 return ioc->bp->b_target == ioc->bp->b_mount->m_ddev_targp;
147}
148
149bool
150iocur_is_extlogdev(const struct iocur *ioc)
151{
152 struct xfs_buf *bp = ioc->bp;
153
154 if (!bp)
155 return false;
156 if (bp->b_mount->m_logdev_targp == bp->b_mount->m_ddev_targp)
157 return false;
158
159 return bp->b_target == bp->b_mount->m_logdev_targp;
160}
161
2bd0ea18
NS
162void
163print_iocur(
164 char *tag,
165 iocur_t *ioc)
166{
1665923a 167 const char *block_unit = "fsbno?";
2bd0ea18
NS
168 int i;
169
1665923a
DW
170 if (iocur_is_ddev(ioc))
171 block_unit = "fsbno";
172 else if (iocur_is_extlogdev(ioc))
173 block_unit = "logbno";
174
2bd0ea18 175 dbprintf("%s\n", tag);
9ee7055c 176 dbprintf(_("\tbyte offset %lld, length %d\n"), ioc->off, ioc->len);
1665923a
DW
177 dbprintf(_("\tbuffer block %lld (%s %lld), %d bb%s\n"), ioc->bb,
178 block_unit,
179 (xfs_fsblock_t)XFS_DADDR_TO_FSB(mp, ioc->bb),
180 ioc->blen, ioc->blen == 1 ? "" : "s");
72298d16 181 if (ioc->bbmap) {
9ee7055c 182 dbprintf(_("\tblock map"));
72298d16
DC
183 for (i = 0; i < ioc->bbmap->nmaps; i++)
184 dbprintf(" %lld:%d", ioc->bbmap->b[i].bm_bn,
185 ioc->bbmap->b[i].bm_len);
2bd0ea18
NS
186 dbprintf("\n");
187 }
9ee7055c
AM
188 dbprintf(_("\tinode %lld, dir inode %lld, type %s\n"), ioc->ino,
189 ioc->dirino, ioc->typ == NULL ? _("none") : ioc->typ->name);
2bd0ea18
NS
190}
191
00ff2b10 192static void
2bd0ea18
NS
193print_ring(void)
194{
195 int i;
196 iocur_t *ioc;
197
198 if (ring_current == -1) {
9ee7055c 199 dbprintf(_("no entries in location ring.\n"));
2bd0ea18
NS
200 return;
201 }
202
9ee7055c 203 dbprintf(_(" type bblock bblen fsbno inode\n"));
2bd0ea18
NS
204
205 i = ring_head;
206 for (;;) {
207 ioc = &iocur_ring[i];
208 if (i == ring_current)
209 printf("*%2d: ", i);
210 else
211 printf(" %2d: ", i);
212
213 dbprintf("%-7.7s %8lld %5d %8lld %9lld\n",
214 ioc->typ == NULL ? "none" : ioc->typ->name,
215 ioc->bb,
216 ioc->blen,
5a35bf2c 217 (xfs_fsblock_t)XFS_DADDR_TO_FSB(mp, ioc->bb),
2bd0ea18
NS
218 ioc->ino
219 );
220
221 if (i == ring_tail)
222 break;
223
224 i = (i+(RING_ENTRIES-1))%RING_ENTRIES;
225 }
226}
227
228
229void
230push_cur(void)
231{
232 if (iocur_sp + 1 >= iocur_len) {
233 iocur_base = xrealloc(iocur_base,
234 sizeof(*iocur_base) * (iocur_len + 1));
235 iocur_len++;
236 }
237 iocur_sp++;
238 iocur_top = iocur_base + iocur_sp;
239 memset(iocur_top, 0, sizeof(*iocur_base));
240 iocur_top->ino = iocur_sp > 0 ? iocur_top[-1].ino : NULLFSINO;
241 iocur_top->dirino = iocur_sp > 0 ? iocur_top[-1].dirino : NULLFSINO;
242 iocur_top->mode = iocur_sp > 0 ? iocur_top[-1].mode : 0;
243 cur_typ = NULL;
244}
245
3540b418
DW
246void
247push_cur_and_set_type(void)
248{
249 /* save current state */
250 push_cur();
251 if (iocur_top[-1].typ && iocur_top[-1].typ->typnm == TYP_INODE)
252 set_cur_inode(iocur_top[-1].ino);
253 else
254 set_cur(iocur_top[-1].typ, iocur_top[-1].bb,
255 iocur_top[-1].blen, DB_RING_IGN,
256 iocur_top[-1].bbmap);
257}
258
2bd0ea18
NS
259static int
260push_f(
261 int argc,
262 char **argv)
263{
264 const cmdinfo_t *ct;
265
266 if (argc > 1) {
dfc130f3
RC
267 /* check we can execute command */
268 ct = find_command(argv[1]);
269 if (ct == NULL) {
9ee7055c 270 dbprintf(_("no such command %s\n"), argv[1]);
dfc130f3
RC
271 return 0;
272 }
273 if (!ct->canpush) {
9ee7055c 274 dbprintf(_("no push form allowed for %s\n"), argv[1]);
dfc130f3
RC
275 return 0;
276 }
277 }
278
3540b418 279 push_cur_and_set_type();
2bd0ea18 280
dfc130f3
RC
281 /* run requested command */
282 if (argc>1)
283 (void)command(argc-1, argv+1);
2bd0ea18
NS
284 return 0;
285}
286
287static void
288push_help(void)
289{
9ee7055c 290 dbprintf(_(
2bd0ea18
NS
291"\n"
292" Allows you to push the current address and data type on the stack for\n"
293" later return. 'push' also accepts an additional command to execute after\n"
294" storing the current address (ex: 'push a rootino' from the superblock).\n"
295"\n"
9ee7055c 296 ));
2bd0ea18
NS
297}
298
299/* move forward through the ring */
300/* ARGSUSED */
301static int
302forward_f(
303 int argc,
304 char **argv)
305{
306 if (ring_current == -1) {
9ee7055c 307 dbprintf(_("ring is empty\n"));
2bd0ea18
NS
308 return 0;
309 }
310 if (ring_current == ring_head) {
9ee7055c 311 dbprintf(_("no further entries\n"));
2bd0ea18
NS
312 return 0;
313 }
314
315 ring_current = (ring_current+1)%RING_ENTRIES;
316
317 set_cur(iocur_ring[ring_current].typ,
318 iocur_ring[ring_current].bb,
319 iocur_ring[ring_current].blen,
320 DB_RING_IGN,
72298d16 321 iocur_ring[ring_current].bbmap);
2bd0ea18
NS
322
323 return 0;
324}
325
326static void
327forward_help(void)
328{
9ee7055c 329 dbprintf(_(
2bd0ea18
NS
330"\n"
331" The 'forward' ('f') command moves to the next location in the position\n"
332" ring, updating the current position and data type. If the current location\n"
333" is the top entry in the ring, then the 'forward' command will have\n"
334" no effect.\n"
335"\n"
9ee7055c 336 ));
2bd0ea18
NS
337}
338
339/* move backwards through the ring */
340/* ARGSUSED */
341static int
342back_f(
343 int argc,
344 char **argv)
345{
346 if (ring_current == -1) {
9ee7055c 347 dbprintf(_("ring is empty\n"));
2bd0ea18
NS
348 return 0;
349 }
350 if (ring_current == ring_tail) {
9ee7055c 351 dbprintf(_("no previous entries\n"));
2bd0ea18
NS
352 return 0;
353 }
354
355 ring_current = (ring_current+(RING_ENTRIES-1))%RING_ENTRIES;
356
357 set_cur(iocur_ring[ring_current].typ,
358 iocur_ring[ring_current].bb,
359 iocur_ring[ring_current].blen,
360 DB_RING_IGN,
72298d16 361 iocur_ring[ring_current].bbmap);
2bd0ea18
NS
362
363 return 0;
364}
365
366static void
367back_help(void)
368{
9ee7055c 369 dbprintf(_(
2bd0ea18
NS
370"\n"
371" The 'back' ('b') command moves to the previous location in the position\n"
372" ring, updating the current position and data type. If the current location\n"
373" is the last entry in the ring, then the 'back' command will have no effect.\n"
374"\n"
9ee7055c 375 ));
2bd0ea18
NS
376}
377
378/* show or go to specific point in ring */
379static int
380ring_f(
381 int argc,
382 char **argv)
383{
384 int index;
385
386 if (argc == 1) {
387 print_ring();
388 return 0;
389 }
390
b3d6b800 391 index = (int)strtoul(argv[1], NULL, 0);
d15f7cfb 392 if (index < 0 || index >= RING_ENTRIES) {
9ee7055c 393 dbprintf(_("invalid entry: %d\n"), index);
d15f7cfb
ES
394 return 0;
395 }
2bd0ea18
NS
396
397 ring_current = index;
398
399 set_cur(iocur_ring[index].typ,
400 iocur_ring[index].bb,
401 iocur_ring[index].blen,
402 DB_RING_IGN,
72298d16 403 iocur_ring[index].bbmap);
2bd0ea18
NS
404
405 return 0;
406}
407
408static void
409ring_help(void)
410{
9ee7055c 411 dbprintf(_(
2bd0ea18
NS
412"\n"
413" The position ring automatically keeps track of each disk location and\n"
414" structure type for each change of position you make during your xfs_db\n"
415" session. The last %d most recent entries are kept in the ring.\n"
416"\n"
417" To display the current list of ring entries type 'ring' by itself on\n"
418" the command line. The entry highlighted by an asterisk ('*') is the\n"
419" current entry.\n"
420"\n"
421" To move to another entry in the ring type 'ring <num>' where <num> is\n"
422" your desired entry from the ring position list.\n"
423"\n"
424" You may also use the 'forward' ('f') or 'back' ('b') commands to move\n"
425" to the previous or next entry in the ring, respectively.\n"
426"\n"
427" Note: Unlike the 'stack', 'push' and 'pop' commands, the ring tracks your\n"
428" location implicitly. Use the 'push' and 'pop' commands if you wish to\n"
429" store a specific location explicitly for later return.\n"
9ee7055c 430"\n"),
2bd0ea18
NS
431 RING_ENTRIES);
432}
433
434
435void
436ring_add(void)
437{
438 if (ring_head == -1) {
439 /* only get here right after startup */
440 ring_head = 0;
441 ring_tail = 0;
442 ring_current = 0;
443 iocur_ring[0] = *iocur_top;
444 } else {
445 if (ring_current == ring_head) {
446 ring_head = (ring_head+1)%RING_ENTRIES;
447 iocur_ring[ring_head] = *iocur_top;
448 if (ring_head == ring_tail)
449 ring_tail = (ring_tail+1)%RING_ENTRIES;
450 ring_current = ring_head;
451 } else {
452 ring_current = (ring_current+1)%RING_ENTRIES;
453 iocur_ring[ring_current] = *iocur_top;
454 }
455 }
456}
457
2a8b3fdf
DC
458static void
459write_cur_buf(void)
460{
461 int ret;
462
331d5956 463 ret = -libxfs_bwrite(iocur_top->bp);
72298d16 464 if (ret != 0)
2a8b3fdf
DC
465 dbprintf(_("write error: %s\n"), strerror(ret));
466
467 /* re-read buffer from disk */
12b53197 468 ret = -libxfs_readbufr(mp->m_ddev_targp, iocur_top->bb, iocur_top->bp,
72298d16
DC
469 iocur_top->blen, 0);
470 if (ret != 0)
2a8b3fdf
DC
471 dbprintf(_("read error: %s\n"), strerror(ret));
472}
473
2a8b3fdf
DC
474static void
475write_cur_bbs(void)
2bd0ea18
NS
476{
477 int ret;
478
331d5956 479 ret = -libxfs_bwrite(iocur_top->bp);
72298d16 480 if (ret != 0)
9ee7055c 481 dbprintf(_("write error: %s\n"), strerror(ret));
2a8b3fdf 482
72298d16 483
2bd0ea18 484 /* re-read buffer from disk */
12b53197 485 ret = -libxfs_readbufr_map(mp->m_ddev_targp, iocur_top->bp, 0);
72298d16 486 if (ret != 0)
9ee7055c 487 dbprintf(_("read error: %s\n"), strerror(ret));
2bd0ea18
NS
488}
489
c9f5e3db
ES
490void
491xfs_dummy_verify(
492 struct xfs_buf *bp)
493{
494 return;
495}
496
86769b32
DC
497void
498xfs_verify_recalc_crc(
499 struct xfs_buf *bp)
500{
501 xfs_buf_update_cksum(bp, iocur_top->typ->crc_off);
502}
503
2a8b3fdf
DC
504void
505write_cur(void)
506{
b64af2c4
ES
507 bool skip_crc = false;
508
2a8b3fdf
DC
509 if (iocur_sp < 0) {
510 dbprintf(_("nothing to write\n"));
511 return;
512 }
513
2660e653 514 if (!xfs_has_crc(mp) ||
b64af2c4
ES
515 !iocur_top->bp->b_ops ||
516 iocur_top->bp->b_ops->verify_write == xfs_dummy_verify)
517 skip_crc = true;
518
519 if (!skip_crc) {
1e9c13c5
ES
520 if (iocur_top->ino_buf)
521 xfs_inode_set_crc(iocur_top->bp);
522 else if (iocur_top->dquot_buf)
523 xfs_dquot_set_crc(iocur_top->bp);
b335ecb5 524 }
72298d16 525 if (iocur_top->bbmap)
2a8b3fdf
DC
526 write_cur_bbs();
527 else
528 write_cur_buf();
b64af2c4
ES
529
530 /* If we didn't write the crc automatically, re-check inode validity */
2660e653 531 if (xfs_has_crc(mp) &&
b64af2c4 532 skip_crc && iocur_top->ino_buf) {
3c73a9a1 533 iocur_top->ino_crc_ok = libxfs_verify_cksum(iocur_top->data,
b64af2c4
ES
534 mp->m_sb.sb_inodesize,
535 XFS_DINODE_CRC_OFF);
536 }
537
2a8b3fdf
DC
538}
539
0323bbf6
CB
540static void
541__set_cur(
542 struct xfs_buftarg *btargp,
543 const typ_t *type,
544 xfs_daddr_t blknum,
545 int len,
546 int ring_flag,
547 bbmap_t *bbmap)
2bd0ea18 548{
0323bbf6
CB
549 struct xfs_buf *bp;
550 xfs_ino_t dirino;
551 xfs_ino_t ino;
552 uint16_t mode;
db23e0f4 553 const struct xfs_buf_ops *ops = type ? type->bops : NULL;
f4afdcb0 554 int error;
2bd0ea18
NS
555
556 if (iocur_sp < 0) {
9ee7055c 557 dbprintf(_("set_cur no stack element to set\n"));
2bd0ea18
NS
558 return;
559 }
560
2bd0ea18
NS
561 ino = iocur_top->ino;
562 dirino = iocur_top->dirino;
563 mode = iocur_top->mode;
564 pop_cur();
565 push_cur();
2a8b3fdf
DC
566
567 if (bbmap) {
857592d2 568#ifdef DEBUG_BBMAP
72298d16 569 int i;
db23e0f4 570 printf(_("xfs_db got a bbmap for %lld\n"), (long long)blknum);
72298d16
DC
571 printf(_("\tblock map"));
572 for (i = 0; i < bbmap->nmaps; i++)
573 printf(" %lld:%d", (long long)bbmap->b[i].bm_bn,
574 bbmap->b[i].bm_len);
575 printf("\n");
2a8b3fdf 576#endif
72298d16
DC
577 iocur_top->bbmap = malloc(sizeof(struct bbmap));
578 if (!iocur_top->bbmap)
2a8b3fdf 579 return;
72298d16 580 memcpy(iocur_top->bbmap, bbmap, sizeof(struct bbmap));
0323bbf6 581 error = -libxfs_buf_read_map(btargp, bbmap->b,
f4afdcb0
DW
582 bbmap->nmaps, LIBXFS_READBUF_SALVAGE, &bp,
583 ops);
2a8b3fdf 584 } else {
0323bbf6 585 error = -libxfs_buf_read(btargp, blknum, len,
31079e67 586 LIBXFS_READBUF_SALVAGE, &bp, ops);
72298d16 587 iocur_top->bbmap = NULL;
2a8b3fdf 588 }
6fea8f83
DC
589
590 /*
f4afdcb0
DW
591 * Salvage mode means that we still get a buffer even if the verifier
592 * says the metadata is corrupt. Therefore, the only errors we should
593 * get are for IO errors or runtime errors.
6fea8f83 594 */
f4afdcb0 595 if (error)
72298d16
DC
596 return;
597 iocur_top->buf = bp->b_addr;
598 iocur_top->bp = bp;
2cf166bc
ES
599 if (!ops) {
600 bp->b_ops = NULL;
b511ff41 601 bp->b_flags |= LIBXFS_B_UNCHECKED;
2cf166bc 602 }
2a8b3fdf 603
db23e0f4
BD
604 iocur_top->bb = blknum;
605 iocur_top->blen = len;
2bd0ea18
NS
606 iocur_top->boff = 0;
607 iocur_top->data = iocur_top->buf;
db23e0f4
BD
608 iocur_top->len = BBTOB(len);
609 iocur_top->off = blknum << BBSHIFT;
610 iocur_top->typ = cur_typ = type;
2bd0ea18
NS
611 iocur_top->ino = ino;
612 iocur_top->dirino = dirino;
613 iocur_top->mode = mode;
a73b88f2 614 iocur_top->ino_buf = 0;
66a40d02 615 iocur_top->dquot_buf = 0;
2bd0ea18
NS
616
617 /* store location in ring */
618 if (ring_flag)
619 ring_add();
620}
621
0323bbf6
CB
622void
623set_cur(
624 const typ_t *type,
625 xfs_daddr_t blknum,
626 int len,
627 int ring_flag,
628 bbmap_t *bbmap)
629{
630 __set_cur(mp->m_ddev_targp, type, blknum, len, ring_flag, bbmap);
631}
632
633void
634set_log_cur(
635 const typ_t *type,
636 xfs_daddr_t blknum,
637 int len,
638 int ring_flag,
639 bbmap_t *bbmap)
640{
641 if (mp->m_logdev_targp->bt_bdev == mp->m_ddev_targp->bt_bdev) {
642 fprintf(stderr, "no external log specified\n");
643 exitcode = 1;
644 return;
645 }
646
647 __set_cur(mp->m_logdev_targp, type, blknum, len, ring_flag, bbmap);
648}
649
650
9ba69ce2
DC
651void
652set_iocur_type(
db23e0f4 653 const typ_t *type)
9ba69ce2 654{
cdabe556 655 int bb_count = 1; /* type's size in basic blocks */
0d376f6c 656 int boff = iocur_top->boff;
9ba69ce2 657
b1a48c4f
ZL
658 /*
659 * Inodes are special; verifier checks all inodes in the chunk, the
660 * set_cur_inode() will help that
661 */
533d1d22
ES
662 if (type->typnm == TYP_INODE) {
663 xfs_daddr_t b = iocur_top->bb;
b1a48c4f
ZL
664 xfs_agblock_t agbno;
665 xfs_agino_t agino;
533d1d22
ES
666 xfs_ino_t ino;
667
b1a48c4f
ZL
668 agbno = xfs_daddr_to_agbno(mp, b);
669 agino = XFS_OFFBNO_TO_AGINO(mp, agbno,
670 iocur_top->boff / mp->m_sb.sb_inodesize);
671 ino = XFS_AGINO_TO_INO(mp, xfs_daddr_to_agno(mp, b), agino);
533d1d22
ES
672 set_cur_inode(ino);
673 return;
674 }
675
55f224ba 676 /* adjust buffer size for types with fields & hence fsize() */
cdabe556 677 if (type->fields)
db23e0f4 678 bb_count = BTOBB(byteize(fsize(type->fields,
cdabe556
ES
679 iocur_top->data, 0, 0)));
680 set_cur(type, iocur_top->bb, bb_count, DB_RING_IGN, NULL);
0d376f6c 681 set_cur_boff(boff);
9ba69ce2
DC
682}
683
2bd0ea18
NS
684static void
685stack_help(void)
686{
9ee7055c 687 dbprintf(_(
2bd0ea18
NS
688"\n"
689" The stack is used to explicitly store your location and data type\n"
690" for later return. The 'push' operation stores the current address\n"
691" and type on the stack, the 'pop' operation returns you to the\n"
692" position and datatype of the top entry on the stack.\n"
693"\n"
694" The 'stack' allows explicit location saves, see 'ring' for implicit\n"
695" position tracking.\n"
696"\n"
9ee7055c 697 ));
2bd0ea18
NS
698}
699
700/*ARGSUSED*/
701static int
702stack_f(
703 int argc,
704 char **argv)
705{
706 int i;
75ff9c67 707 char tagbuf[14];
2bd0ea18 708
2d9475a4
NS
709 for (i = iocur_sp; i > 0; i--) {
710 snprintf(tagbuf, sizeof(tagbuf), "%d: ", i);
2bd0ea18
NS
711 print_iocur(tagbuf, &iocur_base[i]);
712 }
713 return 0;
714}