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