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