BSD 4_4 release
[unix-history] / usr / src / sbin / fsck / main.c
index 3717037..e44a86d 100644 (file)
+/*
+ * Copyright (c) 1980, 1986, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #ifndef lint
 #ifndef lint
-char version[] = "@(#)main.c   2.30 (Berkeley) %G%";
-#endif
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1986, 1993\n\
+       The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c     8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
 
 
-#include <stdio.h>
-#include <ctype.h>
 #include <sys/param.h>
 #include <sys/param.h>
-#include <sys/fs.h>
-#include <sys/inode.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
 #include <fstab.h>
 #include <fstab.h>
-#define KERNEL
-#include <sys/dir.h>
-#undef KERNEL
-
-/* RECONSTRUCT ONLY BAD CG IN PASS 6 */
-
-typedef        int     (*SIG_TYP)();
-
-#define        MAXNINDIR       (MAXBSIZE / sizeof (daddr_t))
-#define        MAXINOPB        (MAXBSIZE / sizeof (struct dinode))
-#define        SPERB           (MAXBSIZE / sizeof(short))
-#define MINDIRSIZE     (sizeof (struct dirtemplate))
-
-#define        MAXDUP  10              /* limit on dup blks (per inode) */
-#define        MAXBAD  10              /* limit on bad blks (per inode) */
-
-#define        USTATE  0               /* inode not allocated */
-#define        FSTATE  01              /* inode is file */
-#define        DSTATE  02              /* inode is directory */
-#define        CLEAR   03              /* inode is to be cleared */
-
-typedef struct dinode  DINODE;
-typedef struct direct  DIRECT;
-
-#define        ALLOC   ((dp->di_mode & IFMT) != 0)
-#define        DIRCT   ((dp->di_mode & IFMT) == IFDIR)
-#define        REG     ((dp->di_mode & IFMT) == IFREG)
-#define        BLK     ((dp->di_mode & IFMT) == IFBLK)
-#define        CHR     ((dp->di_mode & IFMT) == IFCHR)
-#define        LNK     ((dp->di_mode & IFMT) == IFLNK)
-#define        SOCK    ((dp->di_mode & IFMT) == IFSOCK)
-#define        BADBLK  ((dp->di_mode & IFMT) == IFMT)
-#define        SPECIAL (BLK || CHR)
-
-struct bufarea {
-       struct bufarea  *b_next;                /* must be first */
-       daddr_t b_bno;
-       int     b_size;
-       union {
-               char    b_buf[MAXBSIZE];        /* buffer space */
-               short   b_lnks[SPERB];          /* link counts */
-               daddr_t b_indir[MAXNINDIR];     /* indirect block */
-               struct  fs b_fs;                /* super block */
-               struct  cg b_cg;                /* cylinder group */
-               struct dinode b_dinode[MAXINOPB]; /* inode block */
-       } b_un;
-       char    b_dirty;
-};
-
-typedef struct bufarea BUFAREA;
-
-BUFAREA        inoblk;                 /* inode blocks */
-BUFAREA        fileblk;                /* other blks in filesys */
-BUFAREA        sblk;                   /* file system superblock */
-BUFAREA        cgblk;                  /* cylinder group blocks */
-
-#define        initbarea(x)    (x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
-#define        dirty(x)        (x)->b_dirty = 1
-#define        inodirty()      inoblk.b_dirty = 1
-#define        sbdirty()       sblk.b_dirty = 1
-#define        cgdirty()       cgblk.b_dirty = 1
-
-#define        dirblk          fileblk.b_un
-#define        sblock          sblk.b_un.b_fs
-#define        cgrp            cgblk.b_un.b_cg
-
-struct filecntl {
-       int     rfdes;
-       int     wfdes;
-       int     mod;
-} dfile;                       /* file descriptors for filesys */
-
-struct inodesc {
-       char id_type;           /* type of descriptor, DATA or ADDR */
-       int (*id_func)();       /* function to be applied to blocks of inode */
-       ino_t id_number;        /* inode number described */
-       ino_t id_parent;        /* for DATA nodes, their parent */
-       daddr_t id_blkno;       /* current block number being examined */
-       int id_numfrags;        /* number of frags contained in block */
-       long id_filesize;       /* for DATA nodes, the size of the directory */
-       int id_loc;             /* for DATA nodes, current location in dir */
-       int id_entryno;         /* for DATA nodes, current entry number */
-       DIRECT *id_dirp;        /* for data nodes, ptr to current entry */
-       enum {DONTKNOW, NOFIX, FIX} id_fix; /* policy on fixing errors */
-};
-/* file types */
-#define        DATA    1
-#define        ADDR    2
-
-
-#define        DUPTBLSIZE      100     /* num of dup blocks to remember */
-daddr_t        duplist[DUPTBLSIZE];    /* dup block table */
-daddr_t        *enddup;                /* next entry in dup table */
-daddr_t        *muldup;                /* multiple dups part of table */
-
-#define        MAXLNCNT        500     /* num zero link cnts to remember */
-ino_t  badlncnt[MAXLNCNT];     /* table of inos with zero link cnts */
-ino_t  *badlnp;                /* next entry in table */
-
-char   rawflg;
-char   nflag;                  /* assume a no response */
-char   yflag;                  /* assume a yes response */
-int    bflag;                  /* location of alternate super block */
-int    debug;                  /* output debugging info */
-char   preen;                  /* just fix normal inconsistencies */
-char   rplyflag;               /* any questions asked? */
-char   hotroot;                /* checking root device */
-char   fixcg;                  /* corrupted free list bit maps */
-
-char   *blockmap;              /* ptr to primary blk allocation map */
-char   *freemap;               /* ptr to secondary blk allocation map */
-char   *statemap;              /* ptr to inode state table */
-short  *lncntp;                /* ptr to link count table */
-
-char   *srchname;              /* name being searched for in dir */
-char   pathname[BUFSIZ];       /* current pathname */
-char   *pathp;                 /* pointer to pathname position */
-char   *endpathname = &pathname[BUFSIZ - 2];
-
-char   *lfname = "lost+found";
-
-ino_t  imax;                   /* number of inodes */
-ino_t  lastino;                /* hiwater mark of inodes */
-ino_t  lfdir;                  /* lost & found directory */
-
-off_t  maxblk;                 /* largest logical blk in file */
-off_t  bmapsz;                 /* num chars in blockmap */
-
-daddr_t        n_ffree;                /* number of small free blocks */
-daddr_t        n_bfree;                /* number of large free blocks */
-daddr_t        n_blks;                 /* number of blocks used */
-daddr_t        n_files;                /* number of files seen */
-daddr_t        n_index;
-daddr_t        n_bad;
-daddr_t        fmax;                   /* number of blocks in the volume */
-
-daddr_t        badblk;
-daddr_t        dupblk;
-
-int    inosumbad;
-int    offsumbad;
-int    frsumbad;
-int    sbsumbad;
-
-#define        zapino(x)       (*(x) = zino)
-struct dinode zino;
-
-#define        setbmap(x)      setbit(blockmap, x)
-#define        getbmap(x)      isset(blockmap, x)
-#define        clrbmap(x)      clrbit(blockmap, x)
-
-#define        setfmap(x)      setbit(freemap, x)
-#define        getfmap(x)      isset(freemap, x)
-#define        clrfmap(x)      clrbit(freemap, x)
-
-#define        ALTERED 010
-#define        KEEPON  04
-#define        SKIP    02
-#define        STOP    01
-
-int    (*signal())();
-long   lseek();
-time_t time();
-DINODE *ginode();
-DIRECT *fsck_readdir();
-BUFAREA        *getblk();
-int    catch();
-int    findino(), mkentry(), chgdd();
-int    pass1check(), pass1bcheck(), pass2check(), pass4check();
-char   *rawname(), *unrawname();
-char   *calloc(), *strcpy(), *strcat(), *rindex();
-extern int inside[], around[];
-extern unsigned char *fragtbl[];
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include "fsck.h"
 
 
-char   *devname;
+void   catch(), catchquit(), voidquit();
+int    returntosingle;
 
 main(argc, argv)
        int     argc;
        char    *argv[];
 {
 
 main(argc, argv)
        int     argc;
        char    *argv[];
 {
-       struct fstab *fsp;
-       int pid, passno, anygtr, sumstatus;
+       int ch;
+       int ret, maxrun = 0;
+       extern int docheck(), checkfilesys();
+       extern char *optarg, *blockcheck();
+       extern int optind;
 
        sync();
 
        sync();
-       while (--argc > 0 && **++argv == '-') {
-               switch (*++*argv) {
-
+       while ((ch = getopt(argc, argv, "dpnNyYb:c:l:m:")) != EOF) {
+               switch (ch) {
                case 'p':
                        preen++;
                        break;
 
                case 'b':
                case 'p':
                        preen++;
                        break;
 
                case 'b':
-                       if (argv[0][1] != '\0') {
-                               bflag = atoi(argv[0]+1);
-                       } else {
-                               bflag = atoi(*++argv);
-                               argc--;
-                       }
+                       bflag = argtoi('b', "number", optarg, 10);
                        printf("Alternate super block location: %d\n", bflag);
                        break;
 
                        printf("Alternate super block location: %d\n", bflag);
                        break;
 
+               case 'c':
+                       cvtlevel = argtoi('c', "conversion level", optarg, 10);
+                       break;
+               
                case 'd':
                        debug++;
                        break;
 
                case 'd':
                        debug++;
                        break;
 
-               case 'n':       /* default no answer flag */
+               case 'l':
+                       maxrun = argtoi('l', "number", optarg, 10);
+                       break;
+
+               case 'm':
+                       lfmode = argtoi('m', "mode", optarg, 8);
+                       if (lfmode &~ 07777)
+                               errexit("bad mode to -m: %o\n", lfmode);
+                       printf("** lost+found creation mode %o\n", lfmode);
+                       break;
+
+               case 'n':
                case 'N':
                        nflag++;
                        yflag = 0;
                        break;
 
                case 'N':
                        nflag++;
                        yflag = 0;
                        break;
 
-               case 'y':       /* default yes answer flag */
+               case 'y':
                case 'Y':
                        yflag++;
                        nflag = 0;
                        break;
 
                default:
                case 'Y':
                        yflag++;
                        nflag = 0;
                        break;
 
                default:
-                       errexit("%c option?\n", **argv);
+                       errexit("%c option?\n", ch);
                }
        }
                }
        }
+       argc -= optind;
+       argv += optind;
        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                (void)signal(SIGINT, catch);
        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                (void)signal(SIGINT, catch);
+       if (preen)
+               (void)signal(SIGQUIT, catchquit);
        if (argc) {
        if (argc) {
-               while (argc-- > 0) {
-                       hotroot = 0;
-                       checkfilesys(*argv++);
-               }
+               while (argc-- > 0)
+                       (void)checkfilesys(blockcheck(*argv++), 0, 0L, 0);
                exit(0);
        }
                exit(0);
        }
-       sumstatus = 0;
-       passno = 1;
-       do {
-               anygtr = 0;
-               if (setfsent() == 0)
-                       errexit("Can't open checklist file: %s\n", FSTAB);
-               while ((fsp = getfsent()) != 0) {
-                       if (strcmp(fsp->fs_type, FSTAB_RW) &&
-                           strcmp(fsp->fs_type, FSTAB_RO) &&
-                           strcmp(fsp->fs_type, FSTAB_RQ))
-                               continue;
-                       if (preen == 0 ||
-                           passno == 1 && fsp->fs_passno == passno) {
-                               if (blockcheck(fsp->fs_spec) == 0 && preen)
-                                       exit(8);
-                       } else if (fsp->fs_passno > passno)
-                               anygtr = 1;
-                       else if (fsp->fs_passno == passno) {
-                               pid = fork();
-                               if (pid < 0) {
-                                       perror("fork");
-                                       exit(8);
-                               }
-                               if (pid == 0)
-                                       if (blockcheck(fsp->fs_spec)==0)
-                                               exit(8);
-                                       else
-                                               exit(0);
-                       }
-               }
-               if (preen) {
-                       union wait status;
-                       while (wait(&status) != -1)
-                               sumstatus |= status.w_retcode;
-               }
-               passno++;
-       } while (anygtr);
-       if (sumstatus)
-               exit(8);
-       (void)endfsent();
-       exit(0);
+       ret = checkfstab(preen, maxrun, docheck, checkfilesys);
+       if (returntosingle)
+               exit(2);
+       exit(ret);
 }
 
 }
 
-blockcheck(name)
-       char *name;
+argtoi(flag, req, str, base)
+       int flag;
+       char *req, *str;
+       int base;
 {
 {
-       struct stat stslash, stblock, stchar;
-       char *raw;
-       int looped = 0;
+       char *cp;
+       int ret;
 
 
-       hotroot = 0;
-       if (stat("/", &stslash) < 0){
-               error("Can't stat root\n");
-               return (0);
-       }
-retry:
-       if (stat(name, &stblock) < 0){
-               error("Can't stat %s\n", name);
-               return (0);
-       }
-       if (stblock.st_mode & S_IFBLK) {
-               raw = rawname(name);
-               if (stat(raw, &stchar) < 0){
-                       error("Can't stat %s\n", raw);
-                       return (0);
-               }
-               if (stchar.st_mode & S_IFCHR) {
-                       if (stslash.st_dev == stblock.st_rdev) {
-                               hotroot++;
-                               raw = unrawname(name);
-                       }
-                       checkfilesys(raw);
-                       return (1);
-               } else {
-                       error("%s is not a character device\n", raw);
-                       return (0);
-               }
-       } else if (stblock.st_mode & S_IFCHR) {
-               if (looped) {
-                       error("Can't make sense out of name %s\n", name);
-                       return (0);
-               }
-               name = unrawname(name);
-               looped++;
-               goto retry;
-       }
-       error("Can't make sense out of name %s\n", name);
-       return (0);
+       ret = (int)strtol(str, &cp, base);
+       if (cp == str || *cp)
+               errexit("-%c flag requires a %s\n", flag, req);
+       return (ret);
 }
 
 }
 
-checkfilesys(filesys)
-       char *filesys;
+/*
+ * Determine whether a filesystem should be checked.
+ */
+docheck(fsp)
+       register struct fstab *fsp;
 {
 
 {
 
-       devname = filesys;
+       if (strcmp(fsp->fs_vfstype, "ufs") ||
+           (strcmp(fsp->fs_type, FSTAB_RW) &&
+            strcmp(fsp->fs_type, FSTAB_RO)) ||
+           fsp->fs_passno == 0)
+               return (0);
+       return (1);
+}
+
+/*
+ * Check the specified filesystem.
+ */
+/* ARGSUSED */
+checkfilesys(filesys, mntpt, auxdata, child)
+       char *filesys, *mntpt;
+       long auxdata;
+{
+       daddr_t n_ffree, n_bfree;
+       struct dups *dp;
+       struct zlncnt *zlnp;
+       int cylno;
+
+       if (preen && child)
+               (void)signal(SIGQUIT, voidquit);
+       cdevname = filesys;
+       if (debug && preen)
+               pwarn("starting\n");
        if (setup(filesys) == 0) {
                if (preen)
                        pfatal("CAN'T CHECK FILE SYSTEM.");
        if (setup(filesys) == 0) {
                if (preen)
                        pfatal("CAN'T CHECK FILE SYSTEM.");
-               return;
+               return (0);
        }
        }
-/* 1: scan inodes tallying blocks used */
+       /*
+        * 1: scan inodes tallying blocks used
+        */
        if (preen == 0) {
                printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
                if (hotroot)
        if (preen == 0) {
                printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
                if (hotroot)
@@ -349,1937 +193,126 @@ checkfilesys(filesys)
        }
        pass1();
 
        }
        pass1();
 
-/* 1b: locate first references to duplicates, if any */
-       if (enddup != &duplist[0]) {
+       /*
+        * 1b: locate first references to duplicates, if any
+        */
+       if (duplist) {
                if (preen)
                        pfatal("INTERNAL ERROR: dups with -p");
                printf("** Phase 1b - Rescan For More DUPS\n");
                pass1b();
        }
 
                if (preen)
                        pfatal("INTERNAL ERROR: dups with -p");
                printf("** Phase 1b - Rescan For More DUPS\n");
                pass1b();
        }
 
-/* 2: traverse directories from root to mark all connected directories */
+       /*
+        * 2: traverse directories from root to mark all connected directories
+        */
        if (preen == 0)
                printf("** Phase 2 - Check Pathnames\n");
        pass2();
 
        if (preen == 0)
                printf("** Phase 2 - Check Pathnames\n");
        pass2();
 
-/* 3: scan inodes looking for disconnected directories */
+       /*
+        * 3: scan inodes looking for disconnected directories
+        */
        if (preen == 0)
                printf("** Phase 3 - Check Connectivity\n");
        pass3();
 
        if (preen == 0)
                printf("** Phase 3 - Check Connectivity\n");
        pass3();
 
-/* 4: scan inodes looking for disconnected files; check reference counts */
+       /*
+        * 4: scan inodes looking for disconnected files; check reference counts
+        */
        if (preen == 0)
                printf("** Phase 4 - Check Reference Counts\n");
        pass4();
 
        if (preen == 0)
                printf("** Phase 4 - Check Reference Counts\n");
        pass4();
 
-/* 5: check resource counts in cylinder groups */
+       /*
+        * 5: check and repair resource counts in cylinder groups
+        */
        if (preen == 0)
                printf("** Phase 5 - Check Cyl groups\n");
        pass5();
 
        if (preen == 0)
                printf("** Phase 5 - Check Cyl groups\n");
        pass5();
 
-       if (fixcg) {
-               if (preen == 0)
-                       printf("** Phase 6 - Salvage Cylinder Groups\n");
-               makecg();
-               n_ffree = sblock.fs_cstotal.cs_nffree;
-               n_bfree = sblock.fs_cstotal.cs_nbfree;
+       /*
+        * print out summary statistics
+        */
+       n_ffree = sblock.fs_cstotal.cs_nffree;
+       n_bfree = sblock.fs_cstotal.cs_nbfree;
+       pwarn("%ld files, %ld used, %ld free ",
+           n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
+       printf("(%ld frags, %ld blocks, %d.%d%% fragmentation)\n",
+           n_ffree, n_bfree, (n_ffree * 100) / sblock.fs_dsize,
+           ((n_ffree * 1000 + sblock.fs_dsize / 2) / sblock.fs_dsize) % 10);
+       if (debug &&
+           (n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree))
+               printf("%ld files missing\n", n_files);
+       if (debug) {
+               n_blks += sblock.fs_ncg *
+                       (cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
+               n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
+               n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
+               if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
+                       printf("%ld blocks missing\n", n_blks);
+               if (duplist != NULL) {
+                       printf("The following duplicate blocks remain:");
+                       for (dp = duplist; dp; dp = dp->next)
+                               printf(" %ld,", dp->dup);
+                       printf("\n");
+               }
+               if (zlnhead != NULL) {
+                       printf("The following zero link count inodes remain:");
+                       for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
+                               printf(" %lu,", zlnp->zlncnt);
+                       printf("\n");
+               }
        }
        }
-
-       pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n",
-           n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_fsize),
-           n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree);
-       if (dfile.mod) {
+       zlnhead = (struct zlncnt *)0;
+       duplist = (struct dups *)0;
+       muldup = (struct dups *)0;
+       inocleanup();
+       if (fsmodified) {
                (void)time(&sblock.fs_time);
                sbdirty();
        }
                (void)time(&sblock.fs_time);
                sbdirty();
        }
+       if (cvtlevel && sblk.b_dirty) {
+               /* 
+                * Write out the duplicate super blocks
+                */
+               for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
+                       bwrite(fswritefd, (char *)&sblock,
+                           fsbtodb(&sblock, cgsblock(&sblock, cylno)), SBSIZE);
+       }
        ckfini();
        free(blockmap);
        ckfini();
        free(blockmap);
-       free(freemap);
        free(statemap);
        free((char *)lncntp);
        free(statemap);
        free((char *)lncntp);
-       if (!dfile.mod)
-               return;
-       if (!preen) {
+       if (!fsmodified)
+               return (0);
+       if (!preen)
                printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
                printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
-               if (hotroot)
-                       printf("\n***** REBOOT UNIX *****\n");
-       }
        if (hotroot) {
        if (hotroot) {
-               sync();
-               exit(4);
-       }
-}
-
-setup(dev)
-       char *dev;
-{
-       dev_t rootdev;
-       struct stat statb;
-       daddr_t super = bflag ? bflag : SBLOCK;
-       int i, j, c, d, cgd;
-       long size;
-       BUFAREA asblk;
-#      define altsblock asblk.b_un.b_fs
-
-       if (stat("/", &statb) < 0)
-               errexit("Can't stat root\n");
-       rootdev = statb.st_dev;
-       if (stat(dev, &statb) < 0) {
-               error("Can't stat %s\n", dev);
-               return (0);
-       }
-       rawflg = 0;
-       if ((statb.st_mode & S_IFMT) == S_IFBLK)
-               ;
-       else if ((statb.st_mode & S_IFMT) == S_IFCHR)
-               rawflg++;
-       else {
-               if (reply("file is not a block or character device; OK") == 0)
-                       return (0);
-       }
-       if (rootdev == statb.st_rdev)
-               hotroot++;
-       if ((dfile.rfdes = open(dev, 0)) < 0) {
-               error("Can't open %s\n", dev);
-               return (0);
-       }
-       if (preen == 0)
-               printf("** %s", dev);
-       if (nflag || (dfile.wfdes = open(dev, 1)) < 0) {
-               dfile.wfdes = -1;
-               if (preen)
-                       pfatal("NO WRITE ACCESS");
-               printf(" (NO WRITE)");
-       }
-       if (preen == 0)
-               printf("\n");
-       fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; sbsumbad = 0;
-       dfile.mod = 0;
-       n_files = n_blks = n_ffree = n_bfree = 0;
-       muldup = enddup = &duplist[0];
-       badlnp = &badlncnt[0];
-       lfdir = 0;
-       rplyflag = 0;
-       initbarea(&sblk);
-       initbarea(&fileblk);
-       initbarea(&inoblk);
-       initbarea(&cgblk);
-       initbarea(&asblk);
-       /*
-        * Read in the super block and its summary info.
-        */
-       if (bread(&dfile, (char *)&sblock, super, (long)SBSIZE) == 0)
-               return (0);
-       sblk.b_bno = super;
-       sblk.b_size = SBSIZE;
-       /*
-        * run a few consistency checks of the super block
-        */
-       if (sblock.fs_magic != FS_MAGIC)
-               { badsb("MAGIC NUMBER WRONG"); return (0); }
-       if (sblock.fs_ncg < 1)
-               { badsb("NCG OUT OF RANGE"); return (0); }
-       if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
-               { badsb("CPG OUT OF RANGE"); return (0); }
-       if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
-           (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
-               { badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
-       if (sblock.fs_sbsize > SBSIZE)
-               { badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
-       /*
-        * Set all possible fields that could differ, then do check
-        * of whole super block against an alternate super block.
-        * When an alternate super-block is specified this check is skipped.
-        */
-       if (bflag)
-               goto sbok;
-       if (getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1),
-           sblock.fs_sbsize) == 0)
-               return (0);
-       altsblock.fs_link = sblock.fs_link;
-       altsblock.fs_rlink = sblock.fs_rlink;
-       altsblock.fs_time = sblock.fs_time;
-       altsblock.fs_cstotal = sblock.fs_cstotal;
-       altsblock.fs_cgrotor = sblock.fs_cgrotor;
-       altsblock.fs_fmod = sblock.fs_fmod;
-       altsblock.fs_clean = sblock.fs_clean;
-       altsblock.fs_ronly = sblock.fs_ronly;
-       altsblock.fs_flags = sblock.fs_flags;
-       altsblock.fs_maxcontig = sblock.fs_maxcontig;
-       altsblock.fs_minfree = sblock.fs_minfree;
-       altsblock.fs_rotdelay = sblock.fs_rotdelay;
-       altsblock.fs_maxbpg = sblock.fs_maxbpg;
-       bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp,
-               sizeof sblock.fs_csp);
-       bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt,
-               sizeof sblock.fs_fsmnt);
-       if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize))
-               { badsb("TRASHED VALUES IN SUPER BLOCK"); return (0); }
-sbok:
-       fmax = sblock.fs_size;
-       imax = sblock.fs_ncg * sblock.fs_ipg;
-       n_bad = cgsblock(&sblock, 0); /* boot block plus dedicated sblock */
-       /*
-        * read in the summary info.
-        */
-       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, (unsigned)size);
-               if (bread(&dfile, (char *)sblock.fs_csp[j],
-                   fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
-                   size) == 0)
-                       return (0);
-       }
-       /*
-        * allocate and initialize the necessary maps
-        */
-       bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
-       blockmap = calloc((unsigned)bmapsz, sizeof (char));
-       if (blockmap == NULL) {
-               printf("cannot alloc %d bytes for blockmap\n", bmapsz);
-               goto badsb;
-       }
-       freemap = calloc((unsigned)bmapsz, sizeof (char));
-       if (freemap == NULL) {
-               printf("cannot alloc %d bytes for freemap\n", bmapsz);
-               goto badsb;
-       }
-       statemap = calloc((unsigned)(imax + 1), sizeof(char));
-       if (statemap == NULL) {
-               printf("cannot alloc %d bytes for statemap\n", imax + 1);
-               goto badsb;
-       }
-       lncntp = (short *)calloc((unsigned)(imax + 1), sizeof(short));
-       if (lncntp == NULL) {
-               printf("cannot alloc %d bytes for lncntp\n", 
-                   (imax + 1) * sizeof(short));
-               goto badsb;
-       }
-       for (c = 0; c < sblock.fs_ncg; c++) {
-               cgd = cgdmin(&sblock, c);
-               if (c == 0) {
-                       d = cgbase(&sblock, c);
-                       cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
-               } else
-                       d = cgsblock(&sblock, c);
-               for (; d < cgd; d++)
-                       setbmap(d);
-       }
-
-       return (1);
-
-badsb:
-       ckfini();
-       return (0);
-#      undef altsblock
-}
-
-pass1()
-{
-       register int c, i, n, j;
-       register DINODE *dp;
-       int ndb, partial;
-       struct inodesc idesc;
-       ino_t inumber;
-
-       bzero((char *)&idesc, sizeof(struct inodesc));
-       idesc.id_type = ADDR;
-       idesc.id_func = pass1check;
-       inumber = 0;
-       n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
-       for (c = 0; c < sblock.fs_ncg; c++) {
-               if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
-                       continue;
-               if (cgrp.cg_magic != CG_MAGIC) {
-                       pfatal("CG %d: BAD MAGIC NUMBER\n", c);
-                       bzero((char *)&cgrp, (int)sblock.fs_cgsize);
-               }
-               n = 0;
-               for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
-                       dp = ginode(inumber);
-                       if (dp == NULL)
-                               continue;
-                       n++;
-                       if (ALLOC) {
-                               if (!isset(cgrp.cg_iused, i)) {
-                                       if (debug)
-                                               printf("%d bad, not used\n",
-                                                   inumber);
-                                       inosumbad++;
-                               }
-                               n--;
-                               lastino = inumber;
-                               if (!preen && BADBLK &&
-                                   reply("HOLD BAD BLOCK") == 1) {
-                                       dp->di_size = sblock.fs_fsize;
-                                       dp->di_mode = IFREG|0600;
-                                       inodirty();
-                               } else if (ftypeok(dp) == 0)
-                                       goto unknown;
-                               if (dp->di_size < 0) {
-                                       if (debug)
-                                               printf("bad size %d:",
-                                                       dp->di_size);
-                                       goto unknown;
-                               }
-                               ndb = howmany(dp->di_size, sblock.fs_bsize);
-                               if (SPECIAL)
-                                       ndb++;
-                               for (j = ndb; j < NDADDR; j++)
-                                       if (dp->di_db[j] != 0) {
-                                               if (debug)
-                                                       printf("bad direct addr: %d\n",
-                                                               dp->di_db[j]);
-                                               goto unknown;
-                                       }
-                               for (j = 0, ndb -= NDADDR; ndb > 0; j++)
-                                       ndb /= NINDIR(&sblock);
-                               for (; j < NIADDR; j++)
-                                       if (dp->di_ib[j] != 0) {
-                                               if (debug)
-                                                       printf("bad indirect addr: %d\n",
-                                                               dp->di_ib[j]);
-                                               goto unknown;
-                                       }
-                               n_files++;
-                               lncntp[inumber] = dp->di_nlink;
-                               if (dp->di_nlink <= 0) {
-                                       if (badlnp < &badlncnt[MAXLNCNT])
-                                               *badlnp++ = inumber;
-                                       else {
-                                               pfatal("LINK COUNT TABLE OVERFLOW");
-                                               if (reply("CONTINUE") == 0)
-                                                       errexit("");
-                                       }
-                               }
-                               statemap[inumber] = DIRCT ? DSTATE : FSTATE;
-                               badblk = dupblk = 0; maxblk = 0;
-                               idesc.id_number = inumber;
-                               idesc.id_filesize = 0;
-                               (void)ckinode(dp, &idesc);
-                               idesc.id_filesize *= btodb(sblock.fs_fsize);
-                               if (dp->di_blocks != idesc.id_filesize) {
-                                       pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)",
-                                           inumber, dp->di_blocks,
-                                           idesc.id_filesize);
-                                       if (preen)
-                                               printf(" (CORRECTED)\n");
-                                       else if (reply("CORRECT") == 0)
-                                               continue;
-                                       dp->di_blocks = idesc.id_filesize;
-                                       inodirty();
-                               }
-                               continue;
-               unknown:
-                               pfatal("UNKNOWN FILE TYPE I=%u", inumber);
-                               if (reply("CLEAR") == 1) {
-                                       zapino(dp);
-                                       inodirty();
-                                       inosumbad++;
-                               }
-                       } else {
-                               if (isset(cgrp.cg_iused, i)) {
-                                       if (debug)
-                                               printf("%d bad, marked used\n",
-                                                   inumber);
-                                       inosumbad++;
-                                       n--;
-                               }
-                               partial = 0;
-                               for (j = 0; j < NDADDR; j++)
-                                       if (dp->di_db[j] != 0)
-                                               partial++;
-                               for (j = 0; j < NIADDR; j++)
-                                       if (dp->di_ib[j] != 0)
-                                               partial++;
-                               if (partial || dp->di_mode != 0 ||
-                                   dp->di_size != 0) {
-                                       pfatal("PARTIALLY ALLOCATED INODE I=%u",
-                                               inumber);
-                                       if (reply("CLEAR") == 1) {
-                                               zapino(dp);
-                                               inodirty();
-                                               inosumbad++;
-                                       }
-                               }
-                       }
-               }
-               if (n != cgrp.cg_cs.cs_nifree) {
-                       if (debug)
-                               printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n",
-                                   c, cgrp.cg_cs.cs_nifree, n);
-                       inosumbad++;
-               }
-               if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree
-                 || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree
-                 || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree
-                 || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir)
-                       sbsumbad++;
-       }
-}
-
-pass1check(idesc)
-       register struct inodesc *idesc;
-{
-       register daddr_t *dlp;
-       int res = KEEPON;
-       int anyout, nfrags;
-       daddr_t blkno = idesc->id_blkno;
-
-       anyout = outrange(blkno, idesc->id_numfrags);
-       for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
-               if (anyout && outrange(blkno, 1)) {
-                       blkerr(idesc->id_number, "BAD", blkno);
-                       if (++badblk >= MAXBAD) {
-                               pwarn("EXCESSIVE BAD BLKS I=%u",
-                                       idesc->id_number);
-                               if (preen)
-                                       printf(" (SKIPPING)\n");
-                               else if (reply("CONTINUE") == 0)
-                                       errexit("");
-                               return (STOP);
-                       }
-                       res = SKIP;
-               } else if (getbmap(blkno)) {
-                       blkerr(idesc->id_number, "DUP", blkno);
-                       if (++dupblk >= MAXDUP) {
-                               pwarn("EXCESSIVE DUP BLKS I=%u",
-                                       idesc->id_number);
-                               if (preen)
-                                       printf(" (SKIPPING)\n");
-                               else if (reply("CONTINUE") == 0)
-                                       errexit("");
-                               return (STOP);
-                       }
-                       if (enddup >= &duplist[DUPTBLSIZE]) {
-                               pfatal("DUP TABLE OVERFLOW.");
-                               if (reply("CONTINUE") == 0)
-                                       errexit("");
-                               return (STOP);
-                       }
-                       for (dlp = duplist; dlp < muldup; dlp++)
-                               if (*dlp == blkno) {
-                                       *enddup++ = blkno;
-                                       break;
-                               }
-                       if (dlp >= muldup) {
-                               *enddup++ = *muldup;
-                               *muldup++ = blkno;
-                       }
-               } else {
-                       n_blks++;
-                       setbmap(blkno);
-               }
-               idesc->id_filesize++;
-       }
-       return (res);
-}
-
-pass1b()
-{
-       register int c, i;
-       register DINODE *dp;
-       struct inodesc idesc;
-       ino_t inumber;
-
-       bzero((char *)&idesc, sizeof(struct inodesc));
-       idesc.id_type = ADDR;
-       idesc.id_func = pass1bcheck;
-       inumber = 0;
-       for (c = 0; c < sblock.fs_ncg; c++) {
-               for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
-                       dp = ginode(inumber);
-                       if (dp == NULL)
-                               continue;
-                       idesc.id_number = inumber;
-                       if (statemap[inumber] != USTATE &&
-                           (ckinode(dp, &idesc) & STOP))
-                               goto out1b;
-               }
-       }
-out1b:
-       flush(&dfile, &inoblk);
-}
-
-pass1bcheck(idesc)
-       register struct inodesc *idesc;
-{
-       register daddr_t *dlp;
-       int nfrags, res = KEEPON;
-       daddr_t blkno = idesc->id_blkno;
-
-       for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
-               if (outrange(blkno, 1))
-                       res = SKIP;
-               for (dlp = duplist; dlp < muldup; dlp++)
-                       if (*dlp == blkno) {
-                               blkerr(idesc->id_number, "DUP", blkno);
-                               *dlp = *--muldup;
-                               *muldup = blkno;
-                               if (muldup == duplist)
-                                       return (STOP);
-                       }
-       }
-       return (res);
-}
-
-pass2()
-{
-       register DINODE *dp;
-       struct inodesc rootdesc;
-
-       bzero((char *)&rootdesc, sizeof(struct inodesc));
-       rootdesc.id_type = ADDR;
-       rootdesc.id_func = pass2check;
-       rootdesc.id_number = ROOTINO;
-       pathp = pathname;
-       switch (statemap[ROOTINO]) {
-
-       case USTATE:
-               errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
-
-       case FSTATE:
-               pfatal("ROOT INODE NOT DIRECTORY");
-               if (reply("FIX") == 0 || (dp = ginode(ROOTINO)) == NULL)
-                       errexit("");
-               dp->di_mode &= ~IFMT;
-               dp->di_mode |= IFDIR;
-               inodirty();
-               inosumbad++;
-               statemap[ROOTINO] = DSTATE;
-               /* fall into ... */
-
-       case DSTATE:
-               descend(&rootdesc, ROOTINO);
-               break;
-
-       case CLEAR:
-               pfatal("DUPS/BAD IN ROOT INODE");
-               printf("\n");
-               if (reply("CONTINUE") == 0)
-                       errexit("");
-               statemap[ROOTINO] = DSTATE;
-               descend(&rootdesc, ROOTINO);
-       }
-}
-
-pass2check(idesc)
-       struct inodesc *idesc;
-{
-       register DIRECT *dirp = idesc->id_dirp;
-       char *curpathloc;
-       int n, entrysize, ret = 0;
-       DINODE *dp;
-       DIRECT proto;
-
-       /* 
-        * check for "."
-        */
-       if (idesc->id_entryno != 0)
-               goto chk1;
-       if (dirp->d_ino != 0 && dirp->d_namlen == 1 && dirp->d_name[0] == '.') {
-               if (dirp->d_ino != idesc->id_number) {
-                       direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'");
-                       dirp->d_ino = idesc->id_number;
-                       if (reply("FIX") == 1)
-                               ret |= ALTERED;
-               }
-               goto chk1;
-       }
-       direrr(idesc->id_number, "MISSING '.'");
-       proto.d_ino = idesc->id_number;
-       proto.d_namlen = 1;
-       (void)strcpy(proto.d_name, ".");
-       entrysize = DIRSIZ(&proto);
-       if (dirp->d_ino != 0) {
-               pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
-                       dirp->d_name);
-       } else if (dirp->d_reclen < entrysize) {
-               pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
-       } else if (dirp->d_reclen < 2 * entrysize) {
-               proto.d_reclen = dirp->d_reclen;
-               bcopy((char *)&proto, (char *)dirp, entrysize);
-               if (reply("FIX") == 1)
-                       ret |= ALTERED;
-       } else {
-               n = dirp->d_reclen - entrysize;
-               proto.d_reclen = entrysize;
-               bcopy((char *)&proto, (char *)dirp, entrysize);
-               idesc->id_entryno++;
-               lncntp[dirp->d_ino]--;
-               dirp = (DIRECT *)((char *)(dirp) + entrysize);
-               bzero((char *)dirp, n);
-               dirp->d_reclen = n;
-               if (reply("FIX") == 1)
-                       ret |= ALTERED;
-       }
-chk1:
-       if (idesc->id_entryno > 1)
-               goto chk2;
-       proto.d_ino = idesc->id_parent;
-       proto.d_namlen = 2;
-       (void)strcpy(proto.d_name, "..");
-       entrysize = DIRSIZ(&proto);
-       if (idesc->id_entryno == 0) {
-               n = DIRSIZ(dirp);
-               if (dirp->d_reclen < n + entrysize)
-                       goto chk2;
-               proto.d_reclen = dirp->d_reclen - n;
-               dirp->d_reclen = n;
-               idesc->id_entryno++;
-               lncntp[dirp->d_ino]--;
-               dirp = (DIRECT *)((char *)(dirp) + n);
-               bzero((char *)dirp, n);
-               dirp->d_reclen = n;
-       }
-       if (dirp->d_ino != 0 && dirp->d_namlen == 2 &&
-           strcmp(dirp->d_name, "..") == 0) {
-               if (dirp->d_ino != idesc->id_parent) {
-                       direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'");
-                       dirp->d_ino = idesc->id_parent;
-                       if (reply("FIX") == 1)
-                               ret |= ALTERED;
-               }
-               goto chk2;
-       }
-       direrr(idesc->id_number, "MISSING '..'");
-       if (dirp->d_ino != 0) {
-               pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
-                       dirp->d_name);
-       } else if (dirp->d_reclen < entrysize) {
-               pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
-       } else {
-               proto.d_reclen = dirp->d_reclen;
-               bcopy((char *)&proto, (char *)dirp, entrysize);
-               if (reply("FIX") == 1)
-                       ret |= ALTERED;
-       }
-chk2:
-       if (dirp->d_ino == 0)
-               return (ret|KEEPON);
-       if (idesc->id_entryno >= 2 &&
-           dirp->d_namlen <= 2 &&
-           dirp->d_name[0] == '.') {
-               if (dirp->d_namlen == 1) {
-                       direrr(idesc->id_number, "EXTRA '.' ENTRY");
-                       dirp->d_ino = 0;
-                       if (reply("FIX") == 1)
-                               ret |= ALTERED;
-                       return (KEEPON | ret);
-               }
-               if (dirp->d_name[1] == '.') {
-                       direrr(idesc->id_number, "EXTRA '..' ENTRY");
-                       dirp->d_ino = 0;
-                       if (reply("FIX") == 1)
-                               ret |= ALTERED;
-                       return (KEEPON | ret);
-               }
-       }
-       curpathloc = pathp;
-       *pathp++ = '/';
-       if (pathp + dirp->d_namlen >= endpathname) {
-               *pathp = '\0';
-               errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
-       }
-       bcopy(dirp->d_name, pathp, dirp->d_namlen + 1);
-       pathp += dirp->d_namlen;
-       idesc->id_entryno++;
-       n = 0;
-       if (dirp->d_ino > imax || dirp->d_ino <= 0) {
-               direrr(dirp->d_ino, "I OUT OF RANGE");
-               n = reply("REMOVE");
-       } else {
-again:
-               switch (statemap[dirp->d_ino]) {
-               case USTATE:
-                       direrr(dirp->d_ino, "UNALLOCATED");
-                       n = reply("REMOVE");
-                       break;
-
-               case CLEAR:
-                       direrr(dirp->d_ino, "DUP/BAD");
-                       if ((n = reply("REMOVE")) == 1)
-                               break;
-                       if ((dp = ginode(dirp->d_ino)) == NULL)
-                               break;
-                       statemap[dirp->d_ino] = DIRCT ? DSTATE : FSTATE;
-                       goto again;
-
-               case FSTATE:
-                       lncntp[dirp->d_ino]--;
-                       break;
-
-               case DSTATE:
-                       descend(idesc, dirp->d_ino);
-                       if (statemap[dirp->d_ino] != CLEAR) {
-                               lncntp[dirp->d_ino]--;
-                       } else {
-                               dirp->d_ino = 0;
-                               ret |= ALTERED;
-                       }
-                       break;
-               }
-       }
-       pathp = curpathloc;
-       *pathp = '\0';
-       if (n == 0)
-               return (ret|KEEPON);
-       dirp->d_ino = 0;
-       return (ret|KEEPON|ALTERED);
-}
-
-pass3()
-{
-       register DINODE *dp;
-       struct inodesc idesc;
-       ino_t inumber, orphan;
-       int loopcnt;
-
-       bzero((char *)&idesc, sizeof(struct inodesc));
-       idesc.id_type = DATA;
-       for (inumber = ROOTINO; inumber <= lastino; inumber++) {
-               if (statemap[inumber] == DSTATE) {
-                       pathp = pathname;
-                       *pathp++ = '?';
-                       *pathp = '\0';
-                       idesc.id_func = findino;
-                       srchname = "..";
-                       idesc.id_parent = inumber;
-                       loopcnt = 0;
-                       do {
-                               orphan = idesc.id_parent;
-                               if ((dp = ginode(orphan)) == NULL)
-                                       break;
-                               idesc.id_parent = 0;
-                               idesc.id_filesize = dp->di_size;
-                               idesc.id_number = orphan;
-                               (void)ckinode(dp, &idesc);
-                               if (idesc.id_parent == 0)
-                                       break;
-                               if (loopcnt >= sblock.fs_cstotal.cs_ndir)
-                                       break;
-                               loopcnt++;
-                       } while (statemap[idesc.id_parent] == DSTATE);
-                       if (linkup(orphan, idesc.id_parent) == 1) {
-                               idesc.id_func = pass2check;
-                               idesc.id_number = lfdir;
-                               descend(&idesc, orphan);
-                       }
-               }
-       }
-}
-
-pass4()
-{
-       register ino_t inumber, *blp;
-       int n;
-       struct inodesc idesc;
-
-       bzero((char *)&idesc, sizeof(struct inodesc));
-       idesc.id_type = ADDR;
-       idesc.id_func = pass4check;
-       for (inumber = ROOTINO; inumber <= lastino; inumber++) {
-               idesc.id_number = inumber;
-               switch (statemap[inumber]) {
-
-               case FSTATE:
-                       n = lncntp[inumber];
-                       if (n)
-                               adjust(&idesc, (short)n);
-                       else {
-                               for (blp = badlncnt;blp < badlnp; blp++)
-                                       if (*blp == inumber) {
-                                               clri(&idesc, "UNREF", 1);
-                                               break;
-                                       }
-                       }
-                       break;
-
-               case DSTATE:
-                       clri(&idesc, "UNREF", 1);
-                       break;
-
-               case CLEAR:
-                       clri(&idesc, "BAD/DUP", 1);
-                       break;
-               }
-       }
-       if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) {
-               pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
-               if (preen)
-                       printf(" (FIXED)\n");
-               if (preen || reply("FIX") == 1) {
-                       sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files;
-                       sbdirty();
-               }
-       }
-       flush(&dfile, &fileblk);
-}
-
-pass4check(idesc)
-       register struct inodesc *idesc;
-{
-       register daddr_t *dlp;
-       int nfrags, res = KEEPON;
-       daddr_t blkno = idesc->id_blkno;
-
-       for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
-               if (outrange(blkno, 1))
-                       res = SKIP;
-               else if (getbmap(blkno)) {
-                       for (dlp = duplist; dlp < enddup; dlp++)
-                               if (*dlp == blkno) {
-                                       *dlp = *--enddup;
-                                       return (KEEPON);
-                               }
-                       clrbmap(blkno);
-                       n_blks--;
-               }
-       }
-       return (res);
-}
-
-pass5()
-{
-       register int c, n, i, b, d;
-       short bo[MAXCPG][NRPOS];
-       long botot[MAXCPG];
-       long frsum[MAXFRAG];
-       int blk;
-       daddr_t cbase;
-       int blockbits = (1<<sblock.fs_frag)-1;
-
-       bcopy(blockmap, freemap, (unsigned)bmapsz);
-       dupblk = 0;
-       n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0));
-       for (c = 0; c < sblock.fs_ncg; c++) {
-               cbase = cgbase(&sblock, c);
-               bzero((char *)botot, sizeof (botot));
-               bzero((char *)bo, sizeof (bo));
-               bzero((char *)frsum, sizeof (frsum));
+               struct statfs stfs_buf;
                /*
                /*
-                * need to account for the super blocks
-                * which appear (inaccurately) bad
+                * We modified the root.  Do a mount update on
+                * it, unless it is read-write, so we can continue.
                 */
                 */
-               n_bad += cgtod(&sblock, c) - cgsblock(&sblock, c);
-               if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
-                       continue;
-               if (cgrp.cg_magic != CG_MAGIC) {
-                       pfatal("CG %d: BAD MAGIC NUMBER\n", c);
-                       bzero((char *)&cgrp, (int)sblock.fs_cgsize);
-               }
-               for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
-                       blk = blkmap(&sblock, cgrp.cg_free, b);
-                       if (blk == 0)
-                               continue;
-                       if (blk == blockbits) {
-                               if (pass5check(cbase+b, sblock.fs_frag) == STOP)
-                                       goto out5;
-                               /* this is clumsy ... */
-                               n_ffree -= sblock.fs_frag;
-                               n_bfree++;
-                               botot[cbtocylno(&sblock, b)]++;
-                               bo[cbtocylno(&sblock, b)]
-                                   [cbtorpos(&sblock, b)]++;
-                               continue;
-                       }
-                       for (d = 0; d < sblock.fs_frag; d++)
-                               if ((blk & (1<<d)) &&
-                                   pass5check(cbase + b + d, (long)1) == STOP)
-                                       goto out5;
-                       fragacct(&sblock, blk, frsum, 1);
-               }
-               if (bcmp((char *)cgrp.cg_frsum, (char *)frsum, sizeof(frsum))) {
-                       if (debug)
-                       for (i = 0; i < sblock.fs_frag; i++)
-                               if (cgrp.cg_frsum[i] != frsum[i])
-                               printf("cg[%d].cg_frsum[%d] have %d calc %d\n",
-                                   c, i, cgrp.cg_frsum[i], frsum[i]);
-                       frsumbad++;
-               }
-               if (bcmp((char *)cgrp.cg_btot, (char *)botot, sizeof (botot))) {
-                       if (debug)
-                       for (n = 0; n < sblock.fs_cpg; n++)
-                               if (botot[n] != cgrp.cg_btot[n])
-                               printf("cg[%d].cg_btot[%d] have %d calc %d\n",
-                                   c, n, cgrp.cg_btot[n], botot[n]);
-                       offsumbad++;
-               }
-               if (bcmp((char *)cgrp.cg_b, (char *)bo, sizeof (bo))) {
-                       if (debug)
-                       for (i = 0; i < NRPOS; i++)
-                               if (bo[n][i] != cgrp.cg_b[n][i])
-                               printf("cg[%d].cg_b[%d][%d] have %d calc %d\n",
-                                   c, n, i, cgrp.cg_b[n][i], bo[n][i]);
-                       offsumbad++;
-               }
-       }
-out5:
-       if (dupblk)
-               pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk);
-       if (fixcg == 0) {
-               if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) {
-                       pwarn("%ld BLK(S) MISSING\n", fmax - b);
-                       fixcg = 1;
-               } else if (inosumbad + offsumbad + frsumbad + sbsumbad) {
-                       pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n",
-                           inosumbad ? "(INODE FREE) " : "",
-                           offsumbad ? "(BLOCK OFFSETS) " : "",
-                           frsumbad ? "(FRAG SUMMARIES) " : "",
-                           sbsumbad ? "(SUPER BLOCK SUMMARIES) " : "");
-                       fixcg = 1;
-               } else if (n_ffree != sblock.fs_cstotal.cs_nffree ||
-                   n_bfree != sblock.fs_cstotal.cs_nbfree) {
-                       pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK");
-                       if (preen)
-                               printf(" (FIXED)\n");
-                       if (preen || reply("FIX") == 1) {
-                               sblock.fs_cstotal.cs_nffree = n_ffree;
-                               sblock.fs_cstotal.cs_nbfree = n_bfree;
-                               sbdirty();
+               if (statfs("/", &stfs_buf) == 0) {
+                       long flags = stfs_buf.f_flags;
+                       struct ufs_args args;
+                       int ret;
+
+                       if (flags & MNT_RDONLY) {
+                               args.fspec = 0;
+                               args.exflags = 0;
+                               args.exroot = 0;
+                               flags |= MNT_UPDATE | MNT_RELOAD;
+                               ret = mount(MOUNT_UFS, "/", flags, &args);
+                               if (ret == 0)
+                                       return(0);
                        }
                }
                        }
                }
+               if (!preen)
+                       printf("\n***** REBOOT NOW *****\n");
+               sync();
+               return (4);
        }
        }
-       if (fixcg) {
-               pwarn("BAD CYLINDER GROUPS");
-               if (preen)
-                       printf(" (SALVAGED)\n");
-               else if (reply("SALVAGE") == 0)
-                       fixcg = 0;
-       }
-}
-
-pass5check(blk, size)
-       daddr_t blk;
-       long size;
-{
-
-       if (outrange(blk, (int)size)) {
-               fixcg = 1;
-               if (preen)
-                       pfatal("BAD BLOCKS IN BIT MAPS.");
-               if (++badblk >= MAXBAD) {
-                       printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
-                       if (reply("CONTINUE") == 0)
-                               errexit("");
-                       return (STOP);
-               }
-       }
-       for (; size > 0; blk++, size--)
-               if (getfmap(blk)) {
-                       fixcg = 1;
-                       ++dupblk;
-               } else {
-                       n_ffree++;
-                       setfmap(blk);
-               }
-       return (KEEPON);
-}
-
-ckinode(dp, idesc)
-       DINODE *dp;
-       register struct inodesc *idesc;
-{
-       register daddr_t *ap;
-       int ret, n, ndb, offset;
-       DINODE dino;
-
-       if (SPECIAL)
-               return (KEEPON);
-       dino = *dp;
-       idesc->id_fix = DONTKNOW;
-       idesc->id_entryno = 0;
-       ndb = howmany(dino.di_size, sblock.fs_bsize);
-       for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
-               if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
-                       idesc->id_numfrags =
-                               numfrags(&sblock, fragroundup(&sblock, offset));
-               else
-                       idesc->id_numfrags = sblock.fs_frag;
-               if (*ap == 0)
-                       continue;
-               idesc->id_blkno = *ap;
-               if (idesc->id_type == ADDR)
-                       ret = (*idesc->id_func)(idesc);
-               else
-                       ret = dirscan(idesc);
-               if (ret & STOP)
-                       return (ret);
-       }
-       idesc->id_numfrags = sblock.fs_frag;
-       for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) {
-               if (*ap) {
-                       idesc->id_blkno = *ap;
-                       ret = iblock(idesc, n,
-                               dino.di_size - sblock.fs_bsize * NDADDR);
-                       if (ret & STOP)
-                               return (ret);
-               }
-       }
-       return (KEEPON);
-}
-
-iblock(idesc, ilevel, isize)
-       struct inodesc *idesc;
-       register ilevel;
-       long isize;
-{
-       register daddr_t *ap;
-       register daddr_t *aplim;
-       int i, n, (*func)(), nif;
-       BUFAREA ib;
-
-       if (idesc->id_type == ADDR) {
-               func = idesc->id_func;
-               if (((n = (*func)(idesc)) & KEEPON) == 0)
-                       return (n);
-       } else
-               func = dirscan;
-       if (outrange(idesc->id_blkno, idesc->id_numfrags)) /* protect thyself */
-               return (SKIP);
-       initbarea(&ib);
-       if (getblk(&ib, idesc->id_blkno, sblock.fs_bsize) == NULL)
-               return (SKIP);
-       ilevel--;
-       if (ilevel == 0) {
-               nif = lblkno(&sblock, isize) + 1;
-       } else /* ilevel == 1 */ {
-               nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1;
-       }
-       if (nif > NINDIR(&sblock))
-               nif = NINDIR(&sblock);
-       aplim = &ib.b_un.b_indir[nif];
-       for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
-               if (*ap) {
-                       idesc->id_blkno = *ap;
-                       if (ilevel > 0)
-                               n = iblock(idesc, ilevel,
-                                   isize - i*NINDIR(&sblock)*sblock.fs_bsize);
-                       else
-                               n = (*func)(idesc);
-                       if (n & STOP)
-                               return (n);
-               }
-       return (KEEPON);
-}
-
-outrange(blk, cnt)
-       daddr_t blk;
-       int cnt;
-{
-       register int c;
-
-       if ((unsigned)(blk+cnt) > fmax)
-               return (1);
-       c = dtog(&sblock, blk);
-       if (blk < cgdmin(&sblock, c)) {
-               if ((blk+cnt) > cgsblock(&sblock, c)) {
-                       if (debug) {
-                               printf("blk %d < cgdmin %d;",
-                                   blk, cgdmin(&sblock, c));
-                               printf(" blk+cnt %d > cgsbase %d\n",
-                                   blk+cnt, cgsblock(&sblock, c));
-                       }
-                       return (1);
-               }
-       } else {
-               if ((blk+cnt) > cgbase(&sblock, c+1)) {
-                       if (debug)  {
-                               printf("blk %d >= cgdmin %d;",
-                                   blk, cgdmin(&sblock, c));
-                               printf(" blk+cnt %d > sblock.fs_fpg %d\n",
-                                   blk+cnt, sblock.fs_fpg);
-                       }
-                       return (1);
-               }
-       }
-       return (0);
-}
-
-blkerr(ino, s, blk)
-       ino_t ino;
-       char *s;
-       daddr_t blk;
-{
-
-       pfatal("%ld %s I=%u", blk, s, ino);
-       printf("\n");
-       statemap[ino] = CLEAR;
-}
-
-descend(parentino, inumber)
-       struct inodesc *parentino;
-       ino_t inumber;
-{
-       register DINODE *dp;
-       struct inodesc curino;
-
-       bzero((char *)&curino, sizeof(struct inodesc));
-       statemap[inumber] = FSTATE;
-       if ((dp = ginode(inumber)) == NULL)
-               return;
-       if (dp->di_size == 0) {
-               direrr(inumber, "ZERO LENGTH DIRECTORY");
-               if (reply("REMOVE") == 1)
-                       statemap[inumber] = CLEAR;
-               return;
-       }
-       if (dp->di_size < MINDIRSIZE) {
-               direrr(inumber, "DIRECTORY TOO SHORT");
-               dp->di_size = MINDIRSIZE;
-               if (reply("FIX") == 1)
-                       inodirty();
-       }
-       curino.id_type = DATA;
-       curino.id_func = parentino->id_func;
-       curino.id_parent = parentino->id_number;
-       curino.id_number = inumber;
-       curino.id_filesize = dp->di_size;
-       (void)ckinode(dp, &curino);
-}
-
-dirscan(idesc)
-       register struct inodesc *idesc;
-{
-       register DIRECT *dp;
-       int dsize, n;
-       long blksiz;
-       char dbuf[DIRBLKSIZ];
-
-       if (idesc->id_type != DATA)
-               errexit("wrong type to dirscan %d\n", idesc->id_type);
-       blksiz = idesc->id_numfrags * sblock.fs_fsize;
-       if (outrange(idesc->id_blkno, idesc->id_numfrags)) {
-               idesc->id_filesize -= blksiz;
-               return (SKIP);
-       }
-       idesc->id_loc = 0;
-       for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
-               dsize = dp->d_reclen;
-               bcopy((char *)dp, dbuf, dsize);
-               idesc->id_dirp = (DIRECT *)dbuf;
-               if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
-                       if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) {
-                               bcopy(dbuf, (char *)dp, dsize);
-                               dirty(&fileblk);
-                               sbdirty();
-                       } else
-                               n &= ~ALTERED;
-               }
-               if (n & STOP) 
-                       return (n);
-       }
-       return (idesc->id_filesize > 0 ? KEEPON : STOP);
-}
-
-/*
- * get next entry in a directory.
- */
-DIRECT *
-fsck_readdir(idesc)
-       register struct inodesc *idesc;
-{
-       register DIRECT *dp, *ndp;
-       long size, blksiz;
-
-       blksiz = idesc->id_numfrags * sblock.fs_fsize;
-       if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) {
-               idesc->id_filesize -= blksiz - idesc->id_loc;
-               return NULL;
-       }
-       if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
-           idesc->id_loc < blksiz) {
-               dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
-               if (dircheck(idesc, dp))
-                       goto dpok;
-               idesc->id_loc += DIRBLKSIZ;
-               idesc->id_filesize -= DIRBLKSIZ;
-               dp->d_reclen = DIRBLKSIZ;
-               dp->d_ino = 0;
-               dp->d_namlen = 0;
-               dp->d_name[0] = '\0';
-               if (dofix(idesc))
-                       dirty(&fileblk);
-               return (dp);
-       }
-dpok:
-       if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
-               return NULL;
-       dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
-       idesc->id_loc += dp->d_reclen;
-       idesc->id_filesize -= dp->d_reclen;
-       ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
-       if ((idesc->id_filesize <= 0 && idesc->id_loc % DIRBLKSIZ != 0) ||
-           (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
-            dircheck(idesc, ndp) == 0)) {
-               size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
-               dp->d_reclen += size;
-               idesc->id_loc += size;
-               idesc->id_filesize -= size;
-               if (dofix(idesc))
-                       dirty(&fileblk);
-       }
-       return (dp);
-}
-
-/*
- * Verify that a directory entry is valid.
- * This is a superset of the checks made in the kernel.
- */
-dircheck(idesc, dp)
-       struct inodesc *idesc;
-       register DIRECT *dp;
-{
-       register int size;
-       register char *cp;
-       int spaceleft;
-
-       size = DIRSIZ(dp);
-       spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
-       if (dp->d_ino < imax &&
-           dp->d_reclen != 0 &&
-           dp->d_reclen <= spaceleft &&
-           (dp->d_reclen & 0x3) == 0 &&
-           dp->d_reclen >= size &&
-           idesc->id_filesize >= size &&
-           dp->d_namlen <= MAXNAMLEN) {
-               if (dp->d_ino == 0)
-                       return (1);
-               for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++)
-                       if (*cp == 0 || (*cp++ & 0200))
-                               return (0);
-               if (*cp == 0)
-                       return (1);
-       }
-       return (0);
-}
-
-direrr(ino, s)
-       ino_t ino;
-       char *s;
-{
-       register DINODE *dp;
-
-       pwarn("%s ", s);
-       pinode(ino);
-       printf("\n");
-       if ((dp = ginode(ino)) != NULL && ftypeok(dp))
-               pfatal("%s=%s\n", DIRCT?"DIR":"FILE", pathname);
-       else
-               pfatal("NAME=%s\n", pathname);
-}
-
-adjust(idesc, lcnt)
-       register struct inodesc *idesc;
-       short lcnt;
-{
-       register DINODE *dp;
-
-       if ((dp = ginode(idesc->id_number)) == NULL)
-               return;
-       if (dp->di_nlink == lcnt) {
-               if (linkup(idesc->id_number, (ino_t)0) == 0)
-                       clri(idesc, "UNREF", 0);
-       }
-       else {
-               pwarn("LINK COUNT %s",
-                       (lfdir==idesc->id_number)?lfname:(DIRCT?"DIR":"FILE"));
-               pinode(idesc->id_number);
-               printf(" COUNT %d SHOULD BE %d",
-                       dp->di_nlink, dp->di_nlink-lcnt);
-               if (preen) {
-                       if (lcnt < 0) {
-                               printf("\n");
-                               preendie();
-                       }
-                       printf(" (ADJUSTED)\n");
-               }
-               if (preen || reply("ADJUST") == 1) {
-                       dp->di_nlink -= lcnt;
-                       inodirty();
-               }
-       }
-}
-
-clri(idesc, s, flg)
-       register struct inodesc *idesc;
-       char *s;
-       int flg;
-{
-       register DINODE *dp;
-
-       if ((dp = ginode(idesc->id_number)) == NULL)
-               return;
-       if (flg == 1) {
-               pwarn("%s %s", s, DIRCT?"DIR":"FILE");
-               pinode(idesc->id_number);
-       }
-       if (preen || reply("CLEAR") == 1) {
-               if (preen)
-                       printf(" (CLEARED)\n");
-               n_files--;
-               (void)ckinode(dp, idesc);
-               zapino(dp);
-               statemap[idesc->id_number] = USTATE;
-               inodirty();
-               inosumbad++;
-       }
-}
-
-badsb(s)
-       char *s;
-{
-
-       if (preen)
-               printf("%s: ", devname);
-       printf("BAD SUPER BLOCK: %s\n", s);
-       pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
-       pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
-}
-
-DINODE *
-ginode(inumber)
-       ino_t inumber;
-{
-       daddr_t iblk;
-       static ino_t startinum = 0;     /* blk num of first in raw area */
-
-
-       if (inumber < ROOTINO || inumber > imax) {
-               if (debug && inumber > imax)
-                       printf("inumber out of range (%d)\n", inumber);
-               return (NULL);
-       }
-       if (startinum == 0 ||
-           inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
-               iblk = itod(&sblock, inumber);
-               if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
-                       return (NULL);
-               }
-               startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
-       }
-       return (&inoblk.b_un.b_dinode[inumber % INOPB(&sblock)]);
-}
-
-ftypeok(dp)
-       DINODE *dp;
-{
-       switch (dp->di_mode & IFMT) {
-
-       case IFDIR:
-       case IFREG:
-       case IFBLK:
-       case IFCHR:
-       case IFLNK:
-       case IFSOCK:
-               return (1);
-
-       default:
-               if (debug)
-                       printf("bad file type 0%o\n", dp->di_mode);
-               return (0);
-       }
-}
-
-reply(s)
-       char *s;
-{
-       char line[80];
-
-       if (preen)
-               pfatal("INTERNAL ERROR: GOT TO reply()");
-       rplyflag = 1;
-       printf("\n%s? ", s);
-       if (nflag || dfile.wfdes < 0) {
-               printf(" no\n\n");
-               return (0);
-       }
-       if (yflag) {
-               printf(" yes\n\n");
-               return (1);
-       }
-       if (getline(stdin, line, sizeof(line)) == EOF)
-               errexit("\n");
-       printf("\n");
-       if (line[0] == 'y' || line[0] == 'Y')
-               return (1);
-       else
-               return (0);
-}
-
-getline(fp, loc, maxlen)
-       FILE *fp;
-       char *loc;
-{
-       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;
-       }
-       *p = 0;
-       return (p - loc);
-}
-
-BUFAREA *
-getblk(bp, blk, size)
-       register BUFAREA *bp;
-       daddr_t blk;
-       long size;
-{
-       register struct filecntl *fcp;
-       daddr_t dblk;
-
-       fcp = &dfile;
-       dblk = fsbtodb(&sblock, blk);
-       if (bp->b_bno == dblk)
-               return (bp);
-       flush(fcp, bp);
-       if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
-               bp->b_bno = dblk;
-               bp->b_size = size;
-               return (bp);
-       }
-       bp->b_bno = (daddr_t)-1;
-       return (NULL);
-}
-
-flush(fcp, bp)
-       struct filecntl *fcp;
-       register BUFAREA *bp;
-{
-
-       if (bp->b_dirty)
-               (void)bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
-       bp->b_dirty = 0;
-}
-
-rwerr(s, blk)
-       char *s;
-       daddr_t blk;
-{
-
-       if (preen == 0)
-               printf("\n");
-       pfatal("CANNOT %s: BLK %ld", s, blk);
-       if (reply("CONTINUE") == 0)
-               errexit("Program terminated\n");
-}
-
-ckfini()
-{
-
-       flush(&dfile, &fileblk);
-       flush(&dfile, &sblk);
-       if (sblk.b_bno != SBLOCK) {
-               sblk.b_bno = SBLOCK;
-               sbdirty();
-               flush(&dfile, &sblk);
-       }
-       flush(&dfile, &inoblk);
-       (void)close(dfile.rfdes);
-       (void)close(dfile.wfdes);
-}
-
-pinode(ino)
-       ino_t ino;
-{
-       register DINODE *dp;
-       register char *p;
-       char uidbuf[BUFSIZ];
-       char *ctime();
-
-       printf(" I=%u ", ino);
-       if ((dp = ginode(ino)) == NULL)
-               return;
-       printf(" OWNER=");
-       if (getpw((int)dp->di_uid, uidbuf) == 0) {
-               for (p = uidbuf; *p != ':'; p++);
-               *p = 0;
-               printf("%s ", uidbuf);
-       }
-       else {
-               printf("%d ", dp->di_uid);
-       }
-       printf("MODE=%o\n", dp->di_mode);
-       if (preen)
-               printf("%s: ", devname);
-       printf("SIZE=%ld ", dp->di_size);
-       p = ctime(&dp->di_mtime);
-       printf("MTIME=%12.12s %4.4s ", p+4, p+20);
-}
-
-makecg()
-{
-       int c, blk;
-       daddr_t dbase, d, dlower, dupper, dmax;
-       long i, j, s;
-       ino_t inumber;
-       register struct csum *cs;
-       register DINODE *dp;
-
-       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++) {
-               dbase = cgbase(&sblock, c);
-               dmax = dbase + sblock.fs_fpg;
-               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);
-               (void)time(&cgrp.cg_time);
-               cgrp.cg_magic = CG_MAGIC;
-               cgrp.cg_cgx = c;
-               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_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;
-               inumber = sblock.fs_ipg * c;
-               for (i = 0; i < sblock.fs_ipg; inumber++, i++) {
-                       cgrp.cg_cs.cs_nifree++;
-                       clrbit(cgrp.cg_iused, i);
-                       dp = ginode(inumber);
-                       if (dp == NULL)
-                               continue;
-                       if (ALLOC) {
-                               if (DIRCT)
-                                       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++;
-               }
-               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;
-               }
-               if (c == 0) {
-                       dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
-               }
-               for (d = dlower; d < dupper; d++)
-                       clrbit(cgrp.cg_free, d);
-               for (d = 0; (d + sblock.fs_frag) <= dmax - dbase;
-                   d += sblock.fs_frag) {
-                       j = 0;
-                       for (i = 0; i < sblock.fs_frag; i++) {
-                               if (!getbmap(dbase + d + i)) {
-                                       setbit(cgrp.cg_free, d + i);
-                                       j++;
-                               } else
-                                       clrbit(cgrp.cg_free, d+i);
-                       }
-                       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 (j = d; d < dmax - dbase; d++) {
-                       if (!getbmap(dbase + d)) {
-                               setbit(cgrp.cg_free, d);
-                               cgrp.cg_cs.cs_nffree++;
-                       } else
-                               clrbit(cgrp.cg_free, d);
-               }
-               for (; d % sblock.fs_frag != 0; d++)
-                       clrbit(cgrp.cg_free, d);
-               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;
-               (void)bwrite(&dfile, (char *)&cgrp,
-                       fsbtodb(&sblock, cgtod(&sblock, c)), sblock.fs_cgsize);
-       }
-       for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
-               (void)bwrite(&dfile, (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);
-       }
-       sblock.fs_ronly = 0;
-       sblock.fs_fmod = 0;
-       sbdirty();
-}
-
-findino(idesc)
-       struct inodesc *idesc;
-{
-       register DIRECT *dirp = idesc->id_dirp;
-
-       if (dirp->d_ino == 0)
-               return (KEEPON);
-       if (!strcmp(dirp->d_name, srchname)) {
-               if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
-                       idesc->id_parent = dirp->d_ino;
-               return (STOP);
-       }
-       return (KEEPON);
-}
-
-mkentry(idesc)
-       struct inodesc *idesc;
-{
-       register DIRECT *dirp = idesc->id_dirp;
-       DIRECT newent;
-       int newlen, oldlen;
-
-       newent.d_namlen = 11;
-       newlen = DIRSIZ(&newent);
-       if (dirp->d_ino != 0)
-               oldlen = DIRSIZ(dirp);
-       else
-               oldlen = 0;
-       if (dirp->d_reclen - oldlen < newlen)
-               return (KEEPON);
-       newent.d_reclen = dirp->d_reclen - oldlen;
-       dirp->d_reclen = oldlen;
-       dirp = (struct direct *)(((char *)dirp) + oldlen);
-       dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
-       dirp->d_reclen = newent.d_reclen;
-       dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent);
-       return (ALTERED|STOP);
-}
-
-chgdd(idesc)
-       struct inodesc *idesc;
-{
-       register DIRECT *dirp = idesc->id_dirp;
-
-       if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
-       dirp->d_name[2] == 0) {
-               dirp->d_ino = lfdir;
-               return (ALTERED|STOP);
-       }
-       return (KEEPON);
-}
-
-linkup(orphan, pdir)
-       ino_t orphan;
-       ino_t pdir;
-{
-       register DINODE *dp;
-       int lostdir, len;
-       struct inodesc idesc;
-
-       bzero((char *)&idesc, sizeof(struct inodesc));
-       if ((dp = ginode(orphan)) == NULL)
-               return (0);
-       lostdir = DIRCT;
-       pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
-       pinode(orphan);
-       if (preen && dp->di_size == 0)
-               return (0);
-       if (preen)
-               printf(" (RECONNECTED)\n");
-       else
-               if (reply("RECONNECT") == 0)
-                       return (0);
-       pathp = pathname;
-       *pathp++ = '/';
-       *pathp = '\0';
-       if (lfdir == 0) {
-               if ((dp = ginode(ROOTINO)) == NULL)
-                       return (0);
-               srchname = lfname;
-               idesc.id_type = DATA;
-               idesc.id_func = findino;
-               idesc.id_number = ROOTINO;
-               idesc.id_filesize = dp->di_size;
-               (void)ckinode(dp, &idesc);
-               if ((lfdir = idesc.id_parent) == 0) {
-                       pfatal("SORRY. NO lost+found DIRECTORY");
-                       printf("\n\n");
-                       return (0);
-               }
-       }
-       if ((dp = ginode(lfdir)) == NULL ||
-            !DIRCT || statemap[lfdir] != FSTATE) {
-               pfatal("SORRY. NO lost+found DIRECTORY");
-               printf("\n\n");
-               return (0);
-       }
-       if (fragoff(&sblock, dp->di_size)) {
-               dp->di_size = fragroundup(&sblock, dp->di_size);
-               inodirty();
-       }
-       len = strlen(lfname);
-       bcopy(lfname, pathp, len + 1);
-       pathp += len;
-       idesc.id_type = DATA;
-       idesc.id_func = mkentry;
-       idesc.id_number = lfdir;
-       idesc.id_filesize = dp->di_size;
-       idesc.id_parent = orphan;       /* this is the inode to enter */
-       idesc.id_fix = DONTKNOW;
-       if ((ckinode(dp, &idesc) & ALTERED) == 0) {
-               pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
-               printf("\n\n");
-               return (0);
-       }
-       lncntp[orphan]--;
-       *pathp++ = '/';
-       pathp += lftempname(pathp, orphan);
-       if (lostdir) {
-               dp = ginode(orphan);
-               idesc.id_type = DATA;
-               idesc.id_func = chgdd;
-               idesc.id_number = orphan;
-               idesc.id_filesize = dp->di_size;
-               idesc.id_fix = DONTKNOW;
-               (void)ckinode(dp, &idesc);
-               if ((dp = ginode(lfdir)) != NULL) {
-                       dp->di_nlink++;
-                       inodirty();
-                       lncntp[lfdir]++;
-               }
-               pwarn("DIR I=%u CONNECTED. ", orphan);
-               printf("PARENT WAS I=%u\n", pdir);
-               if (preen == 0)
-                       printf("\n");
-       }
-       return (1);
-}
-
-/*
- * generate a temporary name for the lost+found directory.
- */
-lftempname(bufp, ino)
-       char *bufp;
-       ino_t ino;
-{
-       register ino_t in;
-       register char *cp;
-       int namlen;
-
-       cp = bufp + 2;
-       for (in = imax; in > 0; in /= 10)
-               cp++;
-       *--cp = 0;
-       namlen = cp - bufp;
-       in = ino;
-       while (cp > bufp) {
-               *--cp = (in % 10) + '0';
-               in /= 10;
-       }
-       *cp = '#';
-       return (namlen);
-}
-
-bread(fcp, buf, blk, size)
-       register struct filecntl *fcp;
-       char *buf;
-       daddr_t blk;
-       long size;
-{
-       if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
-               rwerr("SEEK", blk);
-       else if (read(fcp->rfdes, buf, (int)size) == size)
-               return (1);
-       rwerr("READ", blk);
-       return (0);
-}
-
-bwrite(fcp, buf, blk, size)
-       register struct filecntl *fcp;
-       char *buf;
-       daddr_t blk;
-       long size;
-{
-
-       if (fcp->wfdes < 0)
-               return (0);
-       if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
-               rwerr("SEEK", blk);
-       else if (write(fcp->wfdes, buf, (int)size) == size) {
-               fcp->mod = 1;
-               return (1);
-       }
-       rwerr("WRITE", blk);
        return (0);
 }
        return (0);
 }
-
-catch()
-{
-
-       ckfini();
-       exit(12);
-}
-
-char *
-unrawname(cp)
-       char *cp;
-{
-       char *dp = rindex(cp, '/');
-       struct stat stb;
-
-       if (dp == 0)
-               return (cp);
-       if (stat(cp, &stb) < 0)
-               return (cp);
-       if ((stb.st_mode&S_IFMT) != S_IFCHR)
-               return (cp);
-       if (*(dp+1) != 'r')
-               return (cp);
-       (void)strcpy(dp+1, dp+2);
-       return (cp);
-}
-
-char *
-rawname(cp)
-       char *cp;
-{
-       static char rawbuf[32];
-       char *dp = rindex(cp, '/');
-
-       if (dp == 0)
-               return (0);
-       *dp = 0;
-       (void)strcpy(rawbuf, cp);
-       *dp = '/';
-       (void)strcat(rawbuf, "/r");
-       (void)strcat(rawbuf, dp+1);
-       return (rawbuf);
-}
-
-/*
- * determine whether an inode should be fixed.
- */
-dofix(idesc)
-       register struct inodesc *idesc;
-{
-
-       switch (idesc->id_fix) {
-
-       case DONTKNOW:
-               direrr(idesc->id_number, "DIRECTORY CORRUPTED");
-               if (reply("SALVAGE") == 0) {
-                       idesc->id_fix = NOFIX;
-                       return (0);
-               }
-               idesc->id_fix = FIX;
-               return (ALTERED);
-
-       case FIX:
-               return (ALTERED);
-
-       case NOFIX:
-               return (0);
-
-       default:
-               errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
-       }
-       /* NOTREACHED */
-}
-
-/* VARARGS1 */
-error(s1, s2, s3, s4)
-       char *s1;
-{
-
-       printf(s1, s2, s3, s4);
-}
-
-/* VARARGS1 */
-errexit(s1, s2, s3, s4)
-       char *s1;
-{
-       error(s1, s2, s3, s4);
-       exit(8);
-}
-
-/*
- * An inconsistency occured which shouldn't during normal operations.
- * Die if preening, otherwise just printf.
- */
-/* VARARGS1 */
-pfatal(s, a1, a2, a3)
-       char *s;
-{
-
-       if (preen) {
-               printf("%s: ", devname);
-               printf(s, a1, a2, a3);
-               printf("\n");
-               preendie();
-       }
-       printf(s, a1, a2, a3);
-}
-
-preendie()
-{
-
-       printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
-       exit(8);
-}
-
-/*
- * Pwarn is like printf when not preening,
- * or a warning (preceded by filename) when preening.
- */
-/* VARARGS1 */
-pwarn(s, a1, a2, a3, a4, a5, a6)
-       char *s;
-{
-
-       if (preen)
-               printf("%s: ", devname);
-       printf(s, a1, a2, a3, a4, a5, a6);
-}
-
-#ifndef lint
-/*
- * Stub for routines from kernel.
- */
-panic(s)
-       char *s;
-{
-
-       pfatal("INTERNAL INCONSISTENCY: %s\n", s);
-       exit(12);
-}
-#endif