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