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