pass1.c revision 241012
18871Srgrimes/* 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 * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 30114589Sobrien#if 0 311558Srgrimes#ifndef lint 3223675Speterstatic const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95"; 33114589Sobrien#endif /* not lint */ 3441477Sjulian#endif 35114589Sobrien#include <sys/cdefs.h> 36114589Sobrien__FBSDID("$FreeBSD: head/sbin/fsck_ffs/pass1.c 241012 2012-09-27 23:30:58Z mdf $"); 371558Srgrimes 381558Srgrimes#include <sys/param.h> 3962668Smckusick#include <sys/stat.h> 4074556Smckusick#include <sys/sysctl.h> 4123675Speter 421558Srgrimes#include <ufs/ufs/dinode.h> 431558Srgrimes#include <ufs/ufs/dir.h> 441558Srgrimes#include <ufs/ffs/fs.h> 4523675Speter 4623675Speter#include <err.h> 47103949Smike#include <limits.h> 48101037Smux#include <stdint.h> 491558Srgrimes#include <string.h> 5023675Speter 511558Srgrimes#include "fsck.h" 521558Srgrimes 5398542Smckusickstatic ufs2_daddr_t badblk; 5498542Smckusickstatic ufs2_daddr_t dupblk; 5541474Sjulianstatic ino_t lastino; /* last inode in use */ 561558Srgrimes 57188110Smckusickstatic int checkinode(ino_t inumber, struct inodesc *, int rebuildcg); 587585Sbde 597585Sbdevoid 6092839Simppass1(void) 611558Srgrimes{ 6241474Sjulian struct inostat *info; 631558Srgrimes struct inodesc idesc; 64188110Smckusick ino_t inumber, inosused, mininos; 6598542Smckusick ufs2_daddr_t i, cgd; 6698542Smckusick u_int8_t *cp; 67188110Smckusick int c, rebuildcg; 681558Srgrimes 691558Srgrimes /* 70102231Strhodes * Set file system reserved blocks in used block map. 711558Srgrimes */ 721558Srgrimes for (c = 0; c < sblock.fs_ncg; c++) { 731558Srgrimes cgd = cgdmin(&sblock, c); 741558Srgrimes if (c == 0) { 751558Srgrimes i = cgbase(&sblock, c); 761558Srgrimes } else 771558Srgrimes i = cgsblock(&sblock, c); 781558Srgrimes for (; i < cgd; i++) 791558Srgrimes setbmap(i); 801558Srgrimes } 8169800Stomsoft i = sblock.fs_csaddr; 8269800Stomsoft cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize); 8369800Stomsoft for (; i < cgd; i++) 8469800Stomsoft setbmap(i); 8569800Stomsoft 861558Srgrimes /* 871558Srgrimes * Find all allocated blocks. 881558Srgrimes */ 8923675Speter memset(&idesc, 0, sizeof(struct inodesc)); 901558Srgrimes idesc.id_func = pass1check; 911558Srgrimes n_files = n_blks = 0; 921558Srgrimes for (c = 0; c < sblock.fs_ncg; c++) { 9341474Sjulian inumber = c * sblock.fs_ipg; 9441474Sjulian setinodebuf(inumber); 9598542Smckusick getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize); 96188110Smckusick rebuildcg = 0; 97188110Smckusick if (!check_cgmagic(c, &cgrp)) 98188110Smckusick rebuildcg = 1; 99188110Smckusick if (!rebuildcg && sblock.fs_magic == FS_UFS2_MAGIC) { 10098542Smckusick inosused = cgrp.cg_initediblk; 101201708Smckusick if (inosused > sblock.fs_ipg) { 102241012Smdf pfatal("%s (%ju > %d) %s %d\nReset to %d\n", 103241012Smdf "Too many initialized inodes", 104241012Smdf (uintmax_t)inosused, 105201708Smckusick sblock.fs_ipg, "in cylinder group", c, 106201708Smckusick sblock.fs_ipg); 107176575Sdelphij inosused = sblock.fs_ipg; 108201708Smckusick } 109201708Smckusick } else { 11098542Smckusick inosused = sblock.fs_ipg; 111201708Smckusick } 11270050Siedowse if (got_siginfo) { 11370050Siedowse printf("%s: phase 1: cyl group %d of %d (%d%%)\n", 11470050Siedowse cdevname, c, sblock.fs_ncg, 11570050Siedowse c * 100 / sblock.fs_ncg); 11670050Siedowse got_siginfo = 0; 11770050Siedowse } 118126345Sscottl if (got_sigalarm) { 119126345Sscottl setproctitle("%s p1 %d%%", cdevname, 120126345Sscottl c * 100 / sblock.fs_ncg); 121126345Sscottl got_sigalarm = 0; 122126345Sscottl } 12341474Sjulian /* 12441474Sjulian * If we are using soft updates, then we can trust the 12541474Sjulian * cylinder group inode allocation maps to tell us which 12641474Sjulian * inodes are allocated. We will scan the used inode map 12741474Sjulian * to find the inodes that are really in use, and then 12841474Sjulian * read only those inodes in from disk. 12941474Sjulian */ 130188110Smckusick if ((preen || inoopt) && usedsoftdep && !rebuildcg) { 131103949Smike cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT]; 132103949Smike for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) { 13341474Sjulian if (*cp == 0) 13441474Sjulian continue; 135103949Smike for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { 13641474Sjulian if (*cp & i) 13741474Sjulian break; 13841474Sjulian inosused--; 13941474Sjulian } 14041474Sjulian break; 14141474Sjulian } 14241474Sjulian if (inosused < 0) 14341474Sjulian inosused = 0; 14441474Sjulian } 14541474Sjulian /* 14641474Sjulian * Allocate inoinfo structures for the allocated inodes. 14741474Sjulian */ 14841474Sjulian inostathead[c].il_numalloced = inosused; 14941474Sjulian if (inosused == 0) { 15041474Sjulian inostathead[c].il_stat = 0; 15141474Sjulian continue; 15241474Sjulian } 15341474Sjulian info = calloc((unsigned)inosused, sizeof(struct inostat)); 15441474Sjulian if (info == NULL) 155125036Scperciva errx(EEXIT, "cannot alloc %u bytes for inoinfo", 15641474Sjulian (unsigned)(sizeof(struct inostat) * inosused)); 15741474Sjulian inostathead[c].il_stat = info; 15841474Sjulian /* 15941474Sjulian * Scan the allocated inodes. 16041474Sjulian */ 16141474Sjulian for (i = 0; i < inosused; i++, inumber++) { 16241474Sjulian if (inumber < ROOTINO) { 163188110Smckusick (void)getnextinode(inumber, rebuildcg); 1641558Srgrimes continue; 16541474Sjulian } 166188110Smckusick /* 167188110Smckusick * NULL return indicates probable end of allocated 168188110Smckusick * inodes during cylinder group rebuild attempt. 169188110Smckusick * We always keep trying until we get to the minimum 170188110Smckusick * valid number for this cylinder group. 171188110Smckusick */ 172188110Smckusick if (checkinode(inumber, &idesc, rebuildcg) == 0 && 173188110Smckusick i > cgrp.cg_initediblk) 174188110Smckusick break; 1751558Srgrimes } 176188110Smckusick /* 177188110Smckusick * This optimization speeds up future runs of fsck 178188110Smckusick * by trimming down the number of inodes in cylinder 179188110Smckusick * groups that formerly had many inodes but now have 180188110Smckusick * fewer in use. 181188110Smckusick */ 182188110Smckusick mininos = roundup(inosused + INOPB(&sblock), INOPB(&sblock)); 183188110Smckusick if (inoopt && !preen && !rebuildcg && 184188110Smckusick sblock.fs_magic == FS_UFS2_MAGIC && 185188110Smckusick cgrp.cg_initediblk > 2 * INOPB(&sblock) && 186188110Smckusick mininos < cgrp.cg_initediblk) { 187188110Smckusick i = cgrp.cg_initediblk; 188188110Smckusick if (mininos < 2 * INOPB(&sblock)) 189188110Smckusick cgrp.cg_initediblk = 2 * INOPB(&sblock); 190188110Smckusick else 191188110Smckusick cgrp.cg_initediblk = mininos; 192188110Smckusick pwarn("CYLINDER GROUP %d: RESET FROM %ju TO %d %s\n", 193188110Smckusick c, i, cgrp.cg_initediblk, "VALID INODES"); 194188110Smckusick cgdirty(); 195188110Smckusick } 196188110Smckusick if (inosused < sblock.fs_ipg) 197188110Smckusick continue; 19841474Sjulian lastino += 1; 199188110Smckusick if (lastino < (c * sblock.fs_ipg)) 200188110Smckusick inosused = 0; 201188110Smckusick else 202188110Smckusick inosused = lastino - (c * sblock.fs_ipg); 203188110Smckusick if (rebuildcg && inosused > cgrp.cg_initediblk && 204188110Smckusick sblock.fs_magic == FS_UFS2_MAGIC) { 205188110Smckusick cgrp.cg_initediblk = roundup(inosused, INOPB(&sblock)); 206188110Smckusick pwarn("CYLINDER GROUP %d: FOUND %d VALID INODES\n", c, 207188110Smckusick cgrp.cg_initediblk); 208188110Smckusick } 20941474Sjulian /* 21041474Sjulian * If we were not able to determine in advance which inodes 21141474Sjulian * were in use, then reduce the size of the inoinfo structure 21241474Sjulian * to the size necessary to describe the inodes that we 21341474Sjulian * really found. 21441474Sjulian */ 215188110Smckusick if (inumber == lastino) 216188110Smckusick continue; 21741474Sjulian inostathead[c].il_numalloced = inosused; 21841474Sjulian if (inosused == 0) { 21941474Sjulian free(inostathead[c].il_stat); 22041474Sjulian inostathead[c].il_stat = 0; 22141474Sjulian continue; 22241474Sjulian } 22341474Sjulian info = calloc((unsigned)inosused, sizeof(struct inostat)); 22441474Sjulian if (info == NULL) 225125036Scperciva errx(EEXIT, "cannot alloc %u bytes for inoinfo", 22641474Sjulian (unsigned)(sizeof(struct inostat) * inosused)); 22741474Sjulian memmove(info, inostathead[c].il_stat, inosused * sizeof(*info)); 22841474Sjulian free(inostathead[c].il_stat); 22941474Sjulian inostathead[c].il_stat = info; 2301558Srgrimes } 2311558Srgrimes freeinodebuf(); 2321558Srgrimes} 2331558Srgrimes 234188110Smckusickstatic int 235188110Smckusickcheckinode(ino_t inumber, struct inodesc *idesc, int rebuildcg) 2361558Srgrimes{ 23798542Smckusick union dinode *dp; 23898542Smckusick off_t kernmaxfilesize; 23998542Smckusick ufs2_daddr_t ndb; 2401558Srgrimes mode_t mode; 241103885Smckusick int j, ret, offset; 2421558Srgrimes 243188110Smckusick if ((dp = getnextinode(inumber, rebuildcg)) == NULL) 244188110Smckusick return (0); 24598542Smckusick mode = DIP(dp, di_mode) & IFMT; 2461558Srgrimes if (mode == 0) { 24798542Smckusick if ((sblock.fs_magic == FS_UFS1_MAGIC && 24898542Smckusick (memcmp(dp->dp1.di_db, ufs1_zino.di_db, 24998542Smckusick NDADDR * sizeof(ufs1_daddr_t)) || 25098542Smckusick memcmp(dp->dp1.di_ib, ufs1_zino.di_ib, 25198542Smckusick NIADDR * sizeof(ufs1_daddr_t)) || 25298542Smckusick dp->dp1.di_mode || dp->dp1.di_size)) || 25398542Smckusick (sblock.fs_magic == FS_UFS2_MAGIC && 25498542Smckusick (memcmp(dp->dp2.di_db, ufs2_zino.di_db, 25598542Smckusick NDADDR * sizeof(ufs2_daddr_t)) || 25698542Smckusick memcmp(dp->dp2.di_ib, ufs2_zino.di_ib, 25798542Smckusick NIADDR * sizeof(ufs2_daddr_t)) || 25898542Smckusick dp->dp2.di_mode || dp->dp2.di_size))) { 25986514Siedowse pfatal("PARTIALLY ALLOCATED INODE I=%lu", 26086514Siedowse (u_long)inumber); 2611558Srgrimes if (reply("CLEAR") == 1) { 2621558Srgrimes dp = ginode(inumber); 2631558Srgrimes clearinode(dp); 2641558Srgrimes inodirty(); 2651558Srgrimes } 2661558Srgrimes } 26741474Sjulian inoinfo(inumber)->ino_state = USTATE; 268188110Smckusick return (1); 2691558Srgrimes } 2701558Srgrimes lastino = inumber; 27171884Siedowse /* This should match the file size limit in ffs_mountfs(). */ 27298888Siedowse if (sblock.fs_magic == FS_UFS1_MAGIC) 27398888Siedowse kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1; 27498888Siedowse else 27598888Siedowse kernmaxfilesize = sblock.fs_maxfilesize; 27698542Smckusick if (DIP(dp, di_size) > kernmaxfilesize || 27798542Smckusick DIP(dp, di_size) > sblock.fs_maxfilesize || 27898542Smckusick (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) { 2791558Srgrimes if (debug) 280101037Smux printf("bad size %ju:", (uintmax_t)DIP(dp, di_size)); 2811558Srgrimes goto unknown; 2821558Srgrimes } 2831558Srgrimes if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 2841558Srgrimes dp = ginode(inumber); 285134589Sscottl DIP_SET(dp, di_size, sblock.fs_fsize); 286134589Sscottl DIP_SET(dp, di_mode, IFREG|0600); 2871558Srgrimes inodirty(); 2881558Srgrimes } 28963003Smckusick if ((mode == IFBLK || mode == IFCHR || mode == IFIFO || 29098542Smckusick mode == IFSOCK) && DIP(dp, di_size) != 0) { 29163003Smckusick if (debug) 292101037Smux printf("bad special-file size %ju:", 293101037Smux (uintmax_t)DIP(dp, di_size)); 29463003Smckusick goto unknown; 29563003Smckusick } 29698542Smckusick if ((mode == IFBLK || mode == IFCHR) && 29798542Smckusick (dev_t)DIP(dp, di_rdev) == NODEV) { 29872525Stegge if (debug) 29972525Stegge printf("bad special-file rdev NODEV:"); 30072525Stegge goto unknown; 30172525Stegge } 30298542Smckusick ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 3031558Srgrimes if (ndb < 0) { 3041558Srgrimes if (debug) 305101037Smux printf("bad size %ju ndb %ju:", 306101037Smux (uintmax_t)DIP(dp, di_size), (uintmax_t)ndb); 3071558Srgrimes goto unknown; 3081558Srgrimes } 3091558Srgrimes if (mode == IFBLK || mode == IFCHR) 3101558Srgrimes ndb++; 3111558Srgrimes if (mode == IFLNK) { 3121558Srgrimes /* 3131558Srgrimes * Fake ndb value so direct/indirect block checks below 3141558Srgrimes * will detect any garbage after symlink string. 3151558Srgrimes */ 31698542Smckusick if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 31798542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 31898542Smckusick ndb = howmany(DIP(dp, di_size), 31998542Smckusick sizeof(ufs1_daddr_t)); 32098542Smckusick else 32198542Smckusick ndb = howmany(DIP(dp, di_size), 32298542Smckusick sizeof(ufs2_daddr_t)); 3231558Srgrimes if (ndb > NDADDR) { 3241558Srgrimes j = ndb - NDADDR; 3251558Srgrimes for (ndb = 1; j > 1; j--) 3261558Srgrimes ndb *= NINDIR(&sblock); 3271558Srgrimes ndb += NDADDR; 3281558Srgrimes } 3291558Srgrimes } 3301558Srgrimes } 33198879Siedowse for (j = ndb; ndb < NDADDR && j < NDADDR; j++) 33298542Smckusick if (DIP(dp, di_db[j]) != 0) { 3331558Srgrimes if (debug) 334101037Smux printf("bad direct addr[%d]: %ju\n", j, 335101037Smux (uintmax_t)DIP(dp, di_db[j])); 3361558Srgrimes goto unknown; 3371558Srgrimes } 3381558Srgrimes for (j = 0, ndb -= NDADDR; ndb > 0; j++) 3391558Srgrimes ndb /= NINDIR(&sblock); 3401558Srgrimes for (; j < NIADDR; j++) 34198542Smckusick if (DIP(dp, di_ib[j]) != 0) { 3421558Srgrimes if (debug) 343101037Smux printf("bad indirect addr: %ju\n", 344101037Smux (uintmax_t)DIP(dp, di_ib[j])); 3451558Srgrimes goto unknown; 3461558Srgrimes } 3471558Srgrimes if (ftypeok(dp) == 0) 3481558Srgrimes goto unknown; 3491558Srgrimes n_files++; 35098542Smckusick inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink); 3511558Srgrimes if (mode == IFDIR) { 35298542Smckusick if (DIP(dp, di_size) == 0) 35341474Sjulian inoinfo(inumber)->ino_state = DCLEAR; 354136281Struckman else if (DIP(dp, di_nlink) <= 0) 355136281Struckman inoinfo(inumber)->ino_state = DZLINK; 3561558Srgrimes else 35741474Sjulian inoinfo(inumber)->ino_state = DSTATE; 3581558Srgrimes cacheino(dp, inumber); 35941474Sjulian countdirs++; 360136281Struckman } else if (DIP(dp, di_nlink) <= 0) 361136281Struckman inoinfo(inumber)->ino_state = FZLINK; 362136281Struckman else 36341474Sjulian inoinfo(inumber)->ino_state = FSTATE; 36441474Sjulian inoinfo(inumber)->ino_type = IFTODT(mode); 3651558Srgrimes badblk = dupblk = 0; 3661558Srgrimes idesc->id_number = inumber; 36798542Smckusick if (DIP(dp, di_flags) & SF_SNAPSHOT) 36862668Smckusick idesc->id_type = SNAP; 36962668Smckusick else 37062668Smckusick idesc->id_type = ADDR; 3711558Srgrimes (void)ckinode(dp, idesc); 372103885Smckusick if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) { 373103885Smckusick idesc->id_type = ADDR; 374103885Smckusick ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize); 375103885Smckusick for (j = 0; j < NXADDR; j++) { 376103885Smckusick if (--ndb == 0 && 377103885Smckusick (offset = blkoff(&sblock, dp->dp2.di_extsize)) != 0) 378103885Smckusick idesc->id_numfrags = numfrags(&sblock, 379103885Smckusick fragroundup(&sblock, offset)); 380103885Smckusick else 381103885Smckusick idesc->id_numfrags = sblock.fs_frag; 382103885Smckusick if (dp->dp2.di_extb[j] == 0) 383103885Smckusick continue; 384103885Smckusick idesc->id_blkno = dp->dp2.di_extb[j]; 385103885Smckusick ret = (*idesc->id_func)(idesc); 386103885Smckusick if (ret & STOP) 387103885Smckusick break; 388103885Smckusick } 389103885Smckusick } 390103398Sphk if (sblock.fs_magic == FS_UFS2_MAGIC) 391103398Sphk eascan(idesc, &dp->dp2); 3921558Srgrimes idesc->id_entryno *= btodb(sblock.fs_fsize); 39398542Smckusick if (DIP(dp, di_blocks) != idesc->id_entryno) { 394101037Smux pwarn("INCORRECT BLOCK COUNT I=%lu (%ju should be %ju)", 395101037Smux (u_long)inumber, (uintmax_t)DIP(dp, di_blocks), 396101037Smux (uintmax_t)idesc->id_entryno); 3971558Srgrimes if (preen) 3981558Srgrimes printf(" (CORRECTED)\n"); 3991558Srgrimes else if (reply("CORRECT") == 0) 400188110Smckusick return (1); 40174556Smckusick if (bkgrdflag == 0) { 40274556Smckusick dp = ginode(inumber); 403134589Sscottl DIP_SET(dp, di_blocks, idesc->id_entryno); 40474556Smckusick inodirty(); 40574556Smckusick } else { 40674556Smckusick cmd.value = idesc->id_number; 40798542Smckusick cmd.size = idesc->id_entryno - DIP(dp, di_blocks); 40874556Smckusick if (debug) 409101037Smux printf("adjblkcnt ino %ju amount %lld\n", 410101037Smux (uintmax_t)cmd.value, (long long)cmd.size); 41174556Smckusick if (sysctl(adjblkcnt, MIBSIZE, 0, 0, 41274556Smckusick &cmd, sizeof cmd) == -1) 41374556Smckusick rwerror("ADJUST INODE BLOCK COUNT", cmd.value); 41474556Smckusick } 4151558Srgrimes } 416188110Smckusick return (1); 4171558Srgrimesunknown: 41886514Siedowse pfatal("UNKNOWN FILE TYPE I=%lu", (u_long)inumber); 41941474Sjulian inoinfo(inumber)->ino_state = FCLEAR; 4201558Srgrimes if (reply("CLEAR") == 1) { 42141474Sjulian inoinfo(inumber)->ino_state = USTATE; 4221558Srgrimes dp = ginode(inumber); 4231558Srgrimes clearinode(dp); 4241558Srgrimes inodirty(); 4251558Srgrimes } 426188110Smckusick return (1); 4271558Srgrimes} 4281558Srgrimes 4297585Sbdeint 43092839Simppass1check(struct inodesc *idesc) 4311558Srgrimes{ 4321558Srgrimes int res = KEEPON; 4331558Srgrimes int anyout, nfrags; 43498542Smckusick ufs2_daddr_t blkno = idesc->id_blkno; 43592806Sobrien struct dups *dlp; 4361558Srgrimes struct dups *new; 4371558Srgrimes 43862668Smckusick if (idesc->id_type == SNAP) { 43962668Smckusick if (blkno == BLK_NOCOPY) 44062668Smckusick return (KEEPON); 44162668Smckusick if (idesc->id_number == cursnapshot) { 44262668Smckusick if (blkno == blkstofrags(&sblock, idesc->id_lbn)) 44362668Smckusick return (KEEPON); 44462668Smckusick if (blkno == BLK_SNAP) { 44562668Smckusick blkno = blkstofrags(&sblock, idesc->id_lbn); 44662668Smckusick idesc->id_entryno -= idesc->id_numfrags; 44762668Smckusick } 44862668Smckusick } else { 44962668Smckusick if (blkno == BLK_SNAP) 45062668Smckusick return (KEEPON); 45162668Smckusick } 45262668Smckusick } 4531558Srgrimes if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 4541558Srgrimes blkerror(idesc->id_number, "BAD", blkno); 4551558Srgrimes if (badblk++ >= MAXBAD) { 4561558Srgrimes pwarn("EXCESSIVE BAD BLKS I=%lu", 45786514Siedowse (u_long)idesc->id_number); 4581558Srgrimes if (preen) 4591558Srgrimes printf(" (SKIPPING)\n"); 46034266Sjulian else if (reply("CONTINUE") == 0) { 46134266Sjulian ckfini(0); 46223675Speter exit(EEXIT); 46334266Sjulian } 4641558Srgrimes return (STOP); 4651558Srgrimes } 4661558Srgrimes } 4671558Srgrimes for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 4681558Srgrimes if (anyout && chkrange(blkno, 1)) { 4691558Srgrimes res = SKIP; 4701558Srgrimes } else if (!testbmap(blkno)) { 4711558Srgrimes n_blks++; 4721558Srgrimes setbmap(blkno); 4731558Srgrimes } else { 4741558Srgrimes blkerror(idesc->id_number, "DUP", blkno); 4751558Srgrimes if (dupblk++ >= MAXDUP) { 4761558Srgrimes pwarn("EXCESSIVE DUP BLKS I=%lu", 47786514Siedowse (u_long)idesc->id_number); 4781558Srgrimes if (preen) 4791558Srgrimes printf(" (SKIPPING)\n"); 48034266Sjulian else if (reply("CONTINUE") == 0) { 48134266Sjulian ckfini(0); 48223675Speter exit(EEXIT); 48334266Sjulian } 4841558Srgrimes return (STOP); 4851558Srgrimes } 4861558Srgrimes new = (struct dups *)malloc(sizeof(struct dups)); 4871558Srgrimes if (new == NULL) { 4881558Srgrimes pfatal("DUP TABLE OVERFLOW."); 48934266Sjulian if (reply("CONTINUE") == 0) { 49034266Sjulian ckfini(0); 49123675Speter exit(EEXIT); 49234266Sjulian } 4931558Srgrimes return (STOP); 4941558Srgrimes } 4951558Srgrimes new->dup = blkno; 4961558Srgrimes if (muldup == 0) { 4971558Srgrimes duplist = muldup = new; 4981558Srgrimes new->next = 0; 4991558Srgrimes } else { 5001558Srgrimes new->next = muldup->next; 5011558Srgrimes muldup->next = new; 5021558Srgrimes } 5031558Srgrimes for (dlp = duplist; dlp != muldup; dlp = dlp->next) 5041558Srgrimes if (dlp->dup == blkno) 5051558Srgrimes break; 5061558Srgrimes if (dlp == muldup && dlp->dup != blkno) 5071558Srgrimes muldup = new; 5081558Srgrimes } 5091558Srgrimes /* 5101558Srgrimes * count the number of blocks found in id_entryno 5111558Srgrimes */ 5121558Srgrimes idesc->id_entryno++; 5131558Srgrimes } 5141558Srgrimes return (res); 5151558Srgrimes} 516