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