|
|
1.1 ! root 1: static char *sccsid = "@(#)fsck.c 4.13 (Berkeley) 81/03/09"; ! 2: #include <stdio.h> ! 3: #include <ctype.h> ! 4: #include <sys/param.h> ! 5: #include <sys/filsys.h> ! 6: #include <sys/dir.h> ! 7: #include <sys/fblk.h> ! 8: #include <sys/ino.h> ! 9: #include <sys/inode.h> ! 10: #include <sys/stat.h> ! 11: #include <fstab.h> ! 12: ! 13: /*typedef int (*SIG_TYP)();*/ ! 14: ! 15: #define BIG 64 /* 4k file systems */ ! 16: #define SMALL 0 /* 1k file systems */ ! 17: #define NDIRECT(x) (BSIZE(x)/sizeof(struct direct)) ! 18: #define SPERB(x) (BSIZE(x)/sizeof(short)) ! 19: ! 20: #define NO 0 ! 21: #define YES 1 ! 22: ! 23: #define MAXDUP 10 /* limit on dup blks (per inode) */ ! 24: #define MAXBAD 10 /* limit on bad blks (per inode) */ ! 25: ! 26: #define STEPSIZE 9 /* default step for freelist spacing */ ! 27: #define CYLSIZE 400 /* default cyl size for spacing */ ! 28: #define MAXCYL 1000 /* maximum cylinder size */ ! 29: ! 30: #define BITSPB 8 /* number bits per byte */ ! 31: #define BITSHIFT 3 /* log2(BITSPB) */ ! 32: #define BITMASK 07 /* BITSPB-1 */ ! 33: #define LSTATE 2 /* bits per inode state */ ! 34: #define STATEPB (BITSPB/LSTATE) /* inode states per byte */ ! 35: #define USTATE 0 /* inode not allocated */ ! 36: #define FSTATE 01 /* inode is file */ ! 37: #define DSTATE 02 /* inode is directory */ ! 38: #define CLEAR 03 /* inode is to be cleared */ ! 39: #define SMASK 03 /* mask for inode state */ ! 40: ! 41: typedef struct dinode DINODE; ! 42: typedef struct direct DIRECT; ! 43: ! 44: #define ALLOC ((dp->di_mode & IFMT) != 0) ! 45: #define DIR ((dp->di_mode & IFMT) == IFDIR) ! 46: #define REG ((dp->di_mode & IFMT) == IFREG) ! 47: #define BLK ((dp->di_mode & IFMT) == IFBLK) ! 48: #define CHR ((dp->di_mode & IFMT) == IFCHR) ! 49: #define MPC ((dp->di_mode & IFMT) == IFMPC) ! 50: #define MPB ((dp->di_mode & IFMT) == IFMPB) ! 51: #define LNK ((dp->di_mode & IFMT) == IFLNK) ! 52: #define SPECIAL (BLK || CHR /* || MPC || MPB */ ) ! 53: ! 54: #define NINOBLK 11 /* num blks for raw reading */ ! 55: #define MAXRAW 110 /* largest raw read (in blks) */ ! 56: daddr_t startib; /* blk num of first in raw area */ ! 57: unsigned niblk; /* num of blks in raw area */ ! 58: ! 59: struct bufarea { ! 60: struct bufarea *b_next; /* must be first */ ! 61: daddr_t b_bno; ! 62: union { ! 63: char b_buf[BSIZE(BIG)]; /* buffer space */ ! 64: short b_lnks[SPERB(BIG)]; /* link counts */ ! 65: daddr_t b_indir[NINDIR(BIG)]; /* indirect block */ ! 66: struct filsys b_fs; /* super block */ ! 67: struct fblk b_fb; /* free block */ ! 68: struct dinode b_dinode[INOPB(BIG)]; /* inode block */ ! 69: DIRECT b_dir[NDIRECT(BIG)]; /* directory */ ! 70: } b_un; ! 71: char b_dirty; ! 72: }; ! 73: ! 74: typedef struct bufarea BUFAREA; ! 75: ! 76: BUFAREA inoblk; /* inode blocks */ ! 77: BUFAREA fileblk; /* other blks in filesys */ ! 78: BUFAREA sblk; /* file system superblock */ ! 79: BUFAREA *poolhead; /* ptr to first buffer in pool */ ! 80: ! 81: #define initbarea(x) (x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1 ! 82: #define dirty(x) (x)->b_dirty = 1 ! 83: #define inodirty() inoblk.b_dirty = 1 ! 84: #define fbdirty() fileblk.b_dirty = 1 ! 85: #define sbdirty() sblk.b_dirty = 1 ! 86: ! 87: #define freeblk fileblk.b_un.b_fb ! 88: #define dirblk fileblk.b_un ! 89: #define superblk sblk.b_un.b_fs ! 90: ! 91: struct filecntl { ! 92: int rfdes; ! 93: int wfdes; ! 94: int mod; ! 95: }; ! 96: ! 97: struct filecntl dfile; /* file descriptors for filesys */ ! 98: struct filecntl sfile; /* file descriptors for scratch file */ ! 99: ! 100: typedef unsigned MEMSIZE; ! 101: ! 102: MEMSIZE memsize; /* amt of memory we got */ ! 103: #ifdef pdp11 ! 104: #define MAXDATA ((MEMSIZE)54*1024) ! 105: #endif ! 106: #ifdef vax ! 107: #define MAXDATA ((MEMSIZE)400*1024) ! 108: #endif ! 109: ! 110: #define DUPTBLSIZE 100 /* num of dup blocks to remember */ ! 111: daddr_t duplist[DUPTBLSIZE]; /* dup block table */ ! 112: daddr_t *enddup; /* next entry in dup table */ ! 113: daddr_t *muldup; /* multiple dups part of table */ ! 114: ! 115: #define MAXLNCNT 500 /* num zero link cnts to remember */ ! 116: ino_t badlncnt[MAXLNCNT]; /* table of inos with zero link cnts */ ! 117: ino_t *badlnp; /* next entry in table */ ! 118: ! 119: char sflag; /* salvage free block list */ ! 120: char csflag; /* salvage free block list (conditional) */ ! 121: char nflag; /* assume a no response */ ! 122: char yflag; /* assume a yes response */ ! 123: char tflag; /* scratch file specified */ ! 124: char preen; /* just fix normal inconsistencies */ ! 125: char rplyflag; /* any questions asked? */ ! 126: char hotroot; /* checking root device */ ! 127: char rawflg; /* read raw device */ ! 128: char rmscr; /* remove scratch file when done */ ! 129: char fixfree; /* corrupted free list */ ! 130: char *membase; /* base of memory we get */ ! 131: char *blkmap; /* ptr to primary blk allocation map */ ! 132: char *freemap; /* ptr to secondary blk allocation map */ ! 133: char *statemap; /* ptr to inode state table */ ! 134: char *pathp; /* pointer to pathname position */ ! 135: char *thisname; /* ptr to current pathname component */ ! 136: char *srchname; /* name being searched for in dir */ ! 137: char pathname[200]; ! 138: char scrfile[80]; ! 139: char *lfname = "lost+found"; ! 140: char *checklist = FSTAB; ! 141: char big; /* it is a 4k file system */ ! 142: ! 143: short *lncntp; /* ptr to link count table */ ! 144: ! 145: int cylsize; /* num blocks per cylinder */ ! 146: int stepsize; /* num blocks for spacing purposes */ ! 147: int badblk; /* num of bad blks seen (per inode) */ ! 148: int dupblk; /* num of dup blks seen (per inode) */ ! 149: int (*pfunc)(); /* function to call to chk blk */ ! 150: ! 151: ino_t inum; /* inode we are currently working on */ ! 152: ino_t imax; /* number of inodes */ ! 153: ino_t parentdir; /* i number of parent directory */ ! 154: ino_t lastino; /* hiwater mark of inodes */ ! 155: ino_t lfdir; /* lost & found directory */ ! 156: ino_t orphan; /* orphaned inode */ ! 157: ! 158: off_t filsize; /* num blks seen in file */ ! 159: off_t maxblk; /* largest logical blk in file */ ! 160: off_t bmapsz; /* num chars in blkmap */ ! 161: ! 162: daddr_t smapblk; /* starting blk of state map */ ! 163: daddr_t lncntblk; /* starting blk of link cnt table */ ! 164: daddr_t fmapblk; /* starting blk of free map */ ! 165: daddr_t n_free; /* number of free blocks */ ! 166: daddr_t n_blks; /* number of blocks used */ ! 167: daddr_t n_files; /* number of files seen */ ! 168: daddr_t fmin; /* block number of the first data block */ ! 169: daddr_t fmax; /* number of blocks in the volume */ ! 170: ! 171: #define howmany(x,y) (((x)+((y)-1))/(y)) ! 172: #define roundup(x,y) ((((x)+((y)-1))/(y))*(y)) ! 173: #define outrange(x) (x < fmin || x >= fmax) ! 174: #define zapino(x) clear((char *)(x),sizeof(DINODE)) ! 175: ! 176: #define setlncnt(x) dolncnt(x,0) ! 177: #define getlncnt() dolncnt(0,1) ! 178: #define declncnt() dolncnt(0,2) ! 179: ! 180: #define setbmap(x) domap(x,0) ! 181: #define getbmap(x) domap(x,1) ! 182: #define clrbmap(x) domap(x,2) ! 183: ! 184: #define setfmap(x) domap(x,0+4) ! 185: #define getfmap(x) domap(x,1+4) ! 186: #define clrfmap(x) domap(x,2+4) ! 187: ! 188: #define setstate(x) dostate(x,0) ! 189: #define getstate() dostate(0,1) ! 190: ! 191: #define DATA 1 ! 192: #define ADDR 0 ! 193: #define ALTERD 010 ! 194: #define KEEPON 04 ! 195: #define SKIP 02 ! 196: #define STOP 01 ! 197: ! 198: int (*signal())(); ! 199: long lseek(); ! 200: long time(); ! 201: DINODE *ginode(); ! 202: BUFAREA *getblk(); ! 203: BUFAREA *search(); ! 204: int dirscan(); ! 205: int findino(); ! 206: int catch(); ! 207: int mkentry(); ! 208: int chgdd(); ! 209: int pass1(); ! 210: int pass1b(); ! 211: int pass2(); ! 212: int pass3(); ! 213: int pass4(); ! 214: int pass5(); ! 215: ! 216: char *devname; ! 217: ! 218: main(argc,argv) ! 219: int argc; ! 220: char *argv[]; ! 221: { ! 222: register FILE *fp; ! 223: register n; ! 224: register char *p; ! 225: char filename[50]; ! 226: char *sbrk(); ! 227: ! 228: sync(); ! 229: while(--argc > 0 && **++argv == '-') { ! 230: switch(*++*argv) { ! 231: case 'p': ! 232: preen++; ! 233: break; ! 234: case 't': ! 235: case 'T': ! 236: tflag++; ! 237: if(**++argv == '-' || --argc <= 0) ! 238: errexit("Bad -t option\n"); ! 239: p = scrfile; ! 240: while(*p++ = **argv) ! 241: (*argv)++; ! 242: break; ! 243: case 's': /* salvage flag */ ! 244: stype(++*argv); ! 245: sflag++; ! 246: break; ! 247: case 'S': /* conditional salvage */ ! 248: stype(++*argv); ! 249: csflag++; ! 250: break; ! 251: case 'n': /* default no answer flag */ ! 252: case 'N': ! 253: nflag++; ! 254: yflag = 0; ! 255: break; ! 256: case 'y': /* default yes answer flag */ ! 257: case 'Y': ! 258: yflag++; ! 259: nflag = 0; ! 260: break; ! 261: default: ! 262: errexit("%c option?\n",**argv); ! 263: } ! 264: } ! 265: if(nflag && (sflag || csflag)) ! 266: errexit("Incompatible options: -n and -%s\n",sflag?"s":"S"); ! 267: if(sflag && csflag) ! 268: sflag = 0; ! 269: memsize = (MEMSIZE)sbrk(0); ! 270: memsize = MAXDATA - memsize - sizeof(int); ! 271: while(memsize >= 2*sizeof(BUFAREA) && ! 272: (membase = sbrk(memsize)) == (char *)-1) ! 273: memsize -= 1024; ! 274: if(memsize < 2*sizeof(BUFAREA)) ! 275: errexit("Can't get memory\n"); ! 276: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 277: signal(SIGINT, catch); ! 278: if(argc) { /* arg list has file names */ ! 279: while(argc-- > 0){ ! 280: hotroot = 0; ! 281: check(*argv++); ! 282: } ! 283: } ! 284: else { /* use default checklist */ ! 285: struct fstab *fsp; ! 286: int pid, passno, anygtr, sumstatus = 0; ! 287: passno = 1; ! 288: do { ! 289: anygtr = 0; ! 290: if (setfsent() == 0) ! 291: errexit("Can't open checklist file: %s\n", ! 292: FSTAB); ! 293: while ( (fsp = getfsent()) != 0){ ! 294: if (strcmp(fsp->fs_type, FSTAB_RW) && ! 295: strcmp(fsp->fs_type, FSTAB_RO)) ! 296: continue; ! 297: if (preen == 0 || ! 298: passno == 1 && fsp->fs_passno == passno) { ! 299: if (blockcheck(fsp->fs_spec) == NO && ! 300: preen) ! 301: exit(8); ! 302: } else if (fsp->fs_passno > passno) ! 303: anygtr = 1; ! 304: else if (fsp->fs_passno == passno) { ! 305: pid = fork(); ! 306: if (pid < 0) { ! 307: perror("fork"); ! 308: exit(8); ! 309: } ! 310: if (pid == 0) ! 311: if (blockcheck(fsp->fs_spec)==NO) ! 312: exit(8); ! 313: else ! 314: exit(0); ! 315: } ! 316: } ! 317: if (preen) { ! 318: int status; ! 319: while (wait(&status) != -1) ! 320: sumstatus |= status; ! 321: } ! 322: passno++; ! 323: } while (anygtr); ! 324: if (sumstatus) ! 325: exit(8); ! 326: endfsent(); ! 327: } ! 328: exit(0); ! 329: } ! 330: ! 331: char *rawname(), *rindex(), *unrawname(); ! 332: ! 333: blockcheck(name) ! 334: char *name; ! 335: { ! 336: struct stat stat_slash, stat_block, stat_char; ! 337: char *raw; ! 338: int looped = 0; ! 339: ! 340: hotroot = 0; ! 341: if (stat("/", &stat_slash) < 0){ ! 342: error("Can't stat root\n"); ! 343: return(NO); ! 344: } ! 345: retry: ! 346: if (stat(name, &stat_block) < 0){ ! 347: error("Can't stat %s\n", name); ! 348: return(NO); ! 349: } ! 350: big = SMALL; /* 1k blocks by default */ ! 351: if (stat_block.st_mode & S_IFBLK){ ! 352: if(BITFS(stat_block.st_rdev)) ! 353: big = BIG; /* a 4k file system */ ! 354: raw = rawname(name); ! 355: if (stat(raw, &stat_char) < 0){ ! 356: error("Can't stat %s\n", raw); ! 357: return(NO); ! 358: } ! 359: if (stat_char.st_mode & S_IFCHR){ ! 360: if (stat_slash.st_dev == stat_block.st_rdev) { ! 361: hotroot++; ! 362: raw = unrawname(name); ! 363: } ! 364: check(raw); ! 365: return(YES); ! 366: } else if(big == BIG) { ! 367: check(name); ! 368: return(YES); ! 369: } else { ! 370: error("%s is not a character device\n", raw); ! 371: return(NO); ! 372: } ! 373: } else ! 374: if (stat_block.st_mode & S_IFCHR){ ! 375: if (looped) { ! 376: error("Can't make sense out of name %s\n", name); ! 377: return(NO); ! 378: } ! 379: name = unrawname(name); ! 380: looped++; ! 381: goto retry; ! 382: } ! 383: error("Can't make sense out of name %s\n", name); ! 384: return(NO); ! 385: } ! 386: ! 387: char * ! 388: unrawname(cp) ! 389: char *cp; ! 390: { ! 391: char *dp = rindex(cp, '/'); ! 392: struct stat stb; ! 393: if (dp == 0) ! 394: return(cp); ! 395: if (stat(cp, &stb) < 0) ! 396: return(cp); ! 397: if ((stb.st_mode&S_IFMT) != S_IFCHR) ! 398: return(cp); ! 399: if (*(dp+1) != 'r') ! 400: return(cp); ! 401: strcpy(dp+1, dp+2); ! 402: return(cp); ! 403: } ! 404: ! 405: char * ! 406: rawname(cp) ! 407: char *cp; ! 408: { ! 409: static char rawbuf[32]; ! 410: char *dp = rindex(cp, '/'); ! 411: ! 412: if (dp == 0) ! 413: return (0); ! 414: if(big == BIG) ! 415: return(cp); ! 416: *dp = 0; ! 417: strcpy(rawbuf, cp); ! 418: *dp = '/'; ! 419: strcat(rawbuf, "/r"); ! 420: strcat(rawbuf, dp+1); ! 421: return (rawbuf); ! 422: } ! 423: ! 424: check(dev) ! 425: char *dev; ! 426: { ! 427: ! 428: devname = dev; ! 429: check1(dev); ! 430: devname = 0; ! 431: } ! 432: ! 433: check1(dev) ! 434: char *dev; ! 435: { ! 436: register DINODE *dp; ! 437: register n; ! 438: register ino_t *blp; ! 439: ino_t savino; ! 440: daddr_t blk; ! 441: BUFAREA *bp1, *bp2; ! 442: ! 443: if(setup(dev) == NO) ! 444: return; ! 445: if (preen==0) { ! 446: printf("** Checking %s\n", dev); ! 447: printf("** Phase 1 - Check Blocks and Sizes\n"); ! 448: } ! 449: pfunc = pass1; ! 450: for(inum = 1; inum <= imax; inum++) { ! 451: if((dp = ginode()) == NULL) ! 452: continue; ! 453: if(ALLOC) { ! 454: lastino = inum; ! 455: if(ftypeok(dp) == NO) { ! 456: pfatal("UNKNOWN FILE TYPE I=%u",inum); ! 457: if(reply("CLEAR") == YES) { ! 458: zapino(dp); ! 459: inodirty(); ! 460: } ! 461: continue; ! 462: } ! 463: n_files++; ! 464: if(setlncnt(dp->di_nlink) <= 0) { ! 465: if(badlnp < &badlncnt[MAXLNCNT]) ! 466: *badlnp++ = inum; ! 467: else { ! 468: pfatal("LINK COUNT TABLE OVERFLOW"); ! 469: if(reply("CONTINUE") == NO) ! 470: errexit(""); ! 471: } ! 472: } ! 473: setstate(DIR ? DSTATE : FSTATE); ! 474: badblk = dupblk = 0; ! 475: filsize = 0; ! 476: maxblk = 0; ! 477: ckinode(dp,ADDR); ! 478: if((n = getstate()) == DSTATE || n == FSTATE) ! 479: sizechk(dp); ! 480: } ! 481: else if(dp->di_mode != 0) { ! 482: pfatal("PARTIALLY ALLOCATED INODE I=%u",inum); ! 483: if(reply("CLEAR") == YES) { ! 484: zapino(dp); ! 485: inodirty(); ! 486: } ! 487: } ! 488: } ! 489: ! 490: ! 491: if(enddup != &duplist[0]) { ! 492: if (preen) ! 493: pfatal("INTERNAL ERROR: dups with -p"); ! 494: printf("** Phase 1b - Rescan For More DUPS\n"); ! 495: pfunc = pass1b; ! 496: for(inum = 1; inum <= lastino; inum++) { ! 497: if(getstate() != USTATE && (dp = ginode()) != NULL) ! 498: if(ckinode(dp,ADDR) & STOP) ! 499: break; ! 500: } ! 501: } ! 502: if(rawflg) { /* shouldn't be set for 4k system */ ! 503: if(inoblk.b_dirty) ! 504: bwrite(&dfile,membase,startib,(int)niblk*BSIZE(big)); ! 505: inoblk.b_dirty = 0; ! 506: if(poolhead) { ! 507: clear(membase,niblk*BSIZE(BIG)); ! 508: for(bp1 = poolhead;bp1->b_next;bp1 = bp1->b_next); ! 509: bp2 = &((BUFAREA *)membase)[(niblk*BSIZE(BIG))/sizeof(BUFAREA)]; ! 510: while(--bp2 >= (BUFAREA *)membase) { ! 511: initbarea(bp2); ! 512: bp2->b_next = bp1->b_next; ! 513: bp1->b_next = bp2; ! 514: } ! 515: } ! 516: rawflg = 0; ! 517: ! 518: } ! 519: ! 520: ! 521: if (preen == 0) ! 522: printf("** Phase 2 - Check Pathnames\n"); ! 523: inum = ROOTINO; ! 524: thisname = pathp = pathname; ! 525: pfunc = pass2; ! 526: switch(getstate()) { ! 527: case USTATE: ! 528: errexit("ROOT INODE UNALLOCATED. TERMINATING.\n"); ! 529: case FSTATE: ! 530: pfatal("ROOT INODE NOT DIRECTORY"); ! 531: if(reply("FIX") == NO || (dp = ginode()) == NULL) ! 532: errexit(""); ! 533: dp->di_mode &= ~IFMT; ! 534: dp->di_mode |= IFDIR; ! 535: inodirty(); ! 536: setstate(DSTATE); ! 537: case DSTATE: ! 538: descend(); ! 539: break; ! 540: case CLEAR: ! 541: pfatal("DUPS/BAD IN ROOT INODE"); ! 542: printf("\n"); ! 543: if(reply("CONTINUE") == NO) ! 544: errexit(""); ! 545: setstate(DSTATE); ! 546: descend(); ! 547: } ! 548: ! 549: ! 550: if (preen == 0) ! 551: printf("** Phase 3 - Check Connectivity\n"); ! 552: for(inum = ROOTINO; inum <= lastino; inum++) { ! 553: if(getstate() == DSTATE) { ! 554: pfunc = findino; ! 555: srchname = ".."; ! 556: savino = inum; ! 557: do { ! 558: orphan = inum; ! 559: if((dp = ginode()) == NULL) ! 560: break; ! 561: filsize = dp->di_size; ! 562: parentdir = 0; ! 563: ckinode(dp,DATA); ! 564: if((inum = parentdir) == 0) ! 565: break; ! 566: } while(getstate() == DSTATE); ! 567: inum = orphan; ! 568: if(linkup() == YES) { ! 569: thisname = pathp = pathname; ! 570: *pathp++ = '?'; ! 571: pfunc = pass2; ! 572: descend(); ! 573: } ! 574: inum = savino; ! 575: } ! 576: } ! 577: ! 578: ! 579: if (preen == 0) ! 580: printf("** Phase 4 - Check Reference Counts\n"); ! 581: pfunc = pass4; ! 582: for(inum = ROOTINO; inum <= lastino; inum++) { ! 583: switch(getstate()) { ! 584: case FSTATE: ! 585: if(n = getlncnt()) ! 586: adjust((short)n); ! 587: else { ! 588: for(blp = badlncnt;blp < badlnp; blp++) ! 589: if(*blp == inum) { ! 590: clri("UNREF",YES); ! 591: break; ! 592: } ! 593: } ! 594: break; ! 595: case DSTATE: ! 596: clri("UNREF",YES); ! 597: break; ! 598: case CLEAR: ! 599: clri("BAD/DUP",YES); ! 600: } ! 601: } ! 602: if(imax - n_files != superblk.s_tinode) { ! 603: pwarn("FREE INODE COUNT %u SHOULD BE %u IN SUPERBLK", ! 604: superblk.s_tinode, imax - n_files); ! 605: if (preen) ! 606: printf(" (FIXED)\n"); ! 607: if (preen || reply("FIX") == YES) { ! 608: superblk.s_tinode = imax - n_files; ! 609: sbdirty(); ! 610: } ! 611: } ! 612: flush(&dfile,&fileblk); ! 613: ! 614: if (preen == 0) ! 615: printf("** Phase 5 - Check Free List "); ! 616: if(sflag || (csflag && rplyflag == 0)) { ! 617: if (preen == 0) ! 618: printf("(Ignored)\n"); ! 619: fixfree = 1; ! 620: } ! 621: else { ! 622: if (preen == 0) ! 623: printf("\n"); ! 624: if(freemap) ! 625: copy(blkmap,freemap,(MEMSIZE)bmapsz); ! 626: else { ! 627: for(blk = 0; blk < fmapblk; blk++) { ! 628: bp1 = getblk((BUFAREA *)NULL,blk); ! 629: bp2 = getblk((BUFAREA *)NULL,blk+fmapblk); ! 630: copy(bp1->b_un.b_buf,bp2->b_un.b_buf,BSIZE(big)); ! 631: dirty(bp2); ! 632: } ! 633: } ! 634: badblk = dupblk = 0; ! 635: if(big == SMALL) { ! 636: freeblk.df_nfree = superblk.s_nfree; ! 637: for(n = 0; n < NICFREE; n++) ! 638: freeblk.df_free[n] = superblk.s_free[n]; ! 639: } ! 640: freechk(); ! 641: if(badblk) { ! 642: pfatal("%d BAD BLKS IN FREE LIST",badblk); ! 643: printf("\n"); ! 644: } ! 645: if(dupblk) ! 646: pwarn("%d DUP BLKS IN FREE LIST\n",dupblk); ! 647: if(fixfree == 0) { ! 648: if((n_blks+n_free) != (fmax-fmin)) { ! 649: pwarn("%ld BLK(S) MISSING\n", ! 650: fmax-fmin-n_blks-n_free); ! 651: fixfree = 1; ! 652: } ! 653: else if(big == SMALL && n_free != superblk.s_tfree) { ! 654: pwarn("FREE BLK COUNT WRONG IN SUPERBLK"); ! 655: if (preen) ! 656: printf(" (FIXED)\n"); ! 657: if(preen || reply("FIX") == YES) { ! 658: superblk.s_tfree = n_free; ! 659: sbdirty(); ! 660: } ! 661: } ! 662: } ! 663: if(fixfree) { ! 664: pwarn("BAD FREE LIST"); ! 665: if (preen) ! 666: printf(" (SALVAGED)\n"); ! 667: else if(reply("SALVAGE") == NO) ! 668: fixfree = 0; ! 669: } ! 670: } ! 671: ! 672: if(fixfree) { ! 673: if (preen == 0) ! 674: printf("** Phase 6 - Salvage Free List\n"); ! 675: makefree(); ! 676: n_free = superblk.s_tfree; ! 677: } ! 678: ! 679: pwarn("%ld files %ld blocks %ld free\n", n_files,n_blks,n_free); ! 680: if(dfile.mod) { ! 681: time(&superblk.s_time); ! 682: sbdirty(); ! 683: } ! 684: ckfini(); ! 685: sync(); ! 686: if(dfile.mod && hotroot) { ! 687: printf("ROOT MODIFIED\n"); ! 688: } ! 689: if(dfile.mod && preen == 0) ! 690: printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); ! 691: } ! 692: ! 693: /* VARARGS1 */ ! 694: error(s1,s2,s3,s4) ! 695: char *s1; ! 696: { ! 697: printf(s1,s2,s3,s4); ! 698: } ! 699: ! 700: /* VARARGS1 */ ! 701: errexit(s1,s2,s3,s4) ! 702: char *s1; ! 703: { ! 704: error(s1,s2,s3,s4); ! 705: exit(8); ! 706: } ! 707: ! 708: /* ! 709: * Pfatal is called when an inconsistency occurs ! 710: * which should not happen during normal operations. ! 711: * It prints a message and then dies. ! 712: * When not preening, this is just a printf. ! 713: */ ! 714: pfatal(s,a1,a2,a3) ! 715: { ! 716: ! 717: if (preen) { ! 718: printf("%s: ", devname); ! 719: printf(s, a1, a2, a3); ! 720: printf("\n"); ! 721: preendie(); ! 722: } ! 723: printf(s, a1, a2, a3); ! 724: } ! 725: ! 726: /* ! 727: * Fatal is called to terminate preening ! 728: * due to unexplainable inconsistency. ! 729: */ ! 730: preendie() ! 731: { ! 732: ! 733: printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname); ! 734: exit(8); ! 735: } ! 736: ! 737: /* ! 738: * Pwarn is like printf when not preening, ! 739: * or a warning (preceded by filename) when preening. ! 740: */ ! 741: pwarn(s,a1,a2,a3,a4,a5,a6) ! 742: { ! 743: ! 744: if (preen) ! 745: printf("%s: ", devname); ! 746: printf(s, a1, a2, a3, a4, a5, a6); ! 747: } ! 748: ! 749: ckinode(dp,flg) ! 750: DINODE *dp; ! 751: register flg; ! 752: { ! 753: register daddr_t *ap; ! 754: register ret; ! 755: int (*func)(), n; ! 756: daddr_t iaddrs[NADDR]; ! 757: ! 758: if(SPECIAL) ! 759: return(KEEPON); ! 760: l3tol(iaddrs,dp->di_addr,NADDR); ! 761: func = (flg == ADDR) ? pfunc : dirscan; ! 762: for(ap = iaddrs; ap < &iaddrs[NADDR-3]; ap++) { ! 763: if(*ap && (ret = (*func)(*ap)) & STOP) ! 764: return(ret); ! 765: } ! 766: for(n = 1; n < 4; n++) { ! 767: if(*ap && (ret = iblock(*ap,n,flg)) & STOP) ! 768: return(ret); ! 769: ap++; ! 770: } ! 771: return(KEEPON); ! 772: } ! 773: ! 774: ! 775: iblock(blk,ilevel,flg) ! 776: daddr_t blk; ! 777: register ilevel; ! 778: { ! 779: register daddr_t *ap; ! 780: register n; ! 781: int (*func)(); ! 782: BUFAREA ib; ! 783: ! 784: if(flg == ADDR) { ! 785: func = pfunc; ! 786: if(((n = (*func)(blk)) & KEEPON) == 0) ! 787: return(n); ! 788: } ! 789: else ! 790: func = dirscan; ! 791: if(outrange(blk)) /* protect thyself */ ! 792: return(SKIP); ! 793: initbarea(&ib); ! 794: if(getblk(&ib,blk) == NULL) ! 795: return(SKIP); ! 796: ilevel--; ! 797: for(ap = ib.b_un.b_indir; ap < &ib.b_un.b_indir[NINDIR(big)]; ap++) { ! 798: if(*ap) { ! 799: if(ilevel > 0) { ! 800: n = iblock(*ap,ilevel,flg); ! 801: } ! 802: else ! 803: n = (*func)(*ap); ! 804: if(n & STOP) ! 805: return(n); ! 806: } ! 807: } ! 808: return(KEEPON); ! 809: } ! 810: ! 811: ! 812: pass1(blk) ! 813: daddr_t blk; ! 814: { ! 815: register daddr_t *dlp; ! 816: ! 817: if(outrange(blk)) { ! 818: blkerr("BAD",blk); ! 819: if(++badblk >= MAXBAD) { ! 820: printf("EXCESSIVE BAD BLKS I=%u",inum); ! 821: if(reply("CONTINUE") == NO) ! 822: errexit(""); ! 823: return(STOP); ! 824: } ! 825: return(SKIP); ! 826: } ! 827: if(getbmap(blk)) { ! 828: blkerr("DUP",blk); ! 829: if(++dupblk >= MAXDUP) { ! 830: printf("EXCESSIVE DUP BLKS I=%u",inum); ! 831: if(reply("CONTINUE") == NO) ! 832: errexit(""); ! 833: return(STOP); ! 834: } ! 835: if(enddup >= &duplist[DUPTBLSIZE]) { ! 836: printf("DUP TABLE OVERFLOW."); ! 837: if(reply("CONTINUE") == NO) ! 838: errexit(""); ! 839: return(STOP); ! 840: } ! 841: for(dlp = duplist; dlp < muldup; dlp++) { ! 842: if(*dlp == blk) { ! 843: *enddup++ = blk; ! 844: break; ! 845: } ! 846: } ! 847: if(dlp >= muldup) { ! 848: *enddup++ = *muldup; ! 849: *muldup++ = blk; ! 850: } ! 851: } ! 852: else { ! 853: n_blks++; ! 854: setbmap(blk); ! 855: } ! 856: filsize++; ! 857: return(KEEPON); ! 858: } ! 859: ! 860: ! 861: pass1b(blk) ! 862: daddr_t blk; ! 863: { ! 864: register daddr_t *dlp; ! 865: ! 866: if(outrange(blk)) ! 867: return(SKIP); ! 868: for(dlp = duplist; dlp < muldup; dlp++) { ! 869: if(*dlp == blk) { ! 870: blkerr("DUP",blk); ! 871: *dlp = *--muldup; ! 872: *muldup = blk; ! 873: return(muldup == duplist ? STOP : KEEPON); ! 874: } ! 875: } ! 876: return(KEEPON); ! 877: } ! 878: ! 879: ! 880: pass2(dirp) ! 881: register DIRECT *dirp; ! 882: { ! 883: register char *p; ! 884: register n; ! 885: DINODE *dp; ! 886: ! 887: if((inum = dirp->d_ino) == 0) ! 888: return(KEEPON); ! 889: thisname = pathp; ! 890: for(p = dirp->d_name; p < &dirp->d_name[DIRSIZ]; ) ! 891: if((*pathp++ = *p++) == 0) { ! 892: --pathp; ! 893: break; ! 894: } ! 895: *pathp = 0; ! 896: n = NO; ! 897: if(inum > imax || inum < ROOTINO) ! 898: n = direrr("I OUT OF RANGE"); ! 899: else { ! 900: again: ! 901: switch(getstate()) { ! 902: case USTATE: ! 903: n = direrr("UNALLOCATED"); ! 904: break; ! 905: case CLEAR: ! 906: if((n = direrr("DUP/BAD")) == YES) ! 907: break; ! 908: if((dp = ginode()) == NULL) ! 909: break; ! 910: setstate(DIR ? DSTATE : FSTATE); ! 911: goto again; ! 912: case FSTATE: ! 913: declncnt(); ! 914: break; ! 915: case DSTATE: ! 916: declncnt(); ! 917: descend(); ! 918: } ! 919: } ! 920: pathp = thisname; ! 921: if(n == NO) ! 922: return(KEEPON); ! 923: dirp->d_ino = 0; ! 924: return(KEEPON|ALTERD); ! 925: } ! 926: ! 927: ! 928: pass4(blk) ! 929: daddr_t blk; ! 930: { ! 931: register daddr_t *dlp; ! 932: ! 933: if(outrange(blk)) ! 934: return(SKIP); ! 935: if(getbmap(blk)) { ! 936: for(dlp = duplist; dlp < enddup; dlp++) ! 937: if(*dlp == blk) { ! 938: *dlp = *--enddup; ! 939: return(KEEPON); ! 940: } ! 941: clrbmap(blk); ! 942: n_blks--; ! 943: } ! 944: return(KEEPON); ! 945: } ! 946: ! 947: ! 948: pass5(blk) ! 949: daddr_t blk; ! 950: { ! 951: if(outrange(blk)) { ! 952: fixfree = 1; ! 953: if (preen) ! 954: pfatal("BAD BLOCKS IN FREE LIST."); ! 955: if(++badblk >= MAXBAD) { ! 956: printf("EXCESSIVE BAD BLKS IN FREE LIST."); ! 957: if(reply("CONTINUE") == NO) ! 958: errexit(""); ! 959: return(STOP); ! 960: } ! 961: return(SKIP); ! 962: } ! 963: if(getfmap(blk)) { ! 964: fixfree = 1; ! 965: if(++dupblk >= DUPTBLSIZE) { ! 966: printf("EXCESSIVE DUP BLKS IN FREE LIST."); ! 967: if(reply("CONTINUE") == NO) ! 968: errexit(""); ! 969: return(STOP); ! 970: } ! 971: } ! 972: else { ! 973: n_free++; ! 974: setfmap(blk); ! 975: } ! 976: return(KEEPON); ! 977: } ! 978: ! 979: ! 980: blkerr(s,blk) ! 981: daddr_t blk; ! 982: char *s; ! 983: { ! 984: pfatal("%ld %s I=%u",blk,s,inum); ! 985: printf("\n"); ! 986: setstate(CLEAR); /* mark for possible clearing */ ! 987: } ! 988: ! 989: ! 990: descend() ! 991: { ! 992: register DINODE *dp; ! 993: register char *savname; ! 994: off_t savsize; ! 995: ! 996: setstate(FSTATE); ! 997: if((dp = ginode()) == NULL) ! 998: return; ! 999: savname = thisname; ! 1000: *pathp++ = '/'; ! 1001: savsize = filsize; ! 1002: filsize = dp->di_size; ! 1003: ckinode(dp,DATA); ! 1004: thisname = savname; ! 1005: *--pathp = 0; ! 1006: filsize = savsize; ! 1007: } ! 1008: ! 1009: ! 1010: dirscan(blk) ! 1011: daddr_t blk; ! 1012: { ! 1013: register DIRECT *dirp; ! 1014: register char *p1, *p2; ! 1015: register n; ! 1016: DIRECT direntry; ! 1017: ! 1018: if(outrange(blk)) { ! 1019: filsize -= BSIZE(big); ! 1020: return(SKIP); ! 1021: } ! 1022: for(dirp = dirblk.b_dir; dirp < &dirblk.b_dir[NDIRECT(big)] && ! 1023: filsize > 0; dirp++, filsize -= sizeof(DIRECT)) { ! 1024: if(getblk(&fileblk,blk) == NULL) { ! 1025: filsize -= (&dirblk.b_dir[NDIRECT(big)]-dirp)* ! 1026: sizeof(DIRECT); ! 1027: return(SKIP); ! 1028: } ! 1029: p1 = &dirp->d_name[DIRSIZ]; ! 1030: p2 = &direntry.d_name[DIRSIZ]; ! 1031: while(p1 > (char *)dirp) ! 1032: *--p2 = *--p1; ! 1033: if((n = (*pfunc)(&direntry)) & ALTERD) { ! 1034: if(getblk(&fileblk,blk) != NULL) { ! 1035: p1 = &dirp->d_name[DIRSIZ]; ! 1036: p2 = &direntry.d_name[DIRSIZ]; ! 1037: while(p1 > (char *)dirp) ! 1038: *--p1 = *--p2; ! 1039: fbdirty(); ! 1040: } ! 1041: else ! 1042: n &= ~ALTERD; ! 1043: } ! 1044: if(n & STOP) ! 1045: return(n); ! 1046: } ! 1047: return(filsize > 0 ? KEEPON : STOP); ! 1048: } ! 1049: ! 1050: ! 1051: direrr(s) ! 1052: char *s; ! 1053: { ! 1054: register DINODE *dp; ! 1055: ! 1056: pwarn("%s ",s); ! 1057: pinode(); ! 1058: printf("\n"); ! 1059: if((dp = ginode()) != NULL && ftypeok(dp)) ! 1060: pfatal("%s=%s",DIR?"DIR":"FILE",pathname); ! 1061: else ! 1062: pfatal("NAME=%s",pathname); ! 1063: return(reply("REMOVE")); ! 1064: } ! 1065: ! 1066: ! 1067: adjust(lcnt) ! 1068: register short lcnt; ! 1069: { ! 1070: register DINODE *dp; ! 1071: ! 1072: if((dp = ginode()) == NULL) ! 1073: return; ! 1074: if(dp->di_nlink == lcnt) { ! 1075: if(linkup() == NO) ! 1076: clri("UNREF",NO); ! 1077: } ! 1078: else { ! 1079: pwarn("LINK COUNT %s", ! 1080: (lfdir==inum)?lfname:(DIR?"DIR":"FILE")); ! 1081: pinode(); ! 1082: printf(" COUNT %d SHOULD BE %d", ! 1083: dp->di_nlink,dp->di_nlink-lcnt); ! 1084: if (preen) { ! 1085: if (lcnt < 0) { ! 1086: printf("\n"); ! 1087: preendie(); ! 1088: } ! 1089: printf(" (ADJUSTED)\n"); ! 1090: } ! 1091: if(preen || reply("ADJUST") == YES) { ! 1092: dp->di_nlink -= lcnt; ! 1093: inodirty(); ! 1094: } ! 1095: } ! 1096: } ! 1097: ! 1098: ! 1099: clri(s,flg) ! 1100: char *s; ! 1101: { ! 1102: register DINODE *dp; ! 1103: ! 1104: if((dp = ginode()) == NULL) ! 1105: return; ! 1106: if(flg == YES) { ! 1107: pwarn("%s %s",s,DIR?"DIR":"FILE"); ! 1108: pinode(); ! 1109: } ! 1110: if(preen || reply("CLEAR") == YES) { ! 1111: if (preen) ! 1112: printf(" (CLEARED)\n"); ! 1113: n_files--; ! 1114: pfunc = pass4; ! 1115: ckinode(dp,ADDR); ! 1116: zapino(dp); ! 1117: inodirty(); ! 1118: } ! 1119: } ! 1120: ! 1121: ! 1122: setup(dev) ! 1123: char *dev; ! 1124: { ! 1125: register n; ! 1126: register BUFAREA *bp; ! 1127: register MEMSIZE msize; ! 1128: char *mbase; ! 1129: daddr_t bcnt, nscrblk; ! 1130: dev_t rootdev; ! 1131: off_t smapsz, lncntsz, totsz; ! 1132: struct stat statarea; ! 1133: ! 1134: if(stat("/",&statarea) < 0) ! 1135: errexit("Can't stat root\n"); ! 1136: rootdev = statarea.st_dev; ! 1137: if(stat(dev,&statarea) < 0) { ! 1138: error("Can't stat %s\n",dev); ! 1139: return(NO); ! 1140: } ! 1141: rawflg = 0; ! 1142: big = SMALL; /* does this undo the work in blockcheck? */ ! 1143: if((statarea.st_mode & S_IFMT) == S_IFBLK) { ! 1144: if(BITFS(statarea.st_rdev)) ! 1145: big = BIG; ! 1146: } ! 1147: else if((statarea.st_mode & S_IFMT) == S_IFCHR) ! 1148: rawflg++; ! 1149: else { ! 1150: if (reply("file is not a block or character device; OK") == NO) ! 1151: return(NO); ! 1152: } ! 1153: if(rootdev == statarea.st_rdev) ! 1154: hotroot++; ! 1155: if((dfile.rfdes = open(dev,0)) < 0) { ! 1156: error("Can't open %s\n",dev); ! 1157: return(NO); ! 1158: } ! 1159: if (preen == 0) ! 1160: printf("\n%s",dev); ! 1161: if(nflag || (dfile.wfdes = open(dev,1)) < 0) { ! 1162: dfile.wfdes = -1; ! 1163: if (preen) ! 1164: pfatal("NO WRITE ACCESS"); ! 1165: printf(" (NO WRITE)"); ! 1166: } ! 1167: if (preen == 0) ! 1168: printf("\n"); ! 1169: fixfree = 0; ! 1170: dfile.mod = 0; ! 1171: n_files = n_blks = n_free = 0; ! 1172: muldup = enddup = &duplist[0]; ! 1173: badlnp = &badlncnt[0]; ! 1174: lfdir = 0; ! 1175: rplyflag = 0; ! 1176: initbarea(&sblk); ! 1177: initbarea(&fileblk); ! 1178: initbarea(&inoblk); ! 1179: sfile.wfdes = sfile.rfdes = -1; ! 1180: rmscr = 0; ! 1181: if(getblk(&sblk,SUPERB) == NULL) { ! 1182: ckfini(); ! 1183: return(NO); ! 1184: } ! 1185: imax = ((ino_t)superblk.s_isize - (SUPERB+1)) * INOPB(big); ! 1186: fmin = (daddr_t)superblk.s_isize; /* first data blk num */ ! 1187: fmax = superblk.s_fsize; /* first invalid blk num */ ! 1188: if(fmin >= fmax || ! 1189: (imax/INOPB(big)) != ((ino_t)superblk.s_isize-(SUPERB+1))) { ! 1190: pfatal("Size check: fsize %ld isize %d", ! 1191: superblk.s_fsize,superblk.s_isize); ! 1192: printf("\n"); ! 1193: ckfini(); ! 1194: return(NO); ! 1195: } ! 1196: if (preen == 0) ! 1197: printf("File System: %.12s\n\n", superblk.s_fsmnt); ! 1198: bmapsz = roundup(howmany(fmax,BITSPB),sizeof(*lncntp)); ! 1199: smapsz = roundup(howmany((long)(imax+1),STATEPB),sizeof(*lncntp)); ! 1200: lncntsz = (long)(imax+1) * sizeof(*lncntp); ! 1201: if(bmapsz > smapsz+lncntsz) ! 1202: smapsz = bmapsz-lncntsz; ! 1203: totsz = bmapsz+smapsz+lncntsz; ! 1204: msize = memsize; ! 1205: mbase = membase; ! 1206: if(rawflg) { ! 1207: if(msize < (MEMSIZE)(NINOBLK*BSIZE(big)) + 2*sizeof(BUFAREA)) ! 1208: rawflg = 0; ! 1209: else { ! 1210: msize -= (MEMSIZE)NINOBLK*BSIZE(big); ! 1211: mbase += (MEMSIZE)NINOBLK*BSIZE(big); ! 1212: niblk = NINOBLK; ! 1213: startib = fmax; ! 1214: } ! 1215: } ! 1216: clear(mbase,msize); ! 1217: if((off_t)msize < totsz) { ! 1218: bmapsz = roundup(bmapsz,BSIZE(big)); ! 1219: smapsz = roundup(smapsz,BSIZE(big)); ! 1220: lncntsz = roundup(lncntsz,BSIZE(big)); ! 1221: nscrblk = (bmapsz+smapsz+lncntsz)>>BSHIFT(big); ! 1222: if(tflag == 0) { ! 1223: printf("\nNEED SCRATCH FILE (%ld BLKS)\n",nscrblk); ! 1224: do { ! 1225: printf("ENTER FILENAME: "); ! 1226: if((n = getline(stdin,scrfile,sizeof(scrfile))) == EOF) ! 1227: errexit("\n"); ! 1228: } while(n == 0); ! 1229: } ! 1230: if(stat(scrfile,&statarea) < 0 || ! 1231: (statarea.st_mode & S_IFMT) == S_IFREG) ! 1232: rmscr++; ! 1233: if((sfile.wfdes = creat(scrfile,0666)) < 0 || ! 1234: (sfile.rfdes = open(scrfile,0)) < 0) { ! 1235: error("Can't create %s\n",scrfile); ! 1236: ckfini(); ! 1237: return(NO); ! 1238: } ! 1239: bp = &((BUFAREA *)mbase)[(msize/sizeof(BUFAREA))]; ! 1240: poolhead = NULL; ! 1241: while(--bp >= (BUFAREA *)mbase) { ! 1242: initbarea(bp); ! 1243: bp->b_next = poolhead; ! 1244: poolhead = bp; ! 1245: } ! 1246: bp = poolhead; ! 1247: for(bcnt = 0; bcnt < nscrblk; bcnt++) { ! 1248: bp->b_bno = bcnt; ! 1249: dirty(bp); ! 1250: flush(&sfile,bp); ! 1251: } ! 1252: blkmap = freemap = statemap = (char *) NULL; ! 1253: lncntp = (short *) NULL; ! 1254: smapblk = bmapsz / BSIZE(big); ! 1255: lncntblk = smapblk + smapsz / BSIZE(big); ! 1256: fmapblk = smapblk; ! 1257: } ! 1258: else { ! 1259: if(rawflg && (off_t)msize > totsz+BSIZE(big)) { ! 1260: niblk += (unsigned)((off_t)msize-totsz)>>BSHIFT(big); ! 1261: if(niblk > MAXRAW) ! 1262: niblk = MAXRAW; ! 1263: msize = memsize - (niblk*BSIZE(big)); ! 1264: mbase = membase + (niblk*BSIZE(big)); ! 1265: } ! 1266: poolhead = NULL; ! 1267: blkmap = mbase; ! 1268: statemap = &mbase[(MEMSIZE)bmapsz]; ! 1269: freemap = statemap; ! 1270: lncntp = (short *)&statemap[(MEMSIZE)smapsz]; ! 1271: } ! 1272: return(YES); ! 1273: } ! 1274: ! 1275: ! 1276: DINODE * ! 1277: ginode() ! 1278: { ! 1279: register DINODE *dp; ! 1280: register char *mbase; ! 1281: daddr_t iblk; ! 1282: ! 1283: if(inum > imax) ! 1284: return(NULL); ! 1285: iblk = itod(big, inum); ! 1286: if(rawflg) { ! 1287: mbase = membase; ! 1288: if(iblk < startib || iblk >= startib+niblk) { ! 1289: if(inoblk.b_dirty) ! 1290: bwrite(&dfile,mbase,startib,(int)niblk*BSIZE(big)); ! 1291: inoblk.b_dirty = 0; ! 1292: if(bread(&dfile,mbase,iblk,(int)niblk*BSIZE(big)) == NO) { ! 1293: startib = fmax; ! 1294: return(NULL); ! 1295: } ! 1296: startib = iblk; ! 1297: } ! 1298: dp = (DINODE *)&mbase[(unsigned)((iblk-startib)<<BSHIFT(big))]; ! 1299: } ! 1300: else if(getblk(&inoblk,iblk) != NULL) ! 1301: dp = inoblk.b_un.b_dinode; ! 1302: else ! 1303: return(NULL); ! 1304: return(dp + itoo(big, inum)); ! 1305: } ! 1306: ! 1307: ! 1308: ftypeok(dp) ! 1309: DINODE *dp; ! 1310: { ! 1311: switch(dp->di_mode & IFMT) { ! 1312: case IFDIR: ! 1313: case IFREG: ! 1314: case IFBLK: ! 1315: case IFCHR: ! 1316: /* case IFMPC: */ ! 1317: case IFLNK: ! 1318: /* case IFMPB: */ ! 1319: return(YES); ! 1320: default: ! 1321: return(NO); ! 1322: } ! 1323: } ! 1324: ! 1325: ! 1326: reply(s) ! 1327: char *s; ! 1328: { ! 1329: char line[80]; ! 1330: ! 1331: if (preen) ! 1332: pfatal("INTERNAL ERROR: GOT TO reply()"); ! 1333: rplyflag = 1; ! 1334: printf("\n%s? ",s); ! 1335: if(nflag || csflag || dfile.wfdes < 0) { ! 1336: printf(" no\n\n"); ! 1337: return(NO); ! 1338: } ! 1339: if(yflag) { ! 1340: printf(" yes\n\n"); ! 1341: return(YES); ! 1342: } ! 1343: if(getline(stdin,line,sizeof(line)) == EOF) ! 1344: errexit("\n"); ! 1345: printf("\n"); ! 1346: if(line[0] == 'y' || line[0] == 'Y') ! 1347: return(YES); ! 1348: else ! 1349: return(NO); ! 1350: } ! 1351: ! 1352: ! 1353: getline(fp,loc,maxlen) ! 1354: FILE *fp; ! 1355: char *loc; ! 1356: { ! 1357: register n; ! 1358: register char *p, *lastloc; ! 1359: ! 1360: p = loc; ! 1361: lastloc = &p[maxlen-1]; ! 1362: while((n = getc(fp)) != '\n') { ! 1363: if(n == EOF) ! 1364: return(EOF); ! 1365: if(!isspace(n) && p < lastloc) ! 1366: *p++ = n; ! 1367: } ! 1368: *p = 0; ! 1369: return(p - loc); ! 1370: } ! 1371: ! 1372: ! 1373: stype(p) ! 1374: register char *p; ! 1375: { ! 1376: if(*p == 0) ! 1377: return; ! 1378: if (*(p+1) == 0) { ! 1379: if (*p == '3') { ! 1380: cylsize = 200; ! 1381: stepsize = 5; ! 1382: return; ! 1383: } ! 1384: if (*p == '4') { ! 1385: cylsize = 418; ! 1386: stepsize = 9; ! 1387: return; ! 1388: } ! 1389: } ! 1390: cylsize = atoi(p); ! 1391: while(*p && *p != ':') ! 1392: p++; ! 1393: if(*p) ! 1394: p++; ! 1395: stepsize = atoi(p); ! 1396: if(stepsize <= 0 || stepsize > cylsize || ! 1397: cylsize <= 0 || cylsize > MAXCYL) { ! 1398: error("Invalid -s argument, defaults assumed\n"); ! 1399: cylsize = stepsize = 0; ! 1400: } ! 1401: } ! 1402: ! 1403: ! 1404: dostate(s,flg) ! 1405: { ! 1406: register char *p; ! 1407: register unsigned byte, shift; ! 1408: BUFAREA *bp; ! 1409: ! 1410: byte = (inum)/STATEPB; ! 1411: shift = LSTATE * ((inum)%STATEPB); ! 1412: if(statemap != NULL) { ! 1413: bp = NULL; ! 1414: p = &statemap[byte]; ! 1415: } ! 1416: else if((bp = getblk((BUFAREA *)NULL, ! 1417: (daddr_t)(smapblk+(byte/BSIZE(big))))) == NULL) ! 1418: errexit("Fatal I/O error\n"); ! 1419: else ! 1420: p = &bp->b_un.b_buf[byte%BSIZE(big)]; ! 1421: switch(flg) { ! 1422: case 0: ! 1423: *p &= ~(SMASK<<(shift)); ! 1424: *p |= s<<(shift); ! 1425: if(bp != NULL) ! 1426: dirty(bp); ! 1427: return(s); ! 1428: case 1: ! 1429: return((*p>>(shift)) & SMASK); ! 1430: } ! 1431: return(USTATE); ! 1432: } ! 1433: ! 1434: ! 1435: domap(blk,flg) ! 1436: daddr_t blk; ! 1437: { ! 1438: register char *p; ! 1439: register unsigned n; ! 1440: register BUFAREA *bp; ! 1441: off_t byte; ! 1442: ! 1443: byte = blk >> BITSHIFT; ! 1444: n = 1<<((unsigned)(blk & BITMASK)); ! 1445: if(flg & 04) { ! 1446: p = freemap; ! 1447: blk = fmapblk; ! 1448: } ! 1449: else { ! 1450: p = blkmap; ! 1451: blk = 0; ! 1452: } ! 1453: if(p != NULL) { ! 1454: bp = NULL; ! 1455: p += (unsigned)byte; ! 1456: } ! 1457: else if((bp = getblk((BUFAREA *)NULL,blk+(byte>>BSHIFT(big)))) == NULL) ! 1458: errexit("Fatal I/O error\n"); ! 1459: else ! 1460: p = &bp->b_un.b_buf[(unsigned)(byte&BMASK(big))]; ! 1461: switch(flg&03) { ! 1462: case 0: ! 1463: *p |= n; ! 1464: break; ! 1465: case 1: ! 1466: n &= *p; ! 1467: bp = NULL; ! 1468: break; ! 1469: case 2: ! 1470: *p &= ~n; ! 1471: } ! 1472: if(bp != NULL) ! 1473: dirty(bp); ! 1474: return(n); ! 1475: } ! 1476: ! 1477: ! 1478: dolncnt(val,flg) ! 1479: short val; ! 1480: { ! 1481: register short *sp; ! 1482: register BUFAREA *bp; ! 1483: ! 1484: if(lncntp != NULL) { ! 1485: bp = NULL; ! 1486: sp = &lncntp[inum]; ! 1487: } ! 1488: else if((bp = getblk((BUFAREA *)NULL,(daddr_t)(lncntblk+(inum/SPERB(big))))) == NULL) ! 1489: errexit("Fatal I/O error\n"); ! 1490: else ! 1491: sp = &bp->b_un.b_lnks[inum%SPERB(big)]; ! 1492: switch(flg) { ! 1493: case 0: ! 1494: *sp = val; ! 1495: break; ! 1496: case 1: ! 1497: bp = NULL; ! 1498: break; ! 1499: case 2: ! 1500: (*sp)--; ! 1501: } ! 1502: if(bp != NULL) ! 1503: dirty(bp); ! 1504: return(*sp); ! 1505: } ! 1506: ! 1507: ! 1508: BUFAREA * ! 1509: getblk(bp,blk) ! 1510: daddr_t blk; ! 1511: register BUFAREA *bp; ! 1512: { ! 1513: register struct filecntl *fcp; ! 1514: ! 1515: if(bp == NULL) { ! 1516: bp = search(blk); ! 1517: fcp = &sfile; ! 1518: } ! 1519: else ! 1520: fcp = &dfile; ! 1521: if(bp->b_bno == blk) ! 1522: return(bp); ! 1523: flush(fcp,bp); ! 1524: if(bread(fcp,bp->b_un.b_buf,blk,BSIZE(big)) != NO) { ! 1525: bp->b_bno = blk; ! 1526: return(bp); ! 1527: } ! 1528: bp->b_bno = (daddr_t)-1; ! 1529: return(NULL); ! 1530: } ! 1531: ! 1532: ! 1533: flush(fcp,bp) ! 1534: struct filecntl *fcp; ! 1535: register BUFAREA *bp; ! 1536: { ! 1537: if(bp->b_dirty) { ! 1538: bwrite(fcp,bp->b_un.b_buf,bp->b_bno,BSIZE(big)); ! 1539: } ! 1540: bp->b_dirty = 0; ! 1541: } ! 1542: ! 1543: ! 1544: rwerr(s,blk) ! 1545: char *s; ! 1546: daddr_t blk; ! 1547: { ! 1548: if (preen == 0) ! 1549: printf("\n"); ! 1550: pfatal("CAN NOT %s: BLK %ld",s,blk); ! 1551: if(reply("CONTINUE") == NO) ! 1552: errexit("Program terminated\n"); ! 1553: } ! 1554: ! 1555: ! 1556: sizechk(dp) ! 1557: register DINODE *dp; ! 1558: { ! 1559: /* ! 1560: if (maxblk != howmany(dp->di_size, BSIZE)) ! 1561: printf("POSSIBLE FILE SIZE ERROR I=%u (%ld,%ld)\n\n", ! 1562: inum, maxblk, howmany(dp->di_size,BSIZE)); ! 1563: */ ! 1564: if(DIR && (dp->di_size % sizeof(DIRECT)) != 0) { ! 1565: pwarn("DIRECTORY MISALIGNED I=%u\n",inum); ! 1566: if (preen == 0) ! 1567: printf("\n"); ! 1568: } ! 1569: } ! 1570: ! 1571: ! 1572: ckfini() ! 1573: { ! 1574: flush(&dfile,&fileblk); ! 1575: flush(&dfile,&sblk); ! 1576: flush(&dfile,&inoblk); ! 1577: close(dfile.rfdes); ! 1578: close(dfile.wfdes); ! 1579: close(sfile.rfdes); ! 1580: close(sfile.wfdes); ! 1581: if(rmscr) { ! 1582: unlink(scrfile); ! 1583: } ! 1584: } ! 1585: ! 1586: ! 1587: pinode() ! 1588: { ! 1589: register DINODE *dp; ! 1590: register char *p; ! 1591: char uidbuf[200]; ! 1592: char *ctime(); ! 1593: ! 1594: printf(" I=%u ",inum); ! 1595: if((dp = ginode()) == NULL) ! 1596: return; ! 1597: printf(" OWNER="); ! 1598: if(getpw((int)dp->di_uid,uidbuf) == 0) { ! 1599: for(p = uidbuf; *p != ':'; p++); ! 1600: *p = 0; ! 1601: printf("%s ",uidbuf); ! 1602: } ! 1603: else { ! 1604: printf("%d ",dp->di_uid); ! 1605: } ! 1606: printf("MODE=%o\n",dp->di_mode); ! 1607: if (preen) ! 1608: printf("%s: ", devname); ! 1609: printf("SIZE=%ld ",dp->di_size); ! 1610: p = ctime(&dp->di_mtime); ! 1611: printf("MTIME=%12.12s %4.4s ",p+4,p+20); ! 1612: } ! 1613: ! 1614: ! 1615: copy(fp,tp,size) ! 1616: register char *tp, *fp; ! 1617: MEMSIZE size; ! 1618: { ! 1619: while(size--) ! 1620: *tp++ = *fp++; ! 1621: } ! 1622: ! 1623: ! 1624: freechk() ! 1625: { ! 1626: register daddr_t *ap; ! 1627: register int i, j; ! 1628: ! 1629: if(big == BIG) { ! 1630: for(i = superblk.s_isize; i < superblk.s_fsize; i++) { ! 1631: j = i - superblk.s_isize; ! 1632: if(!getfmap(i)) { ! 1633: superblk.s_bfree[j>>5] |= (1 << (j&31)); ! 1634: n_free++; ! 1635: } ! 1636: else ! 1637: superblk.s_bfree[j>>5] &= ~(1 << (j&31)); ! 1638: } ! 1639: superblk.s_valid = 1; ! 1640: superblk.s_tfree = n_free; ! 1641: sbdirty(); ! 1642: return; ! 1643: } ! 1644: if(freeblk.df_nfree == 0) ! 1645: return; ! 1646: do { ! 1647: if(freeblk.df_nfree <= 0 || freeblk.df_nfree > NICFREE) { ! 1648: pwarn("BAD FREEBLK COUNT"); ! 1649: printf("\n"); ! 1650: fixfree = 1; ! 1651: return; ! 1652: } ! 1653: ap = &freeblk.df_free[freeblk.df_nfree]; ! 1654: while(--ap > &freeblk.df_free[0]) { ! 1655: if(pass5(*ap) == STOP) ! 1656: return; ! 1657: } ! 1658: if(*ap == (daddr_t)0 || pass5(*ap) != KEEPON) ! 1659: return; ! 1660: } while(getblk(&fileblk,*ap) != NULL); ! 1661: } ! 1662: ! 1663: ! 1664: makefree() ! 1665: { ! 1666: register i, cyl, step; ! 1667: int j; ! 1668: char flg[MAXCYL]; ! 1669: short addr[MAXCYL]; ! 1670: daddr_t blk, baseblk; ! 1671: ! 1672: if(big == BIG) ! 1673: return; ! 1674: superblk.s_nfree = 0; ! 1675: superblk.s_flock = 0; ! 1676: superblk.s_fmod = 0; ! 1677: superblk.s_tfree = 0; ! 1678: superblk.s_ninode = 0; ! 1679: superblk.s_ilock = 0; ! 1680: superblk.s_ronly = 0; ! 1681: if(cylsize == 0 || stepsize == 0) { ! 1682: step = superblk.s_dinfo[0]; ! 1683: cyl = superblk.s_dinfo[1]; ! 1684: } ! 1685: else { ! 1686: step = stepsize; ! 1687: cyl = cylsize; ! 1688: } ! 1689: if(step > cyl || step <= 0 || cyl <= 0 || cyl > MAXCYL) { ! 1690: error("Default free list spacing assumed\n"); ! 1691: step = STEPSIZE; ! 1692: cyl = CYLSIZE; ! 1693: } ! 1694: superblk.s_dinfo[0] = step; ! 1695: superblk.s_dinfo[1] = cyl; ! 1696: clear(flg,sizeof(flg)); ! 1697: i = 0; ! 1698: for(j = 0; j < cyl; j++) { ! 1699: while(flg[i]) ! 1700: i = (i + 1) % cyl; ! 1701: addr[j] = i + 1; ! 1702: flg[i]++; ! 1703: i = (i + step) % cyl; ! 1704: } ! 1705: baseblk = (daddr_t)roundup(fmax,cyl); ! 1706: clear((char *)&freeblk,BSIZE(big)); ! 1707: freeblk.df_nfree++; ! 1708: for( ; baseblk > 0; baseblk -= cyl) ! 1709: for(i = 0; i < cyl; i++) { ! 1710: blk = baseblk - addr[i]; ! 1711: if(!outrange(blk) && !getbmap(blk)) { ! 1712: superblk.s_tfree++; ! 1713: if(freeblk.df_nfree >= NICFREE) { ! 1714: fbdirty(); ! 1715: fileblk.b_bno = blk; ! 1716: flush(&dfile,&fileblk); ! 1717: clear((char *)&freeblk,BSIZE(big)); ! 1718: } ! 1719: freeblk.df_free[freeblk.df_nfree] = blk; ! 1720: freeblk.df_nfree++; ! 1721: } ! 1722: } ! 1723: superblk.s_nfree = freeblk.df_nfree; ! 1724: for(i = 0; i < NICFREE; i++) ! 1725: superblk.s_free[i] = freeblk.df_free[i]; ! 1726: sbdirty(); ! 1727: } ! 1728: ! 1729: ! 1730: clear(p,cnt) ! 1731: register char *p; ! 1732: MEMSIZE cnt; ! 1733: { ! 1734: while(cnt--) ! 1735: *p++ = 0; ! 1736: } ! 1737: ! 1738: ! 1739: BUFAREA * ! 1740: search(blk) ! 1741: daddr_t blk; ! 1742: { ! 1743: register BUFAREA *pbp, *bp; ! 1744: ! 1745: for(bp = (BUFAREA *) &poolhead; bp->b_next; ) { ! 1746: pbp = bp; ! 1747: bp = pbp->b_next; ! 1748: if(bp->b_bno == blk) ! 1749: break; ! 1750: } ! 1751: pbp->b_next = bp->b_next; ! 1752: bp->b_next = poolhead; ! 1753: poolhead = bp; ! 1754: return(bp); ! 1755: } ! 1756: ! 1757: ! 1758: findino(dirp) ! 1759: register DIRECT *dirp; ! 1760: { ! 1761: register char *p1, *p2; ! 1762: ! 1763: if(dirp->d_ino == 0) ! 1764: return(KEEPON); ! 1765: for(p1 = dirp->d_name,p2 = srchname;*p2++ == *p1; p1++) { ! 1766: if(*p1 == 0 || p1 == &dirp->d_name[DIRSIZ-1]) { ! 1767: if(dirp->d_ino >= ROOTINO && dirp->d_ino <= imax) ! 1768: parentdir = dirp->d_ino; ! 1769: return(STOP); ! 1770: } ! 1771: } ! 1772: return(KEEPON); ! 1773: } ! 1774: ! 1775: ! 1776: mkentry(dirp) ! 1777: register DIRECT *dirp; ! 1778: { ! 1779: register ino_t in; ! 1780: register char *p; ! 1781: ! 1782: if(dirp->d_ino) ! 1783: return(KEEPON); ! 1784: dirp->d_ino = orphan; ! 1785: in = orphan; ! 1786: p = &dirp->d_name[8]; ! 1787: *--p = 0; ! 1788: while(p > dirp->d_name) { ! 1789: *--p = (in % 10) + '0'; ! 1790: in /= 10; ! 1791: } ! 1792: *p = '#'; ! 1793: return(ALTERD|STOP); ! 1794: } ! 1795: ! 1796: ! 1797: chgdd(dirp) ! 1798: register DIRECT *dirp; ! 1799: { ! 1800: if(dirp->d_name[0] == '.' && dirp->d_name[1] == '.' && ! 1801: dirp->d_name[2] == 0) { ! 1802: dirp->d_ino = lfdir; ! 1803: return(ALTERD|STOP); ! 1804: } ! 1805: return(KEEPON); ! 1806: } ! 1807: ! 1808: ! 1809: linkup() ! 1810: { ! 1811: register DINODE *dp; ! 1812: register lostdir; ! 1813: register ino_t pdir; ! 1814: ! 1815: if((dp = ginode()) == NULL) ! 1816: return(NO); ! 1817: lostdir = DIR; ! 1818: pdir = parentdir; ! 1819: pwarn("UNREF %s ",lostdir ? "DIR" : "FILE"); ! 1820: pinode(); ! 1821: if (preen && dp->di_size == 0) ! 1822: return(NO); ! 1823: if (preen) ! 1824: printf(" (RECONNECTED)\n"); ! 1825: else ! 1826: if (reply("RECONNECT") == NO) ! 1827: return(NO); ! 1828: orphan = inum; ! 1829: if(lfdir == 0) { ! 1830: inum = ROOTINO; ! 1831: if((dp = ginode()) == NULL) { ! 1832: inum = orphan; ! 1833: return(NO); ! 1834: } ! 1835: pfunc = findino; ! 1836: srchname = lfname; ! 1837: filsize = dp->di_size; ! 1838: parentdir = 0; ! 1839: ckinode(dp,DATA); ! 1840: inum = orphan; ! 1841: if((lfdir = parentdir) == 0) { ! 1842: pfatal("SORRY. NO lost+found DIRECTORY"); ! 1843: printf("\n\n"); ! 1844: return(NO); ! 1845: } ! 1846: } ! 1847: inum = lfdir; ! 1848: if((dp = ginode()) == NULL || !DIR || getstate() != FSTATE) { ! 1849: inum = orphan; ! 1850: pfatal("SORRY. NO lost+found DIRECTORY"); ! 1851: printf("\n\n"); ! 1852: return(NO); ! 1853: } ! 1854: if(dp->di_size & BMASK(big)) { ! 1855: dp->di_size = roundup(dp->di_size,BSIZE(big)); ! 1856: inodirty(); ! 1857: } ! 1858: filsize = dp->di_size; ! 1859: inum = orphan; ! 1860: pfunc = mkentry; ! 1861: if((ckinode(dp,DATA) & ALTERD) == 0) { ! 1862: pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); ! 1863: printf("\n\n"); ! 1864: return(NO); ! 1865: } ! 1866: declncnt(); ! 1867: if(lostdir) { ! 1868: pfunc = chgdd; ! 1869: dp = ginode(); ! 1870: filsize = dp->di_size; ! 1871: ckinode(dp,DATA); ! 1872: inum = lfdir; ! 1873: if((dp = ginode()) != NULL) { ! 1874: dp->di_nlink++; ! 1875: inodirty(); ! 1876: setlncnt(getlncnt()+1); ! 1877: } ! 1878: inum = orphan; ! 1879: pwarn("DIR I=%u CONNECTED. ",orphan); ! 1880: printf("PARENT WAS I=%u\n",pdir); ! 1881: if (preen == 0) ! 1882: printf("\n"); ! 1883: } ! 1884: return(YES); ! 1885: } ! 1886: ! 1887: ! 1888: bread(fcp,buf,blk,size) ! 1889: daddr_t blk; ! 1890: register struct filecntl *fcp; ! 1891: register size; ! 1892: char *buf; ! 1893: { ! 1894: if(lseek(fcp->rfdes,blk<<BSHIFT(big),0) < 0) ! 1895: rwerr("SEEK",blk); ! 1896: else if(read(fcp->rfdes,buf,size) == size) ! 1897: return(YES); ! 1898: rwerr("READ",blk); ! 1899: return(NO); ! 1900: } ! 1901: ! 1902: ! 1903: bwrite(fcp,buf,blk,size) ! 1904: daddr_t blk; ! 1905: register struct filecntl *fcp; ! 1906: register size; ! 1907: char *buf; ! 1908: { ! 1909: if(fcp->wfdes < 0) ! 1910: return(NO); ! 1911: if(lseek(fcp->wfdes,blk<<BSHIFT(big),0) < 0) ! 1912: rwerr("SEEK",blk); ! 1913: else if(write(fcp->wfdes,buf,size) == size) { ! 1914: fcp->mod = 1; ! 1915: return(YES); ! 1916: } ! 1917: rwerr("WRITE",blk); ! 1918: return(NO); ! 1919: } ! 1920: ! 1921: catch() ! 1922: { ! 1923: ckfini(); ! 1924: exit(12); ! 1925: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.