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