xref: /original-bsd/sbin/fsck/pass1.c (revision 64af1d24)
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.3 (Berkeley) 05/13/86";
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 				if (debug)
74 					printf("bad size %d:", dp->di_size);
75 				goto unknown;
76 			}
77 			if (!preen && (dp->di_mode & IFMT) == IFMT &&
78 			    reply("HOLD BAD BLOCK") == 1) {
79 				dp->di_size = sblock.fs_fsize;
80 				dp->di_mode = IFREG|0600;
81 				inodirty();
82 			}
83 			ndb = howmany(dp->di_size, sblock.fs_bsize);
84 			if (SPECIAL(dp))
85 				ndb++;
86 			for (j = ndb; j < NDADDR; j++)
87 				if (dp->di_db[j] != 0) {
88 					if (debug)
89 						printf("bad direct addr: %d\n",
90 							dp->di_db[j]);
91 					goto unknown;
92 				}
93 			for (j = 0, ndb -= NDADDR; ndb > 0; j++)
94 				ndb /= NINDIR(&sblock);
95 			for (; j < NIADDR; j++)
96 				if (dp->di_ib[j] != 0) {
97 					if (debug)
98 						printf("bad indirect addr: %d\n",
99 							dp->di_ib[j]);
100 					goto unknown;
101 				}
102 			if (ftypeok(dp) == 0)
103 				goto unknown;
104 			n_files++;
105 			lncntp[inumber] = dp->di_nlink;
106 			if (dp->di_nlink <= 0) {
107 				zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
108 				if (zlnp == NULL) {
109 					pfatal("LINK COUNT TABLE OVERFLOW");
110 					if (reply("CONTINUE") == 0)
111 						errexit("");
112 				} else {
113 					zlnp->zlncnt = inumber;
114 					zlnp->next = zlnhead;
115 					zlnhead = zlnp;
116 				}
117 			}
118 			statemap[inumber] = DIRCT(dp) ? DSTATE : FSTATE;
119 			badblk = dupblk = 0; maxblk = 0;
120 			idesc.id_number = inumber;
121 			(void)ckinode(dp, &idesc);
122 			idesc.id_entryno *= btodb(sblock.fs_fsize);
123 			if (dp->di_blocks != idesc.id_entryno) {
124 				pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)",
125 				    inumber, dp->di_blocks, idesc.id_entryno);
126 				if (preen)
127 					printf(" (CORRECTED)\n");
128 				else if (reply("CORRECT") == 0)
129 					continue;
130 				dp->di_blocks = idesc.id_entryno;
131 				inodirty();
132 			}
133 			continue;
134 	unknown:
135 			pfatal("UNKNOWN FILE TYPE I=%u", inumber);
136 			statemap[inumber] = FCLEAR;
137 			if (reply("CLEAR") == 1) {
138 				statemap[inumber] = USTATE;
139 				zapino(dp);
140 				inodirty();
141 			}
142 		}
143 	}
144 }
145 
146 pass1check(idesc)
147 	register struct inodesc *idesc;
148 {
149 	int res = KEEPON;
150 	int anyout, nfrags;
151 	daddr_t blkno = idesc->id_blkno;
152 	register struct dups *dlp;
153 	struct dups *new;
154 
155 	if ((anyout = outrange(blkno, idesc->id_numfrags)) != 0) {
156 		blkerr(idesc->id_number, "BAD", blkno);
157 		if (++badblk >= MAXBAD) {
158 			pwarn("EXCESSIVE BAD BLKS I=%u",
159 				idesc->id_number);
160 			if (preen)
161 				printf(" (SKIPPING)\n");
162 			else if (reply("CONTINUE") == 0)
163 				errexit("");
164 			return (STOP);
165 		}
166 	}
167 	for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
168 		if (anyout && outrange(blkno, 1)) {
169 			res = SKIP;
170 		} else if (!getbmap(blkno)) {
171 			n_blks++;
172 			setbmap(blkno);
173 		} else {
174 			blkerr(idesc->id_number, "DUP", blkno);
175 			if (++dupblk >= MAXDUP) {
176 				pwarn("EXCESSIVE DUP BLKS I=%u",
177 					idesc->id_number);
178 				if (preen)
179 					printf(" (SKIPPING)\n");
180 				else if (reply("CONTINUE") == 0)
181 					errexit("");
182 				return (STOP);
183 			}
184 			new = (struct dups *)malloc(sizeof(struct dups));
185 			if (new == NULL) {
186 				pfatal("DUP TABLE OVERFLOW.");
187 				if (reply("CONTINUE") == 0)
188 					errexit("");
189 				return (STOP);
190 			}
191 			new->dup = blkno;
192 			if (muldup == 0) {
193 				duplist = muldup = new;
194 				new->next = 0;
195 			} else {
196 				new->next = muldup->next;
197 				muldup->next = new;
198 			}
199 			for (dlp = duplist; dlp != muldup; dlp = dlp->next)
200 				if (dlp->dup == blkno)
201 					break;
202 			if (dlp == muldup && dlp->dup != blkno)
203 				muldup = new;
204 		}
205 		/*
206 		 * count the number of blocks found in id_entryno
207 		 */
208 		idesc->id_entryno++;
209 	}
210 	return (res);
211 }
212