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