~ubuntu-branches/ubuntu/utopic/xfsprogs/utopic-proposed

« back to all changes in this revision

Viewing changes to db/io.c

  • Committer: Bazaar Package Importer
  • Author(s): Nathan Scott
  • Date: 2002-04-13 09:45:06 UTC
  • Revision ID: james.westby@ubuntu.com-20020413094506-t8dhemv41gkeg4kx
Tags: 2.0.3-1
New upstream bugfix release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}