* Copyright (c) 1992 The Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)library.c 5.5 (Berkeley) %G%";
#include <ufs/ufs/dinode.h>
void add_blocks
__P((FS_INFO
*, BLOCK_INFO
*, int *, SEGSUM
*, caddr_t
,
void add_inodes
__P((FS_INFO
*, BLOCK_INFO
*, int *, SEGSUM
*, caddr_t
,
int bi_compare
__P((const void *, const void *));
int bi_toss
__P((const void *, const void *, const void *));
void get_ifile
__P((FS_INFO
*));
int get_superblock
__P((FS_INFO
*, struct lfs
*));
int pseg_valid
__P((FS_INFO
*, SEGSUM
*));
* This function will get information on all mounted file systems
tcount
= getmntinfo(&tstatfsp
, MNT_NOWAIT
);
err(0, "getmntinfo failed");
for (count
= 0, i
= 0; i
< tcount
; ++i
)
if (tstatfsp
[i
].f_type
== type
)
if (!(*buf
= (struct statfs
*)
malloc(count
* sizeof(struct statfs
))))
err(1, "fs_getmntinfo: out of space");
for (i
= 0, sbp
= *buf
; i
< tcount
; ++i
) {
if (tstatfsp
[i
].f_type
== type
) {
* Get all the information available on an LFS file system.
* Returns an array of FS_INFO structures, NULL on error.
get_fs_info (lstatfsp
, count
)
struct statfs
*lstatfsp
; /* IN: array of statfs structs */
int count
; /* IN: number of file systems */
fsp
= (FS_INFO
*)malloc(count
* sizeof(FS_INFO
));
for (fp
= fsp
, i
= 0; i
< count
; ++i
, ++fp
) {
fp
->fi_statfsp
= lstatfsp
++;
if (get_superblock (fp
, &fp
->fi_lfs
))
err(1, "get_fs_info: get_superblock failed");
fp
->fi_lfs
.lfs_bshift
- fp
->fi_lfs
.lfs_fsbtodb
;
* If we are reading the ifile then we need to refresh it. Even if
* we are mmapping it, it might have grown. Finally, we need to
* refresh the file system information (statfs) info.
reread_fs_info(fsp
, count
)
FS_INFO
*fsp
; /* IN: array of fs_infos to free */
int count
; /* IN: number of file systems */
for (i
= 0; i
< count
; ++i
, ++fsp
) {
if (statfs(fsp
->fi_statfsp
->f_mntonname
, fsp
->fi_statfsp
))
err(0, "reread_fs_info: statfs failed");
if (munmap(fsp
->fi_cip
, fsp
->fi_ifile_length
) < 0)
err(0, "reread_fs_info: munmap failed");
* Gets the superblock from disk (possibly in face of errors)
get_superblock (fsp
, sbp
)
FS_INFO
*fsp
; /* local file system info structure */
char mntfromname
[MNAMELEN
+1];
strcpy(mntfromname
, "/dev/r");
strcat(mntfromname
, fsp
->fi_statfsp
->f_mntfromname
+5);
if ((fid
= open(mntfromname
, O_RDONLY
, (mode_t
)0)) < 0) {
err(0, "get_superblock: bad open");
get(fid
, LFS_LABELPAD
, sbp
, sizeof(struct lfs
));
* This function will map the ifile into memory. It causes a
* fatal error on failure.
ifile_name
= malloc(strlen(fsp
->fi_statfsp
->f_mntonname
) +
strcat(strcat(strcpy(ifile_name
, fsp
->fi_statfsp
->f_mntonname
), "/"),
if ((fid
= open(ifile_name
, O_RDWR
, (mode_t
)0)) < 0)
err(1, "get_ifile: bad open");
if (fstat (fid
, &file_stat
))
err(1, "get_ifile: fstat failed");
fsp
->fi_ifile_length
= file_stat
.st_size
;
if (!(ifp
= malloc ((size_t)fsp
->fi_ifile_length
)))
err (1, "get_ifile: malloc failed");
count
= read (fid
, ifp
, (size_t) fsp
->fi_ifile_length
);
err(1, "get_ifile: bad ifile read");
else if (count
< (int)fsp
->fi_ifile_length
) {
if (lseek(fid
, 0, SEEK_SET
) < 0)
err(1, "get_ifile: bad ifile lseek");
ifp
= mmap ((caddr_t
)0, (size_t) fsp
->fi_ifile_length
, PROT_READ
|PROT_WRITE
,
MAP_FILE
|MAP_SHARED
, fid
, (off_t
)0);
err(1, "get_ifile: mmap failed");
fsp
->fi_cip
= (CLEANERINFO
*)ifp
;
fsp
->fi_segusep
= (SEGUSE
*)(ifp
+ CLEANSIZE(fsp
));
fsp
->fi_ifilep
= (IFILE
*)((caddr_t
)fsp
->fi_segusep
+ SEGTABSIZE(fsp
));
* The number of ifile entries is equal to the number of blocks
* blocks in the ifile minus the ones allocated to cleaner info
* and segment usage table multiplied by the number of ifile
fsp
->fi_ifile_count
= (fsp
->fi_ifile_length
>> fsp
->fi_lfs
.lfs_bshift
-
fsp
->fi_lfs
.lfs_cleansz
- fsp
->fi_lfs
.lfs_segtabsz
) *
* This function will scan a segment and return a list of
* <inode, blocknum> pairs which indicate which blocks were
* contained as live data within the segment when the segment
* summary was read (it may have "died" since then). Any given
* pair will be listed at most once.
lfs_segmapv(fsp
, seg
, seg_buf
, blocks
, bcount
)
FS_INFO
*fsp
; /* pointer to local file system information */
int seg
; /* the segment number */
caddr_t seg_buf
; /* the buffer containing the segment's data */
BLOCK_INFO
**blocks
; /* OUT: array of block_info for live blocks */
int *bcount
; /* OUT: number of active blocks in segment */
daddr_t pseg_addr
, seg_addr
;
nelem
= 2 * lfsp
->lfs_ssize
;
if (!(bip
= malloc(nelem
* sizeof(BLOCK_INFO
))))
sup
= SEGUSE_ENTRY(lfsp
, fsp
->fi_segusep
, seg
);
s
= seg_buf
+ (sup
->su_flags
& SEGUSE_SUPERBLOCK
? LFS_SBPAD
: 0);
seg_addr
= sntoda(lfsp
, seg
);
pseg_addr
= seg_addr
+ (sup
->su_flags
& SEGUSE_SUPERBLOCK
? btodb(LFS_SBPAD
) : 0);
printf("\tsegment buffer at: 0x%x\tseg_addr 0x%x\n", s
, seg_addr
);
for (segend
= seg_buf
+ seg_size(lfsp
), timestamp
= 0; s
< segend
; ) {
printf("\tpartial at: 0x%x\n", pseg_addr
);
nblocks
= pseg_valid(fsp
, sp
);
/* Check if we have hit old data */
if (timestamp
> ((SEGSUM
*)s
)->ss_create
)
timestamp
= ((SEGSUM
*)s
)->ss_create
;
if (*bcount
+ nblocks
+ sp
->ss_ninos
> nelem
) {
nelem
= *bcount
+ nblocks
+ sp
->ss_ninos
;
bip
= realloc (bip
, nelem
* sizeof(BLOCK_INFO
));
add_blocks(fsp
, bip
, bcount
, sp
, seg_buf
, seg_addr
, pseg_addr
);
add_inodes(fsp
, bip
, bcount
, sp
, seg_buf
, seg_addr
);
pseg_addr
+= fsbtodb(lfsp
, nblocks
) +
bytetoda(fsp
, LFS_SUMMARY_SIZE
);
s
+= (nblocks
<< lfsp
->lfs_bshift
) + LFS_SUMMARY_SIZE
;
qsort(bip
, *bcount
, sizeof(BLOCK_INFO
), bi_compare
);
toss(bip
, bcount
, sizeof(BLOCK_INFO
), bi_toss
, NULL
);
for (_bip
= bip
, i
=0; i
< *bcount
; ++_bip
, ++i
)
* This will parse a partial segment and fill in BLOCK_INFO structures
* for each block described in the segment summary. It will not include
* blocks or inodes from files with new version numbers.
add_blocks (fsp
, bip
, countp
, sp
, seg_buf
, segaddr
, psegaddr
)
FS_INFO
*fsp
; /* pointer to super block */
BLOCK_INFO
*bip
; /* Block info array */
int *countp
; /* IN/OUT: number of blocks in array */
SEGSUM
*sp
; /* segment summmary pointer */
caddr_t seg_buf
; /* buffer containing segment */
daddr_t segaddr
; /* address of this segment */
daddr_t psegaddr
; /* address of this partial segment */
db_per_block
= fsbtodb(&fsp
->fi_lfs
, 1);
page_size
= fsp
->fi_lfs
.lfs_bsize
;
bp
= seg_buf
+ datobyte(fsp
, psegaddr
- segaddr
) + LFS_SUMMARY_SIZE
;
psegaddr
+= bytetoda(fsp
, LFS_SUMMARY_SIZE
);
iaddrp
= (daddr_t
*)((caddr_t
)sp
+ LFS_SUMMARY_SIZE
);
for (fip
= (FINFO
*)(sp
+ 1), i
= 0; i
< sp
->ss_nfinfo
;
++i
, fip
= (FINFO
*)(&fip
->fi_blocks
[fip
->fi_nblocks
])) {
ifp
= IFILE_ENTRY(&fsp
->fi_lfs
, fsp
->fi_ifilep
, fip
->fi_ino
);
if (ifp
->if_version
> fip
->fi_version
)
dp
= &(fip
->fi_blocks
[0]);
for (j
= 0; j
< fip
->fi_nblocks
; j
++, dp
++) {
while (psegaddr
== *iaddrp
) {
psegaddr
+= db_per_block
;
bip
->bi_inode
= fip
->fi_ino
;
bip
->bi_daddr
= psegaddr
;
bip
->bi_segcreate
= (time_t)(sp
->ss_create
);
bip
->bi_version
= ifp
->if_version
;
psegaddr
+= db_per_block
;
* For a particular segment summary, reads the inode blocks and adds
* INODE_INFO structures to the array. Returns the number of inodes
add_inodes (fsp
, bip
, countp
, sp
, seg_buf
, seg_addr
)
FS_INFO
*fsp
; /* pointer to super block */
BLOCK_INFO
*bip
; /* block info array */
int *countp
; /* pointer to current number of inodes */
SEGSUM
*sp
; /* segsum pointer */
caddr_t seg_buf
; /* the buffer containing the segment's data */
daddr_t seg_addr
; /* disk address of seg_buf */
(void) printf("INODES:\n");
daddrp
= (daddr_t
*)((caddr_t
)sp
+ LFS_SUMMARY_SIZE
);
for (i
= 0; i
< sp
->ss_ninos
; ++i
) {
if (i
% INOPB(lfsp
) == 0) {
di
= (struct dinode
*)(seg_buf
+
((*daddrp
- seg_addr
) << fsp
->fi_daddr_shift
));
bp
->bi_lbn
= LFS_UNUSED_LBN
;
bp
->bi_segcreate
= sp
->ss_create
;
if (inum
== LFS_IFILE_INUM
) {
bp
->bi_version
= 1; /* Ifile version should be 1 */
ifp
= IFILE_ENTRY(lfsp
, fsp
->fi_ifilep
, inum
);
PRINT_INODE(ifp
->if_daddr
== *daddrp
, bp
);
bp
->bi_version
= ifp
->if_version
;
if (ifp
->if_daddr
== *daddrp
) {
* Checks the summary checksum and the data checksum to determine if the
* segment is valid or not. Returns the size of the partial segment if it
* is valid, * and 0 otherwise. Use dump_summary to figure out size of the
* the partial as well as whether or not the checksum is valid.
FS_INFO
*fsp
; /* pointer to file system info */
SEGSUM
*ssp
; /* pointer to segment summary block */
if ((nblocks
= dump_summary(&fsp
->fi_lfs
, ssp
, 0, NULL
)) <= 0)
/* check data/inode block(s) checksum too */
datap
= (u_long
*)malloc(nblocks
* sizeof(u_long
));
p
= (caddr_t
)ssp
+ LFS_SUMMARY_SIZE
;
for (i
= 0; i
< nblocks
; ++i
) {
datap
[i
] = *((u_long
*)p
);
p
+= fsp
->fi_lfs
.lfs_bsize
;
if (cksum ((void *)datap
, nblocks
* sizeof(u_long
)) != ssp
->ss_datasum
)
/* #define MMAP_SEGMENT */
* read a segment into a memory buffer
mmap_segment (fsp
, segment
, segbuf
)
FS_INFO
*fsp
; /* file system information */
int segment
; /* segment number */
caddr_t
*segbuf
; /* pointer to buffer area */
int fid
; /* fildes for file system device */
daddr_t seg_daddr
; /* base disk address of segment */
char mntfromname
[MNAMELEN
+2];
/* get the disk address of the beginning of the segment */
seg_daddr
= sntoda(lfsp
, segment
);
seg_byte
= datobyte(fsp
, seg_daddr
);
strcpy(mntfromname
, "/dev/r");
strcat(mntfromname
, fsp
->fi_statfsp
->f_mntfromname
+5);
if ((fid
= open(mntfromname
, O_RDONLY
, (mode_t
)0)) < 0) {
err(0, "mmap_segment: bad open");
*segbuf
= mmap ((caddr_t
)0, seg_size(lfsp
), PROT_READ
,
MAP_FILE
, fid
, seg_byte
);
if (*(long *)segbuf
< 0) {
err(0, "mmap_segment: mmap failed");
printf("mmap_segment\tseg_daddr: %lu\tseg_size: %lu\tseg_offset: %qu\n",
seg_daddr
, ssize
, seg_byte
);
/* malloc the space for the buffer */
err(0, "mmap_segment: malloc failed");
/* read the segment data into the buffer */
if (lseek (fid
, seg_byte
, SEEK_SET
) != seg_byte
) {
err (0, "mmap_segment: bad lseek");
if (read (fid
, *segbuf
, ssize
) != ssize
) {
err (0, "mmap_segment: bad read");
#endif /* MMAP_SEGMENT */
munmap_segment (fsp
, seg_buf
)
FS_INFO
*fsp
; /* file system information */
caddr_t seg_buf
; /* pointer to buffer area */
munmap (seg_buf
, seg_size(&fsp
->fi_lfs
));
#endif /* MMAP_SEGMENT */
* USEFUL DEBUGGING TOOLS:
(void) dump_summary(lfsp
, p
, DUMP_ALL
, NULL
);
const BLOCK_INFO
*ba
, *bb
;
if (diff
= (int)(ba
->bi_inode
- bb
->bi_inode
))
if (diff
= (int)(ba
->bi_lbn
- bb
->bi_lbn
)) {
if (ba
->bi_lbn
== LFS_UNUSED_LBN
)
else if (bb
->bi_lbn
== LFS_UNUSED_LBN
)
if (diff
= (int)(ba
->bi_segcreate
- bb
->bi_segcreate
))
diff
= (int)(ba
->bi_daddr
- bb
->bi_daddr
);
const BLOCK_INFO
*ba
, *bb
;
return(ba
->bi_inode
== bb
->bi_inode
&& ba
->bi_lbn
== bb
->bi_lbn
);
toss(p
, nump
, size
, dotoss
, client
)
int (*dotoss
) __P((const void *, const void *, const void *));
for (i
= *nump
; --i
> 0;) {
if (dotoss(client
, p
, p1
)) {