additional sanity checks
[unix-history] / usr / src / sbin / fsck / utilities.c
index e9fe8f9..d8e2b36 100644 (file)
@@ -1,25 +1,29 @@
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1980, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)utilities.c        5.5 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)utilities.c        5.28 (Berkeley) %G%";
+#endif /* not lint */
 
 
+#include <sys/param.h>
+#include <ufs/dinode.h>
+#include <ufs/fs.h>
+#include <ufs/dir.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <ctype.h>
 #include <ctype.h>
-#include <sys/param.h>
-#include <sys/inode.h>
-#include <sys/fs.h>
-#include <sys/dir.h>
 #include "fsck.h"
 
 #include "fsck.h"
 
+long   diskreads, totalreads;  /* Disk cache statistics */
 long   lseek();
 
 ftypeok(dp)
 long   lseek();
 
 ftypeok(dp)
-       DINODE *dp;
+       struct dinode *dp;
 {
        switch (dp->di_mode & IFMT) {
 
 {
        switch (dp->di_mode & IFMT) {
 
@@ -29,6 +33,7 @@ ftypeok(dp)
        case IFCHR:
        case IFLNK:
        case IFSOCK:
        case IFCHR:
        case IFLNK:
        case IFSOCK:
+       case IFIFO:
                return (1);
 
        default:
                return (1);
 
        default:
@@ -38,123 +43,195 @@ ftypeok(dp)
        }
 }
 
        }
 }
 
-reply(s)
-       char *s;
+reply(question)
+       char *question;
 {
 {
-       char line[80];
+       int persevere;
+       char c;
 
        if (preen)
                pfatal("INTERNAL ERROR: GOT TO reply()");
 
        if (preen)
                pfatal("INTERNAL ERROR: GOT TO reply()");
-       printf("\n%s? ", s);
-       if (nflag || dfile.wfdes < 0) {
-               printf(" no\n\n");
+       persevere = !strcmp(question, "CONTINUE");
+       printf("\n");
+       if (!persevere && (nflag || fswritefd < 0)) {
+               printf("%s? no\n\n", question);
                return (0);
        }
                return (0);
        }
-       if (yflag) {
-               printf(" yes\n\n");
+       if (yflag || (persevere && nflag)) {
+               printf("%s? yes\n\n", question);
                return (1);
        }
                return (1);
        }
-       if (getline(stdin, line, sizeof(line)) == EOF)
-               errexit("\n");
+       do      {
+               printf("%s? [yn] ", question);
+               (void) fflush(stdout);
+               c = getc(stdin);
+               while (c != '\n' && getc(stdin) != '\n')
+                       if (feof(stdin))
+                               return (0);
+       } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
        printf("\n");
        printf("\n");
-       if (line[0] == 'y' || line[0] == 'Y')
+       if (c == 'y' || c == 'Y')
                return (1);
                return (1);
-       else
-               return (0);
+       return (0);
 }
 
 }
 
-getline(fp, loc, maxlen)
-       FILE *fp;
-       char *loc;
+/*
+ * Malloc buffers and set up cache.
+ */
+bufinit()
 {
 {
-       register n;
-       register char *p, *lastloc;
-
-       p = loc;
-       lastloc = &p[maxlen-1];
-       while ((n = getc(fp)) != '\n') {
-               if (n == EOF)
-                       return (EOF);
-               if (!isspace(n) && p < lastloc)
-                       *p++ = n;
+       register struct bufarea *bp;
+       long bufcnt, i;
+       char *bufp;
+
+       pbp = pdirbp = (struct bufarea *)0;
+       bufp = malloc((unsigned int)sblock.fs_bsize);
+       if (bufp == 0)
+               errexit("cannot allocate buffer pool\n");
+       cgblk.b_un.b_buf = bufp;
+       initbarea(&cgblk);
+       bufhead.b_next = bufhead.b_prev = &bufhead;
+       bufcnt = MAXBUFSPACE / sblock.fs_bsize;
+       if (bufcnt < MINBUFS)
+               bufcnt = MINBUFS;
+       for (i = 0; i < bufcnt; i++) {
+               bp = (struct bufarea *)malloc(sizeof(struct bufarea));
+               bufp = malloc((unsigned int)sblock.fs_bsize);
+               if (bp == NULL || bufp == NULL) {
+                       if (i >= MINBUFS)
+                               break;
+                       errexit("cannot allocate buffer pool\n");
+               }
+               bp->b_un.b_buf = bufp;
+               bp->b_prev = &bufhead;
+               bp->b_next = bufhead.b_next;
+               bufhead.b_next->b_prev = bp;
+               bufhead.b_next = bp;
+               initbarea(bp);
        }
        }
-       *p = 0;
-       return (p - loc);
+       bufhead.b_size = i;     /* save number of buffers */
+}
+
+/*
+ * Manage a cache of directory blocks.
+ */
+struct bufarea *
+getdatablk(blkno, size)
+       daddr_t blkno;
+       long size;
+{
+       register struct bufarea *bp;
+
+       for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
+               if (bp->b_bno == fsbtodb(&sblock, blkno))
+                       goto foundit;
+       for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
+               if ((bp->b_flags & B_INUSE) == 0)
+                       break;
+       if (bp == &bufhead)
+               errexit("deadlocked buffer pool\n");
+       getblk(bp, blkno, size);
+       /* fall through */
+foundit:
+       totalreads++;
+       bp->b_prev->b_next = bp->b_next;
+       bp->b_next->b_prev = bp->b_prev;
+       bp->b_prev = &bufhead;
+       bp->b_next = bufhead.b_next;
+       bufhead.b_next->b_prev = bp;
+       bufhead.b_next = bp;
+       bp->b_flags |= B_INUSE;
+       return (bp);
 }
 
 }
 
-BUFAREA *
+void
 getblk(bp, blk, size)
 getblk(bp, blk, size)
-       register BUFAREA *bp;
+       register struct bufarea *bp;
        daddr_t blk;
        long size;
 {
        daddr_t blk;
        long size;
 {
-       register struct filecntl *fcp;
        daddr_t dblk;
 
        daddr_t dblk;
 
-       fcp = &dfile;
        dblk = fsbtodb(&sblock, blk);
        dblk = fsbtodb(&sblock, blk);
-       if (bp->b_bno == dblk)
-               return (bp);
-       flush(fcp, bp);
-       bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size);
-       bp->b_bno = dblk;
-       bp->b_size = size;
-       return (bp);
+       if (bp->b_bno != dblk) {
+               flush(fswritefd, bp);
+               diskreads++;
+               bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
+               bp->b_bno = dblk;
+               bp->b_size = size;
+       }
 }
 
 }
 
-flush(fcp, bp)
-       struct filecntl *fcp;
-       register BUFAREA *bp;
+flush(fd, bp)
+       int fd;
+       register struct bufarea *bp;
 {
        register int i, j;
 
        if (!bp->b_dirty)
                return;
        if (bp->b_errs != 0)
 {
        register int i, j;
 
        if (!bp->b_dirty)
                return;
        if (bp->b_errs != 0)
-               pfatal("WRITING ZERO'ED BLOCK %d TO DISK\n", bp->b_bno);
+               pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
+                   (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
+                   bp->b_bno);
        bp->b_dirty = 0;
        bp->b_errs = 0;
        bp->b_dirty = 0;
        bp->b_errs = 0;
-       bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
+       bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
        if (bp != &sblk)
                return;
        for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
        if (bp != &sblk)
                return;
        for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
-               bwrite(&dfile, (char *)sblock.fs_csp[j],
+               bwrite(fswritefd, (char *)sblock.fs_csp[j],
                    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
                    sblock.fs_cssize - i < sblock.fs_bsize ?
                    sblock.fs_cssize - i : sblock.fs_bsize);
        }
 }
 
                    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
                    sblock.fs_cssize - i < sblock.fs_bsize ?
                    sblock.fs_cssize - i : sblock.fs_bsize);
        }
 }
 
-rwerr(s, blk)
-       char *s;
+rwerror(mesg, blk)
+       char *mesg;
        daddr_t blk;
 {
 
        if (preen == 0)
                printf("\n");
        daddr_t blk;
 {
 
        if (preen == 0)
                printf("\n");
-       pfatal("CANNOT %s: BLK %ld", s, blk);
+       pfatal("CANNOT %s: BLK %ld", mesg, blk);
        if (reply("CONTINUE") == 0)
                errexit("Program terminated\n");
 }
 
 ckfini()
 {
        if (reply("CONTINUE") == 0)
                errexit("Program terminated\n");
 }
 
 ckfini()
 {
+       register struct bufarea *bp, *nbp;
+       int cnt = 0;
 
 
-       flush(&dfile, &fileblk);
-       flush(&dfile, &sblk);
-       if (sblk.b_bno != SBLOCK) {
-               sblk.b_bno = SBLOCK;
+       flush(fswritefd, &sblk);
+       if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
+           !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
+               sblk.b_bno = SBOFF / dev_bsize;
                sbdirty();
                sbdirty();
-               flush(&dfile, &sblk);
+               flush(fswritefd, &sblk);
+       }
+       flush(fswritefd, &cgblk);
+       free(cgblk.b_un.b_buf);
+       for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) {
+               cnt++;
+               flush(fswritefd, bp);
+               nbp = bp->b_prev;
+               free(bp->b_un.b_buf);
+               free((char *)bp);
        }
        }
-       flush(&dfile, &inoblk);
-       flush(&dfile, &cgblk);
-       (void)close(dfile.rfdes);
-       (void)close(dfile.wfdes);
+       if (bufhead.b_size != cnt)
+               errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
+       pbp = pdirbp = (struct bufarea *)0;
+       if (debug)
+               printf("cache missed %ld of %ld (%d%%)\n", diskreads,
+                   totalreads, (int)(diskreads * 100 / totalreads));
+       (void)close(fsreadfd);
+       (void)close(fswritefd);
 }
 
 }
 
-bread(fcp, buf, blk, size)
-       register struct filecntl *fcp;
+bread(fd, buf, blk, size)
+       int fd;
        char *buf;
        daddr_t blk;
        long size;
        char *buf;
        daddr_t blk;
        long size;
@@ -162,20 +239,25 @@ bread(fcp, buf, blk, size)
        char *cp;
        int i, errs;
 
        char *cp;
        int i, errs;
 
-       if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
-               rwerr("SEEK", blk);
-       else if (read(fcp->rfdes, buf, (int)size) == size)
+       if (lseek(fd, blk * dev_bsize, 0) < 0)
+               rwerror("SEEK", blk);
+       else if (read(fd, buf, (int)size) == size)
                return (0);
                return (0);
-       rwerr("READ", blk);
-       if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
-               rwerr("SEEK", blk);
+       rwerror("READ", blk);
+       if (lseek(fd, blk * dev_bsize, 0) < 0)
+               rwerror("SEEK", blk);
        errs = 0;
        errs = 0;
-       bzero(buf, size);
-       pfatal("THE FOLLOWING SECTORS COULD NOT BE READ:");
-       for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE) {
-               if (read(fcp->rfdes, cp, DEV_BSIZE) < 0) {
-                       lseek(fcp->rfdes, (long)dbtob(blk) + i + DEV_BSIZE, 0);
-                       printf(" %d,", blk + i / DEV_BSIZE);
+       bzero(buf, (size_t)size);
+       printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
+       for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
+               if (read(fd, cp, (int)secsize) < 0) {
+                       (void)lseek(fd, blk * dev_bsize + i + secsize, 0);
+                       if (secsize != dev_bsize && dev_bsize != 1)
+                               printf(" %ld (%ld),",
+                                   (blk * dev_bsize + i) / secsize,
+                                   blk + i / dev_bsize);
+                       else
+                               printf(" %ld,", blk + i / dev_bsize);
                        errs++;
                }
        }
                        errs++;
                }
        }
@@ -183,8 +265,8 @@ bread(fcp, buf, blk, size)
        return (errs);
 }
 
        return (errs);
 }
 
-bwrite(fcp, buf, blk, size)
-       register struct filecntl *fcp;
+bwrite(fd, buf, blk, size)
+       int fd;
        char *buf;
        daddr_t blk;
        long size;
        char *buf;
        daddr_t blk;
        long size;
@@ -192,22 +274,22 @@ bwrite(fcp, buf, blk, size)
        int i;
        char *cp;
 
        int i;
        char *cp;
 
-       if (fcp->wfdes < 0)
+       if (fd < 0)
                return;
                return;
-       if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
-               rwerr("SEEK", blk);
-       else if (write(fcp->wfdes, buf, (int)size) == size) {
-               fcp->mod = 1;
+       if (lseek(fd, blk * dev_bsize, 0) < 0)
+               rwerror("SEEK", blk);
+       else if (write(fd, buf, (int)size) == size) {
+               fsmodified = 1;
                return;
        }
                return;
        }
-       rwerr("WRITE", blk);
-       if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
-               rwerr("SEEK", blk);
-       pfatal("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
-       for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE)
-               if (write(fcp->wfdes, cp, DEV_BSIZE) < 0) {
-                       lseek(fcp->rfdes, (long)dbtob(blk) + i + DEV_BSIZE, 0);
-                       printf(" %d,", blk + i / DEV_BSIZE);
+       rwerror("WRITE", blk);
+       if (lseek(fd, blk * dev_bsize, 0) < 0)
+               rwerror("SEEK", blk);
+       printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
+       for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
+               if (write(fd, cp, (int)dev_bsize) < 0) {
+                       (void)lseek(fd, blk * dev_bsize + i + dev_bsize, 0);
+                       printf(" %ld,", blk + i / dev_bsize);
                }
        printf("\n");
        return;
                }
        printf("\n");
        return;
@@ -217,18 +299,18 @@ bwrite(fcp, buf, blk, size)
  * allocate a data block with the specified number of fragments
  */
 allocblk(frags)
  * allocate a data block with the specified number of fragments
  */
 allocblk(frags)
-       int frags;
+       long frags;
 {
        register int i, j, k;
 
        if (frags <= 0 || frags > sblock.fs_frag)
                return (0);
 {
        register int i, j, k;
 
        if (frags <= 0 || frags > sblock.fs_frag)
                return (0);
-       for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) {
+       for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
                for (j = 0; j <= sblock.fs_frag - frags; j++) {
                for (j = 0; j <= sblock.fs_frag - frags; j++) {
-                       if (getbmap(i + j))
+                       if (testbmap(i + j))
                                continue;
                        for (k = 1; k < frags; k++)
                                continue;
                        for (k = 1; k < frags; k++)
-                               if (getbmap(i + j + k))
+                               if (testbmap(i + j + k))
                                        break;
                        if (k < frags) {
                                j += k;
                                        break;
                        if (k < frags) {
                                j += k;
@@ -248,13 +330,13 @@ allocblk(frags)
  */
 freeblk(blkno, frags)
        daddr_t blkno;
  */
 freeblk(blkno, frags)
        daddr_t blkno;
-       int frags;
+       long frags;
 {
        struct inodesc idesc;
 
        idesc.id_blkno = blkno;
        idesc.id_numfrags = frags;
 {
        struct inodesc idesc;
 
        idesc.id_blkno = blkno;
        idesc.id_numfrags = frags;
-       pass4check(&idesc);
+       (void)pass4check(&idesc);
 }
 
 /*
 }
 
 /*
@@ -269,13 +351,13 @@ getpathname(namebuf, curdir, ino)
        struct inodesc idesc;
        extern int findname();
 
        struct inodesc idesc;
        extern int findname();
 
-       if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) {
-               strcpy(namebuf, "?");
+       if (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND) {
+               (void)strcpy(namebuf, "?");
                return;
        }
                return;
        }
-       bzero(&idesc, sizeof(struct inodesc));
+       bzero((char *)&idesc, sizeof(struct inodesc));
        idesc.id_type = DATA;
        idesc.id_type = DATA;
-       cp = &namebuf[BUFSIZ - 1];
+       cp = &namebuf[MAXPATHLEN - 1];
        *cp = '\0';
        if (curdir != ino) {
                idesc.id_parent = curdir;
        *cp = '\0';
        if (curdir != ino) {
                idesc.id_parent = curdir;
@@ -292,26 +374,26 @@ getpathname(namebuf, curdir, ino)
                idesc.id_parent = ino;
                idesc.id_func = findname;
                idesc.id_name = namebuf;
                idesc.id_parent = ino;
                idesc.id_func = findname;
                idesc.id_name = namebuf;
-               if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0)
+               if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
                        break;
                len = strlen(namebuf);
                cp -= len;
                if (cp < &namebuf[MAXNAMLEN])
                        break;
                        break;
                len = strlen(namebuf);
                cp -= len;
                if (cp < &namebuf[MAXNAMLEN])
                        break;
-               bcopy(namebuf, cp, len);
+               bcopy(namebuf, cp, (size_t)len);
                *--cp = '/';
                ino = idesc.id_number;
        }
        if (ino != ROOTINO) {
                *--cp = '/';
                ino = idesc.id_number;
        }
        if (ino != ROOTINO) {
-               strcpy(namebuf, "?");
+               (void)strcpy(namebuf, "?");
                return;
        }
                return;
        }
-       bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp);
+       bcopy(cp, namebuf, (size_t)(&namebuf[MAXPATHLEN] - cp));
 }
 
 }
 
+void
 catch()
 {
 catch()
 {
-
        ckfini();
        exit(12);
 }
        ckfini();
        exit(12);
 }
@@ -321,6 +403,7 @@ catch()
  * a special exit after filesystem checks complete
  * so that reboot sequence may be interrupted.
  */
  * a special exit after filesystem checks complete
  * so that reboot sequence may be interrupted.
  */
+void
 catchquit()
 {
        extern returntosingle;
 catchquit()
 {
        extern returntosingle;
@@ -334,6 +417,7 @@ catchquit()
  * Ignore a single quit signal; wait and flush just in case.
  * Used by child processes in preen.
  */
  * Ignore a single quit signal; wait and flush just in case.
  * Used by child processes in preen.
  */
+void
 voidquit()
 {
 
 voidquit()
 {
 
@@ -354,7 +438,7 @@ dofix(idesc, msg)
 
        case DONTKNOW:
                if (idesc->id_type == DATA)
 
        case DONTKNOW:
                if (idesc->id_type == DATA)
-                       direrr(idesc->id_number, msg);
+                       direrror(idesc->id_number, msg);
                else
                        pwarn(msg);
                if (preen) {
                else
                        pwarn(msg);
                if (preen) {
@@ -390,8 +474,8 @@ errexit(s1, s2, s3, s4)
 }
 
 /*
 }
 
 /*
- * An inconsistency occured which shouldn't during normal operations.
- * Die if preening, otherwise just printf.
+ * An unexpected inconsistency occured.
+ * Die if preening, otherwise just print message and continue.
  */
 /* VARARGS1 */
 pfatal(s, a1, a2, a3)
  */
 /* VARARGS1 */
 pfatal(s, a1, a2, a3)
@@ -410,7 +494,7 @@ pfatal(s, a1, a2, a3)
 }
 
 /*
 }
 
 /*
- * Pwarn is like printf when not preening,
+ * Pwarn just prints a message when not preening,
  * or a warning (preceded by filename) when preening.
  */
 /* VARARGS1 */
  * or a warning (preceded by filename) when preening.
  */
 /* VARARGS1 */