speed-ups and clean-ups
[unix-history] / usr / src / sbin / icheck / icheck.c
index d1e8f2c..8d8574a 100644 (file)
@@ -1,40 +1,44 @@
-static char *sccsid = "@(#)icheck.c    1.2 (Berkeley) %G%";
+static char *sccsid = "@(#)icheck.c    2.4 (Berkeley) %G%";
+
 /*
  * icheck
  */
 #define        NB      500
 /*
  * icheck
  */
 #define        NB      500
-#define        BITS    8
 #define        MAXFN   500
 #define        MAXFN   500
+#define        MAXNINDIR       (MAXBSIZE / sizeof (daddr_t))
 
 #ifndef STANDALONE
 #include <stdio.h>
 #endif
 
 #ifndef STANDALONE
 #include <stdio.h>
 #endif
+#ifndef SIMFS
+#include <sys/param.h>
+#include <sys/inode.h>
+#include <sys/fs.h>
+#else
 #include "../h/param.h"
 #include "../h/inode.h"
 #include "../h/fs.h"
 #include "../h/param.h"
 #include "../h/inode.h"
 #include "../h/fs.h"
-
-#define        setbit(a, i)    ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
-#define        clrbit(a, i)    ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
-#define        isset(a,i)      ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
+#endif
 
 union {
        struct  fs sb;
 
 union {
        struct  fs sb;
-       char pad[BSIZE];
+       char pad[MAXBSIZE];
 } sbun;
 #define        sblock sbun.sb
 
 union {
        struct  cg cg;
 } sbun;
 #define        sblock sbun.sb
 
 union {
        struct  cg cg;
-       char pad[BSIZE];
+       char pad[MAXBSIZE];
 } cgun;
 #define        cgrp cgun.cg
 
 struct dinode  itab[MAXIPG];
 daddr_t        blist[NB];
 } cgun;
 #define        cgrp cgun.cg
 
 struct dinode  itab[MAXIPG];
 daddr_t        blist[NB];
+daddr_t        fsblist[NB];
 char   *bmap;
 
 char   *bmap;
 
-int    sflg;
 int    mflg;
 int    mflg;
+int    sflg;
 int    dflg;
 int    fi;
 ino_t  ino;
 int    dflg;
 int    fi;
 ino_t  ino;
@@ -44,31 +48,32 @@ ino_t       nrfile;
 ino_t  ndfile;
 ino_t  nbfile;
 ino_t  ncfile;
 ino_t  ndfile;
 ino_t  nbfile;
 ino_t  ncfile;
-ino_t  nmcfile;
+ino_t  nlfile;
 
 daddr_t        nblock;
 daddr_t        nfrag;
 
 daddr_t        nblock;
 daddr_t        nfrag;
-long   szfrag;
 daddr_t        nindir;
 daddr_t        nindir;
-long   szindir;
 daddr_t        niindir;
 
 daddr_t        nffree;
 daddr_t        niindir;
 
 daddr_t        nffree;
-long   szffree;
 daddr_t        nbfree;
 
 daddr_t        ndup;
 
 int    nerror;
 
 daddr_t        nbfree;
 
 daddr_t        ndup;
 
 int    nerror;
 
+extern int inside[], around[];
+extern unsigned char *fragtbl[];
+
 long   atol();
 long   atol();
-daddr_t        alloc();
 #ifndef STANDALONE
 char   *malloc();
 #ifndef STANDALONE
 char   *malloc();
+char   *calloc();
 #endif
 
 main(argc, argv)
 #endif
 
 main(argc, argv)
-char *argv[];
+       int argc;
+       char *argv[];
 {
        register i;
        long n;
 {
        register i;
        long n;
@@ -121,15 +126,16 @@ char *argv[];
 }
 
 check(file)
 }
 
 check(file)
-char *file;
+       char *file;
 {
        register i, j, c;
        daddr_t d, cgd, cbase, b;
        long n;
 {
        register i, j, c;
        daddr_t d, cgd, cbase, b;
        long n;
+       char buf[BUFSIZ];
 
 
-       fi = open(file, sflg?2:0);
+       fi = open(file, sflg ? 2 : 0);
        if (fi < 0) {
        if (fi < 0) {
-               printf("cannot open %s\n", file);
+               perror(file);
                nerror |= 04;
                return;
        }
                nerror |= 04;
                return;
        }
@@ -138,31 +144,24 @@ char *file;
        ndfile = 0;
        ncfile = 0;
        nbfile = 0;
        ndfile = 0;
        ncfile = 0;
        nbfile = 0;
-       nmcfile = 0;
+       nlfile = 0;
 
        nblock = 0;
        nfrag = 0;
 
        nblock = 0;
        nfrag = 0;
-       szfrag = 0;
        nindir = 0;
        nindir = 0;
-       szindir = 0;
        niindir = 0;
 
        ndup = 0;
 #ifndef STANDALONE
        sync();
 #endif
        niindir = 0;
 
        ndup = 0;
 #ifndef STANDALONE
        sync();
 #endif
-       bread(SBLOCK, (char *)&sblock, BSIZE);
-       if (sblock.fs_magic != FS_MAGIC) {
-               printf("%s: bad magic number\n", file);
-               nerror |= 04;
+       getsb(&sblock, file);
+       if (nerror)
                return;
                return;
-       }
-       sblock.fs_cs =
-           (struct csum *)calloc(howmany(cssize(&sblock), BSIZE), BSIZE);
-       lseek(fi, csaddr(&sblock)*FSIZE, 0);
-       read(fi, (char *)sblock.fs_cs, cssize(&sblock));
+       for (n=0; blist[n] != -1; n++)
+               fsblist[n] = dbtofsb(&sblock, blist[n]);
        ino = 0;
        ino = 0;
-       n = (sblock.fs_size*FRAG + BITS-1) / BITS;
+       n = roundup(howmany(sblock.fs_size, NBBY), sizeof(short));
 #ifdef STANDALONE
        bmap = NULL;
 #else
 #ifdef STANDALONE
        bmap = NULL;
 #else
@@ -171,35 +170,49 @@ char *file;
        if (bmap==NULL) {
                printf("Not enough core; duplicates unchecked\n");
                dflg++;
        if (bmap==NULL) {
                printf("Not enough core; duplicates unchecked\n");
                dflg++;
-               sflg = 0;
+               if (sflg) {
+                       printf("No Updates\n");
+                       sflg = 0;
+               }
        }
        ino = 0;
        cginit = 1;
        }
        ino = 0;
        cginit = 1;
-       if(!dflg) {
-               for (i=0; i<(unsigned)n; i++)
+       if (!dflg) {
+               for (i = 0; i < (unsigned)n; i++)
                        bmap[i] = 0;
                        bmap[i] = 0;
-               for (c=0; c < sblock.fs_ncg; c++) {
-                       cgd = cgtod(c, &sblock);
-                       for (d = cgbase(c, &sblock); d < cgd; d++)
-                               chk(d, "badcg");
-                       d = cgimin(c, &sblock);
+               for (c = 0; c < sblock.fs_ncg; c++) {
+                       cgd = cgtod(&sblock, c);
+                       if (c == 0)
+                               d = cgbase(&sblock, c);
+                       else
+                               d = cgsblock(&sblock, c);
+                       sprintf(buf, "spare super block %d", c);
+                       for (; d < cgd; d += sblock.fs_frag)
+                               chk(d, buf, sblock.fs_bsize);
+                       d = cgimin(&sblock, c);
+                       sprintf(buf, "cylinder group %d", c);
                        while (cgd < d) {
                        while (cgd < d) {
-                               chk(cgd, "cg");
-                               cgd++;
+                               chk(cgd, buf, sblock.fs_bsize);
+                               cgd += sblock.fs_frag;
+                       }
+                       d = cgdmin(&sblock, c);
+                       i = INOPB(&sblock);
+                       for (; cgd < d; cgd += sblock.fs_frag) {
+                               sprintf(buf, "inodes %d-%d", ino, ino + i);
+                               chk(cgd, buf, sblock.fs_bsize);
+                               ino += i;
                        }
                        }
-                       d = cgdmin(c, &sblock);
-                       for (; cgd < d; cgd++)
-                               chk(cgd, "inode");
                        if (c == 0) {
                        if (c == 0) {
-                               d += howmany(cssize(&sblock), BSIZE) * FRAG;
+                               d += howmany(sblock.fs_cssize, sblock.fs_fsize);
                                for (; cgd < d; cgd++)
                                for (; cgd < d; cgd++)
-                                       chk(cgd, "csum");
+                                       chk(cgd, "csum", sblock.fs_fsize);
                        }
                }
        }
                        }
                }
        }
+       ino = 0;
        cginit = 0;
        for (c = 0; c < sblock.fs_ncg; c++) {
        cginit = 0;
        for (c = 0; c < sblock.fs_ncg; c++) {
-               bread(cgimin(c,&sblock), (char *)itab,
+               bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
                    sblock.fs_ipg * sizeof (struct dinode));
                for (j=0; j < sblock.fs_ipg; j++) {
                        pass1(&itab[j]);
                    sblock.fs_ipg * sizeof (struct dinode));
                for (j=0; j < sblock.fs_ipg; j++) {
                        pass1(&itab[j]);
@@ -210,7 +223,6 @@ char *file;
 #ifndef STANDALONE
        sync();
 #endif
 #ifndef STANDALONE
        sync();
 #endif
-       bread(SBLOCK, (char *)&sblock, sizeof(sblock));
        if (sflg) {
                makecg();
                close(fi);
        if (sflg) {
                makecg();
                close(fi);
@@ -221,22 +233,23 @@ char *file;
                return;
        }
        nffree = 0;
                return;
        }
        nffree = 0;
-       szffree = 0;
        nbfree = 0;
        for (c = 0; c < sblock.fs_ncg; c++) {
        nbfree = 0;
        for (c = 0; c < sblock.fs_ncg; c++) {
-               cbase = cgbase(c,&sblock);
-               bread(cgtod(c,&sblock), (char *)&cgrp, sblock.fs_cgsize);
-               for (b = 0; b < sblock.fs_fpg; b += FRAG) {
-                       if (isblock(cgrp.cg_free, b / FRAG)) {
+               cbase = cgbase(&sblock, c);
+               bread(fsbtodb(&sblock, cgtod(&sblock, c)), (char *)&cgrp,
+                       sblock.fs_cgsize);
+               if (cgrp.cg_magic != CG_MAGIC)
+                       printf("cg %d: bad magic number\n", c);
+               for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
+                       if (isblock(&sblock, cgrp.cg_free,
+                           b / sblock.fs_frag)) {
                                nbfree++;
                                nbfree++;
-                               for (d = 0; d < FRAG; d++)
-                                       chk(cbase+b+d, "block");
+                               chk(cbase+b, "free block", sblock.fs_bsize);
                        } else {
                        } else {
-                               for (d = 0; d < FRAG; d++)
+                               for (d = 0; d < sblock.fs_frag; d++)
                                        if (isset(cgrp.cg_free, b+d)) {
                                        if (isset(cgrp.cg_free, b+d)) {
-                                               chk(cbase+b+d, "frag");
+                                               chk(cbase+b+d, "free frag", sblock.fs_fsize);
                                                nffree++;
                                                nffree++;
-                                               szffree++;
                                        }
                        }
                }
                                        }
                        }
                }
@@ -247,30 +260,30 @@ char *file;
                free(bmap);
 #endif
 
                free(bmap);
 #endif
 
-       i = nrfile + ndfile + ncfile + nbfile + nmcfile;
+       i = nrfile + ndfile + ncfile + nbfile + nlfile;
 #ifndef STANDALONE
 #ifndef STANDALONE
-       printf("files %6u (r=%u,d=%u,b=%u,c=%u,mc=%u)\n",
-               i, nrfile, ndfile, nbfile, ncfile, nmcfile);
+       printf("files %6u (r=%u,d=%u,b=%u,c=%u,sl=%u)\n",
+               i, nrfile, ndfile, nbfile, ncfile, nlfile);
 #else
 #else
-       printf("files %u (r=%u,d=%u,b=%u,c=%u,mc=%u)\n",
-               i, nrfile, ndfile, nbfile, ncfile, nmcfile);
+       printf("files %u (r=%u,d=%u,b=%u,c=%u,sl=%u)\n",
+               i, nrfile, ndfile, nbfile, ncfile, nlfile);
 #endif
 #endif
-       n = (nblock + niindir) * FRAG + szfrag + szindir;
+       n = (nblock + nindir + niindir) * sblock.fs_frag + nfrag;
 #ifdef STANDALONE
        printf("used %ld (i=%ld,ii=%ld,b=%ld,f=%ld)\n",
                n, nindir, niindir, nblock, nfrag);
 #ifdef STANDALONE
        printf("used %ld (i=%ld,ii=%ld,b=%ld,f=%ld)\n",
                n, nindir, niindir, nblock, nfrag);
-       printf("free %ld (b=%ld,f=%ld)\n", szffree + FRAG * nbfree,
+       printf("free %ld (b=%ld,f=%ld)\n", nffree + sblock.fs_frag * nbfree,
            nbfree, nffree);
 #else
        printf("used %7ld (i=%ld,ii=%ld,b=%ld,f=%ld)\n",
                n, nindir, niindir, nblock, nfrag);
            nbfree, nffree);
 #else
        printf("used %7ld (i=%ld,ii=%ld,b=%ld,f=%ld)\n",
                n, nindir, niindir, nblock, nfrag);
-       printf("free %7ld (b=%ld,f=%ld)\n", szffree + FRAG * nbfree,
+       printf("free %7ld (b=%ld,f=%ld)\n", nffree + sblock.fs_frag * nbfree,
            nbfree, nffree);
 #endif
        if(!dflg) {
                n = 0;
            nbfree, nffree);
 #endif
        if(!dflg) {
                n = 0;
-               for(d=0; d<sblock.fs_size; d++)
-                       if(!duped(d)) {
+               for (d = 0; d < sblock.fs_size; d++)
+                       if(!duped(d, sblock.fs_fsize)) {
                                if(mflg)
                                        printf("%ld missing\n", d);
                                n++;
                                if(mflg)
                                        printf("%ld missing\n", d);
                                n++;
@@ -280,18 +293,18 @@ char *file;
 }
 
 pass1(ip)
 }
 
 pass1(ip)
-register struct dinode *ip;
+       register struct dinode *ip;
 {
 {
-       daddr_t ind1[NINDIR];
-       daddr_t ind2[NINDIR];
-       register i, j;
-       int k, l, sz, ni, nib, ndb;
+       daddr_t ind1[MAXNINDIR];
+       daddr_t ind2[MAXNINDIR];
+       daddr_t db, ib;
+       register int i, j, k, siz;
+       int lbn;
+       char buf[BUFSIZ];
 
        i = ip->di_mode & IFMT;
 
        i = ip->di_mode & IFMT;
-       if(i == 0) {
-               sblock.fs_nifree++;
+       if(i == 0)
                return;
                return;
-       }
        switch (i) {
        case IFCHR:
                ncfile++;
        switch (i) {
        case IFCHR:
                ncfile++;
@@ -305,228 +318,549 @@ register struct dinode *ip;
        case IFREG:
                nrfile++;
                break;
        case IFREG:
                nrfile++;
                break;
+       case IFLNK:
+               nlfile++;
+               break;
        default:
                printf("bad mode %u\n", ino);
                return;
        }
        default:
                printf("bad mode %u\n", ino);
                return;
        }
-       ndb = howmany(ip->di_size, BSIZE)-1;
-       for(i=0; i<NDADDR; i++) {
-               if(ip->di_db[i] == 0)
+       for (i = 0; i < NDADDR; i++) {
+               db = ip->di_db[i];
+               if (db == 0)
                        continue;
                        continue;
-               if (i==ndb && (ip->di_size&BMASK)) {
-                       sz = howmany(ip->di_size - i * BSIZE, FSIZE);
-                       for (l = 0; l < sz; l++)
-                               chk(ip->di_db[i]+l, "data (frag)");
-                       szfrag += sz;
-                       nfrag++;
-               } else {
-                       for (l = 0; l < FRAG; l++)
-                               chk(ip->di_db[i]+l, "data (block)");
+               siz = dblksize(&sblock, ip, i);
+               sprintf(buf, "logical data block %d", i);
+               chk(db, buf, siz);
+               if (siz == sblock.fs_bsize)
                        nblock++;
                        nblock++;
-               }
+               else
+                       nfrag += howmany(siz, sblock.fs_fsize);
        }
        }
-       for(i=NDADDR; i<NDADDR+NIADDR;i++) {
-               if(ip->di_ib[i] == 0)
+       for(i = 0; i < NIADDR; i++) {
+               ib = ip->di_ib[i];
+               if (ib == 0)
                        continue;
                        continue;
+               if (chk(ib, "1st indirect", sblock.fs_bsize))
+                       continue;
+               bread(fsbtodb(&sblock, ib), (char *)ind1, sblock.fs_bsize);
                nindir++;
                nindir++;
-               if (i==NDADDR) {
-                       sz = howmany((ip->di_size-NDADDR*BSIZE),
-                           (NINDIR/FRAG) * BSIZE);
-                       if (sz > FRAG)
-                               sz = FRAG;
-               } else
-                       sz = FRAG;
-               for (j = 0; j < FRAG; j++)
-                       if (chk(ip->di_ib[i]+j, "1st indirect"))
-                               continue;
-               bread(ip->di_ib[i], (char *)ind1, sz*FSIZE);
-               nib = sz * (NINDIR/FRAG);
-               for(j=0; j<nib; j++) {
-                       if(ind1[j] == 0)
+               for (j = 0; j < NINDIR(&sblock); j++) {
+                       ib = ind1[j];
+                       if (ib == 0)
                                continue;
                                continue;
-                       if(i == NDADDR) {
-                               for (l = 0; l < FRAG; l++)
-                                       chk(ind1[j]+l, "data (large)");
-                               nblock++;
+                       if (i == 0) {
+                               lbn = NDADDR + j;
+                               siz = dblksize(&sblock, ip, lbn);
+                               sprintf(buf, "logical data block %d", lbn);
+                               chk(ib, buf, siz);
+                               if (siz == sblock.fs_bsize)
+                                       nblock++;
+                               else
+                                       nfrag += howmany(siz, sblock.fs_fsize);
                                continue;
                        }
                                continue;
                        }
+                       if (chk(ib, "2nd indirect", sblock.fs_bsize))
+                               continue;
+                       bread(fsbtodb(&sblock, ib), (char *)ind2,
+                               sblock.fs_bsize);
                        niindir++;
                        niindir++;
-                       for (l = 0; l < FRAG; l++)
-                               if(chk(ind1[j], "2nd indirect"))
-                                       goto skip;
-                       bread(ind1[j], (char *)ind2, BSIZE);
-                       for(k=0; k<NINDIR; k++) {
-                               if(ind2[k] == 0)
+                       for (k = 0; k < NINDIR(&sblock); k++) {
+                               ib = ind2[k];
+                               if (ib == 0)
                                        continue;
                                        continue;
-                               for (l = 0; l < FRAG; l++)
-                                       chk(ind1[j]+l, "data (huge)");
-                               nblock++;
-                               continue;
+                               lbn = NDADDR + NINDIR(&sblock) * (i + j) + k;
+                               siz = dblksize(&sblock, ip, lbn);
+                               sprintf(buf, "logical data block %d", lbn);
+                               chk(ib, buf, siz);
+                               if (siz == sblock.fs_bsize)
+                                       nblock++;
+                               else
+                                       nfrag += howmany(siz, sblock.fs_fsize);
                        }
                        }
-skip:
-                       ;
                }
        }
 }
 
                }
        }
 }
 
-chk(bno, s)
-daddr_t bno;
-char *s;
+chk(bno, s, size)
+       daddr_t bno;
+       char *s;
+       int size;
 {
        register n, cg;
 {
        register n, cg;
+       int frags;
 
 
-       cg = dtog(bno, &sblock);
-       if (cginit==0 && bno<cgdmin(cg,&sblock) || bno>=FRAG*sblock.fs_size) {
+       cg = dtog(&sblock, bno);
+       if (cginit == 0 && bno >= sblock.fs_frag * sblock.fs_size) {
                printf("%ld bad; inode=%u, class=%s\n", bno, ino, s);
                return(1);
        }
                printf("%ld bad; inode=%u, class=%s\n", bno, ino, s);
                return(1);
        }
-       if (duped(bno)) {
-               printf("%ld dup; inode=%u, class=%s\n", bno, ino, s);
-               ndup++;
+       frags = numfrags(&sblock, size);
+       if (frags == sblock.fs_frag) {
+               if (duped(bno, size)) {
+                       printf("%ld dup block; inode=%u, class=%s\n",
+                           bno, ino, s);
+                       ndup += sblock.fs_frag;
+               }
+       } else {
+               for (n = 0; n < frags; n++) {
+                       if (duped(bno + n, sblock.fs_fsize)) {
+                               printf("%ld dup frag; inode=%u, class=%s\n",
+                                   bno, ino, s);
+                               ndup++;
+                       }
+               }
        }
        for (n=0; blist[n] != -1; n++)
        }
        for (n=0; blist[n] != -1; n++)
-               if (bno == blist[n])
-                       printf("%ld arg; inode=%u, class=%s\n", bno, ino, s);
+               if (fsblist[n] >= bno && fsblist[n] < bno + frags)
+                       printf("%ld arg; frag %d of %d, inode=%u, class=%s\n",
+                               blist[n], fsblist[n] - bno, frags, ino, s);
        return(0);
 }
 
        return(0);
 }
 
-duped(bno)
-daddr_t bno;
+duped(bno, size)
+       daddr_t bno;
+       int size;
 {
 {
-       daddr_t d;
-       register m, n;
-
        if(dflg)
                return(0);
        if(dflg)
                return(0);
-       m = 1 << (bno%BITS);
-       n = (bno/BITS);
-       if(bmap[n] & m)
-               return(1);
-       bmap[n] |= m;
-       return(0);
-}
-
-bread(bno, buf, cnt)
-daddr_t bno;
-char *buf;
-{
-       register i;
-
-       lseek(fi, bno*FSIZE, 0);
-       if ((i = read(fi, buf, cnt)) != cnt) {
-               if (sflg) {
-                       printf("No update\n");
-                       sflg = 0;
-               }
-               for(i=0; i<BSIZE; i++)
-                       buf[i] = 0;
+       if (size != sblock.fs_fsize && size != sblock.fs_bsize)
+               printf("bad size %d to duped\n", size);
+       if (size == sblock.fs_fsize) {
+               if (isset(bmap, bno))
+                       return(1);
+               setbit(bmap, bno);
+               return (0);
        }
        }
-}
-
-bwrite(bno, buf, cnt)
-daddr_t bno;
-char *buf;
-{
-       register i;
-
-       lseek(fi, bno*FSIZE, 0);
-       if (write(fi, buf, cnt) != cnt)
-               printf("write error %d\n", tell(fi)/BSIZE);
+       if (bno % sblock.fs_frag != 0)
+               printf("bad bno %d to duped\n", bno);
+       if (isblock(&sblock, bmap, bno/sblock.fs_frag))
+               return (1);
+       setblock(&sblock, bmap, bno/sblock.fs_frag);
+       return(0);
 }
 
 makecg()
 {
 }
 
 makecg()
 {
-       int c;
-       daddr_t dbase, d, dmin, dmax;
+       int c, blk;
+       daddr_t dbase, d, dlower, dupper, dmax;
        long i, j, s;
        register struct csum *cs;
        long i, j, s;
        register struct csum *cs;
+       register struct dinode *dp;
 
 
-       sblock.fs_nbfree = 0;
-       sblock.fs_nffree = 0;
+       sblock.fs_cstotal.cs_nbfree = 0;
+       sblock.fs_cstotal.cs_nffree = 0;
+       sblock.fs_cstotal.cs_nifree = 0;
+       sblock.fs_cstotal.cs_ndir = 0;
        for (c = 0; c < sblock.fs_ncg; c++) {
        for (c = 0; c < sblock.fs_ncg; c++) {
-               bread(cgimin(c,&sblock), (char *)itab,
-                   sblock.fs_ipg * sizeof (struct dinode));
-               dbase = cgbase(c, &sblock);
+               dbase = cgbase(&sblock, c);
                dmax = dbase + sblock.fs_fpg;
                dmax = dbase + sblock.fs_fpg;
-               if (dmax > sblock.fs_size)
-                       dmax = sblock.fs_size;
-               cs = &sblock.fs_cs[c];
+               if (dmax > sblock.fs_size) {
+                       for ( ; dmax >= sblock.fs_size; dmax--)
+                               clrbit(cgrp.cg_free, dmax - dbase);
+                       dmax++;
+               }
+               dlower = cgsblock(&sblock, c) - dbase;
+               dupper = cgdmin(&sblock, c) - dbase;
+               cs = &sblock.fs_cs(&sblock, c);
                cgrp.cg_time = time(0);
                cgrp.cg_magic = CG_MAGIC;
                cgrp.cg_cgx = c;
                cgrp.cg_time = time(0);
                cgrp.cg_magic = CG_MAGIC;
                cgrp.cg_cgx = c;
-               cgrp.cg_ncyl = sblock.fs_cpg;
+               if (c == sblock.fs_ncg - 1)
+                       cgrp.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
+               else
+                       cgrp.cg_ncyl = sblock.fs_cpg;
                cgrp.cg_niblk = sblock.fs_ipg;
                cgrp.cg_ndblk = dmax - dbase;
                cgrp.cg_niblk = sblock.fs_ipg;
                cgrp.cg_ndblk = dmax - dbase;
-               cgrp.cg_ndir = 0;
-               cgrp.cg_nffree = 0;
-               cgrp.cg_nbfree = 0;
-               cgrp.cg_nifree = 0;
-               for (i = 0; i < sblock.fs_ipg; i++)
-               switch (itab[i].di_mode&IFMT) {
-
-               case 0:
-                       cgrp.cg_nifree++;
+               cgrp.cg_cs.cs_ndir = 0;
+               cgrp.cg_cs.cs_nffree = 0;
+               cgrp.cg_cs.cs_nbfree = 0;
+               cgrp.cg_cs.cs_nifree = 0;
+               cgrp.cg_rotor = 0;
+               cgrp.cg_frotor = 0;
+               cgrp.cg_irotor = 0;
+               for (i = 0; i < sblock.fs_frag; i++)
+                       cgrp.cg_frsum[i] = 0;
+               bread(fsbtodb(&sblock, cgimin(&sblock, c)), (char *)itab,
+                     sblock.fs_ipg * sizeof(struct dinode));
+               for (i = 0; i < sblock.fs_ipg; i++) {
+                       cgrp.cg_cs.cs_nifree++;
                        clrbit(cgrp.cg_iused, i);
                        clrbit(cgrp.cg_iused, i);
-                       continue;
-
-               case IFDIR:
-                       cgrp.cg_ndir++;
-                       /* fall into ... */
-
-               default:
-                       setbit(cgrp.cg_iused, i);
-                       continue;
+                       dp = &itab[i];
+                       if ((dp->di_mode & IFMT) != 0) {
+                               if ((dp->di_mode & IFMT) == IFDIR)
+                                       cgrp.cg_cs.cs_ndir++;
+                               cgrp.cg_cs.cs_nifree--;
+                               setbit(cgrp.cg_iused, i);
+                               continue;
+                       }
                }
                while (i < MAXIPG) {
                        clrbit(cgrp.cg_iused, i);
                        i++;
                }
                }
                while (i < MAXIPG) {
                        clrbit(cgrp.cg_iused, i);
                        i++;
                }
-               for (s = 0; s < MAXCPG; s++)
+               if (c == 0)
+                       for (i = 0; i < ROOTINO; i++) {
+                               setbit(cgrp.cg_iused, i);
+                               cgrp.cg_cs.cs_nifree--;
+                       }
+               for (s = 0; s < MAXCPG; s++) {
+                       cgrp.cg_btot[s] = 0;
                        for (i = 0; i < NRPOS; i++)
                                cgrp.cg_b[s][i] = 0;
                        for (i = 0; i < NRPOS; i++)
                                cgrp.cg_b[s][i] = 0;
-               dmin = cgdmin(c, &sblock) - dbase;
-               if (c == 0)
-                       dmin += howmany(cssize(&sblock), BSIZE) * FRAG;
-               for (d = 0; d < dmin; d++)
+               }
+               if (c == 0) {
+                       dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
+               }
+               for (d = dlower; d < dupper; d++)
                        clrbit(cgrp.cg_free, d);
                        clrbit(cgrp.cg_free, d);
-#define        getbmap(i) isset(bmap, i)
-               for (; (d + FRAG) <= dmax - dbase; d += FRAG) {
+               for (d = 0; (d + sblock.fs_frag) <= dmax - dbase;
+                   d += sblock.fs_frag) {
                        j = 0;
                        j = 0;
-                       for (i = 0; i < FRAG; i++) {
-                               if (!getbmap(dbase+d+i)) {
-                                       setbit(cgrp.cg_free, d+i);
+                       for (i = 0; i < sblock.fs_frag; i++) {
+                               if (!isset(bmap, dbase + d + i)) {
+                                       setbit(cgrp.cg_free, d + i);
                                        j++;
                                } else
                                        clrbit(cgrp.cg_free, d+i);
                        }
                                        j++;
                                } else
                                        clrbit(cgrp.cg_free, d+i);
                        }
-                       if (j == FRAG) {
-                               cgrp.cg_nbfree++;
-                               s = d * NSPF;
-                               cgrp.cg_b[s/sblock.fs_spc]
-                                 [s%sblock.fs_nsect*NRPOS/sblock.fs_nsect]++;
-                       } else
-                               cgrp.cg_nffree += j;
+                       if (j == sblock.fs_frag) {
+                               cgrp.cg_cs.cs_nbfree++;
+                               cgrp.cg_btot[cbtocylno(&sblock, d)]++;
+                               cgrp.cg_b[cbtocylno(&sblock, d)]
+                                   [cbtorpos(&sblock, d)]++;
+                       } else if (j > 0) {
+                               cgrp.cg_cs.cs_nffree += j;
+                               blk = blkmap(&sblock, cgrp.cg_free, d);
+                               fragacct(&sblock, blk, cgrp.cg_frsum, 1);
+                       }
                }
                }
-               for (; d < dmax - dbase; d++) {
-                       if (!getbmap(dbase+d)) {
+               for (j = d; d < dmax - dbase; d++) {
+                       if (!isset(bmap, dbase + d)) {
                                setbit(cgrp.cg_free, d);
                                setbit(cgrp.cg_free, d);
-                               cgrp.cg_nffree++;
+                               cgrp.cg_cs.cs_nffree++;
                        } else
                                clrbit(cgrp.cg_free, d);
                }
                        } else
                                clrbit(cgrp.cg_free, d);
                }
-               for (; d < MAXBPG; d++)
+               for (; d % sblock.fs_frag != 0; d++)
                        clrbit(cgrp.cg_free, d);
                        clrbit(cgrp.cg_free, d);
-               sblock.fs_nffree += cgrp.cg_nffree;
-               sblock.fs_nbfree += cgrp.cg_nbfree;
-               cs->cs_ndir = cgrp.cg_ndir;
-               cs->cs_nifree = cgrp.cg_nifree;
-               cs->cs_nbfree = cgrp.cg_nbfree;
-               bwrite(cgtod(c, &sblock), (char *)&cgrp, sblock.fs_cgsize);
+               if (j != d) {
+                       blk = blkmap(&sblock, cgrp.cg_free, j);
+                       fragacct(&sblock, blk, cgrp.cg_frsum, 1);
+               }
+               for (d /= sblock.fs_frag; d < MAXBPG(&sblock); d ++)
+                       clrblock(&sblock, cgrp.cg_free, d);
+               sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree;
+               sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree;
+               sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
+               sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
+               *cs = cgrp.cg_cs;
+               bwrite(fsbtodb(&sblock, cgtod(&sblock, c)), &cgrp,
+                       sblock.fs_cgsize);
+       }
+       for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
+               bwrite(fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
+                   (char *)sblock.fs_csp[j],
+                   sblock.fs_cssize - i < sblock.fs_bsize ?
+                   sblock.fs_cssize - i : sblock.fs_bsize);
        }
        sblock.fs_ronly = 0;
        sblock.fs_fmod = 0;
        }
        sblock.fs_ronly = 0;
        sblock.fs_fmod = 0;
-       bwrite(SBLOCK, (char *)&sblock, sizeof (sblock));
-       lseek(fi, csaddr(&sblock)*FSIZE, 0);
-       if (write(fi,(char *)sblock.fs_cs,cssize(&sblock)) != cssize(&sblock))
-               printf("write error %d\n", tell(fi)/BSIZE);
+       bwrite(SBLOCK, (char *)&sblock, SBSIZE);
+}
+
+/*
+ * update the frsum fields to reflect addition or deletion 
+ * of some frags
+ */
+fragacct(fs, fragmap, fraglist, cnt)
+       struct fs *fs;
+       int fragmap;
+       long fraglist[];
+       int cnt;
+{
+       int inblk;
+       register int field, subfield;
+       register int siz, pos;
+
+       inblk = (int)(fragtbl[fs->fs_frag][fragmap] << 1);
+       fragmap <<= 1;
+       for (siz = 1; siz < fs->fs_frag; siz++) {
+               if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
+                       continue;
+               field = around[siz];
+               subfield = inside[siz];
+               for (pos = siz; pos <= fs->fs_frag; pos++) {
+                       if ((fragmap & field) == subfield) {
+                               fraglist[siz] += cnt;
+                               pos += siz;
+                               field <<= siz;
+                               subfield <<= siz;
+                       }
+                       field <<= 1;
+                       subfield <<= 1;
+               }
+       }
 }
 }
+
+getsb(fs, file)
+       register struct fs *fs;
+       char *file;
+{
+       int i, j, size;
+
+       if (bread(SBLOCK, fs, SBSIZE)) {
+               printf("bad super block");
+               perror(file);
+               nerror |= 04;
+               return;
+       }
+       if (fs->fs_magic != FS_MAGIC) {
+               printf("%s: bad magic number\n", file);
+               nerror |= 04;
+               return;
+       }
+       for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
+               size = sblock.fs_cssize - i < sblock.fs_bsize ?
+                   sblock.fs_cssize - i : sblock.fs_bsize;
+               sblock.fs_csp[j] = (struct csum *)calloc(1, size);
+               bread(fsbtodb(fs, fs->fs_csaddr + (j * fs->fs_frag)),
+                     (char *)fs->fs_csp[j], size);
+       }
+}
+
+bwrite(blk, buf, size)
+       char *buf;
+       daddr_t blk;
+       register size;
+{
+       if (lseek(fi, blk * DEV_BSIZE, 0) < 0) {
+               perror("FS SEEK");
+               return(1);
+       }
+       if (write(fi, buf, size) != size) {
+               perror("FS WRITE");
+               return(1);
+       }
+       return (0);
+}
+
+bread(bno, buf, cnt)
+       daddr_t bno;
+       char *buf;
+{
+       register i;
+
+       lseek(fi, bno * DEV_BSIZE, 0);
+       if ((i = read(fi, buf, cnt)) != cnt) {
+               if (sflg) {
+                       printf("No Update\n");
+                       sflg = 0;
+               }
+               for(i=0; i<sblock.fs_bsize; i++)
+                       buf[i] = 0;
+               return (1);
+       }
+       return (0);
+}
+
+/*
+ * check if a block is available
+ */
+isblock(fs, cp, h)
+       struct fs *fs;
+       unsigned char *cp;
+       int h;
+{
+       unsigned char mask;
+
+       switch (fs->fs_frag) {
+       case 8:
+               return (cp[h] == 0xff);
+       case 4:
+               mask = 0x0f << ((h & 0x1) << 2);
+               return ((cp[h >> 1] & mask) == mask);
+       case 2:
+               mask = 0x03 << ((h & 0x3) << 1);
+               return ((cp[h >> 2] & mask) == mask);
+       case 1:
+               mask = 0x01 << (h & 0x7);
+               return ((cp[h >> 3] & mask) == mask);
+       default:
+#ifdef STANDALONE
+               printf("isblock bad fs_frag %d\n", fs->fs_frag);
+#else
+               fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
+#endif
+               return;
+       }
+}
+
+/*
+ * take a block out of the map
+ */
+clrblock(fs, cp, h)
+       struct fs *fs;
+       unsigned char *cp;
+       int h;
+{
+       switch ((fs)->fs_frag) {
+       case 8:
+               cp[h] = 0;
+               return;
+       case 4:
+               cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
+               return;
+       case 2:
+               cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
+               return;
+       case 1:
+               cp[h >> 3] &= ~(0x01 << (h & 0x7));
+               return;
+       default:
+#ifdef STANDALONE
+               printf("clrblock bad fs_frag %d\n", fs->fs_frag);
+#else
+               fprintf(stderr, "clrblock bad fs_frag %d\n", fs->fs_frag);
+#endif
+               return;
+       }
+}
+
+/*
+ * put a block into the map
+ */
+setblock(fs, cp, h)
+       struct fs *fs;
+       unsigned char *cp;
+       int h;
+{
+       switch (fs->fs_frag) {
+       case 8:
+               cp[h] = 0xff;
+               return;
+       case 4:
+               cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
+               return;
+       case 2:
+               cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
+               return;
+       case 1:
+               cp[h >> 3] |= (0x01 << (h & 0x7));
+               return;
+       default:
+#ifdef STANDALONE
+               printf("setblock bad fs_frag %d\n", fs->fs_frag);
+#else
+               fprintf(stderr, "setblock bad fs_frag %d\n", fs->fs_frag);
+#endif
+               return;
+       }
+}
+
+/*     tables.c        4.1     82/03/25        */
+
+/* merged into kernel: tables.c 2.1 3/25/82 */
+
+/* last monet version: partab.c        4.2     81/03/08        */
+
+/*
+ * bit patterns for identifying fragments in the block map
+ * used as ((map & around) == inside)
+ */
+int around[9] = {
+       0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
+};
+int inside[9] = {
+       0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
+};
+
+/*
+ * given a block map bit pattern, the frag tables tell whether a
+ * particular size fragment is available. 
+ *
+ * used as:
+ * if ((1 << (size - 1)) & fragtbl[fs->fs_frag][map] {
+ *     at least one fragment of the indicated size is available
+ * }
+ *
+ * These tables are used by the scanc instruction on the VAX to
+ * quickly find an appropriate fragment.
+ */
+
+unsigned char fragtbl124[256] = {
+       0x00, 0x16, 0x16, 0x2a, 0x16, 0x16, 0x26, 0x4e,
+       0x16, 0x16, 0x16, 0x3e, 0x2a, 0x3e, 0x4e, 0x8a,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x26, 0x36, 0x36, 0x2e, 0x36, 0x36, 0x26, 0x6e,
+       0x36, 0x36, 0x36, 0x3e, 0x2e, 0x3e, 0x6e, 0xae,
+       0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
+       0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
+       0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
+       0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
+       0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
+       0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
+       0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
+       0x8a, 0x9e, 0x9e, 0xaa, 0x9e, 0x9e, 0xae, 0xce,
+       0x9e, 0x9e, 0x9e, 0xbe, 0xaa, 0xbe, 0xce, 0x8a,
+};
+
+unsigned char fragtbl8[256] = {
+       0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04,
+       0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+       0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
+       0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
+       0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
+       0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
+       0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
+       0x08, 0x09, 0x09, 0x0a, 0x10, 0x11, 0x20, 0x40,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
+       0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
+       0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
+       0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
+       0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
+       0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
+       0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
+       0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0a, 0x12,
+       0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
+       0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0c,
+       0x08, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x0a, 0x0c,
+       0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
+};
+
+/*
+ * the actual fragtbl array
+ */
+unsigned char *fragtbl[MAXFRAG + 1] = {
+       0, fragtbl124, fragtbl124, 0, fragtbl124, 0, 0, 0, fragtbl8,
+};