/* * Check and potentially fix certain fields in the super block. */ static void fixup_superblock(void) { /* * Kernel looks for FS_OPTTIME, and assumes that if that's not * what's there, it must be FS_OPTSPACE, so not fixing does not * require setting iscorrupt. */ if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); if (reply("SET TO DEFAULT") == 1) { sblock.fs_optim = FS_OPTTIME; sbdirty(); } } if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", sblock.fs_minfree); if (reply("SET TO DEFAULT") == 1) { sblock.fs_minfree = 10; sbdirty(); } else if (sblock.fs_minfree < 0) { /* * Kernel uses minfree without verification, * and a negative value would do bad things. */ iscorrupt = 1; } } }
void ckfini(int markclean) { struct bufarea *bp, *nbp; int ofsmodified, cnt = 0; if (fswritefd < 0) { close(fsreadfd); return; } flush(fswritefd, &sblk); if (havesb && sblk.b_bno != SBOFF / dev_bsize && !preen && reply("UPDATE STANDARD SUPERBLOCK")) { sblk.b_bno = SBOFF / dev_bsize; sbdirty(); flush(fswritefd, &sblk); } flush(fswritefd, &cgblk); free(cgblk.b_un.b_buf); for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { cnt++; flush(fswritefd, bp); nbp = bp->b_prev; free(bp->b_un.b_buf); free((char *)bp); } if (bufhead.b_size != cnt) errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt); pbp = pdirbp = NULL; if (sblock.fs_clean != markclean) { sblock.fs_clean = markclean; sbdirty(); ofsmodified = fsmodified; flush(fswritefd, &sblk); fsmodified = ofsmodified; if (!preen) { printf("\n***** FILE SYSTEM MARKED %s *****\n", markclean ? "CLEAN" : "DIRTY"); if (!markclean) rerun = 1; } } else if (!preen && !markclean) { printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); rerun = 1; } if (debug) printf("cache missed %ld of %ld (%d%%)\n", diskreads, totalreads, (int)(diskreads * 100 / totalreads)); close(fsreadfd); close(fswritefd); }
void ckfini(int markclean) { struct bufarea *bp, *nbp; int cnt = 0; if (fswritefd < 0) { (void)close(fsreadfd); return; } flush(fswritefd, &sblk); if (havesb && sblk.b_bno != SBOFF / dev_bsize && !preen && reply("UPDATE STANDARD SUPERBLOCKS")) { sblk.b_bno = SBOFF / dev_bsize; sbdirty(); flush(fswritefd, &sblk); copyback_sb(&asblk); asblk.b_dirty = 1; flush(fswritefd, &asblk); } for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { cnt++; flush(fswritefd, bp); nbp = bp->b_prev; free(bp->b_un.b_buf); free((char *)bp); } if (bufhead.b_size != cnt) errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); pbp = pdirbp = (struct bufarea *)0; if (markclean && (sblock.e2fs.e2fs_state & E2FS_ISCLEAN) == 0) { /* * Mark the file system as clean, and sync the superblock. */ if (preen) pwarn("MARKING FILE SYSTEM CLEAN\n"); else if (!reply("MARK FILE SYSTEM CLEAN")) markclean = 0; if (markclean) { sblock.e2fs.e2fs_state = E2FS_ISCLEAN; sbdirty(); flush(fswritefd, &sblk); } } if (debug) printf("cache missed %ld of %ld (%d%%)\n", diskreads, totalreads, (int)(diskreads * 100 / totalreads)); (void)close(fsreadfd); (void)close(fswritefd); }
/* * We suck in lots of fsck code, and just pick & choose the stuff we want. * * fsreadfd is set up to read from the file system, fswritefd to write to * the file system. */ int main(int argc, char *argv[]) { int ch, rval; char *fsys = NULL; while (-1 != (ch = getopt(argc, argv, "f:d"))) { switch (ch) { case 'f': fsys = optarg; break; case 'd': debug++; break; default: usage(); } } if (fsys == NULL) usage(); if (!setup(fsys)) errx(1, "cannot set up file system `%s'", fsys); printf("Editing file system `%s'\nLast Mounted on %s\n", fsys, sblock.fs_fsmnt); rval = cmdloop(); sblock.fs_clean = 0; /* mark it dirty */ sbdirty(); ckfini(0); printf("*** FILE SYSTEM MARKED DIRTY\n"); printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n"); printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n"); exit(rval); }
static int initial_error_state_adjust(void) { int retval = 0; /* do this right away to prevent any other fscks on this fs */ switch (sblock.fs_clean) { case FSBAD: break; case FSFIX: if (preen) errexit("ERROR-LOCKED; MARKED \"FSFIX\"\n"); if (reply("marked FSFIX, CONTINUE") == 0) { retval = -1; goto finish; } break; case FSCLEAN: if (preen) errexit("ERROR-LOCKED; MARKED \"FSCLEAN\"\n"); if (reply("marked FSCLEAN, CONTINUE") == 0) { retval = -1; goto finish; } break; default: if (preen) { if (debug) pwarn("ERRORLOCKED; NOT MARKED \"FSBAD\"\n"); else errexit("ERRORLOCKED; NOT MARKED \"FSBAD\"\n"); } else { (void) printf("error-locked but not marked \"FSBAD\";"); if (reply(" CONTINUE") == 0) { retval = -1; goto finish; } } break; } if (!do_errorlock(LOCKFS_ELOCK)) { if (preen) { retval = -1; goto finish; } if (reply("error-lock reset failed; CONTINUE") == 0) { retval = -1; goto finish; } } sblock.fs_state = FSOKAY - (long)sblock.fs_time; sblock.fs_clean = FSFIX; sbdirty(); write_altsb(fswritefd); finish: return (retval); }
void clearinode(ino_t inumber) { struct ubuf *bp; IFILE *ifp; daddr_t daddr; /* Send cleared inode to the free list */ LFS_IENTRY(ifp, fs, inumber, bp); daddr = ifp->if_daddr; if (daddr == LFS_UNUSED_DADDR) { brelse(bp, 0); return; } ifp->if_daddr = LFS_UNUSED_DADDR; ifp->if_nextfree = fs->lfs_freehd; fs->lfs_freehd = inumber; sbdirty(); VOP_BWRITE(bp); /* * update segment usage. */ if (daddr != LFS_UNUSED_DADDR) { SEGUSE *sup; u_int32_t oldsn = dtosn(fs, daddr); seg_table[oldsn].su_nbytes -= DINODE1_SIZE; LFS_SEGENTRY(sup, fs, oldsn, bp); sup->su_nbytes -= DINODE1_SIZE; LFS_WRITESEGENTRY(sup, fs, oldsn, bp); /* Ifile */ } }
/* * Scan each entry in a directory block. */ int dirscan(struct inodesc *idesc) { struct direct *dp; struct bufarea *bp; unsigned int dsize, n; long blksiz; char dbuf[DIRBLKSIZ]; if (idesc->id_type != DATA) errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); if (idesc->id_entryno == 0 && (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); blksiz = idesc->id_numfrags * sblock.fs_fsize; if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { idesc->id_filesize -= blksiz; return (SKIP); } idesc->id_loc = 0; for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { dsize = dp->d_reclen; if (dsize > sizeof(dbuf)) dsize = sizeof(dbuf); memmove(dbuf, dp, (size_t)dsize); # if (BYTE_ORDER == LITTLE_ENDIAN) if (!newinofmt) { struct direct *tdp = (struct direct *)dbuf; u_char tmp; tmp = tdp->d_namlen; tdp->d_namlen = tdp->d_type; tdp->d_type = tmp; } # endif idesc->id_dirp = (struct direct *)dbuf; if ((n = (*idesc->id_func)(idesc)) & ALTERED) { # if (BYTE_ORDER == LITTLE_ENDIAN) if (!newinofmt && !doinglevel2) { struct direct *tdp; u_char tmp; tdp = (struct direct *)dbuf; tmp = tdp->d_namlen; tdp->d_namlen = tdp->d_type; tdp->d_type = tmp; } # endif bp = getdirblk(idesc->id_blkno, blksiz); memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, (size_t)dsize); dirty(bp); sbdirty(); } if (n & STOP) return (n); } return (idesc->id_filesize > 0 ? KEEPON : STOP); }
static int setlarge(void) { if (sblock.e2fs.e2fs_rev < E2FS_REV1) { pfatal("LARGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS"); return 0; } if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE)) { if (preen) pwarn("SETTING LARGE FILE INDICATOR\n"); else if (!reply("SET LARGE FILE INDICATOR")) return 0; sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_LARGEFILE; sbdirty(); } return 1; }
/* * We suck in lots of fsck code, and just pick & choose the stuff we want. * * fsreadfd is set up to read from the file system, fswritefd to write to * the file system. */ int main(int argc, char *argv[]) { int ch, rval; char *fsys = NULL; while (-1 != (ch = getopt(argc, argv, "fdr"))) { switch (ch) { case 'f': /* The -f option is left for historical * reasons and has no meaning. */ break; case 'd': debug++; break; case 'r': nflag++; /* "no" in fsck, readonly for us */ break; default: usage(); } } argc -= optind; argv += optind; if (argc != 1) usage(); else fsys = argv[0]; sblock_init(); if (!setup(fsys)) errx(1, "cannot set up file system `%s'", fsys); printf("%s file system `%s'\nLast Mounted on %s\n", nflag? "Examining": "Editing", fsys, sblock.fs_fsmnt); rval = cmdloop(); if (!nflag) { sblock.fs_clean = 0; /* mark it dirty */ sbdirty(); ckfini(0); printf("*** FILE SYSTEM MARKED DIRTY\n"); printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n"); printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n"); } exit(rval); }
/* * We suck in lots of fsck code, and just pick & choose the stuff we want. * * fsreadfd is set up to read from the file system, fswritefd to write to * the file system. */ int main(int argc, char *argv[]) { int ch, rval; char *fsys = NULL; forceimage = 0; debug = 0; isappleufs = 0; while ((ch = getopt(argc, argv, "dFf:n")) != -1) { switch (ch) { case 'd': debug++; break; case 'F': forceimage = 1; break; case 'f': fsys = optarg; break; case 'n': nflag++; break; default: usage(); } } if (fsys == NULL) usage(); endian = 0; if (setup(fsys, fsys) <= 0) errx(1, "cannot set up file system `%s'", fsys); printf("Editing file system `%s'\nLast Mounted on %s\n", fsys, sblock->fs_fsmnt); rval = cmdloop(); if (nflag) exit(rval); sblock->fs_clean = 0; /* mark it dirty */ sbdirty(); markclean = 0; ckfini(1); printf("*** FILE SYSTEM MARKED DIRTY\n"); printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n"); printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n"); exit(rval); }
static int sethuge(void) { if (sblock.e2fs.e2fs_rev < E2FS_REV1) { pfatal("HUGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS"); return 0; } if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_HUGE_FILE)) { if (preen) pwarn("SETTING HUGE FILE FEATURE\n"); else if (!reply("SET HUGE FILE FEATURE")) return 0; sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_HUGE_FILE; sbdirty(); } return 1; }
/* * Scan each entry in a directory block. */ int dirscan(struct inodesc *idesc) { struct ext2fs_direct *dp; struct bufarea *bp; int dsize, n; long blksiz; char *dbuf = NULL; if ((dbuf = malloc(sblock.e2fs_bsize)) == NULL) err(8, "Can't allocate directory block"); if (idesc->id_type != DATA) errexit("wrong type to dirscan %d", idesc->id_type); if (idesc->id_entryno == 0 && (idesc->id_filesize & (sblock.e2fs_bsize - 1)) != 0) idesc->id_filesize = roundup(idesc->id_filesize, sblock.e2fs_bsize); blksiz = idesc->id_numfrags * sblock.e2fs_bsize; if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { idesc->id_filesize -= blksiz; free(dbuf); return (SKIP); } idesc->id_loc = 0; for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { dsize = fs2h16(dp->e2d_reclen); memcpy(dbuf, dp, (size_t)dsize); idesc->id_dirp = (struct ext2fs_direct *)dbuf; if ((n = (*idesc->id_func)(idesc)) & ALTERED) { bp = getdirblk(idesc->id_blkno, blksiz); memcpy(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, (size_t)dsize); dirty(bp); sbdirty(); } if (n & STOP) { free(dbuf); return (n); } } free(dbuf); return (idesc->id_filesize > 0 ? KEEPON : STOP); }
/* * Scan each entry in a directory block. */ int dirscan(struct inodesc *idesc) { LFS_DIRHEADER *dp; struct ubuf *bp; int dsize, n; long blksiz; char dbuf[LFS_DIRBLKSIZ]; struct uvnode *vp; if (idesc->id_type != DATA) errexit("wrong type to dirscan %d", idesc->id_type); if (idesc->id_entryno == 0 && (idesc->id_filesize & (LFS_DIRBLKSIZ - 1)) != 0) idesc->id_filesize = roundup(idesc->id_filesize, LFS_DIRBLKSIZ); blksiz = idesc->id_numfrags * lfs_sb_getfsize(fs); if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { idesc->id_filesize -= blksiz; return (SKIP); } idesc->id_loc = 0; vp = vget(fs, idesc->id_number); for (dp = fsck_readdir(vp, idesc); dp != NULL; dp = fsck_readdir(vp, idesc)) { dsize = lfs_dir_getreclen(fs, dp); memcpy(dbuf, dp, (size_t) dsize); idesc->id_dirp = (LFS_DIRHEADER *) dbuf; if ((n = (*idesc->id_func) (idesc)) & ALTERED) { bread(vp, idesc->id_lblkno, blksiz, 0, &bp); memcpy(bp->b_data + idesc->id_loc - dsize, dbuf, (size_t) dsize); VOP_BWRITE(bp); sbdirty(); } if (n & STOP) return (n); } return (idesc->id_filesize > 0 ? KEEPON : STOP); }
/* * Scan each entry in a directory block. */ int dirscan(struct inodesc *idesc) { struct direct *dp; struct bufarea *bp; u_int dsize, n; long blksiz; char dbuf[DIRBLKSIZ]; if (idesc->id_type != DATA) errx(EEXIT, "wrong type to dirscan %d", idesc->id_type); if (idesc->id_entryno == 0 && (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0) idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ); blksiz = idesc->id_numfrags * sblock.fs_fsize; if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { idesc->id_filesize -= blksiz; return (SKIP); } idesc->id_loc = 0; for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { dsize = dp->d_reclen; if (dsize > sizeof(dbuf)) dsize = sizeof(dbuf); memmove(dbuf, dp, (size_t)dsize); idesc->id_dirp = (struct direct *)dbuf; if ((n = (*idesc->id_func)(idesc)) & ALTERED) { bp = getdirblk(idesc->id_blkno, blksiz); memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, (size_t)dsize); dirty(bp); sbdirty(); rerun = 1; } if (n & STOP) return (n); } return (idesc->id_filesize > 0 ? KEEPON : STOP); }
ifreechk() { register int i; ino_t inum; for (i=0; i<sblock.fs_ninode; i++) { inum = sblock.fs_inode[i]; switch (getstate(inum)) { case USTATE: continue; default: pwarn("ALLOCATED INODE(S) IN IFREE LIST"); if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sblock.fs_ninode = i-1; sbdirty(); } return; } } }
int setup(const char *dev) { #ifndef VERBOSE_BLOCKMAP long bmapsize; #endif struct stat statb; int doskipclean; u_int64_t maxfilesize; int open_flags; struct uvnode *ivp; struct ubuf *bp; int i, isdirty; long sn, curseg; SEGUSE *sup; size_t sumstart; havesb = 0; doskipclean = skipclean; if (stat(dev, &statb) < 0) { pfatal("Can't stat %s: %s\n", dev, strerror(errno)); return (0); } if (!S_ISCHR(statb.st_mode) && skipclean) { pfatal("%s is not a character device", dev); if (reply("CONTINUE") == 0) return (0); } if (nflag) open_flags = O_RDONLY; else open_flags = O_RDWR; if ((fsreadfd = open(dev, open_flags)) < 0) { pfatal("Can't open %s: %s\n", dev, strerror(errno)); return (0); } if (nflag) { if (preen) pfatal("NO WRITE ACCESS"); printf("** %s (NO WRITE)\n", dev); quiet = 0; } else if (!preen && !quiet) printf("** %s\n", dev); fsmodified = 0; lfdir = 0; /* Initialize time in case we have to write */ time(&write_time); bufinit(0); /* XXX we could make a better guess */ fs = lfs_init(fsreadfd, bflag, idaddr, 0, debug); if (fs == NULL) { if (preen) printf("%s: ", cdevname()); errexit("BAD SUPER BLOCK OR IFILE INODE NOT FOUND"); } /* Resize buffer cache now that we have a superblock to guess from. */ bufrehash((lfs_sb_getsegtabsz(fs) + maxino / lfs_sb_getifpb(fs)) << 4); if (lfs_sb_getpflags(fs) & LFS_PF_CLEAN) { if (doskipclean) { if (!quiet) pwarn("%sile system is clean; not checking\n", preen ? "f" : "** F"); return (-1); } if (!preen) pwarn("** File system is already clean\n"); } if (idaddr) { daddr_t tdaddr; SEGSUM *sp; FINFO *fp; int bc; if (debug) pwarn("adjusting offset, serial for -i 0x%jx\n", (uintmax_t)idaddr); tdaddr = lfs_sntod(fs, lfs_dtosn(fs, idaddr)); if (lfs_sntod(fs, lfs_dtosn(fs, tdaddr)) == tdaddr) { if (tdaddr == lfs_sb_gets0addr(fs)) tdaddr += lfs_btofsb(fs, LFS_LABELPAD); for (i = 0; i < LFS_MAXNUMSB; i++) { if (lfs_sb_getsboff(fs, i) == tdaddr) tdaddr += lfs_btofsb(fs, LFS_SBPAD); if (lfs_sb_getsboff(fs, i) > tdaddr) break; } } lfs_sb_setoffset(fs, tdaddr); if (debug) pwarn("begin with offset/serial 0x%jx/%jd\n", (uintmax_t)lfs_sb_getoffset(fs), (intmax_t)lfs_sb_getserial(fs)); while (tdaddr < idaddr) { bread(fs->lfs_devvp, LFS_FSBTODB(fs, tdaddr), lfs_sb_getsumsize(fs), 0, &bp); sp = (SEGSUM *)bp->b_data; sumstart = lfs_ss_getsumstart(fs); if (lfs_ss_getsumsum(fs, sp) != cksum((char *)sp + sumstart, lfs_sb_getsumsize(fs) - sumstart)) { brelse(bp, 0); if (debug) printf("bad cksum at %jx\n", (uintmax_t)tdaddr); break; } fp = SEGSUM_FINFOBASE(fs, sp); bc = howmany(lfs_ss_getninos(fs, sp), LFS_INOPB(fs)) << (lfs_sb_getversion(fs) > 1 ? lfs_sb_getffshift(fs) : lfs_sb_getbshift(fs)); for (i = 0; i < lfs_ss_getnfinfo(fs, sp); i++) { bc += lfs_fi_getlastlength(fs, fp) + ((lfs_fi_getnblocks(fs, fp) - 1) << lfs_sb_getbshift(fs)); fp = NEXT_FINFO(fs, fp); } tdaddr += lfs_btofsb(fs, bc) + 1; lfs_sb_setoffset(fs, tdaddr); lfs_sb_setserial(fs, lfs_ss_getserial(fs, sp) + 1); brelse(bp, 0); } /* * Set curseg, nextseg appropriately -- inlined from * lfs_newseg() */ curseg = lfs_dtosn(fs, lfs_sb_getoffset(fs)); lfs_sb_setcurseg(fs, lfs_sntod(fs, curseg)); for (sn = curseg + lfs_sb_getinterleave(fs);;) { sn = (sn + 1) % lfs_sb_getnseg(fs); if (sn == curseg) errx(1, "init: no clean segments"); LFS_SEGENTRY(sup, fs, sn, bp); isdirty = sup->su_flags & SEGUSE_DIRTY; brelse(bp, 0); if (!isdirty) break; } /* Skip superblock if necessary */ for (i = 0; i < LFS_MAXNUMSB; i++) if (lfs_sb_getoffset(fs) == lfs_sb_getsboff(fs, i)) lfs_sb_addoffset(fs, lfs_btofsb(fs, LFS_SBPAD)); ++fs->lfs_nactive; lfs_sb_setnextseg(fs, lfs_sntod(fs, sn)); if (debug) { pwarn("offset = 0x%" PRIx64 ", serial = %" PRIu64 "\n", lfs_sb_getoffset(fs), lfs_sb_getserial(fs)); pwarn("curseg = %" PRIx64 ", nextseg = %" PRIx64 "\n", lfs_sb_getcurseg(fs), lfs_sb_getnextseg(fs)); } if (!nflag && !skipclean) { lfs_sb_setidaddr(fs, idaddr); fsmodified = 1; sbdirty(); } } if (debug) { pwarn("idaddr = 0x%jx\n", idaddr ? (uintmax_t)idaddr : (uintmax_t)lfs_sb_getidaddr(fs)); pwarn("dev_bsize = %lu\n", dev_bsize); pwarn("lfs_bsize = %lu\n", (unsigned long) lfs_sb_getbsize(fs)); pwarn("lfs_fsize = %lu\n", (unsigned long) lfs_sb_getfsize(fs)); pwarn("lfs_frag = %lu\n", (unsigned long) lfs_sb_getfrag(fs)); pwarn("lfs_inopb = %lu\n", (unsigned long) lfs_sb_getinopb(fs)); } if (lfs_sb_getversion(fs) == 1) maxfsblock = lfs_blkstofrags(fs, lfs_sb_getsize(fs)); else maxfsblock = lfs_sb_getsize(fs); maxfilesize = calcmaxfilesize(lfs_sb_getbshift(fs)); if (/* lfs_sb_getminfree(fs) < 0 || */ lfs_sb_getminfree(fs) > 99) { pfatal("IMPOSSIBLE MINFREE=%u IN SUPERBLOCK", lfs_sb_getminfree(fs)); if (reply("SET TO DEFAULT") == 1) { lfs_sb_setminfree(fs, 10); sbdirty(); } } if (lfs_sb_getbmask(fs) != lfs_sb_getbsize(fs) - 1) { pwarn("INCORRECT BMASK=0x%jx IN SUPERBLOCK (SHOULD BE 0x%x)", (uintmax_t)lfs_sb_getbmask(fs), lfs_sb_getbsize(fs) - 1); lfs_sb_setbmask(fs, lfs_sb_getbsize(fs) - 1); if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); } } if (lfs_sb_getffmask(fs) != lfs_sb_getfsize(fs) - 1) { pwarn("INCORRECT FFMASK=0x%jx IN SUPERBLOCK (SHOULD BE 0x%x)", (uintmax_t)lfs_sb_getffmask(fs), lfs_sb_getfsize(fs) - 1); lfs_sb_setffmask(fs, lfs_sb_getfsize(fs) - 1); if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); } } if (lfs_sb_getfbmask(fs) != (1U << lfs_sb_getfbshift(fs)) - 1) { pwarn("INCORRECT FBMASK=0x%jx IN SUPERBLOCK (SHOULD BE 0x%x)", (uintmax_t)lfs_sb_getfbmask(fs), (1U << lfs_sb_getfbshift(fs)) - 1); lfs_sb_setfbmask(fs, (1U << lfs_sb_getfbshift(fs)) - 1); if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); } } if (lfs_sb_getmaxfilesize(fs) != maxfilesize) { pwarn( "INCORRECT MAXFILESIZE=%ju IN SUPERBLOCK (SHOULD BE %ju WITH BSHIFT %u)", (uintmax_t) lfs_sb_getmaxfilesize(fs), (uintmax_t) maxfilesize, lfs_sb_getbshift(fs)); if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { lfs_sb_setmaxfilesize(fs, maxfilesize); sbdirty(); } } if (lfs_sb_getmaxsymlinklen(fs) != LFS_MAXSYMLINKLEN(fs)) { pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK (SHOULD BE %zu)", lfs_sb_getmaxsymlinklen(fs), LFS_MAXSYMLINKLEN(fs)); lfs_sb_setmaxsymlinklen(fs, LFS_MAXSYMLINKLEN(fs)); if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); } } /* * Read in the Ifile; we'll be using it a lot. * XXX If the Ifile is corrupted we are in bad shape. We need to * XXX run through the segment headers of the entire disk to * XXX reconstruct the inode table, then pretend all segments are * XXX dirty while we do the rest. */ ivp = fs->lfs_ivnode; maxino = ((lfs_dino_getsize(fs, VTOI(ivp)->i_din) - (lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs)) * lfs_sb_getbsize(fs)) / lfs_sb_getbsize(fs)) * lfs_sb_getifpb(fs); if (debug) pwarn("maxino = %llu\n", (unsigned long long)maxino); for (i = 0; i < lfs_dino_getsize(fs, VTOI(ivp)->i_din); i += lfs_sb_getbsize(fs)) { bread(ivp, i >> lfs_sb_getbshift(fs), lfs_sb_getbsize(fs), 0, &bp); /* XXX check B_ERROR */ brelse(bp, 0); } /* * allocate and initialize the necessary maps */ din_table = ecalloc(maxino, sizeof(*din_table)); seg_table = ecalloc(lfs_sb_getnseg(fs), sizeof(SEGUSE)); /* Get segment flags */ for (i = 0; i < lfs_sb_getnseg(fs); i++) { LFS_SEGENTRY(sup, fs, i, bp); seg_table[i].su_flags = sup->su_flags & ~SEGUSE_ACTIVE; if (preen) seg_table[i].su_nbytes = sup->su_nbytes; brelse(bp, 0); } /* Initialize Ifile entry */ din_table[LFS_IFILE_INUM] = lfs_sb_getidaddr(fs); seg_table[lfs_dtosn(fs, lfs_sb_getidaddr(fs))].su_nbytes += DINOSIZE(fs); #ifndef VERBOSE_BLOCKMAP bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); blockmap = ecalloc(bmapsize, sizeof(char)); #else blockmap = ecalloc(maxfsblock, sizeof(ino_t)); #endif statemap = ecalloc(maxino, sizeof(char)); typemap = ecalloc(maxino, sizeof(char)); lncntp = ecalloc(maxino, sizeof(int16_t)); if (preen) { n_files = lfs_sb_getnfiles(fs); n_blks = lfs_sb_getdsize(fs) - lfs_sb_getbfree(fs); numdirs = maxino; inplast = 0; listmax = numdirs + 10; inpsort = ecalloc(listmax, sizeof(struct inoinfo *)); inphead = ecalloc(numdirs, sizeof(struct inoinfo *)); } return (1); ckfini(0); return (0); }
pass5() { struct inodesc idesc; daddr_t blkno; int n; BUFAREA *bp1, *bp2; extern int debug; bzero(&idesc, sizeof (idesc)); idesc.id_type = ADDR; if(sflag) fixfree = 1; else { ifreechk(); if(freemap) bcopy(blockmap, freemap, (int)bmapsz); else { for(blkno = 0; blkno < fmapblk-bmapblk; blkno++) { bp1 = getblk((BUFAREA *)NULL,blkno+bmapblk); bp2 = getblk((BUFAREA *)NULL,blkno+fmapblk); bcopy(bp1->b_un.b_buf,bp2->b_un.b_buf,DEV_BSIZE); dirty(bp2); } } badblk = dupblk = 0; freeblk.df_nfree = sblock.fs_nfree; for(n = 0; n < NICFREE; n++) freeblk.df_free[n] = sblock.fs_free[n]; freechk(); if(badblk) pfatal("%d BAD BLKS IN FREE LIST\n",badblk); if(dupblk) pwarn("%d DUP BLKS IN FREE LIST\n",dupblk); if (debug) printf("n_files %ld n_blks %ld n_free %ld fmax %ld fmin %ld ninode: %u\n", n_files, n_blks, n_free, fmax, fmin,sblock.fs_ninode); if(fixfree == 0) { if ((n_blks+n_free) != (fmax-fmin) && dofix(&idesc, "BLK(S) MISSING")) fixfree = 1; else if (n_free != sblock.fs_tfree && dofix(&idesc,"FREE BLK COUNT WRONG IN SUPERBLOCK")) { sblock.fs_tfree = n_free; sbdirty(); } } if(fixfree && !dofix(&idesc, "BAD FREE LIST")) fixfree = 0; } if(fixfree) { if (preen == 0) printf("** Phase 6 - Salvage Free List\n"); makefree(); n_free = sblock.fs_tfree; sblock.fs_ronly = 0; sblock.fs_fmod = 0; sbdirty(); } }
pass5() { int c, blk, frags, sumsize, mapsize; daddr_t dbase, dmax, d; register long i, j; struct csum *cs; time_t now; struct csum cstotal; struct inodesc idesc; char buf[MAXBSIZE]; register struct cg *newcg = (struct cg *)buf; bzero((char *)newcg, sblock.fs_cgsize); newcg->cg_magic = CG_MAGIC; bzero((char *)&idesc, sizeof(struct inodesc)); idesc.id_type = ADDR; bzero((char *)&cstotal, sizeof(struct csum)); sumsize = cgrp.cg_iused - (char *)(&cgrp); mapsize = &cgrp.cg_free[howmany(sblock.fs_fpg, NBBY)] - (u_char *)cgrp.cg_iused; (void)time(&now); for (c = 0; c < sblock.fs_ncg; c++) { getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize); if (cgrp.cg_magic != CG_MAGIC) pfatal("CG %d: BAD MAGIC NUMBER\n", c); dbase = cgbase(&sblock, c); dmax = dbase + sblock.fs_fpg; if (dmax > sblock.fs_size) dmax = sblock.fs_size; if (now > cgrp.cg_time) newcg->cg_time = cgrp.cg_time; else newcg->cg_time = now; newcg->cg_cgx = c; if (c == sblock.fs_ncg - 1) newcg->cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg; else newcg->cg_ncyl = sblock.fs_cpg; newcg->cg_niblk = sblock.fs_ipg; newcg->cg_ndblk = dmax - dbase; newcg->cg_cs.cs_ndir = 0; newcg->cg_cs.cs_nffree = 0; newcg->cg_cs.cs_nbfree = 0; newcg->cg_cs.cs_nifree = sblock.fs_ipg; if (cgrp.cg_rotor < newcg->cg_ndblk) newcg->cg_rotor = cgrp.cg_rotor; else newcg->cg_rotor = 0; if (cgrp.cg_frotor < newcg->cg_ndblk) newcg->cg_frotor = cgrp.cg_frotor; else newcg->cg_frotor = 0; if (cgrp.cg_irotor < newcg->cg_niblk) newcg->cg_irotor = cgrp.cg_irotor; else newcg->cg_irotor = 0; bzero((char *)newcg->cg_frsum, sizeof newcg->cg_frsum); bzero((char *)newcg->cg_btot, sizeof newcg->cg_btot); bzero((char *)newcg->cg_b, sizeof newcg->cg_b); bzero((char *)newcg->cg_free, howmany(sblock.fs_fpg, NBBY)); bzero((char *)newcg->cg_iused, howmany(sblock.fs_ipg, NBBY)); j = sblock.fs_ipg * c; for (i = 0; i < sblock.fs_ipg; j++, i++) { switch (statemap[j]) { case USTATE: break; case DSTATE: case DCLEAR: case DFOUND: newcg->cg_cs.cs_ndir++; /* fall through */ case FSTATE: case FCLEAR: newcg->cg_cs.cs_nifree--; setbit(newcg->cg_iused, i); break; default: if (j < ROOTINO) break; errexit("BAD STATE %d FOR INODE I=%d", statemap[j], j); } } if (c == 0) for (i = 0; i < ROOTINO; i++) { setbit(newcg->cg_iused, i); newcg->cg_cs.cs_nifree--; } for (i = 0, d = dbase; d <= dmax - sblock.fs_frag; d += sblock.fs_frag, i += sblock.fs_frag) { frags = 0; for (j = 0; j < sblock.fs_frag; j++) { if (getbmap(d + j)) continue; setbit(newcg->cg_free, i + j); frags++; } if (frags == sblock.fs_frag) { newcg->cg_cs.cs_nbfree++; j = cbtocylno(&sblock, i); newcg->cg_btot[j]++; newcg->cg_b[j][cbtorpos(&sblock, i)]++; } else if (frags > 0) { newcg->cg_cs.cs_nffree += frags; blk = blkmap(&sblock, newcg->cg_free, i); fragacct(&sblock, blk, newcg->cg_frsum, 1); } } for (frags = d; d < dmax; d++) { if (getbmap(d)) continue; setbit(newcg->cg_free, d - dbase); newcg->cg_cs.cs_nffree++; } if (frags != d) { blk = blkmap(&sblock, newcg->cg_free, (frags - dbase)); fragacct(&sblock, blk, newcg->cg_frsum, 1); } cstotal.cs_nffree += newcg->cg_cs.cs_nffree; cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree; cstotal.cs_nifree += newcg->cg_cs.cs_nifree; cstotal.cs_ndir += newcg->cg_cs.cs_ndir; if (bcmp(newcg->cg_iused, cgrp.cg_iused, mapsize) != 0 && dofix(&idesc, "BLK(S) MISSING IN BIT MAPS")) { bcopy(newcg->cg_iused, cgrp.cg_iused, mapsize); cgdirty(); } if (bcmp((char *)newcg, (char *)&cgrp, sumsize) != 0 && dofix(&idesc, "SUMMARY INFORMATION BAD")) { bcopy((char *)newcg, (char *)&cgrp, sumsize); cgdirty(); } cs = &sblock.fs_cs(&sblock, c); if (bcmp((char *)&newcg->cg_cs, (char *)cs, sizeof *cs) != 0 && dofix(&idesc, "FREE BLK COUNT(S) WRONG IN SUPERBLK")) { bcopy((char *)&newcg->cg_cs, (char *)cs, sizeof *cs); sbdirty(); } } if (bcmp((char *)&cstotal, (char *)&sblock.fs_cstotal, sizeof *cs) != 0 && dofix(&idesc, "FREE BLK COUNT(S) WRONG IN SUPERBLK")) { bcopy((char *)&cstotal, (char *)&sblock.fs_cstotal, sizeof *cs); sblock.fs_ronly = 0; sblock.fs_fmod = 0; sbdirty(); } }
makefree() { register i, cyl, step; int j; char flg[MAXCYL]; short addr[MAXCYL]; daddr_t blk, baseblk; sblock.fs_nfree = 0; sblock.fs_flock = 0; sblock.fs_fmod = 0; sblock.fs_tfree = 0; sblock.fs_ninode = 0; sblock.fs_ilock = 0; sblock.fs_ronly = 0; if(cylsize == 0 || stepsize == 0) { step = sblock.fs_step; cyl = sblock.fs_cyl; } else { step = stepsize; cyl = cylsize; } if(step > cyl || step <= 0 || cyl <= 0 || cyl > MAXCYL) { printf("Default free list spacing assumed\n"); step = STEPSIZE; cyl = CYLSIZE; } sblock.fs_step = step; sblock.fs_cyl = cyl; bzero(flg,sizeof(flg)); i = 0; for(j = 0; j < cyl; j++) { while(flg[i]) i = (i + 1) % cyl; addr[j] = i + 1; flg[i]++; i = (i + step) % cyl; } baseblk = (daddr_t)roundup(fmax,cyl); bzero((char *)&freeblk,DEV_BSIZE); freeblk.df_nfree++; for( ; baseblk > 0; baseblk -= cyl) for(i = 0; i < cyl; i++) { blk = baseblk - addr[i]; if(!outrange(blk) && !getbmap(blk)) { sblock.fs_tfree++; if(freeblk.df_nfree >= NICFREE) { fbdirty(); fileblk.b_bno = blk; flush(&dfile,&fileblk); bzero((char *)&freeblk,DEV_BSIZE); } freeblk.df_free[freeblk.df_nfree] = blk; freeblk.df_nfree++; } } sblock.fs_nfree = freeblk.df_nfree; for(i = 0; i < NICFREE; i++) sblock.fs_free[i] = freeblk.df_free[i]; sbdirty(); }
int setup(const char *dev) { long bmapsize; struct stat statb; int doskipclean; u_int64_t maxfilesize; int open_flags; struct uvnode *ivp; struct ubuf *bp; int i, isdirty; long sn, curseg; SEGUSE *sup; havesb = 0; doskipclean = skipclean; if (stat(dev, &statb) < 0) { pfatal("Can't stat %s: %s\n", dev, strerror(errno)); return (0); } if (!S_ISCHR(statb.st_mode) && skipclean) { pfatal("%s is not a character device", dev); if (reply("CONTINUE") == 0) return (0); } if (nflag) open_flags = O_RDONLY; else open_flags = O_RDWR; if ((fsreadfd = open(dev, open_flags)) < 0) { pfatal("Can't open %s: %s\n", dev, strerror(errno)); return (0); } if (nflag) { if (preen) pfatal("NO WRITE ACCESS"); printf("** %s (NO WRITE)\n", dev); quiet = 0; } else if (!preen && !quiet) printf("** %s\n", dev); fsmodified = 0; lfdir = 0; /* Initialize time in case we have to write */ time(&write_time); bufinit(0); /* XXX we could make a better guess */ fs = lfs_init(fsreadfd, bflag, idaddr, 0, debug); if (fs == NULL) { if (preen) printf("%s: ", cdevname()); errexit("BAD SUPER BLOCK OR IFILE INODE NOT FOUND"); } /* Resize buffer cache now that we have a superblock to guess from. */ bufrehash((fs->lfs_segtabsz + maxino / fs->lfs_ifpb) << 4); if (fs->lfs_pflags & LFS_PF_CLEAN) { if (doskipclean) { if (!quiet) pwarn("%sile system is clean; not checking\n", preen ? "f" : "** F"); return (-1); } if (!preen) pwarn("** File system is already clean\n"); } if (idaddr) { daddr_t tdaddr; SEGSUM *sp; FINFO *fp; int bc; if (debug) pwarn("adjusting offset, serial for -i 0x%lx\n", (unsigned long)idaddr); tdaddr = lfs_sntod(fs, lfs_dtosn(fs, idaddr)); if (lfs_sntod(fs, lfs_dtosn(fs, tdaddr)) == tdaddr) { if (tdaddr == fs->lfs_start) tdaddr += lfs_btofsb(fs, LFS_LABELPAD); for (i = 0; i < LFS_MAXNUMSB; i++) { if (fs->lfs_sboffs[i] == tdaddr) tdaddr += lfs_btofsb(fs, LFS_SBPAD); if (fs->lfs_sboffs[i] > tdaddr) break; } } fs->lfs_offset = tdaddr; if (debug) pwarn("begin with offset/serial 0x%x/%d\n", (int)fs->lfs_offset, (int)fs->lfs_serial); while (tdaddr < idaddr) { bread(fs->lfs_devvp, LFS_FSBTODB(fs, tdaddr), fs->lfs_sumsize, NULL, 0, &bp); sp = (SEGSUM *)bp->b_data; if (sp->ss_sumsum != cksum(&sp->ss_datasum, fs->lfs_sumsize - sizeof(sp->ss_sumsum))) { brelse(bp, 0); if (debug) printf("bad cksum at %x\n", (unsigned)tdaddr); break; } fp = (FINFO *)(sp + 1); bc = howmany(sp->ss_ninos, LFS_INOPB(fs)) << (fs->lfs_version > 1 ? fs->lfs_ffshift : fs->lfs_bshift); for (i = 0; i < sp->ss_nfinfo; i++) { bc += fp->fi_lastlength + ((fp->fi_nblocks - 1) << fs->lfs_bshift); fp = (FINFO *)(fp->fi_blocks + fp->fi_nblocks); } tdaddr += lfs_btofsb(fs, bc) + 1; fs->lfs_offset = tdaddr; fs->lfs_serial = sp->ss_serial + 1; brelse(bp, 0); } /* * Set curseg, nextseg appropriately -- inlined from * lfs_newseg() */ curseg = lfs_dtosn(fs, fs->lfs_offset); fs->lfs_curseg = lfs_sntod(fs, curseg); for (sn = curseg + fs->lfs_interleave;;) { sn = (sn + 1) % fs->lfs_nseg; if (sn == curseg) errx(1, "init: no clean segments"); LFS_SEGENTRY(sup, fs, sn, bp); isdirty = sup->su_flags & SEGUSE_DIRTY; brelse(bp, 0); if (!isdirty) break; } /* Skip superblock if necessary */ for (i = 0; i < LFS_MAXNUMSB; i++) if (fs->lfs_offset == fs->lfs_sboffs[i]) fs->lfs_offset += lfs_btofsb(fs, LFS_SBPAD); ++fs->lfs_nactive; fs->lfs_nextseg = lfs_sntod(fs, sn); if (debug) { pwarn("offset = 0x%" PRIx32 ", serial = %" PRId64 "\n", fs->lfs_offset, fs->lfs_serial); pwarn("curseg = %" PRIx32 ", nextseg = %" PRIx32 "\n", fs->lfs_curseg, fs->lfs_nextseg); } if (!nflag && !skipclean) { fs->lfs_idaddr = idaddr; fsmodified = 1; sbdirty(); } } if (debug) { pwarn("idaddr = 0x%lx\n", idaddr ? (unsigned long)idaddr : (unsigned long)fs->lfs_idaddr); pwarn("dev_bsize = %lu\n", dev_bsize); pwarn("lfs_bsize = %lu\n", (unsigned long) fs->lfs_bsize); pwarn("lfs_fsize = %lu\n", (unsigned long) fs->lfs_fsize); pwarn("lfs_frag = %lu\n", (unsigned long) fs->lfs_frag); pwarn("lfs_inopb = %lu\n", (unsigned long) fs->lfs_inopb); } if (fs->lfs_version == 1) maxfsblock = fs->lfs_size * (fs->lfs_bsize / dev_bsize); else maxfsblock = fs->lfs_size; maxfilesize = calcmaxfilesize(fs->lfs_bshift); if (/* fs->lfs_minfree < 0 || */ fs->lfs_minfree > 99) { pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", fs->lfs_minfree); if (reply("SET TO DEFAULT") == 1) { fs->lfs_minfree = 10; sbdirty(); } } if (fs->lfs_bmask != fs->lfs_bsize - 1) { pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK (SHOULD BE 0x%x)", (unsigned int) fs->lfs_bmask, (unsigned int) fs->lfs_bsize - 1); fs->lfs_bmask = fs->lfs_bsize - 1; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); } } if (fs->lfs_ffmask != fs->lfs_fsize - 1) { pwarn("INCORRECT FFMASK=%" PRId64 " IN SUPERBLOCK", fs->lfs_ffmask); fs->lfs_ffmask = fs->lfs_fsize - 1; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); } } if (fs->lfs_fbmask != (1 << fs->lfs_fbshift) - 1) { pwarn("INCORRECT FBMASK=%" PRId64 " IN SUPERBLOCK", fs->lfs_fbmask); fs->lfs_fbmask = (1 << fs->lfs_fbshift) - 1; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); } } if (fs->lfs_maxfilesize != maxfilesize) { pwarn( "INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK (SHOULD BE %llu WITH BSHIFT %d)", (unsigned long long) fs->lfs_maxfilesize, (unsigned long long) maxfilesize, (int)fs->lfs_bshift); if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { fs->lfs_maxfilesize = maxfilesize; sbdirty(); } } if (fs->lfs_maxsymlinklen != ULFS1_MAXSYMLINKLEN) { pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", fs->lfs_maxsymlinklen); fs->lfs_maxsymlinklen = ULFS1_MAXSYMLINKLEN; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); } } /* * Read in the Ifile; we'll be using it a lot. * XXX If the Ifile is corrupted we are in bad shape. We need to * XXX run through the segment headers of the entire disk to * XXX reconstruct the inode table, then pretend all segments are * XXX dirty while we do the rest. */ ivp = fs->lfs_ivnode; maxino = ((VTOI(ivp)->i_ffs1_size - (fs->lfs_cleansz + fs->lfs_segtabsz) * fs->lfs_bsize) / fs->lfs_bsize) * fs->lfs_ifpb; if (debug) pwarn("maxino = %llu\n", (unsigned long long)maxino); for (i = 0; i < VTOI(ivp)->i_ffs1_size; i += fs->lfs_bsize) { bread(ivp, i >> fs->lfs_bshift, fs->lfs_bsize, NOCRED, 0, &bp); /* XXX check B_ERROR */ brelse(bp, 0); } /* * allocate and initialize the necessary maps */ din_table = ecalloc(maxino, sizeof(*din_table)); seg_table = ecalloc(fs->lfs_nseg, sizeof(SEGUSE)); /* Get segment flags */ for (i = 0; i < fs->lfs_nseg; i++) { LFS_SEGENTRY(sup, fs, i, bp); seg_table[i].su_flags = sup->su_flags & ~SEGUSE_ACTIVE; if (preen) seg_table[i].su_nbytes = sup->su_nbytes; brelse(bp, 0); } /* Initialize Ifile entry */ din_table[fs->lfs_ifile] = fs->lfs_idaddr; seg_table[lfs_dtosn(fs, fs->lfs_idaddr)].su_nbytes += LFS_DINODE1_SIZE; #ifndef VERBOSE_BLOCKMAP bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); blockmap = ecalloc(bmapsize, sizeof(char)); #else bmapsize = maxfsblock * sizeof(ino_t); blockmap = ecalloc(maxfsblock, sizeof(ino_t)); #endif statemap = ecalloc(maxino, sizeof(char)); typemap = ecalloc(maxino, sizeof(char)); lncntp = ecalloc(maxino, sizeof(int16_t)); if (preen) { n_files = fs->lfs_nfiles; n_blks = fs->lfs_dsize - fs->lfs_bfree; numdirs = maxino; inplast = 0; listmax = numdirs + 10; inpsort = ecalloc(listmax, sizeof(struct inoinfo *)); inphead = ecalloc(numdirs, sizeof(struct inoinfo *)); } return (1); ckfini(0); return (0); }
/* * Scan each entry in a directory block. */ int dirscan(struct inodesc *idesc) { struct direct *dp; struct bufarea *bp; int dsize, n; long blksiz; #if DIRBLKSIZ > APPLEUFS_DIRBLKSIZ char dbuf[DIRBLKSIZ]; #else char dbuf[APPLEUFS_DIRBLKSIZ]; #endif if (idesc->id_type != DATA) errexit("wrong type to dirscan %d", idesc->id_type); if (idesc->id_entryno == 0 && (idesc->id_filesize & (dirblksiz - 1)) != 0) idesc->id_filesize = roundup(idesc->id_filesize, dirblksiz); blksiz = idesc->id_numfrags * sblock->fs_fsize; if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { idesc->id_filesize -= blksiz; return (SKIP); } /* * If we are are swapping byte order in directory entries, just swap * this block and return. */ if (do_dirswap) { int off; bp = getdirblk(idesc->id_blkno, blksiz); for (off = 0; off < blksiz; off += iswap16(dp->d_reclen)) { dp = (struct direct *)(bp->b_un.b_buf + off); dp->d_ino = bswap32(dp->d_ino); dp->d_reclen = bswap16(dp->d_reclen); if (!newinofmt) { u_int8_t tmp = dp->d_namlen; dp->d_namlen = dp->d_type; dp->d_type = tmp; } if (dp->d_reclen == 0) break; } dirty(bp); idesc->id_filesize -= blksiz; return (idesc->id_filesize > 0 ? KEEPON : STOP); } idesc->id_loc = 0; for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { dsize = iswap16(dp->d_reclen); if (dsize > sizeof dbuf) dsize = sizeof dbuf; memmove(dbuf, dp, (size_t)dsize); # if (BYTE_ORDER == LITTLE_ENDIAN) if (!newinofmt && !needswap) { # else if (!newinofmt && needswap) { # endif struct direct *tdp = (struct direct *)dbuf; u_char tmp; tmp = tdp->d_namlen; tdp->d_namlen = tdp->d_type; tdp->d_type = tmp; } idesc->id_dirp = (struct direct *)dbuf; if ((n = (*idesc->id_func)(idesc)) & ALTERED) { # if (BYTE_ORDER == LITTLE_ENDIAN) if (!newinofmt && !doinglevel2 && !needswap) { # else if (!newinofmt && !doinglevel2 && needswap) { # endif struct direct *tdp; u_char tmp; tdp = (struct direct *)dbuf; tmp = tdp->d_namlen; tdp->d_namlen = tdp->d_type; tdp->d_type = tmp; } bp = getdirblk(idesc->id_blkno, blksiz); memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf, (size_t)dsize); dirty(bp); sbdirty(); } if (n & STOP) return (n); } return (idesc->id_filesize > 0 ? KEEPON : STOP); } /* * get next entry in a directory. */ static struct direct * fsck_readdir(struct inodesc *idesc) { struct direct *dp, *ndp; struct bufarea *bp; long size, blksiz, fix, dploc; blksiz = idesc->id_numfrags * sblock->fs_fsize; bp = getdirblk(idesc->id_blkno, blksiz); if (idesc->id_loc % dirblksiz == 0 && idesc->id_filesize > 0 && idesc->id_loc < blksiz) { dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); if (dircheck(idesc, dp)) goto dpok; if (idesc->id_fix == IGNORE) return (0); fix = dofix(idesc, "DIRECTORY CORRUPTED"); bp = getdirblk(idesc->id_blkno, blksiz); dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); dp->d_reclen = iswap16(dirblksiz); dp->d_ino = 0; dp->d_type = 0; dp->d_namlen = 0; dp->d_name[0] = '\0'; if (fix) dirty(bp); else markclean = 0; idesc->id_loc += dirblksiz; idesc->id_filesize -= dirblksiz; return (dp); } dpok: if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) return NULL; dploc = idesc->id_loc; dp = (struct direct *)(bp->b_un.b_buf + dploc); idesc->id_loc += iswap16(dp->d_reclen); idesc->id_filesize -= iswap16(dp->d_reclen); if ((idesc->id_loc % dirblksiz) == 0) return (dp); ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc); if (idesc->id_loc < blksiz && idesc->id_filesize > 0 && dircheck(idesc, ndp) == 0) { size = dirblksiz - (idesc->id_loc % dirblksiz); idesc->id_loc += size; idesc->id_filesize -= size; if (idesc->id_fix == IGNORE) return (0); fix = dofix(idesc, "DIRECTORY CORRUPTED"); bp = getdirblk(idesc->id_blkno, blksiz); dp = (struct direct *)(bp->b_un.b_buf + dploc); dp->d_reclen = iswap16(iswap16(dp->d_reclen) + size); if (fix) dirty(bp); else markclean = 0; } return (dp); } /* * Verify that a directory entry is valid. * This is a superset of the checks made in the kernel. */ static int dircheck(struct inodesc *idesc, struct direct *dp) { int size; char *cp; u_char namlen, type; int spaceleft; spaceleft = dirblksiz - (idesc->id_loc % dirblksiz); if (iswap32(dp->d_ino) >= maxino || dp->d_reclen == 0 || iswap16(dp->d_reclen) > spaceleft || (iswap16(dp->d_reclen) & 0x3) != 0) return (0); if (dp->d_ino == 0) return (1); size = DIRSIZ(!newinofmt, dp, needswap); # if (BYTE_ORDER == LITTLE_ENDIAN) if (!newinofmt && !needswap) { # else if (!newinofmt && needswap) { # endif type = dp->d_namlen; namlen = dp->d_type; } else { namlen = dp->d_namlen; type = dp->d_type; } if (iswap16(dp->d_reclen) < size || idesc->id_filesize < size || /* namlen > MAXNAMLEN || */ type > 15) return (0); for (cp = dp->d_name, size = 0; size < namlen; size++) if (*cp == '\0' || (*cp++ == '/')) return (0); if (*cp != '\0') return (0); return (1); } void direrror(ino_t ino, const char *errmesg) { fileerror(ino, ino, errmesg); } void fileerror(ino_t cwd, ino_t ino, const char *errmesg) { union dinode *dp; char pathbuf[MAXPATHLEN + 1]; uint16_t mode; pwarn("%s ", errmesg); pinode(ino); printf("\n"); getpathname(pathbuf, sizeof(pathbuf), cwd, ino); if (ino < ROOTINO || ino > maxino) { pfatal("NAME=%s\n", pathbuf); return; } dp = ginode(ino); if (ftypeok(dp)) { mode = DIP(dp, mode); pfatal("%s=%s\n", (iswap16(mode) & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf); } else pfatal("NAME=%s\n", pathbuf); } void adjust(struct inodesc *idesc, int lcnt) { union dinode *dp; int16_t nlink; int saveresolved; dp = ginode(idesc->id_number); nlink = iswap16(DIP(dp, nlink)); if (nlink == lcnt) { /* * If we have not hit any unresolved problems, are running * in preen mode, and are on a file system using soft updates, * then just toss any partially allocated files. */ if (resolved && preen && usedsoftdep) { clri(idesc, "UNREF", 1); return; } else { /* * The file system can be marked clean even if * a file is not linked up, but is cleared. * Hence, resolved should not be cleared when * linkup is answered no, but clri is answered yes. */ saveresolved = resolved; if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) { resolved = saveresolved; clri(idesc, "UNREF", 0); return; } /* * Account for the new reference created by linkup(). */ dp = ginode(idesc->id_number); lcnt--; } } if (lcnt != 0) { pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname : ((iswap16(DIP(dp, mode)) & IFMT) == IFDIR ? "DIR" : "FILE")); pinode(idesc->id_number); printf(" COUNT %d SHOULD BE %d", nlink, nlink - lcnt); if (preen || usedsoftdep) { if (lcnt < 0) { printf("\n"); pfatal("LINK COUNT INCREASING"); } if (preen) printf(" (ADJUSTED)\n"); } if (preen || reply("ADJUST") == 1) { DIP_SET(dp, nlink, iswap16(nlink - lcnt)); inodirty(); } else markclean = 0; } } static int mkentry(struct inodesc *idesc) { struct direct *dirp = idesc->id_dirp; struct direct newent; int newlen, oldlen; newent.d_namlen = strlen(idesc->id_name); newlen = DIRSIZ(0, &newent, 0); if (dirp->d_ino != 0) oldlen = DIRSIZ(0, dirp, 0); else oldlen = 0; if (iswap16(dirp->d_reclen) - oldlen < newlen) return (KEEPON); newent.d_reclen = iswap16(iswap16(dirp->d_reclen) - oldlen); dirp->d_reclen = iswap16(oldlen); dirp = (struct direct *)(((char *)dirp) + oldlen); /* ino to be entered is in id_parent */ dirp->d_ino = iswap32(idesc->id_parent); dirp->d_reclen = newent.d_reclen; if (newinofmt) dirp->d_type = inoinfo(idesc->id_parent)->ino_type; else dirp->d_type = 0; dirp->d_namlen = newent.d_namlen; memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1); # if (BYTE_ORDER == LITTLE_ENDIAN) /* * If the entry was split, dirscan() will only reverse the byte * order of the original entry, and not the new one, before * writing it back out. So, we reverse the byte order here if * necessary. */ if (oldlen != 0 && !newinofmt && !doinglevel2 && !needswap) { # else if (oldlen != 0 && !newinofmt && !doinglevel2 && needswap) { # endif u_char tmp; tmp = dirp->d_namlen; dirp->d_namlen = dirp->d_type; dirp->d_type = tmp; } return (ALTERED|STOP); } static int chgino(struct inodesc *idesc) { struct direct *dirp = idesc->id_dirp; if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1)) return (KEEPON); dirp->d_ino = iswap32(idesc->id_parent); if (newinofmt) dirp->d_type = inoinfo(idesc->id_parent)->ino_type; else dirp->d_type = 0; return (ALTERED|STOP); } int linkup(ino_t orphan, ino_t parentdir, char *name) { union dinode *dp; int lostdir; ino_t oldlfdir; struct inodesc idesc; char tempname[BUFSIZ]; int16_t nlink; uint16_t mode; memset(&idesc, 0, sizeof(struct inodesc)); dp = ginode(orphan); mode = iswap16(DIP(dp, mode)); nlink = iswap16(DIP(dp, nlink)); lostdir = (mode & IFMT) == IFDIR; pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); pinode(orphan); if (preen && DIP(dp, size) == 0) return (0); if (preen) printf(" (RECONNECTED)\n"); else if (reply("RECONNECT") == 0) { markclean = 0; return (0); } if (parentdir != 0) inoinfo(parentdir)->ino_linkcnt++; if (lfdir == 0) { dp = ginode(ROOTINO); idesc.id_name = lfname; idesc.id_type = DATA; idesc.id_func = findino; idesc.id_number = ROOTINO; if ((ckinode(dp, &idesc) & FOUND) != 0) { lfdir = idesc.id_parent; } else { pwarn("NO lost+found DIRECTORY"); if (preen || reply("CREATE")) { lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); if (lfdir != 0) { if (makeentry(ROOTINO, lfdir, lfname) != 0) { numdirs++; if (preen) printf(" (CREATED)\n"); } else { freedir(lfdir, ROOTINO); lfdir = 0; if (preen) printf("\n"); } } if (lfdir != 0) { reparent(lfdir, ROOTINO); } } } if (lfdir == 0) { pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); markclean = 0; return (0); } } dp = ginode(lfdir); mode = DIP(dp, mode); mode = iswap16(mode); if ((mode & IFMT) != IFDIR) { pfatal("lost+found IS NOT A DIRECTORY"); if (reply("REALLOCATE") == 0) { markclean = 0; return (0); } oldlfdir = lfdir; lfdir = allocdir(ROOTINO, (ino_t)0, lfmode); if (lfdir == 0) { pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); markclean = 0; return (0); } if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) { pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n"); markclean = 0; return (0); } inodirty(); reparent(lfdir, ROOTINO); idesc.id_type = ADDR; idesc.id_func = pass4check; idesc.id_number = oldlfdir; adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1); inoinfo(oldlfdir)->ino_linkcnt = 0; dp = ginode(lfdir); } if (inoinfo(lfdir)->ino_state != DFOUND) { pfatal("SORRY. NO lost+found DIRECTORY\n\n"); markclean = 0; return (0); } (void)lftempname(tempname, orphan); if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) { pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); printf("\n\n"); markclean = 0; return (0); } inoinfo(orphan)->ino_linkcnt--; if (lostdir) { if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 && parentdir != (ino_t)-1) (void)makeentry(orphan, lfdir, ".."); dp = ginode(lfdir); nlink = DIP(dp, nlink); DIP_SET(dp, nlink, iswap16(iswap16(nlink) + 1)); inodirty(); inoinfo(lfdir)->ino_linkcnt++; reparent(orphan, lfdir); pwarn("DIR I=%llu CONNECTED. ", (unsigned long long)orphan); if (parentdir != (ino_t)-1) printf("PARENT WAS I=%llu\n", (unsigned long long)parentdir); if (preen == 0) printf("\n"); } return (1); } /* * fix an entry in a directory. */ int changeino(ino_t dir, const char *name, ino_t newnum) { struct inodesc idesc; memset(&idesc, 0, sizeof(struct inodesc)); idesc.id_type = DATA; idesc.id_func = chgino; idesc.id_number = dir; idesc.id_fix = DONTKNOW; idesc.id_name = name; idesc.id_parent = newnum; /* new value for name */ return (ckinode(ginode(dir), &idesc)); } /* * make an entry in a directory */ int makeentry(ino_t parent, ino_t ino, const char *name) { union dinode *dp; struct inodesc idesc; char pathbuf[MAXPATHLEN + 1]; if (parent < ROOTINO || parent >= maxino || ino < ROOTINO || ino >= maxino) return (0); memset(&idesc, 0, sizeof(struct inodesc)); idesc.id_type = DATA; idesc.id_func = mkentry; idesc.id_number = parent; idesc.id_parent = ino; /* this is the inode to enter */ idesc.id_fix = DONTKNOW; idesc.id_name = name; dp = ginode(parent); if (iswap64(DIP(dp, size)) % dirblksiz) { DIP_SET(dp, size, iswap64(roundup(iswap64(DIP(dp, size)), dirblksiz))); inodirty(); } if ((ckinode(dp, &idesc) & ALTERED) != 0) return (1); getpathname(pathbuf, sizeof(pathbuf), parent, parent); dp = ginode(parent); if (expanddir(dp, pathbuf) == 0) return (0); return (ckinode(dp, &idesc) & ALTERED); } /* * Attempt to expand the size of a directory */ static int expanddir(union dinode *dp, char *name) { daddr_t lastbn, newblk, dirblk; struct bufarea *bp; char *cp; #if DIRBLKSIZ > APPLEUFS_DIRBLKSIZ char firstblk[DIRBLKSIZ]; #else char firstblk[APPLEUFS_DIRBLKSIZ]; #endif struct ufs1_dinode *dp1 = NULL; struct ufs2_dinode *dp2 = NULL; if (is_ufs2) dp2 = &dp->dp2; else dp1 = &dp->dp1; lastbn = lblkno(sblock, iswap64(DIP(dp, size))); if (lastbn >= NDADDR - 1 || DIP(dp, db[lastbn]) == 0 || DIP(dp, size) == 0) return (0); if ((newblk = allocblk(sblock->fs_frag)) == 0) return (0); if (is_ufs2) { dp2->di_db[lastbn + 1] = dp2->di_db[lastbn]; dp2->di_db[lastbn] = iswap64(newblk); dp2->di_size = iswap64(iswap64(dp2->di_size)+sblock->fs_bsize); dp2->di_blocks = iswap64(iswap64(dp2->di_blocks) + btodb(sblock->fs_bsize)); dirblk = iswap64(dp2->di_db[lastbn + 1]); } else { dp1->di_db[lastbn + 1] = dp1->di_db[lastbn]; dp1->di_db[lastbn] = iswap32((int32_t)newblk); dp1->di_size = iswap64(iswap64(dp1->di_size)+sblock->fs_bsize); dp1->di_blocks = iswap32(iswap32(dp1->di_blocks) + btodb(sblock->fs_bsize)); dirblk = iswap32(dp1->di_db[lastbn + 1]); } bp = getdirblk(dirblk, sblksize(sblock, DIP(dp, size), lastbn + 1)); if (bp->b_errs) goto bad; memmove(firstblk, bp->b_un.b_buf, dirblksiz); bp = getdirblk(newblk, sblock->fs_bsize); if (bp->b_errs) goto bad; memmove(bp->b_un.b_buf, firstblk, dirblksiz); emptydir.dot_reclen = iswap16(dirblksiz); for (cp = &bp->b_un.b_buf[dirblksiz]; cp < &bp->b_un.b_buf[sblock->fs_bsize]; cp += dirblksiz) memmove(cp, &emptydir, sizeof emptydir); dirty(bp); bp = getdirblk(dirblk, sblksize(sblock, DIP(dp, size), lastbn + 1)); if (bp->b_errs) goto bad; memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir); pwarn("NO SPACE LEFT IN %s", name); if (preen) printf(" (EXPANDED)\n"); else if (reply("EXPAND") == 0) goto bad; dirty(bp); inodirty(); return (1); bad: if (is_ufs2) { dp2->di_db[lastbn] = dp2->di_db[lastbn + 1]; dp2->di_db[lastbn + 1] = 0; dp2->di_size = iswap64(iswap64(dp2->di_size)-sblock->fs_bsize); dp2->di_blocks = iswap64(iswap64(dp2->di_blocks) - btodb(sblock->fs_bsize)); } else { dp1->di_db[lastbn] = dp1->di_db[lastbn + 1]; dp1->di_db[lastbn + 1] = 0; dp1->di_size = iswap64(iswap64(dp1->di_size)-sblock->fs_bsize); dp1->di_blocks = iswap32(iswap32(dp1->di_blocks) - btodb(sblock->fs_bsize)); } freeblk(newblk, sblock->fs_frag); markclean = 0; return (0); } /* * allocate a new directory */ ino_t allocdir(ino_t parent, ino_t request, int mode) { ino_t ino; char *cp; union dinode *dp; struct bufarea *bp; struct inoinfo *inp; struct dirtemplate *dirp; daddr_t dirblk; ino = allocino(request, IFDIR|mode); if (ino < ROOTINO) return 0; dirhead.dot_reclen = iswap16(12); dirhead.dotdot_reclen = iswap16(dirblksiz - 12); odirhead.dot_reclen = iswap16(12); odirhead.dotdot_reclen = iswap16(dirblksiz - 12); odirhead.dot_namlen = iswap16(1); odirhead.dotdot_namlen = iswap16(2); if (newinofmt) dirp = &dirhead; else dirp = (struct dirtemplate *)&odirhead; dirp->dot_ino = iswap32(ino); dirp->dotdot_ino = iswap32(parent); dp = ginode(ino); dirblk = is_ufs2 ? iswap64(dp->dp2.di_db[0]) : iswap32(dp->dp1.di_db[0]); bp = getdirblk(dirblk, sblock->fs_fsize); if (bp->b_errs) { freeino(ino); return (0); } memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate)); emptydir.dot_reclen = iswap16(dirblksiz); for (cp = &bp->b_un.b_buf[dirblksiz]; cp < &bp->b_un.b_buf[sblock->fs_fsize]; cp += dirblksiz) memmove(cp, &emptydir, sizeof emptydir); dirty(bp); DIP_SET(dp, nlink, iswap16(2)); inodirty(); if (ino == ROOTINO) { inoinfo(ino)->ino_linkcnt = iswap16(DIP(dp, nlink)); cacheino(dp, ino); return(ino); } if (inoinfo(parent)->ino_state != DSTATE && inoinfo(parent)->ino_state != DFOUND) { freeino(ino); return (0); } cacheino(dp, ino); inp = getinoinfo(ino); inp->i_parent = parent; inp->i_dotdot = parent; inoinfo(ino)->ino_state = inoinfo(parent)->ino_state; if (inoinfo(ino)->ino_state == DSTATE) { inoinfo(ino)->ino_linkcnt = iswap16(DIP(dp, nlink)); inoinfo(parent)->ino_linkcnt++; } dp = ginode(parent); DIP_SET(dp, nlink, iswap16(iswap16(DIP(dp, nlink)) + 1)); inodirty(); return (ino); }
int setup(const char *dev) { long cg, asked, i; long bmapsize; struct disklabel *lp; off_t sizepb; struct stat statb; struct m_ext2fs proto; int doskipclean; u_int64_t maxfilesize; havesb = 0; fswritefd = -1; doskipclean = skipclean; if (stat(dev, &statb) < 0) { printf("Can't stat %s: %s\n", dev, strerror(errno)); return 0; } if (!S_ISCHR(statb.st_mode)) { pfatal("%s is not a character device", dev); if (reply("CONTINUE") == 0) return 0; } if ((fsreadfd = open(dev, O_RDONLY)) < 0) { printf("Can't open %s: %s\n", dev, strerror(errno)); return 0; } if (preen == 0) printf("** %s", dev); if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { fswritefd = -1; if (preen) pfatal("NO WRITE ACCESS"); printf(" (NO WRITE)"); } if (preen == 0) printf("\n"); fsmodified = 0; lfdir = 0; initbarea(&sblk); initbarea(&asblk); sblk.b_un.b_buf = malloc(SBSIZE); asblk.b_un.b_buf = malloc(SBSIZE); if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) errexit("cannot allocate space for superblock"); if ((lp = getdisklabel(NULL, fsreadfd)) != NULL) dev_bsize = secsize = lp->d_secsize; else dev_bsize = secsize = DEV_BSIZE; /* * Read in the superblock, looking for alternates if necessary */ if (readsb(1) == 0) { if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) return 0; if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) return 0; for (cg = 1; cg < proto.e2fs_ncg; cg++) { bflag = EXT2_FSBTODB(&proto, cg * proto.e2fs.e2fs_bpg + proto.e2fs.e2fs_first_dblock); if (readsb(0) != 0) break; } if (cg >= proto.e2fs_ncg) { printf("%s %s\n%s %s\n%s %s\n", "SEARCH FOR ALTERNATE SUPER-BLOCK", "FAILED. YOU MUST USE THE", "-b OPTION TO FSCK_FFS TO SPECIFY THE", "LOCATION OF AN ALTERNATE", "SUPER-BLOCK TO SUPPLY NEEDED", "INFORMATION; SEE fsck_ext2fs(8)."); return 0; } doskipclean = 0; pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); } if (debug) printf("state = %d\n", sblock.e2fs.e2fs_state); if (sblock.e2fs.e2fs_state == E2FS_ISCLEAN) { if (doskipclean) { pwarn("%sile system is clean; not checking\n", preen ? "f" : "** F"); return -1; } if (!preen) pwarn("** File system is already clean\n"); } maxfsblock = sblock.e2fs.e2fs_bcount; maxino = sblock.e2fs_ncg * sblock.e2fs.e2fs_ipg; sizepb = sblock.e2fs_bsize; maxfilesize = sblock.e2fs_bsize * EXT2FS_NDADDR - 1; for (i = 0; i < EXT2FS_NIADDR; i++) { sizepb *= EXT2_NINDIR(&sblock); maxfilesize += sizepb; } /* * Check and potentially fix certain fields in the super block. */ if (/* (sblock.e2fs.e2fs_rbcount < 0) || */ (sblock.e2fs.e2fs_rbcount > sblock.e2fs.e2fs_bcount)) { pfatal("IMPOSSIBLE RESERVED BLOCK COUNT=%d IN SUPERBLOCK", sblock.e2fs.e2fs_rbcount); if (reply("SET TO DEFAULT") == 1) { sblock.e2fs.e2fs_rbcount = sblock.e2fs.e2fs_bcount * MINFREE / 100; sbdirty(); dirty(&asblk); } } if (sblock.e2fs.e2fs_bpg != sblock.e2fs.e2fs_fpg) { pfatal("WRONG FPG=%d (BPG=%d) IN SUPERBLOCK", sblock.e2fs.e2fs_fpg, sblock.e2fs.e2fs_bpg); return 0; } if (asblk.b_dirty && !bflag) { copyback_sb(&asblk); flush(fswritefd, &asblk); } /* * read in the summary info. */ sblock.e2fs_gd = malloc(sblock.e2fs_ngdb * sblock.e2fs_bsize); if (sblock.e2fs_gd == NULL) errexit("out of memory"); asked = 0; for (i = 0; i < sblock.e2fs_ngdb; i++) { if (bread(fsreadfd, (char *)&sblock.e2fs_gd[i * sblock.e2fs_bsize / sizeof(struct ext2_gd)], EXT2_FSBTODB(&sblock, ((sblock.e2fs_bsize > 1024) ? 0 : 1) + i + 1), sblock.e2fs_bsize) != 0 && !asked) { pfatal("BAD SUMMARY INFORMATION"); if (reply("CONTINUE") == 0) exit(FSCK_EXIT_CHECK_FAILED); asked++; } } /* * allocate and initialize the necessary maps */ bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); blockmap = calloc((unsigned int)bmapsize, sizeof(char)); if (blockmap == NULL) { printf("cannot alloc %u bytes for blockmap\n", (unsigned int)bmapsize); goto badsblabel; } statemap = calloc((unsigned int)(maxino + 2), sizeof(char)); if (statemap == NULL) { printf("cannot alloc %u bytes for statemap\n", (unsigned int)(maxino + 1)); goto badsblabel; } typemap = calloc((unsigned int)(maxino + 1), sizeof(char)); if (typemap == NULL) { printf("cannot alloc %u bytes for typemap\n", (unsigned int)(maxino + 1)); goto badsblabel; } lncntp = calloc((unsigned)(maxino + 1), sizeof(int16_t)); if (lncntp == NULL) { printf("cannot alloc %u bytes for lncntp\n", (unsigned int)((maxino + 1) * sizeof(int16_t))); goto badsblabel; } for (numdirs = 0, cg = 0; cg < sblock.e2fs_ncg; cg++) { numdirs += fs2h16(sblock.e2fs_gd[cg].ext2bgd_ndirs); } inplast = 0; listmax = numdirs + 10; inpsort = calloc((unsigned int)listmax, sizeof(struct inoinfo *)); inphead = calloc((unsigned int)numdirs, sizeof(struct inoinfo *)); if (inpsort == NULL || inphead == NULL) { printf("cannot alloc %u bytes for inphead\n", (unsigned int)(numdirs * sizeof(struct inoinfo *))); goto badsblabel; } bufinit(); return 1; badsblabel: ckfini(0); return 0; }
void ckfini(int markclean) { struct bufarea *bp, *nbp; int ofsmodified, cnt = 0; if (bkgrdflag) { unlink(snapname); if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) { cmd.value = FS_UNCLEAN; cmd.size = markclean ? -1 : 1; if (sysctlbyname("vfs.ffs.setflags", 0, 0, &cmd, sizeof cmd) == -1) rwerror("SET FILE SYSTEM FLAGS", FS_UNCLEAN); if (!preen) { printf("\n***** FILE SYSTEM MARKED %s *****\n", markclean ? "CLEAN" : "DIRTY"); if (!markclean) rerun = 1; } } else if (!preen && !markclean) { printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); rerun = 1; } } if (fswritefd < 0) { (void)close(fsreadfd); return; } flush(fswritefd, &sblk); if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC && sblk.b_bno != sblock.fs_sblockloc / dev_bsize && !preen && reply("UPDATE STANDARD SUPERBLOCK")) { sblk.b_bno = sblock.fs_sblockloc / dev_bsize; sbdirty(); flush(fswritefd, &sblk); } flush(fswritefd, &cgblk); free(cgblk.b_un.b_buf); for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { cnt++; flush(fswritefd, bp); nbp = bp->b_prev; free(bp->b_un.b_buf); free((char *)bp); } if (bufhead.b_size != cnt) errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt); pbp = pdirbp = (struct bufarea *)0; if (cursnapshot == 0 && sblock.fs_clean != markclean) { if ((sblock.fs_clean = markclean) != 0) { sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK); sblock.fs_pendingblocks = 0; sblock.fs_pendinginodes = 0; } sbdirty(); ofsmodified = fsmodified; flush(fswritefd, &sblk); fsmodified = ofsmodified; if (!preen) { printf("\n***** FILE SYSTEM MARKED %s *****\n", markclean ? "CLEAN" : "DIRTY"); if (!markclean) rerun = 1; } } else if (!preen) { if (markclean) { printf("\n***** FILE SYSTEM IS CLEAN *****\n"); } else { printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); rerun = 1; } } if (debug && totalreads > 0) printf("cache missed %ld of %ld (%d%%)\n", diskreads, totalreads, (int)(diskreads * 100 / totalreads)); (void)close(fsreadfd); (void)close(fswritefd); }
/* * Insert the journal file into the ROOTINO directory. We always extend the * last frag */ static int journal_insertfile(ino_t ino) { struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; void *ip; ufs2_daddr_t nblk; ufs2_daddr_t blk; ufs_lbn_t lbn; int size; int mode; int off; if (getino(&disk, &ip, ROOTINO, &mode) != 0) { warn("Failed to get root inode"); sbdirty(); return (-1); } dp2 = ip; dp1 = ip; blk = 0; size = 0; nblk = journal_balloc(); if (nblk <= 0) return (-1); /* * For simplicity sake we aways extend the ROOTINO into a new * directory block rather than searching for space and inserting * into an existing block. However, if the rootino has frags * have to free them and extend the block. */ if (sblock.fs_magic == FS_UFS1_MAGIC) { lbn = lblkno(&sblock, dp1->di_size); off = blkoff(&sblock, dp1->di_size); blk = dp1->di_db[lbn]; size = sblksize(&sblock, (off_t)dp1->di_size, lbn); } else { lbn = lblkno(&sblock, dp2->di_size); off = blkoff(&sblock, dp2->di_size); blk = dp2->di_db[lbn]; size = sblksize(&sblock, (off_t)dp2->di_size, lbn); } if (off != 0) { if (dir_extend(blk, nblk, off, ino) == -1) return (-1); } else { blk = 0; if (dir_insert(nblk, 0, ino) == -1) return (-1); } if (sblock.fs_magic == FS_UFS1_MAGIC) { dp1->di_blocks += (sblock.fs_bsize - size) / DEV_BSIZE; dp1->di_db[lbn] = nblk; dp1->di_size = lblktosize(&sblock, lbn+1); } else { dp2->di_blocks += (sblock.fs_bsize - size) / DEV_BSIZE; dp2->di_db[lbn] = nblk; dp2->di_size = lblktosize(&sblock, lbn+1); } if (putino(&disk) < 0) { warn("Failed to write root inode"); return (-1); } if (cgwrite(&disk) < 0) { warn("Failed to write updated cg"); sbdirty(); return (-1); } if (blk) { if (cgbfree(&disk, blk, size) < 0) { warn("Failed to write cg"); return (-1); } } return (0); }
static int journal_alloc(int64_t size) { struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; ufs2_daddr_t blk; void *ip; struct cg *cgp; int resid; ino_t ino; int blks; int mode; time_t utime; int i; cgp = &disk.d_cg; ino = 0; /* * If the journal file exists we can't allocate it. */ ino = journal_findfile(); if (ino == (ino_t)-1) return (-1); if (ino > 0) { warnx("Journal file %s already exists, please remove.", SUJ_FILE); return (-1); } /* * If the user didn't supply a size pick one based on the filesystem * size constrained with hardcoded MIN and MAX values. We opt for * 1/1024th of the filesystem up to MAX but not exceeding one CG and * not less than the MIN. */ if (size == 0) { size = (sblock.fs_size * sblock.fs_bsize) / 1024; size = MIN(SUJ_MAX, size); if (size / sblock.fs_fsize > sblock.fs_fpg) size = sblock.fs_fpg * sblock.fs_fsize; size = MAX(SUJ_MIN, size); /* fsck does not support fragments in journal files. */ size = roundup(size, sblock.fs_bsize); } resid = blocks = size / sblock.fs_bsize; if (sblock.fs_cstotal.cs_nbfree < blocks) { warn("Insufficient free space for %jd byte journal", size); return (-1); } /* * Find a cg with enough blocks to satisfy the journal * size. Presently the journal does not span cgs. */ while (cgread(&disk) == 1) { if (cgp->cg_cs.cs_nifree == 0) continue; ino = cgialloc(&disk); if (ino <= 0) break; printf("Using inode %ju in cg %d for %jd byte journal\n", (uintmax_t)ino, cgp->cg_cgx, size); if (getino(&disk, &ip, ino, &mode) != 0) { warn("Failed to get allocated inode"); sbdirty(); goto out; } /* * We leave fields unrelated to the number of allocated * blocks and size uninitialized. This causes legacy * fsck implementations to clear the inode. */ dp2 = ip; dp1 = ip; time(&utime); if (sblock.fs_magic == FS_UFS1_MAGIC) { bzero(dp1, sizeof(*dp1)); dp1->di_size = size; dp1->di_mode = IFREG | IREAD; dp1->di_nlink = 1; dp1->di_flags = SF_IMMUTABLE | SF_NOUNLINK | UF_NODUMP; dp1->di_atime = utime; dp1->di_mtime = utime; dp1->di_ctime = utime; } else { bzero(dp2, sizeof(*dp2)); dp2->di_size = size; dp2->di_mode = IFREG | IREAD; dp2->di_nlink = 1; dp2->di_flags = SF_IMMUTABLE | SF_NOUNLINK | UF_NODUMP; dp2->di_atime = utime; dp2->di_mtime = utime; dp2->di_ctime = utime; dp2->di_birthtime = utime; } for (i = 0; i < NDADDR && resid; i++, resid--) { blk = journal_balloc(); if (blk <= 0) goto out; if (sblock.fs_magic == FS_UFS1_MAGIC) { dp1->di_db[i] = blk; dp1->di_blocks++; } else { dp2->di_db[i] = blk; dp2->di_blocks++; } } for (i = 0; i < NIADDR && resid; i++) { blk = journal_balloc(); if (blk <= 0) goto out; blks = indir_fill(blk, i, &resid) + 1; if (blks <= 0) { sbdirty(); goto out; } if (sblock.fs_magic == FS_UFS1_MAGIC) { dp1->di_ib[i] = blk; dp1->di_blocks += blks; } else { dp2->di_ib[i] = blk; dp2->di_blocks += blks; } } if (sblock.fs_magic == FS_UFS1_MAGIC) dp1->di_blocks *= sblock.fs_bsize / disk.d_bsize; else dp2->di_blocks *= sblock.fs_bsize / disk.d_bsize; if (putino(&disk) < 0) { warn("Failed to write inode"); sbdirty(); return (-1); } if (cgwrite(&disk) < 0) { warn("Failed to write updated cg"); sbdirty(); return (-1); } if (journal_insertfile(ino) < 0) { sbdirty(); return (-1); } sblock.fs_sujfree = 0; return (0); } warnx("Insufficient free space for the journal."); out: return (-1); }
int setup(char *dev) { long cg, size, asked, i, j, bmapsize; struct disklabel *lp; off_t sizepb; struct stat statb; struct fs proto; int doskipclean; int32_t maxsymlinklen, nindir, inopb; u_int64_t maxfilesize; char *realdev; havesb = 0; fswritefd = fsreadfd = -1; doskipclean = skipclean; if ((fsreadfd = opendev(dev, O_RDONLY, 0, &realdev)) < 0) { printf("Can't open %s: %s\n", dev, strerror(errno)); return (0); } if (strncmp(dev, realdev, PATH_MAX) != 0) { blockcheck(unrawname(realdev)); strlcpy(rdevname, realdev, sizeof(rdevname)); setcdevname(rdevname, dev, preen); } if (fstat(fsreadfd, &statb) < 0) { printf("Can't stat %s: %s\n", realdev, strerror(errno)); close(fsreadfd); return (0); } if (!S_ISCHR(statb.st_mode)) { pfatal("%s is not a character device", realdev); if (reply("CONTINUE") == 0) { close(fsreadfd); return (0); } } if (preen == 0) { printf("** %s", realdev); if (strncmp(dev, realdev, PATH_MAX) != 0) printf(" (%s)", dev); } if (nflag || (fswritefd = opendev(dev, O_WRONLY, 0, NULL)) < 0) { fswritefd = -1; if (preen) pfatal("NO WRITE ACCESS"); printf(" (NO WRITE)"); } if (preen == 0) printf("\n"); fsmodified = 0; lfdir = 0; initbarea(&sblk); initbarea(&asblk); sblk.b_un.b_buf = malloc(SBSIZE); asblk.b_un.b_buf = malloc(SBSIZE); if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) errexit("cannot allocate space for superblock\n"); if ((lp = getdisklabel(NULL, fsreadfd)) != NULL) dev_bsize = secsize = lp->d_secsize; else dev_bsize = secsize = DEV_BSIZE; /* * Read in the superblock, looking for alternates if necessary */ if (readsb(1) == 0) { if (bflag || preen || calcsb(realdev, fsreadfd, &proto) == 0) return(0); if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) return (0); for (i = 0; i < sizeof(altsbtry) / sizeof(altsbtry[0]); i++) { bflag = altsbtry[i]; /* proto partially setup by calcsb */ if (readsb(0) != 0 && proto.fs_fsize == sblock.fs_fsize && proto.fs_bsize == sblock.fs_bsize) goto found; } for (cg = 0; cg < proto.fs_ncg; cg++) { bflag = fsbtodb(&proto, cgsblock(&proto, cg)); if (readsb(0) != 0) break; } if (cg >= proto.fs_ncg) { printf("%s %s\n%s %s\n%s %s\n", "SEARCH FOR ALTERNATE SUPER-BLOCK", "FAILED. YOU MUST USE THE", "-b OPTION TO FSCK_FFS TO SPECIFY THE", "LOCATION OF AN ALTERNATE", "SUPER-BLOCK TO SUPPLY NEEDED", "INFORMATION; SEE fsck_ffs(8)."); return(0); } found: doskipclean = 0; pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); } if (debug) printf("clean = %d\n", sblock.fs_clean); if (sblock.fs_clean & FS_ISCLEAN) { if (doskipclean) { pwarn("%sile system is clean; not checking\n", preen ? "f" : "** F"); return (-1); } if (!preen) pwarn("** File system is already clean\n"); } maxfsblock = sblock.fs_size; maxino = sblock.fs_ncg * sblock.fs_ipg; sizepb = sblock.fs_bsize; maxfilesize = sblock.fs_bsize * NDADDR - 1; for (i = 0; i < NIADDR; i++) { sizepb *= NINDIR(&sblock); maxfilesize += sizepb; } /* * Check and potentially fix certain fields in the super block. */ if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); if (reply("SET TO DEFAULT") == 1) { sblock.fs_optim = FS_OPTTIME; sbdirty(); } } if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", sblock.fs_minfree); if (reply("SET TO DEFAULT") == 1) { sblock.fs_minfree = 10; sbdirty(); } } if (sblock.fs_npsect < sblock.fs_nsect || sblock.fs_npsect > sblock.fs_nsect*2) { pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", sblock.fs_npsect); sblock.fs_npsect = sblock.fs_nsect; if (preen) printf(" (FIXED)\n"); if (preen || reply("SET TO DEFAULT") == 1) { sbdirty(); dirty(&asblk); } } if (sblock.fs_bmask != ~(sblock.fs_bsize - 1)) { pwarn("INCORRECT BMASK=%x IN SUPERBLOCK", sblock.fs_bmask); sblock.fs_bmask = ~(sblock.fs_bsize - 1); if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } if (sblock.fs_fmask != ~(sblock.fs_fsize - 1)) { pwarn("INCORRECT FMASK=%x IN SUPERBLOCK", sblock.fs_fmask); sblock.fs_fmask = ~(sblock.fs_fsize - 1); if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } if (1 << sblock.fs_bshift != sblock.fs_bsize) { pwarn("INCORRECT BSHIFT=%d IN SUPERBLOCK", sblock.fs_bshift); sblock.fs_bshift = ffs(sblock.fs_bsize) - 1; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } if (1 << sblock.fs_fshift != sblock.fs_fsize) { pwarn("INCORRECT FSHIFT=%d IN SUPERBLOCK", sblock.fs_fshift); sblock.fs_fshift = ffs(sblock.fs_fsize) - 1; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } if (sblock.fs_inodefmt < FS_44INODEFMT) { pwarn("Format of filesystem is too old.\n"); pwarn("Must update to modern format using a version of fsck\n"); pfatal("from before release 5.0 with the command ``fsck -c 2''\n"); exit(8); } if (sblock.fs_maxfilesize != maxfilesize) { pwarn("INCORRECT MAXFILESIZE=%llu IN SUPERBLOCK", (unsigned long long)sblock.fs_maxfilesize); sblock.fs_maxfilesize = maxfilesize; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } maxsymlinklen = sblock.fs_magic == FS_UFS1_MAGIC ? MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2; if (sblock.fs_maxsymlinklen != maxsymlinklen) { pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", sblock.fs_maxsymlinklen); sblock.fs_maxsymlinklen = maxsymlinklen; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } if (sblock.fs_qbmask != ~sblock.fs_bmask) { pwarn("INCORRECT QBMASK=%lx IN SUPERBLOCK", (unsigned long)sblock.fs_qbmask); sblock.fs_qbmask = ~sblock.fs_bmask; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } if (sblock.fs_qfmask != ~sblock.fs_fmask) { pwarn("INCORRECT QFMASK=%lx IN SUPERBLOCK", (unsigned long)sblock.fs_qfmask); sblock.fs_qfmask = ~sblock.fs_fmask; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } if (sblock.fs_cgsize != fragroundup(&sblock, CGSIZE(&sblock))) { pwarn("INCONSISTENT CGSIZE=%d\n", sblock.fs_cgsize); sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } if (sblock.fs_magic == FS_UFS2_MAGIC) inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); else inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); if (INOPB(&sblock) != inopb) { pwarn("INCONSISTENT INOPB=%d\n", INOPB(&sblock)); sblock.fs_inopb = inopb; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } if (sblock.fs_magic == FS_UFS2_MAGIC) nindir = sblock.fs_bsize / sizeof(int64_t); else nindir = sblock.fs_bsize / sizeof(int32_t); if (NINDIR(&sblock) != nindir) { pwarn("INCONSISTENT NINDIR=%d\n", NINDIR(&sblock)); sblock.fs_nindir = nindir; if (preen) printf(" (FIXED)\n"); if (preen || reply("FIX") == 1) { sbdirty(); dirty(&asblk); } } if (asblk.b_dirty && !bflag) { memcpy(&altsblock, &sblock, (size_t)sblock.fs_sbsize); flush(fswritefd, &asblk); } /* * read in the summary info. */ asked = 0; sblock.fs_csp = calloc(1, sblock.fs_cssize); if (sblock.fs_csp == NULL) { printf("cannot alloc %u bytes for cylinder group summary area\n", (unsigned)sblock.fs_cssize); goto badsblabel; } for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { size = sblock.fs_cssize - i < sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize; if (bread(fsreadfd, (char *)sblock.fs_csp + i, fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), size) != 0 && !asked) { pfatal("BAD SUMMARY INFORMATION"); if (reply("CONTINUE") == 0) { ckfini(0); errexit("%s", ""); } asked++; } } /* * allocate and initialize the necessary maps */ bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); blockmap = calloc((unsigned)bmapsize, sizeof(char)); if (blockmap == NULL) { printf("cannot alloc %u bytes for blockmap\n", (unsigned)bmapsize); goto badsblabel; } inostathead = calloc((unsigned)(sblock.fs_ncg), sizeof(struct inostatlist)); if (inostathead == NULL) { printf("cannot alloc %u bytes for inostathead\n", (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg))); goto badsblabel; } numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128); inplast = 0; listmax = numdirs + 10; inpsort = calloc((unsigned)listmax, sizeof(struct inoinfo *)); if (inpsort == NULL) { printf("cannot alloc %zu bytes for inpsort\n", (unsigned)listmax * sizeof(struct inoinfo *)); goto badsblabel; } inphead = calloc((unsigned)numdirs, sizeof(struct inoinfo *)); if (inphead == NULL) { printf("cannot alloc %zu bytes for inphead\n", (unsigned)numdirs * sizeof(struct inoinfo *)); goto badsblabel; } bufinit(); if (sblock.fs_flags & FS_DOSOFTDEP) usedsoftdep = 1; else usedsoftdep = 0; return (1); badsblabel: ckfini(0); return (0); }
/* * Read in a superblock finding an alternate if necessary. * Return 1 if successful, 0 if unsuccessful, -1 if filesystem * is already clean (preen mode only). */ int setup(char *dev) { long size, asked, i, j; long skipclean, bmapsize; off_t sizepb; struct stat statb; havesb = 0; fswritefd = -1; skipclean = fflag ? 0 : preen; if (stat(dev, &statb) < 0) { printf("Can't stat %s: %s\n", dev, strerror(errno)); return (0); } if ((statb.st_mode & S_IFMT) != S_IFCHR && (statb.st_mode & S_IFMT) != S_IFBLK) { pfatal("%s is not a disk device", dev); if (reply("CONTINUE") == 0) return (0); } if ((fsreadfd = open(dev, O_RDONLY)) < 0) { printf("Can't open %s: %s\n", dev, strerror(errno)); return (0); } if (preen == 0) printf("** %s", dev); if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { fswritefd = -1; if (preen) pfatal("NO WRITE ACCESS"); printf(" (NO WRITE)"); } if (preen == 0) printf("\n"); fsmodified = 0; lfdir = 0; initbarea(&sblk); initbarea(&asblk); sblk.b_un.b_buf = malloc(SBSIZE); asblk.b_un.b_buf = malloc(SBSIZE); if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) errx(EEXIT, "cannot allocate space for superblock"); /* * Figure out the device block size and the sector size. The * block size is updated by readsb() later on. */ { struct partinfo pinfo; if (ioctl(fsreadfd, DIOCGPART, &pinfo) == 0) { dev_bsize = secsize = pinfo.media_blksize; } else { dev_bsize = secsize = DEV_BSIZE; } } /* * Read in the superblock, looking for alternates if necessary */ if (readsb(1) == 0) { skipclean = 0; if (bflag || preen) return(0); if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) return (0); bflag = 32; if (readsb(0) == 0) { printf( "YOU MUST USE THE -b OPTION TO FSCK TO SPECIFY\n" "THE LOCATION OF AN ALTERNATE SUPER-BLOCK TO\n" "SUPPLY NEEDED INFORMATION; SEE fsck(8)."); bflag = 0; return(0); } pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); bflag = 0; } if (skipclean && sblock.fs_clean) { pwarn("FILESYSTEM CLEAN; SKIPPING CHECKS\n"); return (-1); } maxfsblock = sblock.fs_size; maxino = sblock.fs_ncg * sblock.fs_ipg; /* * Check and potentially fix certain fields in the super block. */ if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); if (reply("SET TO DEFAULT") == 1) { sblock.fs_optim = FS_OPTTIME; sbdirty(); } } if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", sblock.fs_minfree); if (reply("SET TO DEFAULT") == 1) { sblock.fs_minfree = 10; sbdirty(); } } if (sblock.fs_interleave < 1 || sblock.fs_interleave > sblock.fs_nsect) { pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK", sblock.fs_interleave); sblock.fs_interleave = 1; if (preen) printf(" (FIXED)\n"); if (preen || reply("SET TO DEFAULT") == 1) { sbdirty(); dirty(&asblk); } } if (sblock.fs_npsect < sblock.fs_nsect || sblock.fs_npsect > sblock.fs_nsect*2) { pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", sblock.fs_npsect); sblock.fs_npsect = sblock.fs_nsect; if (preen) printf(" (FIXED)\n"); if (preen || reply("SET TO DEFAULT") == 1) { sbdirty(); dirty(&asblk); } } if (sblock.fs_inodefmt >= FS_44INODEFMT) { newinofmt = 1; } else { sblock.fs_qbmask = ~sblock.fs_bmask; sblock.fs_qfmask = ~sblock.fs_fmask; /* This should match the kernel limit in ffs_oldfscompat(). */ sblock.fs_maxfilesize = (u_int64_t)1 << 39; newinofmt = 0; } /* * Convert to new inode format. */ if (cvtlevel >= 2 && sblock.fs_inodefmt < FS_44INODEFMT) { if (preen) pwarn("CONVERTING TO NEW INODE FORMAT\n"); else if (!reply("CONVERT TO NEW INODE FORMAT")) return(0); doinglevel2++; sblock.fs_inodefmt = FS_44INODEFMT; sizepb = sblock.fs_bsize; sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; for (i = 0; i < NIADDR; i++) { sizepb *= NINDIR(&sblock); sblock.fs_maxfilesize += sizepb; } sblock.fs_maxsymlinklen = MAXSYMLINKLEN; sblock.fs_qbmask = ~sblock.fs_bmask; sblock.fs_qfmask = ~sblock.fs_fmask; sbdirty(); dirty(&asblk); } /* * Convert to new cylinder group format. */ if (cvtlevel >= 1 && sblock.fs_postblformat == FS_42POSTBLFMT) { if (preen) pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n"); else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT")) return(0); doinglevel1++; sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT; sblock.fs_nrpos = 8; sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) - (char *)(&sblock.fs_firstfield); sblock.fs_rotbloff = &sblock.fs_space[0] - (u_char *)(&sblock.fs_firstfield); sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); sbdirty(); dirty(&asblk); } if (asblk.b_dirty && !bflag) { memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); flush(fswritefd, &asblk); } /* * read in the summary info. */ asked = 0; sblock.fs_csp = calloc(1, sblock.fs_cssize); for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { size = sblock.fs_cssize - i < sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize; if (bread(fsreadfd, (char *)sblock.fs_csp + i, fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), size) != 0 && !asked) { pfatal("BAD SUMMARY INFORMATION"); if (reply("CONTINUE") == 0) { ckfini(0); exit(EEXIT); } asked++; } } /* * allocate and initialize the necessary maps */ bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(short)); blockmap = calloc((unsigned)bmapsize, sizeof (char)); if (blockmap == NULL) { printf("cannot alloc %u bytes for blockmap\n", (unsigned)bmapsize); goto badsb; } inostathead = calloc((unsigned)(sblock.fs_ncg), sizeof(struct inostatlist)); if (inostathead == NULL) { printf("cannot alloc %u bytes for inostathead\n", (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg))); goto badsb; } numdirs = sblock.fs_cstotal.cs_ndir; /* * Calculate the directory hash table size. Do not allocate * a ridiculous amount of memory if we have a lot of directories. */ for (dirhash = 16; dirhash < numdirs; dirhash <<= 1) ; if (dirhash > 1024*1024) dirhash /= 8; dirhashmask = dirhash - 1; if (numdirs == 0) { printf("numdirs is zero, try using an alternate superblock\n"); goto badsb; } inplast = 0; listmax = numdirs + 10; inpsort = calloc((unsigned)listmax, sizeof(struct inoinfo *)); inphead = calloc((unsigned)dirhash, sizeof(struct inoinfo *)); if (inpsort == NULL || inphead == NULL) { printf("cannot allocate base structures for %ld directories\n", numdirs); goto badsb; } bufinit(); if (sblock.fs_flags & FS_DOSOFTDEP) usedsoftdep = 1; else usedsoftdep = 0; return (1); badsb: ckfini(0); return (0); }
pass5() { int c, blk, frags, basesize, sumsize, mapsize, savednrpos; register struct fs *fs = &sblock; register struct cg *cg = &cgrp; daddr_t dbase, dmax; register daddr_t d; register long i, j; struct csum *cs; time_t now; struct csum cstotal; struct inodesc idesc; char buf[MAXBSIZE]; register struct cg *newcg = (struct cg *)buf; struct ocg *ocg = (struct ocg *)buf; bzero((char *)newcg, fs->fs_cgsize); newcg->cg_niblk = fs->fs_ipg; switch (fs->fs_postblformat) { case FS_42POSTBLFMT: basesize = (char *)(&ocg->cg_btot[0]) - (char *)(&ocg->cg_link); sumsize = &ocg->cg_iused[0] - (char *)(&ocg->cg_btot[0]); mapsize = &ocg->cg_free[howmany(fs->fs_fpg, NBBY)] - (u_char *)&ocg->cg_iused[0]; ocg->cg_magic = CG_MAGIC; savednrpos = fs->fs_nrpos; fs->fs_nrpos = 8; break; case FS_DYNAMICPOSTBLFMT: newcg->cg_btotoff = &newcg->cg_space[0] - (u_char *)(&newcg->cg_link); newcg->cg_boff = newcg->cg_btotoff + fs->fs_cpg * sizeof(long); newcg->cg_iusedoff = newcg->cg_boff + fs->fs_cpg * fs->fs_nrpos * sizeof(short); newcg->cg_freeoff = newcg->cg_iusedoff + howmany(fs->fs_ipg, NBBY); newcg->cg_nextfreeoff = newcg->cg_freeoff + howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY); newcg->cg_magic = CG_MAGIC; basesize = &newcg->cg_space[0] - (u_char *)(&newcg->cg_link); sumsize = newcg->cg_iusedoff - newcg->cg_btotoff; mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff; break; default: errexit("UNKNOWN ROTATIONAL TABLE FORMAT %d\n", fs->fs_postblformat); } bzero((char *)&idesc, sizeof(struct inodesc)); idesc.id_type = ADDR; bzero((char *)&cstotal, sizeof(struct csum)); (void)time(&now); for (i = fs->fs_size; i < fragroundup(fs, fs->fs_size); i++) setbmap(i); for (c = 0; c < fs->fs_ncg; c++) { getblk(&cgblk, cgtod(fs, c), fs->fs_cgsize); if (!cg_chkmagic(cg)) pfatal("CG %d: BAD MAGIC NUMBER\n", c); dbase = cgbase(fs, c); dmax = dbase + fs->fs_fpg; if (dmax > fs->fs_size) dmax = fs->fs_size; if (now > cg->cg_time) newcg->cg_time = cg->cg_time; else newcg->cg_time = now; newcg->cg_cgx = c; if (c == fs->fs_ncg - 1) newcg->cg_ncyl = fs->fs_ncyl % fs->fs_cpg; else newcg->cg_ncyl = fs->fs_cpg; newcg->cg_ndblk = dmax - dbase; newcg->cg_cs.cs_ndir = 0; newcg->cg_cs.cs_nffree = 0; newcg->cg_cs.cs_nbfree = 0; newcg->cg_cs.cs_nifree = fs->fs_ipg; if (cg->cg_rotor < newcg->cg_ndblk) newcg->cg_rotor = cg->cg_rotor; else newcg->cg_rotor = 0; if (cg->cg_frotor < newcg->cg_ndblk) newcg->cg_frotor = cg->cg_frotor; else newcg->cg_frotor = 0; if (cg->cg_irotor < newcg->cg_niblk) newcg->cg_irotor = cg->cg_irotor; else newcg->cg_irotor = 0; bzero((char *)&newcg->cg_frsum[0], sizeof newcg->cg_frsum); bzero((char *)&cg_blktot(newcg)[0], sumsize + mapsize); if (fs->fs_postblformat == FS_42POSTBLFMT) ocg->cg_magic = CG_MAGIC; j = fs->fs_ipg * c; for (i = 0; i < fs->fs_ipg; j++, i++) { switch (statemap[j]) { case USTATE: break; case DSTATE: case DCLEAR: case DFOUND: newcg->cg_cs.cs_ndir++; /* fall through */ case FSTATE: case FCLEAR: newcg->cg_cs.cs_nifree--; setbit(cg_inosused(newcg), i); break; default: if (j < ROOTINO) break; errexit("BAD STATE %d FOR INODE I=%d", statemap[j], j); } } if (c == 0) for (i = 0; i < ROOTINO; i++) { setbit(cg_inosused(newcg), i); newcg->cg_cs.cs_nifree--; } for (i = 0, d = dbase; d < dmax; d += fs->fs_frag, i += fs->fs_frag) { frags = 0; for (j = 0; j < fs->fs_frag; j++) { if (getbmap(d + j)) continue; setbit(cg_blksfree(newcg), i + j); frags++; } if (frags == fs->fs_frag) { newcg->cg_cs.cs_nbfree++; j = cbtocylno(fs, i); cg_blktot(newcg)[j]++; cg_blks(fs, newcg, j)[cbtorpos(fs, i)]++; } else if (frags > 0) { newcg->cg_cs.cs_nffree += frags; blk = blkmap(fs, cg_blksfree(newcg), i); fragacct(fs, blk, newcg->cg_frsum, 1); } } cstotal.cs_nffree += newcg->cg_cs.cs_nffree; cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree; cstotal.cs_nifree += newcg->cg_cs.cs_nifree; cstotal.cs_ndir += newcg->cg_cs.cs_ndir; cs = &fs->fs_cs(fs, c); if (bcmp((char *)&newcg->cg_cs, (char *)cs, sizeof *cs) != 0 && dofix(&idesc, "FREE BLK COUNT(S) WRONG IN SUPERBLK")) { bcopy((char *)&newcg->cg_cs, (char *)cs, sizeof *cs); sbdirty(); } if (cvtflag) { bcopy((char *)newcg, (char *)cg, fs->fs_cgsize); cgdirty(); continue; } if (bcmp(cg_inosused(newcg), cg_inosused(cg), mapsize) != 0 && dofix(&idesc, "BLK(S) MISSING IN BIT MAPS")) { bcopy(cg_inosused(newcg), cg_inosused(cg), mapsize); cgdirty(); } if ((bcmp((char *)newcg, (char *)cg, basesize) != 0 || bcmp((char *)&cg_blktot(newcg)[0], (char *)&cg_blktot(cg)[0], sumsize) != 0) && dofix(&idesc, "SUMMARY INFORMATION BAD")) { bcopy((char *)newcg, (char *)cg, basesize); bcopy((char *)&cg_blktot(newcg)[0], (char *)&cg_blktot(cg)[0], sumsize); cgdirty(); } } if (fs->fs_postblformat == FS_42POSTBLFMT) fs->fs_nrpos = savednrpos; if (bcmp((char *)&cstotal, (char *)&fs->fs_cstotal, sizeof *cs) != 0 && dofix(&idesc, "FREE BLK COUNT(S) WRONG IN SUPERBLK")) { bcopy((char *)&cstotal, (char *)&fs->fs_cstotal, sizeof *cs); fs->fs_ronly = 0; fs->fs_fmod = 0; sbdirty(); } }
void pass5(void) { int c, blk, frags, basesize, sumsize, mapsize, savednrpos = 0; int inomapsize, blkmapsize; struct fs *fs = &sblock; struct cg *cg = &cgrp; ufs_daddr_t dbase, dmax; ufs_daddr_t d; long i, j, k; struct csum *cs; struct csum cstotal; struct inodesc idesc[3]; char buf[MAXBSIZE]; struct cg *newcg = (struct cg *)buf; struct ocg *ocg = (struct ocg *)buf; inoinfo(WINO)->ino_state = USTATE; memset(newcg, 0, (size_t)fs->fs_cgsize); newcg->cg_niblk = fs->fs_ipg; if (cvtlevel >= 3) { if (fs->fs_maxcontig < 2 && fs->fs_contigsumsize > 0) { if (preen) pwarn("DELETING CLUSTERING MAPS\n"); if (preen || reply("DELETE CLUSTERING MAPS")) { fs->fs_contigsumsize = 0; doinglevel1 = 1; sbdirty(); } } if (fs->fs_maxcontig > 1) { char *doit = NULL; if (fs->fs_contigsumsize < 1) { doit = "CREAT"; } else if (fs->fs_contigsumsize < fs->fs_maxcontig && fs->fs_contigsumsize < FS_MAXCONTIG) { doit = "EXPAND"; } if (doit) { i = fs->fs_contigsumsize; fs->fs_contigsumsize = MIN(fs->fs_maxcontig, FS_MAXCONTIG); if (CGSIZE(fs) > fs->fs_bsize) { pwarn("CANNOT %s CLUSTER MAPS\n", doit); fs->fs_contigsumsize = i; } else if (preen || reply("CREATE CLUSTER MAPS")) { if (preen) pwarn("%sING CLUSTER MAPS\n", doit); fs->fs_cgsize = fragroundup(fs, CGSIZE(fs)); doinglevel1 = 1; sbdirty(); } } } } switch ((int)fs->fs_postblformat) { case FS_42POSTBLFMT: basesize = (char *)(&ocg->cg_btot[0]) - (char *)(&ocg->cg_firstfield); sumsize = &ocg->cg_iused[0] - (u_int8_t *)(&ocg->cg_btot[0]); mapsize = &ocg->cg_free[howmany(fs->fs_fpg, NBBY)] - (u_char *)&ocg->cg_iused[0]; blkmapsize = howmany(fs->fs_fpg, NBBY); inomapsize = &ocg->cg_free[0] - (u_char *)&ocg->cg_iused[0]; ocg->cg_magic = CG_MAGIC; savednrpos = fs->fs_nrpos; fs->fs_nrpos = 8; break; case FS_DYNAMICPOSTBLFMT: newcg->cg_btotoff = &newcg->cg_space[0] - (u_char *)(&newcg->cg_firstfield); newcg->cg_boff = newcg->cg_btotoff + fs->fs_cpg * sizeof(int32_t); newcg->cg_iusedoff = newcg->cg_boff + fs->fs_cpg * fs->fs_nrpos * sizeof(u_int16_t); newcg->cg_freeoff = newcg->cg_iusedoff + howmany(fs->fs_ipg, NBBY); inomapsize = newcg->cg_freeoff - newcg->cg_iusedoff; newcg->cg_nextfreeoff = newcg->cg_freeoff + howmany(fs->fs_cpg * fs->fs_spc / NSPF(fs), NBBY); blkmapsize = newcg->cg_nextfreeoff - newcg->cg_freeoff; if (fs->fs_contigsumsize > 0) { newcg->cg_clustersumoff = newcg->cg_nextfreeoff - sizeof(u_int32_t); newcg->cg_clustersumoff = roundup(newcg->cg_clustersumoff, sizeof(u_int32_t)); newcg->cg_clusteroff = newcg->cg_clustersumoff + (fs->fs_contigsumsize + 1) * sizeof(u_int32_t); newcg->cg_nextfreeoff = newcg->cg_clusteroff + howmany(fs->fs_cpg * fs->fs_spc / NSPB(fs), NBBY); } newcg->cg_magic = CG_MAGIC; basesize = &newcg->cg_space[0] - (u_char *)(&newcg->cg_firstfield); sumsize = newcg->cg_iusedoff - newcg->cg_btotoff; mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff; break; default: inomapsize = blkmapsize = sumsize = 0; /* keep lint happy */ errx(EEXIT, "UNKNOWN ROTATIONAL TABLE FORMAT %d", fs->fs_postblformat); } memset(&idesc[0], 0, sizeof idesc); for (i = 0; i < 3; i++) { idesc[i].id_type = ADDR; if (doinglevel2) idesc[i].id_fix = FIX; } memset(&cstotal, 0, sizeof(struct csum)); j = blknum(fs, fs->fs_size + fs->fs_frag - 1); for (i = fs->fs_size; i < j; i++) setbmap(i); for (c = 0; c < fs->fs_ncg; c++) { if (got_siginfo) { printf("%s: phase 5: cyl group %d of %d (%d%%)\n", cdevname, c, sblock.fs_ncg, c * 100 / sblock.fs_ncg); got_siginfo = 0; } getblk(&cgblk, cgtod(fs, c), fs->fs_cgsize); if (!cg_chkmagic(cg)) pfatal("CG %d: BAD MAGIC NUMBER\n", c); dbase = cgbase(fs, c); dmax = dbase + fs->fs_fpg; if (dmax > fs->fs_size) dmax = fs->fs_size; newcg->cg_time = cg->cg_time; newcg->cg_cgx = c; if (c == fs->fs_ncg - 1) newcg->cg_ncyl = fs->fs_ncyl % fs->fs_cpg; else newcg->cg_ncyl = fs->fs_cpg; newcg->cg_ndblk = dmax - dbase; if (fs->fs_contigsumsize > 0) newcg->cg_nclusterblks = newcg->cg_ndblk / fs->fs_frag; newcg->cg_cs.cs_ndir = 0; newcg->cg_cs.cs_nffree = 0; newcg->cg_cs.cs_nbfree = 0; newcg->cg_cs.cs_nifree = fs->fs_ipg; if ((cg->cg_rotor >= 0) && (cg->cg_rotor < newcg->cg_ndblk)) newcg->cg_rotor = cg->cg_rotor; else newcg->cg_rotor = 0; if ((cg->cg_frotor >= 0) && (cg->cg_frotor < newcg->cg_ndblk)) newcg->cg_frotor = cg->cg_frotor; else newcg->cg_frotor = 0; if ((cg->cg_irotor >= 0) && (cg->cg_irotor < newcg->cg_niblk)) newcg->cg_irotor = cg->cg_irotor; else newcg->cg_irotor = 0; memset(&newcg->cg_frsum[0], 0, sizeof newcg->cg_frsum); memset(&cg_blktot(newcg)[0], 0, (size_t)(sumsize + mapsize)); if (fs->fs_postblformat == FS_42POSTBLFMT) ocg->cg_magic = CG_MAGIC; j = fs->fs_ipg * c; for (i = 0; i < inostathead[c].il_numalloced; j++, i++) { switch (inoinfo(j)->ino_state) { case USTATE: break; case DSTATE: case DCLEAR: case DFOUND: newcg->cg_cs.cs_ndir++; /* fall through */ case FSTATE: case FCLEAR: newcg->cg_cs.cs_nifree--; setbit(cg_inosused(newcg), i); break; default: if (j < ROOTINO) break; errx(EEXIT, "BAD STATE %d FOR INODE I=%ld", inoinfo(j)->ino_state, j); } } if (c == 0) for (i = 0; i < ROOTINO; i++) { setbit(cg_inosused(newcg), i); newcg->cg_cs.cs_nifree--; } for (i = 0, d = dbase; d < dmax; d += fs->fs_frag, i += fs->fs_frag) { frags = 0; for (j = 0; j < fs->fs_frag; j++) { if (testbmap(d + j)) continue; setbit(cg_blksfree(newcg), i + j); frags++; } if (frags == fs->fs_frag) { newcg->cg_cs.cs_nbfree++; j = cbtocylno(fs, i); cg_blktot(newcg)[j]++; cg_blks(fs, newcg, j)[cbtorpos(fs, i)]++; if (fs->fs_contigsumsize > 0) setbit(cg_clustersfree(newcg), i / fs->fs_frag); } else if (frags > 0) { newcg->cg_cs.cs_nffree += frags; blk = blkmap(fs, cg_blksfree(newcg), i); ffs_fragacct(fs, blk, newcg->cg_frsum, 1); } } if (fs->fs_contigsumsize > 0) { int32_t *sump = cg_clustersum(newcg); u_char *mapp = cg_clustersfree(newcg); int map = *mapp++; int bit = 1; int run = 0; for (i = 0; i < newcg->cg_nclusterblks; i++) { if ((map & bit) != 0) { run++; } else if (run != 0) { if (run > fs->fs_contigsumsize) run = fs->fs_contigsumsize; sump[run]++; run = 0; } if ((i & (NBBY - 1)) != (NBBY - 1)) { bit <<= 1; } else { map = *mapp++; bit = 1; } } if (run != 0) { if (run > fs->fs_contigsumsize) run = fs->fs_contigsumsize; sump[run]++; } } cstotal.cs_nffree += newcg->cg_cs.cs_nffree; cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree; cstotal.cs_nifree += newcg->cg_cs.cs_nifree; cstotal.cs_ndir += newcg->cg_cs.cs_ndir; cs = &fs->fs_cs(fs, c); if (memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 && dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) { memmove(cs, &newcg->cg_cs, sizeof *cs); sbdirty(); } if (doinglevel1) { memmove(cg, newcg, (size_t)fs->fs_cgsize); cgdirty(); continue; } if ((memcmp(newcg, cg, basesize) != 0 || memcmp(&cg_blktot(newcg)[0], &cg_blktot(cg)[0], sumsize) != 0) && dofix(&idesc[2], "SUMMARY INFORMATION BAD")) { memmove(cg, newcg, (size_t)basesize); memmove(&cg_blktot(cg)[0], &cg_blktot(newcg)[0], (size_t)sumsize); cgdirty(); } if (usedsoftdep) { for (i = 0; i < inomapsize; i++) { j = cg_inosused(newcg)[i]; if ((cg_inosused(cg)[i] & j) == j) continue; for (k = 0; k < NBBY; k++) { if ((j & (1 << k)) == 0) continue; if (cg_inosused(cg)[i] & (1 << k)) continue; pwarn("ALLOCATED INODE %d MARKED FREE\n", c * fs->fs_ipg + i * NBBY + k); } } for (i = 0; i < blkmapsize; i++) { j = cg_blksfree(cg)[i]; if ((cg_blksfree(newcg)[i] & j) == j) continue; for (k = 0; k < NBBY; k++) { if ((j & (1 << k)) == 0) continue; if (cg_blksfree(newcg)[i] & (1 << k)) continue; pwarn("ALLOCATED FRAG %d MARKED FREE\n", c * fs->fs_fpg + i * NBBY + k); } } } if (memcmp(cg_inosused(newcg), cg_inosused(cg), mapsize) != 0 && dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) { memmove(cg_inosused(cg), cg_inosused(newcg), (size_t)mapsize); cgdirty(); } } if (fs->fs_postblformat == FS_42POSTBLFMT) fs->fs_nrpos = savednrpos; if (memcmp(&cstotal, &fs->fs_cstotal, sizeof *cs) != 0 && dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) { memmove(&fs->fs_cstotal, &cstotal, sizeof *cs); fs->fs_ronly = 0; fs->fs_fmod = 0; sbdirty(); } }
/* * Read in a superblock finding an alternate if necessary. * Return 1 if successful, 0 if unsuccessful, -1 if file system * is already clean (ckclean and preen mode only). */ int setup(char *dev) { long cg, asked, i, j; long bmapsize; struct stat statb; struct fs proto; size_t size; havesb = 0; fswritefd = -1; cursnapshot = 0; if (stat(dev, &statb) < 0) { printf("Can't stat %s: %s\n", dev, strerror(errno)); if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } return (0); } if ((statb.st_mode & S_IFMT) != S_IFCHR && (statb.st_mode & S_IFMT) != S_IFBLK) { if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { unlink(snapname); printf("background fsck lacks a snapshot\n"); exit(EEXIT); } if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) { cursnapshot = statb.st_ino; } else { if (cvtlevel == 0 || (statb.st_flags & SF_SNAPSHOT) == 0) { if (preen && bkgrdflag) { unlink(snapname); bkgrdflag = 0; } pfatal("%s is not a disk device", dev); if (reply("CONTINUE") == 0) { if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } return (0); } } else { if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } pfatal("cannot convert a snapshot"); exit(EEXIT); } } } if ((fsreadfd = open(dev, O_RDONLY)) < 0) { if (bkgrdflag) { unlink(snapname); bkgrdflag = 0; } printf("Can't open %s: %s\n", dev, strerror(errno)); return (0); } if (bkgrdflag) { unlink(snapname); size = MIBSIZE; if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0|| sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0|| sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0|| sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 || sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) { pfatal("kernel lacks background fsck support\n"); exit(EEXIT); } /* * When kernel is lack of runtime bgfsck superblock summary * adjustment functionality, it does not mean we can not * continue, as old kernels will recompute the summary at * mount time. However, it will be an unexpected softupdates * inconsistency if it turns out that the summary is still * incorrect. Set a flag so subsequent operation can know * this. */ bkgrdsumadj = 1; if (sysctlnametomib("vfs.ffs.adjndir", adjndir, &size) < 0 || sysctlnametomib("vfs.ffs.adjnbfree", adjnbfree, &size) < 0 || sysctlnametomib("vfs.ffs.adjnifree", adjnifree, &size) < 0 || sysctlnametomib("vfs.ffs.adjnffree", adjnffree, &size) < 0 || sysctlnametomib("vfs.ffs.adjnumclusters", adjnumclusters, &size) < 0) { bkgrdsumadj = 0; pwarn("kernel lacks runtime superblock summary adjustment support"); } cmd.version = FFS_CMD_VERSION; cmd.handle = fsreadfd; fswritefd = -1; } if (preen == 0) printf("** %s", dev); if (bkgrdflag == 0 && (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) { fswritefd = -1; if (preen) pfatal("NO WRITE ACCESS"); printf(" (NO WRITE)"); } if (preen == 0) printf("\n"); /* * Read in the superblock, looking for alternates if necessary */ if (readsb(1) == 0) { skipclean = 0; if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) return(0); if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) return (0); for (cg = 0; cg < proto.fs_ncg; cg++) { bflag = fsbtodb(&proto, cgsblock(&proto, cg)); if (readsb(0) != 0) break; } if (cg >= proto.fs_ncg) { printf("%s %s\n%s %s\n%s %s\n", "SEARCH FOR ALTERNATE SUPER-BLOCK", "FAILED. YOU MUST USE THE", "-b OPTION TO FSCK TO SPECIFY THE", "LOCATION OF AN ALTERNATE", "SUPER-BLOCK TO SUPPLY NEEDED", "INFORMATION; SEE fsck_ffs(8)."); bflag = 0; return(0); } pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); bflag = 0; } if (skipclean && ckclean && sblock.fs_clean) { pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); return (-1); } maxfsblock = sblock.fs_size; maxino = sblock.fs_ncg * sblock.fs_ipg; /* * Check and potentially fix certain fields in the super block. */ if (sblock.fs_optim != FS_OPTTIME && sblock.fs_optim != FS_OPTSPACE) { pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); if (reply("SET TO DEFAULT") == 1) { sblock.fs_optim = FS_OPTTIME; sbdirty(); } } if ((sblock.fs_minfree < 0 || sblock.fs_minfree > 99)) { pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", sblock.fs_minfree); if (reply("SET TO DEFAULT") == 1) { sblock.fs_minfree = 10; sbdirty(); } } if (sblock.fs_magic == FS_UFS1_MAGIC && sblock.fs_old_inodefmt < FS_44INODEFMT) { pwarn("Format of file system is too old.\n"); pwarn("Must update to modern format using a version of fsck\n"); pfatal("from before 2002 with the command ``fsck -c 2''\n"); exit(EEXIT); } if (asblk.b_dirty && !bflag) { memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize); flush(fswritefd, &asblk); } /* * read in the summary info. */ asked = 0; sblock.fs_csp = calloc(1, sblock.fs_cssize); if (sblock.fs_csp == NULL) { printf("cannot alloc %u bytes for cg summary info\n", (unsigned)sblock.fs_cssize); goto badsb; } for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { size = sblock.fs_cssize - i < sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize; readcnt[sblk.b_type]++; if (blread(fsreadfd, (char *)sblock.fs_csp + i, fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), size) != 0 && !asked) { pfatal("BAD SUMMARY INFORMATION"); if (reply("CONTINUE") == 0) { ckfini(0); exit(EEXIT); } asked++; } } /* * allocate and initialize the necessary maps */ bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short)); blockmap = calloc((unsigned)bmapsize, sizeof (char)); if (blockmap == NULL) { printf("cannot alloc %u bytes for blockmap\n", (unsigned)bmapsize); goto badsb; } inostathead = calloc((unsigned)(sblock.fs_ncg), sizeof(struct inostatlist)); if (inostathead == NULL) { printf("cannot alloc %u bytes for inostathead\n", (unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg))); goto badsb; } numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128); dirhash = numdirs; inplast = 0; listmax = numdirs + 10; inpsort = (struct inoinfo **)calloc((unsigned)listmax, sizeof(struct inoinfo *)); inphead = (struct inoinfo **)calloc((unsigned)numdirs, sizeof(struct inoinfo *)); if (inpsort == NULL || inphead == NULL) { printf("cannot alloc %ju bytes for inphead\n", (uintmax_t)numdirs * sizeof(struct inoinfo *)); goto badsb; } bufinit(); if (sblock.fs_flags & FS_DOSOFTDEP) usedsoftdep = 1; else usedsoftdep = 0; return (1); badsb: ckfini(0); return (0); }