|
|
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; ap < aplim; ap++, i++) ! 1354: if (*ap) { ! 1355: idesc->id_blkno = *ap; ! 1356: if (ilevel > 0) ! 1357: n = iblock(idesc, ilevel, ! 1358: isize - i*NINDIR(&sblock)*sblock.fs_bsize); ! 1359: else ! 1360: n = (*func)(idesc); ! 1361: if (n & STOP) ! 1362: return (n); ! 1363: } ! 1364: return (KEEPON); ! 1365: } ! 1366: ! 1367: outrange(blk, cnt) ! 1368: daddr_t blk; ! 1369: int cnt; ! 1370: { ! 1371: register int c; ! 1372: ! 1373: if ((unsigned)(blk+cnt) > fmax) ! 1374: return (1); ! 1375: c = dtog(&sblock, blk); ! 1376: if (blk < cgdmin(&sblock, c)) { ! 1377: if ((blk+cnt) > cgsblock(&sblock, c)) { ! 1378: if (debug) { ! 1379: printf("blk %d < cgdmin %d;", ! 1380: blk, cgdmin(&sblock, c)); ! 1381: printf(" blk+cnt %d > cgsbase %d\n", ! 1382: blk+cnt, cgsblock(&sblock, c)); ! 1383: } ! 1384: return (1); ! 1385: } ! 1386: } else { ! 1387: if ((blk+cnt) > cgbase(&sblock, c+1)) { ! 1388: if (debug) { ! 1389: printf("blk %d >= cgdmin %d;", ! 1390: blk, cgdmin(&sblock, c)); ! 1391: printf(" blk+cnt %d > sblock.fs_fpg %d\n", ! 1392: blk+cnt, sblock.fs_fpg); ! 1393: } ! 1394: return (1); ! 1395: } ! 1396: } ! 1397: return (0); ! 1398: } ! 1399: ! 1400: blkerr(ino, s, blk) ! 1401: ino_t ino; ! 1402: char *s; ! 1403: daddr_t blk; ! 1404: { ! 1405: ! 1406: pfatal("%ld %s I=%u", blk, s, ino); ! 1407: printf("\n"); ! 1408: statemap[ino] = CLEAR; ! 1409: } ! 1410: ! 1411: descend(parentino, inumber) ! 1412: struct inodesc *parentino; ! 1413: ino_t inumber; ! 1414: { ! 1415: register DINODE *dp; ! 1416: struct inodesc curino; ! 1417: ! 1418: bzero((char *)&curino, sizeof(struct inodesc)); ! 1419: statemap[inumber] = FSTATE; ! 1420: if ((dp = ginode(inumber)) == NULL) ! 1421: return; ! 1422: if (dp->di_size == 0) { ! 1423: direrr(inumber, "ZERO LENGTH DIRECTORY"); ! 1424: if (reply("REMOVE") == 1) ! 1425: statemap[inumber] = CLEAR; ! 1426: return; ! 1427: } ! 1428: if (dp->di_size < MINDIRSIZE) { ! 1429: direrr(inumber, "DIRECTORY TOO SHORT"); ! 1430: dp->di_size = MINDIRSIZE; ! 1431: if (reply("FIX") == 1) ! 1432: inodirty(); ! 1433: } ! 1434: curino.id_type = DATA; ! 1435: curino.id_func = parentino->id_func; ! 1436: curino.id_parent = parentino->id_number; ! 1437: curino.id_number = inumber; ! 1438: curino.id_filesize = dp->di_size; ! 1439: (void)ckinode(dp, &curino); ! 1440: } ! 1441: ! 1442: dirscan(idesc) ! 1443: register struct inodesc *idesc; ! 1444: { ! 1445: register DIRECT *dp; ! 1446: int dsize, n; ! 1447: long blksiz; ! 1448: char dbuf[DIRBLKSIZ]; ! 1449: ! 1450: if (idesc->id_type != DATA) ! 1451: errexit("wrong type to dirscan %d\n", idesc->id_type); ! 1452: blksiz = idesc->id_numfrags * sblock.fs_fsize; ! 1453: if (outrange(idesc->id_blkno, idesc->id_numfrags)) { ! 1454: idesc->id_filesize -= blksiz; ! 1455: return (SKIP); ! 1456: } ! 1457: idesc->id_loc = 0; ! 1458: for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) { ! 1459: dsize = dp->d_reclen; ! 1460: bcopy((char *)dp, dbuf, dsize); ! 1461: idesc->id_dirp = (DIRECT *)dbuf; ! 1462: if ((n = (*idesc->id_func)(idesc)) & ALTERED) { ! 1463: if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) { ! 1464: bcopy(dbuf, (char *)dp, dsize); ! 1465: dirty(&fileblk); ! 1466: sbdirty(); ! 1467: } else ! 1468: n &= ~ALTERED; ! 1469: } ! 1470: if (n & STOP) ! 1471: return (n); ! 1472: } ! 1473: return (idesc->id_filesize > 0 ? KEEPON : STOP); ! 1474: } ! 1475: ! 1476: /* ! 1477: * get next entry in a directory. ! 1478: */ ! 1479: DIRECT * ! 1480: fsck_readdir(idesc) ! 1481: register struct inodesc *idesc; ! 1482: { ! 1483: register DIRECT *dp, *ndp; ! 1484: long size, blksiz; ! 1485: ! 1486: blksiz = idesc->id_numfrags * sblock.fs_fsize; ! 1487: if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) { ! 1488: idesc->id_filesize -= blksiz - idesc->id_loc; ! 1489: return NULL; ! 1490: } ! 1491: if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 && ! 1492: idesc->id_loc < blksiz) { ! 1493: dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); ! 1494: if (dircheck(idesc, dp)) ! 1495: goto dpok; ! 1496: idesc->id_loc += DIRBLKSIZ; ! 1497: idesc->id_filesize -= DIRBLKSIZ; ! 1498: dp->d_reclen = DIRBLKSIZ; ! 1499: dp->d_ino = 0; ! 1500: dp->d_namlen = 0; ! 1501: dp->d_name[0] = '\0'; ! 1502: if (dofix(idesc)) ! 1503: dirty(&fileblk); ! 1504: return (dp); ! 1505: } ! 1506: dpok: ! 1507: if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz) ! 1508: return NULL; ! 1509: dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); ! 1510: idesc->id_loc += dp->d_reclen; ! 1511: idesc->id_filesize -= dp->d_reclen; ! 1512: ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc); ! 1513: if ((idesc->id_filesize <= 0 && idesc->id_loc % DIRBLKSIZ != 0) || ! 1514: (idesc->id_loc < blksiz && idesc->id_filesize > 0 && ! 1515: dircheck(idesc, ndp) == 0)) { ! 1516: size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); ! 1517: dp->d_reclen += size; ! 1518: idesc->id_loc += size; ! 1519: idesc->id_filesize -= size; ! 1520: if (dofix(idesc)) ! 1521: dirty(&fileblk); ! 1522: } ! 1523: return (dp); ! 1524: } ! 1525: ! 1526: /* ! 1527: * Verify that a directory entry is valid. ! 1528: * This is a superset of the checks made in the kernel. ! 1529: */ ! 1530: dircheck(idesc, dp) ! 1531: struct inodesc *idesc; ! 1532: register DIRECT *dp; ! 1533: { ! 1534: register int size; ! 1535: register char *cp; ! 1536: int spaceleft; ! 1537: ! 1538: size = DIRSIZ(dp); ! 1539: spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ); ! 1540: if (dp->d_ino < imax && ! 1541: dp->d_reclen != 0 && ! 1542: dp->d_reclen <= spaceleft && ! 1543: (dp->d_reclen & 0x3) == 0 && ! 1544: dp->d_reclen >= size && ! 1545: idesc->id_filesize >= size && ! 1546: dp->d_namlen <= MAXNAMLEN) { ! 1547: if (dp->d_ino == 0) ! 1548: return (1); ! 1549: for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++) ! 1550: if (*cp == 0 || (*cp++ & 0200)) ! 1551: return (0); ! 1552: if (*cp == 0) ! 1553: return (1); ! 1554: } ! 1555: return (0); ! 1556: } ! 1557: ! 1558: direrr(ino, s) ! 1559: ino_t ino; ! 1560: char *s; ! 1561: { ! 1562: register DINODE *dp; ! 1563: ! 1564: pwarn("%s ", s); ! 1565: pinode(ino); ! 1566: printf("\n"); ! 1567: if ((dp = ginode(ino)) != NULL && ftypeok(dp)) ! 1568: pfatal("%s=%s\n", DIRCT?"DIR":"FILE", pathname); ! 1569: else ! 1570: pfatal("NAME=%s\n", pathname); ! 1571: } ! 1572: ! 1573: adjust(idesc, lcnt) ! 1574: register struct inodesc *idesc; ! 1575: short lcnt; ! 1576: { ! 1577: register DINODE *dp; ! 1578: ! 1579: if ((dp = ginode(idesc->id_number)) == NULL) ! 1580: return; ! 1581: if (dp->di_nlink == lcnt) { ! 1582: if (linkup(idesc->id_number, (ino_t)0) == 0) ! 1583: clri(idesc, "UNREF", 0); ! 1584: } ! 1585: else { ! 1586: pwarn("LINK COUNT %s", ! 1587: (lfdir==idesc->id_number)?lfname:(DIRCT?"DIR":"FILE")); ! 1588: pinode(idesc->id_number); ! 1589: printf(" COUNT %d SHOULD BE %d", ! 1590: dp->di_nlink, dp->di_nlink-lcnt); ! 1591: if (preen) { ! 1592: if (lcnt < 0) { ! 1593: printf("\n"); ! 1594: preendie(); ! 1595: } ! 1596: printf(" (ADJUSTED)\n"); ! 1597: } ! 1598: if (preen || reply("ADJUST") == 1) { ! 1599: dp->di_nlink -= lcnt; ! 1600: inodirty(); ! 1601: } ! 1602: } ! 1603: } ! 1604: ! 1605: clri(idesc, s, flg) ! 1606: register struct inodesc *idesc; ! 1607: char *s; ! 1608: int flg; ! 1609: { ! 1610: register DINODE *dp; ! 1611: ! 1612: if ((dp = ginode(idesc->id_number)) == NULL) ! 1613: return; ! 1614: if (flg == 1) { ! 1615: pwarn("%s %s", s, DIRCT?"DIR":"FILE"); ! 1616: pinode(idesc->id_number); ! 1617: } ! 1618: if (preen || reply("CLEAR") == 1) { ! 1619: if (preen) ! 1620: printf(" (CLEARED)\n"); ! 1621: n_files--; ! 1622: (void)ckinode(dp, idesc); ! 1623: zapino(dp); ! 1624: statemap[idesc->id_number] = USTATE; ! 1625: inodirty(); ! 1626: inosumbad++; ! 1627: } ! 1628: } ! 1629: ! 1630: badsb(s) ! 1631: char *s; ! 1632: { ! 1633: ! 1634: if (preen) ! 1635: printf("%s: ", devname); ! 1636: printf("BAD SUPER BLOCK: %s\n", s); ! 1637: pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n"); ! 1638: pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n"); ! 1639: } ! 1640: ! 1641: DINODE * ! 1642: ginode(inumber) ! 1643: ino_t inumber; ! 1644: { ! 1645: daddr_t iblk; ! 1646: static ino_t startinum = 0; /* blk num of first in raw area */ ! 1647: ! 1648: ! 1649: if (inumber < ROOTINO || inumber > imax) { ! 1650: if (debug && inumber > imax) ! 1651: printf("inumber out of range (%d)\n", inumber); ! 1652: return (NULL); ! 1653: } ! 1654: if (startinum == 0 || ! 1655: inumber < startinum || inumber >= startinum + INOPB(&sblock)) { ! 1656: iblk = itod(&sblock, inumber); ! 1657: if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) { ! 1658: return (NULL); ! 1659: } ! 1660: startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); ! 1661: } ! 1662: return (&inoblk.b_un.b_dinode[inumber % INOPB(&sblock)]); ! 1663: } ! 1664: ! 1665: ftypeok(dp) ! 1666: DINODE *dp; ! 1667: { ! 1668: switch (dp->di_mode & IFMT) { ! 1669: ! 1670: case IFDIR: ! 1671: case IFREG: ! 1672: case IFBLK: ! 1673: case IFCHR: ! 1674: case IFLNK: ! 1675: case IFSOCK: ! 1676: return (1); ! 1677: ! 1678: default: ! 1679: if (debug) ! 1680: printf("bad file type 0%o\n", dp->di_mode); ! 1681: return (0); ! 1682: } ! 1683: } ! 1684: ! 1685: reply(s) ! 1686: char *s; ! 1687: { ! 1688: char line[80]; ! 1689: ! 1690: if (preen) ! 1691: pfatal("INTERNAL ERROR: GOT TO reply()"); ! 1692: rplyflag = 1; ! 1693: printf("\n%s? ", s); ! 1694: if (nflag || dfile.wfdes < 0) { ! 1695: printf(" no\n\n"); ! 1696: return (0); ! 1697: } ! 1698: if (yflag) { ! 1699: printf(" yes\n\n"); ! 1700: return (1); ! 1701: } ! 1702: if (getline(stdin, line, sizeof(line)) == EOF) ! 1703: errexit("\n"); ! 1704: printf("\n"); ! 1705: if (line[0] == 'y' || line[0] == 'Y') ! 1706: return (1); ! 1707: else ! 1708: return (0); ! 1709: } ! 1710: ! 1711: getline(fp, loc, maxlen) ! 1712: FILE *fp; ! 1713: char *loc; ! 1714: { ! 1715: register n; ! 1716: register char *p, *lastloc; ! 1717: ! 1718: p = loc; ! 1719: lastloc = &p[maxlen-1]; ! 1720: while ((n = getc(fp)) != '\n') { ! 1721: if (n == EOF) ! 1722: return (EOF); ! 1723: if (!isspace(n) && p < lastloc) ! 1724: *p++ = n; ! 1725: } ! 1726: *p = 0; ! 1727: return (p - loc); ! 1728: } ! 1729: ! 1730: BUFAREA * ! 1731: getblk(bp, blk, size) ! 1732: register BUFAREA *bp; ! 1733: daddr_t blk; ! 1734: long size; ! 1735: { ! 1736: register struct filecntl *fcp; ! 1737: daddr_t dblk; ! 1738: ! 1739: fcp = &dfile; ! 1740: dblk = fsbtodb(&sblock, blk); ! 1741: if (bp->b_bno == dblk) ! 1742: return (bp); ! 1743: flush(fcp, bp); ! 1744: if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) { ! 1745: bp->b_bno = dblk; ! 1746: bp->b_size = size; ! 1747: return (bp); ! 1748: } ! 1749: bp->b_bno = (daddr_t)-1; ! 1750: return (NULL); ! 1751: } ! 1752: ! 1753: flush(fcp, bp) ! 1754: struct filecntl *fcp; ! 1755: register BUFAREA *bp; ! 1756: { ! 1757: ! 1758: if (bp->b_dirty) ! 1759: (void)bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); ! 1760: bp->b_dirty = 0; ! 1761: } ! 1762: ! 1763: rwerr(s, blk) ! 1764: char *s; ! 1765: daddr_t blk; ! 1766: { ! 1767: ! 1768: if (preen == 0) ! 1769: printf("\n"); ! 1770: pfatal("CANNOT %s: BLK %ld", s, blk); ! 1771: if (reply("CONTINUE") == 0) ! 1772: errexit("Program terminated\n"); ! 1773: } ! 1774: ! 1775: ckfini() ! 1776: { ! 1777: ! 1778: flush(&dfile, &fileblk); ! 1779: flush(&dfile, &sblk); ! 1780: if (sblk.b_bno != SBLOCK) { ! 1781: sblk.b_bno = SBLOCK; ! 1782: sbdirty(); ! 1783: flush(&dfile, &sblk); ! 1784: } ! 1785: flush(&dfile, &inoblk); ! 1786: (void)close(dfile.rfdes); ! 1787: (void)close(dfile.wfdes); ! 1788: } ! 1789: ! 1790: pinode(ino) ! 1791: ino_t ino; ! 1792: { ! 1793: register DINODE *dp; ! 1794: register char *p; ! 1795: char uidbuf[BUFSIZ]; ! 1796: char *ctime(); ! 1797: ! 1798: printf(" I=%u ", ino); ! 1799: if ((dp = ginode(ino)) == NULL) ! 1800: return; ! 1801: printf(" OWNER="); ! 1802: if (getpw((int)dp->di_uid, uidbuf) == 0) { ! 1803: for (p = uidbuf; *p != ':'; p++); ! 1804: *p = 0; ! 1805: printf("%s ", uidbuf); ! 1806: } ! 1807: else { ! 1808: printf("%d ", dp->di_uid); ! 1809: } ! 1810: printf("MODE=%o\n", dp->di_mode); ! 1811: if (preen) ! 1812: printf("%s: ", devname); ! 1813: printf("SIZE=%ld ", dp->di_size); ! 1814: p = ctime(&dp->di_mtime); ! 1815: printf("MTIME=%12.12s %4.4s ", p+4, p+20); ! 1816: } ! 1817: ! 1818: makecg() ! 1819: { ! 1820: int c, blk; ! 1821: daddr_t dbase, d, dlower, dupper, dmax; ! 1822: long i, j, s; ! 1823: ino_t inumber; ! 1824: register struct csum *cs; ! 1825: register DINODE *dp; ! 1826: ! 1827: sblock.fs_cstotal.cs_nbfree = 0; ! 1828: sblock.fs_cstotal.cs_nffree = 0; ! 1829: sblock.fs_cstotal.cs_nifree = 0; ! 1830: sblock.fs_cstotal.cs_ndir = 0; ! 1831: for (c = 0; c < sblock.fs_ncg; c++) { ! 1832: dbase = cgbase(&sblock, c); ! 1833: dmax = dbase + sblock.fs_fpg; ! 1834: if (dmax > sblock.fs_size) { ! 1835: for ( ; dmax >= sblock.fs_size; dmax--) ! 1836: clrbit(cgrp.cg_free, dmax - dbase); ! 1837: dmax++; ! 1838: } ! 1839: dlower = cgsblock(&sblock, c) - dbase; ! 1840: dupper = cgdmin(&sblock, c) - dbase; ! 1841: cs = &sblock.fs_cs(&sblock, c); ! 1842: (void)time(&cgrp.cg_time); ! 1843: cgrp.cg_magic = CG_MAGIC; ! 1844: cgrp.cg_cgx = c; ! 1845: if (c == sblock.fs_ncg - 1) ! 1846: cgrp.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg; ! 1847: else ! 1848: cgrp.cg_ncyl = sblock.fs_cpg; ! 1849: cgrp.cg_niblk = sblock.fs_ipg; ! 1850: cgrp.cg_ndblk = dmax - dbase; ! 1851: cgrp.cg_cs.cs_ndir = 0; ! 1852: cgrp.cg_cs.cs_nffree = 0; ! 1853: cgrp.cg_cs.cs_nbfree = 0; ! 1854: cgrp.cg_cs.cs_nifree = 0; ! 1855: cgrp.cg_rotor = 0; ! 1856: cgrp.cg_frotor = 0; ! 1857: cgrp.cg_irotor = 0; ! 1858: for (i = 0; i < sblock.fs_frag; i++) ! 1859: cgrp.cg_frsum[i] = 0; ! 1860: inumber = sblock.fs_ipg * c; ! 1861: for (i = 0; i < sblock.fs_ipg; inumber++, i++) { ! 1862: cgrp.cg_cs.cs_nifree++; ! 1863: clrbit(cgrp.cg_iused, i); ! 1864: dp = ginode(inumber); ! 1865: if (dp == NULL) ! 1866: continue; ! 1867: if (ALLOC) { ! 1868: if (DIRCT) ! 1869: cgrp.cg_cs.cs_ndir++; ! 1870: cgrp.cg_cs.cs_nifree--; ! 1871: setbit(cgrp.cg_iused, i); ! 1872: continue; ! 1873: } ! 1874: } ! 1875: while (i < MAXIPG) { ! 1876: clrbit(cgrp.cg_iused, i); ! 1877: i++; ! 1878: } ! 1879: if (c == 0) ! 1880: for (i = 0; i < ROOTINO; i++) { ! 1881: setbit(cgrp.cg_iused, i); ! 1882: cgrp.cg_cs.cs_nifree--; ! 1883: } ! 1884: for (s = 0; s < MAXCPG; s++) { ! 1885: cgrp.cg_btot[s] = 0; ! 1886: for (i = 0; i < NRPOS; i++) ! 1887: cgrp.cg_b[s][i] = 0; ! 1888: } ! 1889: if (c == 0) { ! 1890: dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); ! 1891: } ! 1892: for (d = dlower; d < dupper; d++) ! 1893: clrbit(cgrp.cg_free, d); ! 1894: for (d = 0; (d + sblock.fs_frag) <= dmax - dbase; ! 1895: d += sblock.fs_frag) { ! 1896: j = 0; ! 1897: for (i = 0; i < sblock.fs_frag; i++) { ! 1898: if (!getbmap(dbase + d + i)) { ! 1899: setbit(cgrp.cg_free, d + i); ! 1900: j++; ! 1901: } else ! 1902: clrbit(cgrp.cg_free, d+i); ! 1903: } ! 1904: if (j == sblock.fs_frag) { ! 1905: cgrp.cg_cs.cs_nbfree++; ! 1906: cgrp.cg_btot[cbtocylno(&sblock, d)]++; ! 1907: cgrp.cg_b[cbtocylno(&sblock, d)] ! 1908: [cbtorpos(&sblock, d)]++; ! 1909: } else if (j > 0) { ! 1910: cgrp.cg_cs.cs_nffree += j; ! 1911: blk = blkmap(&sblock, cgrp.cg_free, d); ! 1912: fragacct(&sblock, blk, cgrp.cg_frsum, 1); ! 1913: } ! 1914: } ! 1915: for (j = d; d < dmax - dbase; d++) { ! 1916: if (!getbmap(dbase + d)) { ! 1917: setbit(cgrp.cg_free, d); ! 1918: cgrp.cg_cs.cs_nffree++; ! 1919: } else ! 1920: clrbit(cgrp.cg_free, d); ! 1921: } ! 1922: for (; d % sblock.fs_frag != 0; d++) ! 1923: clrbit(cgrp.cg_free, d); ! 1924: if (j != d) { ! 1925: blk = blkmap(&sblock, cgrp.cg_free, j); ! 1926: fragacct(&sblock, blk, cgrp.cg_frsum, 1); ! 1927: } ! 1928: for (d /= sblock.fs_frag; d < MAXBPG(&sblock); d ++) ! 1929: clrblock(&sblock, cgrp.cg_free, d); ! 1930: sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree; ! 1931: sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree; ! 1932: sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree; ! 1933: sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir; ! 1934: *cs = cgrp.cg_cs; ! 1935: (void)bwrite(&dfile, (char *)&cgrp, ! 1936: fsbtodb(&sblock, cgtod(&sblock, c)), sblock.fs_cgsize); ! 1937: } ! 1938: for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { ! 1939: (void)bwrite(&dfile, (char *)sblock.fs_csp[j], ! 1940: fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), ! 1941: sblock.fs_cssize - i < sblock.fs_bsize ? ! 1942: sblock.fs_cssize - i : sblock.fs_bsize); ! 1943: } ! 1944: sblock.fs_ronly = 0; ! 1945: sblock.fs_fmod = 0; ! 1946: sbdirty(); ! 1947: } ! 1948: ! 1949: findino(idesc) ! 1950: struct inodesc *idesc; ! 1951: { ! 1952: register DIRECT *dirp = idesc->id_dirp; ! 1953: ! 1954: if (dirp->d_ino == 0) ! 1955: return (KEEPON); ! 1956: if (!strcmp(dirp->d_name, srchname)) { ! 1957: if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax) ! 1958: idesc->id_parent = dirp->d_ino; ! 1959: return (STOP); ! 1960: } ! 1961: return (KEEPON); ! 1962: } ! 1963: ! 1964: mkentry(idesc) ! 1965: struct inodesc *idesc; ! 1966: { ! 1967: register DIRECT *dirp = idesc->id_dirp; ! 1968: DIRECT newent; ! 1969: int newlen, oldlen; ! 1970: ! 1971: newent.d_namlen = 11; ! 1972: newlen = DIRSIZ(&newent); ! 1973: if (dirp->d_ino != 0) ! 1974: oldlen = DIRSIZ(dirp); ! 1975: else ! 1976: oldlen = 0; ! 1977: if (dirp->d_reclen - oldlen < newlen) ! 1978: return (KEEPON); ! 1979: newent.d_reclen = dirp->d_reclen - oldlen; ! 1980: dirp->d_reclen = oldlen; ! 1981: dirp = (struct direct *)(((char *)dirp) + oldlen); ! 1982: dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */ ! 1983: dirp->d_reclen = newent.d_reclen; ! 1984: dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent); ! 1985: return (ALTERED|STOP); ! 1986: } ! 1987: ! 1988: chgdd(idesc) ! 1989: struct inodesc *idesc; ! 1990: { ! 1991: register DIRECT *dirp = idesc->id_dirp; ! 1992: ! 1993: if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' && ! 1994: dirp->d_name[2] == 0) { ! 1995: dirp->d_ino = lfdir; ! 1996: return (ALTERED|STOP); ! 1997: } ! 1998: return (KEEPON); ! 1999: } ! 2000: ! 2001: linkup(orphan, pdir) ! 2002: ino_t orphan; ! 2003: ino_t pdir; ! 2004: { ! 2005: register DINODE *dp; ! 2006: int lostdir, len; ! 2007: struct inodesc idesc; ! 2008: ! 2009: bzero((char *)&idesc, sizeof(struct inodesc)); ! 2010: if ((dp = ginode(orphan)) == NULL) ! 2011: return (0); ! 2012: lostdir = DIRCT; ! 2013: pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); ! 2014: pinode(orphan); ! 2015: if (preen && dp->di_size == 0) ! 2016: return (0); ! 2017: if (preen) ! 2018: printf(" (RECONNECTED)\n"); ! 2019: else ! 2020: if (reply("RECONNECT") == 0) ! 2021: return (0); ! 2022: pathp = pathname; ! 2023: *pathp++ = '/'; ! 2024: *pathp = '\0'; ! 2025: if (lfdir == 0) { ! 2026: if ((dp = ginode(ROOTINO)) == NULL) ! 2027: return (0); ! 2028: srchname = lfname; ! 2029: idesc.id_type = DATA; ! 2030: idesc.id_func = findino; ! 2031: idesc.id_number = ROOTINO; ! 2032: idesc.id_filesize = dp->di_size; ! 2033: (void)ckinode(dp, &idesc); ! 2034: if ((lfdir = idesc.id_parent) == 0) { ! 2035: pfatal("SORRY. NO lost+found DIRECTORY"); ! 2036: printf("\n\n"); ! 2037: return (0); ! 2038: } ! 2039: } ! 2040: if ((dp = ginode(lfdir)) == NULL || ! 2041: !DIRCT || statemap[lfdir] != FSTATE) { ! 2042: pfatal("SORRY. NO lost+found DIRECTORY"); ! 2043: printf("\n\n"); ! 2044: return (0); ! 2045: } ! 2046: if (fragoff(&sblock, dp->di_size)) { ! 2047: dp->di_size = fragroundup(&sblock, dp->di_size); ! 2048: inodirty(); ! 2049: } ! 2050: len = strlen(lfname); ! 2051: bcopy(lfname, pathp, len + 1); ! 2052: pathp += len; ! 2053: idesc.id_type = DATA; ! 2054: idesc.id_func = mkentry; ! 2055: idesc.id_number = lfdir; ! 2056: idesc.id_filesize = dp->di_size; ! 2057: idesc.id_parent = orphan; /* this is the inode to enter */ ! 2058: idesc.id_fix = DONTKNOW; ! 2059: if ((ckinode(dp, &idesc) & ALTERED) == 0) { ! 2060: pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); ! 2061: printf("\n\n"); ! 2062: return (0); ! 2063: } ! 2064: lncntp[orphan]--; ! 2065: *pathp++ = '/'; ! 2066: pathp += lftempname(pathp, orphan); ! 2067: if (lostdir) { ! 2068: dp = ginode(orphan); ! 2069: idesc.id_type = DATA; ! 2070: idesc.id_func = chgdd; ! 2071: idesc.id_number = orphan; ! 2072: idesc.id_filesize = dp->di_size; ! 2073: idesc.id_fix = DONTKNOW; ! 2074: (void)ckinode(dp, &idesc); ! 2075: if ((dp = ginode(lfdir)) != NULL) { ! 2076: dp->di_nlink++; ! 2077: inodirty(); ! 2078: lncntp[lfdir]++; ! 2079: } ! 2080: pwarn("DIR I=%u CONNECTED. ", orphan); ! 2081: printf("PARENT WAS I=%u\n", pdir); ! 2082: if (preen == 0) ! 2083: printf("\n"); ! 2084: } ! 2085: return (1); ! 2086: } ! 2087: ! 2088: /* ! 2089: * generate a temporary name for the lost+found directory. ! 2090: */ ! 2091: lftempname(bufp, ino) ! 2092: char *bufp; ! 2093: ino_t ino; ! 2094: { ! 2095: register ino_t in; ! 2096: register char *cp; ! 2097: int namlen; ! 2098: ! 2099: cp = bufp + 2; ! 2100: for (in = imax; in > 0; in /= 10) ! 2101: cp++; ! 2102: *--cp = 0; ! 2103: namlen = cp - bufp; ! 2104: in = ino; ! 2105: while (cp > bufp) { ! 2106: *--cp = (in % 10) + '0'; ! 2107: in /= 10; ! 2108: } ! 2109: *cp = '#'; ! 2110: return (namlen); ! 2111: } ! 2112: ! 2113: bread(fcp, buf, blk, size) ! 2114: register struct filecntl *fcp; ! 2115: char *buf; ! 2116: daddr_t blk; ! 2117: long size; ! 2118: { ! 2119: if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0) ! 2120: rwerr("SEEK", blk); ! 2121: else if (read(fcp->rfdes, buf, (int)size) == size) ! 2122: return (1); ! 2123: rwerr("READ", blk); ! 2124: return (0); ! 2125: } ! 2126: ! 2127: bwrite(fcp, buf, blk, size) ! 2128: register struct filecntl *fcp; ! 2129: char *buf; ! 2130: daddr_t blk; ! 2131: long size; ! 2132: { ! 2133: ! 2134: if (fcp->wfdes < 0) ! 2135: return (0); ! 2136: if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0) ! 2137: rwerr("SEEK", blk); ! 2138: else if (write(fcp->wfdes, buf, (int)size) == size) { ! 2139: fcp->mod = 1; ! 2140: return (1); ! 2141: } ! 2142: rwerr("WRITE", blk); ! 2143: return (0); ! 2144: } ! 2145: ! 2146: catch() ! 2147: { ! 2148: ! 2149: ckfini(); ! 2150: exit(12); ! 2151: } ! 2152: ! 2153: char * ! 2154: unrawname(cp) ! 2155: char *cp; ! 2156: { ! 2157: char *dp = rindex(cp, '/'); ! 2158: struct stat stb; ! 2159: ! 2160: if (dp == 0) ! 2161: return (cp); ! 2162: if (stat(cp, &stb) < 0) ! 2163: return (cp); ! 2164: if ((stb.st_mode&S_IFMT) != S_IFCHR) ! 2165: return (cp); ! 2166: if (*(dp+1) != 'r') ! 2167: return (cp); ! 2168: (void)strcpy(dp+1, dp+2); ! 2169: return (cp); ! 2170: } ! 2171: ! 2172: char * ! 2173: rawname(cp) ! 2174: char *cp; ! 2175: { ! 2176: static char rawbuf[32]; ! 2177: char *dp = rindex(cp, '/'); ! 2178: ! 2179: if (dp == 0) ! 2180: return (0); ! 2181: *dp = 0; ! 2182: (void)strcpy(rawbuf, cp); ! 2183: *dp = '/'; ! 2184: (void)strcat(rawbuf, "/r"); ! 2185: (void)strcat(rawbuf, dp+1); ! 2186: return (rawbuf); ! 2187: } ! 2188: ! 2189: /* ! 2190: * determine whether an inode should be fixed. ! 2191: */ ! 2192: dofix(idesc) ! 2193: register struct inodesc *idesc; ! 2194: { ! 2195: ! 2196: switch (idesc->id_fix) { ! 2197: ! 2198: case DONTKNOW: ! 2199: direrr(idesc->id_number, "DIRECTORY CORRUPTED"); ! 2200: if (reply("SALVAGE") == 0) { ! 2201: idesc->id_fix = NOFIX; ! 2202: return (0); ! 2203: } ! 2204: idesc->id_fix = FIX; ! 2205: return (ALTERED); ! 2206: ! 2207: case FIX: ! 2208: return (ALTERED); ! 2209: ! 2210: case NOFIX: ! 2211: return (0); ! 2212: ! 2213: default: ! 2214: errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); ! 2215: } ! 2216: /* NOTREACHED */ ! 2217: } ! 2218: ! 2219: /* VARARGS1 */ ! 2220: error(s1, s2, s3, s4) ! 2221: char *s1; ! 2222: { ! 2223: ! 2224: printf(s1, s2, s3, s4); ! 2225: } ! 2226: ! 2227: /* VARARGS1 */ ! 2228: errexit(s1, s2, s3, s4) ! 2229: char *s1; ! 2230: { ! 2231: error(s1, s2, s3, s4); ! 2232: exit(8); ! 2233: } ! 2234: ! 2235: /* ! 2236: * An inconsistency occured which shouldn't during normal operations. ! 2237: * Die if preening, otherwise just printf. ! 2238: */ ! 2239: /* VARARGS1 */ ! 2240: pfatal(s, a1, a2, a3) ! 2241: char *s; ! 2242: { ! 2243: ! 2244: if (preen) { ! 2245: printf("%s: ", devname); ! 2246: printf(s, a1, a2, a3); ! 2247: printf("\n"); ! 2248: preendie(); ! 2249: } ! 2250: printf(s, a1, a2, a3); ! 2251: } ! 2252: ! 2253: preendie() ! 2254: { ! 2255: ! 2256: printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname); ! 2257: exit(8); ! 2258: } ! 2259: ! 2260: /* ! 2261: * Pwarn is like printf when not preening, ! 2262: * or a warning (preceded by filename) when preening. ! 2263: */ ! 2264: /* VARARGS1 */ ! 2265: pwarn(s, a1, a2, a3, a4, a5, a6) ! 2266: char *s; ! 2267: { ! 2268: ! 2269: if (preen) ! 2270: printf("%s: ", devname); ! 2271: printf(s, a1, a2, a3, a4, a5, a6); ! 2272: } ! 2273: ! 2274: #ifndef lint ! 2275: /* ! 2276: * Stub for routines from kernel. ! 2277: */ ! 2278: panic(s) ! 2279: char *s; ! 2280: { ! 2281: ! 2282: pfatal("INTERNAL INCONSISTENCY: %s\n", s); ! 2283: exit(12); ! 2284: } ! 2285: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.