]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/io.c
xfsprogs: add missing periods in CHANGES
[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 "pop location from the stack", pop_help };
47 static const cmdinfo_t push_cmd =
48 { "push", NULL, push_f, 0, 2, 0, "[command]",
49 "push location to the stack", push_help };
50 static const cmdinfo_t stack_cmd =
51 { "stack", NULL, stack_f, 0, 0, 0, NULL,
52 "view the location stack", stack_help };
53 static const cmdinfo_t forward_cmd =
54 { "forward", "f", forward_f, 0, 0, 0, NULL,
55 "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 "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 "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->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*/
119 static int
120 pop_f(
121 int argc,
122 char **argv)
123 {
124 pop_cur();
125 return 0;
126 }
127
128 static void
129 pop_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
138 void
139 print_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
160 void
161 print_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
197 void
198 push_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
214 static int
215 push_f(
216 int argc,
217 char **argv)
218 {
219 const cmdinfo_t *ct;
220
221 if (argc > 1) {
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();
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,
240 iocur_top[-1].blen, DB_RING_IGN,
241 iocur_top[-1].use_bbmap ? &iocur_top[-1].bbmap : NULL);
242
243 /* run requested command */
244 if (argc>1)
245 (void)command(argc-1, argv+1);
246 return 0;
247 }
248
249 static void
250 push_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 */
263 static int
264 forward_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
289 static void
290 forward_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 */
304 static int
305 back_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
330 static void
331 back_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 */
343 static int
344 ring_f(
345 int argc,
346 char **argv)
347 {
348 int index;
349
350 if (argc == 1) {
351 print_ring();
352 return 0;
353 }
354
355 index = (int)strtoul(argv[1], NULL, 0);
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
370 static void
371 ring_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
397 void
398 ring_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
421 int
422 write_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];
436 if (lseek64(x.dfd, bbno << BBSHIFT, SEEK_SET) < 0) {
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);
442 i = (int)write(x.dfd, (char *)bufp + BBTOB(j), c);
443 if (i < 0) {
444 rval = errno;
445 } else if (i < c) {
446 rval = -1;
447 } else
448 rval = 0;
449 if (rval)
450 break;
451 }
452 return rval;
453 }
454
455 int
456 read_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;
467
468 if (count <= 0)
469 count = 1;
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];
479 if (lseek64(x.dfd, bbno << BBSHIFT, SEEK_SET) < 0) {
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);
487 i = (int)read(x.dfd, (char *)buf + BBTOB(j), c);
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;
498 } else
499 rval = 0;
500 }
501 if (buf == NULL)
502 break;
503 }
504 if (*bufp == NULL)
505 *bufp = buf;
506 return rval;
507 }
508
509 void
510 write_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)
521 dbprintf("incomplete write, block: %lld\n",
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
535 void
536 set_cur(
537 const typ_t *t,
538 __int64_t d,
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)
554 printf("xfs_db got a bbmap for %lld\n", (long long)d);
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;
573 if ((iocur_top->use_bbmap = (bbmap != NULL)))
574 iocur_top->bbmap = *bbmap;
575
576 /* store location in ring */
577 if (ring_flag)
578 ring_add();
579 }
580
581 static void
582 stack_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*/
598 static int
599 stack_f(
600 int argc,
601 char **argv)
602 {
603 int i;
604 char tagbuf[8];
605
606 for (i = iocur_sp; i > 0; i--) {
607 snprintf(tagbuf, sizeof(tagbuf), "%d: ", i);
608 print_iocur(tagbuf, &iocur_base[i]);
609 }
610 return 0;
611 }