xref: /csrg-svn/sbin/fsck/main.c (revision 6491)
1*6491Smckusick static	char *sccsid = "@(#)main.c	2.2 (Berkeley) 04/08/82";
24428Smckusic 
34236Smckusick #include <stdio.h>
44236Smckusick #include <ctype.h>
56489Smckusick #ifndef SIMFS
66489Smckusick #include <sys/param.h>
76489Smckusick #include <sys/fs.h>
86489Smckusick #include <sys/inode.h>
96489Smckusick #include <ndir.h>
106489Smckusick #else
114236Smckusick #include "../h/param.h"
124236Smckusick #include "../h/fs.h"
134236Smckusick #include "../h/inode.h"
146489Smckusick #include "../h/ndir.h"
156489Smckusick #endif
166489Smckusick #include <sys/stat.h>
174236Smckusick #include <fstab.h>
184236Smckusick 
194236Smckusick typedef	int	(*SIG_TYP)();
204236Smckusick 
215347Smckusic #define	MAXNINDIR	(MAXBSIZE / sizeof (daddr_t))
225347Smckusic #define	MAXINOPB	(MAXBSIZE / sizeof (struct dinode))
235325Smckusic #define	SPERB		(MAXBSIZE / sizeof(short))
244236Smckusick 
254236Smckusick #define	MAXDUP	10		/* limit on dup blks (per inode) */
264236Smckusick #define	MAXBAD	10		/* limit on bad blks (per inode) */
274236Smckusick 
284236Smckusick #define	USTATE	0		/* inode not allocated */
294236Smckusick #define	FSTATE	01		/* inode is file */
304236Smckusick #define	DSTATE	02		/* inode is directory */
314236Smckusick #define	CLEAR	03		/* inode is to be cleared */
324236Smckusick 
334236Smckusick typedef struct dinode	DINODE;
344236Smckusick typedef struct direct	DIRECT;
354236Smckusick 
364236Smckusick #define	ALLOC	((dp->di_mode & IFMT) != 0)
375877Smckusic #define	DIRCT	((dp->di_mode & IFMT) == IFDIR)
384236Smckusick #define	REG	((dp->di_mode & IFMT) == IFREG)
394236Smckusick #define	BLK	((dp->di_mode & IFMT) == IFBLK)
404236Smckusick #define	CHR	((dp->di_mode & IFMT) == IFCHR)
416285Smckusick #define	SPECIAL	(BLK || CHR)
424236Smckusick 
434465Smckusic ino_t	startinum;		/* blk num of first in raw area */
444236Smckusick 
454236Smckusick struct bufarea {
464236Smckusick 	struct bufarea	*b_next;		/* must be first */
474236Smckusick 	daddr_t	b_bno;
484236Smckusick 	int	b_size;
494236Smckusick 	union {
505325Smckusic 		char	b_buf[MAXBSIZE];	/* buffer space */
514236Smckusick 		short	b_lnks[SPERB];		/* link counts */
525325Smckusic 		daddr_t	b_indir[MAXNINDIR];	/* indirect block */
534236Smckusick 		struct	fs b_fs;		/* super block */
544236Smckusick 		struct	cg b_cg;		/* cylinder group */
555325Smckusic 		struct dinode b_dinode[MAXINOPB]; /* inode block */
564236Smckusick 	} b_un;
574236Smckusick 	char	b_dirty;
584236Smckusick };
594236Smckusick 
604236Smckusick typedef struct bufarea BUFAREA;
614236Smckusick 
624236Smckusick BUFAREA	inoblk;			/* inode blocks */
634236Smckusick BUFAREA	fileblk;		/* other blks in filesys */
644236Smckusick BUFAREA	sblk;			/* file system superblock */
654236Smckusick BUFAREA	cgblk;
664236Smckusick 
674236Smckusick #define	initbarea(x)	(x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
684236Smckusick #define	dirty(x)	(x)->b_dirty = 1
694236Smckusick #define	inodirty()	inoblk.b_dirty = 1
704236Smckusick #define	sbdirty()	sblk.b_dirty = 1
714236Smckusick #define	cgdirty()	cgblk.b_dirty = 1
724236Smckusick 
734236Smckusick #define	dirblk		fileblk.b_un
744236Smckusick #define	sblock		sblk.b_un.b_fs
754236Smckusick #define	cgrp		cgblk.b_un.b_cg
764236Smckusick 
774236Smckusick struct filecntl {
784236Smckusick 	int	rfdes;
794236Smckusick 	int	wfdes;
804236Smckusick 	int	mod;
814236Smckusick } dfile;			/* file descriptors for filesys */
824236Smckusick 
834236Smckusick #define	DUPTBLSIZE	100	/* num of dup blocks to remember */
844236Smckusick daddr_t	duplist[DUPTBLSIZE];	/* dup block table */
854236Smckusick daddr_t	*enddup;		/* next entry in dup table */
864236Smckusick daddr_t	*muldup;		/* multiple dups part of table */
874236Smckusick 
884236Smckusick #define	MAXLNCNT	20	/* num zero link cnts to remember */
894236Smckusick ino_t	badlncnt[MAXLNCNT];	/* table of inos with zero link cnts */
904236Smckusick ino_t	*badlnp;		/* next entry in table */
914236Smckusick 
924236Smckusick char	rawflg;
934236Smckusick char	nflag;			/* assume a no response */
944236Smckusick char	yflag;			/* assume a yes response */
954236Smckusick int	bflag;			/* location of alternate super block */
965381Smckusic int	debug;			/* output debugging info */
974236Smckusick char	preen;			/* just fix normal inconsistencies */
984236Smckusick char	rplyflag;		/* any questions asked? */
994236Smckusick char	hotroot;		/* checking root device */
1004236Smckusick char	fixcg;			/* corrupted free list bit maps */
1014236Smckusick 
1026314Smckusick char	*blockmap;		/* ptr to primary blk allocation map */
1034236Smckusick char	*freemap;		/* ptr to secondary blk allocation map */
1044236Smckusick char	*statemap;		/* ptr to inode state table */
1054236Smckusick short	*lncntp;		/* ptr to link count table */
1064236Smckusick 
1074236Smckusick char	*pathp;			/* pointer to pathname position */
1084236Smckusick char	*thisname;		/* ptr to current pathname component */
1094236Smckusick char	*srchname;		/* name being searched for in dir */
1105877Smckusic char	pathname[BUFSIZ];
1114236Smckusick 
1124236Smckusick char	*lfname = "lost+found";
1134236Smckusick 
1144236Smckusick ino_t	inum;			/* inode we are currently working on */
1154236Smckusick ino_t	imax;			/* number of inodes */
1164236Smckusick ino_t	parentdir;		/* i number of parent directory */
1174236Smckusick ino_t	lastino;		/* hiwater mark of inodes */
1184236Smckusick ino_t	lfdir;			/* lost & found directory */
1194236Smckusick ino_t	orphan;			/* orphaned inode */
1204236Smckusick 
1214236Smckusick off_t	filsize;		/* num blks seen in file */
1224236Smckusick off_t	maxblk;			/* largest logical blk in file */
1236314Smckusick off_t	bmapsz;			/* num chars in blockmap */
1244236Smckusick 
1254236Smckusick daddr_t	n_ffree;		/* number of small free blocks */
1264236Smckusick daddr_t	n_bfree;		/* number of large free blocks */
1274236Smckusick daddr_t	n_blks;			/* number of blocks used */
1284236Smckusick daddr_t	n_files;		/* number of files seen */
1294236Smckusick daddr_t	n_index;
1304236Smckusick daddr_t	n_bad;
1314236Smckusick daddr_t	fmax;			/* number of blocks in the volume */
1324236Smckusick 
1334236Smckusick daddr_t	badblk;
1344236Smckusick daddr_t	dupblk;
1354236Smckusick 
1364236Smckusick int	inosumbad;
1374236Smckusick int	offsumbad;
1384465Smckusic int	frsumbad;
139*6491Smckusick int	sbsumbad;
1404236Smckusick 
1414236Smckusick #define	zapino(x)	(*(x) = zino)
1424236Smckusick struct	dinode zino;
1434236Smckusick 
1444236Smckusick #define	setlncnt(x)	(lncntp[inum] = x)
1454236Smckusick #define	getlncnt()	(lncntp[inum])
1464236Smckusick #define	declncnt()	(--lncntp[inum])
1474236Smckusick 
1486314Smckusick #define	setbmap(x)	setbit(blockmap, x)
1496314Smckusick #define	getbmap(x)	isset(blockmap, x)
1506314Smckusick #define	clrbmap(x)	clrbit(blockmap, x)
1514236Smckusick 
1524236Smckusick #define	setfmap(x)	setbit(freemap, x)
1534236Smckusick #define	getfmap(x)	isset(freemap, x)
1544236Smckusick #define	clrfmap(x)	clrbit(freemap, x)
1554236Smckusick 
1564236Smckusick #define	setstate(x)	(statemap[inum] = x)
1574236Smckusick #define	getstate()	statemap[inum]
1584236Smckusick 
1594236Smckusick #define	DATA	1
1604236Smckusick #define	ADDR	0
1614236Smckusick 
1624236Smckusick #define	ALTERD	010
1634236Smckusick #define	KEEPON	04
1644236Smckusick #define	SKIP	02
1654236Smckusick #define	STOP	01
1664236Smckusick 
1674236Smckusick int	(*signal())();
1684236Smckusick long	lseek();
1694236Smckusick time_t	time();
1704236Smckusick DINODE	*ginode();
1714236Smckusick BUFAREA	*getblk();
1724236Smckusick int	dirscan();
1734236Smckusick int	findino();
1744236Smckusick int	catch();
1754236Smckusick int	mkentry();
1764236Smckusick int	chgdd();
1774236Smckusick int	pass1(), pass1b(), pass2(), pass4(), pass5();
1784236Smckusick int	(*pfunc)();
1794236Smckusick char	*rawname(), *rindex(), *unrawname();
1804606Smckusic extern int inside[], around[];
1815325Smckusic extern unsigned char *fragtbl[];
1824236Smckusick 
1834236Smckusick char	*devname;
1844236Smckusick 
1854236Smckusick main(argc, argv)
1864715Smckusic 	int	argc;
1874715Smckusic 	char	*argv[];
1884236Smckusick {
1894236Smckusick 	struct fstab *fsp;
1904236Smckusick 	int pid, passno, anygtr, sumstatus;
1914236Smckusick 
1924236Smckusick 	sync();
1934236Smckusick 	while (--argc > 0 && **++argv == '-') {
1944236Smckusick 		switch (*++*argv) {
1954236Smckusick 
1964236Smckusick 		case 'p':
1974236Smckusick 			preen++;
1984236Smckusick 			break;
1994236Smckusick 
2004236Smckusick 		case 'b':
2014236Smckusick 			bflag = atoi(argv[0]+1);
2024236Smckusick 			printf("Alternate super block location: %d\n", bflag);
2034236Smckusick 			break;
2044236Smckusick 
2055381Smckusic 		case 'd':
2065381Smckusic 			debug++;
2075381Smckusic 			break;
2085381Smckusic 
2094236Smckusick 		case 'n':	/* default no answer flag */
2104236Smckusick 		case 'N':
2114236Smckusick 			nflag++;
2124236Smckusick 			yflag = 0;
2134236Smckusick 			break;
2144236Smckusick 
2154236Smckusick 		case 'y':	/* default yes answer flag */
2164236Smckusick 		case 'Y':
2174236Smckusick 			yflag++;
2184236Smckusick 			nflag = 0;
2194236Smckusick 			break;
2204236Smckusick 
2214236Smckusick 		default:
2224236Smckusick 			errexit("%c option?\n", **argv);
2234236Smckusick 		}
2244236Smckusick 	}
2254236Smckusick 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
2264236Smckusick 		signal(SIGINT, catch);
2274236Smckusick 	if (argc) {
2284236Smckusick 		while (argc-- > 0) {
2294236Smckusick 			hotroot = 0;
2304236Smckusick 			check(*argv++);
2314236Smckusick 		}
2324236Smckusick 		exit(0);
2334236Smckusick 	}
2344236Smckusick 	sumstatus = 0;
2354236Smckusick 	passno = 1;
2364236Smckusick 	do {
2374236Smckusick 		anygtr = 0;
2384236Smckusick 		if (setfsent() == 0)
2394236Smckusick 			errexit("Can't open checklist file: %s\n", FSTAB);
2404236Smckusick 		while ((fsp = getfsent()) != 0) {
2414236Smckusick 			if (strcmp(fsp->fs_type, FSTAB_RW) &&
2424236Smckusick 			    strcmp(fsp->fs_type, FSTAB_RO))
2434236Smckusick 				continue;
2444236Smckusick 			if (preen == 0 ||
2454236Smckusick 			    passno == 1 && fsp->fs_passno == passno) {
2464236Smckusick 				if (blockcheck(fsp->fs_spec) == 0 && preen)
2474236Smckusick 					exit(8);
2484236Smckusick 			} else if (fsp->fs_passno > passno)
2494236Smckusick 				anygtr = 1;
2504236Smckusick 			else if (fsp->fs_passno == passno) {
2514236Smckusick 				pid = fork();
2524236Smckusick 				if (pid < 0) {
2534236Smckusick 					perror("fork");
2544236Smckusick 					exit(8);
2554236Smckusick 				}
2564236Smckusick 				if (pid == 0)
2574236Smckusick 					if (blockcheck(fsp->fs_spec)==0)
2584236Smckusick 						exit(8);
2594236Smckusick 					else
2604236Smckusick 						exit(0);
2614236Smckusick 			}
2624236Smckusick 		}
2634236Smckusick 		if (preen) {
2644236Smckusick 			int status;
2654236Smckusick 			while (wait(&status) != -1)
2664236Smckusick 				sumstatus |= status;
2674236Smckusick 		}
2684236Smckusick 		passno++;
2694236Smckusick 	} while (anygtr);
2704236Smckusick 	if (sumstatus)
2714236Smckusick 		exit(8);
2724236Smckusick 	endfsent();
2734236Smckusick 	exit(0);
2744236Smckusick }
2754236Smckusick 
2764236Smckusick blockcheck(name)
2774236Smckusick 	char *name;
2784236Smckusick {
2796489Smckusick 	struct stat stslash, stblock, stchar;
2804236Smckusick 	char *raw;
2814236Smckusick 	int looped = 0;
2824236Smckusick 
2834236Smckusick 	hotroot = 0;
2844236Smckusick 	if (stat("/", &stslash) < 0){
2854236Smckusick 		error("Can't stat root\n");
2864236Smckusick 		return (0);
2874236Smckusick 	}
2884236Smckusick retry:
2894236Smckusick 	if (stat(name, &stblock) < 0){
2904236Smckusick 		error("Can't stat %s\n", name);
2914236Smckusick 		return (0);
2924236Smckusick 	}
2934236Smckusick 	if (stblock.st_mode & S_IFBLK) {
2944236Smckusick 		raw = rawname(name);
2954236Smckusick 		if (stat(raw, &stchar) < 0){
2964236Smckusick 			error("Can't stat %s\n", raw);
2974236Smckusick 			return (0);
2984236Smckusick 		}
2994236Smckusick 		if (stchar.st_mode & S_IFCHR) {
3004236Smckusick 			if (stslash.st_dev == stblock.st_rdev) {
3014236Smckusick 				hotroot++;
3024236Smckusick 				raw = unrawname(name);
3034236Smckusick 			}
3044236Smckusick 			check(raw);
3054236Smckusick 			return (1);
3064236Smckusick 		} else {
3074236Smckusick 			error("%s is not a character device\n", raw);
3084236Smckusick 			return (0);
3094236Smckusick 		}
3104236Smckusick 	} else if (stblock.st_mode & S_IFCHR) {
3114236Smckusick 		if (looped) {
3124236Smckusick 			error("Can't make sense out of name %s\n", name);
3134236Smckusick 			return (0);
3144236Smckusick 		}
3154236Smckusick 		name = unrawname(name);
3164236Smckusick 		looped++;
3174236Smckusick 		goto retry;
3184236Smckusick 	}
3194236Smckusick 	error("Can't make sense out of name %s\n", name);
3204236Smckusick 	return (0);
3214236Smckusick }
3224236Smckusick 
3234236Smckusick char *
3244236Smckusick unrawname(cp)
3254236Smckusick 	char *cp;
3264236Smckusick {
3274236Smckusick 	char *dp = rindex(cp, '/');
3286489Smckusick 	struct stat stb;
3294236Smckusick 
3304236Smckusick 	if (dp == 0)
3314236Smckusick 		return (cp);
3324236Smckusick 	if (stat(cp, &stb) < 0)
3334236Smckusick 		return (cp);
3344236Smckusick 	if ((stb.st_mode&S_IFMT) != S_IFCHR)
3354236Smckusick 		return (cp);
3364236Smckusick 	if (*(dp+1) != 'r')
3374236Smckusick 		return (cp);
3384236Smckusick 	strcpy(dp+1, dp+2);
3394236Smckusick 	return (cp);
3404236Smckusick }
3414236Smckusick 
3424236Smckusick char *
3434236Smckusick rawname(cp)
3444236Smckusick 	char *cp;
3454236Smckusick {
3464236Smckusick 	static char rawbuf[32];
3474236Smckusick 	char *dp = rindex(cp, '/');
3484236Smckusick 
3494236Smckusick 	if (dp == 0)
3504236Smckusick 		return (0);
3514236Smckusick 	*dp = 0;
3524236Smckusick 	strcpy(rawbuf, cp);
3534236Smckusick 	*dp = '/';
3544236Smckusick 	strcat(rawbuf, "/r");
3554236Smckusick 	strcat(rawbuf, dp+1);
3564236Smckusick 	return (rawbuf);
3574236Smckusick }
3584236Smckusick 
3594236Smckusick check(dev)
3604236Smckusick 	char *dev;
3614236Smckusick {
3624236Smckusick 	register DINODE *dp;
3634236Smckusick 	register ino_t *blp;
3644236Smckusick 	register int i, n;
3654236Smckusick 	ino_t savino;
3664236Smckusick 	int b, c;
3674236Smckusick 	daddr_t d, s;
3684236Smckusick 
3694236Smckusick 	devname = dev;
3704236Smckusick 	if (setup(dev) == 0) {
3714236Smckusick 		if (preen)
3724236Smckusick 			pfatal("CAN'T CHECK DEVICE.");
3734236Smckusick 		return;
3744236Smckusick 	}
3754236Smckusick /* 1 */
3764236Smckusick 	if (preen==0) {
3774236Smckusick 		if (hotroot)
3784236Smckusick 			printf("** Root file system\n");
3794236Smckusick 		printf("** Phase 1 - Check Blocks and Sizes\n");
3804236Smckusick 	}
3814236Smckusick 	pfunc = pass1;
3824236Smckusick 	inum = 0;
3835325Smckusic 	n_blks += howmany(sblock.fs_cssize, sblock.fs_bsize) * sblock.fs_frag;
3844236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
3855381Smckusic 		if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
3864236Smckusick 			continue;
3874236Smckusick 		n = 0;
3884465Smckusic 		for (i = 0; i < sblock.fs_ipg; i++, inum++) {
3894465Smckusic 			dp = ginode();
3904465Smckusic 			if (dp == NULL)
3914465Smckusic 				continue;
3925944Smckusic 			n++;
3934236Smckusick 			if (ALLOC) {
3944236Smckusick 				if (!isset(cgrp.cg_iused, i)) {
3955381Smckusic 					if (debug)
3965381Smckusic 						printf("%d bad, not used\n",
3975381Smckusic 						    inum);
3984236Smckusick 					inosumbad++;
3994236Smckusick 				}
4005944Smckusic 				n--;
4014236Smckusick 				lastino = inum;
4024236Smckusick 				if (ftypeok(dp) == 0) {
4034236Smckusick 					pfatal("UNKNOWN FILE TYPE I=%u", inum);
4044236Smckusick 					if (reply("CLEAR") == 1) {
4054236Smckusick 						zapino(dp);
4064236Smckusick 						inodirty();
4074236Smckusick 						inosumbad++;
4084236Smckusick 					}
4094236Smckusick 					continue;
4104236Smckusick 				}
4114236Smckusick 				n_files++;
4124236Smckusick 				if (setlncnt(dp->di_nlink) <= 0) {
4134236Smckusick 					if (badlnp < &badlncnt[MAXLNCNT])
4144236Smckusick 						*badlnp++ = inum;
4154236Smckusick 					else {
4164236Smckusick 						pfatal("LINK COUNT TABLE OVERFLOW");
4174236Smckusick 						if (reply("CONTINUE") == 0)
4184236Smckusick 							errexit("");
4194236Smckusick 					}
4204236Smckusick 				}
4215877Smckusic 				setstate(DIRCT ? DSTATE : FSTATE);
4224236Smckusick 				badblk = dupblk = 0; filsize = 0; maxblk = 0;
4234236Smckusick 				ckinode(dp, ADDR);
4244236Smckusick 			} else {
4254236Smckusick 				if (isset(cgrp.cg_iused, i)) {
4265381Smckusic 					if (debug)
4275381Smckusic 						printf("%d bad, marked used\n",
4285381Smckusic 						    inum);
4294236Smckusick 					inosumbad++;
4304465Smckusic 					n--;
4314236Smckusick 				}
4324236Smckusick 				if (dp->di_mode != 0) {
4334236Smckusick 					pfatal("PARTIALLY ALLOCATED INODE I=%u", inum);
4344236Smckusick 					if (reply("CLEAR") == 1) {
4354236Smckusick 						zapino(dp);
4364236Smckusick 						inodirty();
4374236Smckusick 						inosumbad++;
4384236Smckusick 					}
4394236Smckusick 				}
4404236Smckusick 			}
4414236Smckusick 		}
4424789Smckusic 		if (n != cgrp.cg_cs.cs_nifree) {
4435381Smckusic 			if (debug)
4445944Smckusic 				printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n",
4455381Smckusic 				    c, cgrp.cg_cs.cs_nifree, n);
4464236Smckusick 			inosumbad++;
4474236Smckusick 		}
448*6491Smckusick 		if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree
449*6491Smckusick 		  || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree
450*6491Smckusick 		  || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree
451*6491Smckusick 		  || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir)
452*6491Smckusick 			sbsumbad++;
4534236Smckusick 	}
4544236Smckusick /* 1b */
4554236Smckusick 	if (enddup != &duplist[0]) {
4564236Smckusick 		if (preen)
4574236Smckusick 			pfatal("INTERNAL ERROR: dups with -p");
4584236Smckusick 		printf("** Phase 1b - Rescan For More DUPS\n");
4594236Smckusick 		pfunc = pass1b;
4604236Smckusick 		inum = 0;
4614236Smckusick 		for (c = 0; c < sblock.fs_ncg; c++) {
4624465Smckusic 			for (i = 0; i < sblock.fs_ipg; i++, inum++) {
4634465Smckusic 				dp = ginode();
4644465Smckusic 				if (dp == NULL)
4654465Smckusic 					continue;
4664236Smckusick 				if (getstate() != USTATE &&
4674236Smckusick 				    (ckinode(dp, ADDR) & STOP))
4684236Smckusick 					goto out1b;
4694465Smckusic 			}
4704236Smckusick 		}
4714236Smckusick 	}
4724236Smckusick out1b:
4734465Smckusic 	flush(&dfile, &inoblk);
4744236Smckusick /* 2 */
4754236Smckusick 	if (preen == 0)
4764236Smckusick 		printf("** Phase 2 - Check Pathnames\n");
4774236Smckusick 	inum = ROOTINO;
4784236Smckusick 	thisname = pathp = pathname;
4794236Smckusick 	pfunc = pass2;
4804236Smckusick 	switch (getstate()) {
4814236Smckusick 
4824236Smckusick 	case USTATE:
4834236Smckusick 		errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
4844236Smckusick 
4854236Smckusick 	case FSTATE:
4864236Smckusick 		pfatal("ROOT INODE NOT DIRECTORY");
4874236Smckusick 		if (reply("FIX") == 0 || (dp = ginode()) == NULL)
4884236Smckusick 			errexit("");
4894236Smckusick 		dp->di_mode &= ~IFMT;
4904236Smckusick 		dp->di_mode |= IFDIR;
4914236Smckusick 		inodirty();
4924236Smckusick 		inosumbad++;
4934236Smckusick 		setstate(DSTATE);
4944236Smckusick 		/* fall into ... */
4954236Smckusick 
4964236Smckusick 	case DSTATE:
4974236Smckusick 		descend();
4984236Smckusick 		break;
4994236Smckusick 
5004236Smckusick 	case CLEAR:
5014236Smckusick 		pfatal("DUPS/BAD IN ROOT INODE");
5024236Smckusick 		printf("\n");
5034236Smckusick 		if (reply("CONTINUE") == 0)
5044236Smckusick 			errexit("");
5054236Smckusick 		setstate(DSTATE);
5064236Smckusick 		descend();
5074236Smckusick 	}
5084236Smckusick /* 3 */
5094236Smckusick 	if (preen == 0)
5104236Smckusick 		printf("** Phase 3 - Check Connectivity\n");
5114236Smckusick 	for (inum = ROOTINO; inum <= lastino; inum++) {
5124236Smckusick 		if (getstate() == DSTATE) {
5134236Smckusick 			pfunc = findino;
5144236Smckusick 			srchname = "..";
5154236Smckusick 			savino = inum;
5164236Smckusick 			do {
5174236Smckusick 				orphan = inum;
5184236Smckusick 				if ((dp = ginode()) == NULL)
5194236Smckusick 					break;
5204236Smckusick 				filsize = dp->di_size;
5214236Smckusick 				parentdir = 0;
5224236Smckusick 				ckinode(dp, DATA);
5234236Smckusick 				if ((inum = parentdir) == 0)
5244236Smckusick 					break;
5254236Smckusick 			} while (getstate() == DSTATE);
5264236Smckusick 			inum = orphan;
5274236Smckusick 			if (linkup() == 1) {
5284236Smckusick 				thisname = pathp = pathname;
5294236Smckusick 				*pathp++ = '?';
5304236Smckusick 				pfunc = pass2;
5314236Smckusick 				descend();
5324236Smckusick 			}
5334236Smckusick 			inum = savino;
5344236Smckusick 		}
5354236Smckusick 	}
5364236Smckusick /* 4 */
5374236Smckusick 	if (preen == 0)
5384236Smckusick 		printf("** Phase 4 - Check Reference Counts\n");
5394236Smckusick 	pfunc = pass4;
5404236Smckusick 	for (inum = ROOTINO; inum <= lastino; inum++) {
5414236Smckusick 		switch (getstate()) {
5424236Smckusick 
5434236Smckusick 		case FSTATE:
5444236Smckusick 			if (n = getlncnt())
5454236Smckusick 				adjust((short)n);
5464236Smckusick 			else {
5474236Smckusick 				for (blp = badlncnt;blp < badlnp; blp++)
5484236Smckusick 					if (*blp == inum) {
5494236Smckusick 						clri("UNREF", 1);
5504236Smckusick 						break;
5514236Smckusick 					}
5524236Smckusick 			}
5534236Smckusick 			break;
5544236Smckusick 
5554236Smckusick 		case DSTATE:
5564236Smckusick 			clri("UNREF", 1);
5574236Smckusick 			break;
5584236Smckusick 
5594236Smckusick 		case CLEAR:
5604236Smckusick 			clri("BAD/DUP", 1);
5614236Smckusick 			break;
5624236Smckusick 		}
5634236Smckusick 	}
5645337Smckusic 	if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) {
5654236Smckusick 		pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
5664236Smckusick 		if (preen)
5674236Smckusick 			printf(" (FIXED)\n");
5684236Smckusick 		if (preen || reply("FIX") == 1) {
5695944Smckusic 			sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files;
5704236Smckusick 			sbdirty();
5714236Smckusick 		}
5724236Smckusick 	}
5734236Smckusick 	flush(&dfile, &fileblk);
5744236Smckusick 
5754236Smckusick /* 5 */
5764236Smckusick 	if (preen == 0)
5774236Smckusick 		printf("** Phase 5 - Check Cyl groups\n");
5786314Smckusick 	copy(blockmap, freemap, (unsigned)bmapsz);
5794236Smckusick 	dupblk = 0;
5805381Smckusic 	n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0));
5814236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
5825381Smckusic 		daddr_t cbase = cgbase(&sblock, c);
5834236Smckusick 		short bo[MAXCPG][NRPOS];
5845371Smckusic 		long botot[MAXCPG];
5855325Smckusic 		long frsum[MAXFRAG];
5864465Smckusic 		int blk;
5874465Smckusic 
5885371Smckusic 		for (n = 0; n < sblock.fs_cpg; n++) {
5895371Smckusic 			botot[n] = 0;
5904236Smckusick 			for (i = 0; i < NRPOS; i++)
5914236Smckusick 				bo[n][i] = 0;
5925371Smckusic 		}
5935325Smckusic 		for (i = 0; i < sblock.fs_frag; i++) {
5944465Smckusic 			frsum[i] = 0;
5954465Smckusic 		}
5964465Smckusic 		/*
5974465Smckusic 		 * need to account for the spare boot and super blocks
5984465Smckusic 		 * which appear (inaccurately) bad
5994465Smckusic 		 */
6005381Smckusic 		n_bad += cgtod(&sblock, c) - cbase;
6015381Smckusic 		if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
6024236Smckusick 			continue;
6035325Smckusic 		for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
6045325Smckusic 			if (isblock(&sblock, cgrp.cg_free, b/sblock.fs_frag)) {
6055325Smckusic 				if (pass5(cbase+b, sblock.fs_frag) == STOP)
6064236Smckusick 					goto out5;
6074236Smckusick 				/* this is clumsy ... */
6085325Smckusic 				n_ffree -= sblock.fs_frag;
6094236Smckusick 				n_bfree++;
6105371Smckusic 				botot[cbtocylno(&sblock, b)]++;
6115363Smckusic 				bo[cbtocylno(&sblock, b)]
6125363Smckusic 				    [cbtorpos(&sblock, b)]++;
6134465Smckusic 			} else {
6145325Smckusic 				for (d = 0; d < sblock.fs_frag; d++)
6154236Smckusick 					if (isset(cgrp.cg_free, b+d))
6164236Smckusick 						if (pass5(cbase+b+d,1) == STOP)
6174236Smckusick 							goto out5;
6184465Smckusic 				blk = ((cgrp.cg_free[b / NBBY] >> (b % NBBY)) &
6195325Smckusic 				       (0xff >> (NBBY - sblock.fs_frag)));
6204465Smckusic 				if (blk != 0)
6215325Smckusic 					fragacct(&sblock, blk, frsum, 1);
6224465Smckusic 			}
6234236Smckusick 		}
6245325Smckusic 		for (i = 0; i < sblock.fs_frag; i++) {
6254465Smckusic 			if (cgrp.cg_frsum[i] != frsum[i]) {
6265381Smckusic 				if (debug)
6275381Smckusic 					printf("cg[%d].cg_frsum[%d] have %d calc %d\n",
6285381Smckusic 					    c, i, cgrp.cg_frsum[i], frsum[i]);
6294465Smckusic 				frsumbad++;
6304465Smckusic 			}
6314465Smckusic 		}
6325371Smckusic 		for (n = 0; n < sblock.fs_cpg; n++) {
6335371Smckusic 			if (botot[n] != cgrp.cg_btot[n]) {
6345381Smckusic 				if (debug)
6355381Smckusic 					printf("cg[%d].cg_btot[%d] have %d calc %d\n",
6365381Smckusic 					    c, n, cgrp.cg_btot[n], botot[n]);
6375371Smckusic 				offsumbad++;
6385371Smckusic 			}
6394236Smckusick 			for (i = 0; i < NRPOS; i++)
6404236Smckusick 				if (bo[n][i] != cgrp.cg_b[n][i]) {
6415381Smckusic 					if (debug)
6425381Smckusic 						printf("cg[%d].cg_b[%d][%d] have %d calc %d\n",
6435381Smckusic 						    c, n, i, cgrp.cg_b[n][i],
6445381Smckusic 						    bo[n][i]);
6454236Smckusick 					offsumbad++;
6464236Smckusick 				}
6475371Smckusic 		}
6484236Smckusick 	}
6494236Smckusick out5:
6504236Smckusick 	if (dupblk)
6514236Smckusick 		pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk);
6524236Smckusick 	if (fixcg == 0) {
6535325Smckusic 		if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) {
6544236Smckusick 			pwarn("%ld BLK(S) MISSING\n", fmax - b);
6554236Smckusick 			fixcg = 1;
656*6491Smckusick 		} else if (inosumbad + offsumbad + frsumbad + sbsumbad) {
657*6491Smckusick 			pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n",
6584236Smckusick 			    inosumbad ? "(INODE FREE) " : "",
6594465Smckusic 			    offsumbad ? "(BLOCK OFFSETS) " : "",
660*6491Smckusick 			    frsumbad ? "(FRAG SUMMARIES) " : "",
661*6491Smckusick 			    sbsumbad ? "(SUPER BLOCK SUMMARIES) " : "");
6624236Smckusick 			fixcg = 1;
6634789Smckusic 		} else if (n_ffree != sblock.fs_cstotal.cs_nffree ||
6644789Smckusic 		    n_bfree != sblock.fs_cstotal.cs_nbfree) {
6654236Smckusick 			pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK");
6664236Smckusick 			if (preen)
6674236Smckusick 				printf(" (FIXED)\n");
6684236Smckusick 			if (preen || reply("FIX") == 1) {
6694789Smckusic 				sblock.fs_cstotal.cs_nffree = n_ffree;
6704789Smckusic 				sblock.fs_cstotal.cs_nbfree = n_bfree;
6714236Smckusick 				sbdirty();
6724236Smckusick 			}
6734236Smckusick 		}
6744236Smckusick 	}
6754236Smckusick 	if (fixcg) {
6764236Smckusick 		pwarn("BAD CYLINDER GROUPS");
6774236Smckusick 		if (preen)
6784236Smckusick 			printf(" (SALVAGED)\n");
6794236Smckusick 		else if (reply("SALVAGE") == 0)
6804236Smckusick 			fixcg = 0;
6814236Smckusick 	}
6824236Smckusick 
6834236Smckusick 	if (fixcg) {
6844236Smckusick 		if (preen == 0)
6854236Smckusick 			printf("** Phase 6 - Salvage Cylinder Groups\n");
6864236Smckusick 		makecg();
6874789Smckusic 		n_ffree = sblock.fs_cstotal.cs_nffree;
6884789Smckusic 		n_bfree = sblock.fs_cstotal.cs_nbfree;
6894236Smckusick 	}
6904236Smckusick 
6914236Smckusick 	pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n",
6925325Smckusic 	    n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_bsize) * sblock.fs_frag,
6935325Smckusic 	    n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree);
6944236Smckusick 	if (dfile.mod) {
6954236Smckusick 		time(&sblock.fs_time);
6964236Smckusick 		sbdirty();
6974236Smckusick 	}
6984236Smckusick 	ckfini();
6994236Smckusick 	sync();
7004236Smckusick 	if (dfile.mod && hotroot) {
7014236Smckusick 		printf("\n***** BOOT UNIX (NO SYNC!) *****\n");
7024236Smckusick 		exit(4);
7034236Smckusick 	}
7044236Smckusick 	if (dfile.mod && preen == 0)
7054236Smckusick 		printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
7066314Smckusick 	free(blockmap);
7074236Smckusick 	free(freemap);
7084236Smckusick 	free(statemap);
7094236Smckusick 	free(lncntp);
7104236Smckusick }
7114236Smckusick 
7124236Smckusick /* VARARGS1 */
7134236Smckusick error(s1, s2, s3, s4)
7144715Smckusic 	char *s1;
7154236Smckusick {
7164236Smckusick 
7174236Smckusick 	printf(s1, s2, s3, s4);
7184236Smckusick }
7194236Smckusick 
7204236Smckusick /* VARARGS1 */
7214236Smckusick errexit(s1, s2, s3, s4)
7224715Smckusic 	char *s1;
7234236Smckusick {
7244236Smckusick 	error(s1, s2, s3, s4);
7254236Smckusick 	exit(8);
7264236Smckusick }
7274236Smckusick 
7284236Smckusick /*
7294236Smckusick  * An inconsistency occured which shouldn't during normal operations.
7304236Smckusick  * Die if preening, otw just printf.
7314236Smckusick  */
7324236Smckusick /* VARARGS1 */
7334236Smckusick pfatal(s, a1, a2, a3)
7344236Smckusick 	char *s;
7354236Smckusick {
7364236Smckusick 
7374236Smckusick 	if (preen) {
7384236Smckusick 		printf("%s: ", devname);
7394236Smckusick 		printf(s, a1, a2, a3);
7404236Smckusick 		printf("\n");
7414236Smckusick 		preendie();
7424236Smckusick 	}
7434236Smckusick 	printf(s, a1, a2, a3);
7444236Smckusick }
7454236Smckusick 
7464236Smckusick preendie()
7474236Smckusick {
7484236Smckusick 
7494236Smckusick 	printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
7504236Smckusick 	exit(8);
7514236Smckusick }
7524236Smckusick 
7534236Smckusick /*
7544236Smckusick  * Pwarn is like printf when not preening,
7554236Smckusick  * or a warning (preceded by filename) when preening.
7564236Smckusick  */
7574236Smckusick /* VARARGS1 */
7584236Smckusick pwarn(s, a1, a2, a3, a4, a5)
7594236Smckusick 	char *s;
7604236Smckusick {
7614236Smckusick 
7624236Smckusick 	if (preen)
7634236Smckusick 		printf("%s: ", devname);
7644236Smckusick 	printf(s, a1, a2, a3, a4, a5);
7654236Smckusick }
7664236Smckusick 
7674236Smckusick ckinode(dp, flg)
7684236Smckusick 	DINODE *dp;
7694236Smckusick 	register flg;
7704236Smckusick {
7714236Smckusick 	register daddr_t *ap;
7724236Smckusick 	register ret;
7735956Smckusic 	int (*func)(), n, ndb, size, offset;
7744236Smckusick 
7754236Smckusick 	if (SPECIAL)
7764236Smckusick 		return (KEEPON);
7774236Smckusick 	func = (flg == ADDR) ? pfunc : dirscan;
7785325Smckusic 	ndb = howmany(dp->di_size, sblock.fs_bsize);
7794428Smckusic 	for (ap = &dp->di_db[0]; ap < &dp->di_db[NDADDR]; ap++) {
7805956Smckusic 		if (--ndb == 0 && (offset = blkoff(&sblock, dp->di_size)) != 0)
7815956Smckusic 			size = numfrags(&sblock, fragroundup(&sblock, offset));
7824236Smckusick 		else
7835325Smckusic 			size = sblock.fs_frag;
7844236Smckusick 		if (*ap && (ret = (*func)(*ap, size)) & STOP)
7854236Smckusick 			return (ret);
7864236Smckusick 	}
7874428Smckusic 	for (ap = &dp->di_ib[0], n = 1; n <= 2; ap++, n++) {
7885325Smckusic 		if (*ap && (ret = iblock(*ap, n, flg, dp->di_size - sblock.fs_bsize * NDADDR)) & STOP)
7894236Smckusick 			return (ret);
7904236Smckusick 	}
7914236Smckusick 	return (KEEPON);
7924236Smckusick }
7934236Smckusick 
7944236Smckusick iblock(blk, ilevel, flg, isize)
7954236Smckusick 	daddr_t blk;
7964236Smckusick 	register ilevel;
7974236Smckusick 	int isize;
7984236Smckusick {
7994236Smckusick 	register daddr_t *ap;
8004236Smckusick 	register daddr_t *aplim;
8014428Smckusic 	register int i, n;
8024236Smckusick 	int (*func)(), nif;
8034236Smckusick 	BUFAREA ib;
8044236Smckusick 
8054236Smckusick 	if (flg == ADDR) {
8064236Smckusick 		func = pfunc;
8075325Smckusic 		if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0)
8084236Smckusick 			return (n);
8094236Smckusick 	} else
8104236Smckusick 		func = dirscan;
8114236Smckusick 	if (outrange(blk))		/* protect thyself */
8124236Smckusick 		return (SKIP);
8134236Smckusick 	initbarea(&ib);
8145325Smckusic 	if (getblk(&ib, blk, sblock.fs_bsize) == NULL)
8154236Smckusick 		return (SKIP);
8164236Smckusick 	ilevel--;
8174428Smckusic 	if (ilevel == 0) {
8185956Smckusic 		nif = lblkno(&sblock, isize) + 1;
8194428Smckusic 	} else /* ilevel == 1 */ {
8205325Smckusic 		nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1;
8214428Smckusic 	}
8225325Smckusic 	if (nif > NINDIR(&sblock))
8235325Smckusic 		nif = NINDIR(&sblock);
8244428Smckusic 	aplim = & ib.b_un.b_indir[nif];
8254428Smckusic 	for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
8264236Smckusick 		if (*ap) {
8274236Smckusick 			if (ilevel > 0)
8285325Smckusic 				n = iblock(*ap, ilevel, flg, isize - i * NINDIR(&sblock) * sblock.fs_bsize);
8294236Smckusick 			else
8305325Smckusic 				n = (*func)(*ap, sblock.fs_frag);
8314236Smckusick 			if (n & STOP)
8324236Smckusick 				return (n);
8334236Smckusick 		}
8344236Smckusick 	return (KEEPON);
8354236Smckusick }
8364236Smckusick 
8374236Smckusick pass1(blk, size)
8384236Smckusick 	daddr_t blk;
8394236Smckusick 	int size;
8404236Smckusick {
8414236Smckusick 	register daddr_t *dlp;
8424236Smckusick 	int res = KEEPON;
8434236Smckusick 
8444236Smckusick 	for (; size > 0; blk++, size--) {
8454236Smckusick 		if (outrange(blk)) {
8464236Smckusick 			blkerr("BAD", blk);
8474236Smckusick 			if (++badblk >= MAXBAD) {
8484236Smckusick 				printf("EXCESSIVE BAD BLKS I=%u", inum);
8494236Smckusick 				if (reply("CONTINUE") == 0)
8504236Smckusick 					errexit("");
8514236Smckusick 				return (STOP);
8524236Smckusick 			}
8534236Smckusick 			res = SKIP;
8544236Smckusick 		} else if (getbmap(blk)) {
8554236Smckusick 			blkerr("DUP", blk);
8564236Smckusick 			if (++dupblk >= MAXDUP) {
8574236Smckusick 				printf("EXCESSIVE DUP BLKS I=%u", inum);
8584236Smckusick 				if (reply("CONTINUE") == 0)
8594236Smckusick 					errexit("");
8604236Smckusick 				return (STOP);
8614236Smckusick 			}
8624236Smckusick 			if (enddup >= &duplist[DUPTBLSIZE]) {
8634236Smckusick 				printf("DUP TABLE OVERFLOW.");
8644236Smckusick 				if (reply("CONTINUE") == 0)
8654236Smckusick 					errexit("");
8664236Smckusick 				return (STOP);
8674236Smckusick 			}
8684236Smckusick 			for (dlp = duplist; dlp < muldup; dlp++)
8694236Smckusick 				if (*dlp == blk) {
8704236Smckusick 					*enddup++ = blk;
8714236Smckusick 					break;
8724236Smckusick 				}
8734236Smckusick 			if (dlp >= muldup) {
8744236Smckusick 				*enddup++ = *muldup;
8754236Smckusick 				*muldup++ = blk;
8764236Smckusick 			}
8774236Smckusick 		} else {
8784236Smckusick 			n_blks++;
8794236Smckusick 			setbmap(blk);
8804236Smckusick 		}
8814236Smckusick 		filsize++;
8824236Smckusick 	}
8834236Smckusick 	return (res);
8844236Smckusick }
8854236Smckusick 
8864236Smckusick pass1b(blk, size)
8874236Smckusick 	daddr_t blk;
8884236Smckusick 	int size;
8894236Smckusick {
8904236Smckusick 	register daddr_t *dlp;
8914236Smckusick 	int res = KEEPON;
8924236Smckusick 
8934236Smckusick 	for (; size > 0; blk++, size--) {
8944236Smckusick 		if (outrange(blk))
8954236Smckusick 			res = SKIP;
8964236Smckusick 		for (dlp = duplist; dlp < muldup; dlp++)
8974236Smckusick 			if (*dlp == blk) {
8984236Smckusick 				blkerr("DUP", blk);
8994236Smckusick 				*dlp = *--muldup;
9004236Smckusick 				*muldup = blk;
9014236Smckusick 				if (muldup == duplist)
9024236Smckusick 					return (STOP);
9034236Smckusick 			}
9044236Smckusick 	}
9054236Smckusick 	return (res);
9064236Smckusick }
9074236Smckusick 
9084236Smckusick pass2(dirp)
9094236Smckusick 	register DIRECT *dirp;
9104236Smckusick {
9114236Smckusick 	register char *p;
9124236Smckusick 	register n;
9134236Smckusick 	DINODE *dp;
9144236Smckusick 
9154236Smckusick 	if ((inum = dirp->d_ino) == 0)
9164236Smckusick 		return (KEEPON);
9174236Smckusick 	thisname = pathp;
9185877Smckusic 	for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; )
9194236Smckusick 		if ((*pathp++ = *p++) == 0) {
9204236Smckusick 			--pathp;
9214236Smckusick 			break;
9224236Smckusick 		}
9234236Smckusick 	*pathp = 0;
9244236Smckusick 	n = 0;
9254715Smckusic 	if (inum > imax || inum <= 0)
9264236Smckusick 		n = direrr("I OUT OF RANGE");
9274236Smckusick 	else {
9284236Smckusick again:
9294236Smckusick 		switch (getstate()) {
9304236Smckusick 		case USTATE:
9314236Smckusick 			n = direrr("UNALLOCATED");
9324236Smckusick 			break;
9334236Smckusick 
9344236Smckusick 		case CLEAR:
9354236Smckusick 			if ((n = direrr("DUP/BAD")) == 1)
9364236Smckusick 				break;
9374236Smckusick 			if ((dp = ginode()) == NULL)
9384236Smckusick 				break;
9395877Smckusic 			setstate(DIRCT ? DSTATE : FSTATE);
9404236Smckusick 			goto again;
9414236Smckusick 
9424236Smckusick 		case FSTATE:
9434236Smckusick 			declncnt();
9444236Smckusick 			break;
9454236Smckusick 
9464236Smckusick 		case DSTATE:
9474236Smckusick 			declncnt();
9484236Smckusick 			descend();
9494236Smckusick 			break;
9504236Smckusick 		}
9514236Smckusick 	}
9524236Smckusick 	pathp = thisname;
9534236Smckusick 	if (n == 0)
9544236Smckusick 		return (KEEPON);
9554236Smckusick 	dirp->d_ino = 0;
9564236Smckusick 	return (KEEPON|ALTERD);
9574236Smckusick }
9584236Smckusick 
9594236Smckusick pass4(blk, size)
9604715Smckusic 	daddr_t blk;
9614236Smckusick {
9624236Smckusick 	register daddr_t *dlp;
9634236Smckusick 	int res = KEEPON;
9644236Smckusick 
9654236Smckusick 	for (; size > 0; blk++, size--) {
9664236Smckusick 		if (outrange(blk))
9674236Smckusick 			res = SKIP;
9684236Smckusick 		else if (getbmap(blk)) {
9694236Smckusick 			for (dlp = duplist; dlp < enddup; dlp++)
9704236Smckusick 				if (*dlp == blk) {
9714236Smckusick 					*dlp = *--enddup;
9724236Smckusick 					return (KEEPON);
9734236Smckusick 				}
9744236Smckusick 			clrbmap(blk);
9754236Smckusick 			n_blks--;
9764236Smckusick 		}
9774236Smckusick 	}
9784236Smckusick 	return (res);
9794236Smckusick }
9804236Smckusick 
9814236Smckusick pass5(blk, size)
9824236Smckusick 	daddr_t blk;
9834236Smckusick 	int size;
9844236Smckusick {
9854236Smckusick 	int res = KEEPON;
9864236Smckusick 
9874236Smckusick 	for (; size > 0; blk++, size--) {
9884236Smckusick 		if (outrange(blk)) {
9894236Smckusick 			fixcg = 1;
9904236Smckusick 			if (preen)
9914236Smckusick 				pfatal("BAD BLOCKS IN BIT MAPS.");
9924236Smckusick 			if (++badblk >= MAXBAD) {
9934236Smckusick 				printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
9944236Smckusick 				if (reply("CONTINUE") == 0)
9954236Smckusick 					errexit("");
9964236Smckusick 				return (STOP);
9974236Smckusick 			}
9984236Smckusick 		} else if (getfmap(blk)) {
9994236Smckusick 			fixcg = 1;
10004236Smckusick 			if (++dupblk >= DUPTBLSIZE) {
10014236Smckusick 				printf("EXCESSIVE DUP BLKS IN BIT MAPS.");
10024236Smckusick 				if (reply("CONTINUE") == 0)
10034236Smckusick 					errexit("");
10044236Smckusick 				return (STOP);
10054236Smckusick 			}
10064236Smckusick 		} else {
10074236Smckusick 			n_ffree++;
10084236Smckusick 			setfmap(blk);
10094236Smckusick 		}
10104236Smckusick 	}
10114236Smckusick 	return (res);
10124236Smckusick }
10134236Smckusick 
10144236Smckusick outrange(blk)
10154236Smckusick 	daddr_t blk;
10164236Smckusick {
10174236Smckusick 	register int c;
10184236Smckusick 
10195381Smckusic 	c = dtog(&sblock, blk);
10205381Smckusic 	if (blk >= fmax || blk < cgdmin(&sblock, c)) {
10214236Smckusick 		return (1);
10224428Smckusic 	}
10234236Smckusick 	return (0);
10244236Smckusick }
10254236Smckusick 
10264236Smckusick blkerr(s, blk)
10274236Smckusick 	daddr_t blk;
10284236Smckusick 	char *s;
10294236Smckusick {
10304236Smckusick 	pfatal("%ld %s I=%u", blk, s, inum);
10314236Smckusick 	printf("\n");
10324236Smckusick 	setstate(CLEAR);	/* mark for possible clearing */
10334236Smckusick }
10344236Smckusick 
10354236Smckusick descend()
10364236Smckusick {
10374236Smckusick 	register DINODE *dp;
10384236Smckusick 	register char *savname;
10394236Smckusick 	off_t savsize;
10404236Smckusick 
10414236Smckusick 	setstate(FSTATE);
10424236Smckusick 	if ((dp = ginode()) == NULL)
10434236Smckusick 		return;
10444236Smckusick 	savname = thisname;
10454236Smckusick 	*pathp++ = '/';
10464236Smckusick 	savsize = filsize;
10474236Smckusick 	filsize = dp->di_size;
10484236Smckusick 	ckinode(dp, DATA);
10494236Smckusick 	thisname = savname;
10504236Smckusick 	*--pathp = 0;
10514236Smckusick 	filsize = savsize;
10524236Smckusick }
10534236Smckusick 
10545877Smckusic struct dirstuff {
10555877Smckusic 	int loc;
10565877Smckusic 	int blkno;
10575877Smckusic 	int blksiz;
10585877Smckusic };
10595877Smckusic 
10604236Smckusick dirscan(blk, nf)
10614715Smckusic 	daddr_t blk;
10624715Smckusic 	int nf;
10634236Smckusick {
10645877Smckusic 	register DIRECT *dp;
10655877Smckusic 	struct dirstuff dirp;
10666251Smckusick 	int blksiz, dsize, n;
10676251Smckusick 	char dbuf[DIRBLKSIZ];
10684236Smckusick 
10694236Smckusick 	if (outrange(blk)) {
10705325Smckusic 		filsize -= sblock.fs_bsize;
10714236Smckusick 		return (SKIP);
10724236Smckusick 	}
10735877Smckusic 	blksiz = nf * sblock.fs_fsize;
10745877Smckusic 	dirp.loc = 0;
10755877Smckusic 	dirp.blkno = blk;
10765877Smckusic 	dirp.blksiz = blksiz;
10775877Smckusic 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
10786251Smckusick 		dsize = dp->d_reclen;
10796251Smckusick 		copy(dp, dbuf, dsize);
10806251Smckusick 		if ((n = (*pfunc)(dbuf)) & ALTERD) {
10815877Smckusic 			if (getblk(&fileblk, blk, blksiz) != NULL) {
10826251Smckusick 				copy(dbuf, dp, dsize);
10834715Smckusic 				dirty(&fileblk);
10844236Smckusick 				sbdirty();
10854236Smckusick 			} else
10864236Smckusick 				n &= ~ALTERD;
10874236Smckusick 		}
10885877Smckusic 		if (n & STOP)
10894236Smckusick 			return (n);
10904236Smckusick 	}
10914236Smckusick 	return (filsize > 0 ? KEEPON : STOP);
10924236Smckusick }
10934236Smckusick 
10945877Smckusic /*
10955877Smckusic  * get next entry in a directory.
10965877Smckusic  */
10975877Smckusic DIRECT *
10985877Smckusic readdir(dirp)
10995877Smckusic 	register struct dirstuff *dirp;
11005877Smckusic {
11016251Smckusick 	register DIRECT *dp, *ndp;
11025877Smckusic 
11035877Smckusic 	if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) {
11045877Smckusic 		filsize -= dirp->blksiz - dirp->loc;
11055877Smckusic 		return NULL;
11065877Smckusic 	}
11075877Smckusic 	for (;;) {
11085877Smckusic 		if (filsize <= 0 || dirp->loc >= dirp->blksiz)
11095877Smckusic 			return NULL;
11105935Smckusic 		dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
11115935Smckusic 		dirp->loc += dp->d_reclen;
11125935Smckusic 		filsize -= dp->d_reclen;
11136251Smckusick 		ndp = (DIRECT *)(dirblk.b_buf + dirp->loc);
11146372Smckusick 		if (dirp->loc < dirp->blksiz && filsize > 0 &&
11156251Smckusick 		    (ndp->d_ino > imax || ndp->d_namlen > MAXNAMLEN ||
11166251Smckusick 		    ndp->d_reclen <= 0 ||
11176251Smckusick 		    ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ))) {
11186251Smckusick 			pwarn("DIRECTORY CORRUPTED");
11196251Smckusick 			if (preen)
11206251Smckusick 				printf(" (SALVAGED)\n");
11216251Smckusick 			else if (reply("SALVAGE") == 0) {
11226251Smckusick 				dirp->loc +=
11236251Smckusick 				    DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
11246251Smckusick 				filsize -= DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
11256251Smckusick 				return(dp);
11266251Smckusick 			}
11276251Smckusick 			dirp->loc -= dp->d_reclen;
11286251Smckusick 			filsize += dp->d_reclen;
11296251Smckusick 			dp->d_reclen = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
11306251Smckusick 			dirty(&fileblk);
11315877Smckusic 			continue;
11326251Smckusick 		}
11335935Smckusic 		return (dp);
11345877Smckusic 	}
11355877Smckusic }
11365877Smckusic 
11374236Smckusick direrr(s)
11384715Smckusic 	char *s;
11394236Smckusick {
11404236Smckusick 	register DINODE *dp;
11414236Smckusick 
11424236Smckusick 	pwarn("%s ", s);
11434236Smckusick 	pinode();
11444236Smckusick 	printf("\n");
11454236Smckusick 	if ((dp = ginode()) != NULL && ftypeok(dp))
11465877Smckusic 		pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname);
11474236Smckusick 	else
11484236Smckusick 		pfatal("NAME=%s", pathname);
11494236Smckusick 	return (reply("REMOVE"));
11504236Smckusick }
11514236Smckusick 
11524236Smckusick adjust(lcnt)
11534465Smckusic 	register short lcnt;
11544236Smckusick {
11554236Smckusick 	register DINODE *dp;
11564236Smckusick 
11574236Smckusick 	if ((dp = ginode()) == NULL)
11584236Smckusick 		return;
11594236Smckusick 	if (dp->di_nlink == lcnt) {
11604236Smckusick 		if (linkup() == 0)
11614236Smckusick 			clri("UNREF", 0);
11624236Smckusick 	}
11634236Smckusick 	else {
11644236Smckusick 		pwarn("LINK COUNT %s",
11655877Smckusic 			(lfdir==inum)?lfname:(DIRCT?"DIR":"FILE"));
11664236Smckusick 		pinode();
11674236Smckusick 		printf(" COUNT %d SHOULD BE %d",
11684236Smckusick 			dp->di_nlink, dp->di_nlink-lcnt);
11694236Smckusick 		if (preen) {
11704236Smckusick 			if (lcnt < 0) {
11714236Smckusick 				printf("\n");
11724236Smckusick 				preendie();
11734236Smckusick 			}
11744236Smckusick 			printf(" (ADJUSTED)\n");
11754236Smckusick 		}
11764236Smckusick 		if (preen || reply("ADJUST") == 1) {
11774236Smckusick 			dp->di_nlink -= lcnt;
11784236Smckusick 			inodirty();
11794236Smckusick 		}
11804236Smckusick 	}
11814236Smckusick }
11824236Smckusick 
11834236Smckusick clri(s, flg)
11844715Smckusic 	char *s;
11854236Smckusick {
11864236Smckusick 	register DINODE *dp;
11874236Smckusick 
11884236Smckusick 	if ((dp = ginode()) == NULL)
11894236Smckusick 		return;
11904236Smckusick 	if (flg == 1) {
11915877Smckusic 		pwarn("%s %s", s, DIRCT?"DIR":"FILE");
11924236Smckusick 		pinode();
11934236Smckusick 	}
11944236Smckusick 	if (preen || reply("CLEAR") == 1) {
11954236Smckusick 		if (preen)
11964236Smckusick 			printf(" (CLEARED)\n");
11974236Smckusick 		n_files--;
11984236Smckusick 		pfunc = pass4;
11994236Smckusick 		ckinode(dp, ADDR);
12004236Smckusick 		zapino(dp);
12014465Smckusic 		setstate(USTATE);
12024236Smckusick 		inodirty();
12034236Smckusick 		inosumbad++;
12044236Smckusick 	}
12054236Smckusick }
12064236Smckusick 
12074236Smckusick setup(dev)
12084715Smckusic 	char *dev;
12094236Smckusick {
12104236Smckusick 	dev_t rootdev;
12116489Smckusick 	struct stat statb;
12124236Smckusick 	int super = bflag ? bflag : SBLOCK;
1213*6491Smckusick 	int i;
12144236Smckusick 
12154236Smckusick 	bflag = 0;
12164236Smckusick 	if (stat("/", &statb) < 0)
12174236Smckusick 		errexit("Can't stat root\n");
12184236Smckusick 	rootdev = statb.st_dev;
12194236Smckusick 	if (stat(dev, &statb) < 0) {
12204236Smckusick 		error("Can't stat %s\n", dev);
12214236Smckusick 		return (0);
12224236Smckusick 	}
12234236Smckusick 	rawflg = 0;
12244236Smckusick 	if ((statb.st_mode & S_IFMT) == S_IFBLK)
12254236Smckusick 		;
12264236Smckusick 	else if ((statb.st_mode & S_IFMT) == S_IFCHR)
12274236Smckusick 		rawflg++;
12284236Smckusick 	else {
12294236Smckusick 		if (reply("file is not a block or character device; OK") == 0)
12304236Smckusick 			return (0);
12314236Smckusick 	}
12324236Smckusick 	if (rootdev == statb.st_rdev)
12334236Smckusick 		hotroot++;
12344236Smckusick 	if ((dfile.rfdes = open(dev, 0)) < 0) {
12354236Smckusick 		error("Can't open %s\n", dev);
12364236Smckusick 		return (0);
12374236Smckusick 	}
12384236Smckusick 	if (preen == 0)
12394236Smckusick 		printf("** %s", dev);
12404236Smckusick 	if (nflag || (dfile.wfdes = open(dev, 1)) < 0) {
12414236Smckusick 		dfile.wfdes = -1;
12424236Smckusick 		if (preen)
12434236Smckusick 			pfatal("NO WRITE ACCESS");
12444236Smckusick 		printf(" (NO WRITE)");
12454236Smckusick 	}
12464236Smckusick 	if (preen == 0)
12474236Smckusick 		printf("\n");
1248*6491Smckusick 	fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; sbsumbad = 0;
12494236Smckusick 	dfile.mod = 0;
12504236Smckusick 	n_files = n_blks = n_ffree = n_bfree = 0;
12514236Smckusick 	muldup = enddup = &duplist[0];
12524236Smckusick 	badlnp = &badlncnt[0];
12534236Smckusick 	lfdir = 0;
12544236Smckusick 	rplyflag = 0;
12554236Smckusick 	initbarea(&sblk);
12564236Smckusick 	initbarea(&fileblk);
12574236Smckusick 	initbarea(&inoblk);
12584236Smckusick 	initbarea(&cgblk);
1259*6491Smckusick 	/*
1260*6491Smckusick 	 * Read in the super block and its summary info.
1261*6491Smckusick 	 */
12625347Smckusic 	if (bread(&dfile, &sblock, super, SBSIZE) == 0)
12634236Smckusick 		return (0);
12644465Smckusic 	sblk.b_bno = super;
12655347Smckusic 	sblk.b_size = SBSIZE;
1266*6491Smckusick 	for (i = 0; i < howmany(sblock.fs_cssize, sblock.fs_bsize); i++) {
1267*6491Smckusick 		sblock.fs_csp[i] = (struct csum *)calloc(1, sblock.fs_bsize);
1268*6491Smckusick 		bread(&dfile, (char *)sblock.fs_csp[i],
1269*6491Smckusick 		    fsbtodb(&sblock, sblock.fs_csaddr + (i * sblock.fs_frag)),
1270*6491Smckusick 		    sblock.fs_bsize);
1271*6491Smckusick 	}
12725363Smckusic 	/*
12735363Smckusic 	 * run a few consistency checks of the super block
12745363Smckusic 	 */
12754236Smckusick 	if (sblock.fs_magic != FS_MAGIC)
12764236Smckusick 		{ badsb("MAGIC NUMBER WRONG"); return (0); }
12774236Smckusick 	if (sblock.fs_ncg < 1)
12784236Smckusick 		{ badsb("NCG OUT OF RANGE"); return (0); }
12794236Smckusick 	if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
12804236Smckusick 		{ badsb("CPG OUT OF RANGE"); return (0); }
12814236Smckusick 	if (sblock.fs_nsect < 1)
12824236Smckusick 		{ badsb("NSECT < 1"); return (0); }
12834236Smckusick 	if (sblock.fs_ntrak < 1)
12844236Smckusick 		{ badsb("NTRAK < 1"); return (0); }
12855363Smckusic 	if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak)
12865363Smckusic 		{ badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); }
12875363Smckusic 	if (sblock.fs_ipg % INOPB(&sblock))
12885363Smckusic 		{ badsb("INODES NOT MULTIPLE OF A BLOCK"); return (0); }
12895381Smckusic 	if (cgdmin(&sblock, 0) >= sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
12904236Smckusick 		{ badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); return (0); }
12915363Smckusic 	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
12925363Smckusic 	    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
12934236Smckusick 		{ badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
12945325Smckusic 	if (sblock.fs_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
12954236Smckusick 		{ badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); }
12965363Smckusic 	if (sblock.fs_size * NSPF(&sblock) <=
12975363Smckusic 	    (sblock.fs_ncyl - 1) * sblock.fs_spc)
12984236Smckusick 		{ badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); }
12995363Smckusic 	if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc)
13004236Smckusick 		{ badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
13014236Smckusick 	/* rest we COULD repair... */
13024236Smckusick 	if (sblock.fs_sblkno != SBLOCK)
13035363Smckusic 		{ badsb("SBLKNO CORRUPTED"); return (0); }
13045363Smckusic 	if (sblock.fs_cblkno !=
13055363Smckusic 	    roundup(howmany(BBSIZE + SBSIZE, sblock.fs_fsize), sblock.fs_frag))
13065363Smckusic 		{ badsb("CBLKNO CORRUPTED"); return (0); }
13075363Smckusic 	if (sblock.fs_iblkno != sblock.fs_cblkno + sblock.fs_frag)
13085363Smckusic 		{ badsb("IBLKNO CORRUPTED"); return (0); }
13095363Smckusic 	if (sblock.fs_dblkno !=
13105363Smckusic 	    sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock))
13115363Smckusic 		{ badsb("DBLKNO CORRUPTED"); return (0); }
13125956Smckusic 	if (sblock.fs_cgsize != fragroundup(&sblock,
13135956Smckusic 	    sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY)))
13144236Smckusick 		{ badsb("CGSIZE INCORRECT"); return (0); }
13155325Smckusic 	if (sblock.fs_cssize != sblock.fs_ncg * sizeof(struct csum))
13164236Smckusick 		{ badsb("CSSIZE INCORRECT"); return (0); }
13174236Smckusick 	fmax = sblock.fs_size;
13184236Smckusick 	imax = sblock.fs_ncg * sblock.fs_ipg;
13195363Smckusic 	/*
13205363Smckusic 	 * allocate the necessary maps
13215363Smckusic 	 */
13224236Smckusick 	bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
13236314Smckusick 	blockmap = (char *)calloc(bmapsz, sizeof (char));
13244236Smckusick 	freemap = (char *)calloc(bmapsz, sizeof (char));
13254236Smckusick 	statemap = (char *)calloc(imax+1, sizeof(char));
13264236Smckusick 	lncntp = (short *)calloc(imax+1, sizeof(short));
13274236Smckusick 
13284465Smckusic 	startinum = imax + 1;
13294236Smckusick 	return (1);
13304236Smckusick 
13314236Smckusick badsb:
13324236Smckusick 	ckfini();
13334236Smckusick 	return (0);
13344236Smckusick }
13354236Smckusick 
13364236Smckusick badsb(s)
13374236Smckusick 	char *s;
13384236Smckusick {
13394236Smckusick 
13404236Smckusick 	if (preen)
13414236Smckusick 		printf("%s: ", devname);
13424236Smckusick 	printf("BAD SUPER BLOCK: %s\n", s);
13434236Smckusick 	pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
13444236Smckusick 	pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
13454236Smckusick }
13464236Smckusick 
13474236Smckusick DINODE *
13484236Smckusick ginode()
13494236Smckusick {
13504236Smckusick 	daddr_t iblk;
13514236Smckusick 
13525337Smckusic 	if (inum < ROOTINO || inum > imax)
13534236Smckusick 		return (NULL);
13545325Smckusic 	if (inum < startinum || inum >= startinum + INOPB(&sblock)) {
13555381Smckusic 		iblk = itod(&sblock, inum);
13565325Smckusic 		if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
13574236Smckusick 			return (NULL);
13584236Smckusick 		}
13595325Smckusic 		startinum = (inum / INOPB(&sblock)) * INOPB(&sblock);
13604236Smckusick 	}
13615325Smckusic 	return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]);
13624236Smckusick }
13634236Smckusick 
13644236Smckusick ftypeok(dp)
13654236Smckusick 	DINODE *dp;
13664236Smckusick {
13674236Smckusick 	switch (dp->di_mode & IFMT) {
13684236Smckusick 
13694236Smckusick 	case IFDIR:
13704236Smckusick 	case IFREG:
13714236Smckusick 	case IFBLK:
13724236Smckusick 	case IFCHR:
13736285Smckusick 	case IFLNK:
13744236Smckusick 		return (1);
13754236Smckusick 
13764236Smckusick 	default:
13774236Smckusick 		return (0);
13784236Smckusick 	}
13794236Smckusick }
13804236Smckusick 
13814236Smckusick reply(s)
13824236Smckusick 	char *s;
13834236Smckusick {
13844236Smckusick 	char line[80];
13854236Smckusick 
13864236Smckusick 	if (preen)
13874236Smckusick 		pfatal("INTERNAL ERROR: GOT TO reply()");
13884236Smckusick 	rplyflag = 1;
13894236Smckusick 	printf("\n%s? ", s);
13904236Smckusick 	if (nflag || dfile.wfdes < 0) {
13914236Smckusick 		printf(" no\n\n");
13924236Smckusick 		return (0);
13934236Smckusick 	}
13944236Smckusick 	if (yflag) {
13954236Smckusick 		printf(" yes\n\n");
13964236Smckusick 		return (1);
13974236Smckusick 	}
13984236Smckusick 	if (getline(stdin, line, sizeof(line)) == EOF)
13994236Smckusick 		errexit("\n");
14004236Smckusick 	printf("\n");
14014236Smckusick 	if (line[0] == 'y' || line[0] == 'Y')
14024236Smckusick 		return (1);
14034236Smckusick 	else
14044236Smckusick 		return (0);
14054236Smckusick }
14064236Smckusick 
14074236Smckusick getline(fp, loc, maxlen)
14084236Smckusick 	FILE *fp;
14094236Smckusick 	char *loc;
14104236Smckusick {
14114236Smckusick 	register n;
14124236Smckusick 	register char *p, *lastloc;
14134236Smckusick 
14144236Smckusick 	p = loc;
14154236Smckusick 	lastloc = &p[maxlen-1];
14164236Smckusick 	while ((n = getc(fp)) != '\n') {
14174236Smckusick 		if (n == EOF)
14184236Smckusick 			return (EOF);
14194236Smckusick 		if (!isspace(n) && p < lastloc)
14204236Smckusick 			*p++ = n;
14214236Smckusick 	}
14224236Smckusick 	*p = 0;
14234236Smckusick 	return (p - loc);
14244236Smckusick }
14254236Smckusick 
14264236Smckusick BUFAREA *
14274236Smckusick getblk(bp, blk, size)
14284236Smckusick 	daddr_t blk;
14294236Smckusick 	register BUFAREA *bp;
14304236Smckusick 	int size;
14314236Smckusick {
14324236Smckusick 	register struct filecntl *fcp;
14335325Smckusic 	daddr_t dblk;
14344236Smckusick 
14354236Smckusick 	fcp = &dfile;
14365325Smckusic 	dblk = fsbtodb(&sblock, blk);
14375325Smckusic 	if (bp->b_bno == dblk)
14384236Smckusick 		return (bp);
14394236Smckusick 	flush(fcp, bp);
14405325Smckusic 	if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
14415325Smckusic 		bp->b_bno = dblk;
14424236Smckusick 		bp->b_size = size;
14434236Smckusick 		return (bp);
14444236Smckusick 	}
14454236Smckusick 	bp->b_bno = (daddr_t)-1;
14464236Smckusick 	return (NULL);
14474236Smckusick }
14484236Smckusick 
14494236Smckusick flush(fcp, bp)
14504236Smckusick 	struct filecntl *fcp;
14514236Smckusick 	register BUFAREA *bp;
14524236Smckusick {
14534236Smckusick 
14544236Smckusick 	if (bp->b_dirty)
14554236Smckusick 		bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size);
14564236Smckusick 	bp->b_dirty = 0;
14574236Smckusick }
14584236Smckusick 
14594236Smckusick rwerr(s, blk)
14604236Smckusick 	char *s;
14614236Smckusick 	daddr_t blk;
14624236Smckusick {
14634236Smckusick 
14644236Smckusick 	if (preen == 0)
14654236Smckusick 		printf("\n");
14664236Smckusick 	pfatal("CANNOT %s: BLK %ld", s, blk);
14674236Smckusick 	if (reply("CONTINUE") == 0)
14684236Smckusick 		errexit("Program terminated\n");
14694236Smckusick }
14704236Smckusick 
14714236Smckusick ckfini()
14724236Smckusick {
14734236Smckusick 
14744236Smckusick 	flush(&dfile, &fileblk);
14754236Smckusick 	flush(&dfile, &sblk);
14764465Smckusic 	if (sblk.b_bno != SBLOCK) {
14774465Smckusic 		sblk.b_bno = SBLOCK;
14784465Smckusic 		sbdirty();
14794465Smckusic 		flush(&dfile, &sblk);
14804465Smckusic 	}
14814236Smckusick 	flush(&dfile, &inoblk);
14824236Smckusick 	close(dfile.rfdes);
14834236Smckusick 	close(dfile.wfdes);
14844236Smckusick }
14854236Smckusick 
14864236Smckusick pinode()
14874236Smckusick {
14884236Smckusick 	register DINODE *dp;
14894236Smckusick 	register char *p;
14905877Smckusic 	char uidbuf[BUFSIZ];
14914236Smckusick 	char *ctime();
14924236Smckusick 
14934236Smckusick 	printf(" I=%u ", inum);
14944236Smckusick 	if ((dp = ginode()) == NULL)
14954236Smckusick 		return;
14964236Smckusick 	printf(" OWNER=");
14974236Smckusick 	if (getpw((int)dp->di_uid, uidbuf) == 0) {
14984236Smckusick 		for (p = uidbuf; *p != ':'; p++);
14994236Smckusick 		*p = 0;
15004236Smckusick 		printf("%s ", uidbuf);
15014236Smckusick 	}
15024236Smckusick 	else {
15034236Smckusick 		printf("%d ", dp->di_uid);
15044236Smckusick 	}
15054236Smckusick 	printf("MODE=%o\n", dp->di_mode);
15064236Smckusick 	if (preen)
15074236Smckusick 		printf("%s: ", devname);
15084236Smckusick 	printf("SIZE=%ld ", dp->di_size);
15094236Smckusick 	p = ctime(&dp->di_mtime);
15104236Smckusick 	printf("MTIME=%12.12s %4.4s ", p+4, p+20);
15114236Smckusick }
15124236Smckusick 
15134236Smckusick copy(fp, tp, size)
15144236Smckusick 	register char *tp, *fp;
15154236Smckusick 	unsigned size;
15164236Smckusick {
15174236Smckusick 
15184236Smckusick 	while (size--)
15194236Smckusick 		*tp++ = *fp++;
15204236Smckusick }
15214236Smckusick 
15224236Smckusick makecg()
15234236Smckusick {
15244465Smckusic 	int c, blk;
15254236Smckusick 	daddr_t dbase, d, dmin, dmax;
15264236Smckusick 	long i, j, s;
15274236Smckusick 	register struct csum *cs;
15284465Smckusic 	register DINODE *dp;
15294236Smckusick 
15304789Smckusic 	sblock.fs_cstotal.cs_nbfree = 0;
15314789Smckusic 	sblock.fs_cstotal.cs_nffree = 0;
15324789Smckusic 	sblock.fs_cstotal.cs_nifree = 0;
15334789Smckusic 	sblock.fs_cstotal.cs_ndir = 0;
15344236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
15355381Smckusic 		dbase = cgbase(&sblock, c);
15364236Smckusick 		dmax = dbase + sblock.fs_fpg;
15375409Smckusic 		if (dmax > sblock.fs_size) {
15385944Smckusic 			for ( ; dmax >= sblock.fs_size; dmax--)
15395401Smckusic 				clrbit(cgrp.cg_free, dmax - dbase);
15405409Smckusic 			dmax++;
15415409Smckusic 		}
15425401Smckusic 		dmin = sblock.fs_dblkno;
15435325Smckusic 		cs = &sblock.fs_cs(&sblock, c);
15444236Smckusick 		cgrp.cg_time = time(0);
15454236Smckusick 		cgrp.cg_magic = CG_MAGIC;
15464236Smckusick 		cgrp.cg_cgx = c;
15474236Smckusick 		cgrp.cg_ncyl = sblock.fs_cpg;
15484236Smckusick 		cgrp.cg_niblk = sblock.fs_ipg;
15494236Smckusick 		cgrp.cg_ndblk = dmax - dbase;
15504789Smckusic 		cgrp.cg_cs.cs_ndir = 0;
15514789Smckusic 		cgrp.cg_cs.cs_nffree = 0;
15524789Smckusic 		cgrp.cg_cs.cs_nbfree = 0;
15534789Smckusic 		cgrp.cg_cs.cs_nifree = 0;
15544465Smckusic 		cgrp.cg_rotor = dmin;
15554465Smckusic 		cgrp.cg_frotor = dmin;
15564258Smckusic 		cgrp.cg_irotor = 0;
15575325Smckusic 		for (i = 0; i < sblock.fs_frag; i++)
15584465Smckusic 			cgrp.cg_frsum[i] = 0;
15594236Smckusick 		inum = sblock.fs_ipg * c;
15604465Smckusic 		for (i = 0; i < sblock.fs_ipg; inum++, i++) {
15615944Smckusic 			cgrp.cg_cs.cs_nifree++;
15625944Smckusic 			clrbit(cgrp.cg_iused, i);
15634465Smckusic 			dp = ginode();
15644465Smckusic 			if (dp == NULL)
15654465Smckusic 				continue;
15664465Smckusic 			if (ALLOC) {
15675877Smckusic 				if (DIRCT)
15684789Smckusic 					cgrp.cg_cs.cs_ndir++;
15695944Smckusic 				cgrp.cg_cs.cs_nifree--;
15704465Smckusic 				setbit(cgrp.cg_iused, i);
15714465Smckusic 				continue;
15724465Smckusic 			}
15734236Smckusick 		}
15744236Smckusick 		while (i < MAXIPG) {
15754236Smckusick 			clrbit(cgrp.cg_iused, i);
15764236Smckusick 			i++;
15774236Smckusick 		}
15785944Smckusic 		if (c == 0)
15795944Smckusic 			for (i = 0; i < ROOTINO; i++) {
15805944Smckusic 				setbit(cgrp.cg_iused, i);
15815944Smckusic 				cgrp.cg_cs.cs_nifree--;
15825944Smckusic 			}
15835371Smckusic 		for (s = 0; s < MAXCPG; s++) {
15845371Smckusic 			cgrp.cg_btot[s] = 0;
15854236Smckusick 			for (i = 0; i < NRPOS; i++)
15864236Smckusick 				cgrp.cg_b[s][i] = 0;
15875371Smckusic 		}
15884236Smckusick 		if (c == 0) {
15895944Smckusic 			dmin += howmany(sblock.fs_cssize, sblock.fs_bsize) *
15905944Smckusic 			    sblock.fs_frag;
15914236Smckusick 		}
15924236Smckusick 		for (d = 0; d < dmin; d++)
15934236Smckusick 			clrbit(cgrp.cg_free, d);
15945325Smckusic 		for (; (d + sblock.fs_frag) <= dmax - dbase; d += sblock.fs_frag) {
15954236Smckusick 			j = 0;
15965325Smckusic 			for (i = 0; i < sblock.fs_frag; i++) {
15974236Smckusick 				if (!getbmap(dbase+d+i)) {
15984236Smckusick 					setbit(cgrp.cg_free, d+i);
15994236Smckusick 					j++;
16004236Smckusick 				} else
16014236Smckusick 					clrbit(cgrp.cg_free, d+i);
16024236Smckusick 			}
16035325Smckusic 			if (j == sblock.fs_frag) {
16044789Smckusic 				cgrp.cg_cs.cs_nbfree++;
16055371Smckusic 				cgrp.cg_btot[cbtocylno(&sblock, d)]++;
16065363Smckusic 				cgrp.cg_b[cbtocylno(&sblock, d)]
16075363Smckusic 				    [cbtorpos(&sblock, d)]++;
16084465Smckusic 			} else if (j > 0) {
16094789Smckusic 				cgrp.cg_cs.cs_nffree += j;
16104465Smckusic 				blk = ((cgrp.cg_free[d / NBBY] >> (d % NBBY)) &
16115325Smckusic 				       (0xff >> (NBBY - sblock.fs_frag)));
16125325Smckusic 				fragacct(&sblock, blk, cgrp.cg_frsum, 1);
16134465Smckusic 			}
16144236Smckusick 		}
16154465Smckusic 		for (j = d; d < dmax - dbase; d++) {
16164236Smckusick 			if (!getbmap(dbase+d)) {
16174236Smckusick 				setbit(cgrp.cg_free, d);
16184789Smckusic 				cgrp.cg_cs.cs_nffree++;
16194236Smckusick 			} else
16204236Smckusick 				clrbit(cgrp.cg_free, d);
16214236Smckusick 		}
16224465Smckusic 		if (j != d) {
16234465Smckusic 			blk = ((cgrp.cg_free[j / NBBY] >> (j % NBBY)) &
16245325Smckusic 			       (0xff >> (NBBY - sblock.fs_frag)));
16255325Smckusic 			fragacct(&sblock, blk, cgrp.cg_frsum, 1);
16264465Smckusic 		}
16275325Smckusic 		for (; d < MAXBPG(&sblock); d++)
16284236Smckusick 			clrbit(cgrp.cg_free, d);
16294789Smckusic 		sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree;
16304789Smckusic 		sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree;
16314789Smckusic 		sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
16324789Smckusic 		sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
16334789Smckusic 		*cs = cgrp.cg_cs;
16345381Smckusic 		bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)),
16355956Smckusic 		    sblock.fs_cgsize);
16364236Smckusick 	}
16375325Smckusic 	for (i = 0; i < howmany(sblock.fs_cssize, sblock.fs_bsize); i++) {
16385097Smckusic 		bwrite(&dfile, (char *)sblock.fs_csp[i],
16395325Smckusic 		    fsbtodb(&sblock, sblock.fs_csaddr + (i * sblock.fs_frag)),
16405325Smckusic 		    sblock.fs_bsize);
16415097Smckusic 	}
16424236Smckusick 	sblock.fs_ronly = 0;
16434236Smckusick 	sblock.fs_fmod = 0;
16444236Smckusick 	sbdirty();
16454236Smckusick }
16464236Smckusick 
16474465Smckusic /*
16484465Smckusic  * update the frsum fields to reflect addition or deletion
16494465Smckusic  * of some frags
16504465Smckusic  */
16515325Smckusic fragacct(fs, fragmap, fraglist, cnt)
16525325Smckusic 	struct fs *fs;
16534470Smckusic 	int fragmap;
16544789Smckusic 	long fraglist[];
16554465Smckusic 	int cnt;
16564465Smckusic {
16574465Smckusic 	int inblk;
16584465Smckusic 	register int field, subfield;
16594465Smckusic 	register int siz, pos;
16604465Smckusic 
16615325Smckusic 	inblk = (int)(fragtbl[fs->fs_frag][fragmap] << 1);
16624465Smckusic 	fragmap <<= 1;
16635325Smckusic 	for (siz = 1; siz < fs->fs_frag; siz++) {
16646290Smckusick 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
16654465Smckusic 			continue;
16664465Smckusic 		field = around[siz];
16674465Smckusic 		subfield = inside[siz];
16685325Smckusic 		for (pos = siz; pos <= fs->fs_frag; pos++) {
16694465Smckusic 			if ((fragmap & field) == subfield) {
16704465Smckusic 				fraglist[siz] += cnt;
16714465Smckusic 				pos += siz;
16724465Smckusic 				field <<= siz;
16734465Smckusic 				subfield <<= siz;
16744465Smckusic 			}
16754465Smckusic 			field <<= 1;
16764465Smckusic 			subfield <<= 1;
16774465Smckusic 		}
16784465Smckusic 	}
16794465Smckusic }
16804465Smckusic 
16814236Smckusick findino(dirp)
16824236Smckusick 	register DIRECT *dirp;
16834236Smckusick {
16844236Smckusick 	if (dirp->d_ino == 0)
16854236Smckusick 		return (KEEPON);
16865877Smckusic 	if (!strcmp(dirp->d_name, srchname)) {
16875877Smckusic 		if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
16885877Smckusic 			parentdir = dirp->d_ino;
16895877Smckusic 		return (STOP);
16904236Smckusick 	}
16914236Smckusick 	return (KEEPON);
16924236Smckusick }
16934236Smckusick 
16944236Smckusick mkentry(dirp)
16954236Smckusick 	register DIRECT *dirp;
16964236Smckusick {
16974236Smckusick 	register ino_t in;
16984236Smckusick 	register char *p;
16996251Smckusick 	DIRECT newent;
17006251Smckusick 	int newlen, oldlen;
17014236Smckusick 
17026251Smckusick 	newent.d_namlen = 11;
17036251Smckusick 	newlen = DIRSIZ(&newent);
17046251Smckusick 	if (dirp->d_ino != 0)
17056251Smckusick 		oldlen = DIRSIZ(dirp);
17066251Smckusick 	else
17076251Smckusick 		oldlen = 0;
17086251Smckusick 	if (dirp->d_reclen - oldlen < newlen)
17094236Smckusick 		return (KEEPON);
17106251Smckusick 	newent.d_reclen = dirp->d_reclen - oldlen;
17116251Smckusick 	dirp->d_reclen = oldlen;
17126251Smckusick 	dirp = (struct direct *)(((char *)dirp) + oldlen);
17134236Smckusick 	dirp->d_ino = orphan;
17146251Smckusick 	dirp->d_reclen = newent.d_reclen;
17156251Smckusick 	p = &dirp->d_name[2];
17166251Smckusick 	for (in = imax; in > 0; in /= 10)
17176251Smckusick 		p++;
17186251Smckusick 	*--p = 0;
17196251Smckusick 	dirp->d_namlen = p - dirp->d_name;
17204236Smckusick 	in = orphan;
17214236Smckusick 	while (p > dirp->d_name) {
17224236Smckusick 		*--p = (in % 10) + '0';
17234236Smckusick 		in /= 10;
17244236Smckusick 	}
17254236Smckusick 	*p = '#';
17264236Smckusick 	return (ALTERD|STOP);
17274236Smckusick }
17284236Smckusick 
17294236Smckusick chgdd(dirp)
17304236Smckusick 	register DIRECT *dirp;
17314236Smckusick {
17324236Smckusick 	if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
17334236Smckusick 	dirp->d_name[2] == 0) {
17344236Smckusick 		dirp->d_ino = lfdir;
17354236Smckusick 		return (ALTERD|STOP);
17364236Smckusick 	}
17374236Smckusick 	return (KEEPON);
17384236Smckusick }
17394236Smckusick 
17404236Smckusick linkup()
17414236Smckusick {
17424236Smckusick 	register DINODE *dp;
17434236Smckusick 	register lostdir;
17444236Smckusick 	register ino_t pdir;
17454236Smckusick 
17464236Smckusick 	if ((dp = ginode()) == NULL)
17474236Smckusick 		return (0);
17485877Smckusic 	lostdir = DIRCT;
17494236Smckusick 	pdir = parentdir;
17504236Smckusick 	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
17514236Smckusick 	pinode();
17524236Smckusick 	if (preen && dp->di_size == 0)
17534236Smckusick 		return (0);
17544236Smckusick 	if (preen)
17554236Smckusick 		printf(" (RECONNECTED)\n");
17564236Smckusick 	else
17574236Smckusick 		if (reply("RECONNECT") == 0)
17584236Smckusick 			return (0);
17594236Smckusick 	orphan = inum;
17604236Smckusick 	if (lfdir == 0) {
17614236Smckusick 		inum = ROOTINO;
17624236Smckusick 		if ((dp = ginode()) == NULL) {
17634236Smckusick 			inum = orphan;
17644236Smckusick 			return (0);
17654236Smckusick 		}
17664236Smckusick 		pfunc = findino;
17674236Smckusick 		srchname = lfname;
17684236Smckusick 		filsize = dp->di_size;
17694236Smckusick 		parentdir = 0;
17704236Smckusick 		ckinode(dp, DATA);
17714236Smckusick 		inum = orphan;
17724236Smckusick 		if ((lfdir = parentdir) == 0) {
17734236Smckusick 			pfatal("SORRY. NO lost+found DIRECTORY");
17744236Smckusick 			printf("\n\n");
17754236Smckusick 			return (0);
17764236Smckusick 		}
17774236Smckusick 	}
17784236Smckusick 	inum = lfdir;
17795877Smckusic 	if ((dp = ginode()) == NULL || !DIRCT || getstate() != FSTATE) {
17804236Smckusick 		inum = orphan;
17814236Smckusick 		pfatal("SORRY. NO lost+found DIRECTORY");
17824236Smckusick 		printf("\n\n");
17834236Smckusick 		return (0);
17844236Smckusick 	}
17855956Smckusic 	if (fragoff(&sblock, dp->di_size)) {
17865956Smckusic 		dp->di_size = fragroundup(&sblock, dp->di_size);
17874236Smckusick 		inodirty();
17884236Smckusick 	}
17894236Smckusick 	filsize = dp->di_size;
17904236Smckusick 	inum = orphan;
17914236Smckusick 	pfunc = mkentry;
17924236Smckusick 	if ((ckinode(dp, DATA) & ALTERD) == 0) {
17934236Smckusick 		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
17944236Smckusick 		printf("\n\n");
17954236Smckusick 		return (0);
17964236Smckusick 	}
17974236Smckusick 	declncnt();
17984236Smckusick 	if (lostdir) {
17994236Smckusick 		pfunc = chgdd;
18004236Smckusick 		dp = ginode();
18014236Smckusick 		filsize = dp->di_size;
18024236Smckusick 		ckinode(dp, DATA);
18034236Smckusick 		inum = lfdir;
18044236Smckusick 		if ((dp = ginode()) != NULL) {
18054236Smckusick 			dp->di_nlink++;
18064236Smckusick 			inodirty();
18074236Smckusick 			setlncnt(getlncnt()+1);
18084236Smckusick 		}
18094236Smckusick 		inum = orphan;
18104236Smckusick 		pwarn("DIR I=%u CONNECTED. ", orphan);
18114236Smckusick 		printf("PARENT WAS I=%u\n", pdir);
18124236Smckusick 		if (preen == 0)
18134236Smckusick 			printf("\n");
18144236Smckusick 	}
18154236Smckusick 	return (1);
18164236Smckusick }
18174236Smckusick 
18184236Smckusick bread(fcp, buf, blk, size)
18194236Smckusick 	daddr_t blk;
18204236Smckusick 	register struct filecntl *fcp;
18214236Smckusick 	register size;
18224236Smckusick 	char *buf;
18234236Smckusick {
18245325Smckusic 	if (lseek(fcp->rfdes, blk * DEV_BSIZE, 0) < 0)
18254236Smckusick 		rwerr("SEEK", blk);
18264236Smckusick 	else if (read(fcp->rfdes, buf, size) == size)
18274236Smckusick 		return (1);
18284236Smckusick 	rwerr("READ", blk);
18294236Smckusick 	return (0);
18304236Smckusick }
18314236Smckusick 
18324236Smckusick bwrite(fcp, buf, blk, size)
18334236Smckusick 	daddr_t blk;
18344236Smckusick 	register struct filecntl *fcp;
18354236Smckusick 	register size;
18364236Smckusick 	char *buf;
18374236Smckusick {
18384236Smckusick 
18394236Smckusick 	if (fcp->wfdes < 0)
18404236Smckusick 		return (0);
18415325Smckusic 	if (lseek(fcp->wfdes, blk * DEV_BSIZE, 0) < 0)
18424236Smckusick 		rwerr("SEEK", blk);
18434236Smckusick 	else if (write(fcp->wfdes, buf, size) == size) {
18444236Smckusick 		fcp->mod = 1;
18454236Smckusick 		return (1);
18464236Smckusick 	}
18474236Smckusick 	rwerr("WRITE", blk);
18484236Smckusick 	return (0);
18494236Smckusick }
18504236Smckusick 
18514236Smckusick catch()
18524236Smckusick {
18534236Smckusick 
18544236Smckusick 	ckfini();
18554236Smckusick 	exit(12);
18564236Smckusick }
18575325Smckusic 
18585325Smckusic /*
18595325Smckusic  * block operations
18605325Smckusic  */
18615325Smckusic 
18625325Smckusic isblock(fs, cp, h)
18635325Smckusic 	struct fs *fs;
18645325Smckusic 	unsigned char *cp;
18655325Smckusic 	int h;
18665325Smckusic {
18675325Smckusic 	unsigned char mask;
18685325Smckusic 
18695325Smckusic 	switch (fs->fs_frag) {
18705325Smckusic 	case 8:
18715325Smckusic 		return (cp[h] == 0xff);
18725325Smckusic 	case 4:
18735325Smckusic 		mask = 0x0f << ((h & 0x1) << 2);
18745325Smckusic 		return ((cp[h >> 1] & mask) == mask);
18755325Smckusic 	case 2:
18765325Smckusic 		mask = 0x03 << ((h & 0x3) << 1);
18775325Smckusic 		return ((cp[h >> 2] & mask) == mask);
18785325Smckusic 	case 1:
18795325Smckusic 		mask = 0x01 << (h & 0x7);
18805325Smckusic 		return ((cp[h >> 3] & mask) == mask);
18815325Smckusic 	default:
18825381Smckusic 		error("isblock bad fs_frag %d\n", fs->fs_frag);
18835381Smckusic 		return (0);
18845325Smckusic 	}
18855325Smckusic }
18866489Smckusick 
18876489Smckusick /*	tables.c	4.1	82/03/25	*/
18886489Smckusick 
18896489Smckusick /* merged into kernel:	tables.c 2.1 3/25/82 */
18906489Smckusick 
18916489Smckusick /* last monet version:	partab.c	4.2	81/03/08	*/
18926489Smckusick 
18936489Smckusick /*
18946489Smckusick  * bit patterns for identifying fragments in the block map
18956489Smckusick  * used as ((map & around) == inside)
18966489Smckusick  */
18976489Smckusick int around[9] = {
18986489Smckusick 	0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
18996489Smckusick };
19006489Smckusick int inside[9] = {
19016489Smckusick 	0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
19026489Smckusick };
19036489Smckusick 
19046489Smckusick /*
19056489Smckusick  * given a block map bit pattern, the frag tables tell whether a
19066489Smckusick  * particular size fragment is available.
19076489Smckusick  *
19086489Smckusick  * used as:
19096489Smckusick  * if ((1 << (size - 1)) & fragtbl[fs->fs_frag][map] {
19106489Smckusick  *	at least one fragment of the indicated size is available
19116489Smckusick  * }
19126489Smckusick  *
19136489Smckusick  * These tables are used by the scanc instruction on the VAX to
19146489Smckusick  * quickly find an appropriate fragment.
19156489Smckusick  */
19166489Smckusick 
19176489Smckusick unsigned char fragtbl124[256] = {
19186489Smckusick 	0x00, 0x16, 0x16, 0x2a, 0x16, 0x16, 0x26, 0x4e,
19196489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x2a, 0x3e, 0x4e, 0x8a,
19206489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19216489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19226489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19236489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19246489Smckusick 	0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
19256489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
19266489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19276489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19286489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19296489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19306489Smckusick 	0x26, 0x36, 0x36, 0x2e, 0x36, 0x36, 0x26, 0x6e,
19316489Smckusick 	0x36, 0x36, 0x36, 0x3e, 0x2e, 0x3e, 0x6e, 0xae,
19326489Smckusick 	0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
19336489Smckusick 	0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
19346489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19356489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19366489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19376489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19386489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19396489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19406489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
19416489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
19426489Smckusick 	0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
19436489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
19446489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
19456489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
19466489Smckusick 	0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
19476489Smckusick 	0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
19486489Smckusick 	0x8a, 0x9e, 0x9e, 0xaa, 0x9e, 0x9e, 0xae, 0xce,
19496489Smckusick 	0x9e, 0x9e, 0x9e, 0xbe, 0xaa, 0xbe, 0xce, 0x8a,
19506489Smckusick };
19516489Smckusick 
19526489Smckusick unsigned char fragtbl8[256] = {
19536489Smckusick 	0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04,
19546489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
19556489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
19566489Smckusick 	0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
19576489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
19586489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
19596489Smckusick 	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
19606489Smckusick 	0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
19616489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
19626489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
19636489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
19646489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
19656489Smckusick 	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
19666489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
19676489Smckusick 	0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
19686489Smckusick 	0x08, 0x09, 0x09, 0x0a, 0x10, 0x11, 0x20, 0x40,
19696489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
19706489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
19716489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
19726489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
19736489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
19746489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
19756489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
19766489Smckusick 	0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
19776489Smckusick 	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
19786489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
19796489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
19806489Smckusick 	0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0a, 0x12,
19816489Smckusick 	0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
19826489Smckusick 	0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0c,
19836489Smckusick 	0x08, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x0a, 0x0c,
19846489Smckusick 	0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
19856489Smckusick };
19866489Smckusick 
19876489Smckusick /*
19886489Smckusick  * the actual fragtbl array
19896489Smckusick  */
19906489Smckusick unsigned char *fragtbl[MAXFRAG + 1] = {
19916489Smckusick 	0, fragtbl124, fragtbl124, 0, fragtbl124, 0, 0, 0, fragtbl8,
19926489Smckusick };
1993