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