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