xref: /csrg-svn/sbin/fsck/main.c (revision 9255)
1*9255Smckusick char version[] = "@(#)main.c	2.17	(Berkeley)	11/15/82";
24428Smckusic 
34236Smckusick #include <stdio.h>
44236Smckusick #include <ctype.h>
56489Smckusick #include <sys/param.h>
66489Smckusick #include <sys/fs.h>
76489Smckusick #include <sys/inode.h>
86634Smckusick #include <dir.h>
96489Smckusick #include <sys/stat.h>
104236Smckusick #include <fstab.h>
114236Smckusick 
12*9255Smckusick /* RECONSTRUCT ONLY BAD CG IN PASS 6 */
13*9255Smckusick 
144236Smckusick typedef	int	(*SIG_TYP)();
154236Smckusick 
165347Smckusic #define	MAXNINDIR	(MAXBSIZE / sizeof (daddr_t))
175347Smckusic #define	MAXINOPB	(MAXBSIZE / sizeof (struct dinode))
185325Smckusic #define	SPERB		(MAXBSIZE / sizeof(short))
194236Smckusick 
204236Smckusick #define	MAXDUP	10		/* limit on dup blks (per inode) */
214236Smckusick #define	MAXBAD	10		/* limit on bad blks (per inode) */
224236Smckusick 
234236Smckusick #define	USTATE	0		/* inode not allocated */
244236Smckusick #define	FSTATE	01		/* inode is file */
254236Smckusick #define	DSTATE	02		/* inode is directory */
264236Smckusick #define	CLEAR	03		/* inode is to be cleared */
274236Smckusick 
284236Smckusick typedef struct dinode	DINODE;
294236Smckusick typedef struct direct	DIRECT;
304236Smckusick 
314236Smckusick #define	ALLOC	((dp->di_mode & IFMT) != 0)
325877Smckusic #define	DIRCT	((dp->di_mode & IFMT) == IFDIR)
334236Smckusick #define	REG	((dp->di_mode & IFMT) == IFREG)
344236Smckusick #define	BLK	((dp->di_mode & IFMT) == IFBLK)
354236Smckusick #define	CHR	((dp->di_mode & IFMT) == IFCHR)
366837Smckusick #define	LNK	((dp->di_mode & IFMT) == IFLNK)
376285Smckusick #define	SPECIAL	(BLK || CHR)
384236Smckusick 
394465Smckusic ino_t	startinum;		/* blk num of first in raw area */
404236Smckusick 
414236Smckusick struct bufarea {
424236Smckusick 	struct bufarea	*b_next;		/* must be first */
434236Smckusick 	daddr_t	b_bno;
444236Smckusick 	int	b_size;
454236Smckusick 	union {
465325Smckusic 		char	b_buf[MAXBSIZE];	/* buffer space */
474236Smckusick 		short	b_lnks[SPERB];		/* link counts */
485325Smckusic 		daddr_t	b_indir[MAXNINDIR];	/* indirect block */
494236Smckusick 		struct	fs b_fs;		/* super block */
504236Smckusick 		struct	cg b_cg;		/* cylinder group */
515325Smckusic 		struct dinode b_dinode[MAXINOPB]; /* inode block */
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 
846837Smckusick #define	MAXLNCNT	50	/* 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 */
925381Smckusic int	debug;			/* output debugging info */
934236Smckusick char	preen;			/* just fix normal inconsistencies */
944236Smckusick char	rplyflag;		/* any questions asked? */
954236Smckusick char	hotroot;		/* checking root device */
964236Smckusick char	fixcg;			/* corrupted free list bit maps */
974236Smckusick 
986314Smckusick char	*blockmap;		/* ptr to primary blk allocation map */
994236Smckusick char	*freemap;		/* ptr to secondary blk allocation map */
1004236Smckusick char	*statemap;		/* ptr to inode state table */
1014236Smckusick short	*lncntp;		/* ptr to link count table */
1024236Smckusick 
1034236Smckusick char	*pathp;			/* pointer to pathname position */
1044236Smckusick char	*thisname;		/* ptr to current pathname component */
1054236Smckusick char	*srchname;		/* name being searched for in dir */
1065877Smckusic char	pathname[BUFSIZ];
1074236Smckusick 
1084236Smckusick char	*lfname = "lost+found";
1094236Smckusick 
1104236Smckusick ino_t	inum;			/* inode we are currently working on */
1116634Smckusick ino_t	dnum;			/* directory inode currently being worked on */
1124236Smckusick ino_t	imax;			/* number of inodes */
1134236Smckusick ino_t	parentdir;		/* i number of parent directory */
1144236Smckusick ino_t	lastino;		/* hiwater mark of inodes */
1154236Smckusick ino_t	lfdir;			/* lost & found directory */
1164236Smckusick ino_t	orphan;			/* orphaned inode */
1174236Smckusick 
1184236Smckusick off_t	filsize;		/* num blks seen in file */
1194236Smckusick off_t	maxblk;			/* largest logical blk in file */
1206314Smckusick off_t	bmapsz;			/* num chars in blockmap */
1214236Smckusick 
1224236Smckusick daddr_t	n_ffree;		/* number of small free blocks */
1234236Smckusick daddr_t	n_bfree;		/* number of large free blocks */
1244236Smckusick daddr_t	n_blks;			/* number of blocks used */
1254236Smckusick daddr_t	n_files;		/* number of files seen */
1264236Smckusick daddr_t	n_index;
1274236Smckusick daddr_t	n_bad;
1284236Smckusick daddr_t	fmax;			/* number of blocks in the volume */
1294236Smckusick 
1304236Smckusick daddr_t	badblk;
1314236Smckusick daddr_t	dupblk;
1324236Smckusick 
1334236Smckusick int	inosumbad;
1344236Smckusick int	offsumbad;
1354465Smckusic int	frsumbad;
1366491Smckusick int	sbsumbad;
1374236Smckusick 
1384236Smckusick #define	zapino(x)	(*(x) = zino)
1394236Smckusick struct	dinode zino;
1404236Smckusick 
1416314Smckusick #define	setbmap(x)	setbit(blockmap, x)
1426314Smckusick #define	getbmap(x)	isset(blockmap, x)
1436314Smckusick #define	clrbmap(x)	clrbit(blockmap, x)
1444236Smckusick 
1454236Smckusick #define	setfmap(x)	setbit(freemap, x)
1464236Smckusick #define	getfmap(x)	isset(freemap, x)
1474236Smckusick #define	clrfmap(x)	clrbit(freemap, x)
1484236Smckusick 
1494236Smckusick #define	DATA	1
1504236Smckusick #define	ADDR	0
1514236Smckusick 
1524236Smckusick #define	ALTERD	010
1534236Smckusick #define	KEEPON	04
1544236Smckusick #define	SKIP	02
1554236Smckusick #define	STOP	01
1564236Smckusick 
1574236Smckusick int	(*signal())();
1584236Smckusick long	lseek();
1594236Smckusick time_t	time();
1604236Smckusick DINODE	*ginode();
1614236Smckusick BUFAREA	*getblk();
1624236Smckusick int	dirscan();
1634236Smckusick int	findino();
1644236Smckusick int	catch();
1654236Smckusick int	mkentry();
1664236Smckusick int	chgdd();
167*9255Smckusick int	pass1check(), pass1bcheck(), pass2check(), pass4check(), pass5check();
1684236Smckusick int	(*pfunc)();
1694236Smckusick char	*rawname(), *rindex(), *unrawname();
1704606Smckusic extern int inside[], around[];
1715325Smckusic extern unsigned char *fragtbl[];
1724236Smckusick 
1734236Smckusick char	*devname;
1744236Smckusick 
1754236Smckusick main(argc, argv)
1764715Smckusic 	int	argc;
1774715Smckusic 	char	*argv[];
1784236Smckusick {
1794236Smckusick 	struct fstab *fsp;
1804236Smckusick 	int pid, passno, anygtr, sumstatus;
1814236Smckusick 
1824236Smckusick 	sync();
1834236Smckusick 	while (--argc > 0 && **++argv == '-') {
1844236Smckusick 		switch (*++*argv) {
1854236Smckusick 
1864236Smckusick 		case 'p':
1874236Smckusick 			preen++;
1884236Smckusick 			break;
1894236Smckusick 
1904236Smckusick 		case 'b':
1914236Smckusick 			bflag = atoi(argv[0]+1);
1924236Smckusick 			printf("Alternate super block location: %d\n", bflag);
1934236Smckusick 			break;
1944236Smckusick 
1955381Smckusic 		case 'd':
1965381Smckusic 			debug++;
1975381Smckusic 			break;
1985381Smckusic 
1994236Smckusick 		case 'n':	/* default no answer flag */
2004236Smckusick 		case 'N':
2014236Smckusick 			nflag++;
2024236Smckusick 			yflag = 0;
2034236Smckusick 			break;
2044236Smckusick 
2054236Smckusick 		case 'y':	/* default yes answer flag */
2064236Smckusick 		case 'Y':
2074236Smckusick 			yflag++;
2084236Smckusick 			nflag = 0;
2094236Smckusick 			break;
2104236Smckusick 
2114236Smckusick 		default:
2124236Smckusick 			errexit("%c option?\n", **argv);
2134236Smckusick 		}
2144236Smckusick 	}
2154236Smckusick 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
2164236Smckusick 		signal(SIGINT, catch);
2174236Smckusick 	if (argc) {
2184236Smckusick 		while (argc-- > 0) {
2194236Smckusick 			hotroot = 0;
220*9255Smckusick 			checkfilesys(*argv++);
2214236Smckusick 		}
2224236Smckusick 		exit(0);
2234236Smckusick 	}
2244236Smckusick 	sumstatus = 0;
2254236Smckusick 	passno = 1;
2264236Smckusick 	do {
2274236Smckusick 		anygtr = 0;
2284236Smckusick 		if (setfsent() == 0)
2294236Smckusick 			errexit("Can't open checklist file: %s\n", FSTAB);
2304236Smckusick 		while ((fsp = getfsent()) != 0) {
2314236Smckusick 			if (strcmp(fsp->fs_type, FSTAB_RW) &&
2324236Smckusick 			    strcmp(fsp->fs_type, FSTAB_RO))
2334236Smckusick 				continue;
2344236Smckusick 			if (preen == 0 ||
2354236Smckusick 			    passno == 1 && fsp->fs_passno == passno) {
2364236Smckusick 				if (blockcheck(fsp->fs_spec) == 0 && preen)
2374236Smckusick 					exit(8);
2384236Smckusick 			} else if (fsp->fs_passno > passno)
2394236Smckusick 				anygtr = 1;
2404236Smckusick 			else if (fsp->fs_passno == passno) {
2414236Smckusick 				pid = fork();
2424236Smckusick 				if (pid < 0) {
2434236Smckusick 					perror("fork");
2444236Smckusick 					exit(8);
2454236Smckusick 				}
2464236Smckusick 				if (pid == 0)
2474236Smckusick 					if (blockcheck(fsp->fs_spec)==0)
2484236Smckusick 						exit(8);
2494236Smckusick 					else
2504236Smckusick 						exit(0);
2514236Smckusick 			}
2524236Smckusick 		}
2534236Smckusick 		if (preen) {
2544236Smckusick 			int status;
2554236Smckusick 			while (wait(&status) != -1)
2564236Smckusick 				sumstatus |= status;
2574236Smckusick 		}
2584236Smckusick 		passno++;
2594236Smckusick 	} while (anygtr);
2604236Smckusick 	if (sumstatus)
2614236Smckusick 		exit(8);
2624236Smckusick 	endfsent();
2634236Smckusick 	exit(0);
2644236Smckusick }
2654236Smckusick 
2664236Smckusick blockcheck(name)
2674236Smckusick 	char *name;
2684236Smckusick {
2696489Smckusick 	struct stat stslash, stblock, stchar;
2704236Smckusick 	char *raw;
2714236Smckusick 	int looped = 0;
2724236Smckusick 
2734236Smckusick 	hotroot = 0;
2744236Smckusick 	if (stat("/", &stslash) < 0){
2754236Smckusick 		error("Can't stat root\n");
2764236Smckusick 		return (0);
2774236Smckusick 	}
2784236Smckusick retry:
2794236Smckusick 	if (stat(name, &stblock) < 0){
2804236Smckusick 		error("Can't stat %s\n", name);
2814236Smckusick 		return (0);
2824236Smckusick 	}
2834236Smckusick 	if (stblock.st_mode & S_IFBLK) {
2844236Smckusick 		raw = rawname(name);
2854236Smckusick 		if (stat(raw, &stchar) < 0){
2864236Smckusick 			error("Can't stat %s\n", raw);
2874236Smckusick 			return (0);
2884236Smckusick 		}
2894236Smckusick 		if (stchar.st_mode & S_IFCHR) {
2904236Smckusick 			if (stslash.st_dev == stblock.st_rdev) {
2914236Smckusick 				hotroot++;
2924236Smckusick 				raw = unrawname(name);
2934236Smckusick 			}
294*9255Smckusick 			checkfilesys(raw);
2954236Smckusick 			return (1);
2964236Smckusick 		} else {
2974236Smckusick 			error("%s is not a character device\n", raw);
2984236Smckusick 			return (0);
2994236Smckusick 		}
3004236Smckusick 	} else if (stblock.st_mode & S_IFCHR) {
3014236Smckusick 		if (looped) {
3024236Smckusick 			error("Can't make sense out of name %s\n", name);
3034236Smckusick 			return (0);
3044236Smckusick 		}
3054236Smckusick 		name = unrawname(name);
3064236Smckusick 		looped++;
3074236Smckusick 		goto retry;
3084236Smckusick 	}
3094236Smckusick 	error("Can't make sense out of name %s\n", name);
3104236Smckusick 	return (0);
3114236Smckusick }
3124236Smckusick 
313*9255Smckusick checkfilesys(filesys)
314*9255Smckusick 	char *filesys;
3154236Smckusick {
3164236Smckusick 	register DINODE *dp;
3174236Smckusick 	register ino_t *blp;
3184236Smckusick 	register int i, n;
3194236Smckusick 	ino_t savino;
3207140Smckusick 	int b, c, j, partial, ndb;
3214236Smckusick 	daddr_t d, s;
3224236Smckusick 
323*9255Smckusick 	devname = filesys;
324*9255Smckusick 	if (setup(filesys) == 0) {
3254236Smckusick 		if (preen)
326*9255Smckusick 			pfatal("CAN'T CHECK FILE SYSTEM.");
3274236Smckusick 		return;
3284236Smckusick 	}
329*9255Smckusick /* 1: scan inodes tallying blocks used */
3306837Smckusick 	if (preen == 0) {
3316837Smckusick 		printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
3324236Smckusick 		if (hotroot)
3334236Smckusick 			printf("** Root file system\n");
3344236Smckusick 		printf("** Phase 1 - Check Blocks and Sizes\n");
3354236Smckusick 	}
336*9255Smckusick 	pass1();
337*9255Smckusick 
338*9255Smckusick /* 1b: locate first references to duplicates, if any */
339*9255Smckusick 	if (enddup != &duplist[0]) {
340*9255Smckusick 		if (preen)
341*9255Smckusick 			pfatal("INTERNAL ERROR: dups with -p");
342*9255Smckusick 		printf("** Phase 1b - Rescan For More DUPS\n");
343*9255Smckusick 		pass1b();
344*9255Smckusick 	}
345*9255Smckusick 
346*9255Smckusick /* 2: traverse directories to check reference counts */
347*9255Smckusick 	if (preen == 0)
348*9255Smckusick 		printf("** Phase 2 - Check Pathnames\n");
349*9255Smckusick 	pass2();
350*9255Smckusick 
351*9255Smckusick /* 3 */
352*9255Smckusick 	if (preen == 0)
353*9255Smckusick 		printf("** Phase 3 - Check Connectivity\n");
354*9255Smckusick 	pass3();
355*9255Smckusick 
356*9255Smckusick /* 4 */
357*9255Smckusick 	if (preen == 0)
358*9255Smckusick 		printf("** Phase 4 - Check Reference Counts\n");
359*9255Smckusick 	pass4();
360*9255Smckusick 
361*9255Smckusick /* 5 */
362*9255Smckusick 	if (preen == 0)
363*9255Smckusick 		printf("** Phase 5 - Check Cyl groups\n");
364*9255Smckusick 	pass5();
365*9255Smckusick 
366*9255Smckusick 	if (fixcg) {
367*9255Smckusick 		if (preen == 0)
368*9255Smckusick 			printf("** Phase 6 - Salvage Cylinder Groups\n");
369*9255Smckusick 		makecg();
370*9255Smckusick 		n_ffree = sblock.fs_cstotal.cs_nffree;
371*9255Smckusick 		n_bfree = sblock.fs_cstotal.cs_nbfree;
372*9255Smckusick 	}
373*9255Smckusick 
374*9255Smckusick 	pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n",
375*9255Smckusick 	    n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_fsize),
376*9255Smckusick 	    n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree);
377*9255Smckusick 	if (dfile.mod) {
378*9255Smckusick 		time(&sblock.fs_time);
379*9255Smckusick 		sbdirty();
380*9255Smckusick 	}
381*9255Smckusick 	ckfini();
382*9255Smckusick 	free(blockmap);
383*9255Smckusick 	free(freemap);
384*9255Smckusick 	free(statemap);
385*9255Smckusick 	free(lncntp);
386*9255Smckusick 	if (dfile.mod) {
387*9255Smckusick 		if (preen) {
388*9255Smckusick 			if (hotroot)
389*9255Smckusick 				exit(4);
390*9255Smckusick 		} else {
391*9255Smckusick 			printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
392*9255Smckusick 			if (hotroot) {
393*9255Smckusick 				printf("\n***** BOOT UNIX (NO SYNC!) *****\n");
394*9255Smckusick 				exit(4);
395*9255Smckusick 			}
396*9255Smckusick 		}
397*9255Smckusick 	}
398*9255Smckusick 	sync();			/* ??? */
399*9255Smckusick }
400*9255Smckusick 
401*9255Smckusick setup(dev)
402*9255Smckusick 	char *dev;
403*9255Smckusick {
404*9255Smckusick 	dev_t rootdev;
405*9255Smckusick 	struct stat statb;
406*9255Smckusick 	int super = bflag ? bflag : SBLOCK;
407*9255Smckusick 	int i, j, size;
408*9255Smckusick 	int c, d, cgd;
409*9255Smckusick 
410*9255Smckusick 	bflag = 0;
411*9255Smckusick 	if (stat("/", &statb) < 0)
412*9255Smckusick 		errexit("Can't stat root\n");
413*9255Smckusick 	rootdev = statb.st_dev;
414*9255Smckusick 	if (stat(dev, &statb) < 0) {
415*9255Smckusick 		error("Can't stat %s\n", dev);
416*9255Smckusick 		return (0);
417*9255Smckusick 	}
418*9255Smckusick 	rawflg = 0;
419*9255Smckusick 	if ((statb.st_mode & S_IFMT) == S_IFBLK)
420*9255Smckusick 		;
421*9255Smckusick 	else if ((statb.st_mode & S_IFMT) == S_IFCHR)
422*9255Smckusick 		rawflg++;
423*9255Smckusick 	else {
424*9255Smckusick 		if (reply("file is not a block or character device; OK") == 0)
425*9255Smckusick 			return (0);
426*9255Smckusick 	}
427*9255Smckusick 	if (rootdev == statb.st_rdev)
428*9255Smckusick 		hotroot++;
429*9255Smckusick 	if ((dfile.rfdes = open(dev, 0)) < 0) {
430*9255Smckusick 		error("Can't open %s\n", dev);
431*9255Smckusick 		return (0);
432*9255Smckusick 	}
433*9255Smckusick 	if (preen == 0)
434*9255Smckusick 		printf("** %s", dev);
435*9255Smckusick 	if (nflag || (dfile.wfdes = open(dev, 1)) < 0) {
436*9255Smckusick 		dfile.wfdes = -1;
437*9255Smckusick 		if (preen)
438*9255Smckusick 			pfatal("NO WRITE ACCESS");
439*9255Smckusick 		printf(" (NO WRITE)");
440*9255Smckusick 	}
441*9255Smckusick 	if (preen == 0)
442*9255Smckusick 		printf("\n");
443*9255Smckusick 	fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; sbsumbad = 0;
444*9255Smckusick 	dfile.mod = 0;
445*9255Smckusick 	n_files = n_blks = n_ffree = n_bfree = 0;
446*9255Smckusick 	muldup = enddup = &duplist[0];
447*9255Smckusick 	badlnp = &badlncnt[0];
448*9255Smckusick 	lfdir = 0;
449*9255Smckusick 	rplyflag = 0;
450*9255Smckusick 	initbarea(&sblk);
451*9255Smckusick 	initbarea(&fileblk);
452*9255Smckusick 	initbarea(&inoblk);
453*9255Smckusick 	initbarea(&cgblk);
454*9255Smckusick 	/*
455*9255Smckusick 	 * Read in the super block and its summary info.
456*9255Smckusick 	 */
457*9255Smckusick 	if (bread(&dfile, &sblock, super, SBSIZE) == 0)
458*9255Smckusick 		return (0);
459*9255Smckusick 	sblk.b_bno = super;
460*9255Smckusick 	sblk.b_size = SBSIZE;
461*9255Smckusick 	/*
462*9255Smckusick 	 * run a few consistency checks of the super block
463*9255Smckusick 	 */
464*9255Smckusick 	if (sblock.fs_magic != FS_MAGIC)
465*9255Smckusick 		{ badsb("MAGIC NUMBER WRONG"); return (0); }
466*9255Smckusick 	if (sblock.fs_ncg < 1)
467*9255Smckusick 		{ badsb("NCG OUT OF RANGE"); return (0); }
468*9255Smckusick 	if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
469*9255Smckusick 		{ badsb("CPG OUT OF RANGE"); return (0); }
470*9255Smckusick 	if (sblock.fs_nsect < 1)
471*9255Smckusick 		{ badsb("NSECT < 1"); return (0); }
472*9255Smckusick 	if (sblock.fs_ntrak < 1)
473*9255Smckusick 		{ badsb("NTRAK < 1"); return (0); }
474*9255Smckusick 	if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak)
475*9255Smckusick 		{ badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); }
476*9255Smckusick 	if (sblock.fs_ipg % INOPB(&sblock))
477*9255Smckusick 		{ badsb("INODES NOT MULTIPLE OF A BLOCK"); return (0); }
478*9255Smckusick 	if (cgdmin(&sblock, 0) >= sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
479*9255Smckusick 		{ badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); return (0); }
480*9255Smckusick 	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
481*9255Smckusick 	    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
482*9255Smckusick 		{ badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
483*9255Smckusick 	if (sblock.fs_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
484*9255Smckusick 		{ badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); }
485*9255Smckusick 	if (sblock.fs_size * NSPF(&sblock) <=
486*9255Smckusick 	    (sblock.fs_ncyl - 1) * sblock.fs_spc)
487*9255Smckusick 		{ badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); }
488*9255Smckusick 	if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc)
489*9255Smckusick 		{ badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
490*9255Smckusick 	/* rest we COULD repair... */
491*9255Smckusick 	if (sblock.fs_cgsize != fragroundup(&sblock,
492*9255Smckusick 	    sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY)))
493*9255Smckusick 		{ badsb("CGSIZE INCORRECT"); return (0); }
494*9255Smckusick 	if (sblock.fs_cssize !=
495*9255Smckusick 	    fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)))
496*9255Smckusick 		{ badsb("CSSIZE INCORRECT"); return (0); }
497*9255Smckusick 	fmax = sblock.fs_size;
498*9255Smckusick 	imax = sblock.fs_ncg * sblock.fs_ipg;
499*9255Smckusick 	n_bad = cgsblock(&sblock, 0); /* boot block plus dedicated sblock */
500*9255Smckusick 	/*
501*9255Smckusick 	 * read in the summary info.
502*9255Smckusick 	 */
503*9255Smckusick 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
504*9255Smckusick 		size = sblock.fs_cssize - i < sblock.fs_bsize ?
505*9255Smckusick 		    sblock.fs_cssize - i : sblock.fs_bsize;
506*9255Smckusick 		sblock.fs_csp[j] = (struct csum *)calloc(1, size);
507*9255Smckusick 		bread(&dfile, (char *)sblock.fs_csp[j],
508*9255Smckusick 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
509*9255Smckusick 		    size);
510*9255Smckusick 	}
511*9255Smckusick 	/*
512*9255Smckusick 	 * allocate and initialize the necessary maps
513*9255Smckusick 	 */
514*9255Smckusick 	bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
515*9255Smckusick 	blockmap = (char *)calloc(bmapsz, sizeof (char));
516*9255Smckusick 	if (blockmap == NULL) {
517*9255Smckusick 		printf("cannot alloc %d bytes for blockmap\n", bmapsz);
518*9255Smckusick 		exit(1);
519*9255Smckusick 	}
520*9255Smckusick 	freemap = (char *)calloc(bmapsz, sizeof (char));
521*9255Smckusick 	if (freemap == NULL) {
522*9255Smckusick 		printf("cannot alloc %d bytes for freemap\n", bmapsz);
523*9255Smckusick 		exit(1);
524*9255Smckusick 	}
525*9255Smckusick 	statemap = (char *)calloc(imax+1, sizeof(char));
526*9255Smckusick 	if (statemap == NULL) {
527*9255Smckusick 		printf("cannot alloc %d bytes for statemap\n", imax + 1);
528*9255Smckusick 		exit(1);
529*9255Smckusick 	}
530*9255Smckusick 	lncntp = (short *)calloc(imax+1, sizeof(short));
531*9255Smckusick 	if (lncntp == NULL) {
532*9255Smckusick 		printf("cannot alloc %d bytes for lncntp\n",
533*9255Smckusick 		    (imax + 1) * sizeof(short));
534*9255Smckusick 		exit(1);
535*9255Smckusick 	}
536*9255Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
537*9255Smckusick 		cgd = cgdmin(&sblock, c);
538*9255Smckusick 		if (c == 0) {
539*9255Smckusick 			d = cgbase(&sblock, c);
540*9255Smckusick 			cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
541*9255Smckusick 		} else
542*9255Smckusick 			d = cgsblock(&sblock, c);
543*9255Smckusick 		for (; d < cgd; d++)
544*9255Smckusick 			setbmap(d);
545*9255Smckusick 	}
546*9255Smckusick 
547*9255Smckusick 	startinum = imax + 1;
548*9255Smckusick 	return (1);
549*9255Smckusick 
550*9255Smckusick badsb:
551*9255Smckusick 	ckfini();
552*9255Smckusick 	return (0);
553*9255Smckusick }
554*9255Smckusick 
555*9255Smckusick pass1()
556*9255Smckusick {
557*9255Smckusick 	register int c, i, n, j;
558*9255Smckusick 	register DINODE *dp;
559*9255Smckusick 	int savino, ndb, partial;
560*9255Smckusick 
561*9255Smckusick 	pfunc = pass1check;
5624236Smckusick 	inum = 0;
5636533Smckusick 	n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
5644236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
5655381Smckusic 		if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
5664236Smckusick 			continue;
567*9255Smckusick 		if (cgrp.cg_magic != CG_MAGIC) {
568*9255Smckusick 			pfatal("cg %d: bad magic number\n", c);
569*9255Smckusick 			bzero((caddr_t)&cgrp, sblock.fs_cgsize);
570*9255Smckusick 		}
5714236Smckusick 		n = 0;
5724465Smckusic 		for (i = 0; i < sblock.fs_ipg; i++, inum++) {
5734465Smckusic 			dp = ginode();
5744465Smckusic 			if (dp == NULL)
5754465Smckusic 				continue;
5765944Smckusic 			n++;
5774236Smckusick 			if (ALLOC) {
5784236Smckusick 				if (!isset(cgrp.cg_iused, i)) {
5795381Smckusic 					if (debug)
5805381Smckusic 						printf("%d bad, not used\n",
5815381Smckusic 						    inum);
5824236Smckusick 					inosumbad++;
5834236Smckusick 				}
5845944Smckusic 				n--;
5854236Smckusick 				lastino = inum;
5867140Smckusick 				if (ftypeok(dp) == 0)
5877140Smckusick 					goto unknown;
5889235Smckusick 				if (dp->di_size < 0) {
5899235Smckusick 					if (debug)
5909235Smckusick 						printf("bad size %d:",
5919235Smckusick 							dp->di_size);
5927140Smckusick 					goto unknown;
5939235Smckusick 				}
5947140Smckusick 				ndb = howmany(dp->di_size, sblock.fs_bsize);
5957140Smckusick 				if (SPECIAL)
5967140Smckusick 					ndb++;
5977140Smckusick 				for (j = ndb; j < NDADDR; j++)
5989235Smckusick 					if (dp->di_db[j] != 0) {
5999235Smckusick 						if (debug)
6009235Smckusick 							printf("bad direct addr:");
6017140Smckusick 						goto unknown;
6029235Smckusick 					}
6037140Smckusick 				for (j = 0, ndb -= NDADDR; ndb > 0; j++)
6047140Smckusick 					ndb /= NINDIR(&sblock);
6057140Smckusick 				for (; j < NIADDR; j++)
6069235Smckusick 					if (dp->di_ib[j] != 0) {
6079235Smckusick 						if (debug)
6089235Smckusick 							printf("bad indirect addr:");
6097140Smckusick 						goto unknown;
6109235Smckusick 					}
6114236Smckusick 				n_files++;
612*9255Smckusick 				lncntp[inum] = dp->di_nlink;
613*9255Smckusick 				if (dp->di_nlink <= 0) {
6144236Smckusick 					if (badlnp < &badlncnt[MAXLNCNT])
6154236Smckusick 						*badlnp++ = inum;
6164236Smckusick 					else {
6174236Smckusick 						pfatal("LINK COUNT TABLE OVERFLOW");
6184236Smckusick 						if (reply("CONTINUE") == 0)
6194236Smckusick 							errexit("");
6204236Smckusick 					}
6214236Smckusick 				}
622*9255Smckusick 				statemap[inum] = DIRCT ? DSTATE : FSTATE;
6234236Smckusick 				badblk = dupblk = 0; filsize = 0; maxblk = 0;
6244236Smckusick 				ckinode(dp, ADDR);
6257140Smckusick 				continue;
6267140Smckusick 		unknown:
6277140Smckusick 				pfatal("UNKNOWN FILE TYPE I=%u", inum);
6287140Smckusick 				if (reply("CLEAR") == 1) {
6297140Smckusick 					zapino(dp);
6307140Smckusick 					inodirty();
6317140Smckusick 					inosumbad++;
6327140Smckusick 				}
6334236Smckusick 			} else {
6344236Smckusick 				if (isset(cgrp.cg_iused, i)) {
6355381Smckusic 					if (debug)
6365381Smckusic 						printf("%d bad, marked used\n",
6375381Smckusic 						    inum);
6384236Smckusick 					inosumbad++;
6394465Smckusic 					n--;
6404236Smckusick 				}
6417140Smckusick 				partial = 0;
6427140Smckusick 				for (j = 0; j < NDADDR; j++)
6437140Smckusick 					if (dp->di_db[j] != 0)
6447140Smckusick 						partial++;
6457140Smckusick 				for (j = 0; j < NIADDR; j++)
6467140Smckusick 					if (dp->di_ib[j] != 0)
6477140Smckusick 						partial++;
6487140Smckusick 				if (partial || dp->di_mode != 0 ||
6497140Smckusick 				    dp->di_size != 0) {
6504236Smckusick 					pfatal("PARTIALLY ALLOCATED INODE I=%u", inum);
6514236Smckusick 					if (reply("CLEAR") == 1) {
6524236Smckusick 						zapino(dp);
6534236Smckusick 						inodirty();
6544236Smckusick 						inosumbad++;
6554236Smckusick 					}
6564236Smckusick 				}
6574236Smckusick 			}
6584236Smckusick 		}
6594789Smckusic 		if (n != cgrp.cg_cs.cs_nifree) {
6605381Smckusic 			if (debug)
6615944Smckusic 				printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n",
6625381Smckusic 				    c, cgrp.cg_cs.cs_nifree, n);
6634236Smckusick 			inosumbad++;
6644236Smckusick 		}
6656491Smckusick 		if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree
6666491Smckusick 		  || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree
6676491Smckusick 		  || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree
6686491Smckusick 		  || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir)
6696491Smckusick 			sbsumbad++;
6704236Smckusick 	}
671*9255Smckusick }
672*9255Smckusick 
673*9255Smckusick pass1check(blk, size)
674*9255Smckusick 	daddr_t blk;
675*9255Smckusick 	int size;
676*9255Smckusick {
677*9255Smckusick 	register daddr_t *dlp;
678*9255Smckusick 	int res = KEEPON;
679*9255Smckusick 	int anyout;
680*9255Smckusick 
681*9255Smckusick 	anyout = outrange(blk, size);
682*9255Smckusick 	for (; size > 0; blk++, size--) {
683*9255Smckusick 		if (anyout && outrange(blk, 1)) {
684*9255Smckusick 			blkerr("BAD", blk);
685*9255Smckusick 			if (++badblk >= MAXBAD) {
686*9255Smckusick 				pwarn("EXCESSIVE BAD BLKS I=%u", inum);
687*9255Smckusick 				if (preen)
688*9255Smckusick 					printf(" (SKIPPING)\n");
689*9255Smckusick 				else if (reply("CONTINUE") == 0)
690*9255Smckusick 					errexit("");
691*9255Smckusick 				return (STOP);
6924465Smckusic 			}
693*9255Smckusick 			res = SKIP;
694*9255Smckusick 		} else if (getbmap(blk)) {
695*9255Smckusick 			blkerr("DUP", blk);
696*9255Smckusick 			if (++dupblk >= MAXDUP) {
697*9255Smckusick 				pwarn("EXCESSIVE DUP BLKS I=%u", inum);
698*9255Smckusick 				if (preen)
699*9255Smckusick 					printf(" (SKIPPING)\n");
700*9255Smckusick 				else if (reply("CONTINUE") == 0)
701*9255Smckusick 					errexit("");
702*9255Smckusick 				return (STOP);
703*9255Smckusick 			}
704*9255Smckusick 			if (enddup >= &duplist[DUPTBLSIZE]) {
705*9255Smckusick 				pfatal("DUP TABLE OVERFLOW.");
706*9255Smckusick 				if (reply("CONTINUE") == 0)
707*9255Smckusick 					errexit("");
708*9255Smckusick 				return (STOP);
709*9255Smckusick 			}
710*9255Smckusick 			for (dlp = duplist; dlp < muldup; dlp++)
711*9255Smckusick 				if (*dlp == blk) {
712*9255Smckusick 					*enddup++ = blk;
713*9255Smckusick 					break;
714*9255Smckusick 				}
715*9255Smckusick 			if (dlp >= muldup) {
716*9255Smckusick 				*enddup++ = *muldup;
717*9255Smckusick 				*muldup++ = blk;
718*9255Smckusick 			}
719*9255Smckusick 		} else {
720*9255Smckusick 			n_blks++;
721*9255Smckusick 			setbmap(blk);
7224236Smckusick 		}
723*9255Smckusick 		filsize++;
7244236Smckusick 	}
725*9255Smckusick 	return (res);
726*9255Smckusick }
727*9255Smckusick 
728*9255Smckusick pass1b()
729*9255Smckusick {
730*9255Smckusick 	register int c, i;
731*9255Smckusick 	register DINODE *dp;
732*9255Smckusick 
733*9255Smckusick 	pfunc = pass1bcheck;
734*9255Smckusick 	inum = 0;
735*9255Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
736*9255Smckusick 		for (i = 0; i < sblock.fs_ipg; i++, inum++) {
737*9255Smckusick 			dp = ginode();
738*9255Smckusick 			if (dp == NULL)
739*9255Smckusick 				continue;
740*9255Smckusick 			if (statemap[inum] != USTATE &&
741*9255Smckusick 			    (ckinode(dp, ADDR) & STOP))
742*9255Smckusick 				goto out1b;
743*9255Smckusick 		}
744*9255Smckusick 	}
7454236Smckusick out1b:
7464465Smckusic 	flush(&dfile, &inoblk);
747*9255Smckusick }
748*9255Smckusick 
749*9255Smckusick pass1bcheck(blk, size)
750*9255Smckusick 	daddr_t blk;
751*9255Smckusick 	int size;
752*9255Smckusick {
753*9255Smckusick 	register daddr_t *dlp;
754*9255Smckusick 	int res = KEEPON;
755*9255Smckusick 
756*9255Smckusick 	for (; size > 0; blk++, size--) {
757*9255Smckusick 		if (outrange(blk, 1))
758*9255Smckusick 			res = SKIP;
759*9255Smckusick 		for (dlp = duplist; dlp < muldup; dlp++)
760*9255Smckusick 			if (*dlp == blk) {
761*9255Smckusick 				blkerr("DUP", blk);
762*9255Smckusick 				*dlp = *--muldup;
763*9255Smckusick 				*muldup = blk;
764*9255Smckusick 				if (muldup == duplist)
765*9255Smckusick 					return (STOP);
766*9255Smckusick 			}
767*9255Smckusick 	}
768*9255Smckusick 	return (res);
769*9255Smckusick }
770*9255Smckusick 
771*9255Smckusick pass2()
772*9255Smckusick {
773*9255Smckusick 	register DINODE *dp;
774*9255Smckusick 
7754236Smckusick 	inum = ROOTINO;
7764236Smckusick 	thisname = pathp = pathname;
777*9255Smckusick 	pfunc = pass2check;
778*9255Smckusick 	switch (statemap[inum]) {
7794236Smckusick 
7804236Smckusick 	case USTATE:
7814236Smckusick 		errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
7824236Smckusick 
7834236Smckusick 	case FSTATE:
7844236Smckusick 		pfatal("ROOT INODE NOT DIRECTORY");
7854236Smckusick 		if (reply("FIX") == 0 || (dp = ginode()) == NULL)
7864236Smckusick 			errexit("");
7874236Smckusick 		dp->di_mode &= ~IFMT;
7884236Smckusick 		dp->di_mode |= IFDIR;
7894236Smckusick 		inodirty();
7904236Smckusick 		inosumbad++;
791*9255Smckusick 		statemap[inum] = DSTATE;
7924236Smckusick 		/* fall into ... */
7934236Smckusick 
7944236Smckusick 	case DSTATE:
7954236Smckusick 		descend();
7964236Smckusick 		break;
7974236Smckusick 
7984236Smckusick 	case CLEAR:
7994236Smckusick 		pfatal("DUPS/BAD IN ROOT INODE");
8004236Smckusick 		printf("\n");
8014236Smckusick 		if (reply("CONTINUE") == 0)
8024236Smckusick 			errexit("");
803*9255Smckusick 		statemap[inum] = DSTATE;
8044236Smckusick 		descend();
8054236Smckusick 	}
806*9255Smckusick }
807*9255Smckusick 
808*9255Smckusick pass2check(dirp)
809*9255Smckusick 	register DIRECT *dirp;
810*9255Smckusick {
811*9255Smckusick 	register char *p;
812*9255Smckusick 	register n;
813*9255Smckusick 	DINODE *dp;
814*9255Smckusick 
815*9255Smckusick 	if ((inum = dirp->d_ino) == 0)
816*9255Smckusick 		return (KEEPON);
817*9255Smckusick 	thisname = pathp;
818*9255Smckusick 	for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; )
819*9255Smckusick 		if ((*pathp++ = *p++) == 0) {
820*9255Smckusick 			--pathp;
821*9255Smckusick 			break;
822*9255Smckusick 		}
823*9255Smckusick 	*pathp = 0;
824*9255Smckusick 	n = 0;
825*9255Smckusick 	if (inum > imax || inum <= 0)
826*9255Smckusick 		n = direrr("I OUT OF RANGE");
827*9255Smckusick 	else {
828*9255Smckusick again:
829*9255Smckusick 		switch (statemap[inum]) {
830*9255Smckusick 		case USTATE:
831*9255Smckusick 			n = direrr("UNALLOCATED");
832*9255Smckusick 			break;
833*9255Smckusick 
834*9255Smckusick 		case CLEAR:
835*9255Smckusick 			if ((n = direrr("DUP/BAD")) == 1)
836*9255Smckusick 				break;
837*9255Smckusick 			if ((dp = ginode()) == NULL)
838*9255Smckusick 				break;
839*9255Smckusick 			statemap[inum] = DIRCT ? DSTATE : FSTATE;
840*9255Smckusick 			goto again;
841*9255Smckusick 
842*9255Smckusick 		case FSTATE:
843*9255Smckusick 			lncntp[inum]--;
844*9255Smckusick 			break;
845*9255Smckusick 
846*9255Smckusick 		case DSTATE:
847*9255Smckusick 			lncntp[inum]--;
848*9255Smckusick 			descend();
849*9255Smckusick 			break;
850*9255Smckusick 		}
851*9255Smckusick 	}
852*9255Smckusick 	pathp = thisname;
853*9255Smckusick 	if (n == 0)
854*9255Smckusick 		return (KEEPON);
855*9255Smckusick 	dirp->d_ino = 0;
856*9255Smckusick 	return (KEEPON|ALTERD);
857*9255Smckusick }
858*9255Smckusick 
859*9255Smckusick pass3()
860*9255Smckusick {
861*9255Smckusick 	ino_t savino;
862*9255Smckusick 	register DINODE *dp;
863*9255Smckusick 
8644236Smckusick 	for (inum = ROOTINO; inum <= lastino; inum++) {
865*9255Smckusick 		if (statemap[inum] == DSTATE) {
8664236Smckusick 			pfunc = findino;
8674236Smckusick 			srchname = "..";
8684236Smckusick 			savino = inum;
8694236Smckusick 			do {
8704236Smckusick 				orphan = inum;
8714236Smckusick 				if ((dp = ginode()) == NULL)
8724236Smckusick 					break;
8734236Smckusick 				filsize = dp->di_size;
8744236Smckusick 				parentdir = 0;
8754236Smckusick 				ckinode(dp, DATA);
8764236Smckusick 				if ((inum = parentdir) == 0)
8774236Smckusick 					break;
878*9255Smckusick 			} while (statemap[inum] == DSTATE);
8794236Smckusick 			inum = orphan;
8804236Smckusick 			if (linkup() == 1) {
8814236Smckusick 				thisname = pathp = pathname;
8824236Smckusick 				*pathp++ = '?';
883*9255Smckusick 				pfunc = pass2check;
8844236Smckusick 				descend();
8854236Smckusick 			}
8864236Smckusick 			inum = savino;
8874236Smckusick 		}
8884236Smckusick 	}
889*9255Smckusick }
890*9255Smckusick 
891*9255Smckusick pass4()
892*9255Smckusick {
893*9255Smckusick 	register int n;
894*9255Smckusick 	register ino_t *blp;
895*9255Smckusick 
896*9255Smckusick 	pfunc = pass4check;
8974236Smckusick 	for (inum = ROOTINO; inum <= lastino; inum++) {
898*9255Smckusick 		switch (statemap[inum]) {
8994236Smckusick 
9004236Smckusick 		case FSTATE:
901*9255Smckusick 			n = lncntp[inum];
902*9255Smckusick 			if (n)
9034236Smckusick 				adjust((short)n);
9044236Smckusick 			else {
9054236Smckusick 				for (blp = badlncnt;blp < badlnp; blp++)
9064236Smckusick 					if (*blp == inum) {
9074236Smckusick 						clri("UNREF", 1);
9084236Smckusick 						break;
9094236Smckusick 					}
9104236Smckusick 			}
9114236Smckusick 			break;
9124236Smckusick 
9134236Smckusick 		case DSTATE:
9144236Smckusick 			clri("UNREF", 1);
9154236Smckusick 			break;
9164236Smckusick 
9174236Smckusick 		case CLEAR:
9184236Smckusick 			clri("BAD/DUP", 1);
9194236Smckusick 			break;
9204236Smckusick 		}
9214236Smckusick 	}
9225337Smckusic 	if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) {
9234236Smckusick 		pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
9244236Smckusick 		if (preen)
9254236Smckusick 			printf(" (FIXED)\n");
9264236Smckusick 		if (preen || reply("FIX") == 1) {
9275944Smckusic 			sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files;
9284236Smckusick 			sbdirty();
9294236Smckusick 		}
9304236Smckusick 	}
9314236Smckusick 	flush(&dfile, &fileblk);
932*9255Smckusick }
9334236Smckusick 
934*9255Smckusick pass4check(blk, size)
935*9255Smckusick 	daddr_t blk;
936*9255Smckusick {
937*9255Smckusick 	register daddr_t *dlp;
938*9255Smckusick 	int res = KEEPON;
939*9255Smckusick 
940*9255Smckusick 	for (; size > 0; blk++, size--) {
941*9255Smckusick 		if (outrange(blk, 1))
942*9255Smckusick 			res = SKIP;
943*9255Smckusick 		else if (getbmap(blk)) {
944*9255Smckusick 			for (dlp = duplist; dlp < enddup; dlp++)
945*9255Smckusick 				if (*dlp == blk) {
946*9255Smckusick 					*dlp = *--enddup;
947*9255Smckusick 					return (KEEPON);
948*9255Smckusick 				}
949*9255Smckusick 			clrbmap(blk);
950*9255Smckusick 			n_blks--;
951*9255Smckusick 		}
952*9255Smckusick 	}
953*9255Smckusick 	return (res);
954*9255Smckusick }
955*9255Smckusick 
956*9255Smckusick pass5()
957*9255Smckusick {
958*9255Smckusick 	register int c, n, i, b, d;
959*9255Smckusick 	short bo[MAXCPG][NRPOS];
960*9255Smckusick 	long botot[MAXCPG];
961*9255Smckusick 	long frsum[MAXFRAG];
962*9255Smckusick 	int blk;
963*9255Smckusick 	daddr_t cbase;
964*9255Smckusick 	int blockbits = (1<<sblock.fs_frag)-1;
965*9255Smckusick 
966*9255Smckusick 	blkcpy((unsigned)bmapsz, blockmap, freemap);
9674236Smckusick 	dupblk = 0;
9685381Smckusic 	n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0));
9694236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
970*9255Smckusick 		cbase = cgbase(&sblock, c);
971*9255Smckusick 		bzero(botot, sizeof (botot));
972*9255Smckusick 		bzero(bo, sizeof (bo));
973*9255Smckusick 		bzero(frsum, sizeof (frsum));
9744465Smckusic 		/*
9756533Smckusick 		 * need to account for the super blocks
9764465Smckusic 		 * which appear (inaccurately) bad
9774465Smckusic 		 */
9786533Smckusick 		n_bad += cgtod(&sblock, c) - cgsblock(&sblock, c);
9795381Smckusic 		if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
9804236Smckusick 			continue;
981*9255Smckusick 		if (cgrp.cg_magic != CG_MAGIC) {
982*9255Smckusick 			pfatal("cg %d: bad magic number\n", c);
983*9255Smckusick 			bzero((caddr_t)&cgrp, sblock.fs_cgsize);
984*9255Smckusick 		}
9855325Smckusic 		for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
986*9255Smckusick 			blk = blkmap(&sblock, cgrp.cg_free, b);
987*9255Smckusick 			if (blk == 0)
988*9255Smckusick 				continue;
989*9255Smckusick 			if (blk == blockbits) {
990*9255Smckusick 				if (pass5check(cbase+b, sblock.fs_frag) == STOP)
9914236Smckusick 					goto out5;
9924236Smckusick 				/* this is clumsy ... */
9935325Smckusic 				n_ffree -= sblock.fs_frag;
9944236Smckusick 				n_bfree++;
9955371Smckusic 				botot[cbtocylno(&sblock, b)]++;
9965363Smckusic 				bo[cbtocylno(&sblock, b)]
9975363Smckusic 				    [cbtorpos(&sblock, b)]++;
998*9255Smckusick 				continue;
9994465Smckusic 			}
1000*9255Smckusick 			for (d = 0; d < sblock.fs_frag; d++)
1001*9255Smckusick 				if ((blk & (1<<d)) &&
1002*9255Smckusick 				    pass5check(cbase+b+d,1) == STOP)
1003*9255Smckusick 					goto out5;
1004*9255Smckusick 			fragacct(&sblock, blk, frsum, 1);
10054236Smckusick 		}
1006*9255Smckusick 		if (bcmp(cgrp.cg_frsum, frsum, sizeof (frsum))) {
1007*9255Smckusick 			if (debug)
1008*9255Smckusick 			for (i = 0; i < sblock.fs_frag; i++)
1009*9255Smckusick 				if (cgrp.cg_frsum[i] != frsum[i])
1010*9255Smckusick 				printf("cg[%d].cg_frsum[%d] have %d calc %d\n",
1011*9255Smckusick 				    c, i, cgrp.cg_frsum[i], frsum[i]);
1012*9255Smckusick 			frsumbad++;
10134465Smckusic 		}
1014*9255Smckusick 		if (bcmp(cgrp.cg_btot, botot, sizeof (botot))) {
1015*9255Smckusick 			if (debug)
1016*9255Smckusick 			for (n = 0; n < sblock.fs_cpg; n++)
1017*9255Smckusick 				if (botot[n] != cgrp.cg_btot[n])
1018*9255Smckusick 				printf("cg[%d].cg_btot[%d] have %d calc %d\n",
1019*9255Smckusick 				    c, n, cgrp.cg_btot[n], botot[n]);
1020*9255Smckusick 			offsumbad++;
1021*9255Smckusick 		}
1022*9255Smckusick 		if (bcmp(cgrp.cg_b, bo, sizeof (bo))) {
1023*9255Smckusick 			if (debug)
10244236Smckusick 			for (i = 0; i < NRPOS; i++)
1025*9255Smckusick 				if (bo[n][i] != cgrp.cg_b[n][i])
1026*9255Smckusick 				printf("cg[%d].cg_b[%d][%d] have %d calc %d\n",
1027*9255Smckusick 				    c, n, i, cgrp.cg_b[n][i], bo[n][i]);
1028*9255Smckusick 			offsumbad++;
10295371Smckusic 		}
10304236Smckusick 	}
10314236Smckusick out5:
10324236Smckusick 	if (dupblk)
10334236Smckusick 		pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk);
10344236Smckusick 	if (fixcg == 0) {
10355325Smckusic 		if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) {
10364236Smckusick 			pwarn("%ld BLK(S) MISSING\n", fmax - b);
10374236Smckusick 			fixcg = 1;
10386491Smckusick 		} else if (inosumbad + offsumbad + frsumbad + sbsumbad) {
10396491Smckusick 			pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n",
10404236Smckusick 			    inosumbad ? "(INODE FREE) " : "",
10414465Smckusic 			    offsumbad ? "(BLOCK OFFSETS) " : "",
10426491Smckusick 			    frsumbad ? "(FRAG SUMMARIES) " : "",
10436491Smckusick 			    sbsumbad ? "(SUPER BLOCK SUMMARIES) " : "");
10444236Smckusick 			fixcg = 1;
10454789Smckusic 		} else if (n_ffree != sblock.fs_cstotal.cs_nffree ||
10464789Smckusic 		    n_bfree != sblock.fs_cstotal.cs_nbfree) {
10474236Smckusick 			pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK");
10484236Smckusick 			if (preen)
10494236Smckusick 				printf(" (FIXED)\n");
10504236Smckusick 			if (preen || reply("FIX") == 1) {
10514789Smckusic 				sblock.fs_cstotal.cs_nffree = n_ffree;
10524789Smckusic 				sblock.fs_cstotal.cs_nbfree = n_bfree;
10534236Smckusick 				sbdirty();
10544236Smckusick 			}
10554236Smckusick 		}
10564236Smckusick 	}
10574236Smckusick 	if (fixcg) {
10584236Smckusick 		pwarn("BAD CYLINDER GROUPS");
10594236Smckusick 		if (preen)
10604236Smckusick 			printf(" (SALVAGED)\n");
10614236Smckusick 		else if (reply("SALVAGE") == 0)
10624236Smckusick 			fixcg = 0;
10634236Smckusick 	}
10647608Sroot }
10654236Smckusick 
1066*9255Smckusick pass5check(blk, size)
1067*9255Smckusick 	daddr_t blk;
1068*9255Smckusick 	int size;
10697608Sroot {
10704236Smckusick 
1071*9255Smckusick 	if (outrange(blk, size)) {
1072*9255Smckusick 		fixcg = 1;
1073*9255Smckusick 		if (preen)
1074*9255Smckusick 			pfatal("BAD BLOCKS IN BIT MAPS.");
1075*9255Smckusick 		if (++badblk >= MAXBAD) {
1076*9255Smckusick 			printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
1077*9255Smckusick 			if (reply("CONTINUE") == 0)
1078*9255Smckusick 				errexit("");
1079*9255Smckusick 			return (STOP);
1080*9255Smckusick 		}
10818534Sroot 	}
1082*9255Smckusick 	for (; size > 0; blk++, size--)
1083*9255Smckusick 		if (getfmap(blk)) {
1084*9255Smckusick 			fixcg = 1;
1085*9255Smckusick 			++dupblk;
1086*9255Smckusick 		} else {
1087*9255Smckusick 			n_ffree++;
1088*9255Smckusick 			setfmap(blk);
1089*9255Smckusick 		}
1090*9255Smckusick 	return (KEEPON);
10914236Smckusick }
10924236Smckusick 
10934236Smckusick ckinode(dp, flg)
10944236Smckusick 	DINODE *dp;
10954236Smckusick 	register flg;
10964236Smckusick {
10974236Smckusick 	register daddr_t *ap;
10984236Smckusick 	register ret;
10995956Smckusic 	int (*func)(), n, ndb, size, offset;
11006634Smckusick 	ino_t number = inum;
11016634Smckusick 	DINODE dino;
11024236Smckusick 
11034236Smckusick 	if (SPECIAL)
11044236Smckusick 		return (KEEPON);
11056634Smckusick 	dino = *dp;
11064236Smckusick 	func = (flg == ADDR) ? pfunc : dirscan;
11076634Smckusick 	ndb = howmany(dino.di_size, sblock.fs_bsize);
11086634Smckusick 	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
11096634Smckusick 		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
11105956Smckusic 			size = numfrags(&sblock, fragroundup(&sblock, offset));
11114236Smckusick 		else
11125325Smckusic 			size = sblock.fs_frag;
11136634Smckusick 		dnum = number;
11144236Smckusick 		if (*ap && (ret = (*func)(*ap, size)) & STOP)
11154236Smckusick 			return (ret);
11164236Smckusick 	}
11176634Smckusick 	for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) {
11186634Smckusick 		dnum = number;
1119*9255Smckusick 		if (*ap) {
1120*9255Smckusick 			ret = iblock(*ap, n, flg,
1121*9255Smckusick 			    dino.di_size - sblock.fs_bsize * NDADDR);
1122*9255Smckusick 			if (ret & STOP)
1123*9255Smckusick 				return (ret);
1124*9255Smckusick 		}
11254236Smckusick 	}
11264236Smckusick 	return (KEEPON);
11274236Smckusick }
11284236Smckusick 
11294236Smckusick iblock(blk, ilevel, flg, isize)
11304236Smckusick 	daddr_t blk;
11314236Smckusick 	register ilevel;
11324236Smckusick 	int isize;
11334236Smckusick {
11344236Smckusick 	register daddr_t *ap;
11354236Smckusick 	register daddr_t *aplim;
11364428Smckusic 	register int i, n;
11374236Smckusick 	int (*func)(), nif;
11384236Smckusick 	BUFAREA ib;
11394236Smckusick 
11404236Smckusick 	if (flg == ADDR) {
11414236Smckusick 		func = pfunc;
11425325Smckusic 		if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0)
11434236Smckusick 			return (n);
11444236Smckusick 	} else
11454236Smckusick 		func = dirscan;
1146*9255Smckusick 	if (outrange(blk, sblock.fs_frag))		/* protect thyself */
11474236Smckusick 		return (SKIP);
11484236Smckusick 	initbarea(&ib);
11495325Smckusic 	if (getblk(&ib, blk, sblock.fs_bsize) == NULL)
11504236Smckusick 		return (SKIP);
11514236Smckusick 	ilevel--;
11524428Smckusic 	if (ilevel == 0) {
11535956Smckusic 		nif = lblkno(&sblock, isize) + 1;
11544428Smckusic 	} else /* ilevel == 1 */ {
11555325Smckusic 		nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1;
11564428Smckusic 	}
11575325Smckusic 	if (nif > NINDIR(&sblock))
11585325Smckusic 		nif = NINDIR(&sblock);
1159*9255Smckusick 	aplim = &ib.b_un.b_indir[nif];
11604428Smckusic 	for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
11614236Smckusick 		if (*ap) {
11624236Smckusick 			if (ilevel > 0)
1163*9255Smckusick 				n = iblock(*ap, ilevel, flg,
1164*9255Smckusick 				    isize - i*NINDIR(&sblock)*sblock.fs_bsize);
11654236Smckusick 			else
11665325Smckusic 				n = (*func)(*ap, sblock.fs_frag);
11674236Smckusick 			if (n & STOP)
11684236Smckusick 				return (n);
11694236Smckusick 		}
11704236Smckusick 	return (KEEPON);
11714236Smckusick }
11724236Smckusick 
1173*9255Smckusick outrange(blk, cnt)
11744236Smckusick 	daddr_t blk;
1175*9255Smckusick 	int cnt;
11764236Smckusick {
1177*9255Smckusick 	register int c;
11784236Smckusick 
1179*9255Smckusick 	if ((unsigned)(blk+cnt) > fmax)
1180*9255Smckusick 		return (1);
1181*9255Smckusick 	c = dtog(&sblock, blk);
1182*9255Smckusick 	if (blk < cgdmin(&sblock, c)) {
1183*9255Smckusick 		if ((blk+cnt) > cgsblock(&sblock, c)) {
1184*9255Smckusick 			if (debug) {
1185*9255Smckusick 				printf("blk %d < cgdmin %d;",
1186*9255Smckusick 				    blk, cgdmin(&sblock, c));
1187*9255Smckusick 				printf(" blk+cnt %d > cgsbase %d\n",
1188*9255Smckusick 				    blk+cnt, cgsblock(&sblock, c));
11898534Sroot 			}
1190*9255Smckusick 			return (1);
11918534Sroot 		}
1192*9255Smckusick 	} else {
1193*9255Smckusick 		if ((blk+cnt) > cgbase(&sblock, c+1)) {
1194*9255Smckusick 			if (debug)  {
1195*9255Smckusick 				printf("blk %d >= cgdmin %d;",
1196*9255Smckusick 				    blk, cgdmin(&sblock, c));
1197*9255Smckusick 				printf(" blk+cnt %d > sblock.fs_fpg %d\n",
1198*9255Smckusick 				    blk+cnt, sblock.fs_fpg);
11998534Sroot 			}
1200*9255Smckusick 			return (1);
12018534Sroot 		}
12024428Smckusic 	}
12034236Smckusick 	return (0);
12044236Smckusick }
12054236Smckusick 
12064236Smckusick blkerr(s, blk)
12074236Smckusick 	daddr_t blk;
12084236Smckusick 	char *s;
12094236Smckusick {
1210*9255Smckusick 
12114236Smckusick 	pfatal("%ld %s I=%u", blk, s, inum);
12124236Smckusick 	printf("\n");
1213*9255Smckusick 	statemap[inum] = CLEAR;
12144236Smckusick }
12154236Smckusick 
12164236Smckusick descend()
12174236Smckusick {
12184236Smckusick 	register DINODE *dp;
12194236Smckusick 	register char *savname;
12204236Smckusick 	off_t savsize;
12214236Smckusick 
1222*9255Smckusick 	statemap[inum] = FSTATE;
12234236Smckusick 	if ((dp = ginode()) == NULL)
12244236Smckusick 		return;
12254236Smckusick 	savname = thisname;
12264236Smckusick 	*pathp++ = '/';
12274236Smckusick 	savsize = filsize;
12284236Smckusick 	filsize = dp->di_size;
12294236Smckusick 	ckinode(dp, DATA);
12304236Smckusick 	thisname = savname;
12314236Smckusick 	*--pathp = 0;
12324236Smckusick 	filsize = savsize;
12334236Smckusick }
12344236Smckusick 
12355877Smckusic struct dirstuff {
12365877Smckusic 	int loc;
12375877Smckusic 	int blkno;
12385877Smckusic 	int blksiz;
12396634Smckusick 	ino_t number;
12406838Smckusick 	enum {DONTKNOW, NOFIX, FIX} fix;
12415877Smckusic };
12425877Smckusic 
12434236Smckusick dirscan(blk, nf)
12444715Smckusic 	daddr_t blk;
12454715Smckusic 	int nf;
12464236Smckusick {
12475877Smckusic 	register DIRECT *dp;
12485877Smckusic 	struct dirstuff dirp;
12496251Smckusick 	int blksiz, dsize, n;
12506251Smckusick 	char dbuf[DIRBLKSIZ];
12514236Smckusick 
1252*9255Smckusick 	if (outrange(blk, 1)) {
12535325Smckusic 		filsize -= sblock.fs_bsize;
12544236Smckusick 		return (SKIP);
12554236Smckusick 	}
12565877Smckusic 	blksiz = nf * sblock.fs_fsize;
12575877Smckusic 	dirp.loc = 0;
12585877Smckusic 	dirp.blkno = blk;
12595877Smckusic 	dirp.blksiz = blksiz;
12606837Smckusick 	if (dirp.number != dnum) {
12616837Smckusick 		dirp.number = dnum;
12626838Smckusick 		dirp.fix = DONTKNOW;
12636837Smckusick 	}
12645877Smckusic 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
12656251Smckusick 		dsize = dp->d_reclen;
1266*9255Smckusick 		bcopy(dp, dbuf, dsize);
12676251Smckusick 		if ((n = (*pfunc)(dbuf)) & ALTERD) {
12685877Smckusic 			if (getblk(&fileblk, blk, blksiz) != NULL) {
1269*9255Smckusick 				bcopy(dbuf, dp, dsize);
12704715Smckusic 				dirty(&fileblk);
12714236Smckusick 				sbdirty();
12724236Smckusick 			} else
12734236Smckusick 				n &= ~ALTERD;
12744236Smckusick 		}
12755877Smckusic 		if (n & STOP)
12764236Smckusick 			return (n);
12774236Smckusick 	}
12784236Smckusick 	return (filsize > 0 ? KEEPON : STOP);
12794236Smckusick }
12804236Smckusick 
12815877Smckusic /*
12825877Smckusic  * get next entry in a directory.
12835877Smckusic  */
12845877Smckusic DIRECT *
12855877Smckusic readdir(dirp)
12865877Smckusic 	register struct dirstuff *dirp;
12875877Smckusic {
12886251Smckusick 	register DIRECT *dp, *ndp;
12896837Smckusick 	long size;
12905877Smckusic 
12915877Smckusic 	if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) {
12925877Smckusic 		filsize -= dirp->blksiz - dirp->loc;
12935877Smckusic 		return NULL;
12945877Smckusic 	}
12956837Smckusick 	while (dirp->loc % DIRBLKSIZ == 0 && filsize > 0 &&
12966837Smckusick 	    dirp->loc < dirp->blksiz) {
12975935Smckusic 		dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
12986837Smckusick 	   	if (dp->d_ino < imax &&
12996837Smckusick 		    dp->d_namlen <= MAXNAMLEN && dp->d_namlen >= 0 &&
13006837Smckusick 		    dp->d_reclen > 0 && dp->d_reclen <= DIRBLKSIZ)
13016837Smckusick 			break;
13026837Smckusick 		dirp->loc += DIRBLKSIZ;
13036837Smckusick 		filsize -= DIRBLKSIZ;
13046838Smckusick 		if (dirp->fix == DONTKNOW) {
13056634Smckusick 			pwarn("DIRECTORY %D CORRUPTED", dirp->number);
13066838Smckusick 			dirp->fix = NOFIX;
13076837Smckusick 			if (preen) {
13086251Smckusick 				printf(" (SALVAGED)\n");
13096838Smckusick 				dirp->fix = FIX;
13106837Smckusick 			} else if (reply("SALVAGE") != 0)
13116838Smckusick 				dirp->fix = FIX;
13126837Smckusick 		}
13136838Smckusick 		if (dirp->fix != FIX)
13145877Smckusic 			continue;
13156837Smckusick 		dp->d_reclen = DIRBLKSIZ;
13166837Smckusick 		dp->d_ino = 0;
13176837Smckusick 		dp->d_namlen = 0;
13186837Smckusick 		dirty(&fileblk);
13196837Smckusick 	}
13206837Smckusick 	if (filsize <= 0 || dirp->loc >= dirp->blksiz)
13216837Smckusick 		return NULL;
13226837Smckusick 	dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
13236837Smckusick 	dirp->loc += dp->d_reclen;
13246837Smckusick 	filsize -= dp->d_reclen;
13256837Smckusick 	ndp = (DIRECT *)(dirblk.b_buf + dirp->loc);
13267529Smckusick 	if ((filsize <= 0 && dirp->loc % DIRBLKSIZ != 0) ||
13277529Smckusick 	    (dirp->loc < dirp->blksiz && filsize > 0 &&
13286837Smckusick 	    (ndp->d_ino >= imax ||
13296837Smckusick 	    ndp->d_namlen > MAXNAMLEN || ndp->d_namlen < 0 ||
13306837Smckusick 	    ndp->d_reclen <= 0 ||
13317529Smckusick 	    ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ)))) {
13326837Smckusick 		size = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
13336837Smckusick 		dirp->loc += size;
13346837Smckusick 		filsize -= size;
13356838Smckusick 		if (dirp->fix == DONTKNOW) {
13366837Smckusick 			pwarn("DIRECTORY %D CORRUPTED", dirp->number);
13376838Smckusick 			dirp->fix = NOFIX;
13386837Smckusick 			if (preen) {
13396837Smckusick 				printf(" (SALVAGED)\n");
13406838Smckusick 				dirp->fix = FIX;
13416837Smckusick 			} else if (reply("SALVAGE") != 0)
13426838Smckusick 				dirp->fix = FIX;
13436251Smckusick 		}
13446838Smckusick 		if (dirp->fix == FIX) {
13456837Smckusick 			dp->d_reclen += size;
13466837Smckusick 			dirty(&fileblk);
13476837Smckusick 		}
13485877Smckusic 	}
13496837Smckusick 	return (dp);
13505877Smckusic }
13515877Smckusic 
13524236Smckusick direrr(s)
13534715Smckusic 	char *s;
13544236Smckusick {
13554236Smckusick 	register DINODE *dp;
13564236Smckusick 
13574236Smckusick 	pwarn("%s ", s);
13584236Smckusick 	pinode();
13594236Smckusick 	printf("\n");
13604236Smckusick 	if ((dp = ginode()) != NULL && ftypeok(dp))
13615877Smckusic 		pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname);
13624236Smckusick 	else
13634236Smckusick 		pfatal("NAME=%s", pathname);
13644236Smckusick 	return (reply("REMOVE"));
13654236Smckusick }
13664236Smckusick 
13674236Smckusick adjust(lcnt)
13684465Smckusic 	register short lcnt;
13694236Smckusick {
13704236Smckusick 	register DINODE *dp;
13714236Smckusick 
13724236Smckusick 	if ((dp = ginode()) == NULL)
13734236Smckusick 		return;
13744236Smckusick 	if (dp->di_nlink == lcnt) {
13754236Smckusick 		if (linkup() == 0)
13764236Smckusick 			clri("UNREF", 0);
13774236Smckusick 	}
13784236Smckusick 	else {
13794236Smckusick 		pwarn("LINK COUNT %s",
13805877Smckusic 			(lfdir==inum)?lfname:(DIRCT?"DIR":"FILE"));
13814236Smckusick 		pinode();
13824236Smckusick 		printf(" COUNT %d SHOULD BE %d",
13834236Smckusick 			dp->di_nlink, dp->di_nlink-lcnt);
13844236Smckusick 		if (preen) {
13854236Smckusick 			if (lcnt < 0) {
13864236Smckusick 				printf("\n");
13874236Smckusick 				preendie();
13884236Smckusick 			}
13894236Smckusick 			printf(" (ADJUSTED)\n");
13904236Smckusick 		}
13914236Smckusick 		if (preen || reply("ADJUST") == 1) {
13924236Smckusick 			dp->di_nlink -= lcnt;
13934236Smckusick 			inodirty();
13944236Smckusick 		}
13954236Smckusick 	}
13964236Smckusick }
13974236Smckusick 
13984236Smckusick clri(s, flg)
13994715Smckusic 	char *s;
14004236Smckusick {
14014236Smckusick 	register DINODE *dp;
14024236Smckusick 
14034236Smckusick 	if ((dp = ginode()) == NULL)
14044236Smckusick 		return;
14054236Smckusick 	if (flg == 1) {
14065877Smckusic 		pwarn("%s %s", s, DIRCT?"DIR":"FILE");
14074236Smckusick 		pinode();
14084236Smckusick 	}
14094236Smckusick 	if (preen || reply("CLEAR") == 1) {
14104236Smckusick 		if (preen)
14114236Smckusick 			printf(" (CLEARED)\n");
14124236Smckusick 		n_files--;
1413*9255Smckusick 		pfunc = pass4check;
14144236Smckusick 		ckinode(dp, ADDR);
14154236Smckusick 		zapino(dp);
1416*9255Smckusick 		statemap[inum] = USTATE;
14174236Smckusick 		inodirty();
14184236Smckusick 		inosumbad++;
14194236Smckusick 	}
14204236Smckusick }
14214236Smckusick 
14224236Smckusick badsb(s)
14234236Smckusick 	char *s;
14244236Smckusick {
14254236Smckusick 
14264236Smckusick 	if (preen)
14274236Smckusick 		printf("%s: ", devname);
14284236Smckusick 	printf("BAD SUPER BLOCK: %s\n", s);
14294236Smckusick 	pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
14304236Smckusick 	pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
14314236Smckusick }
14324236Smckusick 
14334236Smckusick DINODE *
14344236Smckusick ginode()
14354236Smckusick {
14364236Smckusick 	daddr_t iblk;
14374236Smckusick 
14386547Smckusick 	if (inum < ROOTINO || inum > imax) {
14396547Smckusick 		if (debug && (inum < 0 || inum > imax))
14406547Smckusick 			printf("inum out of range (%d)\n", inum);
14414236Smckusick 		return (NULL);
14426547Smckusick 	}
14435325Smckusic 	if (inum < startinum || inum >= startinum + INOPB(&sblock)) {
14445381Smckusic 		iblk = itod(&sblock, inum);
14455325Smckusic 		if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
14464236Smckusick 			return (NULL);
14474236Smckusick 		}
14485325Smckusic 		startinum = (inum / INOPB(&sblock)) * INOPB(&sblock);
14494236Smckusick 	}
14505325Smckusic 	return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]);
14514236Smckusick }
14524236Smckusick 
14534236Smckusick ftypeok(dp)
14544236Smckusick 	DINODE *dp;
14554236Smckusick {
14564236Smckusick 	switch (dp->di_mode & IFMT) {
14574236Smckusick 
14584236Smckusick 	case IFDIR:
14594236Smckusick 	case IFREG:
14604236Smckusick 	case IFBLK:
14614236Smckusick 	case IFCHR:
14626285Smckusick 	case IFLNK:
14634236Smckusick 		return (1);
14644236Smckusick 
14654236Smckusick 	default:
14669235Smckusick 		if (debug)
14679235Smckusick 			printf("bad file type 0%o\n", dp->di_mode);
14684236Smckusick 		return (0);
14694236Smckusick 	}
14704236Smckusick }
14714236Smckusick 
14724236Smckusick reply(s)
14734236Smckusick 	char *s;
14744236Smckusick {
14754236Smckusick 	char line[80];
14764236Smckusick 
14774236Smckusick 	if (preen)
14784236Smckusick 		pfatal("INTERNAL ERROR: GOT TO reply()");
14794236Smckusick 	rplyflag = 1;
14804236Smckusick 	printf("\n%s? ", s);
14814236Smckusick 	if (nflag || dfile.wfdes < 0) {
14824236Smckusick 		printf(" no\n\n");
14834236Smckusick 		return (0);
14844236Smckusick 	}
14854236Smckusick 	if (yflag) {
14864236Smckusick 		printf(" yes\n\n");
14874236Smckusick 		return (1);
14884236Smckusick 	}
14894236Smckusick 	if (getline(stdin, line, sizeof(line)) == EOF)
14904236Smckusick 		errexit("\n");
14914236Smckusick 	printf("\n");
14924236Smckusick 	if (line[0] == 'y' || line[0] == 'Y')
14934236Smckusick 		return (1);
14944236Smckusick 	else
14954236Smckusick 		return (0);
14964236Smckusick }
14974236Smckusick 
14984236Smckusick getline(fp, loc, maxlen)
14994236Smckusick 	FILE *fp;
15004236Smckusick 	char *loc;
15014236Smckusick {
15024236Smckusick 	register n;
15034236Smckusick 	register char *p, *lastloc;
15044236Smckusick 
15054236Smckusick 	p = loc;
15064236Smckusick 	lastloc = &p[maxlen-1];
15074236Smckusick 	while ((n = getc(fp)) != '\n') {
15084236Smckusick 		if (n == EOF)
15094236Smckusick 			return (EOF);
15104236Smckusick 		if (!isspace(n) && p < lastloc)
15114236Smckusick 			*p++ = n;
15124236Smckusick 	}
15134236Smckusick 	*p = 0;
15144236Smckusick 	return (p - loc);
15154236Smckusick }
15164236Smckusick 
15174236Smckusick BUFAREA *
15184236Smckusick getblk(bp, blk, size)
15194236Smckusick 	daddr_t blk;
15204236Smckusick 	register BUFAREA *bp;
15214236Smckusick 	int size;
15224236Smckusick {
15234236Smckusick 	register struct filecntl *fcp;
15245325Smckusic 	daddr_t dblk;
15254236Smckusick 
15264236Smckusick 	fcp = &dfile;
15275325Smckusic 	dblk = fsbtodb(&sblock, blk);
15285325Smckusic 	if (bp->b_bno == dblk)
15294236Smckusick 		return (bp);
15304236Smckusick 	flush(fcp, bp);
15315325Smckusic 	if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
15325325Smckusic 		bp->b_bno = dblk;
15334236Smckusick 		bp->b_size = size;
15344236Smckusick 		return (bp);
15354236Smckusick 	}
15364236Smckusick 	bp->b_bno = (daddr_t)-1;
15374236Smckusick 	return (NULL);
15384236Smckusick }
15394236Smckusick 
15404236Smckusick flush(fcp, bp)
15414236Smckusick 	struct filecntl *fcp;
15424236Smckusick 	register BUFAREA *bp;
15434236Smckusick {
15444236Smckusick 
15454236Smckusick 	if (bp->b_dirty)
15464236Smckusick 		bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size);
15474236Smckusick 	bp->b_dirty = 0;
15484236Smckusick }
15494236Smckusick 
15504236Smckusick rwerr(s, blk)
15514236Smckusick 	char *s;
15524236Smckusick 	daddr_t blk;
15534236Smckusick {
15544236Smckusick 
15554236Smckusick 	if (preen == 0)
15564236Smckusick 		printf("\n");
15574236Smckusick 	pfatal("CANNOT %s: BLK %ld", s, blk);
15584236Smckusick 	if (reply("CONTINUE") == 0)
15594236Smckusick 		errexit("Program terminated\n");
15604236Smckusick }
15614236Smckusick 
15624236Smckusick ckfini()
15634236Smckusick {
15644236Smckusick 
15654236Smckusick 	flush(&dfile, &fileblk);
15664236Smckusick 	flush(&dfile, &sblk);
15674465Smckusic 	if (sblk.b_bno != SBLOCK) {
15684465Smckusic 		sblk.b_bno = SBLOCK;
15694465Smckusic 		sbdirty();
15704465Smckusic 		flush(&dfile, &sblk);
15714465Smckusic 	}
15724236Smckusick 	flush(&dfile, &inoblk);
15734236Smckusick 	close(dfile.rfdes);
15744236Smckusick 	close(dfile.wfdes);
15754236Smckusick }
15764236Smckusick 
15774236Smckusick pinode()
15784236Smckusick {
15794236Smckusick 	register DINODE *dp;
15804236Smckusick 	register char *p;
15815877Smckusic 	char uidbuf[BUFSIZ];
15824236Smckusick 	char *ctime();
15834236Smckusick 
15844236Smckusick 	printf(" I=%u ", inum);
15854236Smckusick 	if ((dp = ginode()) == NULL)
15864236Smckusick 		return;
15874236Smckusick 	printf(" OWNER=");
15884236Smckusick 	if (getpw((int)dp->di_uid, uidbuf) == 0) {
15894236Smckusick 		for (p = uidbuf; *p != ':'; p++);
15904236Smckusick 		*p = 0;
15914236Smckusick 		printf("%s ", uidbuf);
15924236Smckusick 	}
15934236Smckusick 	else {
15944236Smckusick 		printf("%d ", dp->di_uid);
15954236Smckusick 	}
15964236Smckusick 	printf("MODE=%o\n", dp->di_mode);
15974236Smckusick 	if (preen)
15984236Smckusick 		printf("%s: ", devname);
15994236Smckusick 	printf("SIZE=%ld ", dp->di_size);
16004236Smckusick 	p = ctime(&dp->di_mtime);
16014236Smckusick 	printf("MTIME=%12.12s %4.4s ", p+4, p+20);
16024236Smckusick }
16034236Smckusick 
16044236Smckusick makecg()
16054236Smckusick {
16064465Smckusic 	int c, blk;
16076533Smckusick 	daddr_t dbase, d, dlower, dupper, dmax;
16084236Smckusick 	long i, j, s;
16094236Smckusick 	register struct csum *cs;
16104465Smckusic 	register DINODE *dp;
16114236Smckusick 
16124789Smckusic 	sblock.fs_cstotal.cs_nbfree = 0;
16134789Smckusic 	sblock.fs_cstotal.cs_nffree = 0;
16144789Smckusic 	sblock.fs_cstotal.cs_nifree = 0;
16154789Smckusic 	sblock.fs_cstotal.cs_ndir = 0;
16164236Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
16175381Smckusic 		dbase = cgbase(&sblock, c);
16184236Smckusick 		dmax = dbase + sblock.fs_fpg;
16195409Smckusic 		if (dmax > sblock.fs_size) {
16205944Smckusic 			for ( ; dmax >= sblock.fs_size; dmax--)
16215401Smckusic 				clrbit(cgrp.cg_free, dmax - dbase);
16225409Smckusic 			dmax++;
16235409Smckusic 		}
16246533Smckusick 		dlower = cgsblock(&sblock, c) - dbase;
16256533Smckusick 		dupper = cgdmin(&sblock, c) - dbase;
16265325Smckusic 		cs = &sblock.fs_cs(&sblock, c);
16274236Smckusick 		cgrp.cg_time = time(0);
16284236Smckusick 		cgrp.cg_magic = CG_MAGIC;
16294236Smckusick 		cgrp.cg_cgx = c;
16309235Smckusick 		if (c == sblock.fs_ncg - 1)
16319235Smckusick 			cgrp.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
16329235Smckusick 		else
16339235Smckusick 			cgrp.cg_ncyl = sblock.fs_cpg;
16344236Smckusick 		cgrp.cg_niblk = sblock.fs_ipg;
16354236Smckusick 		cgrp.cg_ndblk = dmax - dbase;
16364789Smckusic 		cgrp.cg_cs.cs_ndir = 0;
16374789Smckusic 		cgrp.cg_cs.cs_nffree = 0;
16384789Smckusic 		cgrp.cg_cs.cs_nbfree = 0;
16394789Smckusic 		cgrp.cg_cs.cs_nifree = 0;
16406533Smckusick 		cgrp.cg_rotor = 0;
16416533Smckusick 		cgrp.cg_frotor = 0;
16424258Smckusic 		cgrp.cg_irotor = 0;
16435325Smckusic 		for (i = 0; i < sblock.fs_frag; i++)
16444465Smckusic 			cgrp.cg_frsum[i] = 0;
16454236Smckusick 		inum = sblock.fs_ipg * c;
16464465Smckusic 		for (i = 0; i < sblock.fs_ipg; inum++, i++) {
16475944Smckusic 			cgrp.cg_cs.cs_nifree++;
16485944Smckusic 			clrbit(cgrp.cg_iused, i);
16494465Smckusic 			dp = ginode();
16504465Smckusic 			if (dp == NULL)
16514465Smckusic 				continue;
16524465Smckusic 			if (ALLOC) {
16535877Smckusic 				if (DIRCT)
16544789Smckusic 					cgrp.cg_cs.cs_ndir++;
16555944Smckusic 				cgrp.cg_cs.cs_nifree--;
16564465Smckusic 				setbit(cgrp.cg_iused, i);
16574465Smckusic 				continue;
16584465Smckusic 			}
16594236Smckusick 		}
16604236Smckusick 		while (i < MAXIPG) {
16614236Smckusick 			clrbit(cgrp.cg_iused, i);
16624236Smckusick 			i++;
16634236Smckusick 		}
16645944Smckusic 		if (c == 0)
16655944Smckusic 			for (i = 0; i < ROOTINO; i++) {
16665944Smckusic 				setbit(cgrp.cg_iused, i);
16675944Smckusic 				cgrp.cg_cs.cs_nifree--;
16685944Smckusic 			}
16695371Smckusic 		for (s = 0; s < MAXCPG; s++) {
16705371Smckusic 			cgrp.cg_btot[s] = 0;
16714236Smckusick 			for (i = 0; i < NRPOS; i++)
16724236Smckusick 				cgrp.cg_b[s][i] = 0;
16735371Smckusic 		}
16744236Smckusick 		if (c == 0) {
16756533Smckusick 			dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
16764236Smckusick 		}
16776533Smckusick 		for (d = dlower; d < dupper; d++)
16784236Smckusick 			clrbit(cgrp.cg_free, d);
16796533Smckusick 		for (d = 0; (d + sblock.fs_frag) <= dmax - dbase;
16806533Smckusick 		    d += sblock.fs_frag) {
16814236Smckusick 			j = 0;
16825325Smckusic 			for (i = 0; i < sblock.fs_frag; i++) {
16836533Smckusick 				if (!getbmap(dbase + d + i)) {
16846533Smckusick 					setbit(cgrp.cg_free, d + i);
16854236Smckusick 					j++;
16864236Smckusick 				} else
16874236Smckusick 					clrbit(cgrp.cg_free, d+i);
16884236Smckusick 			}
16895325Smckusic 			if (j == sblock.fs_frag) {
16904789Smckusic 				cgrp.cg_cs.cs_nbfree++;
16915371Smckusic 				cgrp.cg_btot[cbtocylno(&sblock, d)]++;
16925363Smckusic 				cgrp.cg_b[cbtocylno(&sblock, d)]
16935363Smckusic 				    [cbtorpos(&sblock, d)]++;
16944465Smckusic 			} else if (j > 0) {
16954789Smckusic 				cgrp.cg_cs.cs_nffree += j;
16966533Smckusick 				blk = blkmap(&sblock, cgrp.cg_free, d);
16975325Smckusic 				fragacct(&sblock, blk, cgrp.cg_frsum, 1);
16984465Smckusic 			}
16994236Smckusick 		}
17004465Smckusic 		for (j = d; d < dmax - dbase; d++) {
17016533Smckusick 			if (!getbmap(dbase + d)) {
17024236Smckusick 				setbit(cgrp.cg_free, d);
17034789Smckusic 				cgrp.cg_cs.cs_nffree++;
17044236Smckusick 			} else
17054236Smckusick 				clrbit(cgrp.cg_free, d);
17064236Smckusick 		}
17079235Smckusick 		for (; d % sblock.fs_frag != 0; d++)
17089235Smckusick 			clrbit(cgrp.cg_free, d);
17094465Smckusic 		if (j != d) {
17106533Smckusick 			blk = blkmap(&sblock, cgrp.cg_free, j);
17115325Smckusic 			fragacct(&sblock, blk, cgrp.cg_frsum, 1);
17124465Smckusic 		}
17139235Smckusick 		for (d /= sblock.fs_frag; d < MAXBPG(&sblock); d ++)
17149235Smckusick 			clrblock(&sblock, cgrp.cg_free, d);
17154789Smckusic 		sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree;
17164789Smckusic 		sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree;
17174789Smckusic 		sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
17184789Smckusic 		sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
17194789Smckusic 		*cs = cgrp.cg_cs;
17205381Smckusic 		bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)),
17215956Smckusic 		    sblock.fs_cgsize);
17224236Smckusick 	}
17236533Smckusick 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
17246533Smckusick 		bwrite(&dfile, (char *)sblock.fs_csp[j],
17256533Smckusick 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
17266533Smckusick 		    sblock.fs_cssize - i < sblock.fs_bsize ?
17276533Smckusick 		    sblock.fs_cssize - i : sblock.fs_bsize);
17285097Smckusic 	}
17294236Smckusick 	sblock.fs_ronly = 0;
17304236Smckusick 	sblock.fs_fmod = 0;
17314236Smckusick 	sbdirty();
17324236Smckusick }
17334236Smckusick 
17344236Smckusick findino(dirp)
17354236Smckusick 	register DIRECT *dirp;
17364236Smckusick {
17374236Smckusick 	if (dirp->d_ino == 0)
17384236Smckusick 		return (KEEPON);
17395877Smckusic 	if (!strcmp(dirp->d_name, srchname)) {
17405877Smckusic 		if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
17415877Smckusic 			parentdir = dirp->d_ino;
17425877Smckusic 		return (STOP);
17434236Smckusick 	}
17444236Smckusick 	return (KEEPON);
17454236Smckusick }
17464236Smckusick 
17474236Smckusick mkentry(dirp)
17484236Smckusick 	register DIRECT *dirp;
17494236Smckusick {
17504236Smckusick 	register ino_t in;
17514236Smckusick 	register char *p;
17526251Smckusick 	DIRECT newent;
17536251Smckusick 	int newlen, oldlen;
17544236Smckusick 
17556251Smckusick 	newent.d_namlen = 11;
17566251Smckusick 	newlen = DIRSIZ(&newent);
17576251Smckusick 	if (dirp->d_ino != 0)
17586251Smckusick 		oldlen = DIRSIZ(dirp);
17596251Smckusick 	else
17606251Smckusick 		oldlen = 0;
17616251Smckusick 	if (dirp->d_reclen - oldlen < newlen)
17624236Smckusick 		return (KEEPON);
17636251Smckusick 	newent.d_reclen = dirp->d_reclen - oldlen;
17646251Smckusick 	dirp->d_reclen = oldlen;
17656251Smckusick 	dirp = (struct direct *)(((char *)dirp) + oldlen);
17664236Smckusick 	dirp->d_ino = orphan;
17676251Smckusick 	dirp->d_reclen = newent.d_reclen;
17686251Smckusick 	p = &dirp->d_name[2];
17696251Smckusick 	for (in = imax; in > 0; in /= 10)
17706251Smckusick 		p++;
17716251Smckusick 	*--p = 0;
17726251Smckusick 	dirp->d_namlen = p - dirp->d_name;
17734236Smckusick 	in = orphan;
17744236Smckusick 	while (p > dirp->d_name) {
17754236Smckusick 		*--p = (in % 10) + '0';
17764236Smckusick 		in /= 10;
17774236Smckusick 	}
17784236Smckusick 	*p = '#';
17794236Smckusick 	return (ALTERD|STOP);
17804236Smckusick }
17814236Smckusick 
17824236Smckusick chgdd(dirp)
17834236Smckusick 	register DIRECT *dirp;
17844236Smckusick {
17854236Smckusick 	if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
17864236Smckusick 	dirp->d_name[2] == 0) {
17874236Smckusick 		dirp->d_ino = lfdir;
17884236Smckusick 		return (ALTERD|STOP);
17894236Smckusick 	}
17904236Smckusick 	return (KEEPON);
17914236Smckusick }
17924236Smckusick 
17934236Smckusick linkup()
17944236Smckusick {
17954236Smckusick 	register DINODE *dp;
17964236Smckusick 	register lostdir;
17974236Smckusick 	register ino_t pdir;
17984236Smckusick 
17994236Smckusick 	if ((dp = ginode()) == NULL)
18004236Smckusick 		return (0);
18015877Smckusic 	lostdir = DIRCT;
18024236Smckusick 	pdir = parentdir;
18034236Smckusick 	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
18044236Smckusick 	pinode();
18054236Smckusick 	if (preen && dp->di_size == 0)
18064236Smckusick 		return (0);
18074236Smckusick 	if (preen)
18084236Smckusick 		printf(" (RECONNECTED)\n");
18094236Smckusick 	else
18104236Smckusick 		if (reply("RECONNECT") == 0)
18114236Smckusick 			return (0);
18124236Smckusick 	orphan = inum;
18134236Smckusick 	if (lfdir == 0) {
18144236Smckusick 		inum = ROOTINO;
18154236Smckusick 		if ((dp = ginode()) == NULL) {
18164236Smckusick 			inum = orphan;
18174236Smckusick 			return (0);
18184236Smckusick 		}
18194236Smckusick 		pfunc = findino;
18204236Smckusick 		srchname = lfname;
18214236Smckusick 		filsize = dp->di_size;
18224236Smckusick 		parentdir = 0;
18234236Smckusick 		ckinode(dp, DATA);
18244236Smckusick 		inum = orphan;
18254236Smckusick 		if ((lfdir = parentdir) == 0) {
18264236Smckusick 			pfatal("SORRY. NO lost+found DIRECTORY");
18274236Smckusick 			printf("\n\n");
18284236Smckusick 			return (0);
18294236Smckusick 		}
18304236Smckusick 	}
18314236Smckusick 	inum = lfdir;
1832*9255Smckusick 	if ((dp = ginode()) == NULL || !DIRCT || statemap[inum] != FSTATE) {
18334236Smckusick 		inum = orphan;
18344236Smckusick 		pfatal("SORRY. NO lost+found DIRECTORY");
18354236Smckusick 		printf("\n\n");
18364236Smckusick 		return (0);
18374236Smckusick 	}
18385956Smckusic 	if (fragoff(&sblock, dp->di_size)) {
18395956Smckusic 		dp->di_size = fragroundup(&sblock, dp->di_size);
18404236Smckusick 		inodirty();
18414236Smckusick 	}
18424236Smckusick 	filsize = dp->di_size;
18434236Smckusick 	inum = orphan;
18444236Smckusick 	pfunc = mkentry;
18454236Smckusick 	if ((ckinode(dp, DATA) & ALTERD) == 0) {
18464236Smckusick 		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
18474236Smckusick 		printf("\n\n");
18484236Smckusick 		return (0);
18494236Smckusick 	}
1850*9255Smckusick 	lncntp[inum]--;
18514236Smckusick 	if (lostdir) {
18524236Smckusick 		pfunc = chgdd;
18534236Smckusick 		dp = ginode();
18544236Smckusick 		filsize = dp->di_size;
18554236Smckusick 		ckinode(dp, DATA);
18564236Smckusick 		inum = lfdir;
18574236Smckusick 		if ((dp = ginode()) != NULL) {
18584236Smckusick 			dp->di_nlink++;
18594236Smckusick 			inodirty();
1860*9255Smckusick 			lncntp[inum]++;
18614236Smckusick 		}
18624236Smckusick 		inum = orphan;
18634236Smckusick 		pwarn("DIR I=%u CONNECTED. ", orphan);
18644236Smckusick 		printf("PARENT WAS I=%u\n", pdir);
18654236Smckusick 		if (preen == 0)
18664236Smckusick 			printf("\n");
18674236Smckusick 	}
18684236Smckusick 	return (1);
18694236Smckusick }
18704236Smckusick 
18714236Smckusick bread(fcp, buf, blk, size)
18724236Smckusick 	daddr_t blk;
18734236Smckusick 	register struct filecntl *fcp;
18744236Smckusick 	register size;
18754236Smckusick 	char *buf;
18764236Smckusick {
18775325Smckusic 	if (lseek(fcp->rfdes, blk * DEV_BSIZE, 0) < 0)
18784236Smckusick 		rwerr("SEEK", blk);
18794236Smckusick 	else if (read(fcp->rfdes, buf, size) == size)
18804236Smckusick 		return (1);
18814236Smckusick 	rwerr("READ", blk);
18824236Smckusick 	return (0);
18834236Smckusick }
18844236Smckusick 
18854236Smckusick bwrite(fcp, buf, blk, size)
18864236Smckusick 	daddr_t blk;
18874236Smckusick 	register struct filecntl *fcp;
18884236Smckusick 	register size;
18894236Smckusick 	char *buf;
18904236Smckusick {
18914236Smckusick 
18924236Smckusick 	if (fcp->wfdes < 0)
18934236Smckusick 		return (0);
18945325Smckusic 	if (lseek(fcp->wfdes, blk * DEV_BSIZE, 0) < 0)
18954236Smckusick 		rwerr("SEEK", blk);
18964236Smckusick 	else if (write(fcp->wfdes, buf, size) == size) {
18974236Smckusick 		fcp->mod = 1;
18984236Smckusick 		return (1);
18994236Smckusick 	}
19004236Smckusick 	rwerr("WRITE", blk);
19014236Smckusick 	return (0);
19024236Smckusick }
19034236Smckusick 
19044236Smckusick catch()
19054236Smckusick {
19064236Smckusick 
19074236Smckusick 	ckfini();
19084236Smckusick 	exit(12);
19094236Smckusick }
19105325Smckusic 
1911*9255Smckusick char *
1912*9255Smckusick unrawname(cp)
1913*9255Smckusick 	char *cp;
1914*9255Smckusick {
1915*9255Smckusick 	char *dp = rindex(cp, '/');
1916*9255Smckusick 	struct stat stb;
19176489Smckusick 
1918*9255Smckusick 	if (dp == 0)
1919*9255Smckusick 		return (cp);
1920*9255Smckusick 	if (stat(cp, &stb) < 0)
1921*9255Smckusick 		return (cp);
1922*9255Smckusick 	if ((stb.st_mode&S_IFMT) != S_IFCHR)
1923*9255Smckusick 		return (cp);
1924*9255Smckusick 	if (*(dp+1) != 'r')
1925*9255Smckusick 		return (cp);
1926*9255Smckusick 	strcpy(dp+1, dp+2);
1927*9255Smckusick 	return (cp);
1928*9255Smckusick }
1929*9255Smckusick 
1930*9255Smckusick char *
1931*9255Smckusick rawname(cp)
1932*9255Smckusick 	char *cp;
19337608Sroot {
1934*9255Smckusick 	static char rawbuf[32];
1935*9255Smckusick 	char *dp = rindex(cp, '/');
19366489Smckusick 
1937*9255Smckusick 	if (dp == 0)
19387608Sroot 		return (0);
1939*9255Smckusick 	*dp = 0;
1940*9255Smckusick 	strcpy(rawbuf, cp);
1941*9255Smckusick 	*dp = '/';
1942*9255Smckusick 	strcat(rawbuf, "/r");
1943*9255Smckusick 	strcat(rawbuf, dp+1);
1944*9255Smckusick 	return (rawbuf);
19457608Sroot }
19466489Smckusick 
1947*9255Smckusick /* VARARGS1 */
1948*9255Smckusick error(s1, s2, s3, s4)
1949*9255Smckusick 	char *s1;
1950*9255Smckusick {
1951*9255Smckusick 
1952*9255Smckusick 	printf(s1, s2, s3, s4);
1953*9255Smckusick }
1954*9255Smckusick 
1955*9255Smckusick /* VARARGS1 */
1956*9255Smckusick errexit(s1, s2, s3, s4)
1957*9255Smckusick 	char *s1;
1958*9255Smckusick {
1959*9255Smckusick 	error(s1, s2, s3, s4);
1960*9255Smckusick 	exit(8);
1961*9255Smckusick }
1962*9255Smckusick 
19639235Smckusick /*
1964*9255Smckusick  * An inconsistency occured which shouldn't during normal operations.
1965*9255Smckusick  * Die if preening, otw just printf.
19669235Smckusick  */
1967*9255Smckusick /* VARARGS1 */
1968*9255Smckusick pfatal(s, a1, a2, a3)
1969*9255Smckusick 	char *s;
19709235Smckusick {
1971*9255Smckusick 
1972*9255Smckusick 	if (preen) {
1973*9255Smckusick 		printf("%s: ", devname);
1974*9255Smckusick 		printf(s, a1, a2, a3);
1975*9255Smckusick 		printf("\n");
1976*9255Smckusick 		preendie();
19779235Smckusick 	}
1978*9255Smckusick 	printf(s, a1, a2, a3);
19799235Smckusick }
19809235Smckusick 
1981*9255Smckusick preendie()
1982*9255Smckusick {
19837608Sroot 
1984*9255Smckusick 	printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
1985*9255Smckusick 	exit(8);
1986*9255Smckusick }
19877608Sroot 
19886489Smckusick /*
1989*9255Smckusick  * Pwarn is like printf when not preening,
1990*9255Smckusick  * or a warning (preceded by filename) when preening.
19916489Smckusick  */
1992*9255Smckusick /* VARARGS1 */
1993*9255Smckusick pwarn(s, a1, a2, a3, a4, a5, a6)
1994*9255Smckusick 	char *s;
1995*9255Smckusick {
19966489Smckusick 
1997*9255Smckusick 	if (preen)
1998*9255Smckusick 		printf("%s: ", devname);
1999*9255Smckusick 	printf(s, a1, a2, a3, a4, a5, a6);
2000*9255Smckusick }
20016489Smckusick 
2002*9255Smckusick panic(s)
2003*9255Smckusick 	char *s;
2004*9255Smckusick {
20056489Smckusick 
2006*9255Smckusick 	pfatal("internal inconsistency: %s\n");
2007*9255Smckusick 	exit(12);
2008*9255Smckusick }
2009