xref: /csrg-svn/sbin/fsck/main.c (revision 6290)
1*6290Smckusick static	char *sccsid = "@(#)main.c	1.28 (Berkeley) 03/23/82";
24428Smckusic 
34236Smckusick #include <stdio.h>
44236Smckusick #include <ctype.h>
54236Smckusick #include "../h/param.h"
64236Smckusick #include "../h/fs.h"
74236Smckusick #include "../h/inode.h"
84236Smckusick #include "../h/stat.h"
94878Smckusic #include "../h/ostat.h"
105956Smckusic #include <ndir.h>
114236Smckusick #include <fstab.h>
124236Smckusick 
134236Smckusick typedef	int	(*SIG_TYP)();
144236Smckusick 
155347Smckusic #define	MAXNINDIR	(MAXBSIZE / sizeof (daddr_t))
165347Smckusic #define	MAXINOPB	(MAXBSIZE / sizeof (struct dinode))
175325Smckusic #define	SPERB		(MAXBSIZE / sizeof(short))
184236Smckusick 
194236Smckusick #define	MAXDUP	10		/* limit on dup blks (per inode) */
204236Smckusick #define	MAXBAD	10		/* limit on bad blks (per inode) */
214236Smckusick 
224236Smckusick #define	USTATE	0		/* inode not allocated */
234236Smckusick #define	FSTATE	01		/* inode is file */
244236Smckusick #define	DSTATE	02		/* inode is directory */
254236Smckusick #define	CLEAR	03		/* inode is to be cleared */
264236Smckusick 
274236Smckusick typedef struct dinode	DINODE;
284236Smckusick typedef struct direct	DIRECT;
294236Smckusick 
304236Smckusick #define	ALLOC	((dp->di_mode & IFMT) != 0)
315877Smckusic #define	DIRCT	((dp->di_mode & IFMT) == IFDIR)
324236Smckusick #define	REG	((dp->di_mode & IFMT) == IFREG)
334236Smckusick #define	BLK	((dp->di_mode & IFMT) == IFBLK)
344236Smckusick #define	CHR	((dp->di_mode & IFMT) == IFCHR)
356285Smckusick #define	SPECIAL	(BLK || CHR)
364236Smckusick 
374465Smckusic ino_t	startinum;		/* blk num of first in raw area */
384236Smckusick 
394236Smckusick struct bufarea {
404236Smckusick 	struct bufarea	*b_next;		/* must be first */
414236Smckusick 	daddr_t	b_bno;
424236Smckusick 	int	b_size;
434236Smckusick 	union {
445325Smckusic 		char	b_buf[MAXBSIZE];	/* buffer space */
454236Smckusick 		short	b_lnks[SPERB];		/* link counts */
465325Smckusic 		daddr_t	b_indir[MAXNINDIR];	/* indirect block */
474236Smckusick 		struct	fs b_fs;		/* super block */
484236Smckusick 		struct	cg b_cg;		/* cylinder group */
495325Smckusic 		struct dinode b_dinode[MAXINOPB]; /* inode block */
504236Smckusick 	} b_un;
514236Smckusick 	char	b_dirty;
524236Smckusick };
534236Smckusick 
544236Smckusick typedef struct bufarea BUFAREA;
554236Smckusick 
564236Smckusick BUFAREA	inoblk;			/* inode blocks */
574236Smckusick BUFAREA	fileblk;		/* other blks in filesys */
584236Smckusick BUFAREA	sblk;			/* file system superblock */
594236Smckusick BUFAREA	cgblk;
604236Smckusick 
614236Smckusick #define	initbarea(x)	(x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
624236Smckusick #define	dirty(x)	(x)->b_dirty = 1
634236Smckusick #define	inodirty()	inoblk.b_dirty = 1
644236Smckusick #define	sbdirty()	sblk.b_dirty = 1
654236Smckusick #define	cgdirty()	cgblk.b_dirty = 1
664236Smckusick 
674236Smckusick #define	dirblk		fileblk.b_un
684236Smckusick #define	sblock		sblk.b_un.b_fs
694236Smckusick #define	cgrp		cgblk.b_un.b_cg
704236Smckusick 
714236Smckusick struct filecntl {
724236Smckusick 	int	rfdes;
734236Smckusick 	int	wfdes;
744236Smckusick 	int	mod;
754236Smckusick } dfile;			/* file descriptors for filesys */
764236Smckusick 
774236Smckusick #define	DUPTBLSIZE	100	/* num of dup blocks to remember */
784236Smckusick daddr_t	duplist[DUPTBLSIZE];	/* dup block table */
794236Smckusick daddr_t	*enddup;		/* next entry in dup table */
804236Smckusick daddr_t	*muldup;		/* multiple dups part of table */
814236Smckusick 
824236Smckusick #define	MAXLNCNT	20	/* num zero link cnts to remember */
834236Smckusick ino_t	badlncnt[MAXLNCNT];	/* table of inos with zero link cnts */
844236Smckusick ino_t	*badlnp;		/* next entry in table */
854236Smckusick 
864236Smckusick char	rawflg;
874236Smckusick char	nflag;			/* assume a no response */
884236Smckusick char	yflag;			/* assume a yes response */
894236Smckusick int	bflag;			/* location of alternate super block */
905381Smckusic int	debug;			/* output debugging info */
914236Smckusick char	preen;			/* just fix normal inconsistencies */
924236Smckusick char	rplyflag;		/* any questions asked? */
934236Smckusick char	hotroot;		/* checking root device */
944236Smckusick char	fixcg;			/* corrupted free list bit maps */
954236Smckusick 
964236Smckusick char	*blkmap;		/* ptr to primary blk allocation map */
974236Smckusick char	*freemap;		/* ptr to secondary blk allocation map */
984236Smckusick char	*statemap;		/* ptr to inode state table */
994236Smckusick short	*lncntp;		/* ptr to link count table */
1004236Smckusick 
1014236Smckusick char	*pathp;			/* pointer to pathname position */
1024236Smckusick char	*thisname;		/* ptr to current pathname component */
1034236Smckusick char	*srchname;		/* name being searched for in dir */
1045877Smckusic char	pathname[BUFSIZ];
1054236Smckusick 
1064236Smckusick char	*lfname = "lost+found";
1074236Smckusick 
1084236Smckusick ino_t	inum;			/* inode we are currently working on */
1094236Smckusick ino_t	imax;			/* number of inodes */
1104236Smckusick ino_t	parentdir;		/* i number of parent directory */
1114236Smckusick ino_t	lastino;		/* hiwater mark of inodes */
1124236Smckusick ino_t	lfdir;			/* lost & found directory */
1134236Smckusick ino_t	orphan;			/* orphaned inode */
1144236Smckusick 
1154236Smckusick off_t	filsize;		/* num blks seen in file */
1164236Smckusick off_t	maxblk;			/* largest logical blk in file */
1174236Smckusick off_t	bmapsz;			/* num chars in blkmap */
1184236Smckusick 
1194236Smckusick daddr_t	n_ffree;		/* number of small free blocks */
1204236Smckusick daddr_t	n_bfree;		/* number of large free blocks */
1214236Smckusick daddr_t	n_blks;			/* number of blocks used */
1224236Smckusick daddr_t	n_files;		/* number of files seen */
1234236Smckusick daddr_t	n_index;
1244236Smckusick daddr_t	n_bad;
1254236Smckusick daddr_t	fmax;			/* number of blocks in the volume */
1264236Smckusick 
1274236Smckusick daddr_t	badblk;
1284236Smckusick daddr_t	dupblk;
1294236Smckusick 
1304236Smckusick int	inosumbad;
1314236Smckusick int	offsumbad;
1324465Smckusic int	frsumbad;
1334236Smckusick 
1344236Smckusick #define	zapino(x)	(*(x) = zino)
1354236Smckusick struct	dinode zino;
1364236Smckusick 
1374236Smckusick #define	setlncnt(x)	(lncntp[inum] = x)
1384236Smckusick #define	getlncnt()	(lncntp[inum])
1394236Smckusick #define	declncnt()	(--lncntp[inum])
1404236Smckusick 
1414236Smckusick #define	setbmap(x)	setbit(blkmap, x)
1424236Smckusick #define	getbmap(x)	isset(blkmap, x)
1434236Smckusick #define	clrbmap(x)	clrbit(blkmap, x)
1444236Smckusick 
1454236Smckusick #define	setfmap(x)	setbit(freemap, x)
1464236Smckusick #define	getfmap(x)	isset(freemap, x)
1474236Smckusick #define	clrfmap(x)	clrbit(freemap, x)
1484236Smckusick 
1494236Smckusick #define	setstate(x)	(statemap[inum] = x)
1504236Smckusick #define	getstate()	statemap[inum]
1514236Smckusick 
1524236Smckusick #define	DATA	1
1534236Smckusick #define	ADDR	0
1544236Smckusick 
1554236Smckusick #define	ALTERD	010
1564236Smckusick #define	KEEPON	04
1574236Smckusick #define	SKIP	02
1584236Smckusick #define	STOP	01
1594236Smckusick 
1604236Smckusick int	(*signal())();
1614236Smckusick long	lseek();
1624236Smckusick time_t	time();
1634236Smckusick DINODE	*ginode();
1644236Smckusick BUFAREA	*getblk();
1654236Smckusick int	dirscan();
1664236Smckusick int	findino();
1674236Smckusick int	catch();
1684236Smckusick int	mkentry();
1694236Smckusick int	chgdd();
1704236Smckusick int	pass1(), pass1b(), pass2(), pass4(), pass5();
1714236Smckusick int	(*pfunc)();
1724236Smckusick char	*rawname(), *rindex(), *unrawname();
1734606Smckusic extern int inside[], around[];
1745325Smckusic extern unsigned char *fragtbl[];
1754236Smckusick 
1764236Smckusick char	*devname;
1774236Smckusick 
1784236Smckusick main(argc, argv)
1794715Smckusic 	int	argc;
1804715Smckusic 	char	*argv[];
1814236Smckusick {
1824236Smckusick 	struct fstab *fsp;
1834236Smckusick 	int pid, passno, anygtr, sumstatus;
1844236Smckusick 
1854236Smckusick 	sync();
1864236Smckusick 	while (--argc > 0 && **++argv == '-') {
1874236Smckusick 		switch (*++*argv) {
1884236Smckusick 
1894236Smckusick 		case 'p':
1904236Smckusick 			preen++;
1914236Smckusick 			break;
1924236Smckusick 
1934236Smckusick 		case 'b':
1944236Smckusick 			bflag = atoi(argv[0]+1);
1954236Smckusick 			printf("Alternate super block location: %d\n", bflag);
1964236Smckusick 			break;
1974236Smckusick 
1985381Smckusic 		case 'd':
1995381Smckusic 			debug++;
2005381Smckusic 			break;
2015381Smckusic 
2024236Smckusick 		case 'n':	/* default no answer flag */
2034236Smckusick 		case 'N':
2044236Smckusick 			nflag++;
2054236Smckusick 			yflag = 0;
2064236Smckusick 			break;
2074236Smckusick 
2084236Smckusick 		case 'y':	/* default yes answer flag */
2094236Smckusick 		case 'Y':
2104236Smckusick 			yflag++;
2114236Smckusick 			nflag = 0;
2124236Smckusick 			break;
2134236Smckusick 
2144236Smckusick 		default:
2154236Smckusick 			errexit("%c option?\n", **argv);
2164236Smckusick 		}
2174236Smckusick 	}
2184236Smckusick 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
2194236Smckusick 		signal(SIGINT, catch);
2204236Smckusick 	if (argc) {
2214236Smckusick 		while (argc-- > 0) {
2224236Smckusick 			hotroot = 0;
2234236Smckusick 			check(*argv++);
2244236Smckusick 		}
2254236Smckusick 		exit(0);
2264236Smckusick 	}
2274236Smckusick 	sumstatus = 0;
2284236Smckusick 	passno = 1;
2294236Smckusick 	do {
2304236Smckusick 		anygtr = 0;
2314236Smckusick 		if (setfsent() == 0)
2324236Smckusick 			errexit("Can't open checklist file: %s\n", FSTAB);
2334236Smckusick 		while ((fsp = getfsent()) != 0) {
2344236Smckusick 			if (strcmp(fsp->fs_type, FSTAB_RW) &&
2354236Smckusick 			    strcmp(fsp->fs_type, FSTAB_RO))
2364236Smckusick 				continue;
2374236Smckusick 			if (preen == 0 ||
2384236Smckusick 			    passno == 1 && fsp->fs_passno == passno) {
2394236Smckusick 				if (blockcheck(fsp->fs_spec) == 0 && preen)
2404236Smckusick 					exit(8);
2414236Smckusick 			} else if (fsp->fs_passno > passno)
2424236Smckusick 				anygtr = 1;
2434236Smckusick 			else if (fsp->fs_passno == passno) {
2444236Smckusick 				pid = fork();
2454236Smckusick 				if (pid < 0) {
2464236Smckusick 					perror("fork");
2474236Smckusick 					exit(8);
2484236Smckusick 				}
2494236Smckusick 				if (pid == 0)
2504236Smckusick 					if (blockcheck(fsp->fs_spec)==0)
2514236Smckusick 						exit(8);
2524236Smckusick 					else
2534236Smckusick 						exit(0);
2544236Smckusick 			}
2554236Smckusick 		}
2564236Smckusick 		if (preen) {
2574236Smckusick 			int status;
2584236Smckusick 			while (wait(&status) != -1)
2594236Smckusick 				sumstatus |= status;
2604236Smckusick 		}
2614236Smckusick 		passno++;
2624236Smckusick 	} while (anygtr);
2634236Smckusick 	if (sumstatus)
2644236Smckusick 		exit(8);
2654236Smckusick 	endfsent();
2664236Smckusick 	exit(0);
2674236Smckusick }
2684236Smckusick 
2694236Smckusick blockcheck(name)
2704236Smckusick 	char *name;
2714236Smckusick {
2724878Smckusic 	struct ostat stslash, stblock, stchar;
2734236Smckusick 	char *raw;
2744236Smckusick 	int looped = 0;
2754236Smckusick 
2764236Smckusick 	hotroot = 0;
2774236Smckusick 	if (stat("/", &stslash) < 0){
2784236Smckusick 		error("Can't stat root\n");
2794236Smckusick 		return (0);
2804236Smckusick 	}
2814236Smckusick retry:
2824236Smckusick 	if (stat(name, &stblock) < 0){
2834236Smckusick 		error("Can't stat %s\n", name);
2844236Smckusick 		return (0);
2854236Smckusick 	}
2864236Smckusick 	if (stblock.st_mode & S_IFBLK) {
2874236Smckusick 		raw = rawname(name);
2884236Smckusick 		if (stat(raw, &stchar) < 0){
2894236Smckusick 			error("Can't stat %s\n", raw);
2904236Smckusick 			return (0);
2914236Smckusick 		}
2924236Smckusick 		if (stchar.st_mode & S_IFCHR) {
2934236Smckusick 			if (stslash.st_dev == stblock.st_rdev) {
2944236Smckusick 				hotroot++;
2954236Smckusick 				raw = unrawname(name);
2964236Smckusick 			}
2974236Smckusick 			check(raw);
2984236Smckusick 			return (1);
2994236Smckusick 		} else {
3004236Smckusick 			error("%s is not a character device\n", raw);
3014236Smckusick 			return (0);
3024236Smckusick 		}
3034236Smckusick 	} else if (stblock.st_mode & S_IFCHR) {
3044236Smckusick 		if (looped) {
3054236Smckusick 			error("Can't make sense out of name %s\n", name);
3064236Smckusick 			return (0);
3074236Smckusick 		}
3084236Smckusick 		name = unrawname(name);
3094236Smckusick 		looped++;
3104236Smckusick 		goto retry;
3114236Smckusick 	}
3124236Smckusick 	error("Can't make sense out of name %s\n", name);
3134236Smckusick 	return (0);
3144236Smckusick }
3154236Smckusick 
3164236Smckusick char *
3174236Smckusick unrawname(cp)
3184236Smckusick 	char *cp;
3194236Smckusick {
3204236Smckusick 	char *dp = rindex(cp, '/');
3214878Smckusic 	struct ostat stb;
3224236Smckusick 
3234236Smckusick 	if (dp == 0)
3244236Smckusick 		return (cp);
3254236Smckusick 	if (stat(cp, &stb) < 0)
3264236Smckusick 		return (cp);
3274236Smckusick 	if ((stb.st_mode&S_IFMT) != S_IFCHR)
3284236Smckusick 		return (cp);
3294236Smckusick 	if (*(dp+1) != 'r')
3304236Smckusick 		return (cp);
3314236Smckusick 	strcpy(dp+1, dp+2);
3324236Smckusick 	return (cp);
3334236Smckusick }
3344236Smckusick 
3354236Smckusick char *
3364236Smckusick rawname(cp)
3374236Smckusick 	char *cp;
3384236Smckusick {
3394236Smckusick 	static char rawbuf[32];
3404236Smckusick 	char *dp = rindex(cp, '/');
3414236Smckusick 
3424236Smckusick 	if (dp == 0)
3434236Smckusick 		return (0);
3444236Smckusick 	*dp = 0;
3454236Smckusick 	strcpy(rawbuf, cp);
3464236Smckusick 	*dp = '/';
3474236Smckusick 	strcat(rawbuf, "/r");
3484236Smckusick 	strcat(rawbuf, dp+1);
3494236Smckusick 	return (rawbuf);
3504236Smckusick }
3514236Smckusick 
3524236Smckusick check(dev)
3534236Smckusick 	char *dev;
3544236Smckusick {
3554236Smckusick 	register DINODE *dp;
3564236Smckusick 	register ino_t *blp;
3574236Smckusick 	register int i, n;
3584236Smckusick 	ino_t savino;
3594236Smckusick 	int b, c;
3604236Smckusick 	daddr_t d, s;
3614236Smckusick 
3624236Smckusick 	devname = dev;
3634236Smckusick 	if (setup(dev) == 0) {
3644236Smckusick 		if (preen)
3654236Smckusick 			pfatal("CAN'T CHECK DEVICE.");
3664236Smckusick 		return;
3674236Smckusick 	}
3684236Smckusick /* 1 */
3694236Smckusick 	if (preen==0) {
3704236Smckusick 		if (hotroot)
3714236Smckusick 			printf("** Root file system\n");
3724236Smckusick 		printf("** Phase 1 - Check Blocks and Sizes\n");
3734236Smckusick 	}
3744236Smckusick 	pfunc = pass1;
3754236Smckusick 	inum = 0;
3765325Smckusic 	n_blks += howmany(sblock.fs_cssize, sblock.fs_bsize) * sblock.fs_frag;
3774236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
3785381Smckusic 		if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
3794236Smckusick 			continue;
3804236Smckusick 		n = 0;
3814465Smckusic 		for (i = 0; i < sblock.fs_ipg; i++, inum++) {
3824465Smckusic 			dp = ginode();
3834465Smckusic 			if (dp == NULL)
3844465Smckusic 				continue;
3855944Smckusic 			n++;
3864236Smckusick 			if (ALLOC) {
3874236Smckusick 				if (!isset(cgrp.cg_iused, i)) {
3885381Smckusic 					if (debug)
3895381Smckusic 						printf("%d bad, not used\n",
3905381Smckusic 						    inum);
3914236Smckusick 					inosumbad++;
3924236Smckusick 				}
3935944Smckusic 				n--;
3944236Smckusick 				lastino = inum;
3954236Smckusick 				if (ftypeok(dp) == 0) {
3964236Smckusick 					pfatal("UNKNOWN FILE TYPE I=%u", inum);
3974236Smckusick 					if (reply("CLEAR") == 1) {
3984236Smckusick 						zapino(dp);
3994236Smckusick 						inodirty();
4004236Smckusick 						inosumbad++;
4014236Smckusick 					}
4024236Smckusick 					continue;
4034236Smckusick 				}
4044236Smckusick 				n_files++;
4054236Smckusick 				if (setlncnt(dp->di_nlink) <= 0) {
4064236Smckusick 					if (badlnp < &badlncnt[MAXLNCNT])
4074236Smckusick 						*badlnp++ = inum;
4084236Smckusick 					else {
4094236Smckusick 						pfatal("LINK COUNT TABLE OVERFLOW");
4104236Smckusick 						if (reply("CONTINUE") == 0)
4114236Smckusick 							errexit("");
4124236Smckusick 					}
4134236Smckusick 				}
4145877Smckusic 				setstate(DIRCT ? DSTATE : FSTATE);
4154236Smckusick 				badblk = dupblk = 0; filsize = 0; maxblk = 0;
4164236Smckusick 				ckinode(dp, ADDR);
4174236Smckusick 			} else {
4184236Smckusick 				if (isset(cgrp.cg_iused, i)) {
4195381Smckusic 					if (debug)
4205381Smckusic 						printf("%d bad, marked used\n",
4215381Smckusic 						    inum);
4224236Smckusick 					inosumbad++;
4234465Smckusic 					n--;
4244236Smckusick 				}
4254236Smckusick 				if (dp->di_mode != 0) {
4264236Smckusick 					pfatal("PARTIALLY ALLOCATED INODE I=%u", inum);
4274236Smckusick 					if (reply("CLEAR") == 1) {
4284236Smckusick 						zapino(dp);
4294236Smckusick 						inodirty();
4304236Smckusick 						inosumbad++;
4314236Smckusick 					}
4324236Smckusick 				}
4334236Smckusick 			}
4344236Smckusick 		}
4354789Smckusic 		if (n != cgrp.cg_cs.cs_nifree) {
4365381Smckusic 			if (debug)
4375944Smckusic 				printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n",
4385381Smckusic 				    c, cgrp.cg_cs.cs_nifree, n);
4394236Smckusick 			inosumbad++;
4404236Smckusick 		}
4414236Smckusick 	}
4424236Smckusick /* 1b */
4434236Smckusick 	if (enddup != &duplist[0]) {
4444236Smckusick 		if (preen)
4454236Smckusick 			pfatal("INTERNAL ERROR: dups with -p");
4464236Smckusick 		printf("** Phase 1b - Rescan For More DUPS\n");
4474236Smckusick 		pfunc = pass1b;
4484236Smckusick 		inum = 0;
4494236Smckusick 		for (c = 0; c < sblock.fs_ncg; c++) {
4504465Smckusic 			for (i = 0; i < sblock.fs_ipg; i++, inum++) {
4514465Smckusic 				dp = ginode();
4524465Smckusic 				if (dp == NULL)
4534465Smckusic 					continue;
4544236Smckusick 				if (getstate() != USTATE &&
4554236Smckusick 				    (ckinode(dp, ADDR) & STOP))
4564236Smckusick 					goto out1b;
4574465Smckusic 			}
4584236Smckusick 		}
4594236Smckusick 	}
4604236Smckusick out1b:
4614465Smckusic 	flush(&dfile, &inoblk);
4624236Smckusick /* 2 */
4634236Smckusick 	if (preen == 0)
4644236Smckusick 		printf("** Phase 2 - Check Pathnames\n");
4654236Smckusick 	inum = ROOTINO;
4664236Smckusick 	thisname = pathp = pathname;
4674236Smckusick 	pfunc = pass2;
4684236Smckusick 	switch (getstate()) {
4694236Smckusick 
4704236Smckusick 	case USTATE:
4714236Smckusick 		errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
4724236Smckusick 
4734236Smckusick 	case FSTATE:
4744236Smckusick 		pfatal("ROOT INODE NOT DIRECTORY");
4754236Smckusick 		if (reply("FIX") == 0 || (dp = ginode()) == NULL)
4764236Smckusick 			errexit("");
4774236Smckusick 		dp->di_mode &= ~IFMT;
4784236Smckusick 		dp->di_mode |= IFDIR;
4794236Smckusick 		inodirty();
4804236Smckusick 		inosumbad++;
4814236Smckusick 		setstate(DSTATE);
4824236Smckusick 		/* fall into ... */
4834236Smckusick 
4844236Smckusick 	case DSTATE:
4854236Smckusick 		descend();
4864236Smckusick 		break;
4874236Smckusick 
4884236Smckusick 	case CLEAR:
4894236Smckusick 		pfatal("DUPS/BAD IN ROOT INODE");
4904236Smckusick 		printf("\n");
4914236Smckusick 		if (reply("CONTINUE") == 0)
4924236Smckusick 			errexit("");
4934236Smckusick 		setstate(DSTATE);
4944236Smckusick 		descend();
4954236Smckusick 	}
4964236Smckusick /* 3 */
4974236Smckusick 	if (preen == 0)
4984236Smckusick 		printf("** Phase 3 - Check Connectivity\n");
4994236Smckusick 	for (inum = ROOTINO; inum <= lastino; inum++) {
5004236Smckusick 		if (getstate() == DSTATE) {
5014236Smckusick 			pfunc = findino;
5024236Smckusick 			srchname = "..";
5034236Smckusick 			savino = inum;
5044236Smckusick 			do {
5054236Smckusick 				orphan = inum;
5064236Smckusick 				if ((dp = ginode()) == NULL)
5074236Smckusick 					break;
5084236Smckusick 				filsize = dp->di_size;
5094236Smckusick 				parentdir = 0;
5104236Smckusick 				ckinode(dp, DATA);
5114236Smckusick 				if ((inum = parentdir) == 0)
5124236Smckusick 					break;
5134236Smckusick 			} while (getstate() == DSTATE);
5144236Smckusick 			inum = orphan;
5154236Smckusick 			if (linkup() == 1) {
5164236Smckusick 				thisname = pathp = pathname;
5174236Smckusick 				*pathp++ = '?';
5184236Smckusick 				pfunc = pass2;
5194236Smckusick 				descend();
5204236Smckusick 			}
5214236Smckusick 			inum = savino;
5224236Smckusick 		}
5234236Smckusick 	}
5244236Smckusick /* 4 */
5254236Smckusick 	if (preen == 0)
5264236Smckusick 		printf("** Phase 4 - Check Reference Counts\n");
5274236Smckusick 	pfunc = pass4;
5284236Smckusick 	for (inum = ROOTINO; inum <= lastino; inum++) {
5294236Smckusick 		switch (getstate()) {
5304236Smckusick 
5314236Smckusick 		case FSTATE:
5324236Smckusick 			if (n = getlncnt())
5334236Smckusick 				adjust((short)n);
5344236Smckusick 			else {
5354236Smckusick 				for (blp = badlncnt;blp < badlnp; blp++)
5364236Smckusick 					if (*blp == inum) {
5374236Smckusick 						clri("UNREF", 1);
5384236Smckusick 						break;
5394236Smckusick 					}
5404236Smckusick 			}
5414236Smckusick 			break;
5424236Smckusick 
5434236Smckusick 		case DSTATE:
5444236Smckusick 			clri("UNREF", 1);
5454236Smckusick 			break;
5464236Smckusick 
5474236Smckusick 		case CLEAR:
5484236Smckusick 			clri("BAD/DUP", 1);
5494236Smckusick 			break;
5504236Smckusick 		}
5514236Smckusick 	}
5525337Smckusic 	if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) {
5534236Smckusick 		pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
5544236Smckusick 		if (preen)
5554236Smckusick 			printf(" (FIXED)\n");
5564236Smckusick 		if (preen || reply("FIX") == 1) {
5575944Smckusic 			sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files;
5584236Smckusick 			sbdirty();
5594236Smckusick 		}
5604236Smckusick 	}
5614236Smckusick 	flush(&dfile, &fileblk);
5624236Smckusick 
5634236Smckusick /* 5 */
5644236Smckusick 	if (preen == 0)
5654236Smckusick 		printf("** Phase 5 - Check Cyl groups\n");
5664236Smckusick 	copy(blkmap, freemap, (unsigned)bmapsz);
5674236Smckusick 	dupblk = 0;
5685381Smckusic 	n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0));
5694236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
5705381Smckusic 		daddr_t cbase = cgbase(&sblock, c);
5714236Smckusick 		short bo[MAXCPG][NRPOS];
5725371Smckusic 		long botot[MAXCPG];
5735325Smckusic 		long frsum[MAXFRAG];
5744465Smckusic 		int blk;
5754465Smckusic 
5765371Smckusic 		for (n = 0; n < sblock.fs_cpg; n++) {
5775371Smckusic 			botot[n] = 0;
5784236Smckusick 			for (i = 0; i < NRPOS; i++)
5794236Smckusick 				bo[n][i] = 0;
5805371Smckusic 		}
5815325Smckusic 		for (i = 0; i < sblock.fs_frag; i++) {
5824465Smckusic 			frsum[i] = 0;
5834465Smckusic 		}
5844465Smckusic 		/*
5854465Smckusic 		 * need to account for the spare boot and super blocks
5864465Smckusic 		 * which appear (inaccurately) bad
5874465Smckusic 		 */
5885381Smckusic 		n_bad += cgtod(&sblock, c) - cbase;
5895381Smckusic 		if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
5904236Smckusick 			continue;
5915325Smckusic 		for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
5925325Smckusic 			if (isblock(&sblock, cgrp.cg_free, b/sblock.fs_frag)) {
5935325Smckusic 				if (pass5(cbase+b, sblock.fs_frag) == STOP)
5944236Smckusick 					goto out5;
5954236Smckusick 				/* this is clumsy ... */
5965325Smckusic 				n_ffree -= sblock.fs_frag;
5974236Smckusick 				n_bfree++;
5985371Smckusic 				botot[cbtocylno(&sblock, b)]++;
5995363Smckusic 				bo[cbtocylno(&sblock, b)]
6005363Smckusic 				    [cbtorpos(&sblock, b)]++;
6014465Smckusic 			} else {
6025325Smckusic 				for (d = 0; d < sblock.fs_frag; d++)
6034236Smckusick 					if (isset(cgrp.cg_free, b+d))
6044236Smckusick 						if (pass5(cbase+b+d,1) == STOP)
6054236Smckusick 							goto out5;
6064465Smckusic 				blk = ((cgrp.cg_free[b / NBBY] >> (b % NBBY)) &
6075325Smckusic 				       (0xff >> (NBBY - sblock.fs_frag)));
6084465Smckusic 				if (blk != 0)
6095325Smckusic 					fragacct(&sblock, blk, frsum, 1);
6104465Smckusic 			}
6114236Smckusick 		}
6125325Smckusic 		for (i = 0; i < sblock.fs_frag; i++) {
6134465Smckusic 			if (cgrp.cg_frsum[i] != frsum[i]) {
6145381Smckusic 				if (debug)
6155381Smckusic 					printf("cg[%d].cg_frsum[%d] have %d calc %d\n",
6165381Smckusic 					    c, i, cgrp.cg_frsum[i], frsum[i]);
6174465Smckusic 				frsumbad++;
6184465Smckusic 			}
6194465Smckusic 		}
6205371Smckusic 		for (n = 0; n < sblock.fs_cpg; n++) {
6215371Smckusic 			if (botot[n] != cgrp.cg_btot[n]) {
6225381Smckusic 				if (debug)
6235381Smckusic 					printf("cg[%d].cg_btot[%d] have %d calc %d\n",
6245381Smckusic 					    c, n, cgrp.cg_btot[n], botot[n]);
6255371Smckusic 				offsumbad++;
6265371Smckusic 			}
6274236Smckusick 			for (i = 0; i < NRPOS; i++)
6284236Smckusick 				if (bo[n][i] != cgrp.cg_b[n][i]) {
6295381Smckusic 					if (debug)
6305381Smckusic 						printf("cg[%d].cg_b[%d][%d] have %d calc %d\n",
6315381Smckusic 						    c, n, i, cgrp.cg_b[n][i],
6325381Smckusic 						    bo[n][i]);
6334236Smckusick 					offsumbad++;
6344236Smckusick 				}
6355371Smckusic 		}
6364236Smckusick 	}
6374236Smckusick out5:
6384236Smckusick 	if (dupblk)
6394236Smckusick 		pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk);
6404236Smckusick 	if (fixcg == 0) {
6415325Smckusic 		if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) {
6424236Smckusick 			pwarn("%ld BLK(S) MISSING\n", fmax - b);
6434236Smckusick 			fixcg = 1;
6444465Smckusic 		} else if (inosumbad + offsumbad + frsumbad) {
6454465Smckusic 			pwarn("SUMMARY INFORMATION %s%s%sBAD\n",
6464236Smckusick 			    inosumbad ? "(INODE FREE) " : "",
6474465Smckusic 			    offsumbad ? "(BLOCK OFFSETS) " : "",
6484465Smckusic 			    frsumbad ? "(FRAG SUMMARIES) " : "");
6494236Smckusick 			fixcg = 1;
6504789Smckusic 		} else if (n_ffree != sblock.fs_cstotal.cs_nffree ||
6514789Smckusic 		    n_bfree != sblock.fs_cstotal.cs_nbfree) {
6524236Smckusick 			pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK");
6534236Smckusick 			if (preen)
6544236Smckusick 				printf(" (FIXED)\n");
6554236Smckusick 			if (preen || reply("FIX") == 1) {
6564789Smckusic 				sblock.fs_cstotal.cs_nffree = n_ffree;
6574789Smckusic 				sblock.fs_cstotal.cs_nbfree = n_bfree;
6584236Smckusick 				sbdirty();
6594236Smckusick 			}
6604236Smckusick 		}
6614236Smckusick 	}
6624236Smckusick 	if (fixcg) {
6634236Smckusick 		pwarn("BAD CYLINDER GROUPS");
6644236Smckusick 		if (preen)
6654236Smckusick 			printf(" (SALVAGED)\n");
6664236Smckusick 		else if (reply("SALVAGE") == 0)
6674236Smckusick 			fixcg = 0;
6684236Smckusick 	}
6694236Smckusick 
6704236Smckusick 	if (fixcg) {
6714236Smckusick 		if (preen == 0)
6724236Smckusick 			printf("** Phase 6 - Salvage Cylinder Groups\n");
6734236Smckusick 		makecg();
6744789Smckusic 		n_ffree = sblock.fs_cstotal.cs_nffree;
6754789Smckusic 		n_bfree = sblock.fs_cstotal.cs_nbfree;
6764236Smckusick 	}
6774236Smckusick 
6784236Smckusick 	pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n",
6795325Smckusic 	    n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_bsize) * sblock.fs_frag,
6805325Smckusic 	    n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree);
6814236Smckusick 	if (dfile.mod) {
6824236Smckusick 		time(&sblock.fs_time);
6834236Smckusick 		sbdirty();
6844236Smckusick 	}
6854236Smckusick 	ckfini();
6864236Smckusick 	sync();
6874236Smckusick 	if (dfile.mod && hotroot) {
6884236Smckusick 		printf("\n***** BOOT UNIX (NO SYNC!) *****\n");
6894236Smckusick 		exit(4);
6904236Smckusick 	}
6914236Smckusick 	if (dfile.mod && preen == 0)
6924236Smckusick 		printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
6934236Smckusick 	free(blkmap);
6944236Smckusick 	free(freemap);
6954236Smckusick 	free(statemap);
6964236Smckusick 	free(lncntp);
6974236Smckusick }
6984236Smckusick 
6994236Smckusick /* VARARGS1 */
7004236Smckusick error(s1, s2, s3, s4)
7014715Smckusic 	char *s1;
7024236Smckusick {
7034236Smckusick 
7044236Smckusick 	printf(s1, s2, s3, s4);
7054236Smckusick }
7064236Smckusick 
7074236Smckusick /* VARARGS1 */
7084236Smckusick errexit(s1, s2, s3, s4)
7094715Smckusic 	char *s1;
7104236Smckusick {
7114236Smckusick 	error(s1, s2, s3, s4);
7124236Smckusick 	exit(8);
7134236Smckusick }
7144236Smckusick 
7154236Smckusick /*
7164236Smckusick  * An inconsistency occured which shouldn't during normal operations.
7174236Smckusick  * Die if preening, otw just printf.
7184236Smckusick  */
7194236Smckusick /* VARARGS1 */
7204236Smckusick pfatal(s, a1, a2, a3)
7214236Smckusick 	char *s;
7224236Smckusick {
7234236Smckusick 
7244236Smckusick 	if (preen) {
7254236Smckusick 		printf("%s: ", devname);
7264236Smckusick 		printf(s, a1, a2, a3);
7274236Smckusick 		printf("\n");
7284236Smckusick 		preendie();
7294236Smckusick 	}
7304236Smckusick 	printf(s, a1, a2, a3);
7314236Smckusick }
7324236Smckusick 
7334236Smckusick preendie()
7344236Smckusick {
7354236Smckusick 
7364236Smckusick 	printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
7374236Smckusick 	exit(8);
7384236Smckusick }
7394236Smckusick 
7404236Smckusick /*
7414236Smckusick  * Pwarn is like printf when not preening,
7424236Smckusick  * or a warning (preceded by filename) when preening.
7434236Smckusick  */
7444236Smckusick /* VARARGS1 */
7454236Smckusick pwarn(s, a1, a2, a3, a4, a5)
7464236Smckusick 	char *s;
7474236Smckusick {
7484236Smckusick 
7494236Smckusick 	if (preen)
7504236Smckusick 		printf("%s: ", devname);
7514236Smckusick 	printf(s, a1, a2, a3, a4, a5);
7524236Smckusick }
7534236Smckusick 
7544236Smckusick ckinode(dp, flg)
7554236Smckusick 	DINODE *dp;
7564236Smckusick 	register flg;
7574236Smckusick {
7584236Smckusick 	register daddr_t *ap;
7594236Smckusick 	register ret;
7605956Smckusic 	int (*func)(), n, ndb, size, offset;
7614236Smckusick 
7624236Smckusick 	if (SPECIAL)
7634236Smckusick 		return (KEEPON);
7644236Smckusick 	func = (flg == ADDR) ? pfunc : dirscan;
7655325Smckusic 	ndb = howmany(dp->di_size, sblock.fs_bsize);
7664428Smckusic 	for (ap = &dp->di_db[0]; ap < &dp->di_db[NDADDR]; ap++) {
7675956Smckusic 		if (--ndb == 0 && (offset = blkoff(&sblock, dp->di_size)) != 0)
7685956Smckusic 			size = numfrags(&sblock, fragroundup(&sblock, offset));
7694236Smckusick 		else
7705325Smckusic 			size = sblock.fs_frag;
7714236Smckusick 		if (*ap && (ret = (*func)(*ap, size)) & STOP)
7724236Smckusick 			return (ret);
7734236Smckusick 	}
7744428Smckusic 	for (ap = &dp->di_ib[0], n = 1; n <= 2; ap++, n++) {
7755325Smckusic 		if (*ap && (ret = iblock(*ap, n, flg, dp->di_size - sblock.fs_bsize * NDADDR)) & STOP)
7764236Smckusick 			return (ret);
7774236Smckusick 	}
7784236Smckusick 	return (KEEPON);
7794236Smckusick }
7804236Smckusick 
7814236Smckusick iblock(blk, ilevel, flg, isize)
7824236Smckusick 	daddr_t blk;
7834236Smckusick 	register ilevel;
7844236Smckusick 	int isize;
7854236Smckusick {
7864236Smckusick 	register daddr_t *ap;
7874236Smckusick 	register daddr_t *aplim;
7884428Smckusic 	register int i, n;
7894236Smckusick 	int (*func)(), nif;
7904236Smckusick 	BUFAREA ib;
7914236Smckusick 
7924236Smckusick 	if (flg == ADDR) {
7934236Smckusick 		func = pfunc;
7945325Smckusic 		if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0)
7954236Smckusick 			return (n);
7964236Smckusick 	} else
7974236Smckusick 		func = dirscan;
7984236Smckusick 	if (outrange(blk))		/* protect thyself */
7994236Smckusick 		return (SKIP);
8004236Smckusick 	initbarea(&ib);
8015325Smckusic 	if (getblk(&ib, blk, sblock.fs_bsize) == NULL)
8024236Smckusick 		return (SKIP);
8034236Smckusick 	ilevel--;
8044428Smckusic 	if (ilevel == 0) {
8055956Smckusic 		nif = lblkno(&sblock, isize) + 1;
8064428Smckusic 	} else /* ilevel == 1 */ {
8075325Smckusic 		nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1;
8084428Smckusic 	}
8095325Smckusic 	if (nif > NINDIR(&sblock))
8105325Smckusic 		nif = NINDIR(&sblock);
8114428Smckusic 	aplim = & ib.b_un.b_indir[nif];
8124428Smckusic 	for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
8134236Smckusick 		if (*ap) {
8144236Smckusick 			if (ilevel > 0)
8155325Smckusic 				n = iblock(*ap, ilevel, flg, isize - i * NINDIR(&sblock) * sblock.fs_bsize);
8164236Smckusick 			else
8175325Smckusic 				n = (*func)(*ap, sblock.fs_frag);
8184236Smckusick 			if (n & STOP)
8194236Smckusick 				return (n);
8204236Smckusick 		}
8214236Smckusick 	return (KEEPON);
8224236Smckusick }
8234236Smckusick 
8244236Smckusick pass1(blk, size)
8254236Smckusick 	daddr_t blk;
8264236Smckusick 	int size;
8274236Smckusick {
8284236Smckusick 	register daddr_t *dlp;
8294236Smckusick 	int res = KEEPON;
8304236Smckusick 
8314236Smckusick 	for (; size > 0; blk++, size--) {
8324236Smckusick 		if (outrange(blk)) {
8334236Smckusick 			blkerr("BAD", blk);
8344236Smckusick 			if (++badblk >= MAXBAD) {
8354236Smckusick 				printf("EXCESSIVE BAD BLKS I=%u", inum);
8364236Smckusick 				if (reply("CONTINUE") == 0)
8374236Smckusick 					errexit("");
8384236Smckusick 				return (STOP);
8394236Smckusick 			}
8404236Smckusick 			res = SKIP;
8414236Smckusick 		} else if (getbmap(blk)) {
8424236Smckusick 			blkerr("DUP", blk);
8434236Smckusick 			if (++dupblk >= MAXDUP) {
8444236Smckusick 				printf("EXCESSIVE DUP BLKS I=%u", inum);
8454236Smckusick 				if (reply("CONTINUE") == 0)
8464236Smckusick 					errexit("");
8474236Smckusick 				return (STOP);
8484236Smckusick 			}
8494236Smckusick 			if (enddup >= &duplist[DUPTBLSIZE]) {
8504236Smckusick 				printf("DUP TABLE OVERFLOW.");
8514236Smckusick 				if (reply("CONTINUE") == 0)
8524236Smckusick 					errexit("");
8534236Smckusick 				return (STOP);
8544236Smckusick 			}
8554236Smckusick 			for (dlp = duplist; dlp < muldup; dlp++)
8564236Smckusick 				if (*dlp == blk) {
8574236Smckusick 					*enddup++ = blk;
8584236Smckusick 					break;
8594236Smckusick 				}
8604236Smckusick 			if (dlp >= muldup) {
8614236Smckusick 				*enddup++ = *muldup;
8624236Smckusick 				*muldup++ = blk;
8634236Smckusick 			}
8644236Smckusick 		} else {
8654236Smckusick 			n_blks++;
8664236Smckusick 			setbmap(blk);
8674236Smckusick 		}
8684236Smckusick 		filsize++;
8694236Smckusick 	}
8704236Smckusick 	return (res);
8714236Smckusick }
8724236Smckusick 
8734236Smckusick pass1b(blk, size)
8744236Smckusick 	daddr_t blk;
8754236Smckusick 	int size;
8764236Smckusick {
8774236Smckusick 	register daddr_t *dlp;
8784236Smckusick 	int res = KEEPON;
8794236Smckusick 
8804236Smckusick 	for (; size > 0; blk++, size--) {
8814236Smckusick 		if (outrange(blk))
8824236Smckusick 			res = SKIP;
8834236Smckusick 		for (dlp = duplist; dlp < muldup; dlp++)
8844236Smckusick 			if (*dlp == blk) {
8854236Smckusick 				blkerr("DUP", blk);
8864236Smckusick 				*dlp = *--muldup;
8874236Smckusick 				*muldup = blk;
8884236Smckusick 				if (muldup == duplist)
8894236Smckusick 					return (STOP);
8904236Smckusick 			}
8914236Smckusick 	}
8924236Smckusick 	return (res);
8934236Smckusick }
8944236Smckusick 
8954236Smckusick pass2(dirp)
8964236Smckusick 	register DIRECT *dirp;
8974236Smckusick {
8984236Smckusick 	register char *p;
8994236Smckusick 	register n;
9004236Smckusick 	DINODE *dp;
9014236Smckusick 
9024236Smckusick 	if ((inum = dirp->d_ino) == 0)
9034236Smckusick 		return (KEEPON);
9044236Smckusick 	thisname = pathp;
9055877Smckusic 	for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; )
9064236Smckusick 		if ((*pathp++ = *p++) == 0) {
9074236Smckusick 			--pathp;
9084236Smckusick 			break;
9094236Smckusick 		}
9104236Smckusick 	*pathp = 0;
9114236Smckusick 	n = 0;
9124715Smckusic 	if (inum > imax || inum <= 0)
9134236Smckusick 		n = direrr("I OUT OF RANGE");
9144236Smckusick 	else {
9154236Smckusick again:
9164236Smckusick 		switch (getstate()) {
9174236Smckusick 		case USTATE:
9184236Smckusick 			n = direrr("UNALLOCATED");
9194236Smckusick 			break;
9204236Smckusick 
9214236Smckusick 		case CLEAR:
9224236Smckusick 			if ((n = direrr("DUP/BAD")) == 1)
9234236Smckusick 				break;
9244236Smckusick 			if ((dp = ginode()) == NULL)
9254236Smckusick 				break;
9265877Smckusic 			setstate(DIRCT ? DSTATE : FSTATE);
9274236Smckusick 			goto again;
9284236Smckusick 
9294236Smckusick 		case FSTATE:
9304236Smckusick 			declncnt();
9314236Smckusick 			break;
9324236Smckusick 
9334236Smckusick 		case DSTATE:
9344236Smckusick 			declncnt();
9354236Smckusick 			descend();
9364236Smckusick 			break;
9374236Smckusick 		}
9384236Smckusick 	}
9394236Smckusick 	pathp = thisname;
9404236Smckusick 	if (n == 0)
9414236Smckusick 		return (KEEPON);
9424236Smckusick 	dirp->d_ino = 0;
9434236Smckusick 	return (KEEPON|ALTERD);
9444236Smckusick }
9454236Smckusick 
9464236Smckusick pass4(blk, size)
9474715Smckusic 	daddr_t blk;
9484236Smckusick {
9494236Smckusick 	register daddr_t *dlp;
9504236Smckusick 	int res = KEEPON;
9514236Smckusick 
9524236Smckusick 	for (; size > 0; blk++, size--) {
9534236Smckusick 		if (outrange(blk))
9544236Smckusick 			res = SKIP;
9554236Smckusick 		else if (getbmap(blk)) {
9564236Smckusick 			for (dlp = duplist; dlp < enddup; dlp++)
9574236Smckusick 				if (*dlp == blk) {
9584236Smckusick 					*dlp = *--enddup;
9594236Smckusick 					return (KEEPON);
9604236Smckusick 				}
9614236Smckusick 			clrbmap(blk);
9624236Smckusick 			n_blks--;
9634236Smckusick 		}
9644236Smckusick 	}
9654236Smckusick 	return (res);
9664236Smckusick }
9674236Smckusick 
9684236Smckusick pass5(blk, size)
9694236Smckusick 	daddr_t blk;
9704236Smckusick 	int size;
9714236Smckusick {
9724236Smckusick 	int res = KEEPON;
9734236Smckusick 
9744236Smckusick 	for (; size > 0; blk++, size--) {
9754236Smckusick 		if (outrange(blk)) {
9764236Smckusick 			fixcg = 1;
9774236Smckusick 			if (preen)
9784236Smckusick 				pfatal("BAD BLOCKS IN BIT MAPS.");
9794236Smckusick 			if (++badblk >= MAXBAD) {
9804236Smckusick 				printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
9814236Smckusick 				if (reply("CONTINUE") == 0)
9824236Smckusick 					errexit("");
9834236Smckusick 				return (STOP);
9844236Smckusick 			}
9854236Smckusick 		} else if (getfmap(blk)) {
9864236Smckusick 			fixcg = 1;
9874236Smckusick 			if (++dupblk >= DUPTBLSIZE) {
9884236Smckusick 				printf("EXCESSIVE DUP BLKS IN BIT MAPS.");
9894236Smckusick 				if (reply("CONTINUE") == 0)
9904236Smckusick 					errexit("");
9914236Smckusick 				return (STOP);
9924236Smckusick 			}
9934236Smckusick 		} else {
9944236Smckusick 			n_ffree++;
9954236Smckusick 			setfmap(blk);
9964236Smckusick 		}
9974236Smckusick 	}
9984236Smckusick 	return (res);
9994236Smckusick }
10004236Smckusick 
10014236Smckusick outrange(blk)
10024236Smckusick 	daddr_t blk;
10034236Smckusick {
10044236Smckusick 	register int c;
10054236Smckusick 
10065381Smckusic 	c = dtog(&sblock, blk);
10075381Smckusic 	if (blk >= fmax || blk < cgdmin(&sblock, c)) {
10084236Smckusick 		return (1);
10094428Smckusic 	}
10104236Smckusick 	return (0);
10114236Smckusick }
10124236Smckusick 
10134236Smckusick blkerr(s, blk)
10144236Smckusick 	daddr_t blk;
10154236Smckusick 	char *s;
10164236Smckusick {
10174236Smckusick 	pfatal("%ld %s I=%u", blk, s, inum);
10184236Smckusick 	printf("\n");
10194236Smckusick 	setstate(CLEAR);	/* mark for possible clearing */
10204236Smckusick }
10214236Smckusick 
10224236Smckusick descend()
10234236Smckusick {
10244236Smckusick 	register DINODE *dp;
10254236Smckusick 	register char *savname;
10264236Smckusick 	off_t savsize;
10274236Smckusick 
10284236Smckusick 	setstate(FSTATE);
10294236Smckusick 	if ((dp = ginode()) == NULL)
10304236Smckusick 		return;
10314236Smckusick 	savname = thisname;
10324236Smckusick 	*pathp++ = '/';
10334236Smckusick 	savsize = filsize;
10344236Smckusick 	filsize = dp->di_size;
10354236Smckusick 	ckinode(dp, DATA);
10364236Smckusick 	thisname = savname;
10374236Smckusick 	*--pathp = 0;
10384236Smckusick 	filsize = savsize;
10394236Smckusick }
10404236Smckusick 
10415877Smckusic struct dirstuff {
10425877Smckusic 	int loc;
10435877Smckusic 	int blkno;
10445877Smckusic 	int blksiz;
10455877Smckusic };
10465877Smckusic 
10474236Smckusick dirscan(blk, nf)
10484715Smckusic 	daddr_t blk;
10494715Smckusic 	int nf;
10504236Smckusick {
10515877Smckusic 	register DIRECT *dp;
10525877Smckusic 	struct dirstuff dirp;
10536251Smckusick 	int blksiz, dsize, n;
10546251Smckusick 	char dbuf[DIRBLKSIZ];
10554236Smckusick 
10564236Smckusick 	if (outrange(blk)) {
10575325Smckusic 		filsize -= sblock.fs_bsize;
10584236Smckusick 		return (SKIP);
10594236Smckusick 	}
10605877Smckusic 	blksiz = nf * sblock.fs_fsize;
10615877Smckusic 	dirp.loc = 0;
10625877Smckusic 	dirp.blkno = blk;
10635877Smckusic 	dirp.blksiz = blksiz;
10645877Smckusic 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
10656251Smckusick 		dsize = dp->d_reclen;
10666251Smckusick 		copy(dp, dbuf, dsize);
10676251Smckusick 		if ((n = (*pfunc)(dbuf)) & ALTERD) {
10685877Smckusic 			if (getblk(&fileblk, blk, blksiz) != NULL) {
10696251Smckusick 				copy(dbuf, dp, dsize);
10704715Smckusic 				dirty(&fileblk);
10714236Smckusick 				sbdirty();
10724236Smckusick 			} else
10734236Smckusick 				n &= ~ALTERD;
10744236Smckusick 		}
10755877Smckusic 		if (n & STOP)
10764236Smckusick 			return (n);
10774236Smckusick 	}
10784236Smckusick 	return (filsize > 0 ? KEEPON : STOP);
10794236Smckusick }
10804236Smckusick 
10815877Smckusic /*
10825877Smckusic  * get next entry in a directory.
10835877Smckusic  */
10845877Smckusic DIRECT *
10855877Smckusic readdir(dirp)
10865877Smckusic 	register struct dirstuff *dirp;
10875877Smckusic {
10886251Smckusick 	register DIRECT *dp, *ndp;
10895877Smckusic 
10905877Smckusic 	if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) {
10915877Smckusic 		filsize -= dirp->blksiz - dirp->loc;
10925877Smckusic 		return NULL;
10935877Smckusic 	}
10945877Smckusic 	for (;;) {
10955877Smckusic 		if (filsize <= 0 || dirp->loc >= dirp->blksiz)
10965877Smckusic 			return NULL;
10975935Smckusic 		dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
10985935Smckusic 		dirp->loc += dp->d_reclen;
10995935Smckusic 		filsize -= dp->d_reclen;
11006251Smckusick 		ndp = (DIRECT *)(dirblk.b_buf + dirp->loc);
11016251Smckusick 		if (dirp->loc < dirp->blksiz &&
11026251Smckusick 		    (ndp->d_ino > imax || ndp->d_namlen > MAXNAMLEN ||
11036251Smckusick 		    ndp->d_reclen <= 0 ||
11046251Smckusick 		    ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ))) {
11056251Smckusick 			pwarn("DIRECTORY CORRUPTED");
11066251Smckusick 			if (preen)
11076251Smckusick 				printf(" (SALVAGED)\n");
11086251Smckusick 			else if (reply("SALVAGE") == 0) {
11096251Smckusick 				dirp->loc +=
11106251Smckusick 				    DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
11116251Smckusick 				filsize -= DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
11126251Smckusick 				return(dp);
11136251Smckusick 			}
11146251Smckusick 			dirp->loc -= dp->d_reclen;
11156251Smckusick 			filsize += dp->d_reclen;
11166251Smckusick 			dp->d_reclen = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
11176251Smckusick 			dirty(&fileblk);
11185877Smckusic 			continue;
11196251Smckusick 		}
11205935Smckusic 		return (dp);
11215877Smckusic 	}
11225877Smckusic }
11235877Smckusic 
11244236Smckusick direrr(s)
11254715Smckusic 	char *s;
11264236Smckusick {
11274236Smckusick 	register DINODE *dp;
11284236Smckusick 
11294236Smckusick 	pwarn("%s ", s);
11304236Smckusick 	pinode();
11314236Smckusick 	printf("\n");
11324236Smckusick 	if ((dp = ginode()) != NULL && ftypeok(dp))
11335877Smckusic 		pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname);
11344236Smckusick 	else
11354236Smckusick 		pfatal("NAME=%s", pathname);
11364236Smckusick 	return (reply("REMOVE"));
11374236Smckusick }
11384236Smckusick 
11394236Smckusick adjust(lcnt)
11404465Smckusic 	register short lcnt;
11414236Smckusick {
11424236Smckusick 	register DINODE *dp;
11434236Smckusick 
11444236Smckusick 	if ((dp = ginode()) == NULL)
11454236Smckusick 		return;
11464236Smckusick 	if (dp->di_nlink == lcnt) {
11474236Smckusick 		if (linkup() == 0)
11484236Smckusick 			clri("UNREF", 0);
11494236Smckusick 	}
11504236Smckusick 	else {
11514236Smckusick 		pwarn("LINK COUNT %s",
11525877Smckusic 			(lfdir==inum)?lfname:(DIRCT?"DIR":"FILE"));
11534236Smckusick 		pinode();
11544236Smckusick 		printf(" COUNT %d SHOULD BE %d",
11554236Smckusick 			dp->di_nlink, dp->di_nlink-lcnt);
11564236Smckusick 		if (preen) {
11574236Smckusick 			if (lcnt < 0) {
11584236Smckusick 				printf("\n");
11594236Smckusick 				preendie();
11604236Smckusick 			}
11614236Smckusick 			printf(" (ADJUSTED)\n");
11624236Smckusick 		}
11634236Smckusick 		if (preen || reply("ADJUST") == 1) {
11644236Smckusick 			dp->di_nlink -= lcnt;
11654236Smckusick 			inodirty();
11664236Smckusick 		}
11674236Smckusick 	}
11684236Smckusick }
11694236Smckusick 
11704236Smckusick clri(s, flg)
11714715Smckusic 	char *s;
11724236Smckusick {
11734236Smckusick 	register DINODE *dp;
11744236Smckusick 
11754236Smckusick 	if ((dp = ginode()) == NULL)
11764236Smckusick 		return;
11774236Smckusick 	if (flg == 1) {
11785877Smckusic 		pwarn("%s %s", s, DIRCT?"DIR":"FILE");
11794236Smckusick 		pinode();
11804236Smckusick 	}
11814236Smckusick 	if (preen || reply("CLEAR") == 1) {
11824236Smckusick 		if (preen)
11834236Smckusick 			printf(" (CLEARED)\n");
11844236Smckusick 		n_files--;
11854236Smckusick 		pfunc = pass4;
11864236Smckusick 		ckinode(dp, ADDR);
11874236Smckusick 		zapino(dp);
11884465Smckusic 		setstate(USTATE);
11894236Smckusick 		inodirty();
11904236Smckusick 		inosumbad++;
11914236Smckusick 	}
11924236Smckusick }
11934236Smckusick 
11944236Smckusick setup(dev)
11954715Smckusic 	char *dev;
11964236Smckusick {
11974236Smckusick 	dev_t rootdev;
11984878Smckusic 	struct ostat statb;
11994236Smckusick 	int super = bflag ? bflag : SBLOCK;
12004236Smckusick 
12014236Smckusick 	bflag = 0;
12024236Smckusick 	if (stat("/", &statb) < 0)
12034236Smckusick 		errexit("Can't stat root\n");
12044236Smckusick 	rootdev = statb.st_dev;
12054236Smckusick 	if (stat(dev, &statb) < 0) {
12064236Smckusick 		error("Can't stat %s\n", dev);
12074236Smckusick 		return (0);
12084236Smckusick 	}
12094236Smckusick 	rawflg = 0;
12104236Smckusick 	if ((statb.st_mode & S_IFMT) == S_IFBLK)
12114236Smckusick 		;
12124236Smckusick 	else if ((statb.st_mode & S_IFMT) == S_IFCHR)
12134236Smckusick 		rawflg++;
12144236Smckusick 	else {
12154236Smckusick 		if (reply("file is not a block or character device; OK") == 0)
12164236Smckusick 			return (0);
12174236Smckusick 	}
12184236Smckusick 	if (rootdev == statb.st_rdev)
12194236Smckusick 		hotroot++;
12204236Smckusick 	if ((dfile.rfdes = open(dev, 0)) < 0) {
12214236Smckusick 		error("Can't open %s\n", dev);
12224236Smckusick 		return (0);
12234236Smckusick 	}
12244236Smckusick 	if (preen == 0)
12254236Smckusick 		printf("** %s", dev);
12264236Smckusick 	if (nflag || (dfile.wfdes = open(dev, 1)) < 0) {
12274236Smckusick 		dfile.wfdes = -1;
12284236Smckusick 		if (preen)
12294236Smckusick 			pfatal("NO WRITE ACCESS");
12304236Smckusick 		printf(" (NO WRITE)");
12314236Smckusick 	}
12324236Smckusick 	if (preen == 0)
12334236Smckusick 		printf("\n");
12344465Smckusic 	fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0;
12354236Smckusick 	dfile.mod = 0;
12364236Smckusick 	n_files = n_blks = n_ffree = n_bfree = 0;
12374236Smckusick 	muldup = enddup = &duplist[0];
12384236Smckusick 	badlnp = &badlncnt[0];
12394236Smckusick 	lfdir = 0;
12404236Smckusick 	rplyflag = 0;
12414236Smckusick 	initbarea(&sblk);
12424236Smckusick 	initbarea(&fileblk);
12434236Smckusick 	initbarea(&inoblk);
12444236Smckusick 	initbarea(&cgblk);
12455347Smckusic 	if (bread(&dfile, &sblock, super, SBSIZE) == 0)
12464236Smckusick 		return (0);
12474465Smckusic 	sblk.b_bno = super;
12485347Smckusic 	sblk.b_size = SBSIZE;
12495363Smckusic 	/*
12505363Smckusic 	 * run a few consistency checks of the super block
12515363Smckusic 	 */
12524236Smckusick 	if (sblock.fs_magic != FS_MAGIC)
12534236Smckusick 		{ badsb("MAGIC NUMBER WRONG"); return (0); }
12544236Smckusick 	if (sblock.fs_ncg < 1)
12554236Smckusick 		{ badsb("NCG OUT OF RANGE"); return (0); }
12564236Smckusick 	if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
12574236Smckusick 		{ badsb("CPG OUT OF RANGE"); return (0); }
12584236Smckusick 	if (sblock.fs_nsect < 1)
12594236Smckusick 		{ badsb("NSECT < 1"); return (0); }
12604236Smckusick 	if (sblock.fs_ntrak < 1)
12614236Smckusick 		{ badsb("NTRAK < 1"); return (0); }
12625363Smckusic 	if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak)
12635363Smckusic 		{ badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); }
12645363Smckusic 	if (sblock.fs_ipg % INOPB(&sblock))
12655363Smckusic 		{ badsb("INODES NOT MULTIPLE OF A BLOCK"); return (0); }
12665381Smckusic 	if (cgdmin(&sblock, 0) >= sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
12674236Smckusick 		{ badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); return (0); }
12685363Smckusic 	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
12695363Smckusic 	    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
12704236Smckusick 		{ badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
12715325Smckusic 	if (sblock.fs_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
12724236Smckusick 		{ badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); }
12735363Smckusic 	if (sblock.fs_size * NSPF(&sblock) <=
12745363Smckusic 	    (sblock.fs_ncyl - 1) * sblock.fs_spc)
12754236Smckusick 		{ badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); }
12765363Smckusic 	if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc)
12774236Smckusick 		{ badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
12784236Smckusick 	/* rest we COULD repair... */
12794236Smckusick 	if (sblock.fs_sblkno != SBLOCK)
12805363Smckusic 		{ badsb("SBLKNO CORRUPTED"); return (0); }
12815363Smckusic 	if (sblock.fs_cblkno !=
12825363Smckusic 	    roundup(howmany(BBSIZE + SBSIZE, sblock.fs_fsize), sblock.fs_frag))
12835363Smckusic 		{ badsb("CBLKNO CORRUPTED"); return (0); }
12845363Smckusic 	if (sblock.fs_iblkno != sblock.fs_cblkno + sblock.fs_frag)
12855363Smckusic 		{ badsb("IBLKNO CORRUPTED"); return (0); }
12865363Smckusic 	if (sblock.fs_dblkno !=
12875363Smckusic 	    sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock))
12885363Smckusic 		{ badsb("DBLKNO CORRUPTED"); return (0); }
12895956Smckusic 	if (sblock.fs_cgsize != fragroundup(&sblock,
12905956Smckusic 	    sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY)))
12914236Smckusick 		{ badsb("CGSIZE INCORRECT"); return (0); }
12925325Smckusic 	if (sblock.fs_cssize != sblock.fs_ncg * sizeof(struct csum))
12934236Smckusick 		{ badsb("CSSIZE INCORRECT"); return (0); }
12944236Smckusick 	fmax = sblock.fs_size;
12954236Smckusick 	imax = sblock.fs_ncg * sblock.fs_ipg;
12965363Smckusic 	/*
12975363Smckusic 	 * allocate the necessary maps
12985363Smckusic 	 */
12994236Smckusick 	bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
13004236Smckusick 	blkmap = (char *)calloc(bmapsz, sizeof (char));
13014236Smckusick 	freemap = (char *)calloc(bmapsz, sizeof (char));
13024236Smckusick 	statemap = (char *)calloc(imax+1, sizeof(char));
13034236Smckusick 	lncntp = (short *)calloc(imax+1, sizeof(short));
13044236Smckusick 
13054465Smckusic 	startinum = imax + 1;
13064236Smckusick 	return (1);
13074236Smckusick 
13084236Smckusick badsb:
13094236Smckusick 	ckfini();
13104236Smckusick 	return (0);
13114236Smckusick }
13124236Smckusick 
13134236Smckusick badsb(s)
13144236Smckusick 	char *s;
13154236Smckusick {
13164236Smckusick 
13174236Smckusick 	if (preen)
13184236Smckusick 		printf("%s: ", devname);
13194236Smckusick 	printf("BAD SUPER BLOCK: %s\n", s);
13204236Smckusick 	pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
13214236Smckusick 	pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
13224236Smckusick }
13234236Smckusick 
13244236Smckusick DINODE *
13254236Smckusick ginode()
13264236Smckusick {
13274236Smckusick 	daddr_t iblk;
13284236Smckusick 
13295337Smckusic 	if (inum < ROOTINO || inum > imax)
13304236Smckusick 		return (NULL);
13315325Smckusic 	if (inum < startinum || inum >= startinum + INOPB(&sblock)) {
13325381Smckusic 		iblk = itod(&sblock, inum);
13335325Smckusic 		if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
13344236Smckusick 			return (NULL);
13354236Smckusick 		}
13365325Smckusic 		startinum = (inum / INOPB(&sblock)) * INOPB(&sblock);
13374236Smckusick 	}
13385325Smckusic 	return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]);
13394236Smckusick }
13404236Smckusick 
13414236Smckusick ftypeok(dp)
13424236Smckusick 	DINODE *dp;
13434236Smckusick {
13444236Smckusick 	switch (dp->di_mode & IFMT) {
13454236Smckusick 
13464236Smckusick 	case IFDIR:
13474236Smckusick 	case IFREG:
13484236Smckusick 	case IFBLK:
13494236Smckusick 	case IFCHR:
13506285Smckusick 	case IFLNK:
13514236Smckusick 		return (1);
13524236Smckusick 
13534236Smckusick 	default:
13544236Smckusick 		return (0);
13554236Smckusick 	}
13564236Smckusick }
13574236Smckusick 
13584236Smckusick reply(s)
13594236Smckusick 	char *s;
13604236Smckusick {
13614236Smckusick 	char line[80];
13624236Smckusick 
13634236Smckusick 	if (preen)
13644236Smckusick 		pfatal("INTERNAL ERROR: GOT TO reply()");
13654236Smckusick 	rplyflag = 1;
13664236Smckusick 	printf("\n%s? ", s);
13674236Smckusick 	if (nflag || dfile.wfdes < 0) {
13684236Smckusick 		printf(" no\n\n");
13694236Smckusick 		return (0);
13704236Smckusick 	}
13714236Smckusick 	if (yflag) {
13724236Smckusick 		printf(" yes\n\n");
13734236Smckusick 		return (1);
13744236Smckusick 	}
13754236Smckusick 	if (getline(stdin, line, sizeof(line)) == EOF)
13764236Smckusick 		errexit("\n");
13774236Smckusick 	printf("\n");
13784236Smckusick 	if (line[0] == 'y' || line[0] == 'Y')
13794236Smckusick 		return (1);
13804236Smckusick 	else
13814236Smckusick 		return (0);
13824236Smckusick }
13834236Smckusick 
13844236Smckusick getline(fp, loc, maxlen)
13854236Smckusick 	FILE *fp;
13864236Smckusick 	char *loc;
13874236Smckusick {
13884236Smckusick 	register n;
13894236Smckusick 	register char *p, *lastloc;
13904236Smckusick 
13914236Smckusick 	p = loc;
13924236Smckusick 	lastloc = &p[maxlen-1];
13934236Smckusick 	while ((n = getc(fp)) != '\n') {
13944236Smckusick 		if (n == EOF)
13954236Smckusick 			return (EOF);
13964236Smckusick 		if (!isspace(n) && p < lastloc)
13974236Smckusick 			*p++ = n;
13984236Smckusick 	}
13994236Smckusick 	*p = 0;
14004236Smckusick 	return (p - loc);
14014236Smckusick }
14024236Smckusick 
14034236Smckusick BUFAREA *
14044236Smckusick getblk(bp, blk, size)
14054236Smckusick 	daddr_t blk;
14064236Smckusick 	register BUFAREA *bp;
14074236Smckusick 	int size;
14084236Smckusick {
14094236Smckusick 	register struct filecntl *fcp;
14105325Smckusic 	daddr_t dblk;
14114236Smckusick 
14124236Smckusick 	fcp = &dfile;
14135325Smckusic 	dblk = fsbtodb(&sblock, blk);
14145325Smckusic 	if (bp->b_bno == dblk)
14154236Smckusick 		return (bp);
14164236Smckusick 	flush(fcp, bp);
14175325Smckusic 	if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
14185325Smckusic 		bp->b_bno = dblk;
14194236Smckusick 		bp->b_size = size;
14204236Smckusick 		return (bp);
14214236Smckusick 	}
14224236Smckusick 	bp->b_bno = (daddr_t)-1;
14234236Smckusick 	return (NULL);
14244236Smckusick }
14254236Smckusick 
14264236Smckusick flush(fcp, bp)
14274236Smckusick 	struct filecntl *fcp;
14284236Smckusick 	register BUFAREA *bp;
14294236Smckusick {
14304236Smckusick 
14314236Smckusick 	if (bp->b_dirty)
14324236Smckusick 		bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size);
14334236Smckusick 	bp->b_dirty = 0;
14344236Smckusick }
14354236Smckusick 
14364236Smckusick rwerr(s, blk)
14374236Smckusick 	char *s;
14384236Smckusick 	daddr_t blk;
14394236Smckusick {
14404236Smckusick 
14414236Smckusick 	if (preen == 0)
14424236Smckusick 		printf("\n");
14434236Smckusick 	pfatal("CANNOT %s: BLK %ld", s, blk);
14444236Smckusick 	if (reply("CONTINUE") == 0)
14454236Smckusick 		errexit("Program terminated\n");
14464236Smckusick }
14474236Smckusick 
14484236Smckusick ckfini()
14494236Smckusick {
14504236Smckusick 
14514236Smckusick 	flush(&dfile, &fileblk);
14524236Smckusick 	flush(&dfile, &sblk);
14534465Smckusic 	if (sblk.b_bno != SBLOCK) {
14544465Smckusic 		sblk.b_bno = SBLOCK;
14554465Smckusic 		sbdirty();
14564465Smckusic 		flush(&dfile, &sblk);
14574465Smckusic 	}
14584236Smckusick 	flush(&dfile, &inoblk);
14594236Smckusick 	close(dfile.rfdes);
14604236Smckusick 	close(dfile.wfdes);
14614236Smckusick }
14624236Smckusick 
14634236Smckusick pinode()
14644236Smckusick {
14654236Smckusick 	register DINODE *dp;
14664236Smckusick 	register char *p;
14675877Smckusic 	char uidbuf[BUFSIZ];
14684236Smckusick 	char *ctime();
14694236Smckusick 
14704236Smckusick 	printf(" I=%u ", inum);
14714236Smckusick 	if ((dp = ginode()) == NULL)
14724236Smckusick 		return;
14734236Smckusick 	printf(" OWNER=");
14744236Smckusick 	if (getpw((int)dp->di_uid, uidbuf) == 0) {
14754236Smckusick 		for (p = uidbuf; *p != ':'; p++);
14764236Smckusick 		*p = 0;
14774236Smckusick 		printf("%s ", uidbuf);
14784236Smckusick 	}
14794236Smckusick 	else {
14804236Smckusick 		printf("%d ", dp->di_uid);
14814236Smckusick 	}
14824236Smckusick 	printf("MODE=%o\n", dp->di_mode);
14834236Smckusick 	if (preen)
14844236Smckusick 		printf("%s: ", devname);
14854236Smckusick 	printf("SIZE=%ld ", dp->di_size);
14864236Smckusick 	p = ctime(&dp->di_mtime);
14874236Smckusick 	printf("MTIME=%12.12s %4.4s ", p+4, p+20);
14884236Smckusick }
14894236Smckusick 
14904236Smckusick copy(fp, tp, size)
14914236Smckusick 	register char *tp, *fp;
14924236Smckusick 	unsigned size;
14934236Smckusick {
14944236Smckusick 
14954236Smckusick 	while (size--)
14964236Smckusick 		*tp++ = *fp++;
14974236Smckusick }
14984236Smckusick 
14994236Smckusick makecg()
15004236Smckusick {
15014465Smckusic 	int c, blk;
15024236Smckusick 	daddr_t dbase, d, dmin, dmax;
15034236Smckusick 	long i, j, s;
15044236Smckusick 	register struct csum *cs;
15054465Smckusic 	register DINODE *dp;
15064236Smckusick 
15074789Smckusic 	sblock.fs_cstotal.cs_nbfree = 0;
15084789Smckusic 	sblock.fs_cstotal.cs_nffree = 0;
15094789Smckusic 	sblock.fs_cstotal.cs_nifree = 0;
15104789Smckusic 	sblock.fs_cstotal.cs_ndir = 0;
15115325Smckusic 	for (i = 0; i < howmany(sblock.fs_cssize, sblock.fs_bsize); i++) {
15125325Smckusic 		sblock.fs_csp[i] = (struct csum *)calloc(1, sblock.fs_bsize);
15135097Smckusic 		getblk((char *)sblock.fs_csp[i],
15145325Smckusic 		    sblock.fs_csaddr + (i * sblock.fs_frag), sblock.fs_bsize);
15155097Smckusic 	}
15164236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
15175381Smckusic 		dbase = cgbase(&sblock, c);
15184236Smckusick 		dmax = dbase + sblock.fs_fpg;
15195409Smckusic 		if (dmax > sblock.fs_size) {
15205944Smckusic 			for ( ; dmax >= sblock.fs_size; dmax--)
15215401Smckusic 				clrbit(cgrp.cg_free, dmax - dbase);
15225409Smckusic 			dmax++;
15235409Smckusic 		}
15245401Smckusic 		dmin = sblock.fs_dblkno;
15255325Smckusic 		cs = &sblock.fs_cs(&sblock, c);
15264236Smckusick 		cgrp.cg_time = time(0);
15274236Smckusick 		cgrp.cg_magic = CG_MAGIC;
15284236Smckusick 		cgrp.cg_cgx = c;
15294236Smckusick 		cgrp.cg_ncyl = sblock.fs_cpg;
15304236Smckusick 		cgrp.cg_niblk = sblock.fs_ipg;
15314236Smckusick 		cgrp.cg_ndblk = dmax - dbase;
15324789Smckusic 		cgrp.cg_cs.cs_ndir = 0;
15334789Smckusic 		cgrp.cg_cs.cs_nffree = 0;
15344789Smckusic 		cgrp.cg_cs.cs_nbfree = 0;
15354789Smckusic 		cgrp.cg_cs.cs_nifree = 0;
15364465Smckusic 		cgrp.cg_rotor = dmin;
15374465Smckusic 		cgrp.cg_frotor = dmin;
15384258Smckusic 		cgrp.cg_irotor = 0;
15395325Smckusic 		for (i = 0; i < sblock.fs_frag; i++)
15404465Smckusic 			cgrp.cg_frsum[i] = 0;
15414236Smckusick 		inum = sblock.fs_ipg * c;
15424465Smckusic 		for (i = 0; i < sblock.fs_ipg; inum++, i++) {
15435944Smckusic 			cgrp.cg_cs.cs_nifree++;
15445944Smckusic 			clrbit(cgrp.cg_iused, i);
15454465Smckusic 			dp = ginode();
15464465Smckusic 			if (dp == NULL)
15474465Smckusic 				continue;
15484465Smckusic 			if (ALLOC) {
15495877Smckusic 				if (DIRCT)
15504789Smckusic 					cgrp.cg_cs.cs_ndir++;
15515944Smckusic 				cgrp.cg_cs.cs_nifree--;
15524465Smckusic 				setbit(cgrp.cg_iused, i);
15534465Smckusic 				continue;
15544465Smckusic 			}
15554236Smckusick 		}
15564236Smckusick 		while (i < MAXIPG) {
15574236Smckusick 			clrbit(cgrp.cg_iused, i);
15584236Smckusick 			i++;
15594236Smckusick 		}
15605944Smckusic 		if (c == 0)
15615944Smckusic 			for (i = 0; i < ROOTINO; i++) {
15625944Smckusic 				setbit(cgrp.cg_iused, i);
15635944Smckusic 				cgrp.cg_cs.cs_nifree--;
15645944Smckusic 			}
15655371Smckusic 		for (s = 0; s < MAXCPG; s++) {
15665371Smckusic 			cgrp.cg_btot[s] = 0;
15674236Smckusick 			for (i = 0; i < NRPOS; i++)
15684236Smckusick 				cgrp.cg_b[s][i] = 0;
15695371Smckusic 		}
15704236Smckusick 		if (c == 0) {
15715944Smckusic 			dmin += howmany(sblock.fs_cssize, sblock.fs_bsize) *
15725944Smckusic 			    sblock.fs_frag;
15734236Smckusick 		}
15744236Smckusick 		for (d = 0; d < dmin; d++)
15754236Smckusick 			clrbit(cgrp.cg_free, d);
15765325Smckusic 		for (; (d + sblock.fs_frag) <= dmax - dbase; d += sblock.fs_frag) {
15774236Smckusick 			j = 0;
15785325Smckusic 			for (i = 0; i < sblock.fs_frag; i++) {
15794236Smckusick 				if (!getbmap(dbase+d+i)) {
15804236Smckusick 					setbit(cgrp.cg_free, d+i);
15814236Smckusick 					j++;
15824236Smckusick 				} else
15834236Smckusick 					clrbit(cgrp.cg_free, d+i);
15844236Smckusick 			}
15855325Smckusic 			if (j == sblock.fs_frag) {
15864789Smckusic 				cgrp.cg_cs.cs_nbfree++;
15875371Smckusic 				cgrp.cg_btot[cbtocylno(&sblock, d)]++;
15885363Smckusic 				cgrp.cg_b[cbtocylno(&sblock, d)]
15895363Smckusic 				    [cbtorpos(&sblock, d)]++;
15904465Smckusic 			} else if (j > 0) {
15914789Smckusic 				cgrp.cg_cs.cs_nffree += j;
15924465Smckusic 				blk = ((cgrp.cg_free[d / NBBY] >> (d % NBBY)) &
15935325Smckusic 				       (0xff >> (NBBY - sblock.fs_frag)));
15945325Smckusic 				fragacct(&sblock, blk, cgrp.cg_frsum, 1);
15954465Smckusic 			}
15964236Smckusick 		}
15974465Smckusic 		for (j = d; d < dmax - dbase; d++) {
15984236Smckusick 			if (!getbmap(dbase+d)) {
15994236Smckusick 				setbit(cgrp.cg_free, d);
16004789Smckusic 				cgrp.cg_cs.cs_nffree++;
16014236Smckusick 			} else
16024236Smckusick 				clrbit(cgrp.cg_free, d);
16034236Smckusick 		}
16044465Smckusic 		if (j != d) {
16054465Smckusic 			blk = ((cgrp.cg_free[j / NBBY] >> (j % NBBY)) &
16065325Smckusic 			       (0xff >> (NBBY - sblock.fs_frag)));
16075325Smckusic 			fragacct(&sblock, blk, cgrp.cg_frsum, 1);
16084465Smckusic 		}
16095325Smckusic 		for (; d < MAXBPG(&sblock); d++)
16104236Smckusick 			clrbit(cgrp.cg_free, d);
16114789Smckusic 		sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree;
16124789Smckusic 		sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree;
16134789Smckusic 		sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
16144789Smckusic 		sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
16154789Smckusic 		*cs = cgrp.cg_cs;
16165381Smckusic 		bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)),
16175956Smckusic 		    sblock.fs_cgsize);
16184236Smckusick 	}
16195325Smckusic 	for (i = 0; i < howmany(sblock.fs_cssize, sblock.fs_bsize); i++) {
16205097Smckusic 		bwrite(&dfile, (char *)sblock.fs_csp[i],
16215325Smckusic 		    fsbtodb(&sblock, sblock.fs_csaddr + (i * sblock.fs_frag)),
16225325Smckusic 		    sblock.fs_bsize);
16235097Smckusic 	}
16244236Smckusick 	sblock.fs_ronly = 0;
16254236Smckusick 	sblock.fs_fmod = 0;
16264236Smckusick 	sbdirty();
16274236Smckusick }
16284236Smckusick 
16294465Smckusic /*
16304465Smckusic  * update the frsum fields to reflect addition or deletion
16314465Smckusic  * of some frags
16324465Smckusic  */
16335325Smckusic fragacct(fs, fragmap, fraglist, cnt)
16345325Smckusic 	struct fs *fs;
16354470Smckusic 	int fragmap;
16364789Smckusic 	long fraglist[];
16374465Smckusic 	int cnt;
16384465Smckusic {
16394465Smckusic 	int inblk;
16404465Smckusic 	register int field, subfield;
16414465Smckusic 	register int siz, pos;
16424465Smckusic 
16435325Smckusic 	inblk = (int)(fragtbl[fs->fs_frag][fragmap] << 1);
16444465Smckusic 	fragmap <<= 1;
16455325Smckusic 	for (siz = 1; siz < fs->fs_frag; siz++) {
1646*6290Smckusick 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
16474465Smckusic 			continue;
16484465Smckusic 		field = around[siz];
16494465Smckusic 		subfield = inside[siz];
16505325Smckusic 		for (pos = siz; pos <= fs->fs_frag; pos++) {
16514465Smckusic 			if ((fragmap & field) == subfield) {
16524465Smckusic 				fraglist[siz] += cnt;
16534465Smckusic 				pos += siz;
16544465Smckusic 				field <<= siz;
16554465Smckusic 				subfield <<= siz;
16564465Smckusic 			}
16574465Smckusic 			field <<= 1;
16584465Smckusic 			subfield <<= 1;
16594465Smckusic 		}
16604465Smckusic 	}
16614465Smckusic }
16624465Smckusic 
16634236Smckusick findino(dirp)
16644236Smckusick 	register DIRECT *dirp;
16654236Smckusick {
16664236Smckusick 	if (dirp->d_ino == 0)
16674236Smckusick 		return (KEEPON);
16685877Smckusic 	if (!strcmp(dirp->d_name, srchname)) {
16695877Smckusic 		if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
16705877Smckusic 			parentdir = dirp->d_ino;
16715877Smckusic 		return (STOP);
16724236Smckusick 	}
16734236Smckusick 	return (KEEPON);
16744236Smckusick }
16754236Smckusick 
16764236Smckusick mkentry(dirp)
16774236Smckusick 	register DIRECT *dirp;
16784236Smckusick {
16794236Smckusick 	register ino_t in;
16804236Smckusick 	register char *p;
16816251Smckusick 	DIRECT newent;
16826251Smckusick 	int newlen, oldlen;
16834236Smckusick 
16846251Smckusick 	newent.d_namlen = 11;
16856251Smckusick 	newlen = DIRSIZ(&newent);
16866251Smckusick 	if (dirp->d_ino != 0)
16876251Smckusick 		oldlen = DIRSIZ(dirp);
16886251Smckusick 	else
16896251Smckusick 		oldlen = 0;
16906251Smckusick 	if (dirp->d_reclen - oldlen < newlen)
16914236Smckusick 		return (KEEPON);
16926251Smckusick 	newent.d_reclen = dirp->d_reclen - oldlen;
16936251Smckusick 	dirp->d_reclen = oldlen;
16946251Smckusick 	dirp = (struct direct *)(((char *)dirp) + oldlen);
16954236Smckusick 	dirp->d_ino = orphan;
16966251Smckusick 	dirp->d_reclen = newent.d_reclen;
16976251Smckusick 	p = &dirp->d_name[2];
16986251Smckusick 	for (in = imax; in > 0; in /= 10)
16996251Smckusick 		p++;
17006251Smckusick 	*--p = 0;
17016251Smckusick 	dirp->d_namlen = p - dirp->d_name;
17024236Smckusick 	in = orphan;
17034236Smckusick 	while (p > dirp->d_name) {
17044236Smckusick 		*--p = (in % 10) + '0';
17054236Smckusick 		in /= 10;
17064236Smckusick 	}
17074236Smckusick 	*p = '#';
17084236Smckusick 	return (ALTERD|STOP);
17094236Smckusick }
17104236Smckusick 
17114236Smckusick chgdd(dirp)
17124236Smckusick 	register DIRECT *dirp;
17134236Smckusick {
17144236Smckusick 	if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
17154236Smckusick 	dirp->d_name[2] == 0) {
17164236Smckusick 		dirp->d_ino = lfdir;
17174236Smckusick 		return (ALTERD|STOP);
17184236Smckusick 	}
17194236Smckusick 	return (KEEPON);
17204236Smckusick }
17214236Smckusick 
17224236Smckusick linkup()
17234236Smckusick {
17244236Smckusick 	register DINODE *dp;
17254236Smckusick 	register lostdir;
17264236Smckusick 	register ino_t pdir;
17274236Smckusick 
17284236Smckusick 	if ((dp = ginode()) == NULL)
17294236Smckusick 		return (0);
17305877Smckusic 	lostdir = DIRCT;
17314236Smckusick 	pdir = parentdir;
17324236Smckusick 	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
17334236Smckusick 	pinode();
17344236Smckusick 	if (preen && dp->di_size == 0)
17354236Smckusick 		return (0);
17364236Smckusick 	if (preen)
17374236Smckusick 		printf(" (RECONNECTED)\n");
17384236Smckusick 	else
17394236Smckusick 		if (reply("RECONNECT") == 0)
17404236Smckusick 			return (0);
17414236Smckusick 	orphan = inum;
17424236Smckusick 	if (lfdir == 0) {
17434236Smckusick 		inum = ROOTINO;
17444236Smckusick 		if ((dp = ginode()) == NULL) {
17454236Smckusick 			inum = orphan;
17464236Smckusick 			return (0);
17474236Smckusick 		}
17484236Smckusick 		pfunc = findino;
17494236Smckusick 		srchname = lfname;
17504236Smckusick 		filsize = dp->di_size;
17514236Smckusick 		parentdir = 0;
17524236Smckusick 		ckinode(dp, DATA);
17534236Smckusick 		inum = orphan;
17544236Smckusick 		if ((lfdir = parentdir) == 0) {
17554236Smckusick 			pfatal("SORRY. NO lost+found DIRECTORY");
17564236Smckusick 			printf("\n\n");
17574236Smckusick 			return (0);
17584236Smckusick 		}
17594236Smckusick 	}
17604236Smckusick 	inum = lfdir;
17615877Smckusic 	if ((dp = ginode()) == NULL || !DIRCT || getstate() != FSTATE) {
17624236Smckusick 		inum = orphan;
17634236Smckusick 		pfatal("SORRY. NO lost+found DIRECTORY");
17644236Smckusick 		printf("\n\n");
17654236Smckusick 		return (0);
17664236Smckusick 	}
17675956Smckusic 	if (fragoff(&sblock, dp->di_size)) {
17685956Smckusic 		dp->di_size = fragroundup(&sblock, dp->di_size);
17694236Smckusick 		inodirty();
17704236Smckusick 	}
17714236Smckusick 	filsize = dp->di_size;
17724236Smckusick 	inum = orphan;
17734236Smckusick 	pfunc = mkentry;
17744236Smckusick 	if ((ckinode(dp, DATA) & ALTERD) == 0) {
17754236Smckusick 		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
17764236Smckusick 		printf("\n\n");
17774236Smckusick 		return (0);
17784236Smckusick 	}
17794236Smckusick 	declncnt();
17804236Smckusick 	if (lostdir) {
17814236Smckusick 		pfunc = chgdd;
17824236Smckusick 		dp = ginode();
17834236Smckusick 		filsize = dp->di_size;
17844236Smckusick 		ckinode(dp, DATA);
17854236Smckusick 		inum = lfdir;
17864236Smckusick 		if ((dp = ginode()) != NULL) {
17874236Smckusick 			dp->di_nlink++;
17884236Smckusick 			inodirty();
17894236Smckusick 			setlncnt(getlncnt()+1);
17904236Smckusick 		}
17914236Smckusick 		inum = orphan;
17924236Smckusick 		pwarn("DIR I=%u CONNECTED. ", orphan);
17934236Smckusick 		printf("PARENT WAS I=%u\n", pdir);
17944236Smckusick 		if (preen == 0)
17954236Smckusick 			printf("\n");
17964236Smckusick 	}
17974236Smckusick 	return (1);
17984236Smckusick }
17994236Smckusick 
18004236Smckusick bread(fcp, buf, blk, size)
18014236Smckusick 	daddr_t blk;
18024236Smckusick 	register struct filecntl *fcp;
18034236Smckusick 	register size;
18044236Smckusick 	char *buf;
18054236Smckusick {
18065325Smckusic 	if (lseek(fcp->rfdes, blk * DEV_BSIZE, 0) < 0)
18074236Smckusick 		rwerr("SEEK", blk);
18084236Smckusick 	else if (read(fcp->rfdes, buf, size) == size)
18094236Smckusick 		return (1);
18104236Smckusick 	rwerr("READ", blk);
18114236Smckusick 	return (0);
18124236Smckusick }
18134236Smckusick 
18144236Smckusick bwrite(fcp, buf, blk, size)
18154236Smckusick 	daddr_t blk;
18164236Smckusick 	register struct filecntl *fcp;
18174236Smckusick 	register size;
18184236Smckusick 	char *buf;
18194236Smckusick {
18204236Smckusick 
18214236Smckusick 	if (fcp->wfdes < 0)
18224236Smckusick 		return (0);
18235325Smckusic 	if (lseek(fcp->wfdes, blk * DEV_BSIZE, 0) < 0)
18244236Smckusick 		rwerr("SEEK", blk);
18254236Smckusick 	else if (write(fcp->wfdes, buf, size) == size) {
18264236Smckusick 		fcp->mod = 1;
18274236Smckusick 		return (1);
18284236Smckusick 	}
18294236Smckusick 	rwerr("WRITE", blk);
18304236Smckusick 	return (0);
18314236Smckusick }
18324236Smckusick 
18334236Smckusick catch()
18344236Smckusick {
18354236Smckusick 
18364236Smckusick 	ckfini();
18374236Smckusick 	exit(12);
18384236Smckusick }
18395325Smckusic 
18405325Smckusic /*
18415325Smckusic  * block operations
18425325Smckusic  */
18435325Smckusic 
18445325Smckusic isblock(fs, cp, h)
18455325Smckusic 	struct fs *fs;
18465325Smckusic 	unsigned char *cp;
18475325Smckusic 	int h;
18485325Smckusic {
18495325Smckusic 	unsigned char mask;
18505325Smckusic 
18515325Smckusic 	switch (fs->fs_frag) {
18525325Smckusic 	case 8:
18535325Smckusic 		return (cp[h] == 0xff);
18545325Smckusic 	case 4:
18555325Smckusic 		mask = 0x0f << ((h & 0x1) << 2);
18565325Smckusic 		return ((cp[h >> 1] & mask) == mask);
18575325Smckusic 	case 2:
18585325Smckusic 		mask = 0x03 << ((h & 0x3) << 1);
18595325Smckusic 		return ((cp[h >> 2] & mask) == mask);
18605325Smckusic 	case 1:
18615325Smckusic 		mask = 0x01 << (h & 0x7);
18625325Smckusic 		return ((cp[h >> 3] & mask) == mask);
18635325Smckusic 	default:
18645381Smckusic 		error("isblock bad fs_frag %d\n", fs->fs_frag);
18655381Smckusic 		return (0);
18665325Smckusic 	}
18675325Smckusic }
1868