xref: /csrg-svn/sbin/fsck/pass1.c (revision 30868)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)pass1.c	5.4 (Berkeley) 04/09/87";
9 #endif not lint
10 
11 #include <sys/param.h>
12 #include <sys/inode.h>
13 #include <sys/fs.h>
14 #include "fsck.h"
15 
16 static daddr_t badblk;
17 static daddr_t dupblk;
18 int pass1check();
19 
20 pass1()
21 {
22 	register int c, i, j;
23 	register DINODE *dp;
24 	struct zlncnt *zlnp;
25 	int ndb, partial, cgd;
26 	struct inodesc idesc;
27 	ino_t inumber;
28 
29 	/*
30 	 * Set file system reserved blocks in used block map.
31 	 */
32 	for (c = 0; c < sblock.fs_ncg; c++) {
33 		cgd = cgdmin(&sblock, c);
34 		if (c == 0) {
35 			i = cgbase(&sblock, c);
36 			cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
37 		} else
38 			i = cgsblock(&sblock, c);
39 		for (; i < cgd; i++)
40 			setbmap(i);
41 	}
42 	/*
43 	 * Find all allocated blocks.
44 	 */
45 	bzero((char *)&idesc, sizeof(struct inodesc));
46 	idesc.id_type = ADDR;
47 	idesc.id_func = pass1check;
48 	inumber = 0;
49 	n_files = n_blks = 0;
50 	for (c = 0; c < sblock.fs_ncg; c++) {
51 		for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
52 			if (inumber < ROOTINO)
53 				continue;
54 			dp = ginode(inumber);
55 			if (!ALLOC(dp)) {
56 				if (bcmp((char *)dp->di_db, (char *)zino.di_db,
57 					NDADDR * sizeof(daddr_t)) ||
58 				    bcmp((char *)dp->di_ib, (char *)zino.di_ib,
59 					NIADDR * sizeof(daddr_t)) ||
60 				    dp->di_mode || dp->di_size) {
61 					pfatal("PARTIALLY ALLOCATED INODE I=%u",
62 						inumber);
63 					if (reply("CLEAR") == 1) {
64 						zapino(dp);
65 						inodirty();
66 					}
67 				}
68 				statemap[inumber] = USTATE;
69 				continue;
70 			}
71 			lastino = inumber;
72 			if (dp->di_size < 0 ||
73 			    dp->di_size + sblock.fs_bsize - 1 < 0) {
74 				if (debug)
75 					printf("bad size %d:", dp->di_size);
76 				goto unknown;
77 			}
78 			if (!preen && (dp->di_mode & IFMT) == IFMT &&
79 			    reply("HOLD BAD BLOCK") == 1) {
80 				dp->di_size = sblock.fs_fsize;
81 				dp->di_mode = IFREG|0600;
82 				inodirty();
83 			}
84 			ndb = howmany(dp->di_size, sblock.fs_bsize);
85 			if (SPECIAL(dp))
86 				ndb++;
87 			for (j = ndb; j < NDADDR; j++)
88 				if (dp->di_db[j] != 0) {
89 					if (debug)
90 						printf("bad direct addr: %d\n",
91 							dp->di_db[j]);
92 					goto unknown;
93 				}
94 			for (j = 0, ndb -= NDADDR; ndb > 0; j++)
95 				ndb /= NINDIR(&sblock);
96 			for (; j < NIADDR; j++)
97 				if (dp->di_ib[j] != 0) {
98 					if (debug)
99 						printf("bad indirect addr: %d\n",
100 							dp->di_ib[j]);
101 					goto unknown;
102 				}
103 			if (ftypeok(dp) == 0)
104 				goto unknown;
105 			n_files++;
106 			lncntp[inumber] = dp->di_nlink;
107 			if (dp->di_nlink <= 0) {
108 				zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
109 				if (zlnp == NULL) {
110 					pfatal("LINK COUNT TABLE OVERFLOW");
111 					if (reply("CONTINUE") == 0)
112 						errexit("");
113 				} else {
114 					zlnp->zlncnt = inumber;
115 					zlnp->next = zlnhead;
116 					zlnhead = zlnp;
117 				}
118 			}
119 			statemap[inumber] = DIRCT(dp) ? DSTATE : FSTATE;
120 			badblk = dupblk = 0; maxblk = 0;
121 			idesc.id_number = inumber;
122 			(void)ckinode(dp, &idesc);
123 			idesc.id_entryno *= btodb(sblock.fs_fsize);
124 			if (dp->di_blocks != idesc.id_entryno) {
125 				pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)",
126 				    inumber, dp->di_blocks, idesc.id_entryno);
127 				if (preen)
128 					printf(" (CORRECTED)\n");
129 				else if (reply("CORRECT") == 0)
130 					continue;
131 				dp->di_blocks = idesc.id_entryno;
132 				inodirty();
133 			}
134 			continue;
135 	unknown:
136 			pfatal("UNKNOWN FILE TYPE I=%u", inumber);
137 			statemap[inumber] = FCLEAR;
138 			if (reply("CLEAR") == 1) {
139 				statemap[inumber] = USTATE;
140 				zapino(dp);
141 				inodirty();
142 			}
143 		}
144 	}
145 }
146 
147 pass1check(idesc)
148 	register struct inodesc *idesc;
149 {
150 	int res = KEEPON;
151 	int anyout, nfrags;
152 	daddr_t blkno = idesc->id_blkno;
153 	register struct dups *dlp;
154 	struct dups *new;
155 
156 	if ((anyout = outrange(blkno, idesc->id_numfrags)) != 0) {
157 		blkerr(idesc->id_number, "BAD", blkno);
158 		if (++badblk >= MAXBAD) {
159 			pwarn("EXCESSIVE BAD BLKS I=%u",
160 				idesc->id_number);
161 			if (preen)
162 				printf(" (SKIPPING)\n");
163 			else if (reply("CONTINUE") == 0)
164 				errexit("");
165 			return (STOP);
166 		}
167 	}
168 	for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
169 		if (anyout && outrange(blkno, 1)) {
170 			res = SKIP;
171 		} else if (!getbmap(blkno)) {
172 			n_blks++;
173 			setbmap(blkno);
174 		} else {
175 			blkerr(idesc->id_number, "DUP", blkno);
176 			if (++dupblk >= MAXDUP) {
177 				pwarn("EXCESSIVE DUP BLKS I=%u",
178 					idesc->id_number);
179 				if (preen)
180 					printf(" (SKIPPING)\n");
181 				else if (reply("CONTINUE") == 0)
182 					errexit("");
183 				return (STOP);
184 			}
185 			new = (struct dups *)malloc(sizeof(struct dups));
186 			if (new == NULL) {
187 				pfatal("DUP TABLE OVERFLOW.");
188 				if (reply("CONTINUE") == 0)
189 					errexit("");
190 				return (STOP);
191 			}
192 			new->dup = blkno;
193 			if (muldup == 0) {
194 				duplist = muldup = new;
195 				new->next = 0;
196 			} else {
197 				new->next = muldup->next;
198 				muldup->next = new;
199 			}
200 			for (dlp = duplist; dlp != muldup; dlp = dlp->next)
201 				if (dlp->dup == blkno)
202 					break;
203 			if (dlp == muldup && dlp->dup != blkno)
204 				muldup = new;
205 		}
206 		/*
207 		 * count the number of blocks found in id_entryno
208 		 */
209 		idesc->id_entryno++;
210 	}
211 	return (res);
212 }
213