diff --git a/sbin/fsdb/fsdb.8 b/sbin/fsdb/fsdb.8 index e5fdd7fa35ac..c046a89a5d5c 100644 --- a/sbin/fsdb/fsdb.8 +++ b/sbin/fsdb/fsdb.8 @@ -109,6 +109,10 @@ This command is valid only if the starting inode is a directory. .It Cm print Print out the active inode. .Pp +.It Cm blocks +Print out the block list of the active inode. +Note that the printout could become long for large files, since all +indirect block pointers will also be printed. .It Cm uplink Increment the active inode's link count. .Pp diff --git a/sbin/fsdb/fsdb.c b/sbin/fsdb/fsdb.c index 85e34f6c7484..5b4bbcd24c96 100644 --- a/sbin/fsdb/fsdb.c +++ b/sbin/fsdb/fsdb.c @@ -125,6 +125,7 @@ main(argc, argv) CMDFUNC(helpfn); CMDFUNC(focus); /* focus on inode */ CMDFUNC(active); /* print active inode */ +CMDFUNC(blocks); /* print blocks for active inode */ CMDFUNC(focusname); /* focus by name */ CMDFUNC(zapi); /* clear inode */ CMDFUNC(uplink); /* incr link */ @@ -158,6 +159,7 @@ struct cmdtable cmds[] = { { "back", "Go to previous active inode", 1, 1, FL_RO, back }, { "active", "Print active inode", 1, 1, FL_RO, active }, { "print", "Print active inode", 1, 1, FL_RO, active }, + { "blocks", "Print block numbers of active inode", 1, 1, FL_RO, blocks }, { "uplink", "Increment link count", 1, 1, FL_WR, uplink }, { "downlink", "Decrement link count", 1, 1, FL_WR, downlink }, { "linkcount", "Set link count to COUNT", 2, 2, FL_WR, linkcount }, @@ -224,7 +226,7 @@ cmdloop() curinode = ginode(ROOTINO); curinum = ROOTINO; - printactive(); + printactive(0); hist = history_init(); history(hist, &he, H_EVENT, 100); /* 100 elt history buffer */ @@ -307,7 +309,7 @@ CMDFUNCSTART(focus) curinode = ginode(inum); ocurrent = curinum; curinum = inum; - printactive(); + printactive(0); return 0; } @@ -315,7 +317,7 @@ CMDFUNCSTART(back) { curinum = ocurrent; curinode = ginode(curinum); - printactive(); + printactive(0); return 0; } @@ -336,10 +338,15 @@ CMDFUNCSTART(zapi) CMDFUNCSTART(active) { - printactive(); + printactive(0); return 0; } +CMDFUNCSTART(blocks) +{ + printactive(1); + return 0; +} CMDFUNCSTART(quit) { @@ -431,7 +438,7 @@ dolookup(name) if (ckinode(curinode, &idesc) & FOUND) { curinum = idesc.id_parent; curinode = ginode(curinum); - printactive(); + printactive(0); return 1; } else { warnx("name `%s' not found in current inode directory", name); @@ -639,7 +646,7 @@ CMDFUNCSTART(newtype) curinode->di_mode &= ~IFMT; curinode->di_mode |= type; inodirty(); - printactive(); + printactive(0); return 0; } @@ -660,7 +667,7 @@ CMDFUNCSTART(chlen) curinode->di_size = len; inodirty(); - printactive(); + printactive(0); return rval; } @@ -682,7 +689,7 @@ CMDFUNCSTART(chmode) curinode->di_mode &= ~07777; curinode->di_mode |= modebits; inodirty(); - printactive(); + printactive(0); return rval; } @@ -707,7 +714,7 @@ CMDFUNCSTART(chaflags) } curinode->di_flags = flags; inodirty(); - printactive(); + printactive(0); return rval; } @@ -732,7 +739,7 @@ CMDFUNCSTART(chgen) } curinode->di_gen = gen; inodirty(); - printactive(); + printactive(0); return rval; } @@ -757,7 +764,7 @@ CMDFUNCSTART(linkcount) curinode->di_nlink = lcnt; inodirty(); - printactive(); + printactive(0); return rval; } @@ -784,7 +791,7 @@ CMDFUNCSTART(chowner) curinode->di_uid = uid; inodirty(); - printactive(); + printactive(0); return rval; } @@ -810,7 +817,7 @@ CMDFUNCSTART(chgroup) curinode->di_gid = gid; inodirty(); - printactive(); + printactive(0); return rval; } @@ -876,7 +883,7 @@ CMDFUNCSTART(chmtime) if (dotime(argv[1], &curinode->di_ctime)) return 1; inodirty(); - printactive(); + printactive(0); return 0; } @@ -885,7 +892,7 @@ CMDFUNCSTART(chatime) if (dotime(argv[1], &curinode->di_ctime)) return 1; inodirty(); - printactive(); + printactive(0); return 0; } @@ -894,6 +901,6 @@ CMDFUNCSTART(chctime) if (dotime(argv[1], &curinode->di_ctime)) return 1; inodirty(); - printactive(); + printactive(0); return 0; } diff --git a/sbin/fsdb/fsdb.h b/sbin/fsdb/fsdb.h index d884f17da255..7f2bc2e9d14b 100644 --- a/sbin/fsdb/fsdb.h +++ b/sbin/fsdb/fsdb.h @@ -57,6 +57,6 @@ int argcount __P((struct cmdtable *cmdp, int argc, char *argv[])); char **crack __P((char *line, int *argc)); char **recrack __P((char *line, int *argc, int argc_max)); void printstat __P((const char *cp, ino_t inum, struct dinode *dp)); -int printactive __P((void)); +int printactive __P((int doblocks)); int checkactive __P((void)); int checkactivedir __P((void)); diff --git a/sbin/fsdb/fsdbutil.c b/sbin/fsdb/fsdbutil.c index 76edbc2693cf..311be9eecdc9 100644 --- a/sbin/fsdb/fsdbutil.c +++ b/sbin/fsdb/fsdbutil.c @@ -44,9 +44,15 @@ static const char rcsid[] = #include #include +#include + #include "fsdb.h" #include "fsck.h" +static int charsperline __P((void)); +static int printindir __P((ufs_daddr_t blk, int level, char *bufp)); +static void printblocks __P((ino_t inum, struct dinode *dp)); + char ** crack(line, argc) char *line; @@ -176,6 +182,130 @@ printstat(cp, inum, dp) dp->di_blocks, dp->di_gen); } + +/* + * Determine the number of characters in a + * single line. + */ + +static int +charsperline() +{ + int columns; + char *cp; + struct winsize ws; + + columns = 0; + if (ioctl(0, TIOCGWINSZ, &ws) != -1) + columns = ws.ws_col; + if (columns == 0 && (cp = getenv("COLUMNS"))) + columns = atoi(cp); + if (columns == 0) + columns = 80; /* last resort */ + return (columns); +} + + +/* + * Recursively print a list of indirect blocks. + */ +static int +printindir(blk, level, bufp) + ufs_daddr_t blk; + int level; + char *bufp; +{ + struct bufarea buf, *bp; + char tempbuf[32]; /* enough to print an ufs_daddr_t */ + int i, j, cpl, charssofar; + ufs_daddr_t blkno; + + if (level == 0) { + /* for the final indirect level, don't use the cache */ + bp = &buf; + bp->b_un.b_buf = bufp; + bp->b_prev = bp->b_next = bp; + initbarea(bp); + + getblk(bp, blk, sblock.fs_bsize); + } else + bp = getdatablk(blk, sblock.fs_bsize); + + cpl = charsperline(); + for (i = charssofar = 0; i < NINDIR(&sblock); i++) { + blkno = bp->b_un.b_indir[i]; + if (blkno == 0) { + if (level == 0) + putchar('\n'); + return 0; + } + j = sprintf(tempbuf, "%d", blkno); + if (level == 0) { + charssofar += j; + if (charssofar >= cpl - 2) { + putchar('\n'); + charssofar = j; + } + } + fputs(tempbuf, stdout); + if (level == 0) { + printf(", "); + charssofar += 2; + } else { + printf(" =>\n"); + if (printindir(blkno, level - 1, bufp) == 0) + return 0; + } + } + if (level == 0) + putchar('\n'); + return 1; +} + + +/* + * Print the block pointers for one inode. + */ +static void +printblocks(inum, dp) + ino_t inum; + struct dinode *dp; +{ + char *bufp; + int i, j, nfrags; + long ndb, offset; + + printf("Blocks for inode %d:\n", inum); + printf("Direct blocks:\n"); + ndb = howmany(dp->di_size, sblock.fs_bsize); + for (i = 0; i < NDADDR; i++) { + if (dp->di_db[i] == 0) { + putchar('\n'); + return; + } + if (i > 0) + printf(", "); + printf("%d", dp->di_db[i]); + if (--ndb == 0 && (offset = blkoff(&sblock, dp->di_size)) != 0) { + nfrags = numfrags(&sblock, fragroundup(&sblock, offset)); + printf(" (%d frag%s)", nfrags, nfrags > 1? "s": ""); + } + } + putchar('\n'); + if (dp->di_ib[0] == 0) + return; + + bufp = malloc((unsigned int)sblock.fs_bsize); + if (bufp == 0) + errx(EEXIT, "cannot allocate indirect block buffer"); + printf("Indirect blocks:\n"); + for (i = 0; i < NIADDR; i++) + if (printindir(dp->di_ib[i], i, bufp) == 0) + break; + free(bufp); +} + + int checkactive() { @@ -201,7 +331,8 @@ checkactivedir() } int -printactive() +printactive(doblocks) + int doblocks; { if (!checkactive()) return 1; @@ -213,7 +344,10 @@ printactive() case IFLNK: case IFSOCK: case IFIFO: - printstat("current inode", curinum, curinode); + if (doblocks) + printblocks(curinum, curinode); + else + printstat("current inode", curinum, curinode); break; case 0: printf("current inode %d: unallocated inode\n", curinum);