pass1.c revision 125036
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 * 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 34114589Sobrien#if 0 351558Srgrimes#ifndef lint 3623675Speterstatic const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95"; 37114589Sobrien#endif /* not lint */ 3841477Sjulian#endif 39114589Sobrien#include <sys/cdefs.h> 40114589Sobrien__FBSDID("$FreeBSD: head/sbin/fsck_ffs/pass1.c 125036 2004-01-26 15:05:30Z cperciva $"); 411558Srgrimes 421558Srgrimes#include <sys/param.h> 4362668Smckusick#include <sys/stat.h> 4474556Smckusick#include <sys/sysctl.h> 4523675Speter 461558Srgrimes#include <ufs/ufs/dinode.h> 471558Srgrimes#include <ufs/ufs/dir.h> 481558Srgrimes#include <ufs/ffs/fs.h> 4923675Speter 5023675Speter#include <err.h> 51103949Smike#include <limits.h> 52101037Smux#include <stdint.h> 531558Srgrimes#include <string.h> 5423675Speter 551558Srgrimes#include "fsck.h" 561558Srgrimes 5798542Smckusickstatic ufs2_daddr_t badblk; 5898542Smckusickstatic ufs2_daddr_t dupblk; 5941474Sjulianstatic ino_t lastino; /* last inode in use */ 601558Srgrimes 6192839Simpstatic void checkinode(ino_t inumber, struct inodesc *); 627585Sbde 637585Sbdevoid 6492839Simppass1(void) 651558Srgrimes{ 6641474Sjulian struct inostat *info; 671558Srgrimes struct inodesc idesc; 6898542Smckusick ino_t inumber, inosused; 6998542Smckusick ufs2_daddr_t i, cgd; 7098542Smckusick u_int8_t *cp; 7198542Smckusick int c; 721558Srgrimes 731558Srgrimes /* 74102231Strhodes * Set file system reserved blocks in used block map. 751558Srgrimes */ 761558Srgrimes for (c = 0; c < sblock.fs_ncg; c++) { 771558Srgrimes cgd = cgdmin(&sblock, c); 781558Srgrimes if (c == 0) { 791558Srgrimes i = cgbase(&sblock, c); 801558Srgrimes } else 811558Srgrimes i = cgsblock(&sblock, c); 821558Srgrimes for (; i < cgd; i++) 831558Srgrimes setbmap(i); 841558Srgrimes } 8569800Stomsoft i = sblock.fs_csaddr; 8669800Stomsoft cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize); 8769800Stomsoft for (; i < cgd; i++) 8869800Stomsoft setbmap(i); 8969800Stomsoft 901558Srgrimes /* 911558Srgrimes * Find all allocated blocks. 921558Srgrimes */ 9323675Speter memset(&idesc, 0, sizeof(struct inodesc)); 941558Srgrimes idesc.id_func = pass1check; 951558Srgrimes n_files = n_blks = 0; 961558Srgrimes for (c = 0; c < sblock.fs_ncg; c++) { 9741474Sjulian inumber = c * sblock.fs_ipg; 9841474Sjulian setinodebuf(inumber); 9998542Smckusick getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize); 10098542Smckusick if (sblock.fs_magic == FS_UFS2_MAGIC) 10198542Smckusick inosused = cgrp.cg_initediblk; 10298542Smckusick else 10398542Smckusick inosused = sblock.fs_ipg; 10470050Siedowse if (got_siginfo) { 10570050Siedowse printf("%s: phase 1: cyl group %d of %d (%d%%)\n", 10670050Siedowse cdevname, c, sblock.fs_ncg, 10770050Siedowse c * 100 / sblock.fs_ncg); 10870050Siedowse got_siginfo = 0; 10970050Siedowse } 11041474Sjulian /* 11141474Sjulian * If we are using soft updates, then we can trust the 11241474Sjulian * cylinder group inode allocation maps to tell us which 11341474Sjulian * inodes are allocated. We will scan the used inode map 11441474Sjulian * to find the inodes that are really in use, and then 11541474Sjulian * read only those inodes in from disk. 11641474Sjulian */ 11741474Sjulian if (preen && usedsoftdep) { 11841474Sjulian if (!cg_chkmagic(&cgrp)) 11941474Sjulian pfatal("CG %d: BAD MAGIC NUMBER\n", c); 120103949Smike cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT]; 121103949Smike for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) { 12241474Sjulian if (*cp == 0) 12341474Sjulian continue; 124103949Smike for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { 12541474Sjulian if (*cp & i) 12641474Sjulian break; 12741474Sjulian inosused--; 12841474Sjulian } 12941474Sjulian break; 13041474Sjulian } 13141474Sjulian if (inosused < 0) 13241474Sjulian inosused = 0; 13341474Sjulian } 13441474Sjulian /* 13541474Sjulian * Allocate inoinfo structures for the allocated inodes. 13641474Sjulian */ 13741474Sjulian inostathead[c].il_numalloced = inosused; 13841474Sjulian if (inosused == 0) { 13941474Sjulian inostathead[c].il_stat = 0; 14041474Sjulian continue; 14141474Sjulian } 14241474Sjulian info = calloc((unsigned)inosused, sizeof(struct inostat)); 14341474Sjulian if (info == NULL) 144125036Scperciva errx(EEXIT, "cannot alloc %u bytes for inoinfo", 14541474Sjulian (unsigned)(sizeof(struct inostat) * inosused)); 14641474Sjulian inostathead[c].il_stat = info; 14741474Sjulian /* 14841474Sjulian * Scan the allocated inodes. 14941474Sjulian */ 15041474Sjulian for (i = 0; i < inosused; i++, inumber++) { 15141474Sjulian if (inumber < ROOTINO) { 15241474Sjulian (void)getnextinode(inumber); 1531558Srgrimes continue; 15441474Sjulian } 1551558Srgrimes checkinode(inumber, &idesc); 1561558Srgrimes } 15741474Sjulian lastino += 1; 15841474Sjulian if (inosused < sblock.fs_ipg || inumber == lastino) 15941474Sjulian continue; 16041474Sjulian /* 16141474Sjulian * If we were not able to determine in advance which inodes 16241474Sjulian * were in use, then reduce the size of the inoinfo structure 16341474Sjulian * to the size necessary to describe the inodes that we 16441474Sjulian * really found. 16541474Sjulian */ 16698542Smckusick if (lastino < (c * sblock.fs_ipg)) 16741474Sjulian inosused = 0; 16898542Smckusick else 16998542Smckusick inosused = lastino - (c * sblock.fs_ipg); 17041474Sjulian inostathead[c].il_numalloced = inosused; 17141474Sjulian if (inosused == 0) { 17241474Sjulian free(inostathead[c].il_stat); 17341474Sjulian inostathead[c].il_stat = 0; 17441474Sjulian continue; 17541474Sjulian } 17641474Sjulian info = calloc((unsigned)inosused, sizeof(struct inostat)); 17741474Sjulian if (info == NULL) 178125036Scperciva errx(EEXIT, "cannot alloc %u bytes for inoinfo", 17941474Sjulian (unsigned)(sizeof(struct inostat) * inosused)); 18041474Sjulian memmove(info, inostathead[c].il_stat, inosused * sizeof(*info)); 18141474Sjulian free(inostathead[c].il_stat); 18241474Sjulian inostathead[c].il_stat = info; 1831558Srgrimes } 1841558Srgrimes freeinodebuf(); 1851558Srgrimes} 1861558Srgrimes 18723675Speterstatic void 18892839Simpcheckinode(ino_t inumber, struct inodesc *idesc) 1891558Srgrimes{ 19098542Smckusick union dinode *dp; 1911558Srgrimes struct zlncnt *zlnp; 19298542Smckusick off_t kernmaxfilesize; 19398542Smckusick ufs2_daddr_t ndb; 1941558Srgrimes mode_t mode; 195103885Smckusick int j, ret, offset; 1961558Srgrimes 1971558Srgrimes dp = getnextinode(inumber); 19898542Smckusick mode = DIP(dp, di_mode) & IFMT; 1991558Srgrimes if (mode == 0) { 20098542Smckusick if ((sblock.fs_magic == FS_UFS1_MAGIC && 20198542Smckusick (memcmp(dp->dp1.di_db, ufs1_zino.di_db, 20298542Smckusick NDADDR * sizeof(ufs1_daddr_t)) || 20398542Smckusick memcmp(dp->dp1.di_ib, ufs1_zino.di_ib, 20498542Smckusick NIADDR * sizeof(ufs1_daddr_t)) || 20598542Smckusick dp->dp1.di_mode || dp->dp1.di_size)) || 20698542Smckusick (sblock.fs_magic == FS_UFS2_MAGIC && 20798542Smckusick (memcmp(dp->dp2.di_db, ufs2_zino.di_db, 20898542Smckusick NDADDR * sizeof(ufs2_daddr_t)) || 20998542Smckusick memcmp(dp->dp2.di_ib, ufs2_zino.di_ib, 21098542Smckusick NIADDR * sizeof(ufs2_daddr_t)) || 21198542Smckusick dp->dp2.di_mode || dp->dp2.di_size))) { 21286514Siedowse pfatal("PARTIALLY ALLOCATED INODE I=%lu", 21386514Siedowse (u_long)inumber); 2141558Srgrimes if (reply("CLEAR") == 1) { 2151558Srgrimes dp = ginode(inumber); 2161558Srgrimes clearinode(dp); 2171558Srgrimes inodirty(); 2181558Srgrimes } 2191558Srgrimes } 22041474Sjulian inoinfo(inumber)->ino_state = USTATE; 2211558Srgrimes return; 2221558Srgrimes } 2231558Srgrimes lastino = inumber; 22471884Siedowse /* This should match the file size limit in ffs_mountfs(). */ 22598888Siedowse if (sblock.fs_magic == FS_UFS1_MAGIC) 22698888Siedowse kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1; 22798888Siedowse else 22898888Siedowse kernmaxfilesize = sblock.fs_maxfilesize; 22998542Smckusick if (DIP(dp, di_size) > kernmaxfilesize || 23098542Smckusick DIP(dp, di_size) > sblock.fs_maxfilesize || 23198542Smckusick (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) { 2321558Srgrimes if (debug) 233101037Smux printf("bad size %ju:", (uintmax_t)DIP(dp, di_size)); 2341558Srgrimes goto unknown; 2351558Srgrimes } 2361558Srgrimes if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 2371558Srgrimes dp = ginode(inumber); 23898542Smckusick DIP(dp, di_size) = sblock.fs_fsize; 23998542Smckusick DIP(dp, di_mode) = IFREG|0600; 2401558Srgrimes inodirty(); 2411558Srgrimes } 24263003Smckusick if ((mode == IFBLK || mode == IFCHR || mode == IFIFO || 24398542Smckusick mode == IFSOCK) && DIP(dp, di_size) != 0) { 24463003Smckusick if (debug) 245101037Smux printf("bad special-file size %ju:", 246101037Smux (uintmax_t)DIP(dp, di_size)); 24763003Smckusick goto unknown; 24863003Smckusick } 24998542Smckusick if ((mode == IFBLK || mode == IFCHR) && 25098542Smckusick (dev_t)DIP(dp, di_rdev) == NODEV) { 25172525Stegge if (debug) 25272525Stegge printf("bad special-file rdev NODEV:"); 25372525Stegge goto unknown; 25472525Stegge } 25598542Smckusick ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 2561558Srgrimes if (ndb < 0) { 2571558Srgrimes if (debug) 258101037Smux printf("bad size %ju ndb %ju:", 259101037Smux (uintmax_t)DIP(dp, di_size), (uintmax_t)ndb); 2601558Srgrimes goto unknown; 2611558Srgrimes } 2621558Srgrimes if (mode == IFBLK || mode == IFCHR) 2631558Srgrimes ndb++; 2641558Srgrimes if (mode == IFLNK) { 2651558Srgrimes /* 2661558Srgrimes * Fake ndb value so direct/indirect block checks below 2671558Srgrimes * will detect any garbage after symlink string. 2681558Srgrimes */ 26998542Smckusick if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 27098542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 27198542Smckusick ndb = howmany(DIP(dp, di_size), 27298542Smckusick sizeof(ufs1_daddr_t)); 27398542Smckusick else 27498542Smckusick ndb = howmany(DIP(dp, di_size), 27598542Smckusick sizeof(ufs2_daddr_t)); 2761558Srgrimes if (ndb > NDADDR) { 2771558Srgrimes j = ndb - NDADDR; 2781558Srgrimes for (ndb = 1; j > 1; j--) 2791558Srgrimes ndb *= NINDIR(&sblock); 2801558Srgrimes ndb += NDADDR; 2811558Srgrimes } 2821558Srgrimes } 2831558Srgrimes } 28498879Siedowse for (j = ndb; ndb < NDADDR && j < NDADDR; j++) 28598542Smckusick if (DIP(dp, di_db[j]) != 0) { 2861558Srgrimes if (debug) 287101037Smux printf("bad direct addr[%d]: %ju\n", j, 288101037Smux (uintmax_t)DIP(dp, di_db[j])); 2891558Srgrimes goto unknown; 2901558Srgrimes } 2911558Srgrimes for (j = 0, ndb -= NDADDR; ndb > 0; j++) 2921558Srgrimes ndb /= NINDIR(&sblock); 2931558Srgrimes for (; j < NIADDR; j++) 29498542Smckusick if (DIP(dp, di_ib[j]) != 0) { 2951558Srgrimes if (debug) 296101037Smux printf("bad indirect addr: %ju\n", 297101037Smux (uintmax_t)DIP(dp, di_ib[j])); 2981558Srgrimes goto unknown; 2991558Srgrimes } 3001558Srgrimes if (ftypeok(dp) == 0) 3011558Srgrimes goto unknown; 3021558Srgrimes n_files++; 30398542Smckusick inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink); 30498542Smckusick if (DIP(dp, di_nlink) <= 0) { 3051558Srgrimes zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 3061558Srgrimes if (zlnp == NULL) { 3071558Srgrimes pfatal("LINK COUNT TABLE OVERFLOW"); 30834266Sjulian if (reply("CONTINUE") == 0) { 30934266Sjulian ckfini(0); 31023675Speter exit(EEXIT); 31134266Sjulian } 3121558Srgrimes } else { 3131558Srgrimes zlnp->zlncnt = inumber; 3141558Srgrimes zlnp->next = zlnhead; 3151558Srgrimes zlnhead = zlnp; 3161558Srgrimes } 3171558Srgrimes } 3181558Srgrimes if (mode == IFDIR) { 31998542Smckusick if (DIP(dp, di_size) == 0) 32041474Sjulian inoinfo(inumber)->ino_state = DCLEAR; 3211558Srgrimes else 32241474Sjulian inoinfo(inumber)->ino_state = DSTATE; 3231558Srgrimes cacheino(dp, inumber); 32441474Sjulian countdirs++; 3251558Srgrimes } else 32641474Sjulian inoinfo(inumber)->ino_state = FSTATE; 32741474Sjulian inoinfo(inumber)->ino_type = IFTODT(mode); 3281558Srgrimes badblk = dupblk = 0; 3291558Srgrimes idesc->id_number = inumber; 33098542Smckusick if (DIP(dp, di_flags) & SF_SNAPSHOT) 33162668Smckusick idesc->id_type = SNAP; 33262668Smckusick else 33362668Smckusick idesc->id_type = ADDR; 3341558Srgrimes (void)ckinode(dp, idesc); 335103885Smckusick if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) { 336103885Smckusick idesc->id_type = ADDR; 337103885Smckusick ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize); 338103885Smckusick for (j = 0; j < NXADDR; j++) { 339103885Smckusick if (--ndb == 0 && 340103885Smckusick (offset = blkoff(&sblock, dp->dp2.di_extsize)) != 0) 341103885Smckusick idesc->id_numfrags = numfrags(&sblock, 342103885Smckusick fragroundup(&sblock, offset)); 343103885Smckusick else 344103885Smckusick idesc->id_numfrags = sblock.fs_frag; 345103885Smckusick if (dp->dp2.di_extb[j] == 0) 346103885Smckusick continue; 347103885Smckusick idesc->id_blkno = dp->dp2.di_extb[j]; 348103885Smckusick ret = (*idesc->id_func)(idesc); 349103885Smckusick if (ret & STOP) 350103885Smckusick break; 351103885Smckusick } 352103885Smckusick } 353103398Sphk if (sblock.fs_magic == FS_UFS2_MAGIC) 354103398Sphk eascan(idesc, &dp->dp2); 3551558Srgrimes idesc->id_entryno *= btodb(sblock.fs_fsize); 35698542Smckusick if (DIP(dp, di_blocks) != idesc->id_entryno) { 357101037Smux pwarn("INCORRECT BLOCK COUNT I=%lu (%ju should be %ju)", 358101037Smux (u_long)inumber, (uintmax_t)DIP(dp, di_blocks), 359101037Smux (uintmax_t)idesc->id_entryno); 3601558Srgrimes if (preen) 3611558Srgrimes printf(" (CORRECTED)\n"); 3621558Srgrimes else if (reply("CORRECT") == 0) 3631558Srgrimes return; 36474556Smckusick if (bkgrdflag == 0) { 36574556Smckusick dp = ginode(inumber); 36698542Smckusick DIP(dp, di_blocks) = idesc->id_entryno; 36774556Smckusick inodirty(); 36874556Smckusick } else { 36974556Smckusick cmd.value = idesc->id_number; 37098542Smckusick cmd.size = idesc->id_entryno - DIP(dp, di_blocks); 37174556Smckusick if (debug) 372101037Smux printf("adjblkcnt ino %ju amount %lld\n", 373101037Smux (uintmax_t)cmd.value, (long long)cmd.size); 37474556Smckusick if (sysctl(adjblkcnt, MIBSIZE, 0, 0, 37574556Smckusick &cmd, sizeof cmd) == -1) 37674556Smckusick rwerror("ADJUST INODE BLOCK COUNT", cmd.value); 37774556Smckusick } 3781558Srgrimes } 3791558Srgrimes return; 3801558Srgrimesunknown: 38186514Siedowse pfatal("UNKNOWN FILE TYPE I=%lu", (u_long)inumber); 38241474Sjulian inoinfo(inumber)->ino_state = FCLEAR; 3831558Srgrimes if (reply("CLEAR") == 1) { 38441474Sjulian inoinfo(inumber)->ino_state = USTATE; 3851558Srgrimes dp = ginode(inumber); 3861558Srgrimes clearinode(dp); 3871558Srgrimes inodirty(); 3881558Srgrimes } 3891558Srgrimes} 3901558Srgrimes 3917585Sbdeint 39292839Simppass1check(struct inodesc *idesc) 3931558Srgrimes{ 3941558Srgrimes int res = KEEPON; 3951558Srgrimes int anyout, nfrags; 39698542Smckusick ufs2_daddr_t blkno = idesc->id_blkno; 39792806Sobrien struct dups *dlp; 3981558Srgrimes struct dups *new; 3991558Srgrimes 40062668Smckusick if (idesc->id_type == SNAP) { 40162668Smckusick if (blkno == BLK_NOCOPY) 40262668Smckusick return (KEEPON); 40362668Smckusick if (idesc->id_number == cursnapshot) { 40462668Smckusick if (blkno == blkstofrags(&sblock, idesc->id_lbn)) 40562668Smckusick return (KEEPON); 40662668Smckusick if (blkno == BLK_SNAP) { 40762668Smckusick blkno = blkstofrags(&sblock, idesc->id_lbn); 40862668Smckusick idesc->id_entryno -= idesc->id_numfrags; 40962668Smckusick } 41062668Smckusick } else { 41162668Smckusick if (blkno == BLK_SNAP) 41262668Smckusick return (KEEPON); 41362668Smckusick } 41462668Smckusick } 4151558Srgrimes if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 4161558Srgrimes blkerror(idesc->id_number, "BAD", blkno); 4171558Srgrimes if (badblk++ >= MAXBAD) { 4181558Srgrimes pwarn("EXCESSIVE BAD BLKS I=%lu", 41986514Siedowse (u_long)idesc->id_number); 4201558Srgrimes if (preen) 4211558Srgrimes printf(" (SKIPPING)\n"); 42234266Sjulian else if (reply("CONTINUE") == 0) { 42334266Sjulian ckfini(0); 42423675Speter exit(EEXIT); 42534266Sjulian } 4261558Srgrimes return (STOP); 4271558Srgrimes } 4281558Srgrimes } 4291558Srgrimes for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 4301558Srgrimes if (anyout && chkrange(blkno, 1)) { 4311558Srgrimes res = SKIP; 4321558Srgrimes } else if (!testbmap(blkno)) { 4331558Srgrimes n_blks++; 4341558Srgrimes setbmap(blkno); 4351558Srgrimes } else { 4361558Srgrimes blkerror(idesc->id_number, "DUP", blkno); 4371558Srgrimes if (dupblk++ >= MAXDUP) { 4381558Srgrimes pwarn("EXCESSIVE DUP BLKS I=%lu", 43986514Siedowse (u_long)idesc->id_number); 4401558Srgrimes if (preen) 4411558Srgrimes printf(" (SKIPPING)\n"); 44234266Sjulian else if (reply("CONTINUE") == 0) { 44334266Sjulian ckfini(0); 44423675Speter exit(EEXIT); 44534266Sjulian } 4461558Srgrimes return (STOP); 4471558Srgrimes } 4481558Srgrimes new = (struct dups *)malloc(sizeof(struct dups)); 4491558Srgrimes if (new == NULL) { 4501558Srgrimes pfatal("DUP TABLE OVERFLOW."); 45134266Sjulian if (reply("CONTINUE") == 0) { 45234266Sjulian ckfini(0); 45323675Speter exit(EEXIT); 45434266Sjulian } 4551558Srgrimes return (STOP); 4561558Srgrimes } 4571558Srgrimes new->dup = blkno; 4581558Srgrimes if (muldup == 0) { 4591558Srgrimes duplist = muldup = new; 4601558Srgrimes new->next = 0; 4611558Srgrimes } else { 4621558Srgrimes new->next = muldup->next; 4631558Srgrimes muldup->next = new; 4641558Srgrimes } 4651558Srgrimes for (dlp = duplist; dlp != muldup; dlp = dlp->next) 4661558Srgrimes if (dlp->dup == blkno) 4671558Srgrimes break; 4681558Srgrimes if (dlp == muldup && dlp->dup != blkno) 4691558Srgrimes muldup = new; 4701558Srgrimes } 4711558Srgrimes /* 4721558Srgrimes * count the number of blocks found in id_entryno 4731558Srgrimes */ 4741558Srgrimes idesc->id_entryno++; 4751558Srgrimes } 4761558Srgrimes return (res); 4771558Srgrimes} 478