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