xref: /original-bsd/sbin/fsck/pass1.c (revision 2b8d0949)
16481228fSdist /*
2c8f1ef62Sbostic  * Copyright (c) 1980, 1986, 1993
3c8f1ef62Sbostic  *	The Regents of the University of California.  All rights reserved.
4d5bfdc7cSmckusick  *
536738bbfSbostic  * %sccs.include.redist.c%
66481228fSdist  */
76481228fSdist 
824c1d54aSmckusick #ifndef lint
9*2b8d0949Sbostic static char sccsid[] = "@(#)pass1.c	8.6 (Berkeley) 04/28/95";
10d5bfdc7cSmckusick #endif /* not lint */
1124c1d54aSmckusick 
1224c1d54aSmckusick #include <sys/param.h>
13619b789dSmckusick #include <sys/time.h>
1459985965Smckusick 
158cf2dc9aSbostic #include <ufs/ufs/dinode.h>
16f96ba6d8Smckusick #include <ufs/ufs/dir.h>
178cf2dc9aSbostic #include <ufs/ffs/fs.h>
1859985965Smckusick 
1959985965Smckusick #include <err.h>
20858e8542Smckusick #include <string.h>
2159985965Smckusick 
2224c1d54aSmckusick #include "fsck.h"
2324c1d54aSmckusick 
24e385a73bSmckusick static ufs_daddr_t badblk;
25e385a73bSmckusick static ufs_daddr_t dupblk;
2659985965Smckusick static void checkinode __P((ino_t inumber, struct inodesc *));
2724c1d54aSmckusick 
2859985965Smckusick void
pass1()2924c1d54aSmckusick pass1()
3024c1d54aSmckusick {
3124c1d54aSmckusick 	ino_t inumber;
32f96ba6d8Smckusick 	int c, i, cgd;
33f96ba6d8Smckusick 	struct inodesc idesc;
3424c1d54aSmckusick 
35423e4738Smckusick 	/*
36423e4738Smckusick 	 * Set file system reserved blocks in used block map.
37423e4738Smckusick 	 */
38423e4738Smckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
39423e4738Smckusick 		cgd = cgdmin(&sblock, c);
40423e4738Smckusick 		if (c == 0) {
41423e4738Smckusick 			i = cgbase(&sblock, c);
42423e4738Smckusick 			cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
43423e4738Smckusick 		} else
44423e4738Smckusick 			i = cgsblock(&sblock, c);
45423e4738Smckusick 		for (; i < cgd; i++)
46423e4738Smckusick 			setbmap(i);
47423e4738Smckusick 	}
48423e4738Smckusick 	/*
49423e4738Smckusick 	 * Find all allocated blocks.
50423e4738Smckusick 	 */
51*2b8d0949Sbostic 	memset(&idesc, 0, sizeof(struct inodesc));
5224c1d54aSmckusick 	idesc.id_type = ADDR;
5324c1d54aSmckusick 	idesc.id_func = pass1check;
5424c1d54aSmckusick 	inumber = 0;
55350ce55aSmckusick 	n_files = n_blks = 0;
5646dce619Smckusick 	resetinodebuf();
5724c1d54aSmckusick 	for (c = 0; c < sblock.fs_ncg; c++) {
5824c1d54aSmckusick 		for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
59350ce55aSmckusick 			if (inumber < ROOTINO)
6024c1d54aSmckusick 				continue;
61f96ba6d8Smckusick 			checkinode(inumber, &idesc);
62f96ba6d8Smckusick 		}
63f96ba6d8Smckusick 	}
64f96ba6d8Smckusick 	freeinodebuf();
65f96ba6d8Smckusick }
66f96ba6d8Smckusick 
6759985965Smckusick static void
checkinode(inumber,idesc)68f96ba6d8Smckusick checkinode(inumber, idesc)
69f96ba6d8Smckusick 	ino_t inumber;
70f96ba6d8Smckusick 	register struct inodesc *idesc;
71f96ba6d8Smckusick {
72f96ba6d8Smckusick 	register struct dinode *dp;
73f96ba6d8Smckusick 	struct zlncnt *zlnp;
74f96ba6d8Smckusick 	int ndb, j;
75f96ba6d8Smckusick 	mode_t mode;
766f8e7f13Smckusick 	char *symbuf;
77f96ba6d8Smckusick 
7846dce619Smckusick 	dp = getnextinode(inumber);
79f96ba6d8Smckusick 	mode = dp->di_mode & IFMT;
80f96ba6d8Smckusick 	if (mode == 0) {
81*2b8d0949Sbostic 		if (memcmp(dp->di_db, zino.di_db,
82e385a73bSmckusick 			NDADDR * sizeof(ufs_daddr_t)) ||
83*2b8d0949Sbostic 		    memcmp(dp->di_ib, zino.di_ib,
84e385a73bSmckusick 			NIADDR * sizeof(ufs_daddr_t)) ||
85350ce55aSmckusick 		    dp->di_mode || dp->di_size) {
86f96ba6d8Smckusick 			pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber);
87350ce55aSmckusick 			if (reply("CLEAR") == 1) {
88a6fb7d28Smckusick 				dp = ginode(inumber);
89408f77abSmckusick 				clearinode(dp);
9024c1d54aSmckusick 				inodirty();
91350ce55aSmckusick 			}
92350ce55aSmckusick 		}
93350ce55aSmckusick 		statemap[inumber] = USTATE;
94f96ba6d8Smckusick 		return;
95350ce55aSmckusick 	}
96350ce55aSmckusick 	lastino = inumber;
97858e8542Smckusick 	if (/* dp->di_size < 0 || */
98f2132766Smckusick 	    dp->di_size + sblock.fs_bsize - 1 < dp->di_size ||
99f2132766Smckusick 	    (mode == IFDIR && dp->di_size > MAXDIRSIZE)) {
10024c1d54aSmckusick 		if (debug)
101619b789dSmckusick 			printf("bad size %qu:", dp->di_size);
10224c1d54aSmckusick 		goto unknown;
10324c1d54aSmckusick 	}
104f96ba6d8Smckusick 	if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
105a6fb7d28Smckusick 		dp = ginode(inumber);
106ae1e4454Smckusick 		dp->di_size = sblock.fs_fsize;
107ae1e4454Smckusick 		dp->di_mode = IFREG|0600;
108ae1e4454Smckusick 		inodirty();
109ae1e4454Smckusick 	}
11024c1d54aSmckusick 	ndb = howmany(dp->di_size, sblock.fs_bsize);
111f617e948Smckusick 	if (ndb < 0) {
112f617e948Smckusick 		if (debug)
113619b789dSmckusick 			printf("bad size %qu ndb %d:",
114f617e948Smckusick 				dp->di_size, ndb);
115f617e948Smckusick 		goto unknown;
116f617e948Smckusick 	}
117f96ba6d8Smckusick 	if (mode == IFBLK || mode == IFCHR)
11824c1d54aSmckusick 		ndb++;
119f96ba6d8Smckusick 	if (mode == IFLNK) {
1205718e162Smckusick 		if (doinglevel2 &&
1215718e162Smckusick 		    dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN &&
1225718e162Smckusick 		    dp->di_blocks != 0) {
1236f8e7f13Smckusick 			symbuf = alloca(secsize);
124f96ba6d8Smckusick 			if (bread(fsreadfd, symbuf,
125f96ba6d8Smckusick 			    fsbtodb(&sblock, dp->di_db[0]),
1266f8e7f13Smckusick 			    (long)secsize) != 0)
12759985965Smckusick 				errx(EEXIT, "cannot read symlink");
1285718e162Smckusick 			if (debug) {
1295718e162Smckusick 				symbuf[dp->di_size] = 0;
1305718e162Smckusick 				printf("convert symlink %d(%s) of size %d\n",
1315718e162Smckusick 					inumber, symbuf, (long)dp->di_size);
1325718e162Smckusick 			}
133f96ba6d8Smckusick 			dp = ginode(inumber);
134*2b8d0949Sbostic 			memmove(dp->di_shortlink, symbuf, (long)dp->di_size);
135f96ba6d8Smckusick 			dp->di_blocks = 0;
136f96ba6d8Smckusick 			inodirty();
137f96ba6d8Smckusick 		}
1385718e162Smckusick 		/*
1395718e162Smckusick 		 * Fake ndb value so direct/indirect block checks below
1405718e162Smckusick 		 * will detect any garbage after symlink string.
1415718e162Smckusick 		 */
1425718e162Smckusick 		if (dp->di_size < sblock.fs_maxsymlinklen) {
143e385a73bSmckusick 			ndb = howmany(dp->di_size, sizeof(ufs_daddr_t));
1445718e162Smckusick 			if (ndb > NDADDR) {
1455718e162Smckusick 				j = ndb - NDADDR;
1465718e162Smckusick 				for (ndb = 1; j > 1; j--)
1475718e162Smckusick 					ndb *= NINDIR(&sblock);
1485718e162Smckusick 				ndb += NDADDR;
1495718e162Smckusick 			}
1505718e162Smckusick 		}
151f96ba6d8Smckusick 	}
15224c1d54aSmckusick 	for (j = ndb; j < NDADDR; j++)
15324c1d54aSmckusick 		if (dp->di_db[j] != 0) {
15424c1d54aSmckusick 			if (debug)
155f96ba6d8Smckusick 				printf("bad direct addr: %ld\n", dp->di_db[j]);
15624c1d54aSmckusick 			goto unknown;
15724c1d54aSmckusick 		}
15824c1d54aSmckusick 	for (j = 0, ndb -= NDADDR; ndb > 0; j++)
15924c1d54aSmckusick 		ndb /= NINDIR(&sblock);
16024c1d54aSmckusick 	for (; j < NIADDR; j++)
16124c1d54aSmckusick 		if (dp->di_ib[j] != 0) {
1626f8e7f13Smckusick 			if (debug)
1636f8e7f13Smckusick 				printf("bad indirect addr: %ld\n",
1646f8e7f13Smckusick 					dp->di_ib[j]);
16524c1d54aSmckusick 			goto unknown;
16624c1d54aSmckusick 		}
167ae1e4454Smckusick 	if (ftypeok(dp) == 0)
168350ce55aSmckusick 		goto unknown;
16924c1d54aSmckusick 	n_files++;
17024c1d54aSmckusick 	lncntp[inumber] = dp->di_nlink;
17124c1d54aSmckusick 	if (dp->di_nlink <= 0) {
172670f2583Smckusick 		zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
173670f2583Smckusick 		if (zlnp == NULL) {
17424c1d54aSmckusick 			pfatal("LINK COUNT TABLE OVERFLOW");
17524c1d54aSmckusick 			if (reply("CONTINUE") == 0)
17659985965Smckusick 				exit(EEXIT);
177670f2583Smckusick 		} else {
178670f2583Smckusick 			zlnp->zlncnt = inumber;
179670f2583Smckusick 			zlnp->next = zlnhead;
180670f2583Smckusick 			zlnhead = zlnp;
18124c1d54aSmckusick 		}
18224c1d54aSmckusick 	}
183f96ba6d8Smckusick 	if (mode == IFDIR) {
1840a5af6e6Smckusick 		if (dp->di_size == 0)
1850a5af6e6Smckusick 			statemap[inumber] = DCLEAR;
1860a5af6e6Smckusick 		else
187d3133ef2Smckusick 			statemap[inumber] = DSTATE;
188d3133ef2Smckusick 		cacheino(dp, inumber);
189d3133ef2Smckusick 	} else
190d3133ef2Smckusick 		statemap[inumber] = FSTATE;
191f96ba6d8Smckusick 	typemap[inumber] = IFTODT(mode);
192c43fce93Smckusick 	if (doinglevel2 &&
193c43fce93Smckusick 	    (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) {
194f96ba6d8Smckusick 		dp = ginode(inumber);
195f96ba6d8Smckusick 		dp->di_uid = dp->di_ouid;
196f96ba6d8Smckusick 		dp->di_ouid = -1;
197f96ba6d8Smckusick 		dp->di_gid = dp->di_ogid;
198f96ba6d8Smckusick 		dp->di_ogid = -1;
199f96ba6d8Smckusick 		inodirty();
200f96ba6d8Smckusick 	}
201408f77abSmckusick 	badblk = dupblk = 0;
202f96ba6d8Smckusick 	idesc->id_number = inumber;
203f96ba6d8Smckusick 	(void)ckinode(dp, idesc);
204f96ba6d8Smckusick 	idesc->id_entryno *= btodb(sblock.fs_fsize);
205f96ba6d8Smckusick 	if (dp->di_blocks != idesc->id_entryno) {
206858e8542Smckusick 		pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)",
207f96ba6d8Smckusick 		    inumber, dp->di_blocks, idesc->id_entryno);
20824c1d54aSmckusick 		if (preen)
20924c1d54aSmckusick 			printf(" (CORRECTED)\n");
21024c1d54aSmckusick 		else if (reply("CORRECT") == 0)
211f96ba6d8Smckusick 			return;
212a6fb7d28Smckusick 		dp = ginode(inumber);
213f96ba6d8Smckusick 		dp->di_blocks = idesc->id_entryno;
21424c1d54aSmckusick 		inodirty();
21524c1d54aSmckusick 	}
216f96ba6d8Smckusick 	return;
21724c1d54aSmckusick unknown:
218858e8542Smckusick 	pfatal("UNKNOWN FILE TYPE I=%lu", inumber);
2194b27154cSmckusick 	statemap[inumber] = FCLEAR;
22024c1d54aSmckusick 	if (reply("CLEAR") == 1) {
2214b27154cSmckusick 		statemap[inumber] = USTATE;
222a6fb7d28Smckusick 		dp = ginode(inumber);
223408f77abSmckusick 		clearinode(dp);
22424c1d54aSmckusick 		inodirty();
22524c1d54aSmckusick 	}
22624c1d54aSmckusick }
22724c1d54aSmckusick 
22859985965Smckusick int
pass1check(idesc)22924c1d54aSmckusick pass1check(idesc)
23024c1d54aSmckusick 	register struct inodesc *idesc;
23124c1d54aSmckusick {
23224c1d54aSmckusick 	int res = KEEPON;
23324c1d54aSmckusick 	int anyout, nfrags;
234e385a73bSmckusick 	ufs_daddr_t blkno = idesc->id_blkno;
2359bf626e7Smckusick 	register struct dups *dlp;
2369bf626e7Smckusick 	struct dups *new;
23724c1d54aSmckusick 
238408f77abSmckusick 	if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
239408f77abSmckusick 		blkerror(idesc->id_number, "BAD", blkno);
240ab0e4bf5Smckusick 		if (badblk++ >= MAXBAD) {
241858e8542Smckusick 			pwarn("EXCESSIVE BAD BLKS I=%lu",
24224c1d54aSmckusick 				idesc->id_number);
24324c1d54aSmckusick 			if (preen)
24424c1d54aSmckusick 				printf(" (SKIPPING)\n");
24524c1d54aSmckusick 			else if (reply("CONTINUE") == 0)
24659985965Smckusick 				exit(EEXIT);
24724c1d54aSmckusick 			return (STOP);
24824c1d54aSmckusick 		}
249423e4738Smckusick 	}
250423e4738Smckusick 	for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
251408f77abSmckusick 		if (anyout && chkrange(blkno, 1)) {
25224c1d54aSmckusick 			res = SKIP;
253408f77abSmckusick 		} else if (!testbmap(blkno)) {
254423e4738Smckusick 			n_blks++;
255423e4738Smckusick 			setbmap(blkno);
256423e4738Smckusick 		} else {
257408f77abSmckusick 			blkerror(idesc->id_number, "DUP", blkno);
258ab0e4bf5Smckusick 			if (dupblk++ >= MAXDUP) {
259858e8542Smckusick 				pwarn("EXCESSIVE DUP BLKS I=%lu",
26024c1d54aSmckusick 					idesc->id_number);
26124c1d54aSmckusick 				if (preen)
26224c1d54aSmckusick 					printf(" (SKIPPING)\n");
26324c1d54aSmckusick 				else if (reply("CONTINUE") == 0)
26459985965Smckusick 					exit(EEXIT);
26524c1d54aSmckusick 				return (STOP);
26624c1d54aSmckusick 			}
2679bf626e7Smckusick 			new = (struct dups *)malloc(sizeof(struct dups));
2689bf626e7Smckusick 			if (new == NULL) {
26924c1d54aSmckusick 				pfatal("DUP TABLE OVERFLOW.");
27024c1d54aSmckusick 				if (reply("CONTINUE") == 0)
27159985965Smckusick 					exit(EEXIT);
27224c1d54aSmckusick 				return (STOP);
27324c1d54aSmckusick 			}
2749bf626e7Smckusick 			new->dup = blkno;
2759bf626e7Smckusick 			if (muldup == 0) {
2769bf626e7Smckusick 				duplist = muldup = new;
2779bf626e7Smckusick 				new->next = 0;
2789bf626e7Smckusick 			} else {
2799bf626e7Smckusick 				new->next = muldup->next;
2809bf626e7Smckusick 				muldup->next = new;
2819bf626e7Smckusick 			}
2829bf626e7Smckusick 			for (dlp = duplist; dlp != muldup; dlp = dlp->next)
2839bf626e7Smckusick 				if (dlp->dup == blkno)
28424c1d54aSmckusick 					break;
2859bf626e7Smckusick 			if (dlp == muldup && dlp->dup != blkno)
2869bf626e7Smckusick 				muldup = new;
28724c1d54aSmckusick 		}
28836adc084Smckusick 		/*
28936adc084Smckusick 		 * count the number of blocks found in id_entryno
29036adc084Smckusick 		 */
29136adc084Smckusick 		idesc->id_entryno++;
29224c1d54aSmckusick 	}
29324c1d54aSmckusick 	return (res);
29424c1d54aSmckusick }
295