pass1.c revision 103885
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 341558Srgrimes#ifndef lint 3541477Sjulian#if 0 3623675Speterstatic const char sccsid[] = "@(#)pass1.c 8.6 (Berkeley) 4/28/95"; 3741477Sjulian#endif 3841477Sjulianstatic const char rcsid[] = 3950476Speter "$FreeBSD: head/sbin/fsck_ffs/pass1.c 103885 2002-09-24 05:18:17Z mckusick $"; 401558Srgrimes#endif /* not lint */ 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> 51101037Smux#include <stdint.h> 521558Srgrimes#include <string.h> 5323675Speter 541558Srgrimes#include "fsck.h" 551558Srgrimes 5698542Smckusickstatic ufs2_daddr_t badblk; 5798542Smckusickstatic ufs2_daddr_t dupblk; 5841474Sjulianstatic ino_t lastino; /* last inode in use */ 591558Srgrimes 6092839Simpstatic void checkinode(ino_t inumber, struct inodesc *); 617585Sbde 627585Sbdevoid 6392839Simppass1(void) 641558Srgrimes{ 6541474Sjulian struct inostat *info; 661558Srgrimes struct inodesc idesc; 6798542Smckusick ino_t inumber, inosused; 6898542Smckusick ufs2_daddr_t i, cgd; 6998542Smckusick u_int8_t *cp; 7098542Smckusick int c; 711558Srgrimes 721558Srgrimes /* 73102231Strhodes * Set file system reserved blocks in used block map. 741558Srgrimes */ 751558Srgrimes for (c = 0; c < sblock.fs_ncg; c++) { 761558Srgrimes cgd = cgdmin(&sblock, c); 771558Srgrimes if (c == 0) { 781558Srgrimes i = cgbase(&sblock, c); 791558Srgrimes } else 801558Srgrimes i = cgsblock(&sblock, c); 811558Srgrimes for (; i < cgd; i++) 821558Srgrimes setbmap(i); 831558Srgrimes } 8469800Stomsoft i = sblock.fs_csaddr; 8569800Stomsoft cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize); 8669800Stomsoft for (; i < cgd; i++) 8769800Stomsoft setbmap(i); 8869800Stomsoft 891558Srgrimes /* 901558Srgrimes * Find all allocated blocks. 911558Srgrimes */ 9223675Speter memset(&idesc, 0, sizeof(struct inodesc)); 931558Srgrimes idesc.id_func = pass1check; 941558Srgrimes n_files = n_blks = 0; 951558Srgrimes for (c = 0; c < sblock.fs_ncg; c++) { 9641474Sjulian inumber = c * sblock.fs_ipg; 9741474Sjulian setinodebuf(inumber); 9898542Smckusick getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize); 9998542Smckusick if (sblock.fs_magic == FS_UFS2_MAGIC) 10098542Smckusick inosused = cgrp.cg_initediblk; 10198542Smckusick else 10298542Smckusick inosused = sblock.fs_ipg; 10370050Siedowse if (got_siginfo) { 10470050Siedowse printf("%s: phase 1: cyl group %d of %d (%d%%)\n", 10570050Siedowse cdevname, c, sblock.fs_ncg, 10670050Siedowse c * 100 / sblock.fs_ncg); 10770050Siedowse got_siginfo = 0; 10870050Siedowse } 10941474Sjulian /* 11041474Sjulian * If we are using soft updates, then we can trust the 11141474Sjulian * cylinder group inode allocation maps to tell us which 11241474Sjulian * inodes are allocated. We will scan the used inode map 11341474Sjulian * to find the inodes that are really in use, and then 11441474Sjulian * read only those inodes in from disk. 11541474Sjulian */ 11641474Sjulian if (preen && usedsoftdep) { 11741474Sjulian if (!cg_chkmagic(&cgrp)) 11841474Sjulian pfatal("CG %d: BAD MAGIC NUMBER\n", c); 11998542Smckusick cp = &cg_inosused(&cgrp)[(inosused - 1) / NBBY]; 12041474Sjulian for ( ; inosused > 0; inosused -= NBBY, cp--) { 12141474Sjulian if (*cp == 0) 12241474Sjulian continue; 12341474Sjulian for (i = 1 << (NBBY - 1); i > 0; i >>= 1) { 12441474Sjulian if (*cp & i) 12541474Sjulian break; 12641474Sjulian inosused--; 12741474Sjulian } 12841474Sjulian break; 12941474Sjulian } 13041474Sjulian if (inosused < 0) 13141474Sjulian inosused = 0; 13241474Sjulian } 13341474Sjulian /* 13441474Sjulian * Allocate inoinfo structures for the allocated inodes. 13541474Sjulian */ 13641474Sjulian inostathead[c].il_numalloced = inosused; 13741474Sjulian if (inosused == 0) { 13841474Sjulian inostathead[c].il_stat = 0; 13941474Sjulian continue; 14041474Sjulian } 14141474Sjulian info = calloc((unsigned)inosused, sizeof(struct inostat)); 14241474Sjulian if (info == NULL) 14341474Sjulian pfatal("cannot alloc %u bytes for inoinfo\n", 14441474Sjulian (unsigned)(sizeof(struct inostat) * inosused)); 14541474Sjulian inostathead[c].il_stat = info; 14641474Sjulian /* 14741474Sjulian * Scan the allocated inodes. 14841474Sjulian */ 14941474Sjulian for (i = 0; i < inosused; i++, inumber++) { 15041474Sjulian if (inumber < ROOTINO) { 15141474Sjulian (void)getnextinode(inumber); 1521558Srgrimes continue; 15341474Sjulian } 1541558Srgrimes checkinode(inumber, &idesc); 1551558Srgrimes } 15641474Sjulian lastino += 1; 15741474Sjulian if (inosused < sblock.fs_ipg || inumber == lastino) 15841474Sjulian continue; 15941474Sjulian /* 16041474Sjulian * If we were not able to determine in advance which inodes 16141474Sjulian * were in use, then reduce the size of the inoinfo structure 16241474Sjulian * to the size necessary to describe the inodes that we 16341474Sjulian * really found. 16441474Sjulian */ 16598542Smckusick if (lastino < (c * sblock.fs_ipg)) 16641474Sjulian inosused = 0; 16798542Smckusick else 16898542Smckusick inosused = lastino - (c * sblock.fs_ipg); 16941474Sjulian inostathead[c].il_numalloced = inosused; 17041474Sjulian if (inosused == 0) { 17141474Sjulian free(inostathead[c].il_stat); 17241474Sjulian inostathead[c].il_stat = 0; 17341474Sjulian continue; 17441474Sjulian } 17541474Sjulian info = calloc((unsigned)inosused, sizeof(struct inostat)); 17641474Sjulian if (info == NULL) 17741474Sjulian pfatal("cannot alloc %u bytes for inoinfo\n", 17841474Sjulian (unsigned)(sizeof(struct inostat) * inosused)); 17941474Sjulian memmove(info, inostathead[c].il_stat, inosused * sizeof(*info)); 18041474Sjulian free(inostathead[c].il_stat); 18141474Sjulian inostathead[c].il_stat = info; 1821558Srgrimes } 1831558Srgrimes freeinodebuf(); 1841558Srgrimes} 1851558Srgrimes 18623675Speterstatic void 18792839Simpcheckinode(ino_t inumber, struct inodesc *idesc) 1881558Srgrimes{ 18998542Smckusick union dinode *dp; 1901558Srgrimes struct zlncnt *zlnp; 19198542Smckusick off_t kernmaxfilesize; 19298542Smckusick ufs2_daddr_t ndb; 1931558Srgrimes mode_t mode; 194103885Smckusick int j, ret, offset; 1951558Srgrimes 1961558Srgrimes dp = getnextinode(inumber); 19798542Smckusick mode = DIP(dp, di_mode) & IFMT; 1981558Srgrimes if (mode == 0) { 19998542Smckusick if ((sblock.fs_magic == FS_UFS1_MAGIC && 20098542Smckusick (memcmp(dp->dp1.di_db, ufs1_zino.di_db, 20198542Smckusick NDADDR * sizeof(ufs1_daddr_t)) || 20298542Smckusick memcmp(dp->dp1.di_ib, ufs1_zino.di_ib, 20398542Smckusick NIADDR * sizeof(ufs1_daddr_t)) || 20498542Smckusick dp->dp1.di_mode || dp->dp1.di_size)) || 20598542Smckusick (sblock.fs_magic == FS_UFS2_MAGIC && 20698542Smckusick (memcmp(dp->dp2.di_db, ufs2_zino.di_db, 20798542Smckusick NDADDR * sizeof(ufs2_daddr_t)) || 20898542Smckusick memcmp(dp->dp2.di_ib, ufs2_zino.di_ib, 20998542Smckusick NIADDR * sizeof(ufs2_daddr_t)) || 21098542Smckusick dp->dp2.di_mode || dp->dp2.di_size))) { 21186514Siedowse pfatal("PARTIALLY ALLOCATED INODE I=%lu", 21286514Siedowse (u_long)inumber); 2131558Srgrimes if (reply("CLEAR") == 1) { 2141558Srgrimes dp = ginode(inumber); 2151558Srgrimes clearinode(dp); 2161558Srgrimes inodirty(); 2171558Srgrimes } 2181558Srgrimes } 21941474Sjulian inoinfo(inumber)->ino_state = USTATE; 2201558Srgrimes return; 2211558Srgrimes } 2221558Srgrimes lastino = inumber; 22371884Siedowse /* This should match the file size limit in ffs_mountfs(). */ 22498888Siedowse if (sblock.fs_magic == FS_UFS1_MAGIC) 22598888Siedowse kernmaxfilesize = (off_t)0x40000000 * sblock.fs_bsize - 1; 22698888Siedowse else 22798888Siedowse kernmaxfilesize = sblock.fs_maxfilesize; 22898542Smckusick if (DIP(dp, di_size) > kernmaxfilesize || 22998542Smckusick DIP(dp, di_size) > sblock.fs_maxfilesize || 23098542Smckusick (mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) { 2311558Srgrimes if (debug) 232101037Smux printf("bad size %ju:", (uintmax_t)DIP(dp, di_size)); 2331558Srgrimes goto unknown; 2341558Srgrimes } 2351558Srgrimes if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { 2361558Srgrimes dp = ginode(inumber); 23798542Smckusick DIP(dp, di_size) = sblock.fs_fsize; 23898542Smckusick DIP(dp, di_mode) = IFREG|0600; 2391558Srgrimes inodirty(); 2401558Srgrimes } 24163003Smckusick if ((mode == IFBLK || mode == IFCHR || mode == IFIFO || 24298542Smckusick mode == IFSOCK) && DIP(dp, di_size) != 0) { 24363003Smckusick if (debug) 244101037Smux printf("bad special-file size %ju:", 245101037Smux (uintmax_t)DIP(dp, di_size)); 24663003Smckusick goto unknown; 24763003Smckusick } 24898542Smckusick if ((mode == IFBLK || mode == IFCHR) && 24998542Smckusick (dev_t)DIP(dp, di_rdev) == NODEV) { 25072525Stegge if (debug) 25172525Stegge printf("bad special-file rdev NODEV:"); 25272525Stegge goto unknown; 25372525Stegge } 25498542Smckusick ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 2551558Srgrimes if (ndb < 0) { 2561558Srgrimes if (debug) 257101037Smux printf("bad size %ju ndb %ju:", 258101037Smux (uintmax_t)DIP(dp, di_size), (uintmax_t)ndb); 2591558Srgrimes goto unknown; 2601558Srgrimes } 2611558Srgrimes if (mode == IFBLK || mode == IFCHR) 2621558Srgrimes ndb++; 2631558Srgrimes if (mode == IFLNK) { 2641558Srgrimes /* 2651558Srgrimes * Fake ndb value so direct/indirect block checks below 2661558Srgrimes * will detect any garbage after symlink string. 2671558Srgrimes */ 26898542Smckusick if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 26998542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 27098542Smckusick ndb = howmany(DIP(dp, di_size), 27198542Smckusick sizeof(ufs1_daddr_t)); 27298542Smckusick else 27398542Smckusick ndb = howmany(DIP(dp, di_size), 27498542Smckusick sizeof(ufs2_daddr_t)); 2751558Srgrimes if (ndb > NDADDR) { 2761558Srgrimes j = ndb - NDADDR; 2771558Srgrimes for (ndb = 1; j > 1; j--) 2781558Srgrimes ndb *= NINDIR(&sblock); 2791558Srgrimes ndb += NDADDR; 2801558Srgrimes } 2811558Srgrimes } 2821558Srgrimes } 28398879Siedowse for (j = ndb; ndb < NDADDR && j < NDADDR; j++) 28498542Smckusick if (DIP(dp, di_db[j]) != 0) { 2851558Srgrimes if (debug) 286101037Smux printf("bad direct addr[%d]: %ju\n", j, 287101037Smux (uintmax_t)DIP(dp, di_db[j])); 2881558Srgrimes goto unknown; 2891558Srgrimes } 2901558Srgrimes for (j = 0, ndb -= NDADDR; ndb > 0; j++) 2911558Srgrimes ndb /= NINDIR(&sblock); 2921558Srgrimes for (; j < NIADDR; j++) 29398542Smckusick if (DIP(dp, di_ib[j]) != 0) { 2941558Srgrimes if (debug) 295101037Smux printf("bad indirect addr: %ju\n", 296101037Smux (uintmax_t)DIP(dp, di_ib[j])); 2971558Srgrimes goto unknown; 2981558Srgrimes } 2991558Srgrimes if (ftypeok(dp) == 0) 3001558Srgrimes goto unknown; 3011558Srgrimes n_files++; 30298542Smckusick inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink); 30398542Smckusick if (DIP(dp, di_nlink) <= 0) { 3041558Srgrimes zlnp = (struct zlncnt *)malloc(sizeof *zlnp); 3051558Srgrimes if (zlnp == NULL) { 3061558Srgrimes pfatal("LINK COUNT TABLE OVERFLOW"); 30734266Sjulian if (reply("CONTINUE") == 0) { 30834266Sjulian ckfini(0); 30923675Speter exit(EEXIT); 31034266Sjulian } 3111558Srgrimes } else { 3121558Srgrimes zlnp->zlncnt = inumber; 3131558Srgrimes zlnp->next = zlnhead; 3141558Srgrimes zlnhead = zlnp; 3151558Srgrimes } 3161558Srgrimes } 3171558Srgrimes if (mode == IFDIR) { 31898542Smckusick if (DIP(dp, di_size) == 0) 31941474Sjulian inoinfo(inumber)->ino_state = DCLEAR; 3201558Srgrimes else 32141474Sjulian inoinfo(inumber)->ino_state = DSTATE; 3221558Srgrimes cacheino(dp, inumber); 32341474Sjulian countdirs++; 3241558Srgrimes } else 32541474Sjulian inoinfo(inumber)->ino_state = FSTATE; 32641474Sjulian inoinfo(inumber)->ino_type = IFTODT(mode); 3271558Srgrimes badblk = dupblk = 0; 3281558Srgrimes idesc->id_number = inumber; 32998542Smckusick if (DIP(dp, di_flags) & SF_SNAPSHOT) 33062668Smckusick idesc->id_type = SNAP; 33162668Smckusick else 33262668Smckusick idesc->id_type = ADDR; 3331558Srgrimes (void)ckinode(dp, idesc); 334103885Smckusick if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) { 335103885Smckusick idesc->id_type = ADDR; 336103885Smckusick ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize); 337103885Smckusick for (j = 0; j < NXADDR; j++) { 338103885Smckusick if (--ndb == 0 && 339103885Smckusick (offset = blkoff(&sblock, dp->dp2.di_extsize)) != 0) 340103885Smckusick idesc->id_numfrags = numfrags(&sblock, 341103885Smckusick fragroundup(&sblock, offset)); 342103885Smckusick else 343103885Smckusick idesc->id_numfrags = sblock.fs_frag; 344103885Smckusick if (dp->dp2.di_extb[j] == 0) 345103885Smckusick continue; 346103885Smckusick idesc->id_blkno = dp->dp2.di_extb[j]; 347103885Smckusick ret = (*idesc->id_func)(idesc); 348103885Smckusick if (ret & STOP) 349103885Smckusick break; 350103885Smckusick } 351103885Smckusick } 352103398Sphk if (sblock.fs_magic == FS_UFS2_MAGIC) 353103398Sphk eascan(idesc, &dp->dp2); 3541558Srgrimes idesc->id_entryno *= btodb(sblock.fs_fsize); 35598542Smckusick if (DIP(dp, di_blocks) != idesc->id_entryno) { 356101037Smux pwarn("INCORRECT BLOCK COUNT I=%lu (%ju should be %ju)", 357101037Smux (u_long)inumber, (uintmax_t)DIP(dp, di_blocks), 358101037Smux (uintmax_t)idesc->id_entryno); 3591558Srgrimes if (preen) 3601558Srgrimes printf(" (CORRECTED)\n"); 3611558Srgrimes else if (reply("CORRECT") == 0) 3621558Srgrimes return; 36374556Smckusick if (bkgrdflag == 0) { 36474556Smckusick dp = ginode(inumber); 36598542Smckusick DIP(dp, di_blocks) = idesc->id_entryno; 36674556Smckusick inodirty(); 36774556Smckusick } else { 36874556Smckusick cmd.value = idesc->id_number; 36998542Smckusick cmd.size = idesc->id_entryno - DIP(dp, di_blocks); 37074556Smckusick if (debug) 371101037Smux printf("adjblkcnt ino %ju amount %lld\n", 372101037Smux (uintmax_t)cmd.value, (long long)cmd.size); 37374556Smckusick if (sysctl(adjblkcnt, MIBSIZE, 0, 0, 37474556Smckusick &cmd, sizeof cmd) == -1) 37574556Smckusick rwerror("ADJUST INODE BLOCK COUNT", cmd.value); 37674556Smckusick } 3771558Srgrimes } 3781558Srgrimes return; 3791558Srgrimesunknown: 38086514Siedowse pfatal("UNKNOWN FILE TYPE I=%lu", (u_long)inumber); 38141474Sjulian inoinfo(inumber)->ino_state = FCLEAR; 3821558Srgrimes if (reply("CLEAR") == 1) { 38341474Sjulian inoinfo(inumber)->ino_state = USTATE; 3841558Srgrimes dp = ginode(inumber); 3851558Srgrimes clearinode(dp); 3861558Srgrimes inodirty(); 3871558Srgrimes } 3881558Srgrimes} 3891558Srgrimes 3907585Sbdeint 39192839Simppass1check(struct inodesc *idesc) 3921558Srgrimes{ 3931558Srgrimes int res = KEEPON; 3941558Srgrimes int anyout, nfrags; 39598542Smckusick ufs2_daddr_t blkno = idesc->id_blkno; 39692806Sobrien struct dups *dlp; 3971558Srgrimes struct dups *new; 3981558Srgrimes 39962668Smckusick if (idesc->id_type == SNAP) { 40062668Smckusick if (blkno == BLK_NOCOPY) 40162668Smckusick return (KEEPON); 40262668Smckusick if (idesc->id_number == cursnapshot) { 40362668Smckusick if (blkno == blkstofrags(&sblock, idesc->id_lbn)) 40462668Smckusick return (KEEPON); 40562668Smckusick if (blkno == BLK_SNAP) { 40662668Smckusick blkno = blkstofrags(&sblock, idesc->id_lbn); 40762668Smckusick idesc->id_entryno -= idesc->id_numfrags; 40862668Smckusick } 40962668Smckusick } else { 41062668Smckusick if (blkno == BLK_SNAP) 41162668Smckusick return (KEEPON); 41262668Smckusick } 41362668Smckusick } 4141558Srgrimes if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { 4151558Srgrimes blkerror(idesc->id_number, "BAD", blkno); 4161558Srgrimes if (badblk++ >= MAXBAD) { 4171558Srgrimes pwarn("EXCESSIVE BAD BLKS I=%lu", 41886514Siedowse (u_long)idesc->id_number); 4191558Srgrimes if (preen) 4201558Srgrimes printf(" (SKIPPING)\n"); 42134266Sjulian else if (reply("CONTINUE") == 0) { 42234266Sjulian ckfini(0); 42323675Speter exit(EEXIT); 42434266Sjulian } 4251558Srgrimes return (STOP); 4261558Srgrimes } 4271558Srgrimes } 4281558Srgrimes for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { 4291558Srgrimes if (anyout && chkrange(blkno, 1)) { 4301558Srgrimes res = SKIP; 4311558Srgrimes } else if (!testbmap(blkno)) { 4321558Srgrimes n_blks++; 4331558Srgrimes setbmap(blkno); 4341558Srgrimes } else { 4351558Srgrimes blkerror(idesc->id_number, "DUP", blkno); 4361558Srgrimes if (dupblk++ >= MAXDUP) { 4371558Srgrimes pwarn("EXCESSIVE DUP BLKS I=%lu", 43886514Siedowse (u_long)idesc->id_number); 4391558Srgrimes if (preen) 4401558Srgrimes printf(" (SKIPPING)\n"); 44134266Sjulian else if (reply("CONTINUE") == 0) { 44234266Sjulian ckfini(0); 44323675Speter exit(EEXIT); 44434266Sjulian } 4451558Srgrimes return (STOP); 4461558Srgrimes } 4471558Srgrimes new = (struct dups *)malloc(sizeof(struct dups)); 4481558Srgrimes if (new == NULL) { 4491558Srgrimes pfatal("DUP TABLE OVERFLOW."); 45034266Sjulian if (reply("CONTINUE") == 0) { 45134266Sjulian ckfini(0); 45223675Speter exit(EEXIT); 45334266Sjulian } 4541558Srgrimes return (STOP); 4551558Srgrimes } 4561558Srgrimes new->dup = blkno; 4571558Srgrimes if (muldup == 0) { 4581558Srgrimes duplist = muldup = new; 4591558Srgrimes new->next = 0; 4601558Srgrimes } else { 4611558Srgrimes new->next = muldup->next; 4621558Srgrimes muldup->next = new; 4631558Srgrimes } 4641558Srgrimes for (dlp = duplist; dlp != muldup; dlp = dlp->next) 4651558Srgrimes if (dlp->dup == blkno) 4661558Srgrimes break; 4671558Srgrimes if (dlp == muldup && dlp->dup != blkno) 4681558Srgrimes muldup = new; 4691558Srgrimes } 4701558Srgrimes /* 4711558Srgrimes * count the number of blocks found in id_entryno 4721558Srgrimes */ 4731558Srgrimes idesc->id_entryno++; 4741558Srgrimes } 4751558Srgrimes return (res); 4761558Srgrimes} 477