pass1.c revision 7585
12605Sdg/* 21558Srgrimes * Copyright (c) 1980, 1986, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 357585Sbdestatic const char sccsid[] = "@(#)pass1.c 8.1 (Berkeley) 6/5/93"; 361558Srgrimes#endif /* not lint */ 371558Srgrimes 381558Srgrimes#include <sys/param.h> 391558Srgrimes#include <sys/time.h> 401558Srgrimes#include <ufs/ufs/dinode.h> 411558Srgrimes#include <ufs/ufs/dir.h> 421558Srgrimes#include <ufs/ffs/fs.h> 437585Sbde#include <stdio.h> 441558Srgrimes#include <stdlib.h> 451558Srgrimes#include <string.h> 461558Srgrimes#include "fsck.h" 471558Srgrimes 481558Srgrimesstatic daddr_t badblk; 491558Srgrimesstatic daddr_t dupblk; 501558Srgrimes 517585Sbdestatic void checkinode __P((ino_t inumber, struct inodesc *idesc)); 527585Sbde 537585Sbdevoid 541558Srgrimespass1() 551558Srgrimes{ 561558Srgrimes ino_t inumber; 571558Srgrimes int c, i, cgd; 581558Srgrimes struct inodesc idesc; 591558Srgrimes 601558Srgrimes /* 611558Srgrimes * Set file system reserved blocks in used block map. 621558Srgrimes */ 631558Srgrimes for (c = 0; c < sblock.fs_ncg; c++) { 641558Srgrimes cgd = cgdmin(&sblock, c); 651558Srgrimes if (c == 0) { 661558Srgrimes i = cgbase(&sblock, c); 671558Srgrimes cgd += howmany(sblock.fs_cssize, sblock.fs_fsize); 681558Srgrimes } else 691558Srgrimes i = cgsblock(&sblock, c); 701558Srgrimes for (; i < cgd; i++) 711558Srgrimes setbmap(i); 721558Srgrimes } 731558Srgrimes /* 741558Srgrimes * Find all allocated blocks. 751558Srgrimes */ 761558Srgrimes bzero((char *)&idesc, sizeof(struct inodesc)); 771558Srgrimes idesc.id_type = ADDR; 781558Srgrimes idesc.id_func = pass1check; 791558Srgrimes inumber = 0; 801558Srgrimes n_files = n_blks = 0; 811558Srgrimes resetinodebuf(); 821558Srgrimes for (c = 0; c < sblock.fs_ncg; c++) { 831558Srgrimes for (i = 0; i < sblock.fs_ipg; i++, inumber++) { 841558Srgrimes if (inumber < ROOTINO) 851558Srgrimes continue; 861558Srgrimes checkinode(inumber, &idesc); 871558Srgrimes } 881558Srgrimes } 891558Srgrimes freeinodebuf(); 901558Srgrimes} 911558Srgrimes 927585Sbdevoid 931558Srgrimescheckinode(inumber, idesc) 941558Srgrimes ino_t inumber; 951558Srgrimes register struct inodesc *idesc; 961558Srgrimes{ 971558Srgrimes register struct dinode *dp; 981558Srgrimes struct zlncnt *zlnp; 991558Srgrimes int ndb, j; 1001558Srgrimes mode_t mode; 1012603Sdg char *symbuf; 1021558Srgrimes 1031558Srgrimes dp = getnextinode(inumber); 1041558Srgrimes mode = dp->di_mode & IFMT; 1051558Srgrimes if (mode == 0) { 1061558Srgrimes if (bcmp((char *)dp->di_db, (char *)zino.di_db, 1071558Srgrimes NDADDR * sizeof(daddr_t)) || 1081558Srgrimes bcmp((char *)dp->di_ib, (char *)zino.di_ib, 1091558Srgrimes NIADDR * sizeof(daddr_t)) || 1101558Srgrimes dp->di_mode || dp->di_size) { 1111558Srgrimes pfatal("PARTIALLY ALLOCATED INODE I=%lu", inumber); 1121558Srgrimes if (reply("CLEAR") == 1) { 1131558Srgrimes dp = ginode(inumber); 1141558Srgrimes clearinode(dp); 1151558Srgrimes inodirty(); 1161558Srgrimes } 1171558Srgrimes } 1181558Srgrimes statemap[inumber] = USTATE; 1191558Srgrimes return; 1201558Srgrimes } 1211558Srgrimes lastino = inumber; 1221558Srgrimes if (/* dp->di_size < 0 || */ 1231558Srgrimes dp->di_size + sblock.fs_bsize - 1 < dp->di_size) { 1241558Srgrimes if (debug) 1251558Srgrimes printf("bad size %qu:", dp->di_size); 1261558Srgrimes goto unknown; 1271558Srgrimes } 1281558Srgrimes if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 1291558Srgrimes dp = ginode(inumber); 1301558Srgrimes dp->di_size = sblock.fs_fsize; 1311558Srgrimes dp->di_mode = IFREG|0600; 1321558Srgrimes inodirty(); 1331558Srgrimes } 1341558Srgrimes ndb = howmany(dp->di_size, sblock.fs_bsize); 1351558Srgrimes if (ndb < 0) { 1361558Srgrimes if (debug) 1371558Srgrimes printf("bad size %qu ndb %d:", 1381558Srgrimes dp->di_size, ndb); 1391558Srgrimes goto unknown; 1401558Srgrimes } 1411558Srgrimes if (mode == IFBLK || mode == IFCHR) 1421558Srgrimes ndb++; 1431558Srgrimes if (mode == IFLNK) { 1441558Srgrimes if (doinglevel2 && 1451558Srgrimes dp->di_size > 0 && dp->di_size < MAXSYMLINKLEN && 1461558Srgrimes dp->di_blocks != 0) { 1472603Sdg symbuf = alloca(secsize); 1481558Srgrimes if (bread(fsreadfd, symbuf, 1491558Srgrimes fsbtodb(&sblock, dp->di_db[0]), 1502603Sdg (long)secsize) != 0) 1511558Srgrimes errexit("cannot read symlink"); 1521558Srgrimes if (debug) { 1531558Srgrimes symbuf[dp->di_size] = 0; 1547585Sbde printf("convert symlink %ld(%s) of size %ld\n", 1551558Srgrimes inumber, symbuf, (long)dp->di_size); 1561558Srgrimes } 1571558Srgrimes dp = ginode(inumber); 1581558Srgrimes bcopy(symbuf, (caddr_t)dp->di_shortlink, 1591558Srgrimes (long)dp->di_size); 1601558Srgrimes dp->di_blocks = 0; 1611558Srgrimes inodirty(); 1621558Srgrimes } 1631558Srgrimes /* 1641558Srgrimes * Fake ndb value so direct/indirect block checks below 1651558Srgrimes * will detect any garbage after symlink string. 1661558Srgrimes */ 1671820Sdg if ((dp->di_size < sblock.fs_maxsymlinklen) || dp->di_blocks == 0) { 1681558Srgrimes ndb = howmany(dp->di_size, sizeof(daddr_t)); 1691558Srgrimes if (ndb > NDADDR) { 1701558Srgrimes j = ndb - NDADDR; 1711558Srgrimes for (ndb = 1; j > 1; j--) 1721558Srgrimes ndb *= NINDIR(&sblock); 1731558Srgrimes ndb += NDADDR; 1741558Srgrimes } 1751558Srgrimes } 1761558Srgrimes } 1771558Srgrimes for (j = ndb; j < NDADDR; j++) 1781558Srgrimes if (dp->di_db[j] != 0) { 1791558Srgrimes if (debug) 1801558Srgrimes printf("bad direct addr: %ld\n", dp->di_db[j]); 1811558Srgrimes goto unknown; 1821558Srgrimes } 1831558Srgrimes for (j = 0, ndb -= NDADDR; ndb > 0; j++) 1841558Srgrimes ndb /= NINDIR(&sblock); 1851558Srgrimes for (; j < NIADDR; j++) 1861558Srgrimes if (dp->di_ib[j] != 0) { 1871558Srgrimes if (debug) 1881558Srgrimes printf("bad indirect addr: %ld\n", 1891558Srgrimes dp->di_ib[j]); 1901558Srgrimes goto unknown; 1911558Srgrimes } 1921558Srgrimes if (ftypeok(dp) == 0) 1931558Srgrimes goto unknown; 1941558Srgrimes n_files++; 1951558Srgrimes lncntp[inumber] = dp->di_nlink; 1961558Srgrimes if (dp->di_nlink <= 0) { 1971558Srgrimes zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 1981558Srgrimes if (zlnp == NULL) { 1991558Srgrimes pfatal("LINK COUNT TABLE OVERFLOW"); 2001558Srgrimes if (reply("CONTINUE") == 0) 2011558Srgrimes errexit(""); 2021558Srgrimes } else { 2031558Srgrimes zlnp->zlncnt = inumber; 2041558Srgrimes zlnp->next = zlnhead; 2051558Srgrimes zlnhead = zlnp; 2061558Srgrimes } 2071558Srgrimes } 2081558Srgrimes if (mode == IFDIR) { 2091558Srgrimes if (dp->di_size == 0) 2101558Srgrimes statemap[inumber] = DCLEAR; 2111558Srgrimes else 2121558Srgrimes statemap[inumber] = DSTATE; 2131558Srgrimes cacheino(dp, inumber); 2141558Srgrimes } else 2151558Srgrimes statemap[inumber] = FSTATE; 2161558Srgrimes typemap[inumber] = IFTODT(mode); 2171558Srgrimes if (doinglevel2 && 2181558Srgrimes (dp->di_ouid != (u_short)-1 || dp->di_ogid != (u_short)-1)) { 2191558Srgrimes dp = ginode(inumber); 2201558Srgrimes dp->di_uid = dp->di_ouid; 2211558Srgrimes dp->di_ouid = -1; 2221558Srgrimes dp->di_gid = dp->di_ogid; 2231558Srgrimes dp->di_ogid = -1; 2241558Srgrimes inodirty(); 2251558Srgrimes } 2261558Srgrimes badblk = dupblk = 0; 2271558Srgrimes idesc->id_number = inumber; 2281558Srgrimes (void)ckinode(dp, idesc); 2291558Srgrimes idesc->id_entryno *= btodb(sblock.fs_fsize); 2301558Srgrimes if (dp->di_blocks != idesc->id_entryno) { 2311558Srgrimes pwarn("INCORRECT BLOCK COUNT I=%lu (%ld should be %ld)", 2321558Srgrimes inumber, dp->di_blocks, idesc->id_entryno); 2331558Srgrimes if (preen) 2341558Srgrimes printf(" (CORRECTED)\n"); 2351558Srgrimes else if (reply("CORRECT") == 0) 2361558Srgrimes return; 2371558Srgrimes dp = ginode(inumber); 2381558Srgrimes dp->di_blocks = idesc->id_entryno; 2391558Srgrimes inodirty(); 2401558Srgrimes } 2411558Srgrimes return; 2421558Srgrimesunknown: 2431558Srgrimes pfatal("UNKNOWN FILE TYPE I=%lu", inumber); 2441558Srgrimes statemap[inumber] = FCLEAR; 2451558Srgrimes if (reply("CLEAR") == 1) { 2461558Srgrimes statemap[inumber] = USTATE; 2471558Srgrimes dp = ginode(inumber); 2481558Srgrimes clearinode(dp); 2491558Srgrimes inodirty(); 2501558Srgrimes } 2511558Srgrimes} 2521558Srgrimes 2537585Sbdeint 2541558Srgrimespass1check(idesc) 2551558Srgrimes register struct inodesc *idesc; 2561558Srgrimes{ 2571558Srgrimes int res = KEEPON; 2581558Srgrimes int anyout, nfrags; 2591558Srgrimes daddr_t blkno = idesc->id_blkno; 2601558Srgrimes register struct dups *dlp; 2611558Srgrimes struct dups *new; 2621558Srgrimes 2631558Srgrimes if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 2641558Srgrimes blkerror(idesc->id_number, "BAD", blkno); 2651558Srgrimes if (badblk++ >= MAXBAD) { 2661558Srgrimes pwarn("EXCESSIVE BAD BLKS I=%lu", 2671558Srgrimes idesc->id_number); 2681558Srgrimes if (preen) 2691558Srgrimes printf(" (SKIPPING)\n"); 2701558Srgrimes else if (reply("CONTINUE") == 0) 2711558Srgrimes errexit(""); 2721558Srgrimes return (STOP); 2731558Srgrimes } 2741558Srgrimes } 2751558Srgrimes for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 2761558Srgrimes if (anyout && chkrange(blkno, 1)) { 2771558Srgrimes res = SKIP; 2781558Srgrimes } else if (!testbmap(blkno)) { 2791558Srgrimes n_blks++; 2801558Srgrimes setbmap(blkno); 2811558Srgrimes } else { 2821558Srgrimes blkerror(idesc->id_number, "DUP", blkno); 2831558Srgrimes if (dupblk++ >= MAXDUP) { 2841558Srgrimes pwarn("EXCESSIVE DUP BLKS I=%lu", 2851558Srgrimes idesc->id_number); 2861558Srgrimes if (preen) 2871558Srgrimes printf(" (SKIPPING)\n"); 2881558Srgrimes else if (reply("CONTINUE") == 0) 2891558Srgrimes errexit(""); 2901558Srgrimes return (STOP); 2911558Srgrimes } 2921558Srgrimes new = (struct dups *)malloc(sizeof(struct dups)); 2931558Srgrimes if (new == NULL) { 2941558Srgrimes pfatal("DUP TABLE OVERFLOW."); 2951558Srgrimes if (reply("CONTINUE") == 0) 2961558Srgrimes errexit(""); 2971558Srgrimes return (STOP); 2981558Srgrimes } 2991558Srgrimes new->dup = blkno; 3001558Srgrimes if (muldup == 0) { 3011558Srgrimes duplist = muldup = new; 3021558Srgrimes new->next = 0; 3031558Srgrimes } else { 3041558Srgrimes new->next = muldup->next; 3051558Srgrimes muldup->next = new; 3061558Srgrimes } 3071558Srgrimes for (dlp = duplist; dlp != muldup; dlp = dlp->next) 3081558Srgrimes if (dlp->dup == blkno) 3091558Srgrimes break; 3101558Srgrimes if (dlp == muldup && dlp->dup != blkno) 3111558Srgrimes muldup = new; 3121558Srgrimes } 3131558Srgrimes /* 3141558Srgrimes * count the number of blocks found in id_entryno 3151558Srgrimes */ 3161558Srgrimes idesc->id_entryno++; 3171558Srgrimes } 3181558Srgrimes return (res); 3191558Srgrimes} 320