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