pass1.c revision 69800
1/*
2 * Copyright (c) 1980, 1986, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35#if 0
36static const char sccsid[] = "@(#)pass1.c	8.6 (Berkeley) 4/28/95";
37#endif
38static const char rcsid[] =
39  "$FreeBSD: head/sbin/fsck_ffs/pass1.c 69800 2000-12-09 15:27:35Z tomsoft $";
40#endif /* not lint */
41
42#include <sys/param.h>
43#include <sys/stat.h>
44
45#include <ufs/ufs/dinode.h>
46#include <ufs/ufs/dir.h>
47#include <ufs/ffs/fs.h>
48
49#include <err.h>
50#include <string.h>
51
52#include "fsck.h"
53
54static ufs_daddr_t badblk;
55static ufs_daddr_t dupblk;
56static ino_t lastino;		/* last inode in use */
57
58static void checkinode __P((ino_t inumber, struct inodesc *));
59
60void
61pass1()
62{
63	u_int8_t *cp;
64	ino_t inumber;
65	int c, i, cgd, inosused;
66	struct inostat *info;
67	struct inodesc idesc;
68
69	/*
70	 * Set file system reserved blocks in used block map.
71	 */
72	for (c = 0; c < sblock.fs_ncg; c++) {
73		cgd = cgdmin(&sblock, c);
74		if (c == 0) {
75			i = cgbase(&sblock, c);
76		} else
77			i = cgsblock(&sblock, c);
78		for (; i < cgd; i++)
79			setbmap(i);
80	}
81	i = sblock.fs_csaddr;
82	cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize);
83	for (; i < cgd; i++)
84		setbmap(i);
85
86	/*
87	 * Find all allocated blocks.
88	 */
89	memset(&idesc, 0, sizeof(struct inodesc));
90	idesc.id_func = pass1check;
91	n_files = n_blks = 0;
92	for (c = 0; c < sblock.fs_ncg; c++) {
93		inumber = c * sblock.fs_ipg;
94		setinodebuf(inumber);
95		inosused = sblock.fs_ipg;
96		/*
97		 * If we are using soft updates, then we can trust the
98		 * cylinder group inode allocation maps to tell us which
99		 * inodes are allocated. We will scan the used inode map
100		 * to find the inodes that are really in use, and then
101		 * read only those inodes in from disk.
102		 */
103		if (preen && usedsoftdep) {
104			getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
105			if (!cg_chkmagic(&cgrp))
106				pfatal("CG %d: BAD MAGIC NUMBER\n", c);
107			cp = &cg_inosused(&cgrp)[(sblock.fs_ipg - 1) / NBBY];
108			for ( ; inosused > 0; inosused -= NBBY, cp--) {
109				if (*cp == 0)
110					continue;
111				for (i = 1 << (NBBY - 1); i > 0; i >>= 1) {
112					if (*cp & i)
113						break;
114					inosused--;
115				}
116				break;
117			}
118			if (inosused < 0)
119				inosused = 0;
120		}
121		/*
122		 * Allocate inoinfo structures for the allocated inodes.
123		 */
124		inostathead[c].il_numalloced = inosused;
125		if (inosused == 0) {
126			inostathead[c].il_stat = 0;
127			continue;
128		}
129		info = calloc((unsigned)inosused, sizeof(struct inostat));
130		if (info == NULL)
131			pfatal("cannot alloc %u bytes for inoinfo\n",
132			    (unsigned)(sizeof(struct inostat) * inosused));
133		inostathead[c].il_stat = info;
134		/*
135		 * Scan the allocated inodes.
136		 */
137		for (i = 0; i < inosused; i++, inumber++) {
138			if (inumber < ROOTINO) {
139				(void)getnextinode(inumber);
140				continue;
141			}
142			checkinode(inumber, &idesc);
143		}
144		lastino += 1;
145		if (inosused < sblock.fs_ipg || inumber == lastino)
146			continue;
147		/*
148		 * If we were not able to determine in advance which inodes
149		 * were in use, then reduce the size of the inoinfo structure
150		 * to the size necessary to describe the inodes that we
151		 * really found.
152		 */
153		inosused = lastino - (c * sblock.fs_ipg);
154		if (inosused < 0)
155			inosused = 0;
156		inostathead[c].il_numalloced = inosused;
157		if (inosused == 0) {
158			free(inostathead[c].il_stat);
159			inostathead[c].il_stat = 0;
160			continue;
161		}
162		info = calloc((unsigned)inosused, sizeof(struct inostat));
163		if (info == NULL)
164			pfatal("cannot alloc %u bytes for inoinfo\n",
165			    (unsigned)(sizeof(struct inostat) * inosused));
166		memmove(info, inostathead[c].il_stat, inosused * sizeof(*info));
167		free(inostathead[c].il_stat);
168		inostathead[c].il_stat = info;
169	}
170	freeinodebuf();
171}
172
173static void
174checkinode(inumber, idesc)
175	ino_t inumber;
176	register struct inodesc *idesc;
177{
178	register struct dinode *dp;
179	struct zlncnt *zlnp;
180	int ndb, j;
181	mode_t mode;
182	char *symbuf;
183
184	dp = getnextinode(inumber);
185	mode = dp->di_mode & IFMT;
186	if (mode == 0) {
187		if (memcmp(dp->di_db, zino.di_db,
188			NDADDR * sizeof(ufs_daddr_t)) ||
189		    memcmp(dp->di_ib, zino.di_ib,
190			NIADDR * sizeof(ufs_daddr_t)) ||
191		    dp->di_mode || dp->di_size) {
192			pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber);
193			if (reply("CLEAR") == 1) {
194				dp = ginode(inumber);
195				clearinode(dp);
196				inodirty();
197			}
198		}
199		inoinfo(inumber)->ino_state = USTATE;
200		return;
201	}
202	lastino = inumber;
203	if (/* dp->di_size < 0 || */
204	    dp->di_size + sblock.fs_bsize - 1 < dp->di_size ||
205	    (mode == IFDIR && dp->di_size > MAXDIRSIZE)) {
206		if (debug)
207			printf("bad size %qu:", dp->di_size);
208		goto unknown;
209	}
210	if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
211		dp = ginode(inumber);
212		dp->di_size = sblock.fs_fsize;
213		dp->di_mode = IFREG|0600;
214		inodirty();
215	}
216	if ((mode == IFBLK || mode == IFCHR || mode == IFIFO ||
217	     mode == IFSOCK) && dp->di_size != 0) {
218		if (debug)
219			printf("bad special-file size %qu:", dp->di_size);
220		goto unknown;
221	}
222	ndb = howmany(dp->di_size, sblock.fs_bsize);
223	if (ndb < 0) {
224		if (debug)
225			printf("bad size %qu ndb %d:",
226				dp->di_size, ndb);
227		goto unknown;
228	}
229	if (mode == IFBLK || mode == IFCHR)
230		ndb++;
231	if (mode == IFLNK) {
232		if (doinglevel2 &&
233		    dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN &&
234		    dp->di_blocks != 0) {
235			symbuf = alloca(secsize);
236			if (bread(fsreadfd, symbuf,
237			    fsbtodb(&sblock, dp->di_db[0]),
238			    (long)secsize) != 0)
239				errx(EEXIT, "cannot read symlink");
240			if (debug) {
241				symbuf[dp->di_size] = 0;
242				printf("convert symlink %lu(%s) of size %ld\n",
243				    (u_long)inumber, symbuf, (long)dp->di_size);
244			}
245			dp = ginode(inumber);
246			memmove(dp->di_shortlink, symbuf, (long)dp->di_size);
247			dp->di_blocks = 0;
248			inodirty();
249		}
250		/*
251		 * Fake ndb value so direct/indirect block checks below
252		 * will detect any garbage after symlink string.
253		 */
254		if (dp->di_size < sblock.fs_maxsymlinklen) {
255			ndb = howmany(dp->di_size, sizeof(ufs_daddr_t));
256			if (ndb > NDADDR) {
257				j = ndb - NDADDR;
258				for (ndb = 1; j > 1; j--)
259					ndb *= NINDIR(&sblock);
260				ndb += NDADDR;
261			}
262		}
263	}
264	for (j = ndb; j < NDADDR; j++)
265		if (dp->di_db[j] != 0) {
266			if (debug)
267				printf("bad direct addr: %ld\n",
268				    (long)dp->di_db[j]);
269			goto unknown;
270		}
271	for (j = 0, ndb -= NDADDR; ndb > 0; j++)
272		ndb /= NINDIR(&sblock);
273	for (; j < NIADDR; j++)
274		if (dp->di_ib[j] != 0) {
275			if (debug)
276				printf("bad indirect addr: %ld\n",
277				    (long)dp->di_ib[j]);
278			goto unknown;
279		}
280	if (ftypeok(dp) == 0)
281		goto unknown;
282	n_files++;
283	inoinfo(inumber)->ino_linkcnt = dp->di_nlink;
284	if (dp->di_nlink <= 0) {
285		zlnp = (struct zlncnt *)malloc(sizeof *zlnp);
286		if (zlnp == NULL) {
287			pfatal("LINK COUNT TABLE OVERFLOW");
288			if (reply("CONTINUE") == 0) {
289				ckfini(0);
290				exit(EEXIT);
291			}
292		} else {
293			zlnp->zlncnt = inumber;
294			zlnp->next = zlnhead;
295			zlnhead = zlnp;
296		}
297	}
298	if (mode == IFDIR) {
299		if (dp->di_size == 0)
300			inoinfo(inumber)->ino_state = DCLEAR;
301		else
302			inoinfo(inumber)->ino_state = DSTATE;
303		cacheino(dp, inumber);
304		countdirs++;
305	} else
306		inoinfo(inumber)->ino_state = FSTATE;
307	inoinfo(inumber)->ino_type = IFTODT(mode);
308	if (doinglevel2 &&
309	    (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) {
310		dp = ginode(inumber);
311		dp->di_uid = dp->di_ouid;
312		dp->di_ouid = -1;
313		dp->di_gid = dp->di_ogid;
314		dp->di_ogid = -1;
315		inodirty();
316	}
317	badblk = dupblk = 0;
318	idesc->id_number = inumber;
319	if (dp->di_flags & SF_SNAPSHOT)
320		idesc->id_type = SNAP;
321	else
322		idesc->id_type = ADDR;
323	(void)ckinode(dp, idesc);
324	idesc->id_entryno *= btodb(sblock.fs_fsize);
325	if (dp->di_blocks != idesc->id_entryno) {
326		pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)",
327		    inumber, dp->di_blocks, idesc->id_entryno);
328		if (preen)
329			printf(" (CORRECTED)\n");
330		else if (reply("CORRECT") == 0)
331			return;
332		dp = ginode(inumber);
333		dp->di_blocks = idesc->id_entryno;
334		inodirty();
335	}
336	return;
337unknown:
338	pfatal("UNKNOWN FILE TYPE I=%lu", inumber);
339	inoinfo(inumber)->ino_state = FCLEAR;
340	if (reply("CLEAR") == 1) {
341		inoinfo(inumber)->ino_state = USTATE;
342		dp = ginode(inumber);
343		clearinode(dp);
344		inodirty();
345	}
346}
347
348int
349pass1check(idesc)
350	register struct inodesc *idesc;
351{
352	int res = KEEPON;
353	int anyout, nfrags;
354	ufs_daddr_t blkno = idesc->id_blkno;
355	register struct dups *dlp;
356	struct dups *new;
357
358	if (idesc->id_type == SNAP) {
359		if (blkno == BLK_NOCOPY)
360			return (KEEPON);
361		if (idesc->id_number == cursnapshot) {
362			if (blkno == blkstofrags(&sblock, idesc->id_lbn))
363				return (KEEPON);
364			if (blkno == BLK_SNAP) {
365				blkno = blkstofrags(&sblock, idesc->id_lbn);
366				idesc->id_entryno -= idesc->id_numfrags;
367			}
368		} else {
369			if (blkno == BLK_SNAP)
370				return (KEEPON);
371		}
372	}
373	if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
374		blkerror(idesc->id_number, "BAD", blkno);
375		if (badblk++ >= MAXBAD) {
376			pwarn("EXCESSIVE BAD BLKS I=%lu",
377				idesc->id_number);
378			if (preen)
379				printf(" (SKIPPING)\n");
380			else if (reply("CONTINUE") == 0) {
381				ckfini(0);
382				exit(EEXIT);
383			}
384			return (STOP);
385		}
386	}
387	for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
388		if (anyout && chkrange(blkno, 1)) {
389			res = SKIP;
390		} else if (!testbmap(blkno)) {
391			n_blks++;
392			setbmap(blkno);
393		} else {
394			blkerror(idesc->id_number, "DUP", blkno);
395			if (dupblk++ >= MAXDUP) {
396				pwarn("EXCESSIVE DUP BLKS I=%lu",
397					idesc->id_number);
398				if (preen)
399					printf(" (SKIPPING)\n");
400				else if (reply("CONTINUE") == 0) {
401					ckfini(0);
402					exit(EEXIT);
403				}
404				return (STOP);
405			}
406			new = (struct dups *)malloc(sizeof(struct dups));
407			if (new == NULL) {
408				pfatal("DUP TABLE OVERFLOW.");
409				if (reply("CONTINUE") == 0) {
410					ckfini(0);
411					exit(EEXIT);
412				}
413				return (STOP);
414			}
415			new->dup = blkno;
416			if (muldup == 0) {
417				duplist = muldup = new;
418				new->next = 0;
419			} else {
420				new->next = muldup->next;
421				muldup->next = new;
422			}
423			for (dlp = duplist; dlp != muldup; dlp = dlp->next)
424				if (dlp->dup == blkno)
425					break;
426			if (dlp == muldup && dlp->dup != blkno)
427				muldup = new;
428		}
429		/*
430		 * count the number of blocks found in id_entryno
431		 */
432		idesc->id_entryno++;
433	}
434	return (res);
435}
436