X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/6c74eac8457a041fac26f978e5260346a5ff6979..e2326c44aa7105886be6e0b2d2ce507b1f588540:/usr/src/sbin/fsck/main.c diff --git a/usr/src/sbin/fsck/main.c b/usr/src/sbin/fsck/main.c index 67368836d0..37170372cf 100644 --- a/usr/src/sbin/fsck/main.c +++ b/usr/src/sbin/fsck/main.c @@ -1,13 +1,18 @@ -char version[] = "@(#)main.c 2.17 (Berkeley) %G%"; +#ifndef lint +char version[] = "@(#)main.c 2.30 (Berkeley) %G%"; +#endif #include #include #include #include #include -#include #include +#include #include +#define KERNEL +#include +#undef KERNEL /* RECONSTRUCT ONLY BAD CG IN PASS 6 */ @@ -16,6 +21,7 @@ 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) */ @@ -34,10 +40,10 @@ typedef struct direct DIRECT; #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) -ino_t startinum; /* blk num of first in raw area */ - struct bufarea { struct bufarea *b_next; /* must be first */ daddr_t b_bno; @@ -58,7 +64,7 @@ typedef struct bufarea BUFAREA; BUFAREA inoblk; /* inode blocks */ BUFAREA fileblk; /* other blks in filesys */ BUFAREA sblk; /* file system superblock */ -BUFAREA cgblk; +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 @@ -76,12 +82,30 @@ struct filecntl { 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 50 /* num zero link cnts to remember */ +#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 */ @@ -100,22 +124,17 @@ char *freemap; /* ptr to secondary blk allocation map */ char *statemap; /* ptr to inode state table */ short *lncntp; /* ptr to link count table */ -char *pathp; /* pointer to pathname position */ -char *thisname; /* ptr to current pathname component */ char *srchname; /* name being searched for in dir */ -char pathname[BUFSIZ]; +char pathname[BUFSIZ]; /* current pathname */ +char *pathp; /* pointer to pathname position */ +char *endpathname = &pathname[BUFSIZ - 2]; char *lfname = "lost+found"; -ino_t inum; /* inode we are currently working on */ -ino_t dnum; /* directory inode currently being worked on */ ino_t imax; /* number of inodes */ -ino_t parentdir; /* i number of parent directory */ ino_t lastino; /* hiwater mark of inodes */ ino_t lfdir; /* lost & found directory */ -ino_t orphan; /* orphaned inode */ -off_t filsize; /* num blks seen in file */ off_t maxblk; /* largest logical blk in file */ off_t bmapsz; /* num chars in blockmap */ @@ -146,10 +165,7 @@ struct dinode zino; #define getfmap(x) isset(freemap, x) #define clrfmap(x) clrbit(freemap, x) -#define DATA 1 -#define ADDR 0 - -#define ALTERD 010 +#define ALTERED 010 #define KEEPON 04 #define SKIP 02 #define STOP 01 @@ -158,15 +174,13 @@ int (*signal())(); long lseek(); time_t time(); DINODE *ginode(); +DIRECT *fsck_readdir(); BUFAREA *getblk(); -int dirscan(); -int findino(); int catch(); -int mkentry(); -int chgdd(); -int pass1check(), pass1bcheck(), pass2check(), pass4check(), pass5check(); -int (*pfunc)(); -char *rawname(), *rindex(), *unrawname(); +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[]; @@ -188,7 +202,12 @@ main(argc, argv) break; case 'b': - bflag = atoi(argv[0]+1); + if (argv[0][1] != '\0') { + bflag = atoi(argv[0]+1); + } else { + bflag = atoi(*++argv); + argc--; + } printf("Alternate super block location: %d\n", bflag); break; @@ -213,7 +232,7 @@ main(argc, argv) } } if (signal(SIGINT, SIG_IGN) != SIG_IGN) - signal(SIGINT, catch); + (void)signal(SIGINT, catch); if (argc) { while (argc-- > 0) { hotroot = 0; @@ -229,7 +248,8 @@ main(argc, argv) 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_RO) && + strcmp(fsp->fs_type, FSTAB_RQ)) continue; if (preen == 0 || passno == 1 && fsp->fs_passno == passno) { @@ -251,15 +271,15 @@ main(argc, argv) } } if (preen) { - int status; + union wait status; while (wait(&status) != -1) - sumstatus |= status; + sumstatus |= status.w_retcode; } passno++; } while (anygtr); if (sumstatus) exit(8); - endfsent(); + (void)endfsent(); exit(0); } @@ -313,12 +333,6 @@ retry: checkfilesys(filesys) char *filesys; { - register DINODE *dp; - register ino_t *blp; - register int i, n; - ino_t savino; - int b, c, j, partial, ndb; - daddr_t d, s; devname = filesys; if (setup(filesys) == 0) { @@ -343,22 +357,22 @@ checkfilesys(filesys) pass1b(); } -/* 2: traverse directories to check reference counts */ +/* 2: traverse directories from root to mark all connected directories */ if (preen == 0) printf("** Phase 2 - Check Pathnames\n"); pass2(); -/* 3 */ +/* 3: scan inodes looking for disconnected directories */ if (preen == 0) printf("** Phase 3 - Check Connectivity\n"); pass3(); -/* 4 */ +/* 4: scan inodes looking for disconnected files; check reference counts */ if (preen == 0) printf("** Phase 4 - Check Reference Counts\n"); pass4(); -/* 5 */ +/* 5: check resource counts in cylinder groups */ if (preen == 0) printf("** Phase 5 - Check Cyl groups\n"); pass5(); @@ -375,27 +389,25 @@ checkfilesys(filesys) 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) { - time(&sblock.fs_time); + (void)time(&sblock.fs_time); sbdirty(); } ckfini(); free(blockmap); free(freemap); free(statemap); - free(lncntp); - if (dfile.mod) { - if (preen) { - if (hotroot) - exit(4); - } else { - printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); - if (hotroot) { - printf("\n***** BOOT UNIX (NO SYNC!) *****\n"); - exit(4); - } - } + free((char *)lncntp); + if (!dfile.mod) + return; + if (!preen) { + printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); + if (hotroot) + printf("\n***** REBOOT UNIX *****\n"); + } + if (hotroot) { + sync(); + exit(4); } - sync(); /* ??? */ } setup(dev) @@ -403,11 +415,12 @@ setup(dev) { dev_t rootdev; struct stat statb; - int super = bflag ? bflag : SBLOCK; - int i, j, size; - int c, d, cgd; + daddr_t super = bflag ? bflag : SBLOCK; + int i, j, c, d, cgd; + long size; + BUFAREA asblk; +# define altsblock asblk.b_un.b_fs - bflag = 0; if (stat("/", &statb) < 0) errexit("Can't stat root\n"); rootdev = statb.st_dev; @@ -451,10 +464,11 @@ setup(dev) initbarea(&fileblk); initbarea(&inoblk); initbarea(&cgblk); + initbarea(&asblk); /* * Read in the super block and its summary info. */ - if (bread(&dfile, &sblock, super, SBSIZE) == 0) + if (bread(&dfile, (char *)&sblock, super, (long)SBSIZE) == 0) return (0); sblk.b_bno = super; sblk.b_size = SBSIZE; @@ -467,33 +481,41 @@ setup(dev) { 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_nsect < 1) - { badsb("NSECT < 1"); return (0); } - if (sblock.fs_ntrak < 1) - { badsb("NTRAK < 1"); return (0); } - if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak) - { badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); } - if (sblock.fs_ipg % INOPB(&sblock)) - { badsb("INODES NOT MULTIPLE OF A BLOCK"); return (0); } - if (cgdmin(&sblock, 0) >= sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock)) - { badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); 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_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock)) - { badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); } - if (sblock.fs_size * NSPF(&sblock) <= - (sblock.fs_ncyl - 1) * sblock.fs_spc) - { badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); } - if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) + if (sblock.fs_sbsize > SBSIZE) { badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); } - /* rest we COULD repair... */ - if (sblock.fs_cgsize != fragroundup(&sblock, - sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY))) - { badsb("CGSIZE INCORRECT"); return (0); } - if (sblock.fs_cssize != - fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum))) - { badsb("CSSIZE INCORRECT"); 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 */ @@ -503,35 +525,36 @@ setup(dev) for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { size = sblock.fs_cssize - i < sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize; - sblock.fs_csp[j] = (struct csum *)calloc(1, size); - bread(&dfile, (char *)sblock.fs_csp[j], + 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); + size) == 0) + return (0); } /* * allocate and initialize the necessary maps */ bmapsz = roundup(howmany(fmax, NBBY), sizeof(short)); - blockmap = (char *)calloc(bmapsz, sizeof (char)); + blockmap = calloc((unsigned)bmapsz, sizeof (char)); if (blockmap == NULL) { printf("cannot alloc %d bytes for blockmap\n", bmapsz); - exit(1); + goto badsb; } - freemap = (char *)calloc(bmapsz, sizeof (char)); + freemap = calloc((unsigned)bmapsz, sizeof (char)); if (freemap == NULL) { printf("cannot alloc %d bytes for freemap\n", bmapsz); - exit(1); + goto badsb; } - statemap = (char *)calloc(imax+1, sizeof(char)); + statemap = calloc((unsigned)(imax + 1), sizeof(char)); if (statemap == NULL) { printf("cannot alloc %d bytes for statemap\n", imax + 1); - exit(1); + goto badsb; } - lncntp = (short *)calloc(imax+1, sizeof(short)); + lncntp = (short *)calloc((unsigned)(imax + 1), sizeof(short)); if (lncntp == NULL) { printf("cannot alloc %d bytes for lncntp\n", (imax + 1) * sizeof(short)); - exit(1); + goto badsb; } for (c = 0; c < sblock.fs_ncg; c++) { cgd = cgdmin(&sblock, c); @@ -544,33 +567,37 @@ setup(dev) setbmap(d); } - startinum = imax + 1; return (1); badsb: ckfini(); return (0); +# undef altsblock } pass1() { register int c, i, n, j; register DINODE *dp; - int savino, ndb, partial; - - pfunc = pass1check; - inum = 0; + 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((caddr_t)&cgrp, sblock.fs_cgsize); + 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++, inum++) { - dp = ginode(); + for (i = 0; i < sblock.fs_ipg; i++, inumber++) { + dp = ginode(inumber); if (dp == NULL) continue; n++; @@ -578,12 +605,17 @@ pass1() if (!isset(cgrp.cg_iused, i)) { if (debug) printf("%d bad, not used\n", - inum); + inumber); inosumbad++; } n--; - lastino = inum; - if (ftypeok(dp) == 0) + 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) @@ -597,7 +629,8 @@ pass1() for (j = ndb; j < NDADDR; j++) if (dp->di_db[j] != 0) { if (debug) - printf("bad direct addr:"); + printf("bad direct addr: %d\n", + dp->di_db[j]); goto unknown; } for (j = 0, ndb -= NDADDR; ndb > 0; j++) @@ -605,26 +638,41 @@ pass1() for (; j < NIADDR; j++) if (dp->di_ib[j] != 0) { if (debug) - printf("bad indirect addr:"); + printf("bad indirect addr: %d\n", + dp->di_ib[j]); goto unknown; } n_files++; - lncntp[inum] = dp->di_nlink; + lncntp[inumber] = dp->di_nlink; if (dp->di_nlink <= 0) { if (badlnp < &badlncnt[MAXLNCNT]) - *badlnp++ = inum; + *badlnp++ = inumber; else { pfatal("LINK COUNT TABLE OVERFLOW"); if (reply("CONTINUE") == 0) errexit(""); } } - statemap[inum] = DIRCT ? DSTATE : FSTATE; - badblk = dupblk = 0; filsize = 0; maxblk = 0; - ckinode(dp, ADDR); + 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", inum); + pfatal("UNKNOWN FILE TYPE I=%u", inumber); if (reply("CLEAR") == 1) { zapino(dp); inodirty(); @@ -634,7 +682,7 @@ pass1() if (isset(cgrp.cg_iused, i)) { if (debug) printf("%d bad, marked used\n", - inum); + inumber); inosumbad++; n--; } @@ -647,7 +695,8 @@ pass1() partial++; if (partial || dp->di_mode != 0 || dp->di_size != 0) { - pfatal("PARTIALLY ALLOCATED INODE I=%u", inum); + pfatal("PARTIALLY ALLOCATED INODE I=%u", + inumber); if (reply("CLEAR") == 1) { zapino(dp); inodirty(); @@ -670,20 +719,21 @@ pass1() } } -pass1check(blk, size) - daddr_t blk; - int size; +pass1check(idesc) + register struct inodesc *idesc; { register daddr_t *dlp; int res = KEEPON; - int anyout; + int anyout, nfrags; + daddr_t blkno = idesc->id_blkno; - anyout = outrange(blk, size); - for (; size > 0; blk++, size--) { - if (anyout && outrange(blk, 1)) { - blkerr("BAD", blk); + 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", inum); + pwarn("EXCESSIVE BAD BLKS I=%u", + idesc->id_number); if (preen) printf(" (SKIPPING)\n"); else if (reply("CONTINUE") == 0) @@ -691,10 +741,11 @@ pass1check(blk, size) return (STOP); } res = SKIP; - } else if (getbmap(blk)) { - blkerr("DUP", blk); + } else if (getbmap(blkno)) { + blkerr(idesc->id_number, "DUP", blkno); if (++dupblk >= MAXDUP) { - pwarn("EXCESSIVE DUP BLKS I=%u", inum); + pwarn("EXCESSIVE DUP BLKS I=%u", + idesc->id_number); if (preen) printf(" (SKIPPING)\n"); else if (reply("CONTINUE") == 0) @@ -708,19 +759,19 @@ pass1check(blk, size) return (STOP); } for (dlp = duplist; dlp < muldup; dlp++) - if (*dlp == blk) { - *enddup++ = blk; + if (*dlp == blkno) { + *enddup++ = blkno; break; } if (dlp >= muldup) { *enddup++ = *muldup; - *muldup++ = blk; + *muldup++ = blkno; } } else { n_blks++; - setbmap(blk); + setbmap(blkno); } - filsize++; + idesc->id_filesize++; } return (res); } @@ -729,16 +780,21 @@ pass1b() { register int c, i; register DINODE *dp; + struct inodesc idesc; + ino_t inumber; - pfunc = pass1bcheck; - inum = 0; + 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++, inum++) { - dp = ginode(); + for (i = 0; i < sblock.fs_ipg; i++, inumber++) { + dp = ginode(inumber); if (dp == NULL) continue; - if (statemap[inum] != USTATE && - (ckinode(dp, ADDR) & STOP)) + idesc.id_number = inumber; + if (statemap[inumber] != USTATE && + (ckinode(dp, &idesc) & STOP)) goto out1b; } } @@ -746,21 +802,21 @@ out1b: flush(&dfile, &inoblk); } -pass1bcheck(blk, size) - daddr_t blk; - int size; +pass1bcheck(idesc) + register struct inodesc *idesc; { register daddr_t *dlp; - int res = KEEPON; + int nfrags, res = KEEPON; + daddr_t blkno = idesc->id_blkno; - for (; size > 0; blk++, size--) { - if (outrange(blk, 1)) + for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { + if (outrange(blkno, 1)) res = SKIP; for (dlp = duplist; dlp < muldup; dlp++) - if (*dlp == blk) { - blkerr("DUP", blk); + if (*dlp == blkno) { + blkerr(idesc->id_number, "DUP", blkno); *dlp = *--muldup; - *muldup = blk; + *muldup = blkno; if (muldup == duplist) return (STOP); } @@ -771,28 +827,31 @@ pass1bcheck(blk, size) pass2() { register DINODE *dp; + struct inodesc rootdesc; - inum = ROOTINO; - thisname = pathp = pathname; - pfunc = pass2check; - switch (statemap[inum]) { + 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()) == NULL) + if (reply("FIX") == 0 || (dp = ginode(ROOTINO)) == NULL) errexit(""); dp->di_mode &= ~IFMT; dp->di_mode |= IFDIR; inodirty(); inosumbad++; - statemap[inum] = DSTATE; + statemap[ROOTINO] = DSTATE; /* fall into ... */ case DSTATE: - descend(); + descend(&rootdesc, ROOTINO); break; case CLEAR: @@ -800,122 +859,249 @@ pass2() printf("\n"); if (reply("CONTINUE") == 0) errexit(""); - statemap[inum] = DSTATE; - descend(); + statemap[ROOTINO] = DSTATE; + descend(&rootdesc, ROOTINO); } } -pass2check(dirp) - register DIRECT *dirp; +pass2check(idesc) + struct inodesc *idesc; { - register char *p; - register n; + register DIRECT *dirp = idesc->id_dirp; + char *curpathloc; + int n, entrysize, ret = 0; DINODE *dp; + DIRECT proto; - if ((inum = dirp->d_ino) == 0) - return (KEEPON); - thisname = pathp; - for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; ) - if ((*pathp++ = *p++) == 0) { - --pathp; - break; + /* + * 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); } - *pathp = 0; + 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 (inum > imax || inum <= 0) - n = direrr("I OUT OF RANGE"); - else { + if (dirp->d_ino > imax || dirp->d_ino <= 0) { + direrr(dirp->d_ino, "I OUT OF RANGE"); + n = reply("REMOVE"); + } else { again: - switch (statemap[inum]) { + switch (statemap[dirp->d_ino]) { case USTATE: - n = direrr("UNALLOCATED"); + direrr(dirp->d_ino, "UNALLOCATED"); + n = reply("REMOVE"); break; case CLEAR: - if ((n = direrr("DUP/BAD")) == 1) + direrr(dirp->d_ino, "DUP/BAD"); + if ((n = reply("REMOVE")) == 1) break; - if ((dp = ginode()) == NULL) + if ((dp = ginode(dirp->d_ino)) == NULL) break; - statemap[inum] = DIRCT ? DSTATE : FSTATE; + statemap[dirp->d_ino] = DIRCT ? DSTATE : FSTATE; goto again; case FSTATE: - lncntp[inum]--; + lncntp[dirp->d_ino]--; break; case DSTATE: - lncntp[inum]--; - descend(); + descend(idesc, dirp->d_ino); + if (statemap[dirp->d_ino] != CLEAR) { + lncntp[dirp->d_ino]--; + } else { + dirp->d_ino = 0; + ret |= ALTERED; + } break; } } - pathp = thisname; + pathp = curpathloc; + *pathp = '\0'; if (n == 0) - return (KEEPON); + return (ret|KEEPON); dirp->d_ino = 0; - return (KEEPON|ALTERD); + return (ret|KEEPON|ALTERED); } pass3() { - ino_t savino; register DINODE *dp; - - for (inum = ROOTINO; inum <= lastino; inum++) { - if (statemap[inum] == DSTATE) { - pfunc = findino; + 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 = ".."; - savino = inum; + idesc.id_parent = inumber; + loopcnt = 0; do { - orphan = inum; - if ((dp = ginode()) == NULL) + 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; - filsize = dp->di_size; - parentdir = 0; - ckinode(dp, DATA); - if ((inum = parentdir) == 0) + if (loopcnt >= sblock.fs_cstotal.cs_ndir) break; - } while (statemap[inum] == DSTATE); - inum = orphan; - if (linkup() == 1) { - thisname = pathp = pathname; - *pathp++ = '?'; - pfunc = pass2check; - descend(); + 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); } - inum = savino; } } } pass4() { - register int n; - register ino_t *blp; + register ino_t inumber, *blp; + int n; + struct inodesc idesc; - pfunc = pass4check; - for (inum = ROOTINO; inum <= lastino; inum++) { - switch (statemap[inum]) { + 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[inum]; + n = lncntp[inumber]; if (n) - adjust((short)n); + adjust(&idesc, (short)n); else { for (blp = badlncnt;blp < badlnp; blp++) - if (*blp == inum) { - clri("UNREF", 1); + if (*blp == inumber) { + clri(&idesc, "UNREF", 1); break; } } break; case DSTATE: - clri("UNREF", 1); + clri(&idesc, "UNREF", 1); break; case CLEAR: - clri("BAD/DUP", 1); + clri(&idesc, "BAD/DUP", 1); break; } } @@ -931,22 +1117,23 @@ pass4() flush(&dfile, &fileblk); } -pass4check(blk, size) - daddr_t blk; +pass4check(idesc) + register struct inodesc *idesc; { register daddr_t *dlp; - int res = KEEPON; + int nfrags, res = KEEPON; + daddr_t blkno = idesc->id_blkno; - for (; size > 0; blk++, size--) { - if (outrange(blk, 1)) + for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { + if (outrange(blkno, 1)) res = SKIP; - else if (getbmap(blk)) { + else if (getbmap(blkno)) { for (dlp = duplist; dlp < enddup; dlp++) - if (*dlp == blk) { + if (*dlp == blkno) { *dlp = *--enddup; return (KEEPON); } - clrbmap(blk); + clrbmap(blkno); n_blks--; } } @@ -963,14 +1150,14 @@ pass5() daddr_t cbase; int blockbits = (1<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) - size = numfrags(&sblock, fragroundup(&sblock, offset)); + 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 - size = sblock.fs_frag; - dnum = number; - if (*ap && (ret = (*func)(*ap, size)) & STOP) + 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++) { - dnum = number; if (*ap) { - ret = iblock(*ap, n, flg, - dino.di_size - sblock.fs_bsize * NDADDR); + idesc->id_blkno = *ap; + ret = iblock(idesc, n, + dino.di_size - sblock.fs_bsize * NDADDR); if (ret & STOP) return (ret); } @@ -1126,27 +1320,26 @@ ckinode(dp, flg) return (KEEPON); } -iblock(blk, ilevel, flg, isize) - daddr_t blk; +iblock(idesc, ilevel, isize) + struct inodesc *idesc; register ilevel; - int isize; + long isize; { register daddr_t *ap; register daddr_t *aplim; - register int i, n; - int (*func)(), nif; + int i, n, (*func)(), nif; BUFAREA ib; - if (flg == ADDR) { - func = pfunc; - if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0) + if (idesc->id_type == ADDR) { + func = idesc->id_func; + if (((n = (*func)(idesc)) & KEEPON) == 0) return (n); } else func = dirscan; - if (outrange(blk, sblock.fs_frag)) /* protect thyself */ + if (outrange(idesc->id_blkno, idesc->id_numfrags)) /* protect thyself */ return (SKIP); initbarea(&ib); - if (getblk(&ib, blk, sblock.fs_bsize) == NULL) + if (getblk(&ib, idesc->id_blkno, sblock.fs_bsize) == NULL) return (SKIP); ilevel--; if (ilevel == 0) { @@ -1159,11 +1352,12 @@ iblock(blk, ilevel, flg, isize) 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(*ap, ilevel, flg, + n = iblock(idesc, ilevel, isize - i*NINDIR(&sblock)*sblock.fs_bsize); else - n = (*func)(*ap, sblock.fs_frag); + n = (*func)(idesc); if (n & STOP) return (n); } @@ -1203,182 +1397,195 @@ outrange(blk, cnt) return (0); } -blkerr(s, blk) - daddr_t blk; +blkerr(ino, s, blk) + ino_t ino; char *s; + daddr_t blk; { - pfatal("%ld %s I=%u", blk, s, inum); + pfatal("%ld %s I=%u", blk, s, ino); printf("\n"); - statemap[inum] = CLEAR; + statemap[ino] = CLEAR; } -descend() +descend(parentino, inumber) + struct inodesc *parentino; + ino_t inumber; { register DINODE *dp; - register char *savname; - off_t savsize; + struct inodesc curino; - statemap[inum] = FSTATE; - if ((dp = ginode()) == NULL) + bzero((char *)&curino, sizeof(struct inodesc)); + statemap[inumber] = FSTATE; + if ((dp = ginode(inumber)) == NULL) return; - savname = thisname; - *pathp++ = '/'; - savsize = filsize; - filsize = dp->di_size; - ckinode(dp, DATA); - thisname = savname; - *--pathp = 0; - filsize = savsize; + 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); } -struct dirstuff { - int loc; - int blkno; - int blksiz; - ino_t number; - enum {DONTKNOW, NOFIX, FIX} fix; -}; - -dirscan(blk, nf) - daddr_t blk; - int nf; +dirscan(idesc) + register struct inodesc *idesc; { register DIRECT *dp; - struct dirstuff dirp; - int blksiz, dsize, n; + int dsize, n; + long blksiz; char dbuf[DIRBLKSIZ]; - if (outrange(blk, 1)) { - filsize -= sblock.fs_bsize; + 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); } - blksiz = nf * sblock.fs_fsize; - dirp.loc = 0; - dirp.blkno = blk; - dirp.blksiz = blksiz; - if (dirp.number != dnum) { - dirp.number = dnum; - dirp.fix = DONTKNOW; - } - for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) { + idesc->id_loc = 0; + for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { dsize = dp->d_reclen; - bcopy(dp, dbuf, dsize); - if ((n = (*pfunc)(dbuf)) & ALTERD) { - if (getblk(&fileblk, blk, blksiz) != NULL) { - bcopy(dbuf, dp, dsize); + 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 &= ~ALTERD; + n &= ~ALTERED; } if (n & STOP) return (n); } - return (filsize > 0 ? KEEPON : STOP); + return (idesc->id_filesize > 0 ? KEEPON : STOP); } /* * get next entry in a directory. */ DIRECT * -readdir(dirp) - register struct dirstuff *dirp; +fsck_readdir(idesc) + register struct inodesc *idesc; { register DIRECT *dp, *ndp; - long size; + long size, blksiz; - if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) { - filsize -= dirp->blksiz - dirp->loc; + blksiz = idesc->id_numfrags * sblock.fs_fsize; + if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) { + idesc->id_filesize -= blksiz - idesc->id_loc; return NULL; } - while (dirp->loc % DIRBLKSIZ == 0 && filsize > 0 && - dirp->loc < dirp->blksiz) { - dp = (DIRECT *)(dirblk.b_buf + dirp->loc); - if (dp->d_ino < imax && - dp->d_namlen <= MAXNAMLEN && dp->d_namlen >= 0 && - dp->d_reclen > 0 && dp->d_reclen <= DIRBLKSIZ) - break; - dirp->loc += DIRBLKSIZ; - filsize -= DIRBLKSIZ; - if (dirp->fix == DONTKNOW) { - pwarn("DIRECTORY %D CORRUPTED", dirp->number); - dirp->fix = NOFIX; - if (preen) { - printf(" (SALVAGED)\n"); - dirp->fix = FIX; - } else if (reply("SALVAGE") != 0) - dirp->fix = FIX; - } - if (dirp->fix != FIX) - continue; + 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; - dirty(&fileblk); + dp->d_name[0] = '\0'; + if (dofix(idesc)) + dirty(&fileblk); + return (dp); } - if (filsize <= 0 || dirp->loc >= dirp->blksiz) +dpok: + if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) return NULL; - dp = (DIRECT *)(dirblk.b_buf + dirp->loc); - dirp->loc += dp->d_reclen; - filsize -= dp->d_reclen; - ndp = (DIRECT *)(dirblk.b_buf + dirp->loc); - if ((filsize <= 0 && dirp->loc % DIRBLKSIZ != 0) || - (dirp->loc < dirp->blksiz && filsize > 0 && - (ndp->d_ino >= imax || - ndp->d_namlen > MAXNAMLEN || ndp->d_namlen < 0 || - ndp->d_reclen <= 0 || - ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ)))) { - size = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ); - dirp->loc += size; - filsize -= size; - if (dirp->fix == DONTKNOW) { - pwarn("DIRECTORY %D CORRUPTED", dirp->number); - dirp->fix = NOFIX; - if (preen) { - printf(" (SALVAGED)\n"); - dirp->fix = FIX; - } else if (reply("SALVAGE") != 0) - dirp->fix = FIX; - } - if (dirp->fix == FIX) { - dp->d_reclen += size; + 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); } -direrr(s) +/* + * 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(); + pinode(ino); printf("\n"); - if ((dp = ginode()) != NULL && ftypeok(dp)) - pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname); + if ((dp = ginode(ino)) != NULL && ftypeok(dp)) + pfatal("%s=%s\n", DIRCT?"DIR":"FILE", pathname); else - pfatal("NAME=%s", pathname); - return (reply("REMOVE")); + pfatal("NAME=%s\n", pathname); } -adjust(lcnt) - register short lcnt; +adjust(idesc, lcnt) + register struct inodesc *idesc; + short lcnt; { register DINODE *dp; - if ((dp = ginode()) == NULL) + if ((dp = ginode(idesc->id_number)) == NULL) return; if (dp->di_nlink == lcnt) { - if (linkup() == 0) - clri("UNREF", 0); + if (linkup(idesc->id_number, (ino_t)0) == 0) + clri(idesc, "UNREF", 0); } else { pwarn("LINK COUNT %s", - (lfdir==inum)?lfname:(DIRCT?"DIR":"FILE")); - pinode(); + (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) { @@ -1395,25 +1602,26 @@ adjust(lcnt) } } -clri(s, flg) +clri(idesc, s, flg) + register struct inodesc *idesc; char *s; + int flg; { register DINODE *dp; - if ((dp = ginode()) == NULL) + if ((dp = ginode(idesc->id_number)) == NULL) return; if (flg == 1) { pwarn("%s %s", s, DIRCT?"DIR":"FILE"); - pinode(); + pinode(idesc->id_number); } if (preen || reply("CLEAR") == 1) { if (preen) printf(" (CLEARED)\n"); n_files--; - pfunc = pass4check; - ckinode(dp, ADDR); + (void)ckinode(dp, idesc); zapino(dp); - statemap[inum] = USTATE; + statemap[idesc->id_number] = USTATE; inodirty(); inosumbad++; } @@ -1431,23 +1639,27 @@ badsb(s) } DINODE * -ginode() +ginode(inumber) + ino_t inumber; { daddr_t iblk; + static ino_t startinum = 0; /* blk num of first in raw area */ - if (inum < ROOTINO || inum > imax) { - if (debug && (inum < 0 || inum > imax)) - printf("inum out of range (%d)\n", inum); + + if (inumber < ROOTINO || inumber > imax) { + if (debug && inumber > imax) + printf("inumber out of range (%d)\n", inumber); return (NULL); } - if (inum < startinum || inum >= startinum + INOPB(&sblock)) { - iblk = itod(&sblock, inum); + if (startinum == 0 || + inumber < startinum || inumber >= startinum + INOPB(&sblock)) { + iblk = itod(&sblock, inumber); if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) { return (NULL); } - startinum = (inum / INOPB(&sblock)) * INOPB(&sblock); + startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); } - return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]); + return (&inoblk.b_un.b_dinode[inumber % INOPB(&sblock)]); } ftypeok(dp) @@ -1460,6 +1672,7 @@ ftypeok(dp) case IFBLK: case IFCHR: case IFLNK: + case IFSOCK: return (1); default: @@ -1516,9 +1729,9 @@ getline(fp, loc, maxlen) BUFAREA * getblk(bp, blk, size) - daddr_t blk; register BUFAREA *bp; - int size; + daddr_t blk; + long size; { register struct filecntl *fcp; daddr_t dblk; @@ -1543,7 +1756,7 @@ flush(fcp, bp) { if (bp->b_dirty) - bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size); + (void)bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); bp->b_dirty = 0; } @@ -1570,19 +1783,20 @@ ckfini() flush(&dfile, &sblk); } flush(&dfile, &inoblk); - close(dfile.rfdes); - close(dfile.wfdes); + (void)close(dfile.rfdes); + (void)close(dfile.wfdes); } -pinode() +pinode(ino) + ino_t ino; { register DINODE *dp; register char *p; char uidbuf[BUFSIZ]; char *ctime(); - printf(" I=%u ", inum); - if ((dp = ginode()) == NULL) + printf(" I=%u ", ino); + if ((dp = ginode(ino)) == NULL) return; printf(" OWNER="); if (getpw((int)dp->di_uid, uidbuf) == 0) { @@ -1606,6 +1820,7 @@ 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; @@ -1624,7 +1839,7 @@ makecg() dlower = cgsblock(&sblock, c) - dbase; dupper = cgdmin(&sblock, c) - dbase; cs = &sblock.fs_cs(&sblock, c); - cgrp.cg_time = time(0); + (void)time(&cgrp.cg_time); cgrp.cg_magic = CG_MAGIC; cgrp.cg_cgx = c; if (c == sblock.fs_ncg - 1) @@ -1642,11 +1857,11 @@ makecg() cgrp.cg_irotor = 0; for (i = 0; i < sblock.fs_frag; i++) cgrp.cg_frsum[i] = 0; - inum = sblock.fs_ipg * c; - for (i = 0; i < sblock.fs_ipg; inum++, i++) { + 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(); + dp = ginode(inumber); if (dp == NULL) continue; if (ALLOC) { @@ -1717,11 +1932,11 @@ makecg() sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree; sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir; *cs = cgrp.cg_cs; - bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)), - sblock.fs_cgsize); + (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++) { - bwrite(&dfile, (char *)sblock.fs_csp[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); @@ -1731,24 +1946,25 @@ makecg() sbdirty(); } -findino(dirp) - register DIRECT *dirp; +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) - parentdir = dirp->d_ino; + idesc->id_parent = dirp->d_ino; return (STOP); } return (KEEPON); } -mkentry(dirp) - register DIRECT *dirp; +mkentry(idesc) + struct inodesc *idesc; { - register ino_t in; - register char *p; + register DIRECT *dirp = idesc->id_dirp; DIRECT newent; int newlen, oldlen; @@ -1763,45 +1979,39 @@ mkentry(dirp) newent.d_reclen = dirp->d_reclen - oldlen; dirp->d_reclen = oldlen; dirp = (struct direct *)(((char *)dirp) + oldlen); - dirp->d_ino = orphan; + dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ dirp->d_reclen = newent.d_reclen; - p = &dirp->d_name[2]; - for (in = imax; in > 0; in /= 10) - p++; - *--p = 0; - dirp->d_namlen = p - dirp->d_name; - in = orphan; - while (p > dirp->d_name) { - *--p = (in % 10) + '0'; - in /= 10; - } - *p = '#'; - return (ALTERD|STOP); + dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent); + return (ALTERED|STOP); } -chgdd(dirp) - register DIRECT *dirp; +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 (ALTERD|STOP); + return (ALTERED|STOP); } return (KEEPON); } -linkup() +linkup(orphan, pdir) + ino_t orphan; + ino_t pdir; { register DINODE *dp; - register lostdir; - register ino_t pdir; + int lostdir, len; + struct inodesc idesc; - if ((dp = ginode()) == NULL) + bzero((char *)&idesc, sizeof(struct inodesc)); + if ((dp = ginode(orphan)) == NULL) return (0); lostdir = DIRCT; - pdir = parentdir; pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); - pinode(); + pinode(orphan); if (preen && dp->di_size == 0) return (0); if (preen) @@ -1809,28 +2019,26 @@ linkup() else if (reply("RECONNECT") == 0) return (0); - orphan = inum; + pathp = pathname; + *pathp++ = '/'; + *pathp = '\0'; if (lfdir == 0) { - inum = ROOTINO; - if ((dp = ginode()) == NULL) { - inum = orphan; + if ((dp = ginode(ROOTINO)) == NULL) return (0); - } - pfunc = findino; srchname = lfname; - filsize = dp->di_size; - parentdir = 0; - ckinode(dp, DATA); - inum = orphan; - if ((lfdir = parentdir) == 0) { + 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); } } - inum = lfdir; - if ((dp = ginode()) == NULL || !DIRCT || statemap[inum] != FSTATE) { - inum = orphan; + if ((dp = ginode(lfdir)) == NULL || + !DIRCT || statemap[lfdir] != FSTATE) { pfatal("SORRY. NO lost+found DIRECTORY"); printf("\n\n"); return (0); @@ -1839,27 +2047,36 @@ linkup() dp->di_size = fragroundup(&sblock, dp->di_size); inodirty(); } - filsize = dp->di_size; - inum = orphan; - pfunc = mkentry; - if ((ckinode(dp, DATA) & ALTERD) == 0) { + 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[inum]--; + lncntp[orphan]--; + *pathp++ = '/'; + pathp += lftempname(pathp, orphan); if (lostdir) { - pfunc = chgdd; - dp = ginode(); - filsize = dp->di_size; - ckinode(dp, DATA); - inum = lfdir; - if ((dp = ginode()) != NULL) { + 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[inum]++; + lncntp[lfdir]++; } - inum = orphan; pwarn("DIR I=%u CONNECTED. ", orphan); printf("PARENT WAS I=%u\n", pdir); if (preen == 0) @@ -1868,32 +2085,57 @@ linkup() 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) - daddr_t blk; register struct filecntl *fcp; - register size; char *buf; + daddr_t blk; + long size; { - if (lseek(fcp->rfdes, blk * DEV_BSIZE, 0) < 0) + if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0) rwerr("SEEK", blk); - else if (read(fcp->rfdes, buf, size) == size) + else if (read(fcp->rfdes, buf, (int)size) == size) return (1); rwerr("READ", blk); return (0); } bwrite(fcp, buf, blk, size) - daddr_t blk; register struct filecntl *fcp; - register size; char *buf; + daddr_t blk; + long size; { if (fcp->wfdes < 0) return (0); - if (lseek(fcp->wfdes, blk * DEV_BSIZE, 0) < 0) + if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0) rwerr("SEEK", blk); - else if (write(fcp->wfdes, buf, size) == size) { + else if (write(fcp->wfdes, buf, (int)size) == size) { fcp->mod = 1; return (1); } @@ -1923,7 +2165,7 @@ unrawname(cp) return (cp); if (*(dp+1) != 'r') return (cp); - strcpy(dp+1, dp+2); + (void)strcpy(dp+1, dp+2); return (cp); } @@ -1937,13 +2179,43 @@ rawname(cp) if (dp == 0) return (0); *dp = 0; - strcpy(rawbuf, cp); + (void)strcpy(rawbuf, cp); *dp = '/'; - strcat(rawbuf, "/r"); - strcat(rawbuf, dp+1); + (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; @@ -1962,7 +2234,7 @@ errexit(s1, s2, s3, s4) /* * An inconsistency occured which shouldn't during normal operations. - * Die if preening, otw just printf. + * Die if preening, otherwise just printf. */ /* VARARGS1 */ pfatal(s, a1, a2, a3) @@ -1999,10 +2271,15 @@ pwarn(s, a1, a2, a3, a4, a5, a6) printf(s, a1, a2, a3, a4, a5, a6); } +#ifndef lint +/* + * Stub for routines from kernel. + */ panic(s) char *s; { - pfatal("internal inconsistency: %s\n"); + pfatal("INTERNAL INCONSISTENCY: %s\n", s); exit(12); } +#endif