X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/1a724405d4d02a60e48d07564542d251ccdbf7d6..ad7871609881e73855d0b04da49b486cd93efca7:/usr/src/sbin/fsck/main.c diff --git a/usr/src/sbin/fsck/main.c b/usr/src/sbin/fsck/main.c index 4fcf4cfa3b..e44a86d0cb 100644 --- a/usr/src/sbin/fsck/main.c +++ b/usr/src/sbin/fsck/main.c @@ -1,346 +1,190 @@ +/* + * 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 -char version[] = "@(#)main.c 2.27 (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 -#include #include -#include -#include -#include -#include +#include +#include +#include +#include #include -#define KERNEL -#include -#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 +#include +#include +#include +#include "fsck.h" -char *devname; +void catch(), catchquit(), voidquit(); +int returntosingle; 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(); - while (--argc > 0 && **++argv == '-') { - switch (*++*argv) { - + while ((ch = getopt(argc, argv, "dpnNyYb:c:l:m:")) != EOF) { + switch (ch) { 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; + case 'c': + cvtlevel = argtoi('c', "conversion level", optarg, 10); + 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 'y': /* default yes answer flag */ + case 'y': 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 (preen) + (void)signal(SIGQUIT, catchquit); if (argc) { - while (argc-- > 0) { - hotroot = 0; - checkfilesys(*argv++); - } + while (argc-- > 0) + (void)checkfilesys(blockcheck(*argv++), 0, 0L, 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."); - 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) @@ -349,1920 +193,126 @@ checkfilesys(filesys) } 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(); } -/* 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(); -/* 3: scan inodes looking for disconnected directories */ + /* + * 3: scan inodes looking for disconnected directories + */ 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(); -/* 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 (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(); } + 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); - free(freemap); free(statemap); free((char *)lncntp); - if (!dfile.mod) - return; - if (!preen) { + if (!fsmodified) + return (0); + if (!preen) printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); - if (hotroot) - printf("\n***** REBOOT UNIX *****\n"); - } 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; - ret |= dofix(idesc); - } - 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); - ret |= dofix(idesc); - } 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; - ret |= dofix(idesc); - } -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; - ret |= dofix(idesc); - } - 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); - ret |= dofix(idesc); - } -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; - return (KEEPON | dofix(idesc)); - } - if (dirp->d_name[1] == '.') { - direrr(idesc->id_number, "EXTRA '..' ENTRY"); - dirp->d_ino = 0; - return (KEEPON | dofix(idesc)); - } - } - 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 len; - - bzero((char *)&idesc, sizeof(struct inodesc)); - idesc.id_type = DATA; - for (inumber = ROOTINO; inumber <= lastino; inumber++) { - if (statemap[inumber] == DSTATE) { - idesc.id_func = findino; - srchname = ".."; - idesc.id_parent = inumber; - 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; - } while (statemap[idesc.id_parent] == DSTATE); - if (linkup(orphan, idesc.id_parent) == 1) { - pathp = pathname; - *pathp++ = '/'; - len = strlen(lfname); - bcopy(lfname, pathp, len + 1); - pathp += len; - *pathp++ = '/'; - pathp += lftempname(pathp, orphan); - 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<= 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); - } + if (!preen) + printf("\n***** REBOOT NOW *****\n"); + sync(); + return (4); } 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 (idesc->id_fix == DONTKNOW) - direrr(idesc->id_number, "DIRECTORY CORRUPTED"); - 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 (idesc->id_fix == DONTKNOW) - direrr(idesc->id_number, "DIRECTORY CORRUPTED"); - 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; - register lostdir; - 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); - 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(); - } - 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 */ - if ((ckinode(dp, &idesc) & ALTERED) == 0) { - pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); - printf("\n\n"); - return (0); - } - lncntp[orphan]--; - if (lostdir) { - dp = ginode(orphan); - idesc.id_type = DATA; - idesc.id_func = chgdd; - idesc.id_number = orphan; - idesc.id_filesize = dp->di_size; - (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); -} - -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: - if (reply("FIX") == 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