xref: /csrg-svn/sbin/fsck/main.c (revision 6837)
1*6837Smckusick static	char sccsid[] = "@(#)main.c	2.6	(Berkeley)	05/17/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>
96634Smckusick #include <dir.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)
41*6837Smckusick #define	LNK	((dp->di_mode & IFMT) == IFLNK)
426285Smckusick #define	SPECIAL	(BLK || CHR)
434236Smckusick 
444465Smckusic ino_t	startinum;		/* blk num of first in raw area */
454236Smckusick 
464236Smckusick struct bufarea {
474236Smckusick 	struct bufarea	*b_next;		/* must be first */
484236Smckusick 	daddr_t	b_bno;
494236Smckusick 	int	b_size;
504236Smckusick 	union {
515325Smckusic 		char	b_buf[MAXBSIZE];	/* buffer space */
524236Smckusick 		short	b_lnks[SPERB];		/* link counts */
535325Smckusic 		daddr_t	b_indir[MAXNINDIR];	/* indirect block */
544236Smckusick 		struct	fs b_fs;		/* super block */
554236Smckusick 		struct	cg b_cg;		/* cylinder group */
565325Smckusic 		struct dinode b_dinode[MAXINOPB]; /* inode block */
574236Smckusick 	} b_un;
584236Smckusick 	char	b_dirty;
594236Smckusick };
604236Smckusick 
614236Smckusick typedef struct bufarea BUFAREA;
624236Smckusick 
634236Smckusick BUFAREA	inoblk;			/* inode blocks */
644236Smckusick BUFAREA	fileblk;		/* other blks in filesys */
654236Smckusick BUFAREA	sblk;			/* file system superblock */
664236Smckusick BUFAREA	cgblk;
674236Smckusick 
684236Smckusick #define	initbarea(x)	(x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
694236Smckusick #define	dirty(x)	(x)->b_dirty = 1
704236Smckusick #define	inodirty()	inoblk.b_dirty = 1
714236Smckusick #define	sbdirty()	sblk.b_dirty = 1
724236Smckusick #define	cgdirty()	cgblk.b_dirty = 1
734236Smckusick 
744236Smckusick #define	dirblk		fileblk.b_un
754236Smckusick #define	sblock		sblk.b_un.b_fs
764236Smckusick #define	cgrp		cgblk.b_un.b_cg
774236Smckusick 
784236Smckusick struct filecntl {
794236Smckusick 	int	rfdes;
804236Smckusick 	int	wfdes;
814236Smckusick 	int	mod;
824236Smckusick } dfile;			/* file descriptors for filesys */
834236Smckusick 
844236Smckusick #define	DUPTBLSIZE	100	/* num of dup blocks to remember */
854236Smckusick daddr_t	duplist[DUPTBLSIZE];	/* dup block table */
864236Smckusick daddr_t	*enddup;		/* next entry in dup table */
874236Smckusick daddr_t	*muldup;		/* multiple dups part of table */
884236Smckusick 
89*6837Smckusick #define	MAXLNCNT	50	/* num zero link cnts to remember */
904236Smckusick ino_t	badlncnt[MAXLNCNT];	/* table of inos with zero link cnts */
914236Smckusick ino_t	*badlnp;		/* next entry in table */
924236Smckusick 
934236Smckusick char	rawflg;
944236Smckusick char	nflag;			/* assume a no response */
954236Smckusick char	yflag;			/* assume a yes response */
964236Smckusick int	bflag;			/* location of alternate super block */
975381Smckusic int	debug;			/* output debugging info */
984236Smckusick char	preen;			/* just fix normal inconsistencies */
994236Smckusick char	rplyflag;		/* any questions asked? */
1004236Smckusick char	hotroot;		/* checking root device */
1014236Smckusick char	fixcg;			/* corrupted free list bit maps */
1024236Smckusick 
1036314Smckusick char	*blockmap;		/* ptr to primary blk allocation map */
1044236Smckusick char	*freemap;		/* ptr to secondary blk allocation map */
1054236Smckusick char	*statemap;		/* ptr to inode state table */
1064236Smckusick short	*lncntp;		/* ptr to link count table */
1074236Smckusick 
1084236Smckusick char	*pathp;			/* pointer to pathname position */
1094236Smckusick char	*thisname;		/* ptr to current pathname component */
1104236Smckusick char	*srchname;		/* name being searched for in dir */
1115877Smckusic char	pathname[BUFSIZ];
1124236Smckusick 
1134236Smckusick char	*lfname = "lost+found";
1144236Smckusick 
1154236Smckusick ino_t	inum;			/* inode we are currently working on */
1166634Smckusick ino_t	dnum;			/* directory inode currently being worked on */
1174236Smckusick ino_t	imax;			/* number of inodes */
1184236Smckusick ino_t	parentdir;		/* i number of parent directory */
1194236Smckusick ino_t	lastino;		/* hiwater mark of inodes */
1204236Smckusick ino_t	lfdir;			/* lost & found directory */
1214236Smckusick ino_t	orphan;			/* orphaned inode */
1224236Smckusick 
1234236Smckusick off_t	filsize;		/* num blks seen in file */
1244236Smckusick off_t	maxblk;			/* largest logical blk in file */
1256314Smckusick off_t	bmapsz;			/* num chars in blockmap */
1264236Smckusick 
1274236Smckusick daddr_t	n_ffree;		/* number of small free blocks */
1284236Smckusick daddr_t	n_bfree;		/* number of large free blocks */
1294236Smckusick daddr_t	n_blks;			/* number of blocks used */
1304236Smckusick daddr_t	n_files;		/* number of files seen */
1314236Smckusick daddr_t	n_index;
1324236Smckusick daddr_t	n_bad;
1334236Smckusick daddr_t	fmax;			/* number of blocks in the volume */
1344236Smckusick 
1354236Smckusick daddr_t	badblk;
1364236Smckusick daddr_t	dupblk;
1374236Smckusick 
1384236Smckusick int	inosumbad;
1394236Smckusick int	offsumbad;
1404465Smckusic int	frsumbad;
1416491Smckusick int	sbsumbad;
1424236Smckusick 
1434236Smckusick #define	zapino(x)	(*(x) = zino)
1444236Smckusick struct	dinode zino;
1454236Smckusick 
1464236Smckusick #define	setlncnt(x)	(lncntp[inum] = x)
1474236Smckusick #define	getlncnt()	(lncntp[inum])
1484236Smckusick #define	declncnt()	(--lncntp[inum])
1494236Smckusick 
1506314Smckusick #define	setbmap(x)	setbit(blockmap, x)
1516314Smckusick #define	getbmap(x)	isset(blockmap, x)
1526314Smckusick #define	clrbmap(x)	clrbit(blockmap, x)
1534236Smckusick 
1544236Smckusick #define	setfmap(x)	setbit(freemap, x)
1554236Smckusick #define	getfmap(x)	isset(freemap, x)
1564236Smckusick #define	clrfmap(x)	clrbit(freemap, x)
1574236Smckusick 
1584236Smckusick #define	setstate(x)	(statemap[inum] = x)
1594236Smckusick #define	getstate()	statemap[inum]
1604236Smckusick 
1614236Smckusick #define	DATA	1
1624236Smckusick #define	ADDR	0
1634236Smckusick 
1644236Smckusick #define	ALTERD	010
1654236Smckusick #define	KEEPON	04
1664236Smckusick #define	SKIP	02
1674236Smckusick #define	STOP	01
1684236Smckusick 
1694236Smckusick int	(*signal())();
1704236Smckusick long	lseek();
1714236Smckusick time_t	time();
1724236Smckusick DINODE	*ginode();
1734236Smckusick BUFAREA	*getblk();
1744236Smckusick int	dirscan();
1754236Smckusick int	findino();
1764236Smckusick int	catch();
1774236Smckusick int	mkentry();
1784236Smckusick int	chgdd();
1794236Smckusick int	pass1(), pass1b(), pass2(), pass4(), pass5();
1804236Smckusick int	(*pfunc)();
1814236Smckusick char	*rawname(), *rindex(), *unrawname();
1824606Smckusic extern int inside[], around[];
1835325Smckusic extern unsigned char *fragtbl[];
1844236Smckusick 
1854236Smckusick char	*devname;
1864236Smckusick 
1874236Smckusick main(argc, argv)
1884715Smckusic 	int	argc;
1894715Smckusic 	char	*argv[];
1904236Smckusick {
1914236Smckusick 	struct fstab *fsp;
1924236Smckusick 	int pid, passno, anygtr, sumstatus;
1934236Smckusick 
1944236Smckusick 	sync();
1954236Smckusick 	while (--argc > 0 && **++argv == '-') {
1964236Smckusick 		switch (*++*argv) {
1974236Smckusick 
1984236Smckusick 		case 'p':
1994236Smckusick 			preen++;
2004236Smckusick 			break;
2014236Smckusick 
2024236Smckusick 		case 'b':
2034236Smckusick 			bflag = atoi(argv[0]+1);
2044236Smckusick 			printf("Alternate super block location: %d\n", bflag);
2054236Smckusick 			break;
2064236Smckusick 
2075381Smckusic 		case 'd':
2085381Smckusic 			debug++;
2095381Smckusic 			break;
2105381Smckusic 
2114236Smckusick 		case 'n':	/* default no answer flag */
2124236Smckusick 		case 'N':
2134236Smckusick 			nflag++;
2144236Smckusick 			yflag = 0;
2154236Smckusick 			break;
2164236Smckusick 
2174236Smckusick 		case 'y':	/* default yes answer flag */
2184236Smckusick 		case 'Y':
2194236Smckusick 			yflag++;
2204236Smckusick 			nflag = 0;
2214236Smckusick 			break;
2224236Smckusick 
2234236Smckusick 		default:
2244236Smckusick 			errexit("%c option?\n", **argv);
2254236Smckusick 		}
2264236Smckusick 	}
2274236Smckusick 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
2284236Smckusick 		signal(SIGINT, catch);
2294236Smckusick 	if (argc) {
2304236Smckusick 		while (argc-- > 0) {
2314236Smckusick 			hotroot = 0;
2324236Smckusick 			check(*argv++);
2334236Smckusick 		}
2344236Smckusick 		exit(0);
2354236Smckusick 	}
2364236Smckusick 	sumstatus = 0;
2374236Smckusick 	passno = 1;
2384236Smckusick 	do {
2394236Smckusick 		anygtr = 0;
2404236Smckusick 		if (setfsent() == 0)
2414236Smckusick 			errexit("Can't open checklist file: %s\n", FSTAB);
2424236Smckusick 		while ((fsp = getfsent()) != 0) {
2434236Smckusick 			if (strcmp(fsp->fs_type, FSTAB_RW) &&
2444236Smckusick 			    strcmp(fsp->fs_type, FSTAB_RO))
2454236Smckusick 				continue;
2464236Smckusick 			if (preen == 0 ||
2474236Smckusick 			    passno == 1 && fsp->fs_passno == passno) {
2484236Smckusick 				if (blockcheck(fsp->fs_spec) == 0 && preen)
2494236Smckusick 					exit(8);
2504236Smckusick 			} else if (fsp->fs_passno > passno)
2514236Smckusick 				anygtr = 1;
2524236Smckusick 			else if (fsp->fs_passno == passno) {
2534236Smckusick 				pid = fork();
2544236Smckusick 				if (pid < 0) {
2554236Smckusick 					perror("fork");
2564236Smckusick 					exit(8);
2574236Smckusick 				}
2584236Smckusick 				if (pid == 0)
2594236Smckusick 					if (blockcheck(fsp->fs_spec)==0)
2604236Smckusick 						exit(8);
2614236Smckusick 					else
2624236Smckusick 						exit(0);
2634236Smckusick 			}
2644236Smckusick 		}
2654236Smckusick 		if (preen) {
2664236Smckusick 			int status;
2674236Smckusick 			while (wait(&status) != -1)
2684236Smckusick 				sumstatus |= status;
2694236Smckusick 		}
2704236Smckusick 		passno++;
2714236Smckusick 	} while (anygtr);
2724236Smckusick 	if (sumstatus)
2734236Smckusick 		exit(8);
2744236Smckusick 	endfsent();
2754236Smckusick 	exit(0);
2764236Smckusick }
2774236Smckusick 
2784236Smckusick blockcheck(name)
2794236Smckusick 	char *name;
2804236Smckusick {
2816489Smckusick 	struct stat stslash, stblock, stchar;
2824236Smckusick 	char *raw;
2834236Smckusick 	int looped = 0;
2844236Smckusick 
2854236Smckusick 	hotroot = 0;
2864236Smckusick 	if (stat("/", &stslash) < 0){
2874236Smckusick 		error("Can't stat root\n");
2884236Smckusick 		return (0);
2894236Smckusick 	}
2904236Smckusick retry:
2914236Smckusick 	if (stat(name, &stblock) < 0){
2924236Smckusick 		error("Can't stat %s\n", name);
2934236Smckusick 		return (0);
2944236Smckusick 	}
2954236Smckusick 	if (stblock.st_mode & S_IFBLK) {
2964236Smckusick 		raw = rawname(name);
2974236Smckusick 		if (stat(raw, &stchar) < 0){
2984236Smckusick 			error("Can't stat %s\n", raw);
2994236Smckusick 			return (0);
3004236Smckusick 		}
3014236Smckusick 		if (stchar.st_mode & S_IFCHR) {
3024236Smckusick 			if (stslash.st_dev == stblock.st_rdev) {
3034236Smckusick 				hotroot++;
3044236Smckusick 				raw = unrawname(name);
3054236Smckusick 			}
3064236Smckusick 			check(raw);
3074236Smckusick 			return (1);
3084236Smckusick 		} else {
3094236Smckusick 			error("%s is not a character device\n", raw);
3104236Smckusick 			return (0);
3114236Smckusick 		}
3124236Smckusick 	} else if (stblock.st_mode & S_IFCHR) {
3134236Smckusick 		if (looped) {
3144236Smckusick 			error("Can't make sense out of name %s\n", name);
3154236Smckusick 			return (0);
3164236Smckusick 		}
3174236Smckusick 		name = unrawname(name);
3184236Smckusick 		looped++;
3194236Smckusick 		goto retry;
3204236Smckusick 	}
3214236Smckusick 	error("Can't make sense out of name %s\n", name);
3224236Smckusick 	return (0);
3234236Smckusick }
3244236Smckusick 
3254236Smckusick char *
3264236Smckusick unrawname(cp)
3274236Smckusick 	char *cp;
3284236Smckusick {
3294236Smckusick 	char *dp = rindex(cp, '/');
3306489Smckusick 	struct stat stb;
3314236Smckusick 
3324236Smckusick 	if (dp == 0)
3334236Smckusick 		return (cp);
3344236Smckusick 	if (stat(cp, &stb) < 0)
3354236Smckusick 		return (cp);
3364236Smckusick 	if ((stb.st_mode&S_IFMT) != S_IFCHR)
3374236Smckusick 		return (cp);
3384236Smckusick 	if (*(dp+1) != 'r')
3394236Smckusick 		return (cp);
3404236Smckusick 	strcpy(dp+1, dp+2);
3414236Smckusick 	return (cp);
3424236Smckusick }
3434236Smckusick 
3444236Smckusick char *
3454236Smckusick rawname(cp)
3464236Smckusick 	char *cp;
3474236Smckusick {
3484236Smckusick 	static char rawbuf[32];
3494236Smckusick 	char *dp = rindex(cp, '/');
3504236Smckusick 
3514236Smckusick 	if (dp == 0)
3524236Smckusick 		return (0);
3534236Smckusick 	*dp = 0;
3544236Smckusick 	strcpy(rawbuf, cp);
3554236Smckusick 	*dp = '/';
3564236Smckusick 	strcat(rawbuf, "/r");
3574236Smckusick 	strcat(rawbuf, dp+1);
3584236Smckusick 	return (rawbuf);
3594236Smckusick }
3604236Smckusick 
3614236Smckusick check(dev)
3624236Smckusick 	char *dev;
3634236Smckusick {
3644236Smckusick 	register DINODE *dp;
3654236Smckusick 	register ino_t *blp;
3664236Smckusick 	register int i, n;
3674236Smckusick 	ino_t savino;
3684236Smckusick 	int b, c;
3694236Smckusick 	daddr_t d, s;
3704236Smckusick 
3714236Smckusick 	devname = dev;
3724236Smckusick 	if (setup(dev) == 0) {
3734236Smckusick 		if (preen)
3744236Smckusick 			pfatal("CAN'T CHECK DEVICE.");
3754236Smckusick 		return;
3764236Smckusick 	}
3774236Smckusick /* 1 */
378*6837Smckusick 	if (preen == 0) {
379*6837Smckusick 		printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
3804236Smckusick 		if (hotroot)
3814236Smckusick 			printf("** Root file system\n");
3824236Smckusick 		printf("** Phase 1 - Check Blocks and Sizes\n");
3834236Smckusick 	}
3844236Smckusick 	pfunc = pass1;
3854236Smckusick 	inum = 0;
3866533Smckusick 	n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
3874236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
3885381Smckusic 		if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
3894236Smckusick 			continue;
3906533Smckusick 		if (debug && cgrp.cg_magic != CG_MAGIC)
3916533Smckusick 			printf("cg %d: bad magic number\n", c);
3924236Smckusick 		n = 0;
3934465Smckusic 		for (i = 0; i < sblock.fs_ipg; i++, inum++) {
3944465Smckusic 			dp = ginode();
3954465Smckusic 			if (dp == NULL)
3964465Smckusic 				continue;
3975944Smckusic 			n++;
3984236Smckusick 			if (ALLOC) {
3994236Smckusick 				if (!isset(cgrp.cg_iused, i)) {
4005381Smckusic 					if (debug)
4015381Smckusic 						printf("%d bad, not used\n",
4025381Smckusic 						    inum);
4034236Smckusick 					inosumbad++;
4044236Smckusick 				}
4055944Smckusic 				n--;
4064236Smckusick 				lastino = inum;
4074236Smckusick 				if (ftypeok(dp) == 0) {
4084236Smckusick 					pfatal("UNKNOWN FILE TYPE I=%u", inum);
4094236Smckusick 					if (reply("CLEAR") == 1) {
4104236Smckusick 						zapino(dp);
4114236Smckusick 						inodirty();
4124236Smckusick 						inosumbad++;
4134236Smckusick 					}
4144236Smckusick 					continue;
4154236Smckusick 				}
4164236Smckusick 				n_files++;
4174236Smckusick 				if (setlncnt(dp->di_nlink) <= 0) {
4184236Smckusick 					if (badlnp < &badlncnt[MAXLNCNT])
4194236Smckusick 						*badlnp++ = inum;
4204236Smckusick 					else {
4214236Smckusick 						pfatal("LINK COUNT TABLE OVERFLOW");
4224236Smckusick 						if (reply("CONTINUE") == 0)
4234236Smckusick 							errexit("");
4244236Smckusick 					}
4254236Smckusick 				}
4265877Smckusic 				setstate(DIRCT ? DSTATE : FSTATE);
4274236Smckusick 				badblk = dupblk = 0; filsize = 0; maxblk = 0;
4284236Smckusick 				ckinode(dp, ADDR);
4294236Smckusick 			} else {
4304236Smckusick 				if (isset(cgrp.cg_iused, i)) {
4315381Smckusic 					if (debug)
4325381Smckusic 						printf("%d bad, marked used\n",
4335381Smckusic 						    inum);
4344236Smckusick 					inosumbad++;
4354465Smckusic 					n--;
4364236Smckusick 				}
4374236Smckusick 				if (dp->di_mode != 0) {
4384236Smckusick 					pfatal("PARTIALLY ALLOCATED INODE I=%u", inum);
4394236Smckusick 					if (reply("CLEAR") == 1) {
4404236Smckusick 						zapino(dp);
4414236Smckusick 						inodirty();
4424236Smckusick 						inosumbad++;
4434236Smckusick 					}
4444236Smckusick 				}
4454236Smckusick 			}
4464236Smckusick 		}
4474789Smckusic 		if (n != cgrp.cg_cs.cs_nifree) {
4485381Smckusic 			if (debug)
4495944Smckusic 				printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n",
4505381Smckusic 				    c, cgrp.cg_cs.cs_nifree, n);
4514236Smckusick 			inosumbad++;
4524236Smckusick 		}
4536491Smckusick 		if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree
4546491Smckusick 		  || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree
4556491Smckusick 		  || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree
4566491Smckusick 		  || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir)
4576491Smckusick 			sbsumbad++;
4584236Smckusick 	}
4594236Smckusick /* 1b */
4604236Smckusick 	if (enddup != &duplist[0]) {
4614236Smckusick 		if (preen)
4624236Smckusick 			pfatal("INTERNAL ERROR: dups with -p");
4634236Smckusick 		printf("** Phase 1b - Rescan For More DUPS\n");
4644236Smckusick 		pfunc = pass1b;
4654236Smckusick 		inum = 0;
4664236Smckusick 		for (c = 0; c < sblock.fs_ncg; c++) {
4674465Smckusic 			for (i = 0; i < sblock.fs_ipg; i++, inum++) {
4684465Smckusic 				dp = ginode();
4694465Smckusic 				if (dp == NULL)
4704465Smckusic 					continue;
4714236Smckusick 				if (getstate() != USTATE &&
4724236Smckusick 				    (ckinode(dp, ADDR) & STOP))
4734236Smckusick 					goto out1b;
4744465Smckusic 			}
4754236Smckusick 		}
4764236Smckusick 	}
4774236Smckusick out1b:
4784465Smckusic 	flush(&dfile, &inoblk);
4794236Smckusick /* 2 */
4804236Smckusick 	if (preen == 0)
4814236Smckusick 		printf("** Phase 2 - Check Pathnames\n");
4824236Smckusick 	inum = ROOTINO;
4834236Smckusick 	thisname = pathp = pathname;
4844236Smckusick 	pfunc = pass2;
4854236Smckusick 	switch (getstate()) {
4864236Smckusick 
4874236Smckusick 	case USTATE:
4884236Smckusick 		errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
4894236Smckusick 
4904236Smckusick 	case FSTATE:
4914236Smckusick 		pfatal("ROOT INODE NOT DIRECTORY");
4924236Smckusick 		if (reply("FIX") == 0 || (dp = ginode()) == NULL)
4934236Smckusick 			errexit("");
4944236Smckusick 		dp->di_mode &= ~IFMT;
4954236Smckusick 		dp->di_mode |= IFDIR;
4964236Smckusick 		inodirty();
4974236Smckusick 		inosumbad++;
4984236Smckusick 		setstate(DSTATE);
4994236Smckusick 		/* fall into ... */
5004236Smckusick 
5014236Smckusick 	case DSTATE:
5024236Smckusick 		descend();
5034236Smckusick 		break;
5044236Smckusick 
5054236Smckusick 	case CLEAR:
5064236Smckusick 		pfatal("DUPS/BAD IN ROOT INODE");
5074236Smckusick 		printf("\n");
5084236Smckusick 		if (reply("CONTINUE") == 0)
5094236Smckusick 			errexit("");
5104236Smckusick 		setstate(DSTATE);
5114236Smckusick 		descend();
5124236Smckusick 	}
5134236Smckusick /* 3 */
5144236Smckusick 	if (preen == 0)
5154236Smckusick 		printf("** Phase 3 - Check Connectivity\n");
5164236Smckusick 	for (inum = ROOTINO; inum <= lastino; inum++) {
5174236Smckusick 		if (getstate() == DSTATE) {
5184236Smckusick 			pfunc = findino;
5194236Smckusick 			srchname = "..";
5204236Smckusick 			savino = inum;
5214236Smckusick 			do {
5224236Smckusick 				orphan = inum;
5234236Smckusick 				if ((dp = ginode()) == NULL)
5244236Smckusick 					break;
5254236Smckusick 				filsize = dp->di_size;
5264236Smckusick 				parentdir = 0;
5274236Smckusick 				ckinode(dp, DATA);
5284236Smckusick 				if ((inum = parentdir) == 0)
5294236Smckusick 					break;
5304236Smckusick 			} while (getstate() == DSTATE);
5314236Smckusick 			inum = orphan;
5324236Smckusick 			if (linkup() == 1) {
5334236Smckusick 				thisname = pathp = pathname;
5344236Smckusick 				*pathp++ = '?';
5354236Smckusick 				pfunc = pass2;
5364236Smckusick 				descend();
5374236Smckusick 			}
5384236Smckusick 			inum = savino;
5394236Smckusick 		}
5404236Smckusick 	}
5414236Smckusick /* 4 */
5424236Smckusick 	if (preen == 0)
5434236Smckusick 		printf("** Phase 4 - Check Reference Counts\n");
5444236Smckusick 	pfunc = pass4;
5454236Smckusick 	for (inum = ROOTINO; inum <= lastino; inum++) {
5464236Smckusick 		switch (getstate()) {
5474236Smckusick 
5484236Smckusick 		case FSTATE:
5494236Smckusick 			if (n = getlncnt())
5504236Smckusick 				adjust((short)n);
5514236Smckusick 			else {
5524236Smckusick 				for (blp = badlncnt;blp < badlnp; blp++)
5534236Smckusick 					if (*blp == inum) {
5544236Smckusick 						clri("UNREF", 1);
5554236Smckusick 						break;
5564236Smckusick 					}
5574236Smckusick 			}
5584236Smckusick 			break;
5594236Smckusick 
5604236Smckusick 		case DSTATE:
5614236Smckusick 			clri("UNREF", 1);
5624236Smckusick 			break;
5634236Smckusick 
5644236Smckusick 		case CLEAR:
5654236Smckusick 			clri("BAD/DUP", 1);
5664236Smckusick 			break;
5674236Smckusick 		}
5684236Smckusick 	}
5695337Smckusic 	if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) {
5704236Smckusick 		pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
5714236Smckusick 		if (preen)
5724236Smckusick 			printf(" (FIXED)\n");
5734236Smckusick 		if (preen || reply("FIX") == 1) {
5745944Smckusic 			sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files;
5754236Smckusick 			sbdirty();
5764236Smckusick 		}
5774236Smckusick 	}
5784236Smckusick 	flush(&dfile, &fileblk);
5794236Smckusick 
5804236Smckusick /* 5 */
5814236Smckusick 	if (preen == 0)
5824236Smckusick 		printf("** Phase 5 - Check Cyl groups\n");
5836314Smckusick 	copy(blockmap, freemap, (unsigned)bmapsz);
5844236Smckusick 	dupblk = 0;
5855381Smckusic 	n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0));
5864236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
5875381Smckusic 		daddr_t cbase = cgbase(&sblock, c);
5884236Smckusick 		short bo[MAXCPG][NRPOS];
5895371Smckusic 		long botot[MAXCPG];
5905325Smckusic 		long frsum[MAXFRAG];
5914465Smckusic 		int blk;
5924465Smckusic 
5935371Smckusic 		for (n = 0; n < sblock.fs_cpg; n++) {
5945371Smckusic 			botot[n] = 0;
5954236Smckusick 			for (i = 0; i < NRPOS; i++)
5964236Smckusick 				bo[n][i] = 0;
5975371Smckusic 		}
5985325Smckusic 		for (i = 0; i < sblock.fs_frag; i++) {
5994465Smckusic 			frsum[i] = 0;
6004465Smckusic 		}
6014465Smckusic 		/*
6026533Smckusick 		 * need to account for the super blocks
6034465Smckusic 		 * which appear (inaccurately) bad
6044465Smckusic 		 */
6056533Smckusick 		n_bad += cgtod(&sblock, c) - cgsblock(&sblock, c);
6065381Smckusic 		if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
6074236Smckusick 			continue;
6086533Smckusick 		if (debug && cgrp.cg_magic != CG_MAGIC)
6096533Smckusick 			printf("cg %d: bad magic number\n", c);
6105325Smckusic 		for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
6115325Smckusic 			if (isblock(&sblock, cgrp.cg_free, b/sblock.fs_frag)) {
6125325Smckusic 				if (pass5(cbase+b, sblock.fs_frag) == STOP)
6134236Smckusick 					goto out5;
6144236Smckusick 				/* this is clumsy ... */
6155325Smckusic 				n_ffree -= sblock.fs_frag;
6164236Smckusick 				n_bfree++;
6175371Smckusic 				botot[cbtocylno(&sblock, b)]++;
6185363Smckusic 				bo[cbtocylno(&sblock, b)]
6195363Smckusic 				    [cbtorpos(&sblock, b)]++;
6204465Smckusic 			} else {
6215325Smckusic 				for (d = 0; d < sblock.fs_frag; d++)
6224236Smckusick 					if (isset(cgrp.cg_free, b+d))
6234236Smckusick 						if (pass5(cbase+b+d,1) == STOP)
6244236Smckusick 							goto out5;
6254465Smckusic 				blk = ((cgrp.cg_free[b / NBBY] >> (b % NBBY)) &
6265325Smckusic 				       (0xff >> (NBBY - sblock.fs_frag)));
6274465Smckusic 				if (blk != 0)
6285325Smckusic 					fragacct(&sblock, blk, frsum, 1);
6294465Smckusic 			}
6304236Smckusick 		}
6315325Smckusic 		for (i = 0; i < sblock.fs_frag; i++) {
6324465Smckusic 			if (cgrp.cg_frsum[i] != frsum[i]) {
6335381Smckusic 				if (debug)
6345381Smckusic 					printf("cg[%d].cg_frsum[%d] have %d calc %d\n",
6355381Smckusic 					    c, i, cgrp.cg_frsum[i], frsum[i]);
6364465Smckusic 				frsumbad++;
6374465Smckusic 			}
6384465Smckusic 		}
6395371Smckusic 		for (n = 0; n < sblock.fs_cpg; n++) {
6405371Smckusic 			if (botot[n] != cgrp.cg_btot[n]) {
6415381Smckusic 				if (debug)
6425381Smckusic 					printf("cg[%d].cg_btot[%d] have %d calc %d\n",
6435381Smckusic 					    c, n, cgrp.cg_btot[n], botot[n]);
6445371Smckusic 				offsumbad++;
6455371Smckusic 			}
6464236Smckusick 			for (i = 0; i < NRPOS; i++)
6474236Smckusick 				if (bo[n][i] != cgrp.cg_b[n][i]) {
6485381Smckusic 					if (debug)
6495381Smckusic 						printf("cg[%d].cg_b[%d][%d] have %d calc %d\n",
6505381Smckusic 						    c, n, i, cgrp.cg_b[n][i],
6515381Smckusic 						    bo[n][i]);
6524236Smckusick 					offsumbad++;
6534236Smckusick 				}
6545371Smckusic 		}
6554236Smckusick 	}
6564236Smckusick out5:
6574236Smckusick 	if (dupblk)
6584236Smckusick 		pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk);
6594236Smckusick 	if (fixcg == 0) {
6605325Smckusic 		if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) {
6614236Smckusick 			pwarn("%ld BLK(S) MISSING\n", fmax - b);
6624236Smckusick 			fixcg = 1;
6636491Smckusick 		} else if (inosumbad + offsumbad + frsumbad + sbsumbad) {
6646491Smckusick 			pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n",
6654236Smckusick 			    inosumbad ? "(INODE FREE) " : "",
6664465Smckusic 			    offsumbad ? "(BLOCK OFFSETS) " : "",
6676491Smckusick 			    frsumbad ? "(FRAG SUMMARIES) " : "",
6686491Smckusick 			    sbsumbad ? "(SUPER BLOCK SUMMARIES) " : "");
6694236Smckusick 			fixcg = 1;
6704789Smckusic 		} else if (n_ffree != sblock.fs_cstotal.cs_nffree ||
6714789Smckusic 		    n_bfree != sblock.fs_cstotal.cs_nbfree) {
6724236Smckusick 			pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK");
6734236Smckusick 			if (preen)
6744236Smckusick 				printf(" (FIXED)\n");
6754236Smckusick 			if (preen || reply("FIX") == 1) {
6764789Smckusic 				sblock.fs_cstotal.cs_nffree = n_ffree;
6774789Smckusic 				sblock.fs_cstotal.cs_nbfree = n_bfree;
6784236Smckusick 				sbdirty();
6794236Smckusick 			}
6804236Smckusick 		}
6814236Smckusick 	}
6824236Smckusick 	if (fixcg) {
6834236Smckusick 		pwarn("BAD CYLINDER GROUPS");
6844236Smckusick 		if (preen)
6854236Smckusick 			printf(" (SALVAGED)\n");
6864236Smckusick 		else if (reply("SALVAGE") == 0)
6874236Smckusick 			fixcg = 0;
6884236Smckusick 	}
6894236Smckusick 
6904236Smckusick 	if (fixcg) {
6914236Smckusick 		if (preen == 0)
6924236Smckusick 			printf("** Phase 6 - Salvage Cylinder Groups\n");
6934236Smckusick 		makecg();
6944789Smckusic 		n_ffree = sblock.fs_cstotal.cs_nffree;
6954789Smckusic 		n_bfree = sblock.fs_cstotal.cs_nbfree;
6964236Smckusick 	}
6974236Smckusick 
6984236Smckusick 	pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n",
6996533Smckusick 	    n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_fsize),
7005325Smckusic 	    n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree);
7014236Smckusick 	if (dfile.mod) {
7024236Smckusick 		time(&sblock.fs_time);
7034236Smckusick 		sbdirty();
7044236Smckusick 	}
7054236Smckusick 	ckfini();
7064236Smckusick 	sync();
7074236Smckusick 	if (dfile.mod && preen == 0)
7084236Smckusick 		printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
7096314Smckusick 	free(blockmap);
7104236Smckusick 	free(freemap);
7114236Smckusick 	free(statemap);
7124236Smckusick 	free(lncntp);
7134236Smckusick }
7144236Smckusick 
7154236Smckusick /* VARARGS1 */
7164236Smckusick error(s1, s2, s3, s4)
7174715Smckusic 	char *s1;
7184236Smckusick {
7194236Smckusick 
7204236Smckusick 	printf(s1, s2, s3, s4);
7214236Smckusick }
7224236Smckusick 
7234236Smckusick /* VARARGS1 */
7244236Smckusick errexit(s1, s2, s3, s4)
7254715Smckusic 	char *s1;
7264236Smckusick {
7274236Smckusick 	error(s1, s2, s3, s4);
7284236Smckusick 	exit(8);
7294236Smckusick }
7304236Smckusick 
7314236Smckusick /*
7324236Smckusick  * An inconsistency occured which shouldn't during normal operations.
7334236Smckusick  * Die if preening, otw just printf.
7344236Smckusick  */
7354236Smckusick /* VARARGS1 */
7364236Smckusick pfatal(s, a1, a2, a3)
7374236Smckusick 	char *s;
7384236Smckusick {
7394236Smckusick 
7404236Smckusick 	if (preen) {
7414236Smckusick 		printf("%s: ", devname);
7424236Smckusick 		printf(s, a1, a2, a3);
7434236Smckusick 		printf("\n");
7444236Smckusick 		preendie();
7454236Smckusick 	}
7464236Smckusick 	printf(s, a1, a2, a3);
7474236Smckusick }
7484236Smckusick 
7494236Smckusick preendie()
7504236Smckusick {
7514236Smckusick 
7524236Smckusick 	printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
7534236Smckusick 	exit(8);
7544236Smckusick }
7554236Smckusick 
7564236Smckusick /*
7574236Smckusick  * Pwarn is like printf when not preening,
7584236Smckusick  * or a warning (preceded by filename) when preening.
7594236Smckusick  */
7604236Smckusick /* VARARGS1 */
761*6837Smckusick pwarn(s, a1, a2, a3, a4, a5, a6)
7624236Smckusick 	char *s;
7634236Smckusick {
7644236Smckusick 
7654236Smckusick 	if (preen)
7664236Smckusick 		printf("%s: ", devname);
767*6837Smckusick 	printf(s, a1, a2, a3, a4, a5, a6);
7684236Smckusick }
7694236Smckusick 
7704236Smckusick ckinode(dp, flg)
7714236Smckusick 	DINODE *dp;
7724236Smckusick 	register flg;
7734236Smckusick {
7744236Smckusick 	register daddr_t *ap;
7754236Smckusick 	register ret;
7765956Smckusic 	int (*func)(), n, ndb, size, offset;
7776634Smckusick 	ino_t number = inum;
7786634Smckusick 	DINODE dino;
7794236Smckusick 
7804236Smckusick 	if (SPECIAL)
7814236Smckusick 		return (KEEPON);
7826634Smckusick 	dino = *dp;
7834236Smckusick 	func = (flg == ADDR) ? pfunc : dirscan;
7846634Smckusick 	ndb = howmany(dino.di_size, sblock.fs_bsize);
7856634Smckusick 	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
7866634Smckusick 		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
7875956Smckusic 			size = numfrags(&sblock, fragroundup(&sblock, offset));
7884236Smckusick 		else
7895325Smckusic 			size = sblock.fs_frag;
7906634Smckusick 		dnum = number;
7914236Smckusick 		if (*ap && (ret = (*func)(*ap, size)) & STOP)
7924236Smckusick 			return (ret);
7934236Smckusick 	}
7946634Smckusick 	for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) {
7956634Smckusick 		dnum = number;
7966634Smckusick 		if (*ap && (ret = iblock(*ap, n, flg, dino.di_size - sblock.fs_bsize * NDADDR)) & STOP)
7974236Smckusick 			return (ret);
7984236Smckusick 	}
7994236Smckusick 	return (KEEPON);
8004236Smckusick }
8014236Smckusick 
8024236Smckusick iblock(blk, ilevel, flg, isize)
8034236Smckusick 	daddr_t blk;
8044236Smckusick 	register ilevel;
8054236Smckusick 	int isize;
8064236Smckusick {
8074236Smckusick 	register daddr_t *ap;
8084236Smckusick 	register daddr_t *aplim;
8094428Smckusic 	register int i, n;
8104236Smckusick 	int (*func)(), nif;
8114236Smckusick 	BUFAREA ib;
8124236Smckusick 
8134236Smckusick 	if (flg == ADDR) {
8144236Smckusick 		func = pfunc;
8155325Smckusic 		if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0)
8164236Smckusick 			return (n);
8174236Smckusick 	} else
8184236Smckusick 		func = dirscan;
8194236Smckusick 	if (outrange(blk))		/* protect thyself */
8204236Smckusick 		return (SKIP);
8214236Smckusick 	initbarea(&ib);
8225325Smckusic 	if (getblk(&ib, blk, sblock.fs_bsize) == NULL)
8234236Smckusick 		return (SKIP);
8244236Smckusick 	ilevel--;
8254428Smckusic 	if (ilevel == 0) {
8265956Smckusic 		nif = lblkno(&sblock, isize) + 1;
8274428Smckusic 	} else /* ilevel == 1 */ {
8285325Smckusic 		nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1;
8294428Smckusic 	}
8305325Smckusic 	if (nif > NINDIR(&sblock))
8315325Smckusic 		nif = NINDIR(&sblock);
8324428Smckusic 	aplim = & ib.b_un.b_indir[nif];
8334428Smckusic 	for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
8344236Smckusick 		if (*ap) {
8354236Smckusick 			if (ilevel > 0)
8365325Smckusic 				n = iblock(*ap, ilevel, flg, isize - i * NINDIR(&sblock) * sblock.fs_bsize);
8374236Smckusick 			else
8385325Smckusic 				n = (*func)(*ap, sblock.fs_frag);
8394236Smckusick 			if (n & STOP)
8404236Smckusick 				return (n);
8414236Smckusick 		}
8424236Smckusick 	return (KEEPON);
8434236Smckusick }
8444236Smckusick 
8454236Smckusick pass1(blk, size)
8464236Smckusick 	daddr_t blk;
8474236Smckusick 	int size;
8484236Smckusick {
8494236Smckusick 	register daddr_t *dlp;
8504236Smckusick 	int res = KEEPON;
8514236Smckusick 
8524236Smckusick 	for (; size > 0; blk++, size--) {
8534236Smckusick 		if (outrange(blk)) {
8544236Smckusick 			blkerr("BAD", blk);
8554236Smckusick 			if (++badblk >= MAXBAD) {
8564236Smckusick 				printf("EXCESSIVE BAD BLKS I=%u", inum);
8574236Smckusick 				if (reply("CONTINUE") == 0)
8584236Smckusick 					errexit("");
8594236Smckusick 				return (STOP);
8604236Smckusick 			}
8614236Smckusick 			res = SKIP;
8624236Smckusick 		} else if (getbmap(blk)) {
8634236Smckusick 			blkerr("DUP", blk);
8644236Smckusick 			if (++dupblk >= MAXDUP) {
8654236Smckusick 				printf("EXCESSIVE DUP BLKS I=%u", inum);
8664236Smckusick 				if (reply("CONTINUE") == 0)
8674236Smckusick 					errexit("");
8684236Smckusick 				return (STOP);
8694236Smckusick 			}
8704236Smckusick 			if (enddup >= &duplist[DUPTBLSIZE]) {
8714236Smckusick 				printf("DUP TABLE OVERFLOW.");
8724236Smckusick 				if (reply("CONTINUE") == 0)
8734236Smckusick 					errexit("");
8744236Smckusick 				return (STOP);
8754236Smckusick 			}
8764236Smckusick 			for (dlp = duplist; dlp < muldup; dlp++)
8774236Smckusick 				if (*dlp == blk) {
8784236Smckusick 					*enddup++ = blk;
8794236Smckusick 					break;
8804236Smckusick 				}
8814236Smckusick 			if (dlp >= muldup) {
8824236Smckusick 				*enddup++ = *muldup;
8834236Smckusick 				*muldup++ = blk;
8844236Smckusick 			}
8854236Smckusick 		} else {
8864236Smckusick 			n_blks++;
8874236Smckusick 			setbmap(blk);
8884236Smckusick 		}
8894236Smckusick 		filsize++;
8904236Smckusick 	}
8914236Smckusick 	return (res);
8924236Smckusick }
8934236Smckusick 
8944236Smckusick pass1b(blk, size)
8954236Smckusick 	daddr_t blk;
8964236Smckusick 	int size;
8974236Smckusick {
8984236Smckusick 	register daddr_t *dlp;
8994236Smckusick 	int res = KEEPON;
9004236Smckusick 
9014236Smckusick 	for (; size > 0; blk++, size--) {
9024236Smckusick 		if (outrange(blk))
9034236Smckusick 			res = SKIP;
9044236Smckusick 		for (dlp = duplist; dlp < muldup; dlp++)
9054236Smckusick 			if (*dlp == blk) {
9064236Smckusick 				blkerr("DUP", blk);
9074236Smckusick 				*dlp = *--muldup;
9084236Smckusick 				*muldup = blk;
9094236Smckusick 				if (muldup == duplist)
9104236Smckusick 					return (STOP);
9114236Smckusick 			}
9124236Smckusick 	}
9134236Smckusick 	return (res);
9144236Smckusick }
9154236Smckusick 
9164236Smckusick pass2(dirp)
9174236Smckusick 	register DIRECT *dirp;
9184236Smckusick {
9194236Smckusick 	register char *p;
9204236Smckusick 	register n;
9214236Smckusick 	DINODE *dp;
9224236Smckusick 
9234236Smckusick 	if ((inum = dirp->d_ino) == 0)
9244236Smckusick 		return (KEEPON);
9254236Smckusick 	thisname = pathp;
9265877Smckusic 	for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; )
9274236Smckusick 		if ((*pathp++ = *p++) == 0) {
9284236Smckusick 			--pathp;
9294236Smckusick 			break;
9304236Smckusick 		}
9314236Smckusick 	*pathp = 0;
9324236Smckusick 	n = 0;
9334715Smckusic 	if (inum > imax || inum <= 0)
9344236Smckusick 		n = direrr("I OUT OF RANGE");
9354236Smckusick 	else {
9364236Smckusick again:
9374236Smckusick 		switch (getstate()) {
9384236Smckusick 		case USTATE:
9394236Smckusick 			n = direrr("UNALLOCATED");
9404236Smckusick 			break;
9414236Smckusick 
9424236Smckusick 		case CLEAR:
9434236Smckusick 			if ((n = direrr("DUP/BAD")) == 1)
9444236Smckusick 				break;
9454236Smckusick 			if ((dp = ginode()) == NULL)
9464236Smckusick 				break;
9475877Smckusic 			setstate(DIRCT ? DSTATE : FSTATE);
9484236Smckusick 			goto again;
9494236Smckusick 
9504236Smckusick 		case FSTATE:
9514236Smckusick 			declncnt();
9524236Smckusick 			break;
9534236Smckusick 
9544236Smckusick 		case DSTATE:
9554236Smckusick 			declncnt();
9564236Smckusick 			descend();
9574236Smckusick 			break;
9584236Smckusick 		}
9594236Smckusick 	}
9604236Smckusick 	pathp = thisname;
9614236Smckusick 	if (n == 0)
9624236Smckusick 		return (KEEPON);
9634236Smckusick 	dirp->d_ino = 0;
9644236Smckusick 	return (KEEPON|ALTERD);
9654236Smckusick }
9664236Smckusick 
9674236Smckusick pass4(blk, size)
9684715Smckusic 	daddr_t blk;
9694236Smckusick {
9704236Smckusick 	register daddr_t *dlp;
9714236Smckusick 	int res = KEEPON;
9724236Smckusick 
9734236Smckusick 	for (; size > 0; blk++, size--) {
9744236Smckusick 		if (outrange(blk))
9754236Smckusick 			res = SKIP;
9764236Smckusick 		else if (getbmap(blk)) {
9774236Smckusick 			for (dlp = duplist; dlp < enddup; dlp++)
9784236Smckusick 				if (*dlp == blk) {
9794236Smckusick 					*dlp = *--enddup;
9804236Smckusick 					return (KEEPON);
9814236Smckusick 				}
9824236Smckusick 			clrbmap(blk);
9834236Smckusick 			n_blks--;
9844236Smckusick 		}
9854236Smckusick 	}
9864236Smckusick 	return (res);
9874236Smckusick }
9884236Smckusick 
9894236Smckusick pass5(blk, size)
9904236Smckusick 	daddr_t blk;
9914236Smckusick 	int size;
9924236Smckusick {
9934236Smckusick 	int res = KEEPON;
9944236Smckusick 
9954236Smckusick 	for (; size > 0; blk++, size--) {
9964236Smckusick 		if (outrange(blk)) {
9974236Smckusick 			fixcg = 1;
9984236Smckusick 			if (preen)
9994236Smckusick 				pfatal("BAD BLOCKS IN BIT MAPS.");
10004236Smckusick 			if (++badblk >= MAXBAD) {
10014236Smckusick 				printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
10024236Smckusick 				if (reply("CONTINUE") == 0)
10034236Smckusick 					errexit("");
10044236Smckusick 				return (STOP);
10054236Smckusick 			}
10064236Smckusick 		} else if (getfmap(blk)) {
10074236Smckusick 			fixcg = 1;
10084236Smckusick 			if (++dupblk >= DUPTBLSIZE) {
10094236Smckusick 				printf("EXCESSIVE DUP BLKS IN BIT MAPS.");
10104236Smckusick 				if (reply("CONTINUE") == 0)
10114236Smckusick 					errexit("");
10124236Smckusick 				return (STOP);
10134236Smckusick 			}
10144236Smckusick 		} else {
10154236Smckusick 			n_ffree++;
10164236Smckusick 			setfmap(blk);
10174236Smckusick 		}
10184236Smckusick 	}
10194236Smckusick 	return (res);
10204236Smckusick }
10214236Smckusick 
10224236Smckusick outrange(blk)
10234236Smckusick 	daddr_t blk;
10244236Smckusick {
10254236Smckusick 	register int c;
10264236Smckusick 
10275381Smckusic 	c = dtog(&sblock, blk);
10286533Smckusick 	if ((unsigned)blk >= fmax) {
10294236Smckusick 		return (1);
10304428Smckusic 	}
10314236Smckusick 	return (0);
10324236Smckusick }
10334236Smckusick 
10344236Smckusick blkerr(s, blk)
10354236Smckusick 	daddr_t blk;
10364236Smckusick 	char *s;
10374236Smckusick {
10384236Smckusick 	pfatal("%ld %s I=%u", blk, s, inum);
10394236Smckusick 	printf("\n");
10404236Smckusick 	setstate(CLEAR);	/* mark for possible clearing */
10414236Smckusick }
10424236Smckusick 
10434236Smckusick descend()
10444236Smckusick {
10454236Smckusick 	register DINODE *dp;
10464236Smckusick 	register char *savname;
10474236Smckusick 	off_t savsize;
10484236Smckusick 
10494236Smckusick 	setstate(FSTATE);
10504236Smckusick 	if ((dp = ginode()) == NULL)
10514236Smckusick 		return;
10524236Smckusick 	savname = thisname;
10534236Smckusick 	*pathp++ = '/';
10544236Smckusick 	savsize = filsize;
10554236Smckusick 	filsize = dp->di_size;
10564236Smckusick 	ckinode(dp, DATA);
10574236Smckusick 	thisname = savname;
10584236Smckusick 	*--pathp = 0;
10594236Smckusick 	filsize = savsize;
10604236Smckusick }
10614236Smckusick 
10625877Smckusic struct dirstuff {
10635877Smckusic 	int loc;
10645877Smckusic 	int blkno;
10655877Smckusic 	int blksiz;
10666634Smckusick 	ino_t number;
1067*6837Smckusick 	int fix;
10685877Smckusic };
10695877Smckusic 
10704236Smckusick dirscan(blk, nf)
10714715Smckusic 	daddr_t blk;
10724715Smckusic 	int nf;
10734236Smckusick {
10745877Smckusic 	register DIRECT *dp;
10755877Smckusic 	struct dirstuff dirp;
10766251Smckusick 	int blksiz, dsize, n;
10776251Smckusick 	char dbuf[DIRBLKSIZ];
10784236Smckusick 
10794236Smckusick 	if (outrange(blk)) {
10805325Smckusic 		filsize -= sblock.fs_bsize;
10814236Smckusick 		return (SKIP);
10824236Smckusick 	}
10835877Smckusic 	blksiz = nf * sblock.fs_fsize;
10845877Smckusic 	dirp.loc = 0;
10855877Smckusic 	dirp.blkno = blk;
10865877Smckusic 	dirp.blksiz = blksiz;
1087*6837Smckusick 	if (dirp.number != dnum) {
1088*6837Smckusick 		dirp.number = dnum;
1089*6837Smckusick 		dirp.fix = 0;
1090*6837Smckusick 	}
10915877Smckusic 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
10926251Smckusick 		dsize = dp->d_reclen;
10936251Smckusick 		copy(dp, dbuf, dsize);
10946251Smckusick 		if ((n = (*pfunc)(dbuf)) & ALTERD) {
10955877Smckusic 			if (getblk(&fileblk, blk, blksiz) != NULL) {
10966251Smckusick 				copy(dbuf, dp, dsize);
10974715Smckusic 				dirty(&fileblk);
10984236Smckusick 				sbdirty();
10994236Smckusick 			} else
11004236Smckusick 				n &= ~ALTERD;
11014236Smckusick 		}
11025877Smckusic 		if (n & STOP)
11034236Smckusick 			return (n);
11044236Smckusick 	}
11054236Smckusick 	return (filsize > 0 ? KEEPON : STOP);
11064236Smckusick }
11074236Smckusick 
11085877Smckusic /*
11095877Smckusic  * get next entry in a directory.
11105877Smckusic  */
11115877Smckusic DIRECT *
11125877Smckusic readdir(dirp)
11135877Smckusic 	register struct dirstuff *dirp;
11145877Smckusic {
11156251Smckusick 	register DIRECT *dp, *ndp;
1116*6837Smckusick 	long size;
11175877Smckusic 
11185877Smckusic 	if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) {
11195877Smckusic 		filsize -= dirp->blksiz - dirp->loc;
11205877Smckusic 		return NULL;
11215877Smckusic 	}
1122*6837Smckusick 	while (dirp->loc % DIRBLKSIZ == 0 && filsize > 0 &&
1123*6837Smckusick 	    dirp->loc < dirp->blksiz) {
11245935Smckusic 		dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
1125*6837Smckusick 	   	if (dp->d_ino < imax &&
1126*6837Smckusick 		    dp->d_namlen <= MAXNAMLEN && dp->d_namlen >= 0 &&
1127*6837Smckusick 		    dp->d_reclen > 0 && dp->d_reclen <= DIRBLKSIZ)
1128*6837Smckusick 			break;
1129*6837Smckusick 		dirp->loc += DIRBLKSIZ;
1130*6837Smckusick 		filsize -= DIRBLKSIZ;
1131*6837Smckusick 		if (dirp->fix == 0) {
11326634Smckusick 			pwarn("DIRECTORY %D CORRUPTED", dirp->number);
1133*6837Smckusick 			dirp->fix = 1;
1134*6837Smckusick 			if (preen) {
11356251Smckusick 				printf(" (SALVAGED)\n");
1136*6837Smckusick 				dirp->fix = 2;
1137*6837Smckusick 			} else if (reply("SALVAGE") != 0)
1138*6837Smckusick 				dirp->fix = 2;
1139*6837Smckusick 		}
1140*6837Smckusick 		if (dirp->fix < 2)
11415877Smckusic 			continue;
1142*6837Smckusick 		dp->d_reclen = DIRBLKSIZ;
1143*6837Smckusick 		dp->d_ino = 0;
1144*6837Smckusick 		dp->d_namlen = 0;
1145*6837Smckusick 		dirty(&fileblk);
1146*6837Smckusick 	}
1147*6837Smckusick 	if (filsize <= 0 || dirp->loc >= dirp->blksiz)
1148*6837Smckusick 		return NULL;
1149*6837Smckusick 	dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
1150*6837Smckusick 	dirp->loc += dp->d_reclen;
1151*6837Smckusick 	filsize -= dp->d_reclen;
1152*6837Smckusick 	ndp = (DIRECT *)(dirblk.b_buf + dirp->loc);
1153*6837Smckusick 	if (dirp->loc < dirp->blksiz && filsize > 0 &&
1154*6837Smckusick 	    (ndp->d_ino >= imax ||
1155*6837Smckusick 	    ndp->d_namlen > MAXNAMLEN || ndp->d_namlen < 0 ||
1156*6837Smckusick 	    ndp->d_reclen <= 0 ||
1157*6837Smckusick 	    ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ))) {
1158*6837Smckusick 		size = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
1159*6837Smckusick 		dirp->loc += size;
1160*6837Smckusick 		filsize -= size;
1161*6837Smckusick 		if (dirp->fix == 0) {
1162*6837Smckusick 			pwarn("DIRECTORY %D CORRUPTED", dirp->number);
1163*6837Smckusick 			dirp->fix = 1;
1164*6837Smckusick 			if (preen) {
1165*6837Smckusick 				printf(" (SALVAGED)\n");
1166*6837Smckusick 				dirp->fix = 2;
1167*6837Smckusick 			} else if (reply("SALVAGE") != 0)
1168*6837Smckusick 				dirp->fix = 2;
11696251Smckusick 		}
1170*6837Smckusick 		if (dirp->fix > 2) {
1171*6837Smckusick 			dp->d_reclen += size;
1172*6837Smckusick 			dirty(&fileblk);
1173*6837Smckusick 		}
11745877Smckusic 	}
1175*6837Smckusick 	return (dp);
11765877Smckusic }
11775877Smckusic 
11784236Smckusick direrr(s)
11794715Smckusic 	char *s;
11804236Smckusick {
11814236Smckusick 	register DINODE *dp;
11824236Smckusick 
11834236Smckusick 	pwarn("%s ", s);
11844236Smckusick 	pinode();
11854236Smckusick 	printf("\n");
11864236Smckusick 	if ((dp = ginode()) != NULL && ftypeok(dp))
11875877Smckusic 		pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname);
11884236Smckusick 	else
11894236Smckusick 		pfatal("NAME=%s", pathname);
11904236Smckusick 	return (reply("REMOVE"));
11914236Smckusick }
11924236Smckusick 
11934236Smckusick adjust(lcnt)
11944465Smckusic 	register short lcnt;
11954236Smckusick {
11964236Smckusick 	register DINODE *dp;
11974236Smckusick 
11984236Smckusick 	if ((dp = ginode()) == NULL)
11994236Smckusick 		return;
12004236Smckusick 	if (dp->di_nlink == lcnt) {
12014236Smckusick 		if (linkup() == 0)
12024236Smckusick 			clri("UNREF", 0);
12034236Smckusick 	}
12044236Smckusick 	else {
12054236Smckusick 		pwarn("LINK COUNT %s",
12065877Smckusic 			(lfdir==inum)?lfname:(DIRCT?"DIR":"FILE"));
12074236Smckusick 		pinode();
12084236Smckusick 		printf(" COUNT %d SHOULD BE %d",
12094236Smckusick 			dp->di_nlink, dp->di_nlink-lcnt);
12104236Smckusick 		if (preen) {
12114236Smckusick 			if (lcnt < 0) {
12124236Smckusick 				printf("\n");
12134236Smckusick 				preendie();
12144236Smckusick 			}
12154236Smckusick 			printf(" (ADJUSTED)\n");
12164236Smckusick 		}
12174236Smckusick 		if (preen || reply("ADJUST") == 1) {
12184236Smckusick 			dp->di_nlink -= lcnt;
12194236Smckusick 			inodirty();
12204236Smckusick 		}
12214236Smckusick 	}
12224236Smckusick }
12234236Smckusick 
12244236Smckusick clri(s, flg)
12254715Smckusic 	char *s;
12264236Smckusick {
12274236Smckusick 	register DINODE *dp;
12284236Smckusick 
12294236Smckusick 	if ((dp = ginode()) == NULL)
12304236Smckusick 		return;
12314236Smckusick 	if (flg == 1) {
12325877Smckusic 		pwarn("%s %s", s, DIRCT?"DIR":"FILE");
12334236Smckusick 		pinode();
12344236Smckusick 	}
12354236Smckusick 	if (preen || reply("CLEAR") == 1) {
12364236Smckusick 		if (preen)
12374236Smckusick 			printf(" (CLEARED)\n");
12384236Smckusick 		n_files--;
12394236Smckusick 		pfunc = pass4;
12404236Smckusick 		ckinode(dp, ADDR);
12414236Smckusick 		zapino(dp);
12424465Smckusic 		setstate(USTATE);
12434236Smckusick 		inodirty();
12444236Smckusick 		inosumbad++;
12454236Smckusick 	}
12464236Smckusick }
12474236Smckusick 
12484236Smckusick setup(dev)
12494715Smckusic 	char *dev;
12504236Smckusick {
12514236Smckusick 	dev_t rootdev;
12526489Smckusick 	struct stat statb;
12534236Smckusick 	int super = bflag ? bflag : SBLOCK;
12546533Smckusick 	int i, j, size;
12556533Smckusick 	int c, d, cgd;
12564236Smckusick 
12574236Smckusick 	bflag = 0;
12584236Smckusick 	if (stat("/", &statb) < 0)
12594236Smckusick 		errexit("Can't stat root\n");
12604236Smckusick 	rootdev = statb.st_dev;
12614236Smckusick 	if (stat(dev, &statb) < 0) {
12624236Smckusick 		error("Can't stat %s\n", dev);
12634236Smckusick 		return (0);
12644236Smckusick 	}
12654236Smckusick 	rawflg = 0;
12664236Smckusick 	if ((statb.st_mode & S_IFMT) == S_IFBLK)
12674236Smckusick 		;
12684236Smckusick 	else if ((statb.st_mode & S_IFMT) == S_IFCHR)
12694236Smckusick 		rawflg++;
12704236Smckusick 	else {
12714236Smckusick 		if (reply("file is not a block or character device; OK") == 0)
12724236Smckusick 			return (0);
12734236Smckusick 	}
12744236Smckusick 	if (rootdev == statb.st_rdev)
12754236Smckusick 		hotroot++;
12764236Smckusick 	if ((dfile.rfdes = open(dev, 0)) < 0) {
12774236Smckusick 		error("Can't open %s\n", dev);
12784236Smckusick 		return (0);
12794236Smckusick 	}
12804236Smckusick 	if (preen == 0)
12814236Smckusick 		printf("** %s", dev);
12824236Smckusick 	if (nflag || (dfile.wfdes = open(dev, 1)) < 0) {
12834236Smckusick 		dfile.wfdes = -1;
12844236Smckusick 		if (preen)
12854236Smckusick 			pfatal("NO WRITE ACCESS");
12864236Smckusick 		printf(" (NO WRITE)");
12874236Smckusick 	}
12884236Smckusick 	if (preen == 0)
12894236Smckusick 		printf("\n");
12906491Smckusick 	fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; sbsumbad = 0;
12914236Smckusick 	dfile.mod = 0;
12924236Smckusick 	n_files = n_blks = n_ffree = n_bfree = 0;
12934236Smckusick 	muldup = enddup = &duplist[0];
12944236Smckusick 	badlnp = &badlncnt[0];
12954236Smckusick 	lfdir = 0;
12964236Smckusick 	rplyflag = 0;
12974236Smckusick 	initbarea(&sblk);
12984236Smckusick 	initbarea(&fileblk);
12994236Smckusick 	initbarea(&inoblk);
13004236Smckusick 	initbarea(&cgblk);
13016491Smckusick 	/*
13026491Smckusick 	 * Read in the super block and its summary info.
13036491Smckusick 	 */
13045347Smckusic 	if (bread(&dfile, &sblock, super, SBSIZE) == 0)
13054236Smckusick 		return (0);
13064465Smckusic 	sblk.b_bno = super;
13075347Smckusic 	sblk.b_size = SBSIZE;
13085363Smckusic 	/*
13095363Smckusic 	 * run a few consistency checks of the super block
13105363Smckusic 	 */
13114236Smckusick 	if (sblock.fs_magic != FS_MAGIC)
13124236Smckusick 		{ badsb("MAGIC NUMBER WRONG"); return (0); }
13134236Smckusick 	if (sblock.fs_ncg < 1)
13144236Smckusick 		{ badsb("NCG OUT OF RANGE"); return (0); }
13154236Smckusick 	if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
13164236Smckusick 		{ badsb("CPG OUT OF RANGE"); return (0); }
13174236Smckusick 	if (sblock.fs_nsect < 1)
13184236Smckusick 		{ badsb("NSECT < 1"); return (0); }
13194236Smckusick 	if (sblock.fs_ntrak < 1)
13204236Smckusick 		{ badsb("NTRAK < 1"); return (0); }
13215363Smckusic 	if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak)
13225363Smckusic 		{ badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); }
13235363Smckusic 	if (sblock.fs_ipg % INOPB(&sblock))
13245363Smckusic 		{ badsb("INODES NOT MULTIPLE OF A BLOCK"); return (0); }
13255381Smckusic 	if (cgdmin(&sblock, 0) >= sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
13264236Smckusick 		{ badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); return (0); }
13275363Smckusic 	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
13285363Smckusic 	    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
13294236Smckusick 		{ badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
13305325Smckusic 	if (sblock.fs_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
13314236Smckusick 		{ badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); }
13325363Smckusic 	if (sblock.fs_size * NSPF(&sblock) <=
13335363Smckusic 	    (sblock.fs_ncyl - 1) * sblock.fs_spc)
13344236Smckusick 		{ badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); }
13355363Smckusic 	if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc)
13364236Smckusick 		{ badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
13374236Smckusick 	/* rest we COULD repair... */
13385956Smckusic 	if (sblock.fs_cgsize != fragroundup(&sblock,
13395956Smckusic 	    sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY)))
13404236Smckusick 		{ badsb("CGSIZE INCORRECT"); return (0); }
13416533Smckusick 	if (sblock.fs_cssize !=
13426533Smckusick 	    fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)))
13434236Smckusick 		{ badsb("CSSIZE INCORRECT"); return (0); }
13444236Smckusick 	fmax = sblock.fs_size;
13454236Smckusick 	imax = sblock.fs_ncg * sblock.fs_ipg;
13466533Smckusick 	n_bad = cgsblock(&sblock, 0); /* boot block plus dedicated sblock */
13475363Smckusic 	/*
13486533Smckusick 	 * read in the summary info.
13495363Smckusic 	 */
13506533Smckusick 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
13516533Smckusick 		size = sblock.fs_cssize - i < sblock.fs_bsize ?
13526533Smckusick 		    sblock.fs_cssize - i : sblock.fs_bsize;
13536533Smckusick 		sblock.fs_csp[j] = (struct csum *)calloc(1, size);
13546533Smckusick 		bread(&dfile, (char *)sblock.fs_csp[j],
13556533Smckusick 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
13566533Smckusick 		    size);
13576533Smckusick 	}
13586533Smckusick 	/*
13596533Smckusick 	 * allocate and initialize the necessary maps
13606533Smckusick 	 */
13614236Smckusick 	bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
13626314Smckusick 	blockmap = (char *)calloc(bmapsz, sizeof (char));
13636547Smckusick 	if (blockmap == NULL) {
13646547Smckusick 		printf("cannot alloc %d bytes for blockmap\n", bmapsz);
13656547Smckusick 		exit(1);
13666547Smckusick 	}
13674236Smckusick 	freemap = (char *)calloc(bmapsz, sizeof (char));
13686547Smckusick 	if (freemap == NULL) {
13696547Smckusick 		printf("cannot alloc %d bytes for freemap\n", bmapsz);
13706547Smckusick 		exit(1);
13716547Smckusick 	}
13724236Smckusick 	statemap = (char *)calloc(imax+1, sizeof(char));
13736547Smckusick 	if (statemap == NULL) {
13746547Smckusick 		printf("cannot alloc %d bytes for statemap\n", imax + 1);
13756547Smckusick 		exit(1);
13766547Smckusick 	}
13774236Smckusick 	lncntp = (short *)calloc(imax+1, sizeof(short));
13786547Smckusick 	if (lncntp == NULL) {
13796547Smckusick 		printf("cannot alloc %d bytes for lncntp\n",
13806547Smckusick 		    (imax + 1) * sizeof(short));
13816547Smckusick 		exit(1);
13826547Smckusick 	}
13836533Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
13846533Smckusick 		cgd = cgdmin(&sblock, c);
13856533Smckusick 		if (c == 0) {
13866533Smckusick 			d = cgbase(&sblock, c);
13876533Smckusick 			cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
13886533Smckusick 		} else
13896533Smckusick 			d = cgsblock(&sblock, c);
13906533Smckusick 		for (; d < cgd; d++)
13916533Smckusick 			setbmap(d);
13926533Smckusick 	}
13934236Smckusick 
13944465Smckusic 	startinum = imax + 1;
13954236Smckusick 	return (1);
13964236Smckusick 
13974236Smckusick badsb:
13984236Smckusick 	ckfini();
13994236Smckusick 	return (0);
14004236Smckusick }
14014236Smckusick 
14024236Smckusick badsb(s)
14034236Smckusick 	char *s;
14044236Smckusick {
14054236Smckusick 
14064236Smckusick 	if (preen)
14074236Smckusick 		printf("%s: ", devname);
14084236Smckusick 	printf("BAD SUPER BLOCK: %s\n", s);
14094236Smckusick 	pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
14104236Smckusick 	pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
14114236Smckusick }
14124236Smckusick 
14134236Smckusick DINODE *
14144236Smckusick ginode()
14154236Smckusick {
14164236Smckusick 	daddr_t iblk;
14174236Smckusick 
14186547Smckusick 	if (inum < ROOTINO || inum > imax) {
14196547Smckusick 		if (debug && (inum < 0 || inum > imax))
14206547Smckusick 			printf("inum out of range (%d)\n", inum);
14214236Smckusick 		return (NULL);
14226547Smckusick 	}
14235325Smckusic 	if (inum < startinum || inum >= startinum + INOPB(&sblock)) {
14245381Smckusic 		iblk = itod(&sblock, inum);
14255325Smckusic 		if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
14264236Smckusick 			return (NULL);
14274236Smckusick 		}
14285325Smckusic 		startinum = (inum / INOPB(&sblock)) * INOPB(&sblock);
14294236Smckusick 	}
14305325Smckusic 	return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]);
14314236Smckusick }
14324236Smckusick 
14334236Smckusick ftypeok(dp)
14344236Smckusick 	DINODE *dp;
14354236Smckusick {
14364236Smckusick 	switch (dp->di_mode & IFMT) {
14374236Smckusick 
14384236Smckusick 	case IFDIR:
14394236Smckusick 	case IFREG:
14404236Smckusick 	case IFBLK:
14414236Smckusick 	case IFCHR:
14426285Smckusick 	case IFLNK:
14434236Smckusick 		return (1);
14444236Smckusick 
14454236Smckusick 	default:
14464236Smckusick 		return (0);
14474236Smckusick 	}
14484236Smckusick }
14494236Smckusick 
14504236Smckusick reply(s)
14514236Smckusick 	char *s;
14524236Smckusick {
14534236Smckusick 	char line[80];
14544236Smckusick 
14554236Smckusick 	if (preen)
14564236Smckusick 		pfatal("INTERNAL ERROR: GOT TO reply()");
14574236Smckusick 	rplyflag = 1;
14584236Smckusick 	printf("\n%s? ", s);
14594236Smckusick 	if (nflag || dfile.wfdes < 0) {
14604236Smckusick 		printf(" no\n\n");
14614236Smckusick 		return (0);
14624236Smckusick 	}
14634236Smckusick 	if (yflag) {
14644236Smckusick 		printf(" yes\n\n");
14654236Smckusick 		return (1);
14664236Smckusick 	}
14674236Smckusick 	if (getline(stdin, line, sizeof(line)) == EOF)
14684236Smckusick 		errexit("\n");
14694236Smckusick 	printf("\n");
14704236Smckusick 	if (line[0] == 'y' || line[0] == 'Y')
14714236Smckusick 		return (1);
14724236Smckusick 	else
14734236Smckusick 		return (0);
14744236Smckusick }
14754236Smckusick 
14764236Smckusick getline(fp, loc, maxlen)
14774236Smckusick 	FILE *fp;
14784236Smckusick 	char *loc;
14794236Smckusick {
14804236Smckusick 	register n;
14814236Smckusick 	register char *p, *lastloc;
14824236Smckusick 
14834236Smckusick 	p = loc;
14844236Smckusick 	lastloc = &p[maxlen-1];
14854236Smckusick 	while ((n = getc(fp)) != '\n') {
14864236Smckusick 		if (n == EOF)
14874236Smckusick 			return (EOF);
14884236Smckusick 		if (!isspace(n) && p < lastloc)
14894236Smckusick 			*p++ = n;
14904236Smckusick 	}
14914236Smckusick 	*p = 0;
14924236Smckusick 	return (p - loc);
14934236Smckusick }
14944236Smckusick 
14954236Smckusick BUFAREA *
14964236Smckusick getblk(bp, blk, size)
14974236Smckusick 	daddr_t blk;
14984236Smckusick 	register BUFAREA *bp;
14994236Smckusick 	int size;
15004236Smckusick {
15014236Smckusick 	register struct filecntl *fcp;
15025325Smckusic 	daddr_t dblk;
15034236Smckusick 
15044236Smckusick 	fcp = &dfile;
15055325Smckusic 	dblk = fsbtodb(&sblock, blk);
15065325Smckusic 	if (bp->b_bno == dblk)
15074236Smckusick 		return (bp);
15084236Smckusick 	flush(fcp, bp);
15095325Smckusic 	if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
15105325Smckusic 		bp->b_bno = dblk;
15114236Smckusick 		bp->b_size = size;
15124236Smckusick 		return (bp);
15134236Smckusick 	}
15144236Smckusick 	bp->b_bno = (daddr_t)-1;
15154236Smckusick 	return (NULL);
15164236Smckusick }
15174236Smckusick 
15184236Smckusick flush(fcp, bp)
15194236Smckusick 	struct filecntl *fcp;
15204236Smckusick 	register BUFAREA *bp;
15214236Smckusick {
15224236Smckusick 
15234236Smckusick 	if (bp->b_dirty)
15244236Smckusick 		bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size);
15254236Smckusick 	bp->b_dirty = 0;
15264236Smckusick }
15274236Smckusick 
15284236Smckusick rwerr(s, blk)
15294236Smckusick 	char *s;
15304236Smckusick 	daddr_t blk;
15314236Smckusick {
15324236Smckusick 
15334236Smckusick 	if (preen == 0)
15344236Smckusick 		printf("\n");
15354236Smckusick 	pfatal("CANNOT %s: BLK %ld", s, blk);
15364236Smckusick 	if (reply("CONTINUE") == 0)
15374236Smckusick 		errexit("Program terminated\n");
15384236Smckusick }
15394236Smckusick 
15404236Smckusick ckfini()
15414236Smckusick {
15424236Smckusick 
15434236Smckusick 	flush(&dfile, &fileblk);
15444236Smckusick 	flush(&dfile, &sblk);
15454465Smckusic 	if (sblk.b_bno != SBLOCK) {
15464465Smckusic 		sblk.b_bno = SBLOCK;
15474465Smckusic 		sbdirty();
15484465Smckusic 		flush(&dfile, &sblk);
15494465Smckusic 	}
15504236Smckusick 	flush(&dfile, &inoblk);
15514236Smckusick 	close(dfile.rfdes);
15524236Smckusick 	close(dfile.wfdes);
15534236Smckusick }
15544236Smckusick 
15554236Smckusick pinode()
15564236Smckusick {
15574236Smckusick 	register DINODE *dp;
15584236Smckusick 	register char *p;
15595877Smckusic 	char uidbuf[BUFSIZ];
15604236Smckusick 	char *ctime();
15614236Smckusick 
15624236Smckusick 	printf(" I=%u ", inum);
15634236Smckusick 	if ((dp = ginode()) == NULL)
15644236Smckusick 		return;
15654236Smckusick 	printf(" OWNER=");
15664236Smckusick 	if (getpw((int)dp->di_uid, uidbuf) == 0) {
15674236Smckusick 		for (p = uidbuf; *p != ':'; p++);
15684236Smckusick 		*p = 0;
15694236Smckusick 		printf("%s ", uidbuf);
15704236Smckusick 	}
15714236Smckusick 	else {
15724236Smckusick 		printf("%d ", dp->di_uid);
15734236Smckusick 	}
15744236Smckusick 	printf("MODE=%o\n", dp->di_mode);
15754236Smckusick 	if (preen)
15764236Smckusick 		printf("%s: ", devname);
15774236Smckusick 	printf("SIZE=%ld ", dp->di_size);
15784236Smckusick 	p = ctime(&dp->di_mtime);
15794236Smckusick 	printf("MTIME=%12.12s %4.4s ", p+4, p+20);
15804236Smckusick }
15814236Smckusick 
15824236Smckusick copy(fp, tp, size)
15834236Smckusick 	register char *tp, *fp;
15844236Smckusick 	unsigned size;
15854236Smckusick {
15864236Smckusick 
15874236Smckusick 	while (size--)
15884236Smckusick 		*tp++ = *fp++;
15894236Smckusick }
15904236Smckusick 
15914236Smckusick makecg()
15924236Smckusick {
15934465Smckusic 	int c, blk;
15946533Smckusick 	daddr_t dbase, d, dlower, dupper, dmax;
15954236Smckusick 	long i, j, s;
15964236Smckusick 	register struct csum *cs;
15974465Smckusic 	register DINODE *dp;
15984236Smckusick 
15994789Smckusic 	sblock.fs_cstotal.cs_nbfree = 0;
16004789Smckusic 	sblock.fs_cstotal.cs_nffree = 0;
16014789Smckusic 	sblock.fs_cstotal.cs_nifree = 0;
16024789Smckusic 	sblock.fs_cstotal.cs_ndir = 0;
16034236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
16045381Smckusic 		dbase = cgbase(&sblock, c);
16054236Smckusick 		dmax = dbase + sblock.fs_fpg;
16065409Smckusic 		if (dmax > sblock.fs_size) {
16075944Smckusic 			for ( ; dmax >= sblock.fs_size; dmax--)
16085401Smckusic 				clrbit(cgrp.cg_free, dmax - dbase);
16095409Smckusic 			dmax++;
16105409Smckusic 		}
16116533Smckusick 		dlower = cgsblock(&sblock, c) - dbase;
16126533Smckusick 		dupper = cgdmin(&sblock, c) - dbase;
16135325Smckusic 		cs = &sblock.fs_cs(&sblock, c);
16144236Smckusick 		cgrp.cg_time = time(0);
16154236Smckusick 		cgrp.cg_magic = CG_MAGIC;
16164236Smckusick 		cgrp.cg_cgx = c;
16174236Smckusick 		cgrp.cg_ncyl = sblock.fs_cpg;
16184236Smckusick 		cgrp.cg_niblk = sblock.fs_ipg;
16194236Smckusick 		cgrp.cg_ndblk = dmax - dbase;
16204789Smckusic 		cgrp.cg_cs.cs_ndir = 0;
16214789Smckusic 		cgrp.cg_cs.cs_nffree = 0;
16224789Smckusic 		cgrp.cg_cs.cs_nbfree = 0;
16234789Smckusic 		cgrp.cg_cs.cs_nifree = 0;
16246533Smckusick 		cgrp.cg_rotor = 0;
16256533Smckusick 		cgrp.cg_frotor = 0;
16264258Smckusic 		cgrp.cg_irotor = 0;
16275325Smckusic 		for (i = 0; i < sblock.fs_frag; i++)
16284465Smckusic 			cgrp.cg_frsum[i] = 0;
16294236Smckusick 		inum = sblock.fs_ipg * c;
16304465Smckusic 		for (i = 0; i < sblock.fs_ipg; inum++, i++) {
16315944Smckusic 			cgrp.cg_cs.cs_nifree++;
16325944Smckusic 			clrbit(cgrp.cg_iused, i);
16334465Smckusic 			dp = ginode();
16344465Smckusic 			if (dp == NULL)
16354465Smckusic 				continue;
16364465Smckusic 			if (ALLOC) {
16375877Smckusic 				if (DIRCT)
16384789Smckusic 					cgrp.cg_cs.cs_ndir++;
16395944Smckusic 				cgrp.cg_cs.cs_nifree--;
16404465Smckusic 				setbit(cgrp.cg_iused, i);
16414465Smckusic 				continue;
16424465Smckusic 			}
16434236Smckusick 		}
16444236Smckusick 		while (i < MAXIPG) {
16454236Smckusick 			clrbit(cgrp.cg_iused, i);
16464236Smckusick 			i++;
16474236Smckusick 		}
16485944Smckusic 		if (c == 0)
16495944Smckusic 			for (i = 0; i < ROOTINO; i++) {
16505944Smckusic 				setbit(cgrp.cg_iused, i);
16515944Smckusic 				cgrp.cg_cs.cs_nifree--;
16525944Smckusic 			}
16535371Smckusic 		for (s = 0; s < MAXCPG; s++) {
16545371Smckusic 			cgrp.cg_btot[s] = 0;
16554236Smckusick 			for (i = 0; i < NRPOS; i++)
16564236Smckusick 				cgrp.cg_b[s][i] = 0;
16575371Smckusic 		}
16584236Smckusick 		if (c == 0) {
16596533Smckusick 			dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
16604236Smckusick 		}
16616533Smckusick 		for (d = dlower; d < dupper; d++)
16624236Smckusick 			clrbit(cgrp.cg_free, d);
16636533Smckusick 		for (d = 0; (d + sblock.fs_frag) <= dmax - dbase;
16646533Smckusick 		    d += sblock.fs_frag) {
16654236Smckusick 			j = 0;
16665325Smckusic 			for (i = 0; i < sblock.fs_frag; i++) {
16676533Smckusick 				if (!getbmap(dbase + d + i)) {
16686533Smckusick 					setbit(cgrp.cg_free, d + i);
16694236Smckusick 					j++;
16704236Smckusick 				} else
16714236Smckusick 					clrbit(cgrp.cg_free, d+i);
16724236Smckusick 			}
16735325Smckusic 			if (j == sblock.fs_frag) {
16744789Smckusic 				cgrp.cg_cs.cs_nbfree++;
16755371Smckusic 				cgrp.cg_btot[cbtocylno(&sblock, d)]++;
16765363Smckusic 				cgrp.cg_b[cbtocylno(&sblock, d)]
16775363Smckusic 				    [cbtorpos(&sblock, d)]++;
16784465Smckusic 			} else if (j > 0) {
16794789Smckusic 				cgrp.cg_cs.cs_nffree += j;
16806533Smckusick 				blk = blkmap(&sblock, cgrp.cg_free, d);
16815325Smckusic 				fragacct(&sblock, blk, cgrp.cg_frsum, 1);
16824465Smckusic 			}
16834236Smckusick 		}
16844465Smckusic 		for (j = d; d < dmax - dbase; d++) {
16856533Smckusick 			if (!getbmap(dbase + d)) {
16864236Smckusick 				setbit(cgrp.cg_free, d);
16874789Smckusic 				cgrp.cg_cs.cs_nffree++;
16884236Smckusick 			} else
16894236Smckusick 				clrbit(cgrp.cg_free, d);
16904236Smckusick 		}
16914465Smckusic 		if (j != d) {
16926533Smckusick 			blk = blkmap(&sblock, cgrp.cg_free, j);
16935325Smckusic 			fragacct(&sblock, blk, cgrp.cg_frsum, 1);
16944465Smckusic 		}
16955325Smckusic 		for (; d < MAXBPG(&sblock); d++)
16964236Smckusick 			clrbit(cgrp.cg_free, d);
16974789Smckusic 		sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree;
16984789Smckusic 		sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree;
16994789Smckusic 		sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
17004789Smckusic 		sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
17014789Smckusic 		*cs = cgrp.cg_cs;
17025381Smckusic 		bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)),
17035956Smckusic 		    sblock.fs_cgsize);
17044236Smckusick 	}
17056533Smckusick 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
17066533Smckusick 		bwrite(&dfile, (char *)sblock.fs_csp[j],
17076533Smckusick 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
17086533Smckusick 		    sblock.fs_cssize - i < sblock.fs_bsize ?
17096533Smckusick 		    sblock.fs_cssize - i : sblock.fs_bsize);
17105097Smckusic 	}
17114236Smckusick 	sblock.fs_ronly = 0;
17124236Smckusick 	sblock.fs_fmod = 0;
17134236Smckusick 	sbdirty();
17144236Smckusick }
17154236Smckusick 
17164465Smckusic /*
17174465Smckusic  * update the frsum fields to reflect addition or deletion
17184465Smckusic  * of some frags
17194465Smckusic  */
17205325Smckusic fragacct(fs, fragmap, fraglist, cnt)
17215325Smckusic 	struct fs *fs;
17224470Smckusic 	int fragmap;
17234789Smckusic 	long fraglist[];
17244465Smckusic 	int cnt;
17254465Smckusic {
17264465Smckusic 	int inblk;
17274465Smckusic 	register int field, subfield;
17284465Smckusic 	register int siz, pos;
17294465Smckusic 
17305325Smckusic 	inblk = (int)(fragtbl[fs->fs_frag][fragmap] << 1);
17314465Smckusic 	fragmap <<= 1;
17325325Smckusic 	for (siz = 1; siz < fs->fs_frag; siz++) {
17336290Smckusick 		if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
17344465Smckusic 			continue;
17354465Smckusic 		field = around[siz];
17364465Smckusic 		subfield = inside[siz];
17375325Smckusic 		for (pos = siz; pos <= fs->fs_frag; pos++) {
17384465Smckusic 			if ((fragmap & field) == subfield) {
17394465Smckusic 				fraglist[siz] += cnt;
17404465Smckusic 				pos += siz;
17414465Smckusic 				field <<= siz;
17424465Smckusic 				subfield <<= siz;
17434465Smckusic 			}
17444465Smckusic 			field <<= 1;
17454465Smckusic 			subfield <<= 1;
17464465Smckusic 		}
17474465Smckusic 	}
17484465Smckusic }
17494465Smckusic 
17504236Smckusick findino(dirp)
17514236Smckusick 	register DIRECT *dirp;
17524236Smckusick {
17534236Smckusick 	if (dirp->d_ino == 0)
17544236Smckusick 		return (KEEPON);
17555877Smckusic 	if (!strcmp(dirp->d_name, srchname)) {
17565877Smckusic 		if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
17575877Smckusic 			parentdir = dirp->d_ino;
17585877Smckusic 		return (STOP);
17594236Smckusick 	}
17604236Smckusick 	return (KEEPON);
17614236Smckusick }
17624236Smckusick 
17634236Smckusick mkentry(dirp)
17644236Smckusick 	register DIRECT *dirp;
17654236Smckusick {
17664236Smckusick 	register ino_t in;
17674236Smckusick 	register char *p;
17686251Smckusick 	DIRECT newent;
17696251Smckusick 	int newlen, oldlen;
17704236Smckusick 
17716251Smckusick 	newent.d_namlen = 11;
17726251Smckusick 	newlen = DIRSIZ(&newent);
17736251Smckusick 	if (dirp->d_ino != 0)
17746251Smckusick 		oldlen = DIRSIZ(dirp);
17756251Smckusick 	else
17766251Smckusick 		oldlen = 0;
17776251Smckusick 	if (dirp->d_reclen - oldlen < newlen)
17784236Smckusick 		return (KEEPON);
17796251Smckusick 	newent.d_reclen = dirp->d_reclen - oldlen;
17806251Smckusick 	dirp->d_reclen = oldlen;
17816251Smckusick 	dirp = (struct direct *)(((char *)dirp) + oldlen);
17824236Smckusick 	dirp->d_ino = orphan;
17836251Smckusick 	dirp->d_reclen = newent.d_reclen;
17846251Smckusick 	p = &dirp->d_name[2];
17856251Smckusick 	for (in = imax; in > 0; in /= 10)
17866251Smckusick 		p++;
17876251Smckusick 	*--p = 0;
17886251Smckusick 	dirp->d_namlen = p - dirp->d_name;
17894236Smckusick 	in = orphan;
17904236Smckusick 	while (p > dirp->d_name) {
17914236Smckusick 		*--p = (in % 10) + '0';
17924236Smckusick 		in /= 10;
17934236Smckusick 	}
17944236Smckusick 	*p = '#';
17954236Smckusick 	return (ALTERD|STOP);
17964236Smckusick }
17974236Smckusick 
17984236Smckusick chgdd(dirp)
17994236Smckusick 	register DIRECT *dirp;
18004236Smckusick {
18014236Smckusick 	if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
18024236Smckusick 	dirp->d_name[2] == 0) {
18034236Smckusick 		dirp->d_ino = lfdir;
18044236Smckusick 		return (ALTERD|STOP);
18054236Smckusick 	}
18064236Smckusick 	return (KEEPON);
18074236Smckusick }
18084236Smckusick 
18094236Smckusick linkup()
18104236Smckusick {
18114236Smckusick 	register DINODE *dp;
18124236Smckusick 	register lostdir;
18134236Smckusick 	register ino_t pdir;
18144236Smckusick 
18154236Smckusick 	if ((dp = ginode()) == NULL)
18164236Smckusick 		return (0);
18175877Smckusic 	lostdir = DIRCT;
18184236Smckusick 	pdir = parentdir;
18194236Smckusick 	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
18204236Smckusick 	pinode();
18214236Smckusick 	if (preen && dp->di_size == 0)
18224236Smckusick 		return (0);
18234236Smckusick 	if (preen)
18244236Smckusick 		printf(" (RECONNECTED)\n");
18254236Smckusick 	else
18264236Smckusick 		if (reply("RECONNECT") == 0)
18274236Smckusick 			return (0);
18284236Smckusick 	orphan = inum;
18294236Smckusick 	if (lfdir == 0) {
18304236Smckusick 		inum = ROOTINO;
18314236Smckusick 		if ((dp = ginode()) == NULL) {
18324236Smckusick 			inum = orphan;
18334236Smckusick 			return (0);
18344236Smckusick 		}
18354236Smckusick 		pfunc = findino;
18364236Smckusick 		srchname = lfname;
18374236Smckusick 		filsize = dp->di_size;
18384236Smckusick 		parentdir = 0;
18394236Smckusick 		ckinode(dp, DATA);
18404236Smckusick 		inum = orphan;
18414236Smckusick 		if ((lfdir = parentdir) == 0) {
18424236Smckusick 			pfatal("SORRY. NO lost+found DIRECTORY");
18434236Smckusick 			printf("\n\n");
18444236Smckusick 			return (0);
18454236Smckusick 		}
18464236Smckusick 	}
18474236Smckusick 	inum = lfdir;
18485877Smckusic 	if ((dp = ginode()) == NULL || !DIRCT || getstate() != FSTATE) {
18494236Smckusick 		inum = orphan;
18504236Smckusick 		pfatal("SORRY. NO lost+found DIRECTORY");
18514236Smckusick 		printf("\n\n");
18524236Smckusick 		return (0);
18534236Smckusick 	}
18545956Smckusic 	if (fragoff(&sblock, dp->di_size)) {
18555956Smckusic 		dp->di_size = fragroundup(&sblock, dp->di_size);
18564236Smckusick 		inodirty();
18574236Smckusick 	}
18584236Smckusick 	filsize = dp->di_size;
18594236Smckusick 	inum = orphan;
18604236Smckusick 	pfunc = mkentry;
18614236Smckusick 	if ((ckinode(dp, DATA) & ALTERD) == 0) {
18624236Smckusick 		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
18634236Smckusick 		printf("\n\n");
18644236Smckusick 		return (0);
18654236Smckusick 	}
18664236Smckusick 	declncnt();
18674236Smckusick 	if (lostdir) {
18684236Smckusick 		pfunc = chgdd;
18694236Smckusick 		dp = ginode();
18704236Smckusick 		filsize = dp->di_size;
18714236Smckusick 		ckinode(dp, DATA);
18724236Smckusick 		inum = lfdir;
18734236Smckusick 		if ((dp = ginode()) != NULL) {
18744236Smckusick 			dp->di_nlink++;
18754236Smckusick 			inodirty();
18764236Smckusick 			setlncnt(getlncnt()+1);
18774236Smckusick 		}
18784236Smckusick 		inum = orphan;
18794236Smckusick 		pwarn("DIR I=%u CONNECTED. ", orphan);
18804236Smckusick 		printf("PARENT WAS I=%u\n", pdir);
18814236Smckusick 		if (preen == 0)
18824236Smckusick 			printf("\n");
18834236Smckusick 	}
18844236Smckusick 	return (1);
18854236Smckusick }
18864236Smckusick 
18874236Smckusick bread(fcp, buf, blk, size)
18884236Smckusick 	daddr_t blk;
18894236Smckusick 	register struct filecntl *fcp;
18904236Smckusick 	register size;
18914236Smckusick 	char *buf;
18924236Smckusick {
18935325Smckusic 	if (lseek(fcp->rfdes, blk * DEV_BSIZE, 0) < 0)
18944236Smckusick 		rwerr("SEEK", blk);
18954236Smckusick 	else if (read(fcp->rfdes, buf, size) == size)
18964236Smckusick 		return (1);
18974236Smckusick 	rwerr("READ", blk);
18984236Smckusick 	return (0);
18994236Smckusick }
19004236Smckusick 
19014236Smckusick bwrite(fcp, buf, blk, size)
19024236Smckusick 	daddr_t blk;
19034236Smckusick 	register struct filecntl *fcp;
19044236Smckusick 	register size;
19054236Smckusick 	char *buf;
19064236Smckusick {
19074236Smckusick 
19084236Smckusick 	if (fcp->wfdes < 0)
19094236Smckusick 		return (0);
19105325Smckusic 	if (lseek(fcp->wfdes, blk * DEV_BSIZE, 0) < 0)
19114236Smckusick 		rwerr("SEEK", blk);
19124236Smckusick 	else if (write(fcp->wfdes, buf, size) == size) {
19134236Smckusick 		fcp->mod = 1;
19144236Smckusick 		return (1);
19154236Smckusick 	}
19164236Smckusick 	rwerr("WRITE", blk);
19174236Smckusick 	return (0);
19184236Smckusick }
19194236Smckusick 
19204236Smckusick catch()
19214236Smckusick {
19224236Smckusick 
19234236Smckusick 	ckfini();
19244236Smckusick 	exit(12);
19254236Smckusick }
19265325Smckusic 
19275325Smckusic /*
19285325Smckusic  * block operations
19295325Smckusic  */
19305325Smckusic 
19315325Smckusic isblock(fs, cp, h)
19325325Smckusic 	struct fs *fs;
19335325Smckusic 	unsigned char *cp;
19345325Smckusic 	int h;
19355325Smckusic {
19365325Smckusic 	unsigned char mask;
19375325Smckusic 
19385325Smckusic 	switch (fs->fs_frag) {
19395325Smckusic 	case 8:
19405325Smckusic 		return (cp[h] == 0xff);
19415325Smckusic 	case 4:
19425325Smckusic 		mask = 0x0f << ((h & 0x1) << 2);
19435325Smckusic 		return ((cp[h >> 1] & mask) == mask);
19445325Smckusic 	case 2:
19455325Smckusic 		mask = 0x03 << ((h & 0x3) << 1);
19465325Smckusic 		return ((cp[h >> 2] & mask) == mask);
19475325Smckusic 	case 1:
19485325Smckusic 		mask = 0x01 << (h & 0x7);
19495325Smckusic 		return ((cp[h >> 3] & mask) == mask);
19505325Smckusic 	default:
19515381Smckusic 		error("isblock bad fs_frag %d\n", fs->fs_frag);
19525381Smckusic 		return (0);
19535325Smckusic 	}
19545325Smckusic }
19556489Smckusick 
19566489Smckusick /*	tables.c	4.1	82/03/25	*/
19576489Smckusick 
19586489Smckusick /* merged into kernel:	tables.c 2.1 3/25/82 */
19596489Smckusick 
19606489Smckusick /* last monet version:	partab.c	4.2	81/03/08	*/
19616489Smckusick 
19626489Smckusick /*
19636489Smckusick  * bit patterns for identifying fragments in the block map
19646489Smckusick  * used as ((map & around) == inside)
19656489Smckusick  */
19666489Smckusick int around[9] = {
19676489Smckusick 	0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
19686489Smckusick };
19696489Smckusick int inside[9] = {
19706489Smckusick 	0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
19716489Smckusick };
19726489Smckusick 
19736489Smckusick /*
19746489Smckusick  * given a block map bit pattern, the frag tables tell whether a
19756489Smckusick  * particular size fragment is available.
19766489Smckusick  *
19776489Smckusick  * used as:
19786489Smckusick  * if ((1 << (size - 1)) & fragtbl[fs->fs_frag][map] {
19796489Smckusick  *	at least one fragment of the indicated size is available
19806489Smckusick  * }
19816489Smckusick  *
19826489Smckusick  * These tables are used by the scanc instruction on the VAX to
19836489Smckusick  * quickly find an appropriate fragment.
19846489Smckusick  */
19856489Smckusick 
19866489Smckusick unsigned char fragtbl124[256] = {
19876489Smckusick 	0x00, 0x16, 0x16, 0x2a, 0x16, 0x16, 0x26, 0x4e,
19886489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x2a, 0x3e, 0x4e, 0x8a,
19896489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19906489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19916489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19926489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19936489Smckusick 	0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
19946489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
19956489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19966489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19976489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
19986489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
19996489Smckusick 	0x26, 0x36, 0x36, 0x2e, 0x36, 0x36, 0x26, 0x6e,
20006489Smckusick 	0x36, 0x36, 0x36, 0x3e, 0x2e, 0x3e, 0x6e, 0xae,
20016489Smckusick 	0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
20026489Smckusick 	0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
20036489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
20046489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
20056489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
20066489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
20076489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
20086489Smckusick 	0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
20096489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
20106489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
20116489Smckusick 	0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
20126489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
20136489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
20146489Smckusick 	0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
20156489Smckusick 	0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
20166489Smckusick 	0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
20176489Smckusick 	0x8a, 0x9e, 0x9e, 0xaa, 0x9e, 0x9e, 0xae, 0xce,
20186489Smckusick 	0x9e, 0x9e, 0x9e, 0xbe, 0xaa, 0xbe, 0xce, 0x8a,
20196489Smckusick };
20206489Smckusick 
20216489Smckusick unsigned char fragtbl8[256] = {
20226489Smckusick 	0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04,
20236489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
20246489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
20256489Smckusick 	0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
20266489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
20276489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
20286489Smckusick 	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
20296489Smckusick 	0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
20306489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
20316489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
20326489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
20336489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
20346489Smckusick 	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
20356489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
20366489Smckusick 	0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
20376489Smckusick 	0x08, 0x09, 0x09, 0x0a, 0x10, 0x11, 0x20, 0x40,
20386489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
20396489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
20406489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
20416489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
20426489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
20436489Smckusick 	0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
20446489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
20456489Smckusick 	0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
20466489Smckusick 	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
20476489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
20486489Smckusick 	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
20496489Smckusick 	0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0a, 0x12,
20506489Smckusick 	0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
20516489Smckusick 	0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0c,
20526489Smckusick 	0x08, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x0a, 0x0c,
20536489Smckusick 	0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
20546489Smckusick };
20556489Smckusick 
20566489Smckusick /*
20576489Smckusick  * the actual fragtbl array
20586489Smckusick  */
20596489Smckusick unsigned char *fragtbl[MAXFRAG + 1] = {
20606489Smckusick 	0, fragtbl124, fragtbl124, 0, fragtbl124, 0, 0, 0, fragtbl8,
20616489Smckusick };
2062