xref: /csrg-svn/sbin/fsck/main.c (revision 4258)
1*4258Smckusic static	char *sccsid = "@(#)main.c	1.4 (Berkeley) 08/29/81";
24236Smckusick #include <stdio.h>
34236Smckusick #include <ctype.h>
44236Smckusick #include "../h/param.h"
54236Smckusick #include "../h/fs.h"
64236Smckusick #include "../h/dir.h"
74236Smckusick #include "../h/inode.h"
84236Smckusick #include "../h/stat.h"
94236Smckusick #include <fstab.h>
104236Smckusick 
114236Smckusick typedef	int	(*SIG_TYP)();
124236Smckusick 
134236Smckusick #define	NDIRECT	(BSIZE/sizeof(struct direct))
144236Smckusick #define	SPERB	(BSIZE/sizeof(short))
154236Smckusick 
164236Smckusick #define	MAXDUP	10		/* limit on dup blks (per inode) */
174236Smckusick #define	MAXBAD	10		/* limit on bad blks (per inode) */
184236Smckusick 
194236Smckusick #define	USTATE	0		/* inode not allocated */
204236Smckusick #define	FSTATE	01		/* inode is file */
214236Smckusick #define	DSTATE	02		/* inode is directory */
224236Smckusick #define	CLEAR	03		/* inode is to be cleared */
234236Smckusick 
244236Smckusick typedef struct dinode	DINODE;
254236Smckusick typedef struct direct	DIRECT;
264236Smckusick 
274236Smckusick #define	ALLOC	((dp->di_mode & IFMT) != 0)
284236Smckusick #define	DIR	((dp->di_mode & IFMT) == IFDIR)
294236Smckusick #define	REG	((dp->di_mode & IFMT) == IFREG)
304236Smckusick #define	BLK	((dp->di_mode & IFMT) == IFBLK)
314236Smckusick #define	CHR	((dp->di_mode & IFMT) == IFCHR)
324236Smckusick #define	MPC	((dp->di_mode & IFMT) == IFMPC)
334236Smckusick #define	MPB	((dp->di_mode & IFMT) == IFMPB)
344236Smckusick #define	SPECIAL	(BLK || CHR || MPC || MPB)
354236Smckusick 
364236Smckusick daddr_t	startib;		/* blk num of first in raw area */
374236Smckusick struct	dinode ibase[MAXIPG];
384236Smckusick int	niblk;
394236Smckusick 
404236Smckusick struct bufarea {
414236Smckusick 	struct bufarea	*b_next;		/* must be first */
424236Smckusick 	daddr_t	b_bno;
434236Smckusick 	int	b_size;
444236Smckusick 	union {
454236Smckusick 		char	b_buf[BSIZE];		/* buffer space */
464236Smckusick 		short	b_lnks[SPERB];		/* link counts */
474236Smckusick 		daddr_t	b_indir[NINDIR];	/* indirect block */
484236Smckusick 		struct	fs b_fs;		/* super block */
494236Smckusick 		struct	cg b_cg;		/* cylinder group */
504236Smckusick 		struct dinode b_dinode[INOPB];	/* inode block */
514236Smckusick 		DIRECT b_dir[NDIRECT];		/* directory */
524236Smckusick 	} b_un;
534236Smckusick 	char	b_dirty;
544236Smckusick };
554236Smckusick 
564236Smckusick typedef struct bufarea BUFAREA;
574236Smckusick 
584236Smckusick BUFAREA	inoblk;			/* inode blocks */
594236Smckusick BUFAREA	fileblk;		/* other blks in filesys */
604236Smckusick BUFAREA	sblk;			/* file system superblock */
614236Smckusick BUFAREA	cgblk;
624236Smckusick 
634236Smckusick #define	initbarea(x)	(x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
644236Smckusick #define	dirty(x)	(x)->b_dirty = 1
654236Smckusick #define	inodirty()	inoblk.b_dirty = 1
664236Smckusick #define	sbdirty()	sblk.b_dirty = 1
674236Smckusick #define	cgdirty()	cgblk.b_dirty = 1
684236Smckusick 
694236Smckusick #define	dirblk		fileblk.b_un
704236Smckusick #define	sblock		sblk.b_un.b_fs
714236Smckusick #define	cgrp		cgblk.b_un.b_cg
724236Smckusick 
734236Smckusick struct filecntl {
744236Smckusick 	int	rfdes;
754236Smckusick 	int	wfdes;
764236Smckusick 	int	mod;
774236Smckusick } dfile;			/* file descriptors for filesys */
784236Smckusick 
794236Smckusick #define	DUPTBLSIZE	100	/* num of dup blocks to remember */
804236Smckusick daddr_t	duplist[DUPTBLSIZE];	/* dup block table */
814236Smckusick daddr_t	*enddup;		/* next entry in dup table */
824236Smckusick daddr_t	*muldup;		/* multiple dups part of table */
834236Smckusick 
844236Smckusick #define	MAXLNCNT	20	/* num zero link cnts to remember */
854236Smckusick ino_t	badlncnt[MAXLNCNT];	/* table of inos with zero link cnts */
864236Smckusick ino_t	*badlnp;		/* next entry in table */
874236Smckusick 
884236Smckusick char	rawflg;
894236Smckusick char	nflag;			/* assume a no response */
904236Smckusick char	yflag;			/* assume a yes response */
914236Smckusick int	bflag;			/* location of alternate super block */
924236Smckusick char	preen;			/* just fix normal inconsistencies */
934236Smckusick char	rplyflag;		/* any questions asked? */
944236Smckusick char	hotroot;		/* checking root device */
954236Smckusick char	fixcg;			/* corrupted free list bit maps */
964236Smckusick 
974236Smckusick char	*blkmap;		/* ptr to primary blk allocation map */
984236Smckusick char	*freemap;		/* ptr to secondary blk allocation map */
994236Smckusick char	*statemap;		/* ptr to inode state table */
1004236Smckusick short	*lncntp;		/* ptr to link count table */
1014236Smckusick 
1024236Smckusick char	*pathp;			/* pointer to pathname position */
1034236Smckusick char	*thisname;		/* ptr to current pathname component */
1044236Smckusick char	*srchname;		/* name being searched for in dir */
1054236Smckusick char	pathname[200];
1064236Smckusick 
1074236Smckusick char	*lfname = "lost+found";
1084236Smckusick 
1094236Smckusick ino_t	inum;			/* inode we are currently working on */
1104236Smckusick ino_t	imax;			/* number of inodes */
1114236Smckusick ino_t	parentdir;		/* i number of parent directory */
1124236Smckusick ino_t	lastino;		/* hiwater mark of inodes */
1134236Smckusick ino_t	lfdir;			/* lost & found directory */
1144236Smckusick ino_t	orphan;			/* orphaned inode */
1154236Smckusick 
1164236Smckusick off_t	filsize;		/* num blks seen in file */
1174236Smckusick off_t	maxblk;			/* largest logical blk in file */
1184236Smckusick off_t	bmapsz;			/* num chars in blkmap */
1194236Smckusick 
1204236Smckusick daddr_t	n_ffree;		/* number of small free blocks */
1214236Smckusick daddr_t	n_bfree;		/* number of large free blocks */
1224236Smckusick daddr_t	n_blks;			/* number of blocks used */
1234236Smckusick daddr_t	n_files;		/* number of files seen */
1244236Smckusick daddr_t	n_index;
1254236Smckusick daddr_t	n_bad;
1264236Smckusick daddr_t	fmax;			/* number of blocks in the volume */
1274236Smckusick 
1284236Smckusick daddr_t	badblk;
1294236Smckusick daddr_t	dupblk;
1304236Smckusick 
1314236Smckusick int	inosumbad;
1324236Smckusick int	offsumbad;
1334236Smckusick 
1344236Smckusick #define	howmany(x, y)	(((x)+((y)-1))/(y))
1354236Smckusick #define	roundup(x, y)	((((x)+((y)-1))/(y))*(y))
1364236Smckusick #define	zapino(x)	(*(x) = zino)
1374236Smckusick struct	dinode zino;
1384236Smckusick 
1394236Smckusick #define	setlncnt(x)	(lncntp[inum] = x)
1404236Smckusick #define	getlncnt()	(lncntp[inum])
1414236Smckusick #define	declncnt()	(--lncntp[inum])
1424236Smckusick 
1434236Smckusick #define	setbmap(x)	setbit(blkmap, x)
1444236Smckusick #define	getbmap(x)	isset(blkmap, x)
1454236Smckusick #define	clrbmap(x)	clrbit(blkmap, x)
1464236Smckusick 
1474236Smckusick #define	setfmap(x)	setbit(freemap, x)
1484236Smckusick #define	getfmap(x)	isset(freemap, x)
1494236Smckusick #define	clrfmap(x)	clrbit(freemap, x)
1504236Smckusick 
1514236Smckusick #define	setstate(x)	(statemap[inum] = x)
1524236Smckusick #define	getstate()	statemap[inum]
1534236Smckusick 
1544236Smckusick #define	DATA	1
1554236Smckusick #define	ADDR	0
1564236Smckusick 
1574236Smckusick #define	ALTERD	010
1584236Smckusick #define	KEEPON	04
1594236Smckusick #define	SKIP	02
1604236Smckusick #define	STOP	01
1614236Smckusick 
1624236Smckusick int	(*signal())();
1634236Smckusick long	lseek();
1644236Smckusick time_t	time();
1654236Smckusick DINODE	*ginode();
1664236Smckusick BUFAREA	*getblk();
1674236Smckusick int	dirscan();
1684236Smckusick int	findino();
1694236Smckusick int	catch();
1704236Smckusick int	mkentry();
1714236Smckusick int	chgdd();
1724236Smckusick int	pass1(), pass1b(), pass2(), pass4(), pass5();
1734236Smckusick int	(*pfunc)();
1744236Smckusick char	*rawname(), *rindex(), *unrawname();
1754236Smckusick 
1764236Smckusick char	*devname;
1774236Smckusick 
1784236Smckusick main(argc, argv)
1794236Smckusick int	argc;
1804236Smckusick char	*argv[];
1814236Smckusick {
1824236Smckusick 	struct fstab *fsp;
1834236Smckusick 	int pid, passno, anygtr, sumstatus;
1844236Smckusick 
1854236Smckusick 	sync();
1864236Smckusick 	while (--argc > 0 && **++argv == '-') {
1874236Smckusick 		switch (*++*argv) {
1884236Smckusick 
1894236Smckusick 		case 'p':
1904236Smckusick 			preen++;
1914236Smckusick 			break;
1924236Smckusick 
1934236Smckusick 		case 'b':
1944236Smckusick 			bflag = atoi(argv[0]+1);
1954236Smckusick 			printf("Alternate super block location: %d\n", bflag);
1964236Smckusick 			break;
1974236Smckusick 
1984236Smckusick 		case 'n':	/* default no answer flag */
1994236Smckusick 		case 'N':
2004236Smckusick 			nflag++;
2014236Smckusick 			yflag = 0;
2024236Smckusick 			break;
2034236Smckusick 
2044236Smckusick 		case 'y':	/* default yes answer flag */
2054236Smckusick 		case 'Y':
2064236Smckusick 			yflag++;
2074236Smckusick 			nflag = 0;
2084236Smckusick 			break;
2094236Smckusick 
2104236Smckusick 		default:
2114236Smckusick 			errexit("%c option?\n", **argv);
2124236Smckusick 		}
2134236Smckusick 	}
2144236Smckusick 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
2154236Smckusick 		signal(SIGINT, catch);
2164236Smckusick 	if (argc) {
2174236Smckusick 		while (argc-- > 0) {
2184236Smckusick 			hotroot = 0;
2194236Smckusick 			check(*argv++);
2204236Smckusick 		}
2214236Smckusick 		exit(0);
2224236Smckusick 	}
2234236Smckusick 	sumstatus = 0;
2244236Smckusick 	passno = 1;
2254236Smckusick 	do {
2264236Smckusick 		anygtr = 0;
2274236Smckusick 		if (setfsent() == 0)
2284236Smckusick 			errexit("Can't open checklist file: %s\n", FSTAB);
2294236Smckusick 		while ((fsp = getfsent()) != 0) {
2304236Smckusick 			if (strcmp(fsp->fs_type, FSTAB_RW) &&
2314236Smckusick 			    strcmp(fsp->fs_type, FSTAB_RO))
2324236Smckusick 				continue;
2334236Smckusick 			if (preen == 0 ||
2344236Smckusick 			    passno == 1 && fsp->fs_passno == passno) {
2354236Smckusick 				if (blockcheck(fsp->fs_spec) == 0 && preen)
2364236Smckusick 					exit(8);
2374236Smckusick 			} else if (fsp->fs_passno > passno)
2384236Smckusick 				anygtr = 1;
2394236Smckusick 			else if (fsp->fs_passno == passno) {
2404236Smckusick 				pid = fork();
2414236Smckusick 				if (pid < 0) {
2424236Smckusick 					perror("fork");
2434236Smckusick 					exit(8);
2444236Smckusick 				}
2454236Smckusick 				if (pid == 0)
2464236Smckusick 					if (blockcheck(fsp->fs_spec)==0)
2474236Smckusick 						exit(8);
2484236Smckusick 					else
2494236Smckusick 						exit(0);
2504236Smckusick 			}
2514236Smckusick 		}
2524236Smckusick 		if (preen) {
2534236Smckusick 			int status;
2544236Smckusick 			while (wait(&status) != -1)
2554236Smckusick 				sumstatus |= status;
2564236Smckusick 		}
2574236Smckusick 		passno++;
2584236Smckusick 	} while (anygtr);
2594236Smckusick 	if (sumstatus)
2604236Smckusick 		exit(8);
2614236Smckusick 	endfsent();
2624236Smckusick 	exit(0);
2634236Smckusick }
2644236Smckusick 
2654236Smckusick blockcheck(name)
2664236Smckusick 	char *name;
2674236Smckusick {
2684236Smckusick 	struct stat stslash, stblock, stchar;
2694236Smckusick 	char *raw;
2704236Smckusick 	int looped = 0;
2714236Smckusick 
2724236Smckusick 	hotroot = 0;
2734236Smckusick 	if (stat("/", &stslash) < 0){
2744236Smckusick 		error("Can't stat root\n");
2754236Smckusick 		return (0);
2764236Smckusick 	}
2774236Smckusick retry:
2784236Smckusick 	if (stat(name, &stblock) < 0){
2794236Smckusick 		error("Can't stat %s\n", name);
2804236Smckusick 		return (0);
2814236Smckusick 	}
2824236Smckusick 	if (stblock.st_mode & S_IFBLK) {
2834236Smckusick 		raw = rawname(name);
2844236Smckusick 		if (stat(raw, &stchar) < 0){
2854236Smckusick 			error("Can't stat %s\n", raw);
2864236Smckusick 			return (0);
2874236Smckusick 		}
2884236Smckusick 		if (stchar.st_mode & S_IFCHR) {
2894236Smckusick 			if (stslash.st_dev == stblock.st_rdev) {
2904236Smckusick 				hotroot++;
2914236Smckusick 				raw = unrawname(name);
2924236Smckusick 			}
2934236Smckusick 			check(raw);
2944236Smckusick 			return (1);
2954236Smckusick 		} else {
2964236Smckusick 			error("%s is not a character device\n", raw);
2974236Smckusick 			return (0);
2984236Smckusick 		}
2994236Smckusick 	} else if (stblock.st_mode & S_IFCHR) {
3004236Smckusick 		if (looped) {
3014236Smckusick 			error("Can't make sense out of name %s\n", name);
3024236Smckusick 			return (0);
3034236Smckusick 		}
3044236Smckusick 		name = unrawname(name);
3054236Smckusick 		looped++;
3064236Smckusick 		goto retry;
3074236Smckusick 	}
3084236Smckusick 	error("Can't make sense out of name %s\n", name);
3094236Smckusick 	return (0);
3104236Smckusick }
3114236Smckusick 
3124236Smckusick char *
3134236Smckusick unrawname(cp)
3144236Smckusick 	char *cp;
3154236Smckusick {
3164236Smckusick 	char *dp = rindex(cp, '/');
3174236Smckusick 	struct stat stb;
3184236Smckusick 
3194236Smckusick 	if (dp == 0)
3204236Smckusick 		return (cp);
3214236Smckusick 	if (stat(cp, &stb) < 0)
3224236Smckusick 		return (cp);
3234236Smckusick 	if ((stb.st_mode&S_IFMT) != S_IFCHR)
3244236Smckusick 		return (cp);
3254236Smckusick 	if (*(dp+1) != 'r')
3264236Smckusick 		return (cp);
3274236Smckusick 	strcpy(dp+1, dp+2);
3284236Smckusick 	return (cp);
3294236Smckusick }
3304236Smckusick 
3314236Smckusick char *
3324236Smckusick rawname(cp)
3334236Smckusick 	char *cp;
3344236Smckusick {
3354236Smckusick 	static char rawbuf[32];
3364236Smckusick 	char *dp = rindex(cp, '/');
3374236Smckusick 
3384236Smckusick 	if (dp == 0)
3394236Smckusick 		return (0);
3404236Smckusick 	*dp = 0;
3414236Smckusick 	strcpy(rawbuf, cp);
3424236Smckusick 	*dp = '/';
3434236Smckusick 	strcat(rawbuf, "/r");
3444236Smckusick 	strcat(rawbuf, dp+1);
3454236Smckusick 	return (rawbuf);
3464236Smckusick }
3474236Smckusick 
3484236Smckusick check(dev)
3494236Smckusick 	char *dev;
3504236Smckusick {
3514236Smckusick 	register DINODE *dp;
3524236Smckusick 	register ino_t *blp;
3534236Smckusick 	register int i, n;
3544236Smckusick 	ino_t savino;
3554236Smckusick 	int b, c;
3564236Smckusick 	daddr_t d, s;
3574236Smckusick 
3584236Smckusick 	devname = dev;
3594236Smckusick 	if (setup(dev) == 0) {
3604236Smckusick 		if (preen)
3614236Smckusick 			pfatal("CAN'T CHECK DEVICE.");
3624236Smckusick 		return;
3634236Smckusick 	}
3644236Smckusick /* 1 */
3654236Smckusick 	if (preen==0) {
3664236Smckusick 		if (hotroot)
3674236Smckusick 			printf("** Root file system\n");
3684236Smckusick 		printf("** Phase 1 - Check Blocks and Sizes\n");
3694236Smckusick 	}
3704236Smckusick 	pfunc = pass1;
3714236Smckusick 	inum = 0;
3724236Smckusick 	n_blks += roundup(sblock.fs_ncg * sizeof (struct csum), BSIZE)
3734236Smckusick 		/ BSIZE * FRAG;
3744236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
3754236Smckusick 		if (getblk(&cgblk, cgtod(c, &sblock), sblock.fs_cgsize) == 0)
3764236Smckusick 			continue;
3774236Smckusick 		dp = ginode();
3784236Smckusick 		if (dp == NULL)
3794236Smckusick 			continue;
3804236Smckusick 		n = 0;
3814236Smckusick 		for (i = 0; i < sblock.fs_ipg; i++, inum++, dp++) {
3824236Smckusick 			if (ALLOC) {
3834236Smckusick 				if (!isset(cgrp.cg_iused, i)) {
3844236Smckusick 					printf("%d bad, not used\n", inum);
3854236Smckusick 					inosumbad++;
3864236Smckusick 				}
3874236Smckusick 				lastino = inum;
3884236Smckusick 				if (ftypeok(dp) == 0) {
3894236Smckusick 					pfatal("UNKNOWN FILE TYPE I=%u", inum);
3904236Smckusick 					if (reply("CLEAR") == 1) {
3914236Smckusick 						zapino(dp);
3924236Smckusick 						inodirty();
3934236Smckusick 						inosumbad++;
3944236Smckusick 					}
3954236Smckusick 					continue;
3964236Smckusick 				}
3974236Smckusick 				n_files++;
3984236Smckusick 				if (setlncnt(dp->di_nlink) <= 0) {
3994236Smckusick 					if (badlnp < &badlncnt[MAXLNCNT])
4004236Smckusick 						*badlnp++ = inum;
4014236Smckusick 					else {
4024236Smckusick 						pfatal("LINK COUNT TABLE OVERFLOW");
4034236Smckusick 						if (reply("CONTINUE") == 0)
4044236Smckusick 							errexit("");
4054236Smckusick 					}
4064236Smckusick 				}
4074236Smckusick 				setstate(DIR ? DSTATE : FSTATE);
4084236Smckusick 				badblk = dupblk = 0; filsize = 0; maxblk = 0;
4094236Smckusick 				ckinode(dp, ADDR);
4104236Smckusick 				if (DIR && dp->di_size % sizeof(DIRECT)) {
4114236Smckusick 					pwarn("DIRECTORY MISALIGNED I=%u\n",
4124236Smckusick 					    inum);
4134236Smckusick 					if (preen == 0)
4144236Smckusick 						printf("\n");
4154236Smckusick 				}
4164236Smckusick 			} else {
4174236Smckusick 				n++;
4184236Smckusick 				if (isset(cgrp.cg_iused, i)) {
4194236Smckusick 					printf("%d bad, marked used\n", inum);
4204236Smckusick 					inosumbad++;
4214236Smckusick 				}
4224236Smckusick 				if (dp->di_mode != 0) {
4234236Smckusick 					pfatal("PARTIALLY ALLOCATED INODE I=%u", inum);
4244236Smckusick 					if (reply("CLEAR") == 1) {
4254236Smckusick 						zapino(dp);
4264236Smckusick 						inodirty();
4274236Smckusick 						inosumbad++;
4284236Smckusick 					}
4294236Smckusick 				}
4304236Smckusick 			}
4314236Smckusick 		}
4324236Smckusick 		if (n != cgrp.cg_nifree) {
4334236Smckusick 			printf("cg[%d].cg_nifree is %d not %d\n",
4344236Smckusick 			    c, cgrp.cg_nifree, n);
4354236Smckusick 			inosumbad++;
4364236Smckusick 		}
4374236Smckusick 	}
4384236Smckusick /* 1b */
4394236Smckusick 	if (enddup != &duplist[0]) {
4404236Smckusick 		if (preen)
4414236Smckusick 			pfatal("INTERNAL ERROR: dups with -p");
4424236Smckusick 		printf("** Phase 1b - Rescan For More DUPS\n");
4434236Smckusick 		pfunc = pass1b;
4444236Smckusick 		inum = 0;
4454236Smckusick 		for (c = 0; c < sblock.fs_ncg; c++) {
4464236Smckusick 			dp = ginode();
4474236Smckusick 			if (dp == NULL)
4484236Smckusick 				continue;
4494236Smckusick 			for (i = 0; i < sblock.fs_ipg; i++, inum++, dp++)
4504236Smckusick 				if (getstate() != USTATE &&
4514236Smckusick 				    (ckinode(dp, ADDR) & STOP))
4524236Smckusick 					goto out1b;
4534236Smckusick 		}
4544236Smckusick 	}
4554236Smckusick out1b:
4564236Smckusick 	if (inoblk.b_dirty) {
4574236Smckusick 		bwrite(&dfile, (char *)ibase, startib, niblk*BSIZE);
4584236Smckusick 		inoblk.b_dirty = 0;
4594236Smckusick 	}
4604236Smckusick /* 2 */
4614236Smckusick 	if (preen == 0)
4624236Smckusick 		printf("** Phase 2 - Check Pathnames\n");
4634236Smckusick 	inum = ROOTINO;
4644236Smckusick 	thisname = pathp = pathname;
4654236Smckusick 	pfunc = pass2;
4664236Smckusick 	switch (getstate()) {
4674236Smckusick 
4684236Smckusick 	case USTATE:
4694236Smckusick 		errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
4704236Smckusick 
4714236Smckusick 	case FSTATE:
4724236Smckusick 		pfatal("ROOT INODE NOT DIRECTORY");
4734236Smckusick 		if (reply("FIX") == 0 || (dp = ginode()) == NULL)
4744236Smckusick 			errexit("");
4754236Smckusick 		dp->di_mode &= ~IFMT;
4764236Smckusick 		dp->di_mode |= IFDIR;
4774236Smckusick 		inodirty();
4784236Smckusick 		inosumbad++;
4794236Smckusick 		setstate(DSTATE);
4804236Smckusick 		/* fall into ... */
4814236Smckusick 
4824236Smckusick 	case DSTATE:
4834236Smckusick 		descend();
4844236Smckusick 		break;
4854236Smckusick 
4864236Smckusick 	case CLEAR:
4874236Smckusick 		pfatal("DUPS/BAD IN ROOT INODE");
4884236Smckusick 		printf("\n");
4894236Smckusick 		if (reply("CONTINUE") == 0)
4904236Smckusick 			errexit("");
4914236Smckusick 		setstate(DSTATE);
4924236Smckusick 		descend();
4934236Smckusick 	}
4944236Smckusick /* 3 */
4954236Smckusick 	if (preen == 0)
4964236Smckusick 		printf("** Phase 3 - Check Connectivity\n");
4974236Smckusick 	for (inum = ROOTINO; inum <= lastino; inum++) {
4984236Smckusick 		if (getstate() == DSTATE) {
4994236Smckusick 			pfunc = findino;
5004236Smckusick 			srchname = "..";
5014236Smckusick 			savino = inum;
5024236Smckusick 			do {
5034236Smckusick 				orphan = inum;
5044236Smckusick 				if ((dp = ginode()) == NULL)
5054236Smckusick 					break;
5064236Smckusick 				filsize = dp->di_size;
5074236Smckusick 				parentdir = 0;
5084236Smckusick 				ckinode(dp, DATA);
5094236Smckusick 				if ((inum = parentdir) == 0)
5104236Smckusick 					break;
5114236Smckusick 			} while (getstate() == DSTATE);
5124236Smckusick 			inum = orphan;
5134236Smckusick 			if (linkup() == 1) {
5144236Smckusick 				thisname = pathp = pathname;
5154236Smckusick 				*pathp++ = '?';
5164236Smckusick 				pfunc = pass2;
5174236Smckusick 				descend();
5184236Smckusick 			}
5194236Smckusick 			inum = savino;
5204236Smckusick 		}
5214236Smckusick 	}
5224236Smckusick /* 4 */
5234236Smckusick 	if (preen == 0)
5244236Smckusick 		printf("** Phase 4 - Check Reference Counts\n");
5254236Smckusick 	pfunc = pass4;
5264236Smckusick 	for (inum = ROOTINO; inum <= lastino; inum++) {
5274236Smckusick 		switch (getstate()) {
5284236Smckusick 
5294236Smckusick 		case FSTATE:
5304236Smckusick 			if (n = getlncnt())
5314236Smckusick 				adjust((short)n);
5324236Smckusick 			else {
5334236Smckusick 				for (blp = badlncnt;blp < badlnp; blp++)
5344236Smckusick 					if (*blp == inum) {
5354236Smckusick 						clri("UNREF", 1);
5364236Smckusick 						break;
5374236Smckusick 					}
5384236Smckusick 			}
5394236Smckusick 			break;
5404236Smckusick 
5414236Smckusick 		case DSTATE:
5424236Smckusick 			clri("UNREF", 1);
5434236Smckusick 			break;
5444236Smckusick 
5454236Smckusick 		case CLEAR:
5464236Smckusick 			clri("BAD/DUP", 1);
5474236Smckusick 			break;
5484236Smckusick 		}
5494236Smckusick 	}
5504236Smckusick 	if (imax - n_files != sblock.fs_nifree) {
5514236Smckusick 		pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
5524236Smckusick 		if (preen)
5534236Smckusick 			printf(" (FIXED)\n");
5544236Smckusick 		if (preen || reply("FIX") == 1) {
5554236Smckusick 			sblock.fs_nifree = imax - n_files;
5564236Smckusick 			sbdirty();
5574236Smckusick 		}
5584236Smckusick 	}
5594236Smckusick 	flush(&dfile, &fileblk);
5604236Smckusick 
5614236Smckusick /* 5 */
5624236Smckusick 	if (preen == 0)
5634236Smckusick 		printf("** Phase 5 - Check Cyl groups\n");
5644236Smckusick 	copy(blkmap, freemap, (unsigned)bmapsz);
5654236Smckusick 	dupblk = 0;
5664236Smckusick 	n_index = sblock.fs_ncg * (cgdmin(0, &sblock) - cgtod(0, &sblock));
5674236Smckusick 	n_index += SBLOCK;	/* super-block and boot block */
5684236Smckusick 	n_bad = -SBLOCK;	/* ... which appear (inaccurately) bad */
5694236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
5704236Smckusick 		daddr_t cbase = cgbase(c,&sblock);
5714236Smckusick 		short bo[MAXCPG][NRPOS];
5724236Smckusick 		for (n = 0; n < sblock.fs_cpg; n++)
5734236Smckusick 			for (i = 0; i < NRPOS; i++)
5744236Smckusick 				bo[n][i] = 0;
5754236Smckusick 		n_bad += cgtod(c, &sblock) - cbase;
5764236Smckusick 		if (getblk(&cgblk, cgtod(c, &sblock), sblock.fs_cgsize) == 0)
5774236Smckusick 			continue;
5784236Smckusick 		for (b = 0; b < sblock.fs_fpg; b += FRAG) {
5794236Smckusick 			if (isblock(cgrp.cg_free, b/FRAG)) {
5804236Smckusick 				if (pass5(cbase+b, FRAG) == STOP)
5814236Smckusick 					goto out5;
5824236Smckusick 				/* this is clumsy ... */
5834236Smckusick 				n_ffree -= FRAG;
5844236Smckusick 				n_bfree++;
5854236Smckusick 				s = b * NSPF;
5864236Smckusick 				bo[s/sblock.fs_spc]
5874236Smckusick 				    [s%sblock.fs_nsect*NRPOS/sblock.fs_nsect]++;
5884236Smckusick 			} else
5894236Smckusick 				for (d = 0; d < FRAG; d++)
5904236Smckusick 					if (isset(cgrp.cg_free, b+d))
5914236Smckusick 						if (pass5(cbase+b+d,1) == STOP)
5924236Smckusick 							goto out5;
5934236Smckusick 		}
5944236Smckusick 		for (n = 0; n < sblock.fs_cpg; n++)
5954236Smckusick 			for (i = 0; i < NRPOS; i++)
5964236Smckusick 				if (bo[n][i] != cgrp.cg_b[n][i]) {
5974236Smckusick 					printf("[%d][%d] have %d calc %d\n",
5984236Smckusick 					    n, i, cgrp.cg_b[n][i], bo[n][i]);
5994236Smckusick 					offsumbad++;
6004236Smckusick 				}
6014236Smckusick 	}
6024236Smckusick out5:
6034236Smckusick 	if (dupblk)
6044236Smckusick 		pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk);
6054236Smckusick 	if (fixcg == 0) {
6064236Smckusick 		if ((b = n_blks+n_ffree+FRAG*n_bfree+n_index+n_bad) != fmax) {
6074236Smckusick 			pwarn("%ld BLK(S) MISSING\n", fmax - b);
6084236Smckusick 			fixcg = 1;
6094236Smckusick 		} else if (inosumbad+offsumbad) {
6104236Smckusick 			pwarn("SUMMARY INFORMATION %s%sBAD\n",
6114236Smckusick 			    inosumbad ? "(INODE FREE) " : "",
6124236Smckusick 			    offsumbad ? "(BLOCK OFFSETS) " : "");
6134236Smckusick 			fixcg = 1;
6144236Smckusick 		} else if (n_ffree != sblock.fs_nffree ||
6154236Smckusick 		    n_bfree != sblock.fs_nbfree) {
6164236Smckusick 			pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK");
6174236Smckusick 			if (preen)
6184236Smckusick 				printf(" (FIXED)\n");
6194236Smckusick 			if (preen || reply("FIX") == 1) {
6204236Smckusick 				sblock.fs_nffree = n_ffree;
6214236Smckusick 				sblock.fs_nbfree = n_bfree;
6224236Smckusick 				sbdirty();
6234236Smckusick 			}
6244236Smckusick 		}
6254236Smckusick 	}
6264236Smckusick 	if (fixcg) {
6274236Smckusick 		pwarn("BAD CYLINDER GROUPS");
6284236Smckusick 		if (preen)
6294236Smckusick 			printf(" (SALVAGED)\n");
6304236Smckusick 		else if (reply("SALVAGE") == 0)
6314236Smckusick 			fixcg = 0;
6324236Smckusick 	}
6334236Smckusick 
6344236Smckusick 	if (fixcg) {
6354236Smckusick 		if (preen == 0)
6364236Smckusick 			printf("** Phase 6 - Salvage Cylinder Groups\n");
6374236Smckusick 		sblock.fs_cs = (struct csum *)
6384236Smckusick 		    calloc(sblock.fs_ncg, roundup(sizeof (struct csum), BSIZE));
6394236Smckusick 		makecg();
6404236Smckusick 		for (i = 0; i < cssize(&sblock); i += BSIZE)
6414236Smckusick 			bwrite(&dfile, ((char *)sblock.fs_cs) + i,
6424236Smckusick 				csaddr(&sblock) + i / BSIZE, BSIZE);
6434236Smckusick 		n_ffree = sblock.fs_nffree;
6444236Smckusick 		n_bfree = sblock.fs_nbfree;
6454236Smckusick 	}
6464236Smckusick 
6474236Smckusick 	pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n",
6484236Smckusick 	    n_files, n_blks, n_ffree + FRAG * n_bfree, n_ffree, n_bfree);
6494236Smckusick 	if (dfile.mod) {
6504236Smckusick 		time(&sblock.fs_time);
6514236Smckusick 		sbdirty();
6524236Smckusick 	}
6534236Smckusick 	ckfini();
6544236Smckusick 	sync();
6554236Smckusick 	if (dfile.mod && hotroot) {
6564236Smckusick 		printf("\n***** BOOT UNIX (NO SYNC!) *****\n");
6574236Smckusick 		exit(4);
6584236Smckusick 	}
6594236Smckusick 	if (dfile.mod && preen == 0)
6604236Smckusick 		printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
6614236Smckusick 	free(blkmap);
6624236Smckusick 	free(freemap);
6634236Smckusick 	free(statemap);
6644236Smckusick 	free(lncntp);
6654236Smckusick }
6664236Smckusick 
6674236Smckusick /* VARARGS1 */
6684236Smckusick error(s1, s2, s3, s4)
6694236Smckusick char *s1;
6704236Smckusick {
6714236Smckusick 
6724236Smckusick 	printf(s1, s2, s3, s4);
6734236Smckusick }
6744236Smckusick 
6754236Smckusick /* VARARGS1 */
6764236Smckusick errexit(s1, s2, s3, s4)
6774236Smckusick char *s1;
6784236Smckusick {
6794236Smckusick 	error(s1, s2, s3, s4);
6804236Smckusick 	exit(8);
6814236Smckusick }
6824236Smckusick 
6834236Smckusick /*
6844236Smckusick  * An inconsistency occured which shouldn't during normal operations.
6854236Smckusick  * Die if preening, otw just printf.
6864236Smckusick  */
6874236Smckusick /* VARARGS1 */
6884236Smckusick pfatal(s, a1, a2, a3)
6894236Smckusick 	char *s;
6904236Smckusick {
6914236Smckusick 
6924236Smckusick 	if (preen) {
6934236Smckusick 		printf("%s: ", devname);
6944236Smckusick 		printf(s, a1, a2, a3);
6954236Smckusick 		printf("\n");
6964236Smckusick 		preendie();
6974236Smckusick 	}
6984236Smckusick 	printf(s, a1, a2, a3);
6994236Smckusick }
7004236Smckusick 
7014236Smckusick preendie()
7024236Smckusick {
7034236Smckusick 
7044236Smckusick 	printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
7054236Smckusick 	exit(8);
7064236Smckusick }
7074236Smckusick 
7084236Smckusick /*
7094236Smckusick  * Pwarn is like printf when not preening,
7104236Smckusick  * or a warning (preceded by filename) when preening.
7114236Smckusick  */
7124236Smckusick /* VARARGS1 */
7134236Smckusick pwarn(s, a1, a2, a3, a4, a5)
7144236Smckusick 	char *s;
7154236Smckusick {
7164236Smckusick 
7174236Smckusick 	if (preen)
7184236Smckusick 		printf("%s: ", devname);
7194236Smckusick 	printf(s, a1, a2, a3, a4, a5);
7204236Smckusick }
7214236Smckusick 
7224236Smckusick ckinode(dp, flg)
7234236Smckusick 	DINODE *dp;
7244236Smckusick 	register flg;
7254236Smckusick {
7264236Smckusick 	register daddr_t *ap;
7274236Smckusick 	register ret;
7284236Smckusick 	int (*func)(), n, ndb, size;
7294236Smckusick 
7304236Smckusick 	if (SPECIAL)
7314236Smckusick 		return (KEEPON);
7324236Smckusick 	func = (flg == ADDR) ? pfunc : dirscan;
7334236Smckusick 	ndb = howmany(dp->di_size, BSIZE);
7344252Smckusic 	for (ap = dp->di_db; ap < &dp->di_db[NDADDR]; ap++) {
7354236Smckusick 		if (--ndb == 0 && (dp->di_size&BMASK))
7364236Smckusick 			size = howmany(dp->di_size&BMASK, FSIZE);
7374236Smckusick 		else
7384236Smckusick 			size = FRAG;
7394236Smckusick 		if (*ap && (ret = (*func)(*ap, size)) & STOP)
7404236Smckusick 			return (ret);
7414236Smckusick 	}
7424236Smckusick 	for (n = 1; n <= 2; n++) {
7434236Smckusick 		if (*ap && (ret = iblock(*ap, n, flg, dp->di_size)) & STOP)
7444236Smckusick 			return (ret);
7454236Smckusick 		ap++;
7464236Smckusick 	}
7474236Smckusick 	return (KEEPON);
7484236Smckusick }
7494236Smckusick 
7504236Smckusick iblock(blk, ilevel, flg, isize)
7514236Smckusick 	daddr_t blk;
7524236Smckusick 	register ilevel;
7534236Smckusick 	int isize;
7544236Smckusick {
7554236Smckusick 	register daddr_t *ap;
7564236Smckusick 	register daddr_t *aplim;
7574236Smckusick 	register n;
7584236Smckusick 	int (*func)(), nif;
7594236Smckusick 	BUFAREA ib;
7604236Smckusick 
7614236Smckusick 	nif = howmany(isize - NDADDR*BSIZE, NINDIR / FRAG * BSIZE);
7624236Smckusick 	if (nif > FRAG || ilevel > 1)
7634236Smckusick 		nif = FRAG;
7644236Smckusick 	if (flg == ADDR) {
7654236Smckusick 		func = pfunc;
7664236Smckusick 		if (((n = (*func)(blk, nif)) & KEEPON) == 0)
7674236Smckusick 			return (n);
7684236Smckusick 	} else
7694236Smckusick 		func = dirscan;
7704236Smckusick 	if (outrange(blk))		/* protect thyself */
7714236Smckusick 		return (SKIP);
7724236Smckusick 	initbarea(&ib);
7734236Smckusick 	if (getblk(&ib, blk, nif * FSIZE) == NULL)
7744236Smckusick 		return (SKIP);
7754236Smckusick 	ilevel--;
7764236Smckusick 	aplim = & ib.b_un.b_indir[NINDIR*nif/FRAG];
7774236Smckusick 	for (ap = ib.b_un.b_indir; ap < aplim; ap++)
7784236Smckusick 		if (*ap) {
7794236Smckusick 			if (ilevel > 0)
7804236Smckusick 				n = iblock(*ap, ilevel, flg, BSIZE);
7814236Smckusick 			else
7824236Smckusick 				n = (*func)(*ap, BSIZE);
7834236Smckusick 			if (n & STOP)
7844236Smckusick 				return (n);
7854236Smckusick 		}
7864236Smckusick 	return (KEEPON);
7874236Smckusick }
7884236Smckusick 
7894236Smckusick pass1(blk, size)
7904236Smckusick 	daddr_t blk;
7914236Smckusick 	int size;
7924236Smckusick {
7934236Smckusick 	register daddr_t *dlp;
7944236Smckusick 	int res = KEEPON;
7954236Smckusick 
7964236Smckusick 	for (; size > 0; blk++, size--) {
7974236Smckusick 		if (outrange(blk)) {
7984236Smckusick 			blkerr("BAD", blk);
7994236Smckusick 			if (++badblk >= MAXBAD) {
8004236Smckusick 				printf("EXCESSIVE BAD BLKS I=%u", inum);
8014236Smckusick 				if (reply("CONTINUE") == 0)
8024236Smckusick 					errexit("");
8034236Smckusick 				return (STOP);
8044236Smckusick 			}
8054236Smckusick 			res = SKIP;
8064236Smckusick 		} else if (getbmap(blk)) {
8074236Smckusick 			blkerr("DUP", blk);
8084236Smckusick 			if (++dupblk >= MAXDUP) {
8094236Smckusick 				printf("EXCESSIVE DUP BLKS I=%u", inum);
8104236Smckusick 				if (reply("CONTINUE") == 0)
8114236Smckusick 					errexit("");
8124236Smckusick 				return (STOP);
8134236Smckusick 			}
8144236Smckusick 			if (enddup >= &duplist[DUPTBLSIZE]) {
8154236Smckusick 				printf("DUP TABLE OVERFLOW.");
8164236Smckusick 				if (reply("CONTINUE") == 0)
8174236Smckusick 					errexit("");
8184236Smckusick 				return (STOP);
8194236Smckusick 			}
8204236Smckusick 			for (dlp = duplist; dlp < muldup; dlp++)
8214236Smckusick 				if (*dlp == blk) {
8224236Smckusick 					*enddup++ = blk;
8234236Smckusick 					break;
8244236Smckusick 				}
8254236Smckusick 			if (dlp >= muldup) {
8264236Smckusick 				*enddup++ = *muldup;
8274236Smckusick 				*muldup++ = blk;
8284236Smckusick 			}
8294236Smckusick 		} else {
8304236Smckusick 			n_blks++;
8314236Smckusick 			setbmap(blk);
8324236Smckusick 		}
8334236Smckusick 		filsize++;
8344236Smckusick 	}
8354236Smckusick 	return (res);
8364236Smckusick }
8374236Smckusick 
8384236Smckusick pass1b(blk, size)
8394236Smckusick 	daddr_t blk;
8404236Smckusick 	int size;
8414236Smckusick {
8424236Smckusick 	register daddr_t *dlp;
8434236Smckusick 	int res = KEEPON;
8444236Smckusick 
8454236Smckusick 	for (; size > 0; blk++, size--) {
8464236Smckusick 		if (outrange(blk))
8474236Smckusick 			res = SKIP;
8484236Smckusick 		for (dlp = duplist; dlp < muldup; dlp++)
8494236Smckusick 			if (*dlp == blk) {
8504236Smckusick 				blkerr("DUP", blk);
8514236Smckusick 				*dlp = *--muldup;
8524236Smckusick 				*muldup = blk;
8534236Smckusick 				if (muldup == duplist)
8544236Smckusick 					return (STOP);
8554236Smckusick 			}
8564236Smckusick 	}
8574236Smckusick 	return (res);
8584236Smckusick }
8594236Smckusick 
8604236Smckusick pass2(dirp)
8614236Smckusick 	register DIRECT *dirp;
8624236Smckusick {
8634236Smckusick 	register char *p;
8644236Smckusick 	register n;
8654236Smckusick 	DINODE *dp;
8664236Smckusick 
8674236Smckusick 	if ((inum = dirp->d_ino) == 0)
8684236Smckusick 		return (KEEPON);
8694236Smckusick 	thisname = pathp;
8704236Smckusick 	for (p = dirp->d_name; p < &dirp->d_name[DIRSIZ]; )
8714236Smckusick 		if ((*pathp++ = *p++) == 0) {
8724236Smckusick 			--pathp;
8734236Smckusick 			break;
8744236Smckusick 		}
8754236Smckusick 	*pathp = 0;
8764236Smckusick 	n = 0;
8774236Smckusick 	if (inum > imax || inum < ROOTINO)
8784236Smckusick 		n = direrr("I OUT OF RANGE");
8794236Smckusick 	else {
8804236Smckusick again:
8814236Smckusick 		switch (getstate()) {
8824236Smckusick 		case USTATE:
8834236Smckusick 			n = direrr("UNALLOCATED");
8844236Smckusick 			break;
8854236Smckusick 
8864236Smckusick 		case CLEAR:
8874236Smckusick 			if ((n = direrr("DUP/BAD")) == 1)
8884236Smckusick 				break;
8894236Smckusick 			if ((dp = ginode()) == NULL)
8904236Smckusick 				break;
8914236Smckusick 			setstate(DIR ? DSTATE : FSTATE);
8924236Smckusick 			goto again;
8934236Smckusick 
8944236Smckusick 		case FSTATE:
8954236Smckusick 			declncnt();
8964236Smckusick 			break;
8974236Smckusick 
8984236Smckusick 		case DSTATE:
8994236Smckusick 			declncnt();
9004236Smckusick 			descend();
9014236Smckusick 			break;
9024236Smckusick 		}
9034236Smckusick 	}
9044236Smckusick 	pathp = thisname;
9054236Smckusick 	if (n == 0)
9064236Smckusick 		return (KEEPON);
9074236Smckusick 	dirp->d_ino = 0;
9084236Smckusick 	return (KEEPON|ALTERD);
9094236Smckusick }
9104236Smckusick 
9114236Smckusick pass4(blk, size)
9124236Smckusick daddr_t blk;
9134236Smckusick {
9144236Smckusick 	register daddr_t *dlp;
9154236Smckusick 	int res = KEEPON;
9164236Smckusick 
9174236Smckusick 	for (; size > 0; blk++, size--) {
9184236Smckusick 		if (outrange(blk))
9194236Smckusick 			res = SKIP;
9204236Smckusick 		else if (getbmap(blk)) {
9214236Smckusick 			for (dlp = duplist; dlp < enddup; dlp++)
9224236Smckusick 				if (*dlp == blk) {
9234236Smckusick 					*dlp = *--enddup;
9244236Smckusick 					return (KEEPON);
9254236Smckusick 				}
9264236Smckusick 			clrbmap(blk);
9274236Smckusick 			n_blks--;
9284236Smckusick 		}
9294236Smckusick 	}
9304236Smckusick 	return (res);
9314236Smckusick }
9324236Smckusick 
9334236Smckusick pass5(blk, size)
9344236Smckusick 	daddr_t blk;
9354236Smckusick 	int size;
9364236Smckusick {
9374236Smckusick 	int res = KEEPON;
9384236Smckusick 
9394236Smckusick 	for (; size > 0; blk++, size--) {
9404236Smckusick 		if (outrange(blk)) {
9414236Smckusick 			fixcg = 1;
9424236Smckusick 			if (preen)
9434236Smckusick 				pfatal("BAD BLOCKS IN BIT MAPS.");
9444236Smckusick 			if (++badblk >= MAXBAD) {
9454236Smckusick 				printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
9464236Smckusick 				if (reply("CONTINUE") == 0)
9474236Smckusick 					errexit("");
9484236Smckusick 				return (STOP);
9494236Smckusick 			}
9504236Smckusick 		} else if (getfmap(blk)) {
9514236Smckusick 			fixcg = 1;
9524236Smckusick 			if (++dupblk >= DUPTBLSIZE) {
9534236Smckusick 				printf("EXCESSIVE DUP BLKS IN BIT MAPS.");
9544236Smckusick 				if (reply("CONTINUE") == 0)
9554236Smckusick 					errexit("");
9564236Smckusick 				return (STOP);
9574236Smckusick 			}
9584236Smckusick 		} else {
9594236Smckusick 			n_ffree++;
9604236Smckusick 			setfmap(blk);
9614236Smckusick 		}
9624236Smckusick 	}
9634236Smckusick 	return (res);
9644236Smckusick }
9654236Smckusick 
9664236Smckusick outrange(blk)
9674236Smckusick 	daddr_t blk;
9684236Smckusick {
9694236Smckusick 	register int c;
9704236Smckusick 
9714236Smckusick 	c = dtog(blk, &sblock);
9724236Smckusick 	if (blk >= fmax || blk < cgdmin(c, &sblock))
9734236Smckusick 		return (1);
9744236Smckusick 	return (0);
9754236Smckusick }
9764236Smckusick 
9774236Smckusick blkerr(s, blk)
9784236Smckusick 	daddr_t blk;
9794236Smckusick 	char *s;
9804236Smckusick {
9814236Smckusick 	pfatal("%ld %s I=%u", blk, s, inum);
9824236Smckusick 	printf("\n");
9834236Smckusick 	setstate(CLEAR);	/* mark for possible clearing */
9844236Smckusick }
9854236Smckusick 
9864236Smckusick descend()
9874236Smckusick {
9884236Smckusick 	register DINODE *dp;
9894236Smckusick 	register char *savname;
9904236Smckusick 	off_t savsize;
9914236Smckusick 
9924236Smckusick 	setstate(FSTATE);
9934236Smckusick 	if ((dp = ginode()) == NULL)
9944236Smckusick 		return;
9954236Smckusick 	savname = thisname;
9964236Smckusick 	*pathp++ = '/';
9974236Smckusick 	savsize = filsize;
9984236Smckusick 	filsize = dp->di_size;
9994236Smckusick 	ckinode(dp, DATA);
10004236Smckusick 	thisname = savname;
10014236Smckusick 	*--pathp = 0;
10024236Smckusick 	filsize = savsize;
10034236Smckusick }
10044236Smckusick 
10054236Smckusick dirscan(blk, nf)
10064236Smckusick daddr_t blk;
10074236Smckusick int nf;
10084236Smckusick {
10094236Smckusick 	register DIRECT *dirp;
10104236Smckusick 	register DIRECT *edirp;
10114236Smckusick 	register char *p1, *p2;
10124236Smckusick 	register n;
10134236Smckusick 	DIRECT direntry;
10144236Smckusick 
10154236Smckusick 	if (outrange(blk)) {
10164236Smckusick 		filsize -= BSIZE;
10174236Smckusick 		return (SKIP);
10184236Smckusick 	}
10194236Smckusick 	edirp = &dirblk.b_dir[NDIRECT*nf/FRAG];
10204236Smckusick 	for (dirp = dirblk.b_dir; dirp < edirp &&
10214236Smckusick 		filsize > 0; dirp++, filsize -= sizeof(DIRECT)) {
10224236Smckusick 		if (getblk(&fileblk, blk, nf * FSIZE) == NULL) {
10234236Smckusick 			filsize -= (&dirblk.b_dir[NDIRECT]-dirp)*sizeof(DIRECT);
10244236Smckusick 			return (SKIP);
10254236Smckusick 		}
10264236Smckusick 		p1 = &dirp->d_name[DIRSIZ];
10274236Smckusick 		p2 = &direntry.d_name[DIRSIZ];
10284236Smckusick 		while (p1 > (char *)dirp)
10294236Smckusick 			*--p2 = *--p1;
10304236Smckusick 		if ((n = (*pfunc)(&direntry)) & ALTERD) {
10314236Smckusick 			if (getblk(&fileblk, blk, nf * FSIZE) != NULL) {
10324236Smckusick 				p1 = &dirp->d_name[DIRSIZ];
10334236Smckusick 				p2 = &direntry.d_name[DIRSIZ];
10344236Smckusick 				while (p1 > (char *)dirp)
10354236Smckusick 					*--p1 = *--p2;
10364236Smckusick 				sbdirty();
10374236Smckusick 			} else
10384236Smckusick 				n &= ~ALTERD;
10394236Smckusick 		}
10404236Smckusick 		if (n & STOP)
10414236Smckusick 			return (n);
10424236Smckusick 	}
10434236Smckusick 	return (filsize > 0 ? KEEPON : STOP);
10444236Smckusick }
10454236Smckusick 
10464236Smckusick direrr(s)
10474236Smckusick char *s;
10484236Smckusick {
10494236Smckusick 	register DINODE *dp;
10504236Smckusick 
10514236Smckusick 	pwarn("%s ", s);
10524236Smckusick 	pinode();
10534236Smckusick 	printf("\n");
10544236Smckusick 	if ((dp = ginode()) != NULL && ftypeok(dp))
10554236Smckusick 		pfatal("%s=%s", DIR?"DIR":"FILE", pathname);
10564236Smckusick 	else
10574236Smckusick 		pfatal("NAME=%s", pathname);
10584236Smckusick 	return (reply("REMOVE"));
10594236Smckusick }
10604236Smckusick 
10614236Smckusick adjust(lcnt)
10624236Smckusick register short lcnt;
10634236Smckusick {
10644236Smckusick 	register DINODE *dp;
10654236Smckusick 
10664236Smckusick 	if ((dp = ginode()) == NULL)
10674236Smckusick 		return;
10684236Smckusick 	if (dp->di_nlink == lcnt) {
10694236Smckusick 		if (linkup() == 0)
10704236Smckusick 			clri("UNREF", 0);
10714236Smckusick 	}
10724236Smckusick 	else {
10734236Smckusick 		pwarn("LINK COUNT %s",
10744236Smckusick 			(lfdir==inum)?lfname:(DIR?"DIR":"FILE"));
10754236Smckusick 		pinode();
10764236Smckusick 		printf(" COUNT %d SHOULD BE %d",
10774236Smckusick 			dp->di_nlink, dp->di_nlink-lcnt);
10784236Smckusick 		if (preen) {
10794236Smckusick 			if (lcnt < 0) {
10804236Smckusick 				printf("\n");
10814236Smckusick 				preendie();
10824236Smckusick 			}
10834236Smckusick 			printf(" (ADJUSTED)\n");
10844236Smckusick 		}
10854236Smckusick 		if (preen || reply("ADJUST") == 1) {
10864236Smckusick 			dp->di_nlink -= lcnt;
10874236Smckusick 			inodirty();
10884236Smckusick 		}
10894236Smckusick 	}
10904236Smckusick }
10914236Smckusick 
10924236Smckusick clri(s, flg)
10934236Smckusick char *s;
10944236Smckusick {
10954236Smckusick 	register DINODE *dp;
10964236Smckusick 
10974236Smckusick 	if ((dp = ginode()) == NULL)
10984236Smckusick 		return;
10994236Smckusick 	if (flg == 1) {
11004236Smckusick 		pwarn("%s %s", s, DIR?"DIR":"FILE");
11014236Smckusick 		pinode();
11024236Smckusick 	}
11034236Smckusick 	if (preen || reply("CLEAR") == 1) {
11044236Smckusick 		if (preen)
11054236Smckusick 			printf(" (CLEARED)\n");
11064236Smckusick 		n_files--;
11074236Smckusick 		pfunc = pass4;
11084236Smckusick 		ckinode(dp, ADDR);
11094236Smckusick 		zapino(dp);
11104236Smckusick 		inodirty();
11114236Smckusick 		inosumbad++;
11124236Smckusick 	}
11134236Smckusick }
11144236Smckusick 
11154236Smckusick setup(dev)
11164236Smckusick char *dev;
11174236Smckusick {
11184236Smckusick 	dev_t rootdev;
11194236Smckusick 	struct stat statb;
11204236Smckusick 	int super = bflag ? bflag : SBLOCK;
11214236Smckusick 
11224236Smckusick 	bflag = 0;
11234236Smckusick 	if (stat("/", &statb) < 0)
11244236Smckusick 		errexit("Can't stat root\n");
11254236Smckusick 	rootdev = statb.st_dev;
11264236Smckusick 	if (stat(dev, &statb) < 0) {
11274236Smckusick 		error("Can't stat %s\n", dev);
11284236Smckusick 		return (0);
11294236Smckusick 	}
11304236Smckusick 	rawflg = 0;
11314236Smckusick 	if ((statb.st_mode & S_IFMT) == S_IFBLK)
11324236Smckusick 		;
11334236Smckusick 	else if ((statb.st_mode & S_IFMT) == S_IFCHR)
11344236Smckusick 		rawflg++;
11354236Smckusick 	else {
11364236Smckusick 		if (reply("file is not a block or character device; OK") == 0)
11374236Smckusick 			return (0);
11384236Smckusick 	}
11394236Smckusick 	if (rootdev == statb.st_rdev)
11404236Smckusick 		hotroot++;
11414236Smckusick 	if ((dfile.rfdes = open(dev, 0)) < 0) {
11424236Smckusick 		error("Can't open %s\n", dev);
11434236Smckusick 		return (0);
11444236Smckusick 	}
11454236Smckusick 	if (preen == 0)
11464236Smckusick 		printf("** %s", dev);
11474236Smckusick 	if (nflag || (dfile.wfdes = open(dev, 1)) < 0) {
11484236Smckusick 		dfile.wfdes = -1;
11494236Smckusick 		if (preen)
11504236Smckusick 			pfatal("NO WRITE ACCESS");
11514236Smckusick 		printf(" (NO WRITE)");
11524236Smckusick 	}
11534236Smckusick 	if (preen == 0)
11544236Smckusick 		printf("\n");
11554236Smckusick 	fixcg = 0; inosumbad = 0; offsumbad = 0;
11564236Smckusick 	dfile.mod = 0;
11574236Smckusick 	n_files = n_blks = n_ffree = n_bfree = 0;
11584236Smckusick 	muldup = enddup = &duplist[0];
11594236Smckusick 	badlnp = &badlncnt[0];
11604236Smckusick 	lfdir = 0;
11614236Smckusick 	rplyflag = 0;
11624236Smckusick 	initbarea(&sblk);
11634236Smckusick 	initbarea(&fileblk);
11644236Smckusick 	initbarea(&inoblk);
11654236Smckusick 	initbarea(&cgblk);
11664236Smckusick 	if (getblk(&sblk, super, BSIZE) == NULL) {
11674236Smckusick 		ckfini();
11684236Smckusick 		return (0);
11694236Smckusick 	}
11704236Smckusick 	sblk.b_bno = SBLOCK;
11714236Smckusick 	if (sblock.fs_magic != FS_MAGIC)
11724236Smckusick 		{ badsb("MAGIC NUMBER WRONG"); return (0); }
11734236Smckusick 	if (sblock.fs_ncg < 1)
11744236Smckusick 		{ badsb("NCG OUT OF RANGE"); return (0); }
11754236Smckusick 	if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
11764236Smckusick 		{ badsb("CPG OUT OF RANGE"); return (0); }
11774236Smckusick 	if (sblock.fs_nsect < 1)
11784236Smckusick 		{ badsb("NSECT < 1"); return (0); }
11794236Smckusick 	if (sblock.fs_ntrak < 1)
11804236Smckusick 		{ badsb("NTRAK < 1"); return (0); }
11814236Smckusick 	if (sblock.fs_ipg*sblock.fs_ncg > 65535 || sblock.fs_ipg%INOPB)
11824236Smckusick 		{ badsb("TOO MANY INODES IMPLIED"); return (0); }
11834236Smckusick 	if (sblock.fs_ipg/INOPF+IBLOCK >=
11844236Smckusick 	    sblock.fs_cpg*sblock.fs_nsect*sblock.fs_ntrak/NSPF)
11854236Smckusick 		{ badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); return (0); }
11864236Smckusick /* THE FOLLOWING COULD BE CHECKED MORE CLOSELY... */
11874236Smckusick 	if ((sblock.fs_ncg + 1) * sblock.fs_cpg < sblock.fs_ncyl ||
11884236Smckusick 	    (sblock.fs_ncg - 1) * sblock.fs_cpg > sblock.fs_ncyl)
11894236Smckusick 		{ badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
11904236Smckusick 	if (sblock.fs_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF)
11914236Smckusick 		{ badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); }
11924236Smckusick 	if (sblock.fs_size <=
11934236Smckusick 	    (sblock.fs_ncg-1)*sblock.fs_fpg+IBLOCK+sblock.fs_ipg/INOPF)
11944236Smckusick 		{ badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); }
11954236Smckusick 	if (sblock.fs_size*NSPF >
11964236Smckusick 	    (sblock.fs_ncg+2)*sblock.fs_cpg*sblock.fs_spc)
11974236Smckusick 		{ badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
11984236Smckusick 	/* rest we COULD repair... */
11994236Smckusick 	if (sblock.fs_sblkno != SBLOCK)
12004236Smckusick 		{ badsb("BLKNO CORRUPTED"); return (0); }
12014236Smckusick 	if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak)
12024236Smckusick 		{ badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); }
12034236Smckusick 	if (sblock.fs_cgsize != cgsize(&sblock))
12044236Smckusick 		{ badsb("CGSIZE INCORRECT"); return (0); }
12054236Smckusick 	if (sblock.fs_cssize != cssize(&sblock))
12064236Smckusick 		{ badsb("CSSIZE INCORRECT"); return (0); }
12074236Smckusick 	fmax = sblock.fs_size;
12084236Smckusick 	imax = sblock.fs_ncg * sblock.fs_ipg;
12094236Smckusick 
12104236Smckusick 	bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
12114236Smckusick 	blkmap = (char *)calloc(bmapsz, sizeof (char));
12124236Smckusick 	freemap = (char *)calloc(bmapsz, sizeof (char));
12134236Smckusick 	statemap = (char *)calloc(imax+1, sizeof(char));
12144236Smckusick 	lncntp = (short *)calloc(imax+1, sizeof(short));
12154236Smckusick 
12164236Smckusick 	niblk = sblock.fs_ipg / INOPB;
12174236Smckusick 	startib = fmax;
12184236Smckusick 	return (1);
12194236Smckusick 
12204236Smckusick badsb:
12214236Smckusick 	ckfini();
12224236Smckusick 	return (0);
12234236Smckusick }
12244236Smckusick 
12254236Smckusick badsb(s)
12264236Smckusick 	char *s;
12274236Smckusick {
12284236Smckusick 
12294236Smckusick 	if (preen)
12304236Smckusick 		printf("%s: ", devname);
12314236Smckusick 	printf("BAD SUPER BLOCK: %s\n", s);
12324236Smckusick 	pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
12334236Smckusick 	pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
12344236Smckusick }
12354236Smckusick 
12364236Smckusick DINODE *
12374236Smckusick ginode()
12384236Smckusick {
12394236Smckusick 	daddr_t iblk;
12404236Smckusick 
12414236Smckusick 	if (inum > imax)
12424236Smckusick 		return (NULL);
12434236Smckusick 	iblk = itod(inum, &sblock);
12444236Smckusick 	if (iblk < startib || iblk >= startib+niblk) {
12454236Smckusick 		if (inoblk.b_dirty)
12464236Smckusick 			bwrite(&dfile, (char *)ibase, startib, niblk*BSIZE);
12474236Smckusick 		inoblk.b_dirty = 0;
12484236Smckusick 		startib = cgimin(inum/sblock.fs_ipg, &sblock);
12494236Smckusick 		if (bread(&dfile, (char *)ibase, iblk, niblk*BSIZE) == 0) {
12504236Smckusick 			startib = fmax;
12514236Smckusick 			return (NULL);
12524236Smckusick 		}
12534236Smckusick 		startib = iblk;
12544236Smckusick 	}
12554236Smckusick 	return (&ibase[(iblk - startib)*INOPB + itoo(inum)]);
12564236Smckusick }
12574236Smckusick 
12584236Smckusick ftypeok(dp)
12594236Smckusick 	DINODE *dp;
12604236Smckusick {
12614236Smckusick 	switch (dp->di_mode & IFMT) {
12624236Smckusick 
12634236Smckusick 	case IFDIR:
12644236Smckusick 	case IFREG:
12654236Smckusick 	case IFBLK:
12664236Smckusick 	case IFCHR:
12674236Smckusick 	case IFMPC:
12684236Smckusick 	case IFMPB:
12694236Smckusick 		return (1);
12704236Smckusick 
12714236Smckusick 	default:
12724236Smckusick 		return (0);
12734236Smckusick 	}
12744236Smckusick }
12754236Smckusick 
12764236Smckusick reply(s)
12774236Smckusick 	char *s;
12784236Smckusick {
12794236Smckusick 	char line[80];
12804236Smckusick 
12814236Smckusick 	if (preen)
12824236Smckusick 		pfatal("INTERNAL ERROR: GOT TO reply()");
12834236Smckusick 	rplyflag = 1;
12844236Smckusick 	printf("\n%s? ", s);
12854236Smckusick 	if (nflag || dfile.wfdes < 0) {
12864236Smckusick 		printf(" no\n\n");
12874236Smckusick 		return (0);
12884236Smckusick 	}
12894236Smckusick 	if (yflag) {
12904236Smckusick 		printf(" yes\n\n");
12914236Smckusick 		return (1);
12924236Smckusick 	}
12934236Smckusick 	if (getline(stdin, line, sizeof(line)) == EOF)
12944236Smckusick 		errexit("\n");
12954236Smckusick 	printf("\n");
12964236Smckusick 	if (line[0] == 'y' || line[0] == 'Y')
12974236Smckusick 		return (1);
12984236Smckusick 	else
12994236Smckusick 		return (0);
13004236Smckusick }
13014236Smckusick 
13024236Smckusick getline(fp, loc, maxlen)
13034236Smckusick 	FILE *fp;
13044236Smckusick 	char *loc;
13054236Smckusick {
13064236Smckusick 	register n;
13074236Smckusick 	register char *p, *lastloc;
13084236Smckusick 
13094236Smckusick 	p = loc;
13104236Smckusick 	lastloc = &p[maxlen-1];
13114236Smckusick 	while ((n = getc(fp)) != '\n') {
13124236Smckusick 		if (n == EOF)
13134236Smckusick 			return (EOF);
13144236Smckusick 		if (!isspace(n) && p < lastloc)
13154236Smckusick 			*p++ = n;
13164236Smckusick 	}
13174236Smckusick 	*p = 0;
13184236Smckusick 	return (p - loc);
13194236Smckusick }
13204236Smckusick 
13214236Smckusick BUFAREA *
13224236Smckusick getblk(bp, blk, size)
13234236Smckusick 	daddr_t blk;
13244236Smckusick 	register BUFAREA *bp;
13254236Smckusick 	int size;
13264236Smckusick {
13274236Smckusick 	register struct filecntl *fcp;
13284236Smckusick 
13294236Smckusick 	fcp = &dfile;
13304236Smckusick 	if (bp->b_bno == blk)
13314236Smckusick 		return (bp);
13324236Smckusick 	flush(fcp, bp);
13334236Smckusick 	if (bread(fcp, bp->b_un.b_buf, blk, size) != 0) {
13344236Smckusick 		bp->b_bno = blk;
13354236Smckusick 		bp->b_size = size;
13364236Smckusick 		return (bp);
13374236Smckusick 	}
13384236Smckusick 	bp->b_bno = (daddr_t)-1;
13394236Smckusick 	return (NULL);
13404236Smckusick }
13414236Smckusick 
13424236Smckusick flush(fcp, bp)
13434236Smckusick 	struct filecntl *fcp;
13444236Smckusick 	register BUFAREA *bp;
13454236Smckusick {
13464236Smckusick 
13474236Smckusick 	if (bp->b_dirty)
13484236Smckusick 		bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size);
13494236Smckusick 	bp->b_dirty = 0;
13504236Smckusick }
13514236Smckusick 
13524236Smckusick rwerr(s, blk)
13534236Smckusick 	char *s;
13544236Smckusick 	daddr_t blk;
13554236Smckusick {
13564236Smckusick 
13574236Smckusick 	if (preen == 0)
13584236Smckusick 		printf("\n");
13594236Smckusick 	pfatal("CANNOT %s: BLK %ld", s, blk);
13604236Smckusick 	if (reply("CONTINUE") == 0)
13614236Smckusick 		errexit("Program terminated\n");
13624236Smckusick }
13634236Smckusick 
13644236Smckusick ckfini()
13654236Smckusick {
13664236Smckusick 
13674236Smckusick 	flush(&dfile, &fileblk);
13684236Smckusick 	flush(&dfile, &sblk);
13694236Smckusick 	flush(&dfile, &inoblk);
13704236Smckusick 	close(dfile.rfdes);
13714236Smckusick 	close(dfile.wfdes);
13724236Smckusick }
13734236Smckusick 
13744236Smckusick pinode()
13754236Smckusick {
13764236Smckusick 	register DINODE *dp;
13774236Smckusick 	register char *p;
13784236Smckusick 	char uidbuf[200];
13794236Smckusick 	char *ctime();
13804236Smckusick 
13814236Smckusick 	printf(" I=%u ", inum);
13824236Smckusick 	if ((dp = ginode()) == NULL)
13834236Smckusick 		return;
13844236Smckusick 	printf(" OWNER=");
13854236Smckusick 	if (getpw((int)dp->di_uid, uidbuf) == 0) {
13864236Smckusick 		for (p = uidbuf; *p != ':'; p++);
13874236Smckusick 		*p = 0;
13884236Smckusick 		printf("%s ", uidbuf);
13894236Smckusick 	}
13904236Smckusick 	else {
13914236Smckusick 		printf("%d ", dp->di_uid);
13924236Smckusick 	}
13934236Smckusick 	printf("MODE=%o\n", dp->di_mode);
13944236Smckusick 	if (preen)
13954236Smckusick 		printf("%s: ", devname);
13964236Smckusick 	printf("SIZE=%ld ", dp->di_size);
13974236Smckusick 	p = ctime(&dp->di_mtime);
13984236Smckusick 	printf("MTIME=%12.12s %4.4s ", p+4, p+20);
13994236Smckusick }
14004236Smckusick 
14014236Smckusick copy(fp, tp, size)
14024236Smckusick 	register char *tp, *fp;
14034236Smckusick 	unsigned size;
14044236Smckusick {
14054236Smckusick 
14064236Smckusick 	while (size--)
14074236Smckusick 		*tp++ = *fp++;
14084236Smckusick }
14094236Smckusick 
14104236Smckusick makecg()
14114236Smckusick {
14124236Smckusick 	int c;
14134236Smckusick 	daddr_t dbase, d, dmin, dmax;
14144236Smckusick 	long i, j, s;
14154236Smckusick 	register struct csum *cs;
14164236Smckusick 
14174236Smckusick 	sblock.fs_nbfree = 0;
14184236Smckusick 	sblock.fs_nffree = 0;
14194236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
14204236Smckusick 		dbase = cgbase(c, &sblock);
14214236Smckusick 		dmax = dbase + sblock.fs_fpg;
14224236Smckusick 		if (dmax > sblock.fs_size)
14234236Smckusick 			dmax = sblock.fs_size;
14244236Smckusick 		cs = &sblock.fs_cs[c];
14254236Smckusick 		cgrp.cg_time = time(0);
14264236Smckusick 		cgrp.cg_magic = CG_MAGIC;
14274236Smckusick 		cgrp.cg_cgx = c;
14284236Smckusick 		cgrp.cg_ncyl = sblock.fs_cpg;
14294236Smckusick 		cgrp.cg_niblk = sblock.fs_ipg;
14304236Smckusick 		cgrp.cg_ndblk = dmax - dbase;
14314236Smckusick 		cgrp.cg_ndir = 0;
14324236Smckusick 		cgrp.cg_nffree = 0;
14334236Smckusick 		cgrp.cg_nbfree = 0;
14344236Smckusick 		cgrp.cg_nifree = 0;
14354236Smckusick 		cgrp.cg_rotor = 0;
1436*4258Smckusic 		cgrp.cg_irotor = 0;
14374236Smckusick 		inum = sblock.fs_ipg * c;
14384236Smckusick 		for (i = 0; i < sblock.fs_ipg; inum++, i++)
14394236Smckusick 		switch (getstate()) {
14404236Smckusick 
14414236Smckusick 		case USTATE:
14424236Smckusick 			cgrp.cg_nifree++;
14434236Smckusick 			clrbit(cgrp.cg_iused, i);
14444236Smckusick 			continue;
14454236Smckusick 
14464236Smckusick 		case DSTATE:
14474236Smckusick 			cgrp.cg_ndir++;
14484236Smckusick 			/* fall into ... */
14494236Smckusick 
14504236Smckusick 		case FSTATE:
14514236Smckusick 			setbit(cgrp.cg_iused, i);
14524236Smckusick 			continue;
14534236Smckusick 
14544236Smckusick 		default:
14554236Smckusick 			errexit("internal error: inode state %d in makecg()\n",
14564236Smckusick 			    getstate());
14574236Smckusick 		}
14584236Smckusick 		while (i < MAXIPG) {
14594236Smckusick 			clrbit(cgrp.cg_iused, i);
14604236Smckusick 			i++;
14614236Smckusick 		}
14624236Smckusick 		for (s = 0; s < MAXCPG; s++)
14634236Smckusick 			for (i = 0; i < NRPOS; i++)
14644236Smckusick 				cgrp.cg_b[s][i] = 0;
14654236Smckusick 		dmin = cgdmin(c, &sblock) - dbase;
14664236Smckusick 		if (c == 0) {
14674236Smckusick 			dmin += howmany(cssize(&sblock), BSIZE) * FRAG;
14684236Smckusick 		}
14694236Smckusick 		for (d = 0; d < dmin; d++)
14704236Smckusick 			clrbit(cgrp.cg_free, d);
14714236Smckusick 		for (; (d + FRAG) <= dmax - dbase; d += FRAG) {
14724236Smckusick 			j = 0;
14734236Smckusick 			for (i = 0; i < FRAG; i++) {
14744236Smckusick 				if (!getbmap(dbase+d+i)) {
14754236Smckusick 					setbit(cgrp.cg_free, d+i);
14764236Smckusick 					j++;
14774236Smckusick 				} else
14784236Smckusick 					clrbit(cgrp.cg_free, d+i);
14794236Smckusick 			}
14804236Smckusick 			if (j == FRAG) {
14814236Smckusick 				cgrp.cg_nbfree++;
14824236Smckusick 				s = d * NSPF;
14834236Smckusick 				cgrp.cg_b[s/sblock.fs_spc]
14844236Smckusick 				  [s%sblock.fs_nsect*NRPOS/sblock.fs_nsect]++;
14854236Smckusick 			} else
14864236Smckusick 				cgrp.cg_nffree += j;
14874236Smckusick 		}
14884236Smckusick 		for (; d < dmax - dbase; d++) {
14894236Smckusick 			if (!getbmap(dbase+d)) {
14904236Smckusick 				setbit(cgrp.cg_free, d);
14914236Smckusick 				cgrp.cg_nffree++;
14924236Smckusick 			} else
14934236Smckusick 				clrbit(cgrp.cg_free, d);
14944236Smckusick 		}
14954236Smckusick 		for (; d < MAXBPG; d++)
14964236Smckusick 			clrbit(cgrp.cg_free, d);
14974236Smckusick 		sblock.fs_nffree += cgrp.cg_nffree;
14984236Smckusick 		sblock.fs_nbfree += cgrp.cg_nbfree;
14994236Smckusick 		cs->cs_ndir = cgrp.cg_ndir;
15004236Smckusick 		cs->cs_nifree = cgrp.cg_nifree;
15014236Smckusick 		cs->cs_nbfree = cgrp.cg_nbfree;
15024236Smckusick 		bwrite(&dfile, &cgrp, cgtod(c, &sblock), sblock.fs_cgsize);
15034236Smckusick 	}
15044236Smckusick 	sblock.fs_ronly = 0;
15054236Smckusick 	sblock.fs_fmod = 0;
15064236Smckusick 	sbdirty();
15074236Smckusick }
15084236Smckusick 
15094236Smckusick findino(dirp)
15104236Smckusick 	register DIRECT *dirp;
15114236Smckusick {
15124236Smckusick 	register char *p1, *p2;
15134236Smckusick 
15144236Smckusick 	if (dirp->d_ino == 0)
15154236Smckusick 		return (KEEPON);
15164236Smckusick 	for (p1 = dirp->d_name, p2 = srchname;*p2++ == *p1; p1++) {
15174236Smckusick 		if (*p1 == 0 || p1 == &dirp->d_name[DIRSIZ-1]) {
15184236Smckusick 			if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
15194236Smckusick 				parentdir = dirp->d_ino;
15204236Smckusick 			return (STOP);
15214236Smckusick 		}
15224236Smckusick 	}
15234236Smckusick 	return (KEEPON);
15244236Smckusick }
15254236Smckusick 
15264236Smckusick mkentry(dirp)
15274236Smckusick 	register DIRECT *dirp;
15284236Smckusick {
15294236Smckusick 	register ino_t in;
15304236Smckusick 	register char *p;
15314236Smckusick 
15324236Smckusick 	if (dirp->d_ino)
15334236Smckusick 		return (KEEPON);
15344236Smckusick 	dirp->d_ino = orphan;
15354236Smckusick 	in = orphan;
15364236Smckusick 	p = &dirp->d_name[8];
15374236Smckusick 	*--p = 0;
15384236Smckusick 	while (p > dirp->d_name) {
15394236Smckusick 		*--p = (in % 10) + '0';
15404236Smckusick 		in /= 10;
15414236Smckusick 	}
15424236Smckusick 	*p = '#';
15434236Smckusick 	return (ALTERD|STOP);
15444236Smckusick }
15454236Smckusick 
15464236Smckusick chgdd(dirp)
15474236Smckusick 	register DIRECT *dirp;
15484236Smckusick {
15494236Smckusick 	if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
15504236Smckusick 	dirp->d_name[2] == 0) {
15514236Smckusick 		dirp->d_ino = lfdir;
15524236Smckusick 		return (ALTERD|STOP);
15534236Smckusick 	}
15544236Smckusick 	return (KEEPON);
15554236Smckusick }
15564236Smckusick 
15574236Smckusick linkup()
15584236Smckusick {
15594236Smckusick 	register DINODE *dp;
15604236Smckusick 	register lostdir;
15614236Smckusick 	register ino_t pdir;
15624236Smckusick 
15634236Smckusick 	if ((dp = ginode()) == NULL)
15644236Smckusick 		return (0);
15654236Smckusick 	lostdir = DIR;
15664236Smckusick 	pdir = parentdir;
15674236Smckusick 	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
15684236Smckusick 	pinode();
15694236Smckusick 	if (preen && dp->di_size == 0)
15704236Smckusick 		return (0);
15714236Smckusick 	if (preen)
15724236Smckusick 		printf(" (RECONNECTED)\n");
15734236Smckusick 	else
15744236Smckusick 		if (reply("RECONNECT") == 0)
15754236Smckusick 			return (0);
15764236Smckusick 	orphan = inum;
15774236Smckusick 	if (lfdir == 0) {
15784236Smckusick 		inum = ROOTINO;
15794236Smckusick 		if ((dp = ginode()) == NULL) {
15804236Smckusick 			inum = orphan;
15814236Smckusick 			return (0);
15824236Smckusick 		}
15834236Smckusick 		pfunc = findino;
15844236Smckusick 		srchname = lfname;
15854236Smckusick 		filsize = dp->di_size;
15864236Smckusick 		parentdir = 0;
15874236Smckusick 		ckinode(dp, DATA);
15884236Smckusick 		inum = orphan;
15894236Smckusick 		if ((lfdir = parentdir) == 0) {
15904236Smckusick 			pfatal("SORRY. NO lost+found DIRECTORY");
15914236Smckusick 			printf("\n\n");
15924236Smckusick 			return (0);
15934236Smckusick 		}
15944236Smckusick 	}
15954236Smckusick 	inum = lfdir;
15964236Smckusick 	if ((dp = ginode()) == NULL || !DIR || getstate() != FSTATE) {
15974236Smckusick 		inum = orphan;
15984236Smckusick 		pfatal("SORRY. NO lost+found DIRECTORY");
15994236Smckusick 		printf("\n\n");
16004236Smckusick 		return (0);
16014236Smckusick 	}
16024236Smckusick 	if (dp->di_size & BMASK) {
16034236Smckusick 		dp->di_size = roundup(dp->di_size, BSIZE);
16044236Smckusick 		inodirty();
16054236Smckusick 	}
16064236Smckusick 	filsize = dp->di_size;
16074236Smckusick 	inum = orphan;
16084236Smckusick 	pfunc = mkentry;
16094236Smckusick 	if ((ckinode(dp, DATA) & ALTERD) == 0) {
16104236Smckusick 		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
16114236Smckusick 		printf("\n\n");
16124236Smckusick 		return (0);
16134236Smckusick 	}
16144236Smckusick 	declncnt();
16154236Smckusick 	if (lostdir) {
16164236Smckusick 		pfunc = chgdd;
16174236Smckusick 		dp = ginode();
16184236Smckusick 		filsize = dp->di_size;
16194236Smckusick 		ckinode(dp, DATA);
16204236Smckusick 		inum = lfdir;
16214236Smckusick 		if ((dp = ginode()) != NULL) {
16224236Smckusick 			dp->di_nlink++;
16234236Smckusick 			inodirty();
16244236Smckusick 			setlncnt(getlncnt()+1);
16254236Smckusick 		}
16264236Smckusick 		inum = orphan;
16274236Smckusick 		pwarn("DIR I=%u CONNECTED. ", orphan);
16284236Smckusick 		printf("PARENT WAS I=%u\n", pdir);
16294236Smckusick 		if (preen == 0)
16304236Smckusick 			printf("\n");
16314236Smckusick 	}
16324236Smckusick 	return (1);
16334236Smckusick }
16344236Smckusick 
16354236Smckusick bread(fcp, buf, blk, size)
16364236Smckusick 	daddr_t blk;
16374236Smckusick 	register struct filecntl *fcp;
16384236Smckusick 	register size;
16394236Smckusick 	char *buf;
16404236Smckusick {
16414236Smckusick 	if (lseek(fcp->rfdes, blk*FSIZE, 0) < 0)
16424236Smckusick 		rwerr("SEEK", blk);
16434236Smckusick 	else if (read(fcp->rfdes, buf, size) == size)
16444236Smckusick 		return (1);
16454236Smckusick 	rwerr("READ", blk);
16464236Smckusick 	return (0);
16474236Smckusick }
16484236Smckusick 
16494236Smckusick bwrite(fcp, buf, blk, size)
16504236Smckusick 	daddr_t blk;
16514236Smckusick 	register struct filecntl *fcp;
16524236Smckusick 	register size;
16534236Smckusick 	char *buf;
16544236Smckusick {
16554236Smckusick 
16564236Smckusick 	if (fcp->wfdes < 0)
16574236Smckusick 		return (0);
16584236Smckusick 	if (lseek(fcp->wfdes, blk*FSIZE, 0) < 0)
16594236Smckusick 		rwerr("SEEK", blk);
16604236Smckusick 	else if (write(fcp->wfdes, buf, size) == size) {
16614236Smckusick 		fcp->mod = 1;
16624236Smckusick 		return (1);
16634236Smckusick 	}
16644236Smckusick 	rwerr("WRITE", blk);
16654236Smckusick 	return (0);
16664236Smckusick }
16674236Smckusick 
16684236Smckusick catch()
16694236Smckusick {
16704236Smckusick 
16714236Smckusick 	ckfini();
16724236Smckusick 	exit(12);
16734236Smckusick }
1674