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