]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/io.c
progs: clean up libxfs.h includes
[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 "xfs/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
31 static int pop_f(int argc, char **argv);
32 static void pop_help(void);
33 static int push_f(int argc, char **argv);
34 static void push_help(void);
35 static int stack_f(int argc, char **argv);
36 static void stack_help(void);
37 static int forward_f(int argc, char **argv);
38 static void forward_help(void);
39 static int back_f(int argc, char **argv);
40 static void back_help(void);
41 static int ring_f(int argc, char **argv);
42 static void ring_help(void);
43
44 static const cmdinfo_t pop_cmd =
45 { "pop", NULL, pop_f, 0, 0, 0, NULL,
46 N_("pop location from the stack"), pop_help };
47 static const cmdinfo_t push_cmd =
48 { "push", NULL, push_f, 0, 2, 0, N_("[command]"),
49 N_("push location to the stack"), push_help };
50 static const cmdinfo_t stack_cmd =
51 { "stack", NULL, stack_f, 0, 0, 0, NULL,
52 N_("view the location stack"), stack_help };
53 static const cmdinfo_t forward_cmd =
54 { "forward", "f", forward_f, 0, 0, 0, NULL,
55 N_("move forward to next entry in the position ring"), forward_help };
56 static const cmdinfo_t back_cmd =
57 { "back", "b", back_f, 0, 0, 0, NULL,
58 N_("move to the previous location in the position ring"), back_help };
59 static const cmdinfo_t ring_cmd =
60 { "ring", NULL, ring_f, 0, 1, 0, NULL,
61 N_("show position ring or move to a specific entry"), ring_help };
62
63 iocur_t *iocur_base;
64 iocur_t *iocur_top;
65 int iocur_sp = -1;
66 int iocur_len;
67
68 #define RING_ENTRIES 20
69 static iocur_t iocur_ring[RING_ENTRIES];
70 static int ring_head = -1;
71 static int ring_tail = -1;
72 static int ring_current = -1;
73
74 void
75 io_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
85 void
86 off_cur(
87 int off,
88 int len)
89 {
90 if (iocur_top == NULL || off + len > BBTOB(iocur_top->blen))
91 dbprintf(_("can't set block offset to %d\n"), off);
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
100 void
101 pop_cur(void)
102 {
103 if (iocur_sp < 0) {
104 dbprintf(_("can't pop anything from I/O stack\n"));
105 return;
106 }
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 }
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*/
125 static int
126 pop_f(
127 int argc,
128 char **argv)
129 {
130 pop_cur();
131 return 0;
132 }
133
134 static void
135 pop_help(void)
136 {
137 dbprintf(_(
138 "\n"
139 " Changes the address and data type to the first entry on the stack.\n"
140 "\n"
141 ));
142 }
143
144 void
145 print_iocur(
146 char *tag,
147 iocur_t *ioc)
148 {
149 int i;
150
151 dbprintf("%s\n", tag);
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,
154 (xfs_fsblock_t)XFS_DADDR_TO_FSB(mp, ioc->bb), ioc->blen,
155 ioc->blen == 1 ? "" : "s");
156 if (ioc->bbmap) {
157 dbprintf(_("\tblock map"));
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);
161 dbprintf("\n");
162 }
163 dbprintf(_("\tinode %lld, dir inode %lld, type %s\n"), ioc->ino,
164 ioc->dirino, ioc->typ == NULL ? _("none") : ioc->typ->name);
165 }
166
167 void
168 print_ring(void)
169 {
170 int i;
171 iocur_t *ioc;
172
173 if (ring_current == -1) {
174 dbprintf(_("no entries in location ring.\n"));
175 return;
176 }
177
178 dbprintf(_(" type bblock bblen fsbno inode\n"));
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_fsblock_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
204 void
205 push_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
221 static int
222 push_f(
223 int argc,
224 char **argv)
225 {
226 const cmdinfo_t *ct;
227
228 if (argc > 1) {
229 /* check we can execute command */
230 ct = find_command(argv[1]);
231 if (ct == NULL) {
232 dbprintf(_("no such command %s\n"), argv[1]);
233 return 0;
234 }
235 if (!ct->canpush) {
236 dbprintf(_("no push form allowed for %s\n"), argv[1]);
237 return 0;
238 }
239 }
240
241 /* save current state */
242 push_cur();
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,
247 iocur_top[-1].blen, DB_RING_IGN,
248 iocur_top[-1].bbmap);
249
250 /* run requested command */
251 if (argc>1)
252 (void)command(argc-1, argv+1);
253 return 0;
254 }
255
256 static void
257 push_help(void)
258 {
259 dbprintf(_(
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"
265 ));
266 }
267
268 /* move forward through the ring */
269 /* ARGSUSED */
270 static int
271 forward_f(
272 int argc,
273 char **argv)
274 {
275 if (ring_current == -1) {
276 dbprintf(_("ring is empty\n"));
277 return 0;
278 }
279 if (ring_current == ring_head) {
280 dbprintf(_("no further entries\n"));
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,
290 iocur_ring[ring_current].bbmap);
291
292 return 0;
293 }
294
295 static void
296 forward_help(void)
297 {
298 dbprintf(_(
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"
305 ));
306 }
307
308 /* move backwards through the ring */
309 /* ARGSUSED */
310 static int
311 back_f(
312 int argc,
313 char **argv)
314 {
315 if (ring_current == -1) {
316 dbprintf(_("ring is empty\n"));
317 return 0;
318 }
319 if (ring_current == ring_tail) {
320 dbprintf(_("no previous entries\n"));
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,
330 iocur_ring[ring_current].bbmap);
331
332 return 0;
333 }
334
335 static void
336 back_help(void)
337 {
338 dbprintf(_(
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"
344 ));
345 }
346
347 /* show or go to specific point in ring */
348 static int
349 ring_f(
350 int argc,
351 char **argv)
352 {
353 int index;
354
355 if (argc == 1) {
356 print_ring();
357 return 0;
358 }
359
360 index = (int)strtoul(argv[1], NULL, 0);
361 if (index < 0 || index >= RING_ENTRIES) {
362 dbprintf(_("invalid entry: %d\n"), index);
363 return 0;
364 }
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,
372 iocur_ring[index].bbmap);
373
374 return 0;
375 }
376
377 static void
378 ring_help(void)
379 {
380 dbprintf(_(
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"
399 "\n"),
400 RING_ENTRIES);
401 }
402
403
404 void
405 ring_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
427 static void
428 write_cur_buf(void)
429 {
430 int ret;
431
432 ret = -libxfs_writebufr(iocur_top->bp);
433 if (ret != 0)
434 dbprintf(_("write error: %s\n"), strerror(ret));
435
436 /* re-read buffer from disk */
437 ret = -libxfs_readbufr(mp->m_ddev_targp, iocur_top->bb, iocur_top->bp,
438 iocur_top->blen, 0);
439 if (ret != 0)
440 dbprintf(_("read error: %s\n"), strerror(ret));
441 }
442
443 static void
444 write_cur_bbs(void)
445 {
446 int ret;
447
448 ret = -libxfs_writebufr(iocur_top->bp);
449 if (ret != 0)
450 dbprintf(_("write error: %s\n"), strerror(ret));
451
452
453 /* re-read buffer from disk */
454 ret = -libxfs_readbufr_map(mp->m_ddev_targp, iocur_top->bp, 0);
455 if (ret != 0)
456 dbprintf(_("read error: %s\n"), strerror(ret));
457 }
458
459 void
460 xfs_dummy_verify(
461 struct xfs_buf *bp)
462 {
463 return;
464 }
465
466 void
467 write_cur(void)
468 {
469 if (iocur_sp < 0) {
470 dbprintf(_("nothing to write\n"));
471 return;
472 }
473
474 if (xfs_sb_version_hascrc(&mp->m_sb) && iocur_top->ino_buf) {
475 libxfs_dinode_calc_crc(mp, iocur_top->data);
476 iocur_top->ino_crc_ok = 1;
477 }
478 if (iocur_top->dquot_buf)
479 xfs_update_cksum(iocur_top->data, sizeof(struct xfs_dqblk),
480 XFS_DQUOT_CRC_OFF);
481 if (iocur_top->bbmap)
482 write_cur_bbs();
483 else
484 write_cur_buf();
485 }
486
487 void
488 set_cur(
489 const typ_t *t,
490 __int64_t d,
491 int c,
492 int ring_flag,
493 bbmap_t *bbmap)
494 {
495 struct xfs_buf *bp;
496 xfs_ino_t dirino;
497 xfs_ino_t ino;
498 __uint16_t mode;
499 const struct xfs_buf_ops *ops = t ? t->bops : NULL;
500
501 if (iocur_sp < 0) {
502 dbprintf(_("set_cur no stack element to set\n"));
503 return;
504 }
505
506
507 ino = iocur_top->ino;
508 dirino = iocur_top->dirino;
509 mode = iocur_top->mode;
510 pop_cur();
511 push_cur();
512
513 if (bbmap) {
514 #ifdef DEBUG_BBMAP
515 int i;
516 printf(_("xfs_db got a bbmap for %lld\n"), (long long)d);
517 printf(_("\tblock map"));
518 for (i = 0; i < bbmap->nmaps; i++)
519 printf(" %lld:%d", (long long)bbmap->b[i].bm_bn,
520 bbmap->b[i].bm_len);
521 printf("\n");
522 #endif
523 iocur_top->bbmap = malloc(sizeof(struct bbmap));
524 if (!iocur_top->bbmap)
525 return;
526 memcpy(iocur_top->bbmap, bbmap, sizeof(struct bbmap));
527 bp = libxfs_readbuf_map(mp->m_ddev_targp, bbmap->b,
528 bbmap->nmaps, 0, ops);
529 } else {
530 bp = libxfs_readbuf(mp->m_ddev_targp, d, c, 0, ops);
531 iocur_top->bbmap = NULL;
532 }
533
534 /*
535 * Keep the buffer even if the verifier says it is corrupted.
536 * We're a diagnostic tool, after all.
537 */
538 if (!bp || (bp->b_error && bp->b_error != EFSCORRUPTED &&
539 bp->b_error != EFSBADCRC))
540 return;
541 iocur_top->buf = bp->b_addr;
542 iocur_top->bp = bp;
543 if (!ops)
544 bp->b_flags |= LIBXFS_B_UNCHECKED;
545
546 iocur_top->bb = d;
547 iocur_top->blen = c;
548 iocur_top->boff = 0;
549 iocur_top->data = iocur_top->buf;
550 iocur_top->len = BBTOB(c);
551 iocur_top->off = d << BBSHIFT;
552 iocur_top->typ = cur_typ = t;
553 iocur_top->ino = ino;
554 iocur_top->dirino = dirino;
555 iocur_top->mode = mode;
556 iocur_top->ino_buf = 0;
557 iocur_top->dquot_buf = 0;
558
559 /* store location in ring */
560 if (ring_flag)
561 ring_add();
562 }
563
564 void
565 set_iocur_type(
566 const typ_t *t)
567 {
568 struct xfs_buf *bp = iocur_top->bp;
569
570 iocur_top->typ = t;
571
572 /* verify the buffer if the type has one. */
573 if (!bp)
574 return;
575 if (!t->bops) {
576 bp->b_ops = NULL;
577 bp->b_flags |= LIBXFS_B_UNCHECKED;
578 return;
579 }
580 if (!(bp->b_flags & LIBXFS_B_UPTODATE))
581 return;
582 bp->b_error = 0;
583 bp->b_ops = t->bops;
584 bp->b_ops->verify_read(bp);
585 bp->b_flags &= ~LIBXFS_B_UNCHECKED;
586 }
587
588 static void
589 stack_help(void)
590 {
591 dbprintf(_(
592 "\n"
593 " The stack is used to explicitly store your location and data type\n"
594 " for later return. The 'push' operation stores the current address\n"
595 " and type on the stack, the 'pop' operation returns you to the\n"
596 " position and datatype of the top entry on the stack.\n"
597 "\n"
598 " The 'stack' allows explicit location saves, see 'ring' for implicit\n"
599 " position tracking.\n"
600 "\n"
601 ));
602 }
603
604 /*ARGSUSED*/
605 static int
606 stack_f(
607 int argc,
608 char **argv)
609 {
610 int i;
611 char tagbuf[8];
612
613 for (i = iocur_sp; i > 0; i--) {
614 snprintf(tagbuf, sizeof(tagbuf), "%d: ", i);
615 print_iocur(tagbuf, &iocur_base[i]);
616 }
617 return 0;
618 }