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