/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1991, 1993\
The Regents of the University of California. All rights reserved.");
#endif /* not lint */
if (daddr == LFS_UNUSED_DADDR)
printf("%d\tFREE\t%u\t \t\t%ju\n", i, version,
(uintmax_t)nextfree);
else
printf("%d\tINUSE\t%u\t%8jX\t%s\n",
i, version, (intmax_t)daddr,
nextfree == LFS_ORPHAN_NEXTFREE(lfsp) ? "orphan" : "-");
}
/*
* Set the is64 and dobyteswap fields of struct lfs. Note that the
* magic number (and version) fields are necessarily at the same place
* in all superblock versions, so we can read it via u_32 without
* getting confused.
*/
static void
identify(struct lfs *fs)
{
unsigned magic;
/* If that wasn't the real first sb, get the real first sb */
if (lfs_sb_getversion(&lfs_sb1) > 1 &&
lfs_sb_getsboff(&lfs_sb1, 0) > lfs_btofsb(&lfs_sb1, LFS_LABELPAD)) {
get(fd, lfs_fsbtob(&lfs_sb1, lfs_sb_getsboff(&lfs_sb1, 0)),
&lfs_sb1.lfs_dlfs_u, sizeof(struct dlfs));
identify(&lfs_sb1);
}
/*
* Read the second superblock and figure out which check point is
* most up to date.
*/
get(fd,
fsbtobyte(&lfs_sb1, lfs_sb_getsboff(&lfs_sb1, 1)),
sbuf, LFS_SBPAD);
memcpy(&lfs_sb2.lfs_dlfs_u, sbuf, sizeof(struct dlfs));
identify(&lfs_sb2);
/*
* We are reading all the blocks of an inode and dumping out the ifile table.
* This code could be tighter, but this is a first pass at getting the stuff
* printed out rather than making this code incredibly efficient.
*/
static void
dump_ifile(int fd, struct lfs *lfsp, int do_ientries, int do_segentries, daddr_t addr)
{
char *ipage;
char *dpage;
union lfs_dinode *dip = NULL;
void *dindir, *indir;
unsigned offset;
daddr_t thisblock;
daddr_t pdb;
int block_limit, i, inum, j, nblocks, psize;
psize = lfs_sb_getbsize(lfsp);
if (!addr)
addr = lfs_sb_getidaddr(lfsp);
/* Get the direct block */
ipage = emalloc(psize);
for (inum = 0, i = 0; i < block_limit; i++) {
pdb = lfs_dino_getdb(lfsp, dip, i);
get(fd, fsbtobyte(lfsp, pdb), ipage, psize);
if (i < lfs_sb_getcleansz(lfsp)) {
dump_cleaner_info(lfsp, ipage);
if (do_segentries)
print_suheader;
continue;
}
if (i < (lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp))) {
if (do_segentries)
inum = dump_ipage_segusage(lfsp, inum, ipage,
lfs_sb_getsepb(lfsp));
else
inum = (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp) - 1);
if (!inum) {
if(!do_ientries)
goto e0;
else
print_iheader;
}
} else
inum = dump_ipage_ifile(lfsp, inum, ipage, lfs_sb_getifpb(lfsp));
}
if (nblocks <= ULFS_NDADDR)
goto e0;
/* Dump out blocks off of single indirect block */
indir = emalloc(psize);
get(fd, fsbtobyte(lfsp, lfs_dino_getib(lfsp, dip, 0)), indir, psize);
block_limit = MIN(i + lfs_sb_getnindir(lfsp), nblocks);
for (offset = 0; i < block_limit; i++, offset++) {
thisblock = lfs_iblock_get(lfsp, indir, offset);
if (thisblock == LFS_UNUSED_DADDR)
break;
get(fd, fsbtobyte(lfsp, thisblock), ipage, psize);
if (i < lfs_sb_getcleansz(lfsp)) {
dump_cleaner_info(lfsp, ipage);
continue;
}
if (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp)) {
if (do_segentries)
inum = dump_ipage_segusage(lfsp, inum, ipage,
lfs_sb_getsepb(lfsp));
else
inum = (i < lfs_sb_getsegtabsz(lfsp) + lfs_sb_getcleansz(lfsp) - 1);
if (!inum) {
if(!do_ientries)
goto e1;
else
print_iheader;
}
} else
inum = dump_ipage_ifile(lfsp, inum, ipage, lfs_sb_getifpb(lfsp));
}
if (nblocks <= ULFS_NDADDR + lfs_sb_getnindir(lfsp))
goto e1;
/* Get the double indirect block */
dindir = emalloc(psize);
get(fd, fsbtobyte(lfsp, lfs_dino_getib(lfsp, dip, 1)), dindir, psize);
for (j = 0; j < lfs_sb_getnindir(lfsp); j++) {
thisblock = lfs_iblock_get(lfsp, dindir, j);
if (thisblock == LFS_UNUSED_DADDR)
break;
get(fd, fsbtobyte(lfsp, thisblock), indir, psize);
block_limit = MIN(i + lfs_sb_getnindir(lfsp), nblocks);
for (offset = 0; i < block_limit; i++, offset++) {
thisblock = lfs_iblock_get(lfsp, indir, offset);
if (thisblock == LFS_UNUSED_DADDR)
break;
get(fd, fsbtobyte(lfsp, thisblock), ipage, psize);
if (i < lfs_sb_getcleansz(lfsp)) {
dump_cleaner_info(lfsp, ipage);
continue;
}
/* Dump out inode disk addresses */
iip = SEGSUM_IINFOSTART(lfsp, sp);
diblock = emalloc(lfs_sb_getbsize(lfsp));
printf(" Inode addresses:");
numbytes = 0;
numblocks = 0;
for (i = 0; i < lfs_ss_getninos(lfsp, sp); iip = NEXTLOWER_IINFO(lfsp, iip)) {
++numblocks;
numbytes += lfs_sb_getibsize(lfsp); /* add bytes for inode block */
printf("\t0x%jx {", (intmax_t)lfs_ii_getblock(lfsp, iip));
get(fd, fsbtobyte(lfsp, lfs_ii_getblock(lfsp, iip)), diblock, lfs_sb_getibsize(lfsp));
for (j = 0; i < lfs_ss_getninos(lfsp, sp) && j < LFS_INOPB(lfsp); j++, i++) {
if (j > 0)
(void)printf(", ");
dip = DINO_IN_BLOCK(lfsp, diblock, j);
(void)printf("%juv%d", lfs_dino_getinumber(lfsp, dip),
lfs_dino_getgen(lfsp, dip));
}
(void)printf("}");
if (((i/LFS_INOPB(lfsp)) % 4) == 3)
(void)printf("\n");
}
free(diblock);
printf("\n");
fp = SEGSUM_FINFOBASE(lfsp, sp);
for (i = 0; i < lfs_ss_getnfinfo(lfsp, sp); i++) {
(void)printf(" FINFO for inode: %ju version %u nblocks %u lastlength %u\n",
(uintmax_t)lfs_fi_getino(lfsp, fp),
lfs_fi_getversion(lfsp, fp),
lfs_fi_getnblocks(lfsp, fp),
lfs_fi_getlastlength(lfsp, fp));
lfs_blocks_fromfinfo(lfsp, &fipblocks, fp);
numblocks += lfs_fi_getnblocks(lfsp, fp);
for (j = 0; j < lfs_fi_getnblocks(lfsp, fp); j++) {
(void)printf("\t%jd",
(intmax_t)lfs_blocks_get(lfsp, &fipblocks, j));
if ((j % 8) == 7)
(void)printf("\n");
if (j == lfs_fi_getnblocks(lfsp, fp) - 1)
numbytes += lfs_fi_getlastlength(lfsp, fp);
else
numbytes += lfs_sb_getbsize(lfsp);
}
if ((j % 8) != 0)
(void)printf("\n");
fp = NEXT_FINFO(lfsp, fp);
}
if (datasum_check == 0)
return (numbytes);
/*
* Now that we know the number of blocks, run back through and
* compute the data checksum. (A bad data checksum is not enough
* to prevent us from continuing, but it does merit a warning.)
*/
iip2 = SEGSUM_IINFOSTART(lfsp, sp);
fp = SEGSUM_FINFOBASE(lfsp, sp);
if (lfs_sb_getversion(lfsp) == 1) {
el_size = sizeof(unsigned long);
} else {
el_size = sizeof(u_int32_t);
}
datap = ecalloc(numblocks, el_size);
acc = 0;
addr += lfs_btofsb(lfsp, lfs_sb_getsumsize(lfsp));
buf = emalloc(lfs_sb_getbsize(lfsp));
for (i = 0; i < lfs_ss_getnfinfo(lfsp, sp); i++) {
while (addr == lfs_ii_getblock(lfsp, iip2)) {
get(fd, fsbtobyte(lfsp, addr), buf, lfs_sb_getibsize(lfsp));
memcpy(datap + acc * el_size, buf, el_size);
addr += lfs_btofsb(lfsp, lfs_sb_getibsize(lfsp));
iip2 = NEXTLOWER_IINFO(lfsp, iip2);
++acc;
}
for (j = 0; j < lfs_fi_getnblocks(lfsp, fp); j++) {
get(fd, fsbtobyte(lfsp, addr), buf, lfs_sb_getfsize(lfsp));
memcpy(datap + acc * el_size, buf, el_size);
if (j == lfs_fi_getnblocks(lfsp, fp) - 1)
addr += lfs_btofsb(lfsp, lfs_fi_getlastlength(lfsp, fp));
else
addr += lfs_btofsb(lfsp, lfs_sb_getbsize(lfsp));
++acc;
}
fp = NEXT_FINFO(lfsp, fp);
}
while (addr == lfs_ii_getblock(lfsp, iip2)) {
get(fd, fsbtobyte(lfsp, addr), buf, lfs_sb_getibsize(lfsp));
memcpy(datap + acc * el_size, buf, el_size);
addr += lfs_btofsb(lfsp, lfs_sb_getibsize(lfsp));
iip2 = NEXTLOWER_IINFO(lfsp, iip2);
++acc;
}
free(buf);
if (acc != numblocks)
printf("** counted %d blocks but should have been %d\n",
acc, numblocks);
datasum = cksum(datap, numblocks * el_size);
if (datasum != lfs_ss_getdatasum(lfsp, sp))
printf("** computed datasum 0x%lx does not match given datasum 0x%lx\n", (unsigned long)datasum, (unsigned long)lfs_ss_getdatasum(lfsp, sp));
free(datap);
(void)printf(" Superblock disk addresses:\n ");
for (i = 0; i < LFS_MAXNUMSB; i++) {
(void)printf(" 0x%-8jx", (intmax_t)lfs_sb_getsboff(lfsp, i));
if (i == (LFS_MAXNUMSB >> 1))
(void)printf("\n ");
}
(void)printf("\n");