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); }
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; }