|
|
1.1 ! root 1: #ifndef lint ! 2: char version[] = "@(#)fsck.c 2.30 (Berkeley) 9/19/83"; ! 3: #endif ! 4: ! 5: #include <stdio.h> ! 6: #include <ctype.h> ! 7: #include <sys/param.h> ! 8: #include <sys/fs.h> ! 9: #include <sys/inode.h> ! 10: #include <sys/stat.h> ! 11: #include <sys/wait.h> ! 12: #include <fstab.h> ! 13: #define KERNEL ! 14: #include <sys/dir.h> ! 15: #undef KERNEL ! 16: ! 17: /* RECONSTRUCT ONLY BAD CG IN PASS 6 */ ! 18: ! 19: typedef int (*SIG_TYP)(); ! 20: ! 21: #define MAXNINDIR (MAXBSIZE / sizeof (daddr_t)) ! 22: #define MAXINOPB (MAXBSIZE / sizeof (struct dinode)) ! 23: #define SPERB (MAXBSIZE / sizeof(short)) ! 24: #define MINDIRSIZE (sizeof (struct dirtemplate)) ! 25: ! 26: #define MAXDUP 10 /* limit on dup blks (per inode) */ ! 27: #define MAXBAD 10 /* limit on bad blks (per inode) */ ! 28: ! 29: #define USTATE 0 /* inode not allocated */ ! 30: #define FSTATE 01 /* inode is file */ ! 31: #define DSTATE 02 /* inode is directory */ ! 32: #define CLEAR 03 /* inode is to be cleared */ ! 33: ! 34: typedef struct dinode DINODE; ! 35: typedef struct direct DIRECT; ! 36: ! 37: #define ALLOC ((dp->di_mode & IFMT) != 0) ! 38: #define DIRCT ((dp->di_mode & IFMT) == IFDIR) ! 39: #define REG ((dp->di_mode & IFMT) == IFREG) ! 40: #define BLK ((dp->di_mode & IFMT) == IFBLK) ! 41: #define CHR ((dp->di_mode & IFMT) == IFCHR) ! 42: #define LNK ((dp->di_mode & IFMT) == IFLNK) ! 43: #define SOCK ((dp->di_mode & IFMT) == IFSOCK) ! 44: #define BADBLK ((dp->di_mode & IFMT) == IFMT) ! 45: #define SPECIAL (BLK || CHR) ! 46: ! 47: struct bufarea { ! 48: struct bufarea *b_next; /* must be first */ ! 49: daddr_t b_bno; ! 50: int b_size; ! 51: union { ! 52: char b_buf[MAXBSIZE]; /* buffer space */ ! 53: short b_lnks[SPERB]; /* link counts */ ! 54: daddr_t b_indir[MAXNINDIR]; /* indirect block */ ! 55: struct fs b_fs; /* super block */ ! 56: struct cg b_cg; /* cylinder group */ ! 57: struct dinode b_dinode[MAXINOPB]; /* inode block */ ! 58: } b_un; ! 59: char b_dirty; ! 60: }; ! 61: ! 62: typedef struct bufarea BUFAREA; ! 63: ! 64: BUFAREA inoblk; /* inode blocks */ ! 65: BUFAREA fileblk; /* other blks in filesys */ ! 66: BUFAREA sblk; /* file system superblock */ ! 67: BUFAREA cgblk; /* cylinder group blocks */ ! 68: ! 69: #define initbarea(x) (x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1 ! 70: #define dirty(x) (x)->b_dirty = 1 ! 71: #define inodirty() inoblk.b_dirty = 1 ! 72: #define sbdirty() sblk.b_dirty = 1 ! 73: #define cgdirty() cgblk.b_dirty = 1 ! 74: ! 75: #define dirblk fileblk.b_un ! 76: #define sblock sblk.b_un.b_fs ! 77: #define cgrp cgblk.b_un.b_cg ! 78: ! 79: struct filecntl { ! 80: int rfdes; ! 81: int wfdes; ! 82: int mod; ! 83: } dfile; /* file descriptors for filesys */ ! 84: ! 85: struct inodesc { ! 86: char id_type; /* type of descriptor, DATA or ADDR */ ! 87: int (*id_func)(); /* function to be applied to blocks of inode */ ! 88: ino_t id_number; /* inode number described */ ! 89: ino_t id_parent; /* for DATA nodes, their parent */ ! 90: daddr_t id_blkno; /* current block number being examined */ ! 91: int id_numfrags; /* number of frags contained in block */ ! 92: long id_filesize; /* for DATA nodes, the size of the directory */ ! 93: int id_loc; /* for DATA nodes, current location in dir */ ! 94: int id_entryno; /* for DATA nodes, current entry number */ ! 95: DIRECT *id_dirp; /* for data nodes, ptr to current entry */ ! 96: enum {DONTKNOW, NOFIX, FIX} id_fix; /* policy on fixing errors */ ! 97: }; ! 98: /* file types */ ! 99: #define DATA 1 ! 100: #define ADDR 2 ! 101: ! 102: ! 103: #define DUPTBLSIZE 100 /* num of dup blocks to remember */ ! 104: daddr_t duplist[DUPTBLSIZE]; /* dup block table */ ! 105: daddr_t *enddup; /* next entry in dup table */ ! 106: daddr_t *muldup; /* multiple dups part of table */ ! 107: ! 108: #define MAXLNCNT 500 /* num zero link cnts to remember */ ! 109: ino_t badlncnt[MAXLNCNT]; /* table of inos with zero link cnts */ ! 110: ino_t *badlnp; /* next entry in table */ ! 111: ! 112: char rawflg; ! 113: char nflag; /* assume a no response */ ! 114: char yflag; /* assume a yes response */ ! 115: int bflag; /* location of alternate super block */ ! 116: int debug; /* output debugging info */ ! 117: char preen; /* just fix normal inconsistencies */ ! 118: char rplyflag; /* any questions asked? */ ! 119: char hotroot; /* checking root device */ ! 120: char fixcg; /* corrupted free list bit maps */ ! 121: ! 122: char *blockmap; /* ptr to primary blk allocation map */ ! 123: char *freemap; /* ptr to secondary blk allocation map */ ! 124: char *statemap; /* ptr to inode state table */ ! 125: short *lncntp; /* ptr to link count table */ ! 126: ! 127: char *srchname; /* name being searched for in dir */ ! 128: char pathname[BUFSIZ]; /* current pathname */ ! 129: char *pathp; /* pointer to pathname position */ ! 130: char *endpathname = &pathname[BUFSIZ - 2]; ! 131: ! 132: char *lfname = "lost+found"; ! 133: ! 134: ino_t imax; /* number of inodes */ ! 135: ino_t lastino; /* hiwater mark of inodes */ ! 136: ino_t lfdir; /* lost & found directory */ ! 137: ! 138: off_t maxblk; /* largest logical blk in file */ ! 139: off_t bmapsz; /* num chars in blockmap */ ! 140: ! 141: daddr_t n_ffree; /* number of small free blocks */ ! 142: daddr_t n_bfree; /* number of large free blocks */ ! 143: daddr_t n_blks; /* number of blocks used */ ! 144: daddr_t n_files; /* number of files seen */ ! 145: daddr_t n_index; ! 146: daddr_t n_bad; ! 147: daddr_t fmax; /* number of blocks in the volume */ ! 148: ! 149: daddr_t badblk; ! 150: daddr_t dupblk; ! 151: ! 152: int inosumbad; ! 153: int offsumbad; ! 154: int frsumbad; ! 155: int sbsumbad; ! 156: ! 157: #define zapino(x) (*(x) = zino) ! 158: struct dinode zino; ! 159: ! 160: #define setbmap(x) setbit(blockmap, x) ! 161: #define getbmap(x) isset(blockmap, x) ! 162: #define clrbmap(x) clrbit(blockmap, x) ! 163: ! 164: #define setfmap(x) setbit(freemap, x) ! 165: #define getfmap(x) isset(freemap, x) ! 166: #define clrfmap(x) clrbit(freemap, x) ! 167: ! 168: #define ALTERED 010 ! 169: #define KEEPON 04 ! 170: #define SKIP 02 ! 171: #define STOP 01 ! 172: ! 173: int (*signal())(); ! 174: long lseek(); ! 175: time_t time(); ! 176: DINODE *ginode(); ! 177: DIRECT *fsck_readdir(); ! 178: BUFAREA *getblk(); ! 179: int catch(); ! 180: int findino(), mkentry(), chgdd(); ! 181: int pass1check(), pass1bcheck(), pass2check(), pass4check(); ! 182: char *rawname(), *unrawname(); ! 183: char *calloc(), *strcpy(), *strcat(), *rindex(); ! 184: extern int inside[], around[]; ! 185: extern unsigned char *fragtbl[]; ! 186: ! 187: char *devname; ! 188: ! 189: main(argc, argv) ! 190: int argc; ! 191: char *argv[]; ! 192: { ! 193: struct fstab *fsp; ! 194: int pid, passno, anygtr, sumstatus; ! 195: ! 196: sync(); ! 197: while (--argc > 0 && **++argv == '-') { ! 198: switch (*++*argv) { ! 199: ! 200: case 'p': ! 201: preen++; ! 202: break; ! 203: ! 204: case 'b': ! 205: if (argv[0][1] != '\0') { ! 206: bflag = atoi(argv[0]+1); ! 207: } else { ! 208: bflag = atoi(*++argv); ! 209: argc--; ! 210: } ! 211: printf("Alternate super block location: %d\n", bflag); ! 212: break; ! 213: ! 214: case 'd': ! 215: debug++; ! 216: break; ! 217: ! 218: case 'n': /* default no answer flag */ ! 219: case 'N': ! 220: nflag++; ! 221: yflag = 0; ! 222: break; ! 223: ! 224: case 'y': /* default yes answer flag */ ! 225: case 'Y': ! 226: yflag++; ! 227: nflag = 0; ! 228: break; ! 229: ! 230: default: ! 231: errexit("%c option?\n", **argv); ! 232: } ! 233: } ! 234: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 235: (void)signal(SIGINT, catch); ! 236: if (argc) { ! 237: while (argc-- > 0) { ! 238: hotroot = 0; ! 239: checkfilesys(*argv++); ! 240: } ! 241: exit(0); ! 242: } ! 243: sumstatus = 0; ! 244: passno = 1; ! 245: do { ! 246: anygtr = 0; ! 247: if (setfsent() == 0) ! 248: errexit("Can't open checklist file: %s\n", FSTAB); ! 249: while ((fsp = getfsent()) != 0) { ! 250: if (strcmp(fsp->fs_type, FSTAB_RW) && ! 251: strcmp(fsp->fs_type, FSTAB_RO) && ! 252: strcmp(fsp->fs_type, FSTAB_RQ)) ! 253: continue; ! 254: if (preen == 0 || ! 255: passno == 1 && fsp->fs_passno == passno) { ! 256: if (blockcheck(fsp->fs_spec) == 0 && preen) ! 257: exit(8); ! 258: } else if (fsp->fs_passno > passno) ! 259: anygtr = 1; ! 260: else if (fsp->fs_passno == passno) { ! 261: pid = fork(); ! 262: if (pid < 0) { ! 263: perror("fork"); ! 264: exit(8); ! 265: } ! 266: if (pid == 0) ! 267: if (blockcheck(fsp->fs_spec)==0) ! 268: exit(8); ! 269: else ! 270: exit(0); ! 271: } ! 272: } ! 273: if (preen) { ! 274: union wait status; ! 275: while (wait(&status) != -1) ! 276: sumstatus |= status.w_retcode; ! 277: } ! 278: passno++; ! 279: } while (anygtr); ! 280: if (sumstatus) ! 281: exit(8); ! 282: (void)endfsent(); ! 283: exit(0); ! 284: } ! 285: ! 286: blockcheck(name) ! 287: char *name; ! 288: { ! 289: struct stat stslash, stblock, stchar; ! 290: char *raw; ! 291: int looped = 0; ! 292: ! 293: hotroot = 0; ! 294: if (stat("/", &stslash) < 0){ ! 295: error("Can't stat root\n"); ! 296: return (0); ! 297: } ! 298: retry: ! 299: if (stat(name, &stblock) < 0){ ! 300: error("Can't stat %s\n", name); ! 301: return (0); ! 302: } ! 303: if (stblock.st_mode & S_IFBLK) { ! 304: raw = rawname(name); ! 305: if (stat(raw, &stchar) < 0){ ! 306: error("Can't stat %s\n", raw); ! 307: return (0); ! 308: } ! 309: if (stchar.st_mode & S_IFCHR) { ! 310: if (stslash.st_dev == stblock.st_rdev) { ! 311: hotroot++; ! 312: raw = unrawname(name); ! 313: } ! 314: checkfilesys(raw); ! 315: return (1); ! 316: } else { ! 317: error("%s is not a character device\n", raw); ! 318: return (0); ! 319: } ! 320: } else if (stblock.st_mode & S_IFCHR) { ! 321: if (looped) { ! 322: error("Can't make sense out of name %s\n", name); ! 323: return (0); ! 324: } ! 325: name = unrawname(name); ! 326: looped++; ! 327: goto retry; ! 328: } ! 329: error("Can't make sense out of name %s\n", name); ! 330: return (0); ! 331: } ! 332: ! 333: checkfilesys(filesys) ! 334: char *filesys; ! 335: { ! 336: ! 337: devname = filesys; ! 338: if (setup(filesys) == 0) { ! 339: if (preen) ! 340: pfatal("CAN'T CHECK FILE SYSTEM."); ! 341: return; ! 342: } ! 343: /* 1: scan inodes tallying blocks used */ ! 344: if (preen == 0) { ! 345: printf("** Last Mounted on %s\n", sblock.fs_fsmnt); ! 346: if (hotroot) ! 347: printf("** Root file system\n"); ! 348: printf("** Phase 1 - Check Blocks and Sizes\n"); ! 349: } ! 350: pass1(); ! 351: ! 352: /* 1b: locate first references to duplicates, if any */ ! 353: if (enddup != &duplist[0]) { ! 354: if (preen) ! 355: pfatal("INTERNAL ERROR: dups with -p"); ! 356: printf("** Phase 1b - Rescan For More DUPS\n"); ! 357: pass1b(); ! 358: } ! 359: ! 360: /* 2: traverse directories from root to mark all connected directories */ ! 361: if (preen == 0) ! 362: printf("** Phase 2 - Check Pathnames\n"); ! 363: pass2(); ! 364: ! 365: /* 3: scan inodes looking for disconnected directories */ ! 366: if (preen == 0) ! 367: printf("** Phase 3 - Check Connectivity\n"); ! 368: pass3(); ! 369: ! 370: /* 4: scan inodes looking for disconnected files; check reference counts */ ! 371: if (preen == 0) ! 372: printf("** Phase 4 - Check Reference Counts\n"); ! 373: pass4(); ! 374: ! 375: /* 5: check resource counts in cylinder groups */ ! 376: if (preen == 0) ! 377: printf("** Phase 5 - Check Cyl groups\n"); ! 378: pass5(); ! 379: ! 380: if (fixcg) { ! 381: if (preen == 0) ! 382: printf("** Phase 6 - Salvage Cylinder Groups\n"); ! 383: makecg(); ! 384: n_ffree = sblock.fs_cstotal.cs_nffree; ! 385: n_bfree = sblock.fs_cstotal.cs_nbfree; ! 386: } ! 387: ! 388: pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n", ! 389: n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_fsize), ! 390: n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree); ! 391: if (dfile.mod) { ! 392: (void)time(&sblock.fs_time); ! 393: sbdirty(); ! 394: } ! 395: ckfini(); ! 396: free(blockmap); ! 397: free(freemap); ! 398: free(statemap); ! 399: free((char *)lncntp); ! 400: if (!dfile.mod) ! 401: return; ! 402: if (!preen) { ! 403: printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); ! 404: if (hotroot) ! 405: printf("\n***** REBOOT UNIX *****\n"); ! 406: } ! 407: if (hotroot) { ! 408: sync(); ! 409: exit(4); ! 410: } ! 411: } ! 412: ! 413: setup(dev) ! 414: char *dev; ! 415: { ! 416: dev_t rootdev; ! 417: struct stat statb; ! 418: daddr_t super = bflag ? bflag : SBLOCK; ! 419: int i, j, c, d, cgd; ! 420: long size; ! 421: BUFAREA asblk; ! 422: # define altsblock asblk.b_un.b_fs ! 423: ! 424: if (stat("/", &statb) < 0) ! 425: errexit("Can't stat root\n"); ! 426: rootdev = statb.st_dev; ! 427: if (stat(dev, &statb) < 0) { ! 428: error("Can't stat %s\n", dev); ! 429: return (0); ! 430: } ! 431: rawflg = 0; ! 432: if ((statb.st_mode & S_IFMT) == S_IFBLK) ! 433: ; ! 434: else if ((statb.st_mode & S_IFMT) == S_IFCHR) ! 435: rawflg++; ! 436: else { ! 437: if (reply("file is not a block or character device; OK") == 0) ! 438: return (0); ! 439: } ! 440: if (rootdev == statb.st_rdev) ! 441: hotroot++; ! 442: if ((dfile.rfdes = open(dev, 0)) < 0) { ! 443: error("Can't open %s\n", dev); ! 444: return (0); ! 445: } ! 446: if (preen == 0) ! 447: printf("** %s", dev); ! 448: if (nflag || (dfile.wfdes = open(dev, 1)) < 0) { ! 449: dfile.wfdes = -1; ! 450: if (preen) ! 451: pfatal("NO WRITE ACCESS"); ! 452: printf(" (NO WRITE)"); ! 453: } ! 454: if (preen == 0) ! 455: printf("\n"); ! 456: fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; sbsumbad = 0; ! 457: dfile.mod = 0; ! 458: n_files = n_blks = n_ffree = n_bfree = 0; ! 459: muldup = enddup = &duplist[0]; ! 460: badlnp = &badlncnt[0]; ! 461: lfdir = 0; ! 462: rplyflag = 0; ! 463: initbarea(&sblk); ! 464: initbarea(&fileblk); ! 465: initbarea(&inoblk); ! 466: initbarea(&cgblk); ! 467: initbarea(&asblk); ! 468: /* ! 469: * Read in the super block and its summary info. ! 470: */ ! 471: if (bread(&dfile, (char *)&sblock, super, (long)SBSIZE) == 0) ! 472: return (0); ! 473: sblk.b_bno = super; ! 474: sblk.b_size = SBSIZE; ! 475: /* ! 476: * run a few consistency checks of the super block ! 477: */ ! 478: if (sblock.fs_magic != FS_MAGIC) ! 479: { badsb("MAGIC NUMBER WRONG"); return (0); } ! 480: if (sblock.fs_ncg < 1) ! 481: { badsb("NCG OUT OF RANGE"); return (0); } ! 482: if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) ! 483: { badsb("CPG OUT OF RANGE"); return (0); } ! 484: if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl || ! 485: (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) ! 486: { badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); } ! 487: if (sblock.fs_sbsize > SBSIZE) ! 488: { badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); } ! 489: /* ! 490: * Set all possible fields that could differ, then do check ! 491: * of whole super block against an alternate super block. ! 492: * When an alternate super-block is specified this check is skipped. ! 493: */ ! 494: if (bflag) ! 495: goto sbok; ! 496: if (getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), ! 497: sblock.fs_sbsize) == 0) ! 498: return (0); ! 499: altsblock.fs_link = sblock.fs_link; ! 500: altsblock.fs_rlink = sblock.fs_rlink; ! 501: altsblock.fs_time = sblock.fs_time; ! 502: altsblock.fs_cstotal = sblock.fs_cstotal; ! 503: altsblock.fs_cgrotor = sblock.fs_cgrotor; ! 504: altsblock.fs_fmod = sblock.fs_fmod; ! 505: altsblock.fs_clean = sblock.fs_clean; ! 506: altsblock.fs_ronly = sblock.fs_ronly; ! 507: altsblock.fs_flags = sblock.fs_flags; ! 508: altsblock.fs_maxcontig = sblock.fs_maxcontig; ! 509: altsblock.fs_minfree = sblock.fs_minfree; ! 510: altsblock.fs_rotdelay = sblock.fs_rotdelay; ! 511: altsblock.fs_maxbpg = sblock.fs_maxbpg; ! 512: bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp, ! 513: sizeof sblock.fs_csp); ! 514: bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt, ! 515: sizeof sblock.fs_fsmnt); ! 516: if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize)) ! 517: { badsb("TRASHED VALUES IN SUPER BLOCK"); return (0); } ! 518: sbok: ! 519: fmax = sblock.fs_size; ! 520: imax = sblock.fs_ncg * sblock.fs_ipg; ! 521: n_bad = cgsblock(&sblock, 0); /* boot block plus dedicated sblock */ ! 522: /* ! 523: * read in the summary info. ! 524: */ ! 525: for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { ! 526: size = sblock.fs_cssize - i < sblock.fs_bsize ? ! 527: sblock.fs_cssize - i : sblock.fs_bsize; ! 528: sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size); ! 529: if (bread(&dfile, (char *)sblock.fs_csp[j], ! 530: fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), ! 531: size) == 0) ! 532: return (0); ! 533: } ! 534: /* ! 535: * allocate and initialize the necessary maps ! 536: */ ! 537: bmapsz = roundup(howmany(fmax, NBBY), sizeof(short)); ! 538: blockmap = calloc((unsigned)bmapsz, sizeof (char)); ! 539: if (blockmap == NULL) { ! 540: printf("cannot alloc %d bytes for blockmap\n", bmapsz); ! 541: goto badsb; ! 542: } ! 543: freemap = calloc((unsigned)bmapsz, sizeof (char)); ! 544: if (freemap == NULL) { ! 545: printf("cannot alloc %d bytes for freemap\n", bmapsz); ! 546: goto badsb; ! 547: } ! 548: statemap = calloc((unsigned)(imax + 1), sizeof(char)); ! 549: if (statemap == NULL) { ! 550: printf("cannot alloc %d bytes for statemap\n", imax + 1); ! 551: goto badsb; ! 552: } ! 553: lncntp = (short *)calloc((unsigned)(imax + 1), sizeof(short)); ! 554: if (lncntp == NULL) { ! 555: printf("cannot alloc %d bytes for lncntp\n", ! 556: (imax + 1) * sizeof(short)); ! 557: goto badsb; ! 558: } ! 559: for (c = 0; c < sblock.fs_ncg; c++) { ! 560: cgd = cgdmin(&sblock, c); ! 561: if (c == 0) { ! 562: d = cgbase(&sblock, c); ! 563: cgd += howmany(sblock.fs_cssize, sblock.fs_fsize); ! 564: } else ! 565: d = cgsblock(&sblock, c); ! 566: for (; d < cgd; d++) ! 567: setbmap(d); ! 568: } ! 569: ! 570: return (1); ! 571: ! 572: badsb: ! 573: ckfini(); ! 574: return (0); ! 575: # undef altsblock ! 576: } ! 577: ! 578: pass1() ! 579: { ! 580: register int c, i, n, j; ! 581: register DINODE *dp; ! 582: int ndb, partial; ! 583: struct inodesc idesc; ! 584: ino_t inumber; ! 585: ! 586: bzero((char *)&idesc, sizeof(struct inodesc)); ! 587: idesc.id_type = ADDR; ! 588: idesc.id_func = pass1check; ! 589: inumber = 0; ! 590: n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize); ! 591: for (c = 0; c < sblock.fs_ncg; c++) { ! 592: if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0) ! 593: continue; ! 594: if (cgrp.cg_magic != CG_MAGIC) { ! 595: pfatal("CG %d: BAD MAGIC NUMBER\n", c); ! 596: bzero((char *)&cgrp, (int)sblock.fs_cgsize); ! 597: } ! 598: n = 0; ! 599: for (i = 0; i < sblock.fs_ipg; i++, inumber++) { ! 600: dp = ginode(inumber); ! 601: if (dp == NULL) ! 602: continue; ! 603: n++; ! 604: if (ALLOC) { ! 605: if (!isset(cgrp.cg_iused, i)) { ! 606: if (debug) ! 607: printf("%d bad, not used\n", ! 608: inumber); ! 609: inosumbad++; ! 610: } ! 611: n--; ! 612: lastino = inumber; ! 613: if (!preen && BADBLK && ! 614: reply("HOLD BAD BLOCK") == 1) { ! 615: dp->di_size = sblock.fs_fsize; ! 616: dp->di_mode = IFREG|0600; ! 617: inodirty(); ! 618: } else if (ftypeok(dp) == 0) ! 619: goto unknown; ! 620: if (dp->di_size < 0) { ! 621: if (debug) ! 622: printf("bad size %d:", ! 623: dp->di_size); ! 624: goto unknown; ! 625: } ! 626: ndb = howmany(dp->di_size, sblock.fs_bsize); ! 627: if (SPECIAL) ! 628: ndb++; ! 629: for (j = ndb; j < NDADDR; j++) ! 630: if (dp->di_db[j] != 0) { ! 631: if (debug) ! 632: printf("bad direct addr: %d\n", ! 633: dp->di_db[j]); ! 634: goto unknown; ! 635: } ! 636: for (j = 0, ndb -= NDADDR; ndb > 0; j++) ! 637: ndb /= NINDIR(&sblock); ! 638: for (; j < NIADDR; j++) ! 639: if (dp->di_ib[j] != 0) { ! 640: if (debug) ! 641: printf("bad indirect addr: %d\n", ! 642: dp->di_ib[j]); ! 643: goto unknown; ! 644: } ! 645: n_files++; ! 646: lncntp[inumber] = dp->di_nlink; ! 647: if (dp->di_nlink <= 0) { ! 648: if (badlnp < &badlncnt[MAXLNCNT]) ! 649: *badlnp++ = inumber; ! 650: else { ! 651: pfatal("LINK COUNT TABLE OVERFLOW"); ! 652: if (reply("CONTINUE") == 0) ! 653: errexit(""); ! 654: } ! 655: } ! 656: statemap[inumber] = DIRCT ? DSTATE : FSTATE; ! 657: badblk = dupblk = 0; maxblk = 0; ! 658: idesc.id_number = inumber; ! 659: idesc.id_filesize = 0; ! 660: (void)ckinode(dp, &idesc); ! 661: idesc.id_filesize *= btodb(sblock.fs_fsize); ! 662: if (dp->di_blocks != idesc.id_filesize) { ! 663: pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)", ! 664: inumber, dp->di_blocks, ! 665: idesc.id_filesize); ! 666: if (preen) ! 667: printf(" (CORRECTED)\n"); ! 668: else if (reply("CORRECT") == 0) ! 669: continue; ! 670: dp->di_blocks = idesc.id_filesize; ! 671: inodirty(); ! 672: } ! 673: continue; ! 674: unknown: ! 675: pfatal("UNKNOWN FILE TYPE I=%u", inumber); ! 676: if (reply("CLEAR") == 1) { ! 677: zapino(dp); ! 678: inodirty(); ! 679: inosumbad++; ! 680: } ! 681: } else { ! 682: if (isset(cgrp.cg_iused, i)) { ! 683: if (debug) ! 684: printf("%d bad, marked used\n", ! 685: inumber); ! 686: inosumbad++; ! 687: n--; ! 688: } ! 689: partial = 0; ! 690: for (j = 0; j < NDADDR; j++) ! 691: if (dp->di_db[j] != 0) ! 692: partial++; ! 693: for (j = 0; j < NIADDR; j++) ! 694: if (dp->di_ib[j] != 0) ! 695: partial++; ! 696: if (partial || dp->di_mode != 0 || ! 697: dp->di_size != 0) { ! 698: pfatal("PARTIALLY ALLOCATED INODE I=%u", ! 699: inumber); ! 700: if (reply("CLEAR") == 1) { ! 701: zapino(dp); ! 702: inodirty(); ! 703: inosumbad++; ! 704: } ! 705: } ! 706: } ! 707: } ! 708: if (n != cgrp.cg_cs.cs_nifree) { ! 709: if (debug) ! 710: printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n", ! 711: c, cgrp.cg_cs.cs_nifree, n); ! 712: inosumbad++; ! 713: } ! 714: if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree ! 715: || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree ! 716: || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree ! 717: || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir) ! 718: sbsumbad++; ! 719: } ! 720: } ! 721: ! 722: pass1check(idesc) ! 723: register struct inodesc *idesc; ! 724: { ! 725: register daddr_t *dlp; ! 726: int res = KEEPON; ! 727: int anyout, nfrags; ! 728: daddr_t blkno = idesc->id_blkno; ! 729: ! 730: anyout = outrange(blkno, idesc->id_numfrags); ! 731: for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { ! 732: if (anyout && outrange(blkno, 1)) { ! 733: blkerr(idesc->id_number, "BAD", blkno); ! 734: if (++badblk >= MAXBAD) { ! 735: pwarn("EXCESSIVE BAD BLKS I=%u", ! 736: idesc->id_number); ! 737: if (preen) ! 738: printf(" (SKIPPING)\n"); ! 739: else if (reply("CONTINUE") == 0) ! 740: errexit(""); ! 741: return (STOP); ! 742: } ! 743: res = SKIP; ! 744: } else if (getbmap(blkno)) { ! 745: blkerr(idesc->id_number, "DUP", blkno); ! 746: if (++dupblk >= MAXDUP) { ! 747: pwarn("EXCESSIVE DUP BLKS I=%u", ! 748: idesc->id_number); ! 749: if (preen) ! 750: printf(" (SKIPPING)\n"); ! 751: else if (reply("CONTINUE") == 0) ! 752: errexit(""); ! 753: return (STOP); ! 754: } ! 755: if (enddup >= &duplist[DUPTBLSIZE]) { ! 756: pfatal("DUP TABLE OVERFLOW."); ! 757: if (reply("CONTINUE") == 0) ! 758: errexit(""); ! 759: return (STOP); ! 760: } ! 761: for (dlp = duplist; dlp < muldup; dlp++) ! 762: if (*dlp == blkno) { ! 763: *enddup++ = blkno; ! 764: break; ! 765: } ! 766: if (dlp >= muldup) { ! 767: *enddup++ = *muldup; ! 768: *muldup++ = blkno; ! 769: } ! 770: } else { ! 771: n_blks++; ! 772: setbmap(blkno); ! 773: } ! 774: idesc->id_filesize++; ! 775: } ! 776: return (res); ! 777: } ! 778: ! 779: pass1b() ! 780: { ! 781: register int c, i; ! 782: register DINODE *dp; ! 783: struct inodesc idesc; ! 784: ino_t inumber; ! 785: ! 786: bzero((char *)&idesc, sizeof(struct inodesc)); ! 787: idesc.id_type = ADDR; ! 788: idesc.id_func = pass1bcheck; ! 789: inumber = 0; ! 790: for (c = 0; c < sblock.fs_ncg; c++) { ! 791: for (i = 0; i < sblock.fs_ipg; i++, inumber++) { ! 792: dp = ginode(inumber); ! 793: if (dp == NULL) ! 794: continue; ! 795: idesc.id_number = inumber; ! 796: if (statemap[inumber] != USTATE && ! 797: (ckinode(dp, &idesc) & STOP)) ! 798: goto out1b; ! 799: } ! 800: } ! 801: out1b: ! 802: flush(&dfile, &inoblk); ! 803: } ! 804: ! 805: pass1bcheck(idesc) ! 806: register struct inodesc *idesc; ! 807: { ! 808: register daddr_t *dlp; ! 809: int nfrags, res = KEEPON; ! 810: daddr_t blkno = idesc->id_blkno; ! 811: ! 812: for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { ! 813: if (outrange(blkno, 1)) ! 814: res = SKIP; ! 815: for (dlp = duplist; dlp < muldup; dlp++) ! 816: if (*dlp == blkno) { ! 817: blkerr(idesc->id_number, "DUP", blkno); ! 818: *dlp = *--muldup; ! 819: *muldup = blkno; ! 820: if (muldup == duplist) ! 821: return (STOP); ! 822: } ! 823: } ! 824: return (res); ! 825: } ! 826: ! 827: pass2() ! 828: { ! 829: register DINODE *dp; ! 830: struct inodesc rootdesc; ! 831: ! 832: bzero((char *)&rootdesc, sizeof(struct inodesc)); ! 833: rootdesc.id_type = ADDR; ! 834: rootdesc.id_func = pass2check; ! 835: rootdesc.id_number = ROOTINO; ! 836: pathp = pathname; ! 837: switch (statemap[ROOTINO]) { ! 838: ! 839: case USTATE: ! 840: errexit("ROOT INODE UNALLOCATED. TERMINATING.\n"); ! 841: ! 842: case FSTATE: ! 843: pfatal("ROOT INODE NOT DIRECTORY"); ! 844: if (reply("FIX") == 0 || (dp = ginode(ROOTINO)) == NULL) ! 845: errexit(""); ! 846: dp->di_mode &= ~IFMT; ! 847: dp->di_mode |= IFDIR; ! 848: inodirty(); ! 849: inosumbad++; ! 850: statemap[ROOTINO] = DSTATE; ! 851: /* fall into ... */ ! 852: ! 853: case DSTATE: ! 854: descend(&rootdesc, ROOTINO); ! 855: break; ! 856: ! 857: case CLEAR: ! 858: pfatal("DUPS/BAD IN ROOT INODE"); ! 859: printf("\n"); ! 860: if (reply("CONTINUE") == 0) ! 861: errexit(""); ! 862: statemap[ROOTINO] = DSTATE; ! 863: descend(&rootdesc, ROOTINO); ! 864: } ! 865: } ! 866: ! 867: pass2check(idesc) ! 868: struct inodesc *idesc; ! 869: { ! 870: register DIRECT *dirp = idesc->id_dirp; ! 871: char *curpathloc; ! 872: int n, entrysize, ret = 0; ! 873: DINODE *dp; ! 874: DIRECT proto; ! 875: ! 876: /* ! 877: * check for "." ! 878: */ ! 879: if (idesc->id_entryno != 0) ! 880: goto chk1; ! 881: if (dirp->d_ino != 0 && dirp->d_namlen == 1 && dirp->d_name[0] == '.') { ! 882: if (dirp->d_ino != idesc->id_number) { ! 883: direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'"); ! 884: dirp->d_ino = idesc->id_number; ! 885: if (reply("FIX") == 1) ! 886: ret |= ALTERED; ! 887: } ! 888: goto chk1; ! 889: } ! 890: direrr(idesc->id_number, "MISSING '.'"); ! 891: proto.d_ino = idesc->id_number; ! 892: proto.d_namlen = 1; ! 893: (void)strcpy(proto.d_name, "."); ! 894: entrysize = DIRSIZ(&proto); ! 895: if (dirp->d_ino != 0) { ! 896: pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", ! 897: dirp->d_name); ! 898: } else if (dirp->d_reclen < entrysize) { ! 899: pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); ! 900: } else if (dirp->d_reclen < 2 * entrysize) { ! 901: proto.d_reclen = dirp->d_reclen; ! 902: bcopy((char *)&proto, (char *)dirp, entrysize); ! 903: if (reply("FIX") == 1) ! 904: ret |= ALTERED; ! 905: } else { ! 906: n = dirp->d_reclen - entrysize; ! 907: proto.d_reclen = entrysize; ! 908: bcopy((char *)&proto, (char *)dirp, entrysize); ! 909: idesc->id_entryno++; ! 910: lncntp[dirp->d_ino]--; ! 911: dirp = (DIRECT *)((char *)(dirp) + entrysize); ! 912: bzero((char *)dirp, n); ! 913: dirp->d_reclen = n; ! 914: if (reply("FIX") == 1) ! 915: ret |= ALTERED; ! 916: } ! 917: chk1: ! 918: if (idesc->id_entryno > 1) ! 919: goto chk2; ! 920: proto.d_ino = idesc->id_parent; ! 921: proto.d_namlen = 2; ! 922: (void)strcpy(proto.d_name, ".."); ! 923: entrysize = DIRSIZ(&proto); ! 924: if (idesc->id_entryno == 0) { ! 925: n = DIRSIZ(dirp); ! 926: if (dirp->d_reclen < n + entrysize) ! 927: goto chk2; ! 928: proto.d_reclen = dirp->d_reclen - n; ! 929: dirp->d_reclen = n; ! 930: idesc->id_entryno++; ! 931: lncntp[dirp->d_ino]--; ! 932: dirp = (DIRECT *)((char *)(dirp) + n); ! 933: bzero((char *)dirp, n); ! 934: dirp->d_reclen = n; ! 935: } ! 936: if (dirp->d_ino != 0 && dirp->d_namlen == 2 && ! 937: strcmp(dirp->d_name, "..") == 0) { ! 938: if (dirp->d_ino != idesc->id_parent) { ! 939: direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'"); ! 940: dirp->d_ino = idesc->id_parent; ! 941: if (reply("FIX") == 1) ! 942: ret |= ALTERED; ! 943: } ! 944: goto chk2; ! 945: } ! 946: direrr(idesc->id_number, "MISSING '..'"); ! 947: if (dirp->d_ino != 0) { ! 948: pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", ! 949: dirp->d_name); ! 950: } else if (dirp->d_reclen < entrysize) { ! 951: pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); ! 952: } else { ! 953: proto.d_reclen = dirp->d_reclen; ! 954: bcopy((char *)&proto, (char *)dirp, entrysize); ! 955: if (reply("FIX") == 1) ! 956: ret |= ALTERED; ! 957: } ! 958: chk2: ! 959: if (dirp->d_ino == 0) ! 960: return (ret|KEEPON); ! 961: if (idesc->id_entryno >= 2 && ! 962: dirp->d_namlen <= 2 && ! 963: dirp->d_name[0] == '.') { ! 964: if (dirp->d_namlen == 1) { ! 965: direrr(idesc->id_number, "EXTRA '.' ENTRY"); ! 966: dirp->d_ino = 0; ! 967: if (reply("FIX") == 1) ! 968: ret |= ALTERED; ! 969: return (KEEPON | ret); ! 970: } ! 971: if (dirp->d_name[1] == '.') { ! 972: direrr(idesc->id_number, "EXTRA '..' ENTRY"); ! 973: dirp->d_ino = 0; ! 974: if (reply("FIX") == 1) ! 975: ret |= ALTERED; ! 976: return (KEEPON | ret); ! 977: } ! 978: } ! 979: curpathloc = pathp; ! 980: *pathp++ = '/'; ! 981: if (pathp + dirp->d_namlen >= endpathname) { ! 982: *pathp = '\0'; ! 983: errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name); ! 984: } ! 985: bcopy(dirp->d_name, pathp, dirp->d_namlen + 1); ! 986: pathp += dirp->d_namlen; ! 987: idesc->id_entryno++; ! 988: n = 0; ! 989: if (dirp->d_ino > imax || dirp->d_ino <= 0) { ! 990: direrr(dirp->d_ino, "I OUT OF RANGE"); ! 991: n = reply("REMOVE"); ! 992: } else { ! 993: again: ! 994: switch (statemap[dirp->d_ino]) { ! 995: case USTATE: ! 996: direrr(dirp->d_ino, "UNALLOCATED"); ! 997: n = reply("REMOVE"); ! 998: break; ! 999: ! 1000: case CLEAR: ! 1001: direrr(dirp->d_ino, "DUP/BAD"); ! 1002: if ((n = reply("REMOVE")) == 1) ! 1003: break; ! 1004: if ((dp = ginode(dirp->d_ino)) == NULL) ! 1005: break; ! 1006: statemap[dirp->d_ino] = DIRCT ? DSTATE : FSTATE; ! 1007: goto again; ! 1008: ! 1009: case FSTATE: ! 1010: lncntp[dirp->d_ino]--; ! 1011: break; ! 1012: ! 1013: case DSTATE: ! 1014: descend(idesc, dirp->d_ino); ! 1015: if (statemap[dirp->d_ino] != CLEAR) { ! 1016: lncntp[dirp->d_ino]--; ! 1017: } else { ! 1018: dirp->d_ino = 0; ! 1019: ret |= ALTERED; ! 1020: } ! 1021: break; ! 1022: } ! 1023: } ! 1024: pathp = curpathloc; ! 1025: *pathp = '\0'; ! 1026: if (n == 0) ! 1027: return (ret|KEEPON); ! 1028: dirp->d_ino = 0; ! 1029: return (ret|KEEPON|ALTERED); ! 1030: } ! 1031: ! 1032: pass3() ! 1033: { ! 1034: register DINODE *dp; ! 1035: struct inodesc idesc; ! 1036: ino_t inumber, orphan; ! 1037: int loopcnt; ! 1038: ! 1039: bzero((char *)&idesc, sizeof(struct inodesc)); ! 1040: idesc.id_type = DATA; ! 1041: for (inumber = ROOTINO; inumber <= lastino; inumber++) { ! 1042: if (statemap[inumber] == DSTATE) { ! 1043: pathp = pathname; ! 1044: *pathp++ = '?'; ! 1045: *pathp = '\0'; ! 1046: idesc.id_func = findino; ! 1047: srchname = ".."; ! 1048: idesc.id_parent = inumber; ! 1049: loopcnt = 0; ! 1050: do { ! 1051: orphan = idesc.id_parent; ! 1052: if ((dp = ginode(orphan)) == NULL) ! 1053: break; ! 1054: idesc.id_parent = 0; ! 1055: idesc.id_filesize = dp->di_size; ! 1056: idesc.id_number = orphan; ! 1057: (void)ckinode(dp, &idesc); ! 1058: if (idesc.id_parent == 0) ! 1059: break; ! 1060: if (loopcnt >= sblock.fs_cstotal.cs_ndir) ! 1061: break; ! 1062: loopcnt++; ! 1063: } while (statemap[idesc.id_parent] == DSTATE); ! 1064: if (linkup(orphan, idesc.id_parent) == 1) { ! 1065: idesc.id_func = pass2check; ! 1066: idesc.id_number = lfdir; ! 1067: descend(&idesc, orphan); ! 1068: } ! 1069: } ! 1070: } ! 1071: } ! 1072: ! 1073: pass4() ! 1074: { ! 1075: register ino_t inumber, *blp; ! 1076: int n; ! 1077: struct inodesc idesc; ! 1078: ! 1079: bzero((char *)&idesc, sizeof(struct inodesc)); ! 1080: idesc.id_type = ADDR; ! 1081: idesc.id_func = pass4check; ! 1082: for (inumber = ROOTINO; inumber <= lastino; inumber++) { ! 1083: idesc.id_number = inumber; ! 1084: switch (statemap[inumber]) { ! 1085: ! 1086: case FSTATE: ! 1087: n = lncntp[inumber]; ! 1088: if (n) ! 1089: adjust(&idesc, (short)n); ! 1090: else { ! 1091: for (blp = badlncnt;blp < badlnp; blp++) ! 1092: if (*blp == inumber) { ! 1093: clri(&idesc, "UNREF", 1); ! 1094: break; ! 1095: } ! 1096: } ! 1097: break; ! 1098: ! 1099: case DSTATE: ! 1100: clri(&idesc, "UNREF", 1); ! 1101: break; ! 1102: ! 1103: case CLEAR: ! 1104: clri(&idesc, "BAD/DUP", 1); ! 1105: break; ! 1106: } ! 1107: } ! 1108: if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) { ! 1109: pwarn("FREE INODE COUNT WRONG IN SUPERBLK"); ! 1110: if (preen) ! 1111: printf(" (FIXED)\n"); ! 1112: if (preen || reply("FIX") == 1) { ! 1113: sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files; ! 1114: sbdirty(); ! 1115: } ! 1116: } ! 1117: flush(&dfile, &fileblk); ! 1118: } ! 1119: ! 1120: pass4check(idesc) ! 1121: register struct inodesc *idesc; ! 1122: { ! 1123: register daddr_t *dlp; ! 1124: int nfrags, res = KEEPON; ! 1125: daddr_t blkno = idesc->id_blkno; ! 1126: ! 1127: for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { ! 1128: if (outrange(blkno, 1)) ! 1129: res = SKIP; ! 1130: else if (getbmap(blkno)) { ! 1131: for (dlp = duplist; dlp < enddup; dlp++) ! 1132: if (*dlp == blkno) { ! 1133: *dlp = *--enddup; ! 1134: return (KEEPON); ! 1135: } ! 1136: clrbmap(blkno); ! 1137: n_blks--; ! 1138: } ! 1139: } ! 1140: return (res); ! 1141: } ! 1142: ! 1143: pass5() ! 1144: { ! 1145: register int c, n, i, b, d; ! 1146: short bo[MAXCPG][NRPOS]; ! 1147: long botot[MAXCPG]; ! 1148: long frsum[MAXFRAG]; ! 1149: int blk; ! 1150: daddr_t cbase; ! 1151: int blockbits = (1<<sblock.fs_frag)-1; ! 1152: ! 1153: bcopy(blockmap, freemap, (unsigned)bmapsz); ! 1154: dupblk = 0; ! 1155: n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0)); ! 1156: for (c = 0; c < sblock.fs_ncg; c++) { ! 1157: cbase = cgbase(&sblock, c); ! 1158: bzero((char *)botot, sizeof (botot)); ! 1159: bzero((char *)bo, sizeof (bo)); ! 1160: bzero((char *)frsum, sizeof (frsum)); ! 1161: /* ! 1162: * need to account for the super blocks ! 1163: * which appear (inaccurately) bad ! 1164: */ ! 1165: n_bad += cgtod(&sblock, c) - cgsblock(&sblock, c); ! 1166: if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0) ! 1167: continue; ! 1168: if (cgrp.cg_magic != CG_MAGIC) { ! 1169: pfatal("CG %d: BAD MAGIC NUMBER\n", c); ! 1170: bzero((char *)&cgrp, (int)sblock.fs_cgsize); ! 1171: } ! 1172: for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) { ! 1173: blk = blkmap(&sblock, cgrp.cg_free, b); ! 1174: if (blk == 0) ! 1175: continue; ! 1176: if (blk == blockbits) { ! 1177: if (pass5check(cbase+b, sblock.fs_frag) == STOP) ! 1178: goto out5; ! 1179: /* this is clumsy ... */ ! 1180: n_ffree -= sblock.fs_frag; ! 1181: n_bfree++; ! 1182: botot[cbtocylno(&sblock, b)]++; ! 1183: bo[cbtocylno(&sblock, b)] ! 1184: [cbtorpos(&sblock, b)]++; ! 1185: continue; ! 1186: } ! 1187: for (d = 0; d < sblock.fs_frag; d++) ! 1188: if ((blk & (1<<d)) && ! 1189: pass5check(cbase + b + d, (long)1) == STOP) ! 1190: goto out5; ! 1191: fragacct(&sblock, blk, frsum, 1); ! 1192: } ! 1193: if (bcmp((char *)cgrp.cg_frsum, (char *)frsum, sizeof(frsum))) { ! 1194: if (debug) ! 1195: for (i = 0; i < sblock.fs_frag; i++) ! 1196: if (cgrp.cg_frsum[i] != frsum[i]) ! 1197: printf("cg[%d].cg_frsum[%d] have %d calc %d\n", ! 1198: c, i, cgrp.cg_frsum[i], frsum[i]); ! 1199: frsumbad++; ! 1200: } ! 1201: if (bcmp((char *)cgrp.cg_btot, (char *)botot, sizeof (botot))) { ! 1202: if (debug) ! 1203: for (n = 0; n < sblock.fs_cpg; n++) ! 1204: if (botot[n] != cgrp.cg_btot[n]) ! 1205: printf("cg[%d].cg_btot[%d] have %d calc %d\n", ! 1206: c, n, cgrp.cg_btot[n], botot[n]); ! 1207: offsumbad++; ! 1208: } ! 1209: if (bcmp((char *)cgrp.cg_b, (char *)bo, sizeof (bo))) { ! 1210: if (debug) ! 1211: for (i = 0; i < NRPOS; i++) ! 1212: if (bo[n][i] != cgrp.cg_b[n][i]) ! 1213: printf("cg[%d].cg_b[%d][%d] have %d calc %d\n", ! 1214: c, n, i, cgrp.cg_b[n][i], bo[n][i]); ! 1215: offsumbad++; ! 1216: } ! 1217: } ! 1218: out5: ! 1219: if (dupblk) ! 1220: pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk); ! 1221: if (fixcg == 0) { ! 1222: if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) { ! 1223: pwarn("%ld BLK(S) MISSING\n", fmax - b); ! 1224: fixcg = 1; ! 1225: } else if (inosumbad + offsumbad + frsumbad + sbsumbad) { ! 1226: pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n", ! 1227: inosumbad ? "(INODE FREE) " : "", ! 1228: offsumbad ? "(BLOCK OFFSETS) " : "", ! 1229: frsumbad ? "(FRAG SUMMARIES) " : "", ! 1230: sbsumbad ? "(SUPER BLOCK SUMMARIES) " : ""); ! 1231: fixcg = 1; ! 1232: } else if (n_ffree != sblock.fs_cstotal.cs_nffree || ! 1233: n_bfree != sblock.fs_cstotal.cs_nbfree) { ! 1234: pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK"); ! 1235: if (preen) ! 1236: printf(" (FIXED)\n"); ! 1237: if (preen || reply("FIX") == 1) { ! 1238: sblock.fs_cstotal.cs_nffree = n_ffree; ! 1239: sblock.fs_cstotal.cs_nbfree = n_bfree; ! 1240: sbdirty(); ! 1241: } ! 1242: } ! 1243: } ! 1244: if (fixcg) { ! 1245: pwarn("BAD CYLINDER GROUPS"); ! 1246: if (preen) ! 1247: printf(" (SALVAGED)\n"); ! 1248: else if (reply("SALVAGE") == 0) ! 1249: fixcg = 0; ! 1250: } ! 1251: } ! 1252: ! 1253: pass5check(blk, size) ! 1254: daddr_t blk; ! 1255: long size; ! 1256: { ! 1257: ! 1258: if (outrange(blk, (int)size)) { ! 1259: fixcg = 1; ! 1260: if (preen) ! 1261: pfatal("BAD BLOCKS IN BIT MAPS."); ! 1262: if (++badblk >= MAXBAD) { ! 1263: printf("EXCESSIVE BAD BLKS IN BIT MAPS."); ! 1264: if (reply("CONTINUE") == 0) ! 1265: errexit(""); ! 1266: return (STOP); ! 1267: } ! 1268: } ! 1269: for (; size > 0; blk++, size--) ! 1270: if (getfmap(blk)) { ! 1271: fixcg = 1; ! 1272: ++dupblk; ! 1273: } else { ! 1274: n_ffree++; ! 1275: setfmap(blk); ! 1276: } ! 1277: return (KEEPON); ! 1278: } ! 1279: ! 1280: ckinode(dp, idesc) ! 1281: DINODE *dp; ! 1282: register struct inodesc *idesc; ! 1283: { ! 1284: register daddr_t *ap; ! 1285: int ret, n, ndb, offset; ! 1286: DINODE dino; ! 1287: ! 1288: if (SPECIAL) ! 1289: return (KEEPON); ! 1290: dino = *dp; ! 1291: idesc->id_fix = DONTKNOW; ! 1292: idesc->id_entryno = 0; ! 1293: ndb = howmany(dino.di_size, sblock.fs_bsize); ! 1294: for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { ! 1295: if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) ! 1296: idesc->id_numfrags = ! 1297: numfrags(&sblock, fragroundup(&sblock, offset)); ! 1298: else ! 1299: idesc->id_numfrags = sblock.fs_frag; ! 1300: if (*ap == 0) ! 1301: continue; ! 1302: idesc->id_blkno = *ap; ! 1303: if (idesc->id_type == ADDR) ! 1304: ret = (*idesc->id_func)(idesc); ! 1305: else ! 1306: ret = dirscan(idesc); ! 1307: if (ret & STOP) ! 1308: return (ret); ! 1309: } ! 1310: idesc->id_numfrags = sblock.fs_frag; ! 1311: for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) { ! 1312: if (*ap) { ! 1313: idesc->id_blkno = *ap; ! 1314: ret = iblock(idesc, n, ! 1315: dino.di_size - sblock.fs_bsize * NDADDR); ! 1316: if (ret & STOP) ! 1317: return (ret); ! 1318: } ! 1319: } ! 1320: return (KEEPON); ! 1321: } ! 1322: ! 1323: iblock(idesc, ilevel, isize) ! 1324: struct inodesc *idesc; ! 1325: register ilevel; ! 1326: long isize; ! 1327: { ! 1328: register daddr_t *ap; ! 1329: register daddr_t *aplim; ! 1330: int i, n, (*func)(), nif; ! 1331: BUFAREA ib; ! 1332: ! 1333: if (idesc->id_type == ADDR) { ! 1334: func = idesc->id_func; ! 1335: if (((n = (*func)(idesc)) & KEEPON) == 0) ! 1336: return (n); ! 1337: } else ! 1338: func = dirscan; ! 1339: if (outrange(idesc->id_blkno, idesc->id_numfrags)) /* protect thyself */ ! 1340: return (SKIP); ! 1341: initbarea(&ib); ! 1342: if (getblk(&ib, idesc->id_blkno, sblock.fs_bsize) == NULL) ! 1343: return (SKIP); ! 1344: ilevel--; ! 1345: if (ilevel == 0) { ! 1346: nif = lblkno(&sblock, isize) + 1; ! 1347: } else /* ilevel == 1 */ { ! 1348: nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1; ! 1349: } ! 1350: if (nif > NINDIR(&sblock)) ! 1351: nif = NINDIR(&sblock); ! 1352: aplim = &ib.b_un.b_indir[nif]; ! 1353: for (ap = ib.b_un.b_indir, i = 1; ! 1354: ap < aplim || (*ap && i <= NINDIR(&sblock)); ! 1355: ap++, i++) ! 1356: if (*ap) { ! 1357: idesc->id_blkno = *ap; ! 1358: if (ilevel > 0) ! 1359: n = iblock(idesc, ilevel, ! 1360: isize - i*NINDIR(&sblock)*sblock.fs_bsize); ! 1361: else ! 1362: n = (*func)(idesc); ! 1363: if (n & STOP) ! 1364: return (n); ! 1365: } ! 1366: return (KEEPON); ! 1367: } ! 1368: ! 1369: outrange(blk, cnt) ! 1370: daddr_t blk; ! 1371: int cnt; ! 1372: { ! 1373: register int c; ! 1374: ! 1375: if ((unsigned)(blk+cnt) > fmax) ! 1376: return (1); ! 1377: c = dtog(&sblock, blk); ! 1378: if (blk < cgdmin(&sblock, c)) { ! 1379: if ((blk+cnt) > cgsblock(&sblock, c)) { ! 1380: if (debug) { ! 1381: printf("blk %d < cgdmin %d;", ! 1382: blk, cgdmin(&sblock, c)); ! 1383: printf(" blk+cnt %d > cgsbase %d\n", ! 1384: blk+cnt, cgsblock(&sblock, c)); ! 1385: } ! 1386: return (1); ! 1387: } ! 1388: } else { ! 1389: if ((blk+cnt) > cgbase(&sblock, c+1)) { ! 1390: if (debug) { ! 1391: printf("blk %d >= cgdmin %d;", ! 1392: blk, cgdmin(&sblock, c)); ! 1393: printf(" blk+cnt %d > sblock.fs_fpg %d\n", ! 1394: blk+cnt, sblock.fs_fpg); ! 1395: } ! 1396: return (1); ! 1397: } ! 1398: } ! 1399: return (0); ! 1400: } ! 1401: ! 1402: blkerr(ino, s, blk) ! 1403: ino_t ino; ! 1404: char *s; ! 1405: daddr_t blk; ! 1406: { ! 1407: ! 1408: pfatal("%ld %s I=%u", blk, s, ino); ! 1409: printf("\n"); ! 1410: statemap[ino] = CLEAR; ! 1411: } ! 1412: ! 1413: descend(parentino, inumber) ! 1414: struct inodesc *parentino; ! 1415: ino_t inumber; ! 1416: { ! 1417: register DINODE *dp; ! 1418: struct inodesc curino; ! 1419: ! 1420: bzero((char *)&curino, sizeof(struct inodesc)); ! 1421: statemap[inumber] = FSTATE; ! 1422: if ((dp = ginode(inumber)) == NULL) ! 1423: return; ! 1424: if (dp->di_size == 0) { ! 1425: direrr(inumber, "ZERO LENGTH DIRECTORY"); ! 1426: if (reply("REMOVE") == 1) ! 1427: statemap[inumber] = CLEAR; ! 1428: return; ! 1429: } ! 1430: if (dp->di_size < MINDIRSIZE) { ! 1431: direrr(inumber, "DIRECTORY TOO SHORT"); ! 1432: dp->di_size = MINDIRSIZE; ! 1433: if (reply("FIX") == 1) ! 1434: inodirty(); ! 1435: } ! 1436: curino.id_type = DATA; ! 1437: curino.id_func = parentino->id_func; ! 1438: curino.id_parent = parentino->id_number; ! 1439: curino.id_number = inumber; ! 1440: curino.id_filesize = dp->di_size; ! 1441: (void)ckinode(dp, &curino); ! 1442: } ! 1443: ! 1444: dirscan(idesc) ! 1445: register struct inodesc *idesc; ! 1446: { ! 1447: register DIRECT *dp; ! 1448: int dsize, n; ! 1449: long blksiz; ! 1450: char dbuf[DIRBLKSIZ]; ! 1451: ! 1452: if (idesc->id_type != DATA) ! 1453: errexit("wrong type to dirscan %d\n", idesc->id_type); ! 1454: blksiz = idesc->id_numfrags * sblock.fs_fsize; ! 1455: if (outrange(idesc->id_blkno, idesc->id_numfrags)) { ! 1456: idesc->id_filesize -= blksiz; ! 1457: return (SKIP); ! 1458: } ! 1459: idesc->id_loc = 0; ! 1460: for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { ! 1461: dsize = dp->d_reclen; ! 1462: bcopy((char *)dp, dbuf, dsize); ! 1463: idesc->id_dirp = (DIRECT *)dbuf; ! 1464: if ((n = (*idesc->id_func)(idesc)) & ALTERED) { ! 1465: if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) { ! 1466: bcopy(dbuf, (char *)dp, dsize); ! 1467: dirty(&fileblk); ! 1468: sbdirty(); ! 1469: } else ! 1470: n &= ~ALTERED; ! 1471: } ! 1472: if (n & STOP) ! 1473: return (n); ! 1474: } ! 1475: return (idesc->id_filesize > 0 ? KEEPON : STOP); ! 1476: } ! 1477: ! 1478: /* ! 1479: * get next entry in a directory. ! 1480: */ ! 1481: DIRECT * ! 1482: fsck_readdir(idesc) ! 1483: register struct inodesc *idesc; ! 1484: { ! 1485: register DIRECT *dp, *ndp; ! 1486: long size, blksiz; ! 1487: ! 1488: blksiz = idesc->id_numfrags * sblock.fs_fsize; ! 1489: if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) { ! 1490: idesc->id_filesize -= blksiz - idesc->id_loc; ! 1491: return NULL; ! 1492: } ! 1493: if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && ! 1494: idesc->id_loc < blksiz) { ! 1495: dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); ! 1496: if (dircheck(idesc, dp)) ! 1497: goto dpok; ! 1498: idesc->id_loc += DIRBLKSIZ; ! 1499: idesc->id_filesize -= DIRBLKSIZ; ! 1500: dp->d_reclen = DIRBLKSIZ; ! 1501: dp->d_ino = 0; ! 1502: dp->d_namlen = 0; ! 1503: dp->d_name[0] = '\0'; ! 1504: if (dofix(idesc)) ! 1505: dirty(&fileblk); ! 1506: return (dp); ! 1507: } ! 1508: dpok: ! 1509: if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) ! 1510: return NULL; ! 1511: dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); ! 1512: idesc->id_loc += dp->d_reclen; ! 1513: idesc->id_filesize -= dp->d_reclen; ! 1514: ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); ! 1515: if ((idesc->id_filesize <= 0 && idesc->id_loc % DIRBLKSIZ != 0) || ! 1516: (idesc->id_loc < blksiz && idesc->id_filesize > 0 && ! 1517: dircheck(idesc, ndp) == 0)) { ! 1518: size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); ! 1519: dp->d_reclen += size; ! 1520: idesc->id_loc += size; ! 1521: idesc->id_filesize -= size; ! 1522: if (dofix(idesc)) ! 1523: dirty(&fileblk); ! 1524: } ! 1525: return (dp); ! 1526: } ! 1527: ! 1528: /* ! 1529: * Verify that a directory entry is valid. ! 1530: * This is a superset of the checks made in the kernel. ! 1531: */ ! 1532: dircheck(idesc, dp) ! 1533: struct inodesc *idesc; ! 1534: register DIRECT *dp; ! 1535: { ! 1536: register int size; ! 1537: register char *cp; ! 1538: int spaceleft; ! 1539: ! 1540: size = DIRSIZ(dp); ! 1541: spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); ! 1542: if (dp->d_ino < imax && ! 1543: dp->d_reclen != 0 && ! 1544: dp->d_reclen <= spaceleft && ! 1545: (dp->d_reclen & 0x3) == 0 && ! 1546: dp->d_reclen >= size && ! 1547: idesc->id_filesize >= size && ! 1548: dp->d_namlen <= MAXNAMLEN) { ! 1549: if (dp->d_ino == 0) ! 1550: return (1); ! 1551: for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) ! 1552: if (*cp == 0 || (*cp++ & 0200)) ! 1553: return (0); ! 1554: if (*cp == 0) ! 1555: return (1); ! 1556: } ! 1557: return (0); ! 1558: } ! 1559: ! 1560: direrr(ino, s) ! 1561: ino_t ino; ! 1562: char *s; ! 1563: { ! 1564: register DINODE *dp; ! 1565: ! 1566: pwarn("%s ", s); ! 1567: pinode(ino); ! 1568: printf("\n"); ! 1569: if ((dp = ginode(ino)) != NULL && ftypeok(dp)) ! 1570: pfatal("%s=%s\n", DIRCT?"DIR":"FILE", pathname); ! 1571: else ! 1572: pfatal("NAME=%s\n", pathname); ! 1573: } ! 1574: ! 1575: adjust(idesc, lcnt) ! 1576: register struct inodesc *idesc; ! 1577: short lcnt; ! 1578: { ! 1579: register DINODE *dp; ! 1580: ! 1581: if ((dp = ginode(idesc->id_number)) == NULL) ! 1582: return; ! 1583: if (dp->di_nlink == lcnt) { ! 1584: if (linkup(idesc->id_number, (ino_t)0) == 0) ! 1585: clri(idesc, "UNREF", 0); ! 1586: } ! 1587: else { ! 1588: pwarn("LINK COUNT %s", ! 1589: (lfdir==idesc->id_number)?lfname:(DIRCT?"DIR":"FILE")); ! 1590: pinode(idesc->id_number); ! 1591: printf(" COUNT %d SHOULD BE %d", ! 1592: dp->di_nlink, dp->di_nlink-lcnt); ! 1593: if (preen) { ! 1594: if (lcnt < 0) { ! 1595: printf("\n"); ! 1596: preendie(); ! 1597: } ! 1598: printf(" (ADJUSTED)\n"); ! 1599: } ! 1600: if (preen || reply("ADJUST") == 1) { ! 1601: dp->di_nlink -= lcnt; ! 1602: inodirty(); ! 1603: } ! 1604: } ! 1605: } ! 1606: ! 1607: clri(idesc, s, flg) ! 1608: register struct inodesc *idesc; ! 1609: char *s; ! 1610: int flg; ! 1611: { ! 1612: register DINODE *dp; ! 1613: ! 1614: if ((dp = ginode(idesc->id_number)) == NULL) ! 1615: return; ! 1616: if (flg == 1) { ! 1617: pwarn("%s %s", s, DIRCT?"DIR":"FILE"); ! 1618: pinode(idesc->id_number); ! 1619: } ! 1620: if (preen || reply("CLEAR") == 1) { ! 1621: if (preen) ! 1622: printf(" (CLEARED)\n"); ! 1623: n_files--; ! 1624: (void)ckinode(dp, idesc); ! 1625: zapino(dp); ! 1626: statemap[idesc->id_number] = USTATE; ! 1627: inodirty(); ! 1628: inosumbad++; ! 1629: } ! 1630: } ! 1631: ! 1632: badsb(s) ! 1633: char *s; ! 1634: { ! 1635: ! 1636: if (preen) ! 1637: printf("%s: ", devname); ! 1638: printf("BAD SUPER BLOCK: %s\n", s); ! 1639: pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n"); ! 1640: pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n"); ! 1641: } ! 1642: ! 1643: DINODE * ! 1644: ginode(inumber) ! 1645: ino_t inumber; ! 1646: { ! 1647: daddr_t iblk; ! 1648: static ino_t startinum = 0; /* blk num of first in raw area */ ! 1649: ! 1650: ! 1651: if (inumber < ROOTINO || inumber > imax) { ! 1652: if (debug && inumber > imax) ! 1653: printf("inumber out of range (%d)\n", inumber); ! 1654: return (NULL); ! 1655: } ! 1656: if (startinum == 0 || ! 1657: inumber < startinum || inumber >= startinum + INOPB(&sblock)) { ! 1658: iblk = itod(&sblock, inumber); ! 1659: if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) { ! 1660: return (NULL); ! 1661: } ! 1662: startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); ! 1663: } ! 1664: return (&inoblk.b_un.b_dinode[inumber % INOPB(&sblock)]); ! 1665: } ! 1666: ! 1667: ftypeok(dp) ! 1668: DINODE *dp; ! 1669: { ! 1670: switch (dp->di_mode & IFMT) { ! 1671: ! 1672: case IFDIR: ! 1673: case IFREG: ! 1674: case IFBLK: ! 1675: case IFCHR: ! 1676: case IFLNK: ! 1677: case IFSOCK: ! 1678: return (1); ! 1679: ! 1680: default: ! 1681: if (debug) ! 1682: printf("bad file type 0%o\n", dp->di_mode); ! 1683: return (0); ! 1684: } ! 1685: } ! 1686: ! 1687: reply(s) ! 1688: char *s; ! 1689: { ! 1690: char line[80]; ! 1691: ! 1692: if (preen) ! 1693: pfatal("INTERNAL ERROR: GOT TO reply()"); ! 1694: rplyflag = 1; ! 1695: printf("\n%s? ", s); ! 1696: if (nflag || dfile.wfdes < 0) { ! 1697: printf(" no\n\n"); ! 1698: return (0); ! 1699: } ! 1700: if (yflag) { ! 1701: printf(" yes\n\n"); ! 1702: return (1); ! 1703: } ! 1704: if (getline(stdin, line, sizeof(line)) == EOF) ! 1705: errexit("\n"); ! 1706: printf("\n"); ! 1707: if (line[0] == 'y' || line[0] == 'Y') ! 1708: return (1); ! 1709: else ! 1710: return (0); ! 1711: } ! 1712: ! 1713: getline(fp, loc, maxlen) ! 1714: FILE *fp; ! 1715: char *loc; ! 1716: { ! 1717: register n; ! 1718: register char *p, *lastloc; ! 1719: ! 1720: p = loc; ! 1721: lastloc = &p[maxlen-1]; ! 1722: while ((n = getc(fp)) != '\n') { ! 1723: if (n == EOF) ! 1724: return (EOF); ! 1725: if (!isspace(n) && p < lastloc) ! 1726: *p++ = n; ! 1727: } ! 1728: *p = 0; ! 1729: return (p - loc); ! 1730: } ! 1731: ! 1732: BUFAREA * ! 1733: getblk(bp, blk, size) ! 1734: register BUFAREA *bp; ! 1735: daddr_t blk; ! 1736: long size; ! 1737: { ! 1738: register struct filecntl *fcp; ! 1739: daddr_t dblk; ! 1740: ! 1741: fcp = &dfile; ! 1742: dblk = fsbtodb(&sblock, blk); ! 1743: if (bp->b_bno == dblk) ! 1744: return (bp); ! 1745: flush(fcp, bp); ! 1746: if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) { ! 1747: bp->b_bno = dblk; ! 1748: bp->b_size = size; ! 1749: return (bp); ! 1750: } ! 1751: bp->b_bno = (daddr_t)-1; ! 1752: return (NULL); ! 1753: } ! 1754: ! 1755: flush(fcp, bp) ! 1756: struct filecntl *fcp; ! 1757: register BUFAREA *bp; ! 1758: { ! 1759: ! 1760: if (bp->b_dirty) ! 1761: (void)bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); ! 1762: bp->b_dirty = 0; ! 1763: } ! 1764: ! 1765: rwerr(s, blk) ! 1766: char *s; ! 1767: daddr_t blk; ! 1768: { ! 1769: ! 1770: if (preen == 0) ! 1771: printf("\n"); ! 1772: pfatal("CANNOT %s: BLK %ld", s, blk); ! 1773: if (reply("CONTINUE") == 0) ! 1774: errexit("Program terminated\n"); ! 1775: } ! 1776: ! 1777: ckfini() ! 1778: { ! 1779: ! 1780: flush(&dfile, &fileblk); ! 1781: flush(&dfile, &sblk); ! 1782: if (sblk.b_bno != SBLOCK) { ! 1783: sblk.b_bno = SBLOCK; ! 1784: sbdirty(); ! 1785: flush(&dfile, &sblk); ! 1786: } ! 1787: flush(&dfile, &inoblk); ! 1788: (void)close(dfile.rfdes); ! 1789: (void)close(dfile.wfdes); ! 1790: } ! 1791: ! 1792: pinode(ino) ! 1793: ino_t ino; ! 1794: { ! 1795: register DINODE *dp; ! 1796: register char *p; ! 1797: char uidbuf[BUFSIZ]; ! 1798: char *ctime(); ! 1799: ! 1800: printf(" I=%u ", ino); ! 1801: if ((dp = ginode(ino)) == NULL) ! 1802: return; ! 1803: printf(" OWNER="); ! 1804: if (getpw((int)dp->di_uid, uidbuf) == 0) { ! 1805: for (p = uidbuf; *p != ':'; p++); ! 1806: *p = 0; ! 1807: printf("%s ", uidbuf); ! 1808: } ! 1809: else { ! 1810: printf("%d ", dp->di_uid); ! 1811: } ! 1812: printf("MODE=%o\n", dp->di_mode); ! 1813: if (preen) ! 1814: printf("%s: ", devname); ! 1815: printf("SIZE=%ld ", dp->di_size); ! 1816: p = ctime(&dp->di_mtime); ! 1817: printf("MTIME=%12.12s %4.4s ", p+4, p+20); ! 1818: } ! 1819: ! 1820: makecg() ! 1821: { ! 1822: int c, blk; ! 1823: daddr_t dbase, d, dlower, dupper, dmax; ! 1824: long i, j, s; ! 1825: ino_t inumber; ! 1826: register struct csum *cs; ! 1827: register DINODE *dp; ! 1828: ! 1829: sblock.fs_cstotal.cs_nbfree = 0; ! 1830: sblock.fs_cstotal.cs_nffree = 0; ! 1831: sblock.fs_cstotal.cs_nifree = 0; ! 1832: sblock.fs_cstotal.cs_ndir = 0; ! 1833: for (c = 0; c < sblock.fs_ncg; c++) { ! 1834: dbase = cgbase(&sblock, c); ! 1835: dmax = dbase + sblock.fs_fpg; ! 1836: if (dmax > sblock.fs_size) { ! 1837: for ( ; dmax >= sblock.fs_size; dmax--) ! 1838: clrbit(cgrp.cg_free, dmax - dbase); ! 1839: dmax++; ! 1840: } ! 1841: dlower = cgsblock(&sblock, c) - dbase; ! 1842: dupper = cgdmin(&sblock, c) - dbase; ! 1843: cs = &sblock.fs_cs(&sblock, c); ! 1844: (void)time(&cgrp.cg_time); ! 1845: cgrp.cg_magic = CG_MAGIC; ! 1846: cgrp.cg_cgx = c; ! 1847: if (c == sblock.fs_ncg - 1) ! 1848: cgrp.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg; ! 1849: else ! 1850: cgrp.cg_ncyl = sblock.fs_cpg; ! 1851: cgrp.cg_niblk = sblock.fs_ipg; ! 1852: cgrp.cg_ndblk = dmax - dbase; ! 1853: cgrp.cg_cs.cs_ndir = 0; ! 1854: cgrp.cg_cs.cs_nffree = 0; ! 1855: cgrp.cg_cs.cs_nbfree = 0; ! 1856: cgrp.cg_cs.cs_nifree = 0; ! 1857: cgrp.cg_rotor = 0; ! 1858: cgrp.cg_frotor = 0; ! 1859: cgrp.cg_irotor = 0; ! 1860: for (i = 0; i < sblock.fs_frag; i++) ! 1861: cgrp.cg_frsum[i] = 0; ! 1862: inumber = sblock.fs_ipg * c; ! 1863: for (i = 0; i < sblock.fs_ipg; inumber++, i++) { ! 1864: cgrp.cg_cs.cs_nifree++; ! 1865: clrbit(cgrp.cg_iused, i); ! 1866: dp = ginode(inumber); ! 1867: if (dp == NULL) ! 1868: continue; ! 1869: if (ALLOC) { ! 1870: if (DIRCT) ! 1871: cgrp.cg_cs.cs_ndir++; ! 1872: cgrp.cg_cs.cs_nifree--; ! 1873: setbit(cgrp.cg_iused, i); ! 1874: continue; ! 1875: } ! 1876: } ! 1877: while (i < MAXIPG) { ! 1878: clrbit(cgrp.cg_iused, i); ! 1879: i++; ! 1880: } ! 1881: if (c == 0) ! 1882: for (i = 0; i < ROOTINO; i++) { ! 1883: setbit(cgrp.cg_iused, i); ! 1884: cgrp.cg_cs.cs_nifree--; ! 1885: } ! 1886: for (s = 0; s < MAXCPG; s++) { ! 1887: cgrp.cg_btot[s] = 0; ! 1888: for (i = 0; i < NRPOS; i++) ! 1889: cgrp.cg_b[s][i] = 0; ! 1890: } ! 1891: if (c == 0) { ! 1892: dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); ! 1893: } ! 1894: for (d = dlower; d < dupper; d++) ! 1895: clrbit(cgrp.cg_free, d); ! 1896: for (d = 0; (d + sblock.fs_frag) <= dmax - dbase; ! 1897: d += sblock.fs_frag) { ! 1898: j = 0; ! 1899: for (i = 0; i < sblock.fs_frag; i++) { ! 1900: if (!getbmap(dbase + d + i)) { ! 1901: setbit(cgrp.cg_free, d + i); ! 1902: j++; ! 1903: } else ! 1904: clrbit(cgrp.cg_free, d+i); ! 1905: } ! 1906: if (j == sblock.fs_frag) { ! 1907: cgrp.cg_cs.cs_nbfree++; ! 1908: cgrp.cg_btot[cbtocylno(&sblock, d)]++; ! 1909: cgrp.cg_b[cbtocylno(&sblock, d)] ! 1910: [cbtorpos(&sblock, d)]++; ! 1911: } else if (j > 0) { ! 1912: cgrp.cg_cs.cs_nffree += j; ! 1913: blk = blkmap(&sblock, cgrp.cg_free, d); ! 1914: fragacct(&sblock, blk, cgrp.cg_frsum, 1); ! 1915: } ! 1916: } ! 1917: for (j = d; d < dmax - dbase; d++) { ! 1918: if (!getbmap(dbase + d)) { ! 1919: setbit(cgrp.cg_free, d); ! 1920: cgrp.cg_cs.cs_nffree++; ! 1921: } else ! 1922: clrbit(cgrp.cg_free, d); ! 1923: } ! 1924: for (; d % sblock.fs_frag != 0; d++) ! 1925: clrbit(cgrp.cg_free, d); ! 1926: if (j != d) { ! 1927: blk = blkmap(&sblock, cgrp.cg_free, j); ! 1928: fragacct(&sblock, blk, cgrp.cg_frsum, 1); ! 1929: } ! 1930: for (d /= sblock.fs_frag; d < MAXBPG(&sblock); d ++) ! 1931: clrblock(&sblock, cgrp.cg_free, d); ! 1932: sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree; ! 1933: sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree; ! 1934: sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree; ! 1935: sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir; ! 1936: *cs = cgrp.cg_cs; ! 1937: (void)bwrite(&dfile, (char *)&cgrp, ! 1938: fsbtodb(&sblock, cgtod(&sblock, c)), sblock.fs_cgsize); ! 1939: } ! 1940: for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { ! 1941: (void)bwrite(&dfile, (char *)sblock.fs_csp[j], ! 1942: fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), ! 1943: sblock.fs_cssize - i < sblock.fs_bsize ? ! 1944: sblock.fs_cssize - i : sblock.fs_bsize); ! 1945: } ! 1946: sblock.fs_ronly = 0; ! 1947: sblock.fs_fmod = 0; ! 1948: sbdirty(); ! 1949: } ! 1950: ! 1951: findino(idesc) ! 1952: struct inodesc *idesc; ! 1953: { ! 1954: register DIRECT *dirp = idesc->id_dirp; ! 1955: ! 1956: if (dirp->d_ino == 0) ! 1957: return (KEEPON); ! 1958: if (!strcmp(dirp->d_name, srchname)) { ! 1959: if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax) ! 1960: idesc->id_parent = dirp->d_ino; ! 1961: return (STOP); ! 1962: } ! 1963: return (KEEPON); ! 1964: } ! 1965: ! 1966: mkentry(idesc) ! 1967: struct inodesc *idesc; ! 1968: { ! 1969: register DIRECT *dirp = idesc->id_dirp; ! 1970: DIRECT newent; ! 1971: int newlen, oldlen; ! 1972: ! 1973: newent.d_namlen = 11; ! 1974: newlen = DIRSIZ(&newent); ! 1975: if (dirp->d_ino != 0) ! 1976: oldlen = DIRSIZ(dirp); ! 1977: else ! 1978: oldlen = 0; ! 1979: if (dirp->d_reclen - oldlen < newlen) ! 1980: return (KEEPON); ! 1981: newent.d_reclen = dirp->d_reclen - oldlen; ! 1982: dirp->d_reclen = oldlen; ! 1983: dirp = (struct direct *)(((char *)dirp) + oldlen); ! 1984: dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ ! 1985: dirp->d_reclen = newent.d_reclen; ! 1986: dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent); ! 1987: return (ALTERED|STOP); ! 1988: } ! 1989: ! 1990: chgdd(idesc) ! 1991: struct inodesc *idesc; ! 1992: { ! 1993: register DIRECT *dirp = idesc->id_dirp; ! 1994: ! 1995: if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' && ! 1996: dirp->d_name[2] == 0) { ! 1997: dirp->d_ino = lfdir; ! 1998: return (ALTERED|STOP); ! 1999: } ! 2000: return (KEEPON); ! 2001: } ! 2002: ! 2003: linkup(orphan, pdir) ! 2004: ino_t orphan; ! 2005: ino_t pdir; ! 2006: { ! 2007: register DINODE *dp; ! 2008: int lostdir, len; ! 2009: struct inodesc idesc; ! 2010: ! 2011: bzero((char *)&idesc, sizeof(struct inodesc)); ! 2012: if ((dp = ginode(orphan)) == NULL) ! 2013: return (0); ! 2014: lostdir = DIRCT; ! 2015: pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); ! 2016: pinode(orphan); ! 2017: if (preen && dp->di_size == 0) ! 2018: return (0); ! 2019: if (preen) ! 2020: printf(" (RECONNECTED)\n"); ! 2021: else ! 2022: if (reply("RECONNECT") == 0) ! 2023: return (0); ! 2024: pathp = pathname; ! 2025: *pathp++ = '/'; ! 2026: *pathp = '\0'; ! 2027: if (lfdir == 0) { ! 2028: if ((dp = ginode(ROOTINO)) == NULL) ! 2029: return (0); ! 2030: srchname = lfname; ! 2031: idesc.id_type = DATA; ! 2032: idesc.id_func = findino; ! 2033: idesc.id_number = ROOTINO; ! 2034: idesc.id_filesize = dp->di_size; ! 2035: (void)ckinode(dp, &idesc); ! 2036: if ((lfdir = idesc.id_parent) == 0) { ! 2037: pfatal("SORRY. NO lost+found DIRECTORY"); ! 2038: printf("\n\n"); ! 2039: return (0); ! 2040: } ! 2041: } ! 2042: if ((dp = ginode(lfdir)) == NULL || ! 2043: !DIRCT || statemap[lfdir] != FSTATE) { ! 2044: pfatal("SORRY. NO lost+found DIRECTORY"); ! 2045: printf("\n\n"); ! 2046: return (0); ! 2047: } ! 2048: if (fragoff(&sblock, dp->di_size)) { ! 2049: dp->di_size = fragroundup(&sblock, dp->di_size); ! 2050: inodirty(); ! 2051: } ! 2052: len = strlen(lfname); ! 2053: bcopy(lfname, pathp, len + 1); ! 2054: pathp += len; ! 2055: idesc.id_type = DATA; ! 2056: idesc.id_func = mkentry; ! 2057: idesc.id_number = lfdir; ! 2058: idesc.id_filesize = dp->di_size; ! 2059: idesc.id_parent = orphan; /* this is the inode to enter */ ! 2060: idesc.id_fix = DONTKNOW; ! 2061: if ((ckinode(dp, &idesc) & ALTERED) == 0) { ! 2062: pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); ! 2063: printf("\n\n"); ! 2064: return (0); ! 2065: } ! 2066: lncntp[orphan]--; ! 2067: *pathp++ = '/'; ! 2068: pathp += lftempname(pathp, orphan); ! 2069: if (lostdir) { ! 2070: dp = ginode(orphan); ! 2071: idesc.id_type = DATA; ! 2072: idesc.id_func = chgdd; ! 2073: idesc.id_number = orphan; ! 2074: idesc.id_filesize = dp->di_size; ! 2075: idesc.id_fix = DONTKNOW; ! 2076: (void)ckinode(dp, &idesc); ! 2077: if ((dp = ginode(lfdir)) != NULL) { ! 2078: dp->di_nlink++; ! 2079: inodirty(); ! 2080: lncntp[lfdir]++; ! 2081: } ! 2082: pwarn("DIR I=%u CONNECTED. ", orphan); ! 2083: printf("PARENT WAS I=%u\n", pdir); ! 2084: if (preen == 0) ! 2085: printf("\n"); ! 2086: } ! 2087: return (1); ! 2088: } ! 2089: ! 2090: /* ! 2091: * generate a temporary name for the lost+found directory. ! 2092: */ ! 2093: lftempname(bufp, ino) ! 2094: char *bufp; ! 2095: ino_t ino; ! 2096: { ! 2097: register ino_t in; ! 2098: register char *cp; ! 2099: int namlen; ! 2100: ! 2101: cp = bufp + 2; ! 2102: for (in = imax; in > 0; in /= 10) ! 2103: cp++; ! 2104: *--cp = 0; ! 2105: namlen = cp - bufp; ! 2106: in = ino; ! 2107: while (cp > bufp) { ! 2108: *--cp = (in % 10) + '0'; ! 2109: in /= 10; ! 2110: } ! 2111: *cp = '#'; ! 2112: return (namlen); ! 2113: } ! 2114: ! 2115: bread(fcp, buf, blk, size) ! 2116: register struct filecntl *fcp; ! 2117: char *buf; ! 2118: daddr_t blk; ! 2119: long size; ! 2120: { ! 2121: if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0) ! 2122: rwerr("SEEK", blk); ! 2123: else if (read(fcp->rfdes, buf, (int)size) == size) ! 2124: return (1); ! 2125: rwerr("READ", blk); ! 2126: return (0); ! 2127: } ! 2128: ! 2129: bwrite(fcp, buf, blk, size) ! 2130: register struct filecntl *fcp; ! 2131: char *buf; ! 2132: daddr_t blk; ! 2133: long size; ! 2134: { ! 2135: ! 2136: if (fcp->wfdes < 0) ! 2137: return (0); ! 2138: if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0) ! 2139: rwerr("SEEK", blk); ! 2140: else if (write(fcp->wfdes, buf, (int)size) == size) { ! 2141: fcp->mod = 1; ! 2142: return (1); ! 2143: } ! 2144: rwerr("WRITE", blk); ! 2145: return (0); ! 2146: } ! 2147: ! 2148: catch() ! 2149: { ! 2150: ! 2151: ckfini(); ! 2152: exit(12); ! 2153: } ! 2154: ! 2155: char * ! 2156: unrawname(cp) ! 2157: char *cp; ! 2158: { ! 2159: char *dp = rindex(cp, '/'); ! 2160: struct stat stb; ! 2161: ! 2162: if (dp == 0) ! 2163: return (cp); ! 2164: if (stat(cp, &stb) < 0) ! 2165: return (cp); ! 2166: if ((stb.st_mode&S_IFMT) != S_IFCHR) ! 2167: return (cp); ! 2168: if (*(dp+1) != 'r') ! 2169: return (cp); ! 2170: (void)strcpy(dp+1, dp+2); ! 2171: return (cp); ! 2172: } ! 2173: ! 2174: char * ! 2175: rawname(cp) ! 2176: char *cp; ! 2177: { ! 2178: static char rawbuf[32]; ! 2179: char *dp = rindex(cp, '/'); ! 2180: ! 2181: if (dp == 0) ! 2182: return (0); ! 2183: *dp = 0; ! 2184: (void)strcpy(rawbuf, cp); ! 2185: *dp = '/'; ! 2186: (void)strcat(rawbuf, "/r"); ! 2187: (void)strcat(rawbuf, dp+1); ! 2188: return (rawbuf); ! 2189: } ! 2190: ! 2191: /* ! 2192: * determine whether an inode should be fixed. ! 2193: */ ! 2194: dofix(idesc) ! 2195: register struct inodesc *idesc; ! 2196: { ! 2197: ! 2198: switch (idesc->id_fix) { ! 2199: ! 2200: case DONTKNOW: ! 2201: direrr(idesc->id_number, "DIRECTORY CORRUPTED"); ! 2202: if (reply("SALVAGE") == 0) { ! 2203: idesc->id_fix = NOFIX; ! 2204: return (0); ! 2205: } ! 2206: idesc->id_fix = FIX; ! 2207: return (ALTERED); ! 2208: ! 2209: case FIX: ! 2210: return (ALTERED); ! 2211: ! 2212: case NOFIX: ! 2213: return (0); ! 2214: ! 2215: default: ! 2216: errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); ! 2217: } ! 2218: /* NOTREACHED */ ! 2219: } ! 2220: ! 2221: /* VARARGS1 */ ! 2222: error(s1, s2, s3, s4) ! 2223: char *s1; ! 2224: { ! 2225: ! 2226: printf(s1, s2, s3, s4); ! 2227: } ! 2228: ! 2229: /* VARARGS1 */ ! 2230: errexit(s1, s2, s3, s4) ! 2231: char *s1; ! 2232: { ! 2233: error(s1, s2, s3, s4); ! 2234: exit(8); ! 2235: } ! 2236: ! 2237: /* ! 2238: * An inconsistency occured which shouldn't during normal operations. ! 2239: * Die if preening, otherwise just printf. ! 2240: */ ! 2241: /* VARARGS1 */ ! 2242: pfatal(s, a1, a2, a3) ! 2243: char *s; ! 2244: { ! 2245: ! 2246: if (preen) { ! 2247: printf("%s: ", devname); ! 2248: printf(s, a1, a2, a3); ! 2249: printf("\n"); ! 2250: preendie(); ! 2251: } ! 2252: printf(s, a1, a2, a3); ! 2253: } ! 2254: ! 2255: preendie() ! 2256: { ! 2257: ! 2258: printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname); ! 2259: exit(8); ! 2260: } ! 2261: ! 2262: /* ! 2263: * Pwarn is like printf when not preening, ! 2264: * or a warning (preceded by filename) when preening. ! 2265: */ ! 2266: /* VARARGS1 */ ! 2267: pwarn(s, a1, a2, a3, a4, a5, a6) ! 2268: char *s; ! 2269: { ! 2270: ! 2271: if (preen) ! 2272: printf("%s: ", devname); ! 2273: printf(s, a1, a2, a3, a4, a5, a6); ! 2274: } ! 2275: ! 2276: #ifndef lint ! 2277: /* ! 2278: * Stub for routines from kernel. ! 2279: */ ! 2280: panic(s) ! 2281: char *s; ! 2282: { ! 2283: ! 2284: pfatal("INTERNAL INCONSISTENCY: %s\n", s); ! 2285: exit(12); ! 2286: } ! 2287: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.