예제 #1
0
파일: setup.c 프로젝트: andreiw/polaris
/*
 * 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;
		}
	}
}
예제 #2
0
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);
}
예제 #3
0
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);
}
예제 #4
0
파일: fsdb.c 프로젝트: sofuture/bitrig
/*
 * 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);
}
예제 #5
0
파일: setup.c 프로젝트: andreiw/polaris
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);
}
예제 #6
0
파일: inode.c 프로젝트: lacombar/netbsd-alc
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 */
	}
}
예제 #7
0
/*
 * 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);
}
예제 #8
0
파일: inode.c 프로젝트: SylvestreG/bitrig
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;
}
예제 #9
0
/*
 * 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);
}
예제 #10
0
파일: fsdb.c 프로젝트: ajinkya93/netbsd-src
/*
 * 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);
}
예제 #11
0
파일: inode.c 프로젝트: ryo/netbsd-src
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;
}
예제 #12
0
파일: dir.c 프로젝트: AgamAgarwal/minix
/*
 * 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);
}
예제 #13
0
파일: dir.c 프로젝트: ajinkya93/netbsd-src
/*
 * 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);
}
예제 #14
0
/*
 * 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);
}
예제 #15
0
파일: pass5.c 프로젝트: sergev/2.11BSD
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;
		}
	}
}
예제 #16
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);
}
예제 #17
0
파일: pass5.c 프로젝트: sergev/2.11BSD
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();
	}
}
예제 #18
0
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();
	}
}
예제 #19
0
파일: pass5.c 프로젝트: sergev/2.11BSD
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();
}
예제 #20
0
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);
}
예제 #21
0
파일: dir.c 프로젝트: lacombar/netbsd-alc
/*
 * 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);
}
예제 #22
0
파일: setup.c 프로젝트: ryo/netbsd-src
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;
}
예제 #23
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);
}
예제 #24
0
파일: tunefs.c 프로젝트: Alkzndr/freebsd
/*
 * 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);
}
예제 #25
0
파일: tunefs.c 프로젝트: Alkzndr/freebsd
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);
}
예제 #26
0
파일: setup.c 프로젝트: sofuture/bitrig
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);
}
예제 #27
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);
}
예제 #28
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();
	}
}
예제 #29
0
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();
	}
}
예제 #30
0
파일: setup.c 프로젝트: ornarium/freebsd
/*
 * 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);
}