1 static char sccsid[] = "@(#)main.c 2.16 (Berkeley) 10/13/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 = unrawname(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 goto unknown; 590 ndb = howmany(dp->di_size, sblock.fs_bsize); 591 if (SPECIAL) 592 ndb++; 593 for (j = ndb; j < NDADDR; j++) 594 if (dp->di_db[j] != 0) 595 goto unknown; 596 for (j = 0, ndb -= NDADDR; ndb > 0; j++) 597 ndb /= NINDIR(&sblock); 598 for (; j < NIADDR; j++) 599 if (dp->di_ib[j] != 0) 600 goto unknown; 601 n_files++; 602 lncntp[inum] = dp->di_nlink; 603 if (dp->di_nlink <= 0) { 604 if (badlnp < &badlncnt[MAXLNCNT]) 605 *badlnp++ = inum; 606 else { 607 pfatal("LINK COUNT TABLE OVERFLOW"); 608 if (reply("CONTINUE") == 0) 609 errexit(""); 610 } 611 } 612 statemap[inum] = DIRCT ? DSTATE : FSTATE; 613 badblk = dupblk = 0; filsize = 0; maxblk = 0; 614 ckinode(dp, ADDR); 615 continue; 616 unknown: 617 pfatal("UNKNOWN FILE TYPE I=%u", inum); 618 if (reply("CLEAR") == 1) { 619 zapino(dp); 620 inodirty(); 621 inosumbad++; 622 } 623 } else { 624 if (isset(cgrp.cg_iused, i)) { 625 if (debug) 626 printf("%d bad, marked used\n", 627 inum); 628 inosumbad++; 629 n--; 630 } 631 partial = 0; 632 for (j = 0; j < NDADDR; j++) 633 if (dp->di_db[j] != 0) 634 partial++; 635 for (j = 0; j < NIADDR; j++) 636 if (dp->di_ib[j] != 0) 637 partial++; 638 if (partial || dp->di_mode != 0 || 639 dp->di_size != 0) { 640 pfatal("PARTIALLY ALLOCATED INODE I=%u", inum); 641 if (reply("CLEAR") == 1) { 642 zapino(dp); 643 inodirty(); 644 inosumbad++; 645 } 646 } 647 } 648 } 649 if (n != cgrp.cg_cs.cs_nifree) { 650 if (debug) 651 printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n", 652 c, cgrp.cg_cs.cs_nifree, n); 653 inosumbad++; 654 } 655 if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree 656 || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree 657 || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree 658 || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir) 659 sbsumbad++; 660 } 661 } 662 663 pass1check(blk, size) 664 daddr_t blk; 665 int size; 666 { 667 register daddr_t *dlp; 668 int res = KEEPON; 669 int anyout; 670 671 anyout = outrange(blk, size); 672 for (; size > 0; blk++, size--) { 673 if (anyout && outrange(blk, 1)) { 674 blkerr("BAD", blk); 675 if (++badblk >= MAXBAD) { 676 pwarn("EXCESSIVE BAD BLKS I=%u", inum); 677 if (preen) 678 printf(" (SKIPPING)\n"); 679 else if (reply("CONTINUE") == 0) 680 errexit(""); 681 return (STOP); 682 } 683 res = SKIP; 684 } else if (getbmap(blk)) { 685 blkerr("DUP", blk); 686 if (++dupblk >= MAXDUP) { 687 pwarn("EXCESSIVE DUP BLKS I=%u", inum); 688 if (preen) 689 printf(" (SKIPPING)\n"); 690 else if (reply("CONTINUE") == 0) 691 errexit(""); 692 return (STOP); 693 } 694 if (enddup >= &duplist[DUPTBLSIZE]) { 695 pfatal("DUP TABLE OVERFLOW."); 696 if (reply("CONTINUE") == 0) 697 errexit(""); 698 return (STOP); 699 } 700 for (dlp = duplist; dlp < muldup; dlp++) 701 if (*dlp == blk) { 702 *enddup++ = blk; 703 break; 704 } 705 if (dlp >= muldup) { 706 *enddup++ = *muldup; 707 *muldup++ = blk; 708 } 709 } else { 710 n_blks++; 711 setbmap(blk); 712 } 713 filsize++; 714 } 715 return (res); 716 } 717 718 pass1b() 719 { 720 register int c, i; 721 register DINODE *dp; 722 723 pfunc = pass1bcheck; 724 inum = 0; 725 for (c = 0; c < sblock.fs_ncg; c++) { 726 for (i = 0; i < sblock.fs_ipg; i++, inum++) { 727 dp = ginode(); 728 if (dp == NULL) 729 continue; 730 if (statemap[inum] != USTATE && 731 (ckinode(dp, ADDR) & STOP)) 732 goto out1b; 733 } 734 } 735 out1b: 736 flush(&dfile, &inoblk); 737 } 738 739 pass1bcheck(blk, size) 740 daddr_t blk; 741 int size; 742 { 743 register daddr_t *dlp; 744 int res = KEEPON; 745 746 for (; size > 0; blk++, size--) { 747 if (outrange(blk, 1)) 748 res = SKIP; 749 for (dlp = duplist; dlp < muldup; dlp++) 750 if (*dlp == blk) { 751 blkerr("DUP", blk); 752 *dlp = *--muldup; 753 *muldup = blk; 754 if (muldup == duplist) 755 return (STOP); 756 } 757 } 758 return (res); 759 } 760 761 pass2() 762 { 763 register DINODE *dp; 764 765 inum = ROOTINO; 766 thisname = pathp = pathname; 767 pfunc = pass2check; 768 switch (statemap[inum]) { 769 770 case USTATE: 771 errexit("ROOT INODE UNALLOCATED. TERMINATING.\n"); 772 773 case FSTATE: 774 pfatal("ROOT INODE NOT DIRECTORY"); 775 if (reply("FIX") == 0 || (dp = ginode()) == NULL) 776 errexit(""); 777 dp->di_mode &= ~IFMT; 778 dp->di_mode |= IFDIR; 779 inodirty(); 780 inosumbad++; 781 statemap[inum] = DSTATE; 782 /* fall into ... */ 783 784 case DSTATE: 785 descend(); 786 break; 787 788 case CLEAR: 789 pfatal("DUPS/BAD IN ROOT INODE"); 790 printf("\n"); 791 if (reply("CONTINUE") == 0) 792 errexit(""); 793 statemap[inum] = DSTATE; 794 descend(); 795 } 796 } 797 798 pass2check(dirp) 799 register DIRECT *dirp; 800 { 801 register char *p; 802 register n; 803 DINODE *dp; 804 805 if ((inum = dirp->d_ino) == 0) 806 return (KEEPON); 807 thisname = pathp; 808 for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; ) 809 if ((*pathp++ = *p++) == 0) { 810 --pathp; 811 break; 812 } 813 *pathp = 0; 814 n = 0; 815 if (inum > imax || inum <= 0) 816 n = direrr("I OUT OF RANGE"); 817 else { 818 again: 819 switch (statemap[inum]) { 820 case USTATE: 821 n = direrr("UNALLOCATED"); 822 break; 823 824 case CLEAR: 825 if ((n = direrr("DUP/BAD")) == 1) 826 break; 827 if ((dp = ginode()) == NULL) 828 break; 829 statemap[inum] = DIRCT ? DSTATE : FSTATE; 830 goto again; 831 832 case FSTATE: 833 lncntp[inum]--; 834 break; 835 836 case DSTATE: 837 lncntp[inum]--; 838 descend(); 839 break; 840 } 841 } 842 pathp = thisname; 843 if (n == 0) 844 return (KEEPON); 845 dirp->d_ino = 0; 846 return (KEEPON|ALTERD); 847 } 848 849 pass3() 850 { 851 ino_t savino; 852 register DINODE *dp; 853 854 for (inum = ROOTINO; inum <= lastino; inum++) { 855 if (statemap[inum] == DSTATE) { 856 pfunc = findino; 857 srchname = ".."; 858 savino = inum; 859 do { 860 orphan = inum; 861 if ((dp = ginode()) == NULL) 862 break; 863 filsize = dp->di_size; 864 parentdir = 0; 865 ckinode(dp, DATA); 866 if ((inum = parentdir) == 0) 867 break; 868 } while (statemap[inum] == DSTATE); 869 inum = orphan; 870 if (linkup() == 1) { 871 thisname = pathp = pathname; 872 *pathp++ = '?'; 873 pfunc = pass2check; 874 descend(); 875 } 876 inum = savino; 877 } 878 } 879 } 880 881 pass4() 882 { 883 register int n; 884 register ino_t *blp; 885 886 pfunc = pass4check; 887 for (inum = ROOTINO; inum <= lastino; inum++) { 888 switch (statemap[inum]) { 889 890 case FSTATE: 891 n = lncntp[inum]; 892 if (n) 893 adjust((short)n); 894 else { 895 for (blp = badlncnt;blp < badlnp; blp++) 896 if (*blp == inum) { 897 clri("UNREF", 1); 898 break; 899 } 900 } 901 break; 902 903 case DSTATE: 904 clri("UNREF", 1); 905 break; 906 907 case CLEAR: 908 clri("BAD/DUP", 1); 909 break; 910 } 911 } 912 if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) { 913 pwarn("FREE INODE COUNT WRONG IN SUPERBLK"); 914 if (preen) 915 printf(" (FIXED)\n"); 916 if (preen || reply("FIX") == 1) { 917 sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files; 918 sbdirty(); 919 } 920 } 921 flush(&dfile, &fileblk); 922 } 923 924 pass4check(blk, size) 925 daddr_t blk; 926 { 927 register daddr_t *dlp; 928 int res = KEEPON; 929 930 for (; size > 0; blk++, size--) { 931 if (outrange(blk, 1)) 932 res = SKIP; 933 else if (getbmap(blk)) { 934 for (dlp = duplist; dlp < enddup; dlp++) 935 if (*dlp == blk) { 936 *dlp = *--enddup; 937 return (KEEPON); 938 } 939 clrbmap(blk); 940 n_blks--; 941 } 942 } 943 return (res); 944 } 945 946 pass5() 947 { 948 register int c, n, i, b, d; 949 short bo[MAXCPG][NRPOS]; 950 long botot[MAXCPG]; 951 long frsum[MAXFRAG]; 952 int blk; 953 daddr_t cbase; 954 int blockbits = (1<<sblock.fs_frag)-1; 955 956 blkcpy((unsigned)bmapsz, blockmap, freemap); 957 dupblk = 0; 958 n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0)); 959 for (c = 0; c < sblock.fs_ncg; c++) { 960 cbase = cgbase(&sblock, c); 961 bzero(botot, sizeof (botot)); 962 bzero(bo, sizeof (bo)); 963 bzero(frsum, sizeof (frsum)); 964 /* 965 * need to account for the super blocks 966 * which appear (inaccurately) bad 967 */ 968 n_bad += cgtod(&sblock, c) - cgsblock(&sblock, c); 969 if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0) 970 continue; 971 if (cgrp.cg_magic != CG_MAGIC) { 972 pfatal("cg %d: bad magic number\n", c); 973 bzero((caddr_t)&cgrp, sblock.fs_cgsize); 974 } 975 for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) { 976 blk = blkmap(&sblock, cgrp.cg_free, b); 977 if (blk == 0) 978 continue; 979 if (blk == blockbits) { 980 if (pass5check(cbase+b, sblock.fs_frag) == STOP) 981 goto out5; 982 /* this is clumsy ... */ 983 n_ffree -= sblock.fs_frag; 984 n_bfree++; 985 botot[cbtocylno(&sblock, b)]++; 986 bo[cbtocylno(&sblock, b)] 987 [cbtorpos(&sblock, b)]++; 988 continue; 989 } 990 for (d = 0; d < sblock.fs_frag; d++) 991 if ((blk & (1<<d)) && 992 pass5check(cbase+b+d,1) == STOP) 993 goto out5; 994 fragacct(&sblock, blk, frsum, 1); 995 } 996 if (bcmp(cgrp.cg_frsum, frsum, sizeof (frsum))) { 997 if (debug) 998 for (i = 0; i < sblock.fs_frag; i++) 999 if (cgrp.cg_frsum[i] != frsum[i]) 1000 printf("cg[%d].cg_frsum[%d] have %d calc %d\n", 1001 c, i, cgrp.cg_frsum[i], frsum[i]); 1002 frsumbad++; 1003 } 1004 if (bcmp(cgrp.cg_btot, botot, sizeof (botot))) { 1005 if (debug) 1006 for (n = 0; n < sblock.fs_cpg; n++) 1007 if (botot[n] != cgrp.cg_btot[n]) 1008 printf("cg[%d].cg_btot[%d] have %d calc %d\n", 1009 c, n, cgrp.cg_btot[n], botot[n]); 1010 offsumbad++; 1011 } 1012 if (bcmp(cgrp.cg_b, bo, sizeof (bo))) { 1013 if (debug) 1014 for (i = 0; i < NRPOS; i++) 1015 if (bo[n][i] != cgrp.cg_b[n][i]) 1016 printf("cg[%d].cg_b[%d][%d] have %d calc %d\n", 1017 c, n, i, cgrp.cg_b[n][i], bo[n][i]); 1018 offsumbad++; 1019 } 1020 } 1021 out5: 1022 if (dupblk) 1023 pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk); 1024 if (fixcg == 0) { 1025 if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) { 1026 pwarn("%ld BLK(S) MISSING\n", fmax - b); 1027 fixcg = 1; 1028 } else if (inosumbad + offsumbad + frsumbad + sbsumbad) { 1029 pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n", 1030 inosumbad ? "(INODE FREE) " : "", 1031 offsumbad ? "(BLOCK OFFSETS) " : "", 1032 frsumbad ? "(FRAG SUMMARIES) " : "", 1033 sbsumbad ? "(SUPER BLOCK SUMMARIES) " : ""); 1034 fixcg = 1; 1035 } else if (n_ffree != sblock.fs_cstotal.cs_nffree || 1036 n_bfree != sblock.fs_cstotal.cs_nbfree) { 1037 pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK"); 1038 if (preen) 1039 printf(" (FIXED)\n"); 1040 if (preen || reply("FIX") == 1) { 1041 sblock.fs_cstotal.cs_nffree = n_ffree; 1042 sblock.fs_cstotal.cs_nbfree = n_bfree; 1043 sbdirty(); 1044 } 1045 } 1046 } 1047 if (fixcg) { 1048 pwarn("BAD CYLINDER GROUPS"); 1049 if (preen) 1050 printf(" (SALVAGED)\n"); 1051 else if (reply("SALVAGE") == 0) 1052 fixcg = 0; 1053 } 1054 } 1055 1056 pass5check(blk, size) 1057 daddr_t blk; 1058 int size; 1059 { 1060 1061 if (outrange(blk, size)) { 1062 fixcg = 1; 1063 if (preen) 1064 pfatal("BAD BLOCKS IN BIT MAPS."); 1065 if (++badblk >= MAXBAD) { 1066 printf("EXCESSIVE BAD BLKS IN BIT MAPS."); 1067 if (reply("CONTINUE") == 0) 1068 errexit(""); 1069 return (STOP); 1070 } 1071 } 1072 for (; size > 0; blk++, size--) 1073 if (getfmap(blk)) { 1074 fixcg = 1; 1075 ++dupblk; 1076 } else { 1077 n_ffree++; 1078 setfmap(blk); 1079 } 1080 return (KEEPON); 1081 } 1082 1083 ckinode(dp, flg) 1084 DINODE *dp; 1085 register flg; 1086 { 1087 register daddr_t *ap; 1088 register ret; 1089 int (*func)(), n, ndb, size, offset; 1090 ino_t number = inum; 1091 DINODE dino; 1092 1093 if (SPECIAL) 1094 return (KEEPON); 1095 dino = *dp; 1096 func = (flg == ADDR) ? pfunc : dirscan; 1097 ndb = howmany(dino.di_size, sblock.fs_bsize); 1098 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 1099 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 1100 size = numfrags(&sblock, fragroundup(&sblock, offset)); 1101 else 1102 size = sblock.fs_frag; 1103 dnum = number; 1104 if (*ap && (ret = (*func)(*ap, size)) & STOP) 1105 return (ret); 1106 } 1107 for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) { 1108 dnum = number; 1109 if (*ap) { 1110 ret = iblock(*ap, n, flg, 1111 dino.di_size - sblock.fs_bsize * NDADDR); 1112 if (ret & STOP) 1113 return (ret); 1114 } 1115 } 1116 return (KEEPON); 1117 } 1118 1119 iblock(blk, ilevel, flg, isize) 1120 daddr_t blk; 1121 register ilevel; 1122 int isize; 1123 { 1124 register daddr_t *ap; 1125 register daddr_t *aplim; 1126 register int i, n; 1127 int (*func)(), nif; 1128 BUFAREA ib; 1129 1130 if (flg == ADDR) { 1131 func = pfunc; 1132 if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0) 1133 return (n); 1134 } else 1135 func = dirscan; 1136 if (outrange(blk, sblock.fs_frag)) /* protect thyself */ 1137 return (SKIP); 1138 initbarea(&ib); 1139 if (getblk(&ib, blk, sblock.fs_bsize) == NULL) 1140 return (SKIP); 1141 ilevel--; 1142 if (ilevel == 0) { 1143 nif = lblkno(&sblock, isize) + 1; 1144 } else /* ilevel == 1 */ { 1145 nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1; 1146 } 1147 if (nif > NINDIR(&sblock)) 1148 nif = NINDIR(&sblock); 1149 aplim = &ib.b_un.b_indir[nif]; 1150 for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++) 1151 if (*ap) { 1152 if (ilevel > 0) 1153 n = iblock(*ap, ilevel, flg, 1154 isize - i*NINDIR(&sblock)*sblock.fs_bsize); 1155 else 1156 n = (*func)(*ap, sblock.fs_frag); 1157 if (n & STOP) 1158 return (n); 1159 } 1160 return (KEEPON); 1161 } 1162 1163 outrange(blk, cnt) 1164 daddr_t blk; 1165 int cnt; 1166 { 1167 register int c; 1168 1169 if ((unsigned)(blk+cnt) > fmax) 1170 return (1); 1171 c = dtog(&sblock, blk); 1172 if (blk < cgdmin(&sblock, c)) { 1173 if ((blk+cnt) > cgsblock(&sblock, c)) { 1174 if (debug) { 1175 printf("blk %d < cgdmin %d;", 1176 blk, cgdmin(&sblock, c)); 1177 printf(" blk+cnt %d > cgsbase %d\n", 1178 blk+cnt, cgsblock(&sblock, c)); 1179 } 1180 return (1); 1181 } 1182 } else { 1183 if ((blk+cnt) > cgbase(&sblock, c+1)) { 1184 if (debug) { 1185 printf("blk %d >= cgdmin %d;", 1186 blk, cgdmin(&sblock, c)); 1187 printf(" blk+cnt %d > sblock.fs_fpg %d\n", 1188 blk+cnt, sblock.fs_fpg); 1189 } 1190 return (1); 1191 } 1192 } 1193 return (0); 1194 } 1195 1196 blkerr(s, blk) 1197 daddr_t blk; 1198 char *s; 1199 { 1200 1201 pfatal("%ld %s I=%u", blk, s, inum); 1202 printf("\n"); 1203 statemap[inum] = CLEAR; 1204 } 1205 1206 descend() 1207 { 1208 register DINODE *dp; 1209 register char *savname; 1210 off_t savsize; 1211 1212 statemap[inum] = FSTATE; 1213 if ((dp = ginode()) == NULL) 1214 return; 1215 savname = thisname; 1216 *pathp++ = '/'; 1217 savsize = filsize; 1218 filsize = dp->di_size; 1219 ckinode(dp, DATA); 1220 thisname = savname; 1221 *--pathp = 0; 1222 filsize = savsize; 1223 } 1224 1225 struct dirstuff { 1226 int loc; 1227 int blkno; 1228 int blksiz; 1229 ino_t number; 1230 enum {DONTKNOW, NOFIX, FIX} fix; 1231 }; 1232 1233 dirscan(blk, nf) 1234 daddr_t blk; 1235 int nf; 1236 { 1237 register DIRECT *dp; 1238 struct dirstuff dirp; 1239 int blksiz, dsize, n; 1240 char dbuf[DIRBLKSIZ]; 1241 1242 if (outrange(blk, 1)) { 1243 filsize -= sblock.fs_bsize; 1244 return (SKIP); 1245 } 1246 blksiz = nf * sblock.fs_fsize; 1247 dirp.loc = 0; 1248 dirp.blkno = blk; 1249 dirp.blksiz = blksiz; 1250 if (dirp.number != dnum) { 1251 dirp.number = dnum; 1252 dirp.fix = DONTKNOW; 1253 } 1254 for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) { 1255 dsize = dp->d_reclen; 1256 bcopy(dp, dbuf, dsize); 1257 if ((n = (*pfunc)(dbuf)) & ALTERD) { 1258 if (getblk(&fileblk, blk, blksiz) != NULL) { 1259 bcopy(dbuf, dp, dsize); 1260 dirty(&fileblk); 1261 sbdirty(); 1262 } else 1263 n &= ~ALTERD; 1264 } 1265 if (n & STOP) 1266 return (n); 1267 } 1268 return (filsize > 0 ? KEEPON : STOP); 1269 } 1270 1271 /* 1272 * get next entry in a directory. 1273 */ 1274 DIRECT * 1275 readdir(dirp) 1276 register struct dirstuff *dirp; 1277 { 1278 register DIRECT *dp, *ndp; 1279 long size; 1280 1281 if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) { 1282 filsize -= dirp->blksiz - dirp->loc; 1283 return NULL; 1284 } 1285 while (dirp->loc % DIRBLKSIZ == 0 && filsize > 0 && 1286 dirp->loc < dirp->blksiz) { 1287 dp = (DIRECT *)(dirblk.b_buf + dirp->loc); 1288 if (dp->d_ino < imax && 1289 dp->d_namlen <= MAXNAMLEN && dp->d_namlen >= 0 && 1290 dp->d_reclen > 0 && dp->d_reclen <= DIRBLKSIZ) 1291 break; 1292 dirp->loc += DIRBLKSIZ; 1293 filsize -= DIRBLKSIZ; 1294 if (dirp->fix == DONTKNOW) { 1295 pwarn("DIRECTORY %D CORRUPTED", dirp->number); 1296 dirp->fix = NOFIX; 1297 if (preen) { 1298 printf(" (SALVAGED)\n"); 1299 dirp->fix = FIX; 1300 } else if (reply("SALVAGE") != 0) 1301 dirp->fix = FIX; 1302 } 1303 if (dirp->fix != FIX) 1304 continue; 1305 dp->d_reclen = DIRBLKSIZ; 1306 dp->d_ino = 0; 1307 dp->d_namlen = 0; 1308 dirty(&fileblk); 1309 } 1310 if (filsize <= 0 || dirp->loc >= dirp->blksiz) 1311 return NULL; 1312 dp = (DIRECT *)(dirblk.b_buf + dirp->loc); 1313 dirp->loc += dp->d_reclen; 1314 filsize -= dp->d_reclen; 1315 ndp = (DIRECT *)(dirblk.b_buf + dirp->loc); 1316 if ((filsize <= 0 && dirp->loc % DIRBLKSIZ != 0) || 1317 (dirp->loc < dirp->blksiz && filsize > 0 && 1318 (ndp->d_ino >= imax || 1319 ndp->d_namlen > MAXNAMLEN || ndp->d_namlen < 0 || 1320 ndp->d_reclen <= 0 || 1321 ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ)))) { 1322 size = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ); 1323 dirp->loc += size; 1324 filsize -= size; 1325 if (dirp->fix == DONTKNOW) { 1326 pwarn("DIRECTORY %D CORRUPTED", dirp->number); 1327 dirp->fix = NOFIX; 1328 if (preen) { 1329 printf(" (SALVAGED)\n"); 1330 dirp->fix = FIX; 1331 } else if (reply("SALVAGE") != 0) 1332 dirp->fix = FIX; 1333 } 1334 if (dirp->fix == FIX) { 1335 dp->d_reclen += size; 1336 dirty(&fileblk); 1337 } 1338 } 1339 return (dp); 1340 } 1341 1342 direrr(s) 1343 char *s; 1344 { 1345 register DINODE *dp; 1346 1347 pwarn("%s ", s); 1348 pinode(); 1349 printf("\n"); 1350 if ((dp = ginode()) != NULL && ftypeok(dp)) 1351 pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname); 1352 else 1353 pfatal("NAME=%s", pathname); 1354 return (reply("REMOVE")); 1355 } 1356 1357 adjust(lcnt) 1358 register short lcnt; 1359 { 1360 register DINODE *dp; 1361 1362 if ((dp = ginode()) == NULL) 1363 return; 1364 if (dp->di_nlink == lcnt) { 1365 if (linkup() == 0) 1366 clri("UNREF", 0); 1367 } 1368 else { 1369 pwarn("LINK COUNT %s", 1370 (lfdir==inum)?lfname:(DIRCT?"DIR":"FILE")); 1371 pinode(); 1372 printf(" COUNT %d SHOULD BE %d", 1373 dp->di_nlink, dp->di_nlink-lcnt); 1374 if (preen) { 1375 if (lcnt < 0) { 1376 printf("\n"); 1377 preendie(); 1378 } 1379 printf(" (ADJUSTED)\n"); 1380 } 1381 if (preen || reply("ADJUST") == 1) { 1382 dp->di_nlink -= lcnt; 1383 inodirty(); 1384 } 1385 } 1386 } 1387 1388 clri(s, flg) 1389 char *s; 1390 { 1391 register DINODE *dp; 1392 1393 if ((dp = ginode()) == NULL) 1394 return; 1395 if (flg == 1) { 1396 pwarn("%s %s", s, DIRCT?"DIR":"FILE"); 1397 pinode(); 1398 } 1399 if (preen || reply("CLEAR") == 1) { 1400 if (preen) 1401 printf(" (CLEARED)\n"); 1402 n_files--; 1403 pfunc = pass4check; 1404 ckinode(dp, ADDR); 1405 zapino(dp); 1406 statemap[inum] = USTATE; 1407 inodirty(); 1408 inosumbad++; 1409 } 1410 } 1411 1412 badsb(s) 1413 char *s; 1414 { 1415 1416 if (preen) 1417 printf("%s: ", devname); 1418 printf("BAD SUPER BLOCK: %s\n", s); 1419 pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n"); 1420 pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n"); 1421 } 1422 1423 DINODE * 1424 ginode() 1425 { 1426 daddr_t iblk; 1427 1428 if (inum < ROOTINO || inum > imax) { 1429 if (debug && (inum < 0 || inum > imax)) 1430 printf("inum out of range (%d)\n", inum); 1431 return (NULL); 1432 } 1433 if (inum < startinum || inum >= startinum + INOPB(&sblock)) { 1434 iblk = itod(&sblock, inum); 1435 if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) { 1436 return (NULL); 1437 } 1438 startinum = (inum / INOPB(&sblock)) * INOPB(&sblock); 1439 } 1440 return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]); 1441 } 1442 1443 ftypeok(dp) 1444 DINODE *dp; 1445 { 1446 switch (dp->di_mode & IFMT) { 1447 1448 case IFDIR: 1449 case IFREG: 1450 case IFBLK: 1451 case IFCHR: 1452 case IFLNK: 1453 return (1); 1454 1455 default: 1456 return (0); 1457 } 1458 } 1459 1460 reply(s) 1461 char *s; 1462 { 1463 char line[80]; 1464 1465 if (preen) 1466 pfatal("INTERNAL ERROR: GOT TO reply()"); 1467 rplyflag = 1; 1468 printf("\n%s? ", s); 1469 if (nflag || dfile.wfdes < 0) { 1470 printf(" no\n\n"); 1471 return (0); 1472 } 1473 if (yflag) { 1474 printf(" yes\n\n"); 1475 return (1); 1476 } 1477 if (getline(stdin, line, sizeof(line)) == EOF) 1478 errexit("\n"); 1479 printf("\n"); 1480 if (line[0] == 'y' || line[0] == 'Y') 1481 return (1); 1482 else 1483 return (0); 1484 } 1485 1486 getline(fp, loc, maxlen) 1487 FILE *fp; 1488 char *loc; 1489 { 1490 register n; 1491 register char *p, *lastloc; 1492 1493 p = loc; 1494 lastloc = &p[maxlen-1]; 1495 while ((n = getc(fp)) != '\n') { 1496 if (n == EOF) 1497 return (EOF); 1498 if (!isspace(n) && p < lastloc) 1499 *p++ = n; 1500 } 1501 *p = 0; 1502 return (p - loc); 1503 } 1504 1505 BUFAREA * 1506 getblk(bp, blk, size) 1507 daddr_t blk; 1508 register BUFAREA *bp; 1509 int size; 1510 { 1511 register struct filecntl *fcp; 1512 daddr_t dblk; 1513 1514 fcp = &dfile; 1515 dblk = fsbtodb(&sblock, blk); 1516 if (bp->b_bno == dblk) 1517 return (bp); 1518 flush(fcp, bp); 1519 if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) { 1520 bp->b_bno = dblk; 1521 bp->b_size = size; 1522 return (bp); 1523 } 1524 bp->b_bno = (daddr_t)-1; 1525 return (NULL); 1526 } 1527 1528 flush(fcp, bp) 1529 struct filecntl *fcp; 1530 register BUFAREA *bp; 1531 { 1532 1533 if (bp->b_dirty) 1534 bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size); 1535 bp->b_dirty = 0; 1536 } 1537 1538 rwerr(s, blk) 1539 char *s; 1540 daddr_t blk; 1541 { 1542 1543 if (preen == 0) 1544 printf("\n"); 1545 pfatal("CANNOT %s: BLK %ld", s, blk); 1546 if (reply("CONTINUE") == 0) 1547 errexit("Program terminated\n"); 1548 } 1549 1550 ckfini() 1551 { 1552 1553 flush(&dfile, &fileblk); 1554 flush(&dfile, &sblk); 1555 if (sblk.b_bno != SBLOCK) { 1556 sblk.b_bno = SBLOCK; 1557 sbdirty(); 1558 flush(&dfile, &sblk); 1559 } 1560 flush(&dfile, &inoblk); 1561 close(dfile.rfdes); 1562 close(dfile.wfdes); 1563 } 1564 1565 pinode() 1566 { 1567 register DINODE *dp; 1568 register char *p; 1569 char uidbuf[BUFSIZ]; 1570 char *ctime(); 1571 1572 printf(" I=%u ", inum); 1573 if ((dp = ginode()) == NULL) 1574 return; 1575 printf(" OWNER="); 1576 if (getpw((int)dp->di_uid, uidbuf) == 0) { 1577 for (p = uidbuf; *p != ':'; p++); 1578 *p = 0; 1579 printf("%s ", uidbuf); 1580 } 1581 else { 1582 printf("%d ", dp->di_uid); 1583 } 1584 printf("MODE=%o\n", dp->di_mode); 1585 if (preen) 1586 printf("%s: ", devname); 1587 printf("SIZE=%ld ", dp->di_size); 1588 p = ctime(&dp->di_mtime); 1589 printf("MTIME=%12.12s %4.4s ", p+4, p+20); 1590 } 1591 1592 makecg() 1593 { 1594 int c, blk; 1595 daddr_t dbase, d, dlower, dupper, dmax; 1596 long i, j, s; 1597 register struct csum *cs; 1598 register DINODE *dp; 1599 1600 sblock.fs_cstotal.cs_nbfree = 0; 1601 sblock.fs_cstotal.cs_nffree = 0; 1602 sblock.fs_cstotal.cs_nifree = 0; 1603 sblock.fs_cstotal.cs_ndir = 0; 1604 for (c = 0; c < sblock.fs_ncg; c++) { 1605 dbase = cgbase(&sblock, c); 1606 dmax = dbase + sblock.fs_fpg; 1607 if (dmax > sblock.fs_size) { 1608 for ( ; dmax >= sblock.fs_size; dmax--) 1609 clrbit(cgrp.cg_free, dmax - dbase); 1610 dmax++; 1611 } 1612 dlower = cgsblock(&sblock, c) - dbase; 1613 dupper = cgdmin(&sblock, c) - dbase; 1614 cs = &sblock.fs_cs(&sblock, c); 1615 cgrp.cg_time = time(0); 1616 cgrp.cg_magic = CG_MAGIC; 1617 cgrp.cg_cgx = c; 1618 cgrp.cg_ncyl = sblock.fs_cpg; 1619 cgrp.cg_niblk = sblock.fs_ipg; 1620 cgrp.cg_ndblk = dmax - dbase; 1621 cgrp.cg_cs.cs_ndir = 0; 1622 cgrp.cg_cs.cs_nffree = 0; 1623 cgrp.cg_cs.cs_nbfree = 0; 1624 cgrp.cg_cs.cs_nifree = 0; 1625 cgrp.cg_rotor = 0; 1626 cgrp.cg_frotor = 0; 1627 cgrp.cg_irotor = 0; 1628 for (i = 0; i < sblock.fs_frag; i++) 1629 cgrp.cg_frsum[i] = 0; 1630 inum = sblock.fs_ipg * c; 1631 for (i = 0; i < sblock.fs_ipg; inum++, i++) { 1632 cgrp.cg_cs.cs_nifree++; 1633 clrbit(cgrp.cg_iused, i); 1634 dp = ginode(); 1635 if (dp == NULL) 1636 continue; 1637 if (ALLOC) { 1638 if (DIRCT) 1639 cgrp.cg_cs.cs_ndir++; 1640 cgrp.cg_cs.cs_nifree--; 1641 setbit(cgrp.cg_iused, i); 1642 continue; 1643 } 1644 } 1645 while (i < MAXIPG) { 1646 clrbit(cgrp.cg_iused, i); 1647 i++; 1648 } 1649 if (c == 0) 1650 for (i = 0; i < ROOTINO; i++) { 1651 setbit(cgrp.cg_iused, i); 1652 cgrp.cg_cs.cs_nifree--; 1653 } 1654 for (s = 0; s < MAXCPG; s++) { 1655 cgrp.cg_btot[s] = 0; 1656 for (i = 0; i < NRPOS; i++) 1657 cgrp.cg_b[s][i] = 0; 1658 } 1659 if (c == 0) { 1660 dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 1661 } 1662 for (d = dlower; d < dupper; d++) 1663 clrbit(cgrp.cg_free, d); 1664 for (d = 0; (d + sblock.fs_frag) <= dmax - dbase; 1665 d += sblock.fs_frag) { 1666 j = 0; 1667 for (i = 0; i < sblock.fs_frag; i++) { 1668 if (!getbmap(dbase + d + i)) { 1669 setbit(cgrp.cg_free, d + i); 1670 j++; 1671 } else 1672 clrbit(cgrp.cg_free, d+i); 1673 } 1674 if (j == sblock.fs_frag) { 1675 cgrp.cg_cs.cs_nbfree++; 1676 cgrp.cg_btot[cbtocylno(&sblock, d)]++; 1677 cgrp.cg_b[cbtocylno(&sblock, d)] 1678 [cbtorpos(&sblock, d)]++; 1679 } else if (j > 0) { 1680 cgrp.cg_cs.cs_nffree += j; 1681 blk = blkmap(&sblock, cgrp.cg_free, d); 1682 fragacct(&sblock, blk, cgrp.cg_frsum, 1); 1683 } 1684 } 1685 for (j = d; d < dmax - dbase; d++) { 1686 if (!getbmap(dbase + d)) { 1687 setbit(cgrp.cg_free, d); 1688 cgrp.cg_cs.cs_nffree++; 1689 } else 1690 clrbit(cgrp.cg_free, d); 1691 } 1692 if (j != d) { 1693 blk = blkmap(&sblock, cgrp.cg_free, j); 1694 fragacct(&sblock, blk, cgrp.cg_frsum, 1); 1695 } 1696 for (; d < MAXBPG(&sblock); d++) 1697 clrbit(cgrp.cg_free, d); 1698 sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree; 1699 sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree; 1700 sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree; 1701 sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir; 1702 *cs = cgrp.cg_cs; 1703 bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)), 1704 sblock.fs_cgsize); 1705 } 1706 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 1707 bwrite(&dfile, (char *)sblock.fs_csp[j], 1708 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 1709 sblock.fs_cssize - i < sblock.fs_bsize ? 1710 sblock.fs_cssize - i : sblock.fs_bsize); 1711 } 1712 sblock.fs_ronly = 0; 1713 sblock.fs_fmod = 0; 1714 sbdirty(); 1715 } 1716 1717 findino(dirp) 1718 register DIRECT *dirp; 1719 { 1720 if (dirp->d_ino == 0) 1721 return (KEEPON); 1722 if (!strcmp(dirp->d_name, srchname)) { 1723 if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax) 1724 parentdir = dirp->d_ino; 1725 return (STOP); 1726 } 1727 return (KEEPON); 1728 } 1729 1730 mkentry(dirp) 1731 register DIRECT *dirp; 1732 { 1733 register ino_t in; 1734 register char *p; 1735 DIRECT newent; 1736 int newlen, oldlen; 1737 1738 newent.d_namlen = 11; 1739 newlen = DIRSIZ(&newent); 1740 if (dirp->d_ino != 0) 1741 oldlen = DIRSIZ(dirp); 1742 else 1743 oldlen = 0; 1744 if (dirp->d_reclen - oldlen < newlen) 1745 return (KEEPON); 1746 newent.d_reclen = dirp->d_reclen - oldlen; 1747 dirp->d_reclen = oldlen; 1748 dirp = (struct direct *)(((char *)dirp) + oldlen); 1749 dirp->d_ino = orphan; 1750 dirp->d_reclen = newent.d_reclen; 1751 p = &dirp->d_name[2]; 1752 for (in = imax; in > 0; in /= 10) 1753 p++; 1754 *--p = 0; 1755 dirp->d_namlen = p - dirp->d_name; 1756 in = orphan; 1757 while (p > dirp->d_name) { 1758 *--p = (in % 10) + '0'; 1759 in /= 10; 1760 } 1761 *p = '#'; 1762 return (ALTERD|STOP); 1763 } 1764 1765 chgdd(dirp) 1766 register DIRECT *dirp; 1767 { 1768 if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' && 1769 dirp->d_name[2] == 0) { 1770 dirp->d_ino = lfdir; 1771 return (ALTERD|STOP); 1772 } 1773 return (KEEPON); 1774 } 1775 1776 linkup() 1777 { 1778 register DINODE *dp; 1779 register lostdir; 1780 register ino_t pdir; 1781 1782 if ((dp = ginode()) == NULL) 1783 return (0); 1784 lostdir = DIRCT; 1785 pdir = parentdir; 1786 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 1787 pinode(); 1788 if (preen && dp->di_size == 0) 1789 return (0); 1790 if (preen) 1791 printf(" (RECONNECTED)\n"); 1792 else 1793 if (reply("RECONNECT") == 0) 1794 return (0); 1795 orphan = inum; 1796 if (lfdir == 0) { 1797 inum = ROOTINO; 1798 if ((dp = ginode()) == NULL) { 1799 inum = orphan; 1800 return (0); 1801 } 1802 pfunc = findino; 1803 srchname = lfname; 1804 filsize = dp->di_size; 1805 parentdir = 0; 1806 ckinode(dp, DATA); 1807 inum = orphan; 1808 if ((lfdir = parentdir) == 0) { 1809 pfatal("SORRY. NO lost+found DIRECTORY"); 1810 printf("\n\n"); 1811 return (0); 1812 } 1813 } 1814 inum = lfdir; 1815 if ((dp = ginode()) == NULL || !DIRCT || statemap[inum] != FSTATE) { 1816 inum = orphan; 1817 pfatal("SORRY. NO lost+found DIRECTORY"); 1818 printf("\n\n"); 1819 return (0); 1820 } 1821 if (fragoff(&sblock, dp->di_size)) { 1822 dp->di_size = fragroundup(&sblock, dp->di_size); 1823 inodirty(); 1824 } 1825 filsize = dp->di_size; 1826 inum = orphan; 1827 pfunc = mkentry; 1828 if ((ckinode(dp, DATA) & ALTERD) == 0) { 1829 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 1830 printf("\n\n"); 1831 return (0); 1832 } 1833 lncntp[inum]--; 1834 if (lostdir) { 1835 pfunc = chgdd; 1836 dp = ginode(); 1837 filsize = dp->di_size; 1838 ckinode(dp, DATA); 1839 inum = lfdir; 1840 if ((dp = ginode()) != NULL) { 1841 dp->di_nlink++; 1842 inodirty(); 1843 lncntp[inum]++; 1844 } 1845 inum = orphan; 1846 pwarn("DIR I=%u CONNECTED. ", orphan); 1847 printf("PARENT WAS I=%u\n", pdir); 1848 if (preen == 0) 1849 printf("\n"); 1850 } 1851 return (1); 1852 } 1853 1854 bread(fcp, buf, blk, size) 1855 daddr_t blk; 1856 register struct filecntl *fcp; 1857 register size; 1858 char *buf; 1859 { 1860 if (lseek(fcp->rfdes, blk * DEV_BSIZE, 0) < 0) 1861 rwerr("SEEK", blk); 1862 else if (read(fcp->rfdes, buf, size) == size) 1863 return (1); 1864 rwerr("READ", blk); 1865 return (0); 1866 } 1867 1868 bwrite(fcp, buf, blk, size) 1869 daddr_t blk; 1870 register struct filecntl *fcp; 1871 register size; 1872 char *buf; 1873 { 1874 1875 if (fcp->wfdes < 0) 1876 return (0); 1877 if (lseek(fcp->wfdes, blk * DEV_BSIZE, 0) < 0) 1878 rwerr("SEEK", blk); 1879 else if (write(fcp->wfdes, buf, size) == size) { 1880 fcp->mod = 1; 1881 return (1); 1882 } 1883 rwerr("WRITE", blk); 1884 return (0); 1885 } 1886 1887 catch() 1888 { 1889 1890 ckfini(); 1891 exit(12); 1892 } 1893 1894 char * 1895 unrawname(cp) 1896 char *cp; 1897 { 1898 char *dp = rindex(cp, '/'); 1899 struct stat stb; 1900 1901 if (dp == 0) 1902 return (cp); 1903 if (stat(cp, &stb) < 0) 1904 return (cp); 1905 if ((stb.st_mode&S_IFMT) != S_IFCHR) 1906 return (cp); 1907 if (*(dp+1) != 'r') 1908 return (cp); 1909 strcpy(dp+1, dp+2); 1910 return (cp); 1911 } 1912 1913 char * 1914 rawname(cp) 1915 char *cp; 1916 { 1917 static char rawbuf[32]; 1918 char *dp = rindex(cp, '/'); 1919 1920 if (dp == 0) 1921 return (0); 1922 *dp = 0; 1923 strcpy(rawbuf, cp); 1924 *dp = '/'; 1925 strcat(rawbuf, "/r"); 1926 strcat(rawbuf, dp+1); 1927 return (rawbuf); 1928 } 1929 1930 /* VARARGS1 */ 1931 error(s1, s2, s3, s4) 1932 char *s1; 1933 { 1934 1935 printf(s1, s2, s3, s4); 1936 } 1937 1938 /* VARARGS1 */ 1939 errexit(s1, s2, s3, s4) 1940 char *s1; 1941 { 1942 error(s1, s2, s3, s4); 1943 exit(8); 1944 } 1945 1946 /* 1947 * An inconsistency occured which shouldn't during normal operations. 1948 * Die if preening, otw just printf. 1949 */ 1950 /* VARARGS1 */ 1951 pfatal(s, a1, a2, a3) 1952 char *s; 1953 { 1954 1955 if (preen) { 1956 printf("%s: ", devname); 1957 printf(s, a1, a2, a3); 1958 printf("\n"); 1959 preendie(); 1960 } 1961 printf(s, a1, a2, a3); 1962 } 1963 1964 preendie() 1965 { 1966 1967 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname); 1968 exit(8); 1969 } 1970 1971 /* 1972 * Pwarn is like printf when not preening, 1973 * or a warning (preceded by filename) when preening. 1974 */ 1975 /* VARARGS1 */ 1976 pwarn(s, a1, a2, a3, a4, a5, a6) 1977 char *s; 1978 { 1979 1980 if (preen) 1981 printf("%s: ", devname); 1982 printf(s, a1, a2, a3, a4, a5, a6); 1983 } 1984 1985 panic(s) 1986 char *s; 1987 { 1988 1989 pfatal("internal inconsistency: %s\n"); 1990 exit(12); 1991 } 1992