Correct BSD License clause numbering from 1-2-4 to 1-2-3.
[dragonfly.git] / sbin / fsck / pass1.c
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. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)pass1.c  8.6 (Berkeley) 4/28/95
30  * $FreeBSD: src/sbin/fsck/pass1.c,v 1.16.2.5 2002/06/23 22:34:58 iedowse Exp $
31  * $DragonFly: src/sbin/fsck/pass1.c,v 1.9 2006/10/12 04:04:03 dillon Exp $
32  */
33
34 #include <sys/param.h>
35
36 #include <vfs/ufs/dinode.h>
37 #include <vfs/ufs/dir.h>
38 #include <vfs/ufs/fs.h>
39
40 #include <err.h>
41 #include <string.h>
42
43 #include "fsck.h"
44
45 static ufs_daddr_t badblk;
46 static ufs_daddr_t dupblk;
47 static ufs1_ino_t lastino;              /* last inode in use */
48
49 static void checkinode(ufs1_ino_t inumber, struct inodesc *);
50
51 void
52 pass1(void)
53 {
54         u_int8_t *cp;
55         ufs1_ino_t inumber;
56         int c, i, cgd, inosused;
57         struct inostat *info;
58         struct inodesc idesc;
59
60         /*
61          * Set file system reserved blocks in used block map.
62          */
63         for (c = 0; c < sblock.fs_ncg; c++) {
64                 cgd = cgdmin(&sblock, c);
65                 if (c == 0) {
66                         i = cgbase(&sblock, c);
67                 } else
68                         i = cgsblock(&sblock, c);
69                 for (; i < cgd; i++)
70                         setbmap(i);
71         }
72         i = sblock.fs_csaddr;
73         cgd = i+ howmany(sblock.fs_cssize, sblock.fs_fsize);
74         for (; i < cgd; i++)
75                 setbmap(i);
76         /*
77          * Find all allocated blocks.
78          */
79         memset(&idesc, 0, sizeof(struct inodesc));
80         idesc.id_type = ADDR;
81         idesc.id_func = pass1check;
82         n_files = n_blks = 0;
83         for (c = 0; c < sblock.fs_ncg; c++) {
84                 inumber = c * sblock.fs_ipg;
85                 setinodebuf(inumber);
86                 inosused = sblock.fs_ipg;
87                 if (got_siginfo) {
88                         printf("%s: phase 1: cyl group %d of %d (%d%%)\n",
89                             cdevname, c, sblock.fs_ncg,
90                             c * 100 / sblock.fs_ncg);
91                         got_siginfo = 0;
92                 }
93                 /*
94                  * If we are using soft updates, then we can trust the
95                  * cylinder group inode allocation maps to tell us which
96                  * inodes are allocated. We will scan the used inode map
97                  * to find the inodes that are really in use, and then
98                  * read only those inodes in from disk.
99                  */
100                 if (preen && usedsoftdep) {
101                         getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
102                         if (!cg_chkmagic(&cgrp))
103                                 pfatal("CG %d: BAD MAGIC NUMBER\n", c);
104                         cp = &cg_inosused(&cgrp)[(sblock.fs_ipg - 1) / NBBY];
105                         for ( ; inosused > 0; inosused -= NBBY, cp--) {
106                                 if (*cp == 0)
107                                         continue;
108                                 for (i = 1 << (NBBY - 1); i > 0; i >>= 1) {
109                                         if (*cp & i)
110                                                 break;
111                                         inosused--;
112                                 }
113                                 break;
114                         }
115                         if (inosused < 0)
116                                 inosused = 0;
117                 }
118                 /*
119                  * Allocate inoinfo structures for the allocated inodes.
120                  */
121                 inostathead[c].il_numalloced = inosused;
122                 if (inosused == 0) {
123                         inostathead[c].il_stat = 0;
124                         continue;
125                 }
126                 info = calloc((unsigned)inosused, sizeof(struct inostat));
127                 if (info == NULL)
128                         pfatal("cannot alloc %u bytes for inoinfo\n",
129                             (unsigned)(sizeof(struct inostat) * inosused));
130                 inostathead[c].il_stat = info;
131                 /*
132                  * Scan the allocated inodes.
133                  */
134                 for (i = 0; i < inosused; i++, inumber++) {
135                         if (inumber < ROOTINO) {
136                                 getnextinode(inumber);
137                                 continue;
138                         }
139                         checkinode(inumber, &idesc);
140                 }
141                 lastino += 1;
142                 if (inosused < sblock.fs_ipg || inumber == lastino)
143                         continue;
144                 /*
145                  * If we were not able to determine in advance which inodes
146                  * were in use, then reduce the size of the inoinfo structure
147                  * to the size necessary to describe the inodes that we
148                  * really found.
149                  */
150                 inosused = lastino - (c * sblock.fs_ipg);
151                 if (inosused < 0)
152                         inosused = 0;
153                 inostathead[c].il_numalloced = inosused;
154                 if (inosused == 0) {
155                         free(inostathead[c].il_stat);
156                         inostathead[c].il_stat = 0;
157                         continue;
158                 }
159                 info = calloc((unsigned)inosused, sizeof(struct inostat));
160                 if (info == NULL)
161                         pfatal("cannot alloc %u bytes for inoinfo\n",
162                             (unsigned)(sizeof(struct inostat) * inosused));
163                 memmove(info, inostathead[c].il_stat, inosused * sizeof(*info));
164                 free(inostathead[c].il_stat);
165                 inostathead[c].il_stat = info;
166         }
167         freeinodebuf();
168 }
169
170 static void
171 checkinode(ufs1_ino_t inumber, struct inodesc *idesc)
172 {
173         struct ufs1_dinode *dp;
174         struct zlncnt *zlnp;
175         u_int64_t kernmaxfilesize;
176         ufs_daddr_t ndb, j;
177         mode_t mode;
178         char *symbuf;
179
180         dp = getnextinode(inumber);
181         mode = dp->di_mode & IFMT;
182         if (mode == 0) {
183                 if (memcmp(dp->di_db, zino.di_db,
184                         NDADDR * sizeof(ufs_daddr_t)) ||
185                     memcmp(dp->di_ib, zino.di_ib,
186                         NIADDR * sizeof(ufs_daddr_t)) ||
187                     dp->di_mode || dp->di_size) {
188                         pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber);
189                         if (reply("CLEAR") == 1) {
190                                 dp = ginode(inumber);
191                                 clearinode(dp);
192                                 inodirty();
193                         }
194                 }
195                 inoinfo(inumber)->ino_state = USTATE;
196                 return;
197         }
198         lastino = inumber;
199         /* This should match the file size limit in ffs_mountfs(). */
200         kernmaxfilesize = (u_int64_t)0x40000000 * sblock.fs_bsize - 1;
201         if (kernmaxfilesize > (u_int64_t)0x80000000u * PAGE_SIZE - 1)
202                 kernmaxfilesize = (u_int64_t)0x80000000u * PAGE_SIZE - 1;
203         if (dp->di_size > kernmaxfilesize ||
204             dp->di_size > sblock.fs_maxfilesize ||
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         ckinode(dp, idesc);
320         idesc->id_entryno *= btodb(sblock.fs_fsize);
321         if (dp->di_blocks != idesc->id_entryno) {
322                 pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)",
323                     inumber, dp->di_blocks, idesc->id_entryno);
324                 if (preen)
325                         printf(" (CORRECTED)\n");
326                 else if (reply("CORRECT") == 0)
327                         return;
328                 dp = ginode(inumber);
329                 dp->di_blocks = idesc->id_entryno;
330                 inodirty();
331         }
332         return;
333 unknown:
334         pfatal("UNKNOWN FILE TYPE I=%lu", inumber);
335         inoinfo(inumber)->ino_state = FCLEAR;
336         if (reply("CLEAR") == 1) {
337                 inoinfo(inumber)->ino_state = USTATE;
338                 dp = ginode(inumber);
339                 clearinode(dp);
340                 inodirty();
341         }
342 }
343
344 int
345 pass1check(struct inodesc *idesc)
346 {
347         int res = KEEPON;
348         int anyout, nfrags;
349         ufs_daddr_t blkno = idesc->id_blkno;
350         struct dups *dlp;
351         struct dups *new;
352
353         if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
354                 blkerror(idesc->id_number, "BAD", blkno);
355                 if (badblk++ >= MAXBAD) {
356                         pwarn("EXCESSIVE BAD BLKS I=%lu",
357                                 idesc->id_number);
358                         if (preen)
359                                 printf(" (SKIPPING)\n");
360                         else if (reply("CONTINUE") == 0) {
361                                 ckfini(0);
362                                 exit(EEXIT);
363                         }
364                         return (STOP);
365                 }
366         }
367         for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
368                 if (anyout && chkrange(blkno, 1)) {
369                         res = SKIP;
370                 } else if (!testbmap(blkno)) {
371                         n_blks++;
372                         setbmap(blkno);
373                 } else {
374                         blkerror(idesc->id_number, "DUP", blkno);
375                         if (dupblk++ >= MAXDUP) {
376                                 pwarn("EXCESSIVE DUP 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                         new = (struct dups *)malloc(sizeof(struct dups));
387                         if (new == NULL) {
388                                 pfatal("DUP TABLE OVERFLOW.");
389                                 if (reply("CONTINUE") == 0) {
390                                         ckfini(0);
391                                         exit(EEXIT);
392                                 }
393                                 return (STOP);
394                         }
395                         new->dup = blkno;
396                         if (muldup == 0) {
397                                 duplist = muldup = new;
398                                 new->next = 0;
399                         } else {
400                                 new->next = muldup->next;
401                                 muldup->next = new;
402                         }
403                         for (dlp = duplist; dlp != muldup; dlp = dlp->next)
404                                 if (dlp->dup == blkno)
405                                         break;
406                         if (dlp == muldup && dlp->dup != blkno)
407                                 muldup = new;
408                 }
409                 /*
410                  * count the number of blocks found in id_entryno
411                  */
412                 idesc->id_entryno++;
413         }
414         return (res);
415 }