void pinode(ino_t ino) { struct ufs1_dinode *dp; char *p; struct passwd *pw; time_t t; printf(" I=%llu ", (unsigned long long)ino); if (ino < ROOTINO || ino >= maxino) return; dp = ginode(ino); if (dp) { printf(" OWNER="); #ifndef SMALL if (Uflag && (pw = getpwuid((int) dp->di_uid)) != 0) printf("%s ", pw->pw_name); else #endif printf("%u ", (unsigned) dp->di_uid); printf("MODE=%o\n", dp->di_mode); if (preen) printf("%s: ", cdevname()); printf("SIZE=%llu ", (unsigned long long) dp->di_size); t = dp->di_mtime; p = ctime(&t); printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); } }
void badsb(int listerr, char *s) { if (!listerr) return; if (preen) printf("%s: ", cdevname()); pfatal("BAD SUPER BLOCK: %s\n", s); }
void pass1b(void) { int c, i; union dinode *dp; struct inodesc idesc; ino_t inumber; memset(&idesc, 0, sizeof(struct inodesc)); idesc.id_type = ADDR; idesc.id_func = pass1bcheck; duphead = duplist; inumber = 0; for (c = 0; c < sblock->fs_ncg; c++) { if (got_siginfo) { fprintf(stderr, "%s: phase 1b: cyl group %d of %d (%d%%)\n", cdevname(), c, sblock->fs_ncg, c * 100 / sblock->fs_ncg); got_siginfo = 0; } #ifdef PROGRESS progress_bar(cdevname(), "phase 1b", c, sblock->fs_ncg); #endif /* PROGRESS */ for (i = 0; i < sblock->fs_ipg; i++, inumber++) { if (inumber < ROOTINO) continue; dp = ginode(inumber); if (dp == NULL) continue; idesc.id_number = inumber; if (inoinfo(inumber)->ino_state != USTATE && (ckinode(dp, &idesc) & STOP)) return; } } #ifdef PROGRESS progress_done(); #endif /* PROGRESS */ }
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); }
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); }
void pass5(void) { int c, blk, frags, basesize, sumsize, mapsize, cssize; int inomapsize, blkmapsize; struct fs *fs = sblock; daddr_t dbase, dmax; daddr_t d; long i, j, k; struct csum *cs; struct csum_total cstotal; struct inodesc idesc[4]; char buf[MAXBSIZE]; struct cg *newcg = (struct cg *)buf; struct ocg *ocg = (struct ocg *)buf; struct cg *cg = cgrp, *ncg; struct inostat *info; u_int32_t ncgsize; 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) { const 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); ncgsize = fragroundup(fs, CGSIZE(fs)); ncg = realloc(cgrp, ncgsize); if (ncg == NULL) errexit( "cannot reallocate cg space"); cg = cgrp = ncg; fs->fs_cgsize = ncgsize; doinglevel1 = 1; sbdirty(); } } } } basesize = &newcg->cg_space[0] - (u_char *)(&newcg->cg_firstfield); cssize = (u_char *)&cstotal.cs_spare[0] - (u_char *)&cstotal.cs_ndir; sumsize = 0; if (is_ufs2) { newcg->cg_iusedoff = basesize; } else { /* * We reserve the space for the old rotation summary * tables for the benefit of old kernels, but do not * maintain them in modern kernels. In time, they can * go away. */ newcg->cg_old_btotoff = basesize; newcg->cg_old_boff = newcg->cg_old_btotoff + fs->fs_old_cpg * sizeof(int32_t); newcg->cg_iusedoff = newcg->cg_old_boff + fs->fs_old_cpg * fs->fs_old_nrpos * sizeof(u_int16_t); memset(&newcg->cg_space[0], 0, newcg->cg_iusedoff - basesize); } inomapsize = howmany(fs->fs_ipg, CHAR_BIT); newcg->cg_freeoff = newcg->cg_iusedoff + inomapsize; blkmapsize = howmany(fs->fs_fpg, CHAR_BIT); newcg->cg_nextfreeoff = newcg->cg_freeoff + blkmapsize; if (fs->fs_contigsumsize > 0) { newcg->cg_clustersumoff = newcg->cg_nextfreeoff - sizeof(u_int32_t); if (isappleufs) { /* Apple PR2216969 gives rationale for this change. * I believe they were mistaken, but we need to * duplicate it for compatibility. -- [email protected] */ newcg->cg_clustersumoff += 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(fragstoblks(fs, fs->fs_fpg), CHAR_BIT); } newcg->cg_magic = CG_MAGIC; mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff; if (!is_ufs2 && ((fs->fs_old_flags & FS_FLAGS_UPDATED) == 0)) { switch ((int)fs->fs_old_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; newcg->cg_magic = 0; break; case FS_DYNAMICPOSTBLFMT: sumsize = newcg->cg_iusedoff - newcg->cg_old_btotoff; break; default: errexit("UNKNOWN ROTATIONAL TABLE FORMAT %d", fs->fs_old_postblformat); } } memset(&idesc[0], 0, sizeof idesc); for (i = 0; i < 4; i++) { idesc[i].id_type = ADDR; if (!is_ufs2 && doinglevel2) idesc[i].id_fix = FIX; } memset(&cstotal, 0, sizeof(struct csum_total)); dmax = blknum(fs, fs->fs_size + fs->fs_frag - 1); for (d = fs->fs_size; d < dmax; d++) setbmap(d); for (c = 0; c < fs->fs_ncg; c++) { if (got_siginfo) { fprintf(stderr, "%s: phase 5: cyl group %d of %d (%d%%)\n", cdevname(), c, fs->fs_ncg, c * 100 / fs->fs_ncg); got_siginfo = 0; } #ifdef PROGRESS progress_bar(cdevname(), preen ? NULL : "phase 5", c, fs->fs_ncg); #endif /* PROGRESS */ getblk(&cgblk, cgtod(fs, c), fs->fs_cgsize); memcpy(cg, cgblk.b_un.b_cg, fs->fs_cgsize); if((doswap && !needswap) || (!doswap && needswap)) ffs_cg_swap(cgblk.b_un.b_cg, cg, sblock); if (!doinglevel1 && !cg_chkmagic(cg, 0)) pfatal("CG %d: PASS5: BAD MAGIC NUMBER\n", c); if(doswap) cgdirty(); /* * While we have the disk head where we want it, * write back the superblock to the spare at this * cylinder group. */ if ((cvtlevel && sblk.b_dirty) || doswap) { bwrite(fswritefd, sblk.b_un.b_buf, fsbtodb(sblock, cgsblock(sblock, c)), sblock->fs_sbsize); } else { /* * Read in the current alternate superblock, * and compare it to the master. If it's * wrong, fix it up. */ getblk(&asblk, cgsblock(sblock, c), sblock->fs_sbsize); if (asblk.b_errs) pfatal("CG %d: UNABLE TO READ ALTERNATE " "SUPERBLK\n", c); else { memmove(altsblock, asblk.b_un.b_fs, sblock->fs_sbsize); if (needswap) ffs_sb_swap(asblk.b_un.b_fs, altsblock); } sb_oldfscompat_write(sblock, sblocksave); if ((asblk.b_errs || cmpsblks(sblock, altsblock)) && dofix(&idesc[3], "ALTERNATE SUPERBLK(S) ARE INCORRECT")) { bwrite(fswritefd, sblk.b_un.b_buf, fsbtodb(sblock, cgsblock(sblock, c)), sblock->fs_sbsize); } sb_oldfscompat_read(sblock, 0); } dbase = cgbase(fs, c); dmax = dbase + fs->fs_fpg; if (dmax > fs->fs_size) dmax = fs->fs_size; if (is_ufs2 || (fs->fs_old_flags & FS_FLAGS_UPDATED)) newcg->cg_time = cg->cg_time; newcg->cg_old_time = cg->cg_old_time; newcg->cg_cgx = c; newcg->cg_ndblk = dmax - dbase; if (!is_ufs2) { if (c == fs->fs_ncg - 1) { /* Avoid fighting old fsck for this value. Its never used * outside of this check anyway. */ if ((fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) newcg->cg_old_ncyl = fs->fs_old_ncyl % fs->fs_old_cpg; else newcg->cg_old_ncyl = howmany(newcg->cg_ndblk, fs->fs_fpg / fs->fs_old_cpg); } else newcg->cg_old_ncyl = fs->fs_old_cpg; newcg->cg_old_niblk = fs->fs_ipg; newcg->cg_niblk = 0; } 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 < fs->fs_ipg) newcg->cg_irotor = cg->cg_irotor; else newcg->cg_irotor = 0; if (!is_ufs2) { newcg->cg_initediblk = 0; } else { if ((unsigned)cg->cg_initediblk > fs->fs_ipg) newcg->cg_initediblk = fs->fs_ipg; else newcg->cg_initediblk = cg->cg_initediblk; } memset(&newcg->cg_frsum[0], 0, sizeof newcg->cg_frsum); memset(&old_cg_blktot(newcg, 0)[0], 0, (size_t)(sumsize)); memset(cg_inosused(newcg, 0), 0, (size_t)(mapsize)); if (!is_ufs2 && ((fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) && fs->fs_old_postblformat == FS_42POSTBLFMT) ocg->cg_magic = CG_MAGIC; j = fs->fs_ipg * c; for (i = 0; i < fs->fs_ipg; j++, i++) { info = inoinfo(j); switch (info->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, 0), i); break; default: if (j < ROOTINO) break; errexit("BAD STATE %d FOR INODE I=%ld", info->ino_state, (long)j); } } if (c == 0) for (i = 0; i < ROOTINO; i++) { setbit(cg_inosused(newcg, 0), 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, 0), i + j); frags++; } if (frags == fs->fs_frag) { newcg->cg_cs.cs_nbfree++; if (sumsize) { j = old_cbtocylno(fs, i); old_cg_blktot(newcg, 0)[j]++; old_cg_blks(fs, newcg, j, 0)[old_cbtorpos(fs, i)]++; } if (fs->fs_contigsumsize > 0) setbit(cg_clustersfree(newcg, 0), fragstoblks(fs, i)); } else if (frags > 0) { newcg->cg_cs.cs_nffree += frags; blk = blkmap(fs, cg_blksfree(newcg, 0), i); ffs_fragacct(fs, blk, newcg->cg_frsum, 1, 0); } } if (fs->fs_contigsumsize > 0) { int32_t *sump = cg_clustersum(newcg, 0); u_char *mapp = cg_clustersfree(newcg, 0); 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) { if (debug) { printf("cg %d: nffree: %d/%d nbfree %d/%d" " nifree %d/%d ndir %d/%d\n", c, cs->cs_nffree,newcg->cg_cs.cs_nffree, cs->cs_nbfree,newcg->cg_cs.cs_nbfree, cs->cs_nifree,newcg->cg_cs.cs_nifree, cs->cs_ndir,newcg->cg_cs.cs_ndir); } if (dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) { memmove(cs, &newcg->cg_cs, sizeof *cs); sbdirty(); } else markclean = 0; } if (doinglevel1) { memmove(cg, newcg, (size_t)fs->fs_cgsize); cgdirty(); continue; } if ((memcmp(newcg, cg, basesize) != 0) || (memcmp(&old_cg_blktot(newcg, 0)[0], &old_cg_blktot(cg, 0)[0], sumsize) != 0)) { if (dofix(&idesc[2], "SUMMARY INFORMATION BAD")) { memmove(cg, newcg, (size_t)basesize); memmove(&old_cg_blktot(cg, 0)[0], &old_cg_blktot(newcg, 0)[0], (size_t)sumsize); cgdirty(); } else markclean = 0; } if (usedsoftdep) { for (i = 0; i < inomapsize; i++) { j = cg_inosused(newcg, 0)[i]; if ((cg_inosused(cg, 0)[i] & j) == j) continue; for (k = 0; k < NBBY; k++) { if ((j & (1 << k)) == 0) continue; if (cg_inosused(cg, 0)[i] & (1 << k)) continue; pwarn("ALLOCATED INODE %ld " "MARKED FREE\n", c * fs->fs_ipg + i * 8 + k); } } for (i = 0; i < blkmapsize; i++) { j = cg_blksfree(cg, 0)[i]; if ((cg_blksfree(newcg, 0)[i] & j) == j) continue; for (k = 0; k < NBBY; k++) { if ((j & (1 << k)) == 0) continue; if (cg_inosused(cg, 0)[i] & (1 << k)) continue; pwarn("ALLOCATED FRAG %ld " "MARKED FREE\n", c * fs->fs_fpg + i * 8 + k); } } } if (memcmp(cg_inosused(newcg, 0), cg_inosused(cg, 0), mapsize) != 0 && dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) { memmove(cg_inosused(cg, 0), cg_inosused(newcg, 0), (size_t)mapsize); cgdirty(); } } if (memcmp(&cstotal, &fs->fs_cstotal, cssize) != 0) { if (debug) { printf("total: nffree: %lld/%lld nbfree %lld/%lld" " nifree %lld/%lld ndir %lld/%lld\n", (long long int)fs->fs_cstotal.cs_nffree, (long long int)cstotal.cs_nffree, (long long int)fs->fs_cstotal.cs_nbfree, (long long int)cstotal.cs_nbfree, (long long int)fs->fs_cstotal.cs_nifree, (long long int)cstotal.cs_nifree, (long long int)fs->fs_cstotal.cs_ndir, (long long int)cstotal.cs_ndir); } if (dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) { memmove(&fs->fs_cstotal, &cstotal, sizeof cstotal); fs->fs_ronly = 0; fs->fs_fmod = 0; sbdirty(); } else markclean = 0; } #ifdef PROGRESS if (!preen) progress_done(); #endif /* PROGRESS */ }
void pass2(void) { union dinode *dp; struct inoinfo **inpp, *inp, *pinp; struct inoinfo **inpend; struct inostat *rinfo, *info; struct inodesc curino; union dinode dino; int i, maxblk; char pathbuf[MAXPATHLEN + 1]; rinfo = inoinfo(ROOTINO); switch (rinfo->ino_state) { case USTATE: pfatal("ROOT INODE UNALLOCATED"); if (reply("ALLOCATE") == 0) { markclean = 0; ckfini(); exit(FSCK_EXIT_CHECK_FAILED); } if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) errexit("CANNOT ALLOCATE ROOT INODE"); break; case DCLEAR: pfatal("DUPS/BAD IN ROOT INODE"); if (reply("REALLOCATE")) { freeino(ROOTINO); if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) errexit("CANNOT ALLOCATE ROOT INODE"); break; } markclean = 0; if (reply("CONTINUE") == 0) { ckfini(); exit(FSCK_EXIT_CHECK_FAILED); } break; case FSTATE: case FCLEAR: pfatal("ROOT INODE NOT DIRECTORY"); if (reply("REALLOCATE")) { freeino(ROOTINO); if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) errexit("CANNOT ALLOCATE ROOT INODE"); break; } if (reply("FIX") == 0) { markclean = 0; ckfini(); exit(FSCK_EXIT_CHECK_FAILED); } dp = ginode(ROOTINO); DIP_SET(dp, mode, iswap16((iswap16(DIP(dp, mode)) & ~IFMT) | IFDIR)); inodirty(); break; case DSTATE: break; default: errexit("BAD STATE %d FOR ROOT INODE", rinfo->ino_state); } if (newinofmt) { info = inoinfo(WINO); info->ino_state = FSTATE; info->ino_type = DT_WHT; } /* * Sort the directory list into disk block order. */ qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort); /* * Check the integrity of each directory. */ memset(&curino, 0, sizeof(struct inodesc)); curino.id_type = DATA; curino.id_func = pass2check; inpend = &inpsort[inplast]; for (inpp = inpsort; inpp < inpend; inpp++) { if (got_siginfo) { fprintf(stderr, "%s: phase 2: dir %ld of %d (%d%%)\n", cdevname(), (long)(inpp - inpsort), (int)inplast, (int)((inpp - inpsort) * 100 / inplast)); got_siginfo = 0; } #ifdef PROGRESS progress_bar(cdevname(), preen ? NULL : "phase 2", (inpp - inpsort), inplast); #endif /* PROGRESS */ inp = *inpp; if (inp->i_isize == 0) continue; if (inp->i_isize < MINDIRSIZE) { direrror(inp->i_number, "DIRECTORY TOO SHORT"); inp->i_isize = roundup(MINDIRSIZE, dirblksiz); if (reply("FIX") == 1) { dp = ginode(inp->i_number); DIP_SET(dp, size, iswap64(inp->i_isize)); inodirty(); } else markclean = 0; } else if ((inp->i_isize & (dirblksiz - 1)) != 0) { getpathname(pathbuf, sizeof(pathbuf), inp->i_number, inp->i_number); if (usedsoftdep) pfatal("%s %s: LENGTH %lld NOT MULTIPLE OF %d", "DIRECTORY", pathbuf, (long long)inp->i_isize, dirblksiz); else pwarn("%s %s: LENGTH %lld NOT MULTIPLE OF %d", "DIRECTORY", pathbuf, (long long)inp->i_isize, dirblksiz); if (preen) printf(" (ADJUSTED)\n"); inp->i_isize = roundup(inp->i_isize, dirblksiz); if (preen || reply("ADJUST") == 1) { dp = ginode(inp->i_number); DIP_SET(dp, size, iswap64(inp->i_isize)); inodirty(); } else markclean = 0; } memset(&dino, 0, sizeof dino); dp = &dino; if (!is_ufs2) { dp->dp1.di_mode = iswap16(IFDIR); dp->dp1.di_size = iswap64(inp->i_isize); maxblk = inp->i_numblks < NDADDR ? inp->i_numblks : NDADDR; for (i = 0; i < maxblk; i++) dp->dp1.di_db[i] = inp->i_blks[i]; if (inp->i_numblks > NDADDR) { for (i = 0; i < NIADDR; i++) dp->dp1.di_ib[i] = inp->i_blks[NDADDR + i]; } } else { dp->dp2.di_mode = iswap16(IFDIR); dp->dp2.di_size = iswap64(inp->i_isize); maxblk = inp->i_numblks < NDADDR ? inp->i_numblks : NDADDR; for (i = 0; i < maxblk; i++) dp->dp2.di_db[i] = inp->i_blks[i]; if (inp->i_numblks > NDADDR) { for (i = 0; i < NIADDR; i++) dp->dp2.di_ib[i] = inp->i_blks[NDADDR + i]; } } curino.id_number = inp->i_number; curino.id_parent = inp->i_parent; (void)ckinode(&dino, &curino); } /* * Byte swapping in directory entries, if needed, has been done. * Now rescan dirs for pass2check() */ if (do_dirswap) { do_dirswap = 0; for (inpp = inpsort; inpp < inpend; inpp++) { inp = *inpp; if (inp->i_isize == 0) continue; memset(&dino, 0, sizeof dino); if (!is_ufs2) { dino.dp1.di_mode = iswap16(IFDIR); dino.dp1.di_size = iswap64(inp->i_isize); for (i = 0; i < inp->i_numblks; i++) dino.dp1.di_db[i] = inp->i_blks[i]; } else { dino.dp2.di_mode = iswap16(IFDIR); dino.dp2.di_size = iswap64(inp->i_isize); for (i = 0; i < inp->i_numblks; i++) dino.dp2.di_db[i] = inp->i_blks[i]; } curino.id_number = inp->i_number; curino.id_parent = inp->i_parent; (void)ckinode(&dino, &curino); } } /* * Now that the parents of all directories have been found, * make another pass to verify the value of `..' */ for (inpp = inpsort; inpp < inpend; inpp++) { inp = *inpp; if (inp->i_parent == 0 || inp->i_isize == 0) continue; if (inp->i_dotdot == inp->i_parent || inp->i_dotdot == (ino_t)-1) continue; info = inoinfo(inp->i_parent); if (inp->i_dotdot == 0) { inp->i_dotdot = inp->i_parent; fileerror(inp->i_parent, inp->i_number, "MISSING '..'"); if (reply("FIX") == 0) { markclean = 0; continue; } (void)makeentry(inp->i_number, inp->i_parent, ".."); info->ino_linkcnt--; continue; } fileerror(inp->i_parent, inp->i_number, "BAD INODE NUMBER FOR '..'"); if (reply("FIX") == 0) { markclean = 0; continue; } inoinfo(inp->i_dotdot)->ino_linkcnt++; info->ino_linkcnt--; inp->i_dotdot = inp->i_parent; (void)changeino(inp->i_number, "..", inp->i_parent); } /* * Create a list of children for each directory. */ inpend = &inpsort[inplast]; for (inpp = inpsort; inpp < inpend; inpp++) { inp = *inpp; info = inoinfo(inp->i_number); inp->i_child = inp->i_sibling = 0; if (info->ino_state == DFOUND) info->ino_state = DSTATE; } for (inpp = inpsort; inpp < inpend; inpp++) { inp = *inpp; if (inp->i_parent == 0 || inp->i_number == ROOTINO) continue; pinp = getinoinfo(inp->i_parent); inp->i_sibling = pinp->i_child; pinp->i_child = inp; } /* * Mark all the directories that can be found from the root. */ propagate(ROOTINO); #ifdef PROGRESS if (!preen) progress_done(); #endif /* PROGRESS */ }