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