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