#include #include #include #include #include #include #include #include #include #include #include #include #include "clean.h" /* * fs_getmntinfo: * * This function will get information on all mounted file systems * of a given type. */ int fs_getmntinfo(buf, type) struct statfs **buf; int type; { int i; int count; int tcount; struct statfs *tstatfsp; tcount = getmntinfo(&tstatfsp, 0); if (tcount < 0) { perror ("fs_getmntinfo: getmntinfo failed"); return -1; } for (count = 0, i = 0 ; i < tcount ; i ++) if (type == 0 || tstatfsp[i].f_type == type) ++ count; if (count > 0) { *buf = (struct statfs *) malloc(count*sizeof(struct statfs)); if (*buf == 0) { perror ("fs_getmntinfo: out of space"); exit (1); } for (i = 0, count = 0 ; i < tcount ; i ++) { if (type == 0 || tstatfsp[i].f_type == type) { (*buf)[count] = tstatfsp[i]; ++count; } } return count; } return 0; } /* * get_fs_info: * * get all the information available on a file system */ int get_fs_info (lstatfsp, fspp, count) struct statfs *lstatfsp; /* IN: array of statfs structs */ FS_INFO **fspp; /* OUT: resulting array of FS_INFOs */ int count; /* IN: number of file systems */ { int i; caddr_t ifp; FS_INFO *fsp; *fspp = (FS_INFO *)malloc(count * sizeof(FS_INFO)); for (i = 0 ; i < count ; i++) { fsp = *fspp + i; statfsp = lstatfsp + i; lfsp = (struct lfs *)malloc (LFS_SBPAD); if (get_superblock (fsp, lfsp) < 0) { perror("get_fs_info: get_superblock failed"); return -1; } fsp->fi_daddr_shift = lfsp->lfs_bshift - lfsp->lfs_fsbtodb; if (get_ifile (fsp) < 0) { perror("get_fs_info: get_ifile failed"); return -1; } } return 0; } /* this is needed temporarily, because of the bug in mmap'ed files */ void free_fs_info (fsp, count) FS_INFO *fsp; /* IN: array of fs_infos we will dispose of */ int count; /* IN: number of file systems */ { int i; caddr_t fsp_base = (caddr_t)fsp; for (i = 0 ; i < count ; i++, fsp++) { /* free superblock */ free (lfsp); /* sdp points to the beginning of the ifile area */ #ifndef MMAP_WORKS free (cip); #else if (munmap (cip, ifile_length) < 0) { perror("free_fs_info: munmap failed\n"); } #endif /* MMAP_WORKS */ } free (fsp_base); } /* * get_superblock: * gets the superblock from disk (possibly in face of errors) */ int get_superblock (fsp, sbp) FS_INFO *fsp; /* IN: array of fs_infos we will dispose of */ struct lfs *sbp; { int fid; char mntfromname[MNAMELEN+1]; strcpy(mntfromname, "/dev/r"); strcat(mntfromname, statfsp->f_mntfromname+5); if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) { perror("get_superblock: bad open"); return -1; } if(lseek (fid, LFS_LABELPAD, SEEK_SET) != LFS_LABELPAD) { perror("get_superblock: bad seek"); return -1; } if(read (fid, (char *)sbp, LFS_SBPAD) != LFS_SBPAD) { perror("get_superblock: bad read"); return -1; } close (fid); return 0; } /* * get_ifile: * This function will map the ifile into memory. It returns * NULL on failure. */ int get_ifile (fsp) FS_INFO *fsp; { int fid; int count; caddr_t ifp = NULL; char *ifile_name; struct stat file_stat; ifile_name = (char *) malloc(strlen(statfsp->f_mntonname)+strlen(IFILE_NAME)+2); strcpy(ifile_name, statfsp->f_mntonname); strcat(ifile_name, "/"); strcat(ifile_name, IFILE_NAME); if ((fid = open(ifile_name, O_RDWR, (mode_t)0)) < 0) { perror("get_ifile: bad open"); return -1; } if(fstat (fid, &file_stat)) { perror("get_ifile: fstat failed"); return -1; } ifile_length = file_stat.st_size; /* get the ifile */ #ifndef MMAP_WORKS ifp = (caddr_t)malloc (ifile_length); if (ifp == 0) { perror ("get_ifile: malloc failed, out of memory?"); return -1; } count = read (fid, ifp, ifile_length); if (count != ifile_length) { perror("get_ifile: bad ifile read"); return -1; } #else /* MMAP_WORKS */ ifp = mmap ((caddr_t)0, ifile_length, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fid, (off_t)0); if (ifp < 0) { perror("get_ifile: mmap failed"); return NULL; } #endif /* MMAP_WORKS */ close (fid); cip = (CLEANERINFO*)ifp; segusep = (SEGUSE*)(ifp + CLEANSIZE(lfsp)); ifilep = (IFILE*)(ifp + CLEANSIZE(lfsp) + SEGTABSIZE(lfsp)); /* # of bytes in ifile table */ ifile_count = ifile_length - (CLEANSIZE(lfsp) + SEGTABSIZE(lfsp)); /* # of ifile entries in ifile table */ ifile_count = (ifile_count / lfsp->lfs_bsize) * lfsp->lfs_ifpb; free (ifile_name); return 0; } /* * segmapv: * * This function will scan a segment and return a list of * pairs which indicate which blocks were * contained as live data within the segment at some point * (it may have "died" since then). Any given pair will be * listed at most once. */ int lfs_segmapv(fsp, seg, seg_buf, blocks, bcount, inodes, icount) FS_INFO *fsp; /* pointer to super block */ int seg; /* the segment id */ caddr_t seg_buf; /* the buffer containing the segment's data */ /* OUT: array of block_info for live blocks */ BLOCK_INFO **blocks; int *bcount; /* OUT: number of active blocks in segment */ /* OUT: array of inode_info for live inodes */ INODE_INFO **inodes; int *icount; /* OUT: number of active inodes in segment */ { caddr_t s; caddr_t endofseg; int nextsum; u_long sb_off; time_t timestamp; *bcount = 0; *blocks = (BLOCK_INFO *)malloc (sizeof(BLOCK_INFO)); *icount = 0; *inodes = (INODE_INFO *)malloc(sizeof(INODE_INFO)); sb_off = (SEGUSE_ENTRY(lfsp, segusep, seg)->su_flags & SEGUSE_SUPERBLOCK) ? LFS_SBPAD : 0; for (s = seg_buf + sb_off, endofseg = seg_buf + seg_size(lfsp), timestamp = 0 ; s < endofseg ; s += pseg_size (fsp, (SEGSUM*)s)) { BLOCK_INFO *pblocks; int pbcount; INODE_INFO *pinodes; int picount; #ifdef VERBOSE printf("lfs_segmapv: seg_buf = 0x%x, pseg_buf = 0x%x, offset = %lu (0x%x), pseg = \n\t", (u_int)seg_buf, (u_int)s, (u_int)s - (u_int)seg_buf - (u_int)sb_off, (u_int)s - (u_int)seg_buf - (u_int)sb_off); /* this can cause core dumps when printing an invalid segsum * print_SEGSUM ((SEGSUM*)s); * printf("\n"); * printf("pseg_size = %lu\n", pseg_size(fsp, (SEGSUM*)s)); */ fflush(stdout); #endif /* VERBOSE */ /* we have hit the end of the valid data */ if (! pseg_valid (fsp, (SEGSUM*)s)) break; /* we have gone back in time and hit old data */ if (timestamp > ((SEGSUM*)s)->ss_create) break; timestamp = ((SEGSUM*)s)->ss_create; /* get the block and inode list */ pseg_blocks (fsp, seg, (SEGSUM*)s, seg_buf, &pblocks, &pbcount); pseg_bjoin (fsp, blocks, bcount, pblocks, pbcount); pseg_inodes (fsp, seg, (SEGSUM*)s, seg_buf, &pinodes, &picount); pseg_ijoin (fsp, inodes, icount, pinodes, picount); /* free the temporary tables */ free (pblocks); free (pinodes); } } /* * this will parse a partial segment and create a vector of block_info's * for live data and a vector of inode_info's for live inodes. It will * not include blocks or inodes from files with new version numbers. */ void pseg_blocks (fsp, seg, s, seg_buf, blocks, count) FS_INFO *fsp; /* pointer to super block */ int seg; /* the segment id */ SEGSUM *s; /* (unvalidated) segsum pointer */ caddr_t seg_buf; /* the buffer containing the segment's data */ /* OUT: array of block_info for live blocks */ BLOCK_INFO **blocks; int *count; /* OUT: number of active blocks in segment */ { FINFO **finfos; int finfoc; int blockc; int i; int j; int ninob; /* number of inode blocks passed */ daddr_t seg_daddr; daddr_t *cur_iaddrp; /* pointer to current inode block */ u_long offset; /* the offset (in bytes) within the segment */ *count = 0; *blocks = NULL; pseg_finfos (fsp, s, &finfos, &finfoc); #ifdef VERBOSE for(i=0;ifi_version == IFILE_ENTRY(lfsp, ifilep, finfos[i]->fi_ino)->if_version) blockc += finfos[i]->fi_nblocks; if (finfoc == 0 || blockc == 0) return; ninob = 0; offset = LFS_SUMMARY_SIZE + ((u_int)s - (u_int)seg_buf) + s->ss_next * datobyte(fsp, 1<lfs_bshift); cur_iaddrp = (daddr_t*)(s->ss_ninos == 0 ? 0 : (char *)s + LFS_SUMMARY_SIZE - sizeof(daddr_t)); seg_daddr = sntoda(lfsp, seg); *blocks = (BLOCK_INFO *)malloc (blockc*sizeof(BLOCK_INFO)); for (i = 0 ; i < finfoc ; i ++) { FINFO *f = finfos[i]; if (f->fi_version != IFILE_ENTRY(lfsp, ifilep, f->fi_ino)->if_version) continue; #ifdef VERBOSE printf("finfo %d = ", i); print_FINFO(f); printf("\n"); fflush(stdout); printf("IFILE entry for file %d = ", f->fi_ino); print_IFILE (IFILE_ENTRY(lfsp, ifilep, f->fi_ino)); printf("\n"); fflush(stdout); #endif for (j = 0 ; j < finfos[i]->fi_nblocks ; j ++) { BLOCK_INFO *b = &(*blocks)[*count]; /* * XXX: * this changes if we have variable size blocks */ for (;cur_iaddrp && seg_daddr + bytetoda(fsp, offset) == *cur_iaddrp; offset += datobyte(fsp, 1<lfs_bshift)) { if (ninob <= (s->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp)) { ++ninob; --cur_iaddrp; } else cur_iaddrp = NULL; } b->bi_inode = f->fi_ino; b->bi_lbn = f->fi_blocks[j]; b->bi_daddr = seg_daddr + bytetoda(fsp, offset); b->bi_segcreate = s->ss_create; b->bi_bp = seg_buf + offset; (*count) ++; offset += blocksize(fsp, b->bi_lbn); #ifdef VERBOSE printf("\tb[%d] = ", j); print_BLOCK_INFO(b); printf("\n"); fflush(stdout); #endif } } free (finfos); } void pseg_inodes (fsp, seg, s, seg_buf, inodes, count) FS_INFO *fsp; /* pointer to super block */ int seg; /* the segment id */ SEGSUM *s; /* (unvalidated) segsum pointer */ caddr_t seg_buf; /* the buffer containing the segment's data */ /* OUT: array of inode_info for live inodes */ INODE_INFO **inodes; int *count; /* OUT: number of active inodes in segment */ { int i; ino_t inum; daddr_t *daddrp, i_daddr, seg_daddr; struct dinode *di; *count = 0; *inodes = NULL; if (s->ss_ninos <= 0) return; *inodes = (INODE_INFO *)malloc (s->ss_ninos * sizeof(INODE_INFO)); seg_daddr = sntoda(lfsp, seg); #ifdef VERBOSE printf("pseg_inodes:\n"); print_SEGSUM(s); printf("\n"); fflush(stdout); #endif daddrp = (daddr_t *)((caddr_t)s + LFS_SUMMARY_SIZE); for (i = 0 ; i < s->ss_ninos ; ++i) { if (i % INOPB(lfsp) == 0) { i_daddr = *--daddrp; if (datosn(lfsp, i_daddr) != seg || datobyte(fsp, i_daddr - seg_daddr) > seg_size(lfsp)) { printf("pseg_inodes: bad i_daddr\n"); print_SEGSUM(s); printf("\n"); fflush(stdout); printf("i_daddr = %d, seg_daddr = %d, offset = %d, pseg_size = %d\n", i_daddr, seg_daddr, i_daddr - seg_daddr, pseg_size(fsp, (SEGSUM*)s)); fflush(stdout); } di = (struct dinode *) (seg_buf + datobyte(fsp, i_daddr - seg_daddr)); } else ++di; inum = di->di_inum; if (IFILE_ENTRY(lfsp, ifilep, inum)->if_daddr == i_daddr) { (*inodes)[*count].ii_inode = inum; (*inodes)[*count].ii_daddr = i_daddr; (*inodes)[*count].ii_segcreate = s->ss_create; (*inodes)[*count].ii_dinode = di; (*count) ++; } } } /* return the size of the partial segment in bytes. */ u_long pseg_size (fsp, s) FS_INFO *fsp; /* pointer to super block */ SEGSUM *s; /* segsum pointer */ { int i; int j; FINFO **finfos; int finfoc; u_long size = LFS_SUMMARY_SIZE; pseg_finfos (fsp, s, &finfos, &finfoc); for (i = 0 ; i < finfoc ; i ++) for (j = 0 ; j < finfos[i]->fi_nblocks ; j ++) size += blocksize(fsp, finfos[i]->fi_blocks[j]); /* inodes are packed INOPB inodes per block */ /* there can be unused space in an inode block */ size += datobyte(fsp, fsbtodb(lfsp,1)*((s->ss_ninos+INOPB(lfsp)-1)/INOPB(lfsp))); return size; } /* * join block list b with list a (eliminating duplicates), leaving result * in list a. */ void pseg_bjoin (fsp, ablocks, acount, bblocks, bcount) FS_INFO *fsp; /* pointer to file system info */ /* INOUT: array of live blocks block_info */ BLOCK_INFO **ablocks; int *acount; /* INOUT: number of active blocks */ /* IN: array of live blocks block_info */ BLOCK_INFO *bblocks; int bcount; /* IN: number of active blocks */ { int i; int j; BLOCK_INFO *abp; BLOCK_INFO *bbp; #ifdef VERBOSE printf("pseg_bjoin: *acount = %d, bcount = %d\n", *acount, bcount); /**/ printf("ablocks = \n"); for(i=0;i<*acount;i++){print_BLOCK_INFO((*ablocks)+i); printf("\n");} /**/ printf("bblocks = \n"); for(i=0;ibi_inode == bbp->bi_inode && abp->bi_lbn == bbp->bi_lbn) { /* the data is for the same file and logical block */ if (abp->bi_segcreate < bbp->bi_segcreate) *abp = *bbp; break; } } if (j == *acount) { /* this is a block we haven't seen before */ *ablocks = (BLOCK_INFO*) realloc (*ablocks, sizeof(BLOCK_INFO)*(*acount + 1)); (*ablocks)[*acount] = *bbp; (*acount) ++; } } } /* * join block list b with list a (eliminating duplicates), leaving result * in list a. */ void pseg_ijoin (fsp, ainodes, acount, binodes, bcount) FS_INFO *fsp; /* pointer to file system info */ /* INOUT: array of live inodes inode_info */ INODE_INFO **ainodes; int *acount; /* INOUT: number of active inodes */ /* IN: array of live inodes inode_info */ INODE_INFO *binodes; int bcount; /* IN: number of active inodes */ { int i; int j; daddr_t daddr; INODE_INFO *aip; INODE_INFO *bip; /* we assume that we have no duplicate live inodes on "a" and "b" */ /* eliminate dead inodes from "a" */ for (i = 0, aip = *ainodes ; i < *acount ; ++aip ) { daddr = IFILE_ENTRY(lfsp, ifilep, aip->ii_inode)->if_daddr; if (daddr != aip->ii_daddr) *aip = (*ainodes)[--(*acount)]; else i++; } /* eliminate dead inodes from "b" */ for (i = 0, bip = binodes ; i < bcount ; ++bip) { daddr = IFILE_ENTRY(lfsp, ifilep, bip->ii_inode)->if_daddr; if (daddr != bip->ii_daddr) { /* don't really need to do this, only we don't want to lose any inodes, just in case */ INODE_INFO tmp; tmp = *bip; *bip = binodes[bcount]; binodes[bcount] = tmp; bcount --; } else i++; } /* append "b" to "a" */ if (bcount > 0) { *ainodes = (INODE_INFO *)realloc ((void *)*ainodes, (*acount + bcount + 1)*sizeof(INODE_INFO)); for (i = 0 ; i < bcount ; i ++) (*ainodes)[(*acount)++] = binodes[i]; } } /* is the segsum block valid? return TRUE if it is, FALSE otherwise */ int segsum_valid (fsp, ssp) FS_INFO *fsp; /* pointer to file system info */ SEGSUM *ssp; /* pointer to segment summary block */ { u_long sumsum; /* check segsum block checksum */ sumsum = cksum(&ssp->ss_datasum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum)); if (sumsum != ssp->ss_sumsum) return FALSE; return TRUE; } /* * pseg_valid: * * returns 1 if the partial segment is valid, and 0 if it is invalid. * it uses the checksums to verify validity. */ int pseg_valid (fsp, ssp) FS_INFO *fsp; /* pointer to file system info */ SEGSUM *ssp; /* pointer to segment summary block */ { u_long datasum; u_long size; int nblocks; int i; u_long *datap; caddr_t p; /* check segsum block checksum */ if (segsum_valid (fsp, ssp) == FALSE) return FALSE; return TRUE; /* check data/inode block(s) checksum too... */ size = pseg_size (fsp, ssp); nblocks = size/fsbtodb(lfsp, 1); datap = (u_long*)malloc(sizeof(u_long)*nblocks); p = (caddr_t)ssp + LFS_SUMMARY_SIZE; for (i = 0 ; i < nblocks ; i ++) { datap[i] = *((u_long *)p); p += lfsp->lfs_bsize; } datasum = cksum ((void *)datap, nblocks*sizeof(u_long)); if (datasum != ssp->ss_datasum) return FALSE; return TRUE; } /* get array of FINFO pointers for partial segment */ void pseg_finfos (fsp, ssp, finfos, count) FS_INFO *fsp; /* pointer to file system info */ SEGSUM *ssp; /* pointer to segment summary block */ FINFO ***finfos; /* OUT: return an array of FINFO pointers */ int *count; /* OUT: return size of array */ { caddr_t p = (caddr_t)ssp + sizeof(SEGSUM); int i; FINFO *fip; *count = 0; *finfos = NULL; if (ssp->ss_nfinfo > 0) *finfos = (FINFO**)malloc (ssp->ss_nfinfo*sizeof(FINFO*)); for (i = 0 ; i < ssp->ss_nfinfo ; i ++) { fip = (FINFO *)p; (*finfos)[*count] = fip; (*count) ++; p += finfo_size (fip); } } /* * blocksize: * * returns the size (in bytes) of a (logical) block. * this is used because lfs uses different block sizes, depending * on the logical # of the block. Lfs uses various sizes so * it doesn't need fragments. */ u_long blocksize (fsp, index) FS_INFO *fsp; /* pointer to file system info */ int index; /* logical block # w/in file */ { return lfsp->lfs_bsize; /* XXX: blocksize might depend on the logical block number */ } /* * finfo_size * * returns the size in bytes of an FINFO structure */ u_long finfo_size (finfop) FINFO *finfop; { return sizeof(FINFO) + sizeof(long)*(finfop->fi_nblocks-1); } /* #define MMAP_SEGMENT */ /* * read a segment into a memory buffer */ int mmap_segment (fsp, segment, seg_buf) FS_INFO *fsp; /* file system information */ int segment; /* the index of the segment to be cleaned */ caddr_t *seg_buf; /* pointer to buffer area */ { off_t seg_daddr; /* base disk address of segment */ int fid; /* fildes for file system device */ char mntfromname[MNAMELEN+2]; /* get the disk address of the beginning of the segment */ seg_daddr = sntoda(lfsp, segment); strcpy(mntfromname, "/dev/r"); strcat(mntfromname, statfsp->f_mntfromname+5); if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) { perror("mmap_segment: bad open"); return -1; } #ifdef MMAP_SEGMENT *seg_buf = mmap ((caddr_t)0, seg_size(lfsp), PROT_READ, MAP_FILE, fid, (off_t)datobyte(fsp, seg_daddr)); if ((long)*seg_buf < 0) { perror("mmap_segment: mmap failed"); return NULL; } #else /* MMAP_SEGMENT */ printf("mmap_segment: seg_daddr = %lu, seg_size = %lu, seg_offset = %lu\n", seg_daddr, seg_size(lfsp), datobyte(fsp, seg_daddr)); /* malloc the space for the buffer */ *seg_buf = (caddr_t)malloc(seg_size(lfsp)); /* read the segment data into the buffer */ if (datobyte(fsp, seg_daddr) != lseek (fid, datobyte(fsp, seg_daddr), SEEK_SET)) { perror ("mmap_segment: bad lseek"); return -1; } if (seg_size(lfsp) != read (fid, *seg_buf, seg_size(lfsp))) { perror ("mmap_segment: bad read"); return -1; } #endif /* MMAP_SEGMENT */ close (fid); return 0; } void munmap_segment (fsp, seg_buf) FS_INFO *fsp; /* file system information */ caddr_t seg_buf; /* pointer to buffer area */ { #ifdef MMAP_SEGMENT munmap (seg_buf, seg_size(lfsp)); #else /* MMAP_SEGMENT */ free (seg_buf); #endif /* MMAP_SEGMENT */ } /* * USEFUL DEBUGGING TOOLS: */ void print_IFILE (p) IFILE *p; { if (p) { if (p->if_daddr == 0) printf("{free, if_version=%lu, if_nextfree=%lu}", p->if_version, p->if_nextfree); else printf("{if_version=%lu, if_daddr=%lu}", p->if_version, p->if_daddr); } else printf("0x0"); fflush(stdout); } void print_SEGUSE (p) SEGUSE *p; { if (p) { printf("{su_nbytes=%lu, su_flags=%c%c%c, su_lastmod=", p->su_nbytes, ((p->su_flags & SEGUSE_DIRTY) ? 'D' : 'C'), ((p->su_flags & SEGUSE_ACTIVE) ? 'A' : ' '), ((p->su_flags & SEGUSE_SUPERBLOCK) ? 'S' : ' ')); print_time_t(p->su_lastmod); printf("}"); } else printf("0x0"); fflush(stdout); } void print_CLEANERINFO (p) CLEANERINFO *p; { if (p) printf("{clean=%lu, dirty=%lu}", p->clean, p->dirty); else printf("0x0"); fflush(stdout); } void print_SEGSUM (p) SEGSUM *p; { if (p) { printf("{ss_sumsum=%lu, ss_datasum=%lu, ss_next=%lu, ", p->ss_sumsum, p->ss_datasum, p->ss_next); printf("ss_create=%lu, ss_nfinfo=%lu, ss_ninos=%lu", p->ss_create, p->ss_nfinfo, p->ss_ninos); printf("}"); } else printf("0x0"); fflush(stdout); } void print_time_t (t) time_t t; { char temp[128]; int len; strcpy (temp, ctime(&t)); len = strlen(temp); if (temp[len-1] == '\n') temp[len-1] = 0; printf("%s", temp); fflush(stdout); } void print_FINFO (p) FINFO *p; { int i; if (p) { printf("{fi_nblocks=%lu, fi_version=%lu, fi_ino=%lu, fi_blocks={", p->fi_nblocks, p->fi_version, p->fi_ino); for (i = 0 ; i < p->fi_nblocks ; i ++) { if (i > 0) printf(", "); printf("%ld", p->fi_blocks[i]); } printf("}}"); } else printf("0x0"); fflush(stdout); } void print_BLOCK_INFO (p) BLOCK_INFO *p; { if (p) { printf("{bi_inode=%lu, bi_lbn=%ld, bi_daddr=%lu, bi_segcreate=", p->bi_inode, p->bi_lbn, p->bi_daddr); print_time_t(p->bi_segcreate); printf(", bi_bp = 0x%x}", p->bi_bp); } else printf("0x0"); fflush(stdout); } void print_INODE_INFO (p) INODE_INFO *p; { if (p) { printf("{ii_inode=%lu, ii_daddr=%lu, ii_segcreate=", p->ii_inode, p->ii_daddr); print_time_t (p->ii_segcreate); printf(", ii_dinode=0x%x}", p->ii_dinode); } else printf("0x0"); fflush(stdout); } void print_lfs (p) struct lfs *p; { int i; if (p) { printf("{\n"); printf("\tlfs_magic=0x%x\n", p->lfs_magic); printf("\tlfs_version=%lu\n", p->lfs_version); printf("\tlfs_size=%lu\n", p->lfs_size); printf("\tlfs_ssize=%lu\n", p->lfs_ssize); printf("\tlfs_dsize=%lu\n", p->lfs_dsize); printf("\tlfs_bsize=%lu\n", p->lfs_bsize); printf("\tlfs_fsize=%lu\n", p->lfs_fsize); printf("\tlfs_frag=%lu\n", p->lfs_frag); /* checkpoint region */ printf("\tlfs_free=%lu\n", p->lfs_free); printf("\tlfs_bfree=%lu\n", p->lfs_bfree); printf("\tlfs_nfiles=%lu\n", p->lfs_nfiles); printf("\tlfs_idaddr=%lu\n", p->lfs_idaddr); printf("\tlfs_ifile=%lu\n", p->lfs_ifile); printf("\tlfs_lastseg=%lu\n", p->lfs_lastseg); printf("\tlfs_nextseg=%lu\n", p->lfs_nextseg); printf("\tlfs_curseg=%lu\n", p->lfs_curseg); printf("\tlfs_offset=%lu\n", p->lfs_offset); printf("\tlfs_tstamp=%lu\n", p->lfs_tstamp); /* configuration parameters */ printf("\tlfs_minfree=%lu\n", p->lfs_minfree); /* these fields can be computed from the others */ printf("\tlfs_dbpseg=%lu\n", p->lfs_dbpseg); printf("\tlfs_inopb=%lu\n", p->lfs_inopb); printf("\tlfs_ifpb=%lu\n", p->lfs_ifpb); printf("\tlfs_sepb=%lu\n", p->lfs_sepb); printf("\tlfs_nindir=%lu\n", p->lfs_nindir); printf("\tlfs_nseg=%lu\n", p->lfs_nseg); printf("\tlfs_nspf=%lu\n", p->lfs_nspf); printf("\tlfs_cleansz=%lu\n", p->lfs_cleansz); printf("\tlfs_segtabsz=%lu\n", p->lfs_segtabsz); printf("\tlfs_segmask=%lu\n", p->lfs_segmask); printf("\tlfs_segshift=%lu\n", p->lfs_segshift); printf("\tlfs_bmask=%lu\n", p->lfs_bmask); printf("\tlfs_bshift=%lu\n", p->lfs_bshift); printf("\tlfs_ffmask=%lu\n", p->lfs_ffmask); printf("\tlfs_ffshift=%lu\n", p->lfs_ffshift); printf("\tlfs_fbmask=%lu\n", p->lfs_fbmask); printf("\tlfs_fbshift=%lu\n", p->lfs_fbshift); printf("\tlfs_fsbtodb=%lu\n", p->lfs_fsbtodb); /* superblock offsets */ printf("\tlfs_sboffs={"); for (i = 0 ; i < LFS_MAXNUMSB ; i ++) { if (i > 0) printf(", "); printf("%lu", p->lfs_sboffs[i]); } printf("}\n"); printf("}"); } else printf("0x0"); fflush(stdout); }