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