1 static char *sccsid = "@(#)main.c 1.26 (Berkeley) 03/17/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 struct dirstuff dirp; 1055 int blksiz, dsize, n; 1056 char dbuf[DIRBLKSIZ]; 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 dsize = dp->d_reclen; 1068 copy(dp, dbuf, dsize); 1069 if ((n = (*pfunc)(dbuf)) & ALTERD) { 1070 if (getblk(&fileblk, blk, blksiz) != NULL) { 1071 copy(dbuf, dp, dsize); 1072 dirty(&fileblk); 1073 sbdirty(); 1074 } else 1075 n &= ~ALTERD; 1076 } 1077 if (n & STOP) 1078 return (n); 1079 } 1080 return (filsize > 0 ? KEEPON : STOP); 1081 } 1082 1083 /* 1084 * get next entry in a directory. 1085 */ 1086 DIRECT * 1087 readdir(dirp) 1088 register struct dirstuff *dirp; 1089 { 1090 register DIRECT *dp, *ndp; 1091 1092 if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) { 1093 filsize -= dirp->blksiz - dirp->loc; 1094 return NULL; 1095 } 1096 for (;;) { 1097 if (filsize <= 0 || dirp->loc >= dirp->blksiz) 1098 return NULL; 1099 dp = (DIRECT *)(dirblk.b_buf + dirp->loc); 1100 dirp->loc += dp->d_reclen; 1101 filsize -= dp->d_reclen; 1102 ndp = (DIRECT *)(dirblk.b_buf + dirp->loc); 1103 if (dirp->loc < dirp->blksiz && 1104 (ndp->d_ino > imax || ndp->d_namlen > MAXNAMLEN || 1105 ndp->d_reclen <= 0 || 1106 ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ))) { 1107 pwarn("DIRECTORY CORRUPTED"); 1108 if (preen) 1109 printf(" (SALVAGED)\n"); 1110 else if (reply("SALVAGE") == 0) { 1111 dirp->loc += 1112 DIRBLKSIZ - (dirp->loc % DIRBLKSIZ); 1113 filsize -= DIRBLKSIZ - (dirp->loc % DIRBLKSIZ); 1114 return(dp); 1115 } 1116 dirp->loc -= dp->d_reclen; 1117 filsize += dp->d_reclen; 1118 dp->d_reclen = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ); 1119 dirty(&fileblk); 1120 continue; 1121 } 1122 return (dp); 1123 } 1124 } 1125 1126 direrr(s) 1127 char *s; 1128 { 1129 register DINODE *dp; 1130 1131 pwarn("%s ", s); 1132 pinode(); 1133 printf("\n"); 1134 if ((dp = ginode()) != NULL && ftypeok(dp)) 1135 pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname); 1136 else 1137 pfatal("NAME=%s", pathname); 1138 return (reply("REMOVE")); 1139 } 1140 1141 adjust(lcnt) 1142 register short lcnt; 1143 { 1144 register DINODE *dp; 1145 1146 if ((dp = ginode()) == NULL) 1147 return; 1148 if (dp->di_nlink == lcnt) { 1149 if (linkup() == 0) 1150 clri("UNREF", 0); 1151 } 1152 else { 1153 pwarn("LINK COUNT %s", 1154 (lfdir==inum)?lfname:(DIRCT?"DIR":"FILE")); 1155 pinode(); 1156 printf(" COUNT %d SHOULD BE %d", 1157 dp->di_nlink, dp->di_nlink-lcnt); 1158 if (preen) { 1159 if (lcnt < 0) { 1160 printf("\n"); 1161 preendie(); 1162 } 1163 printf(" (ADJUSTED)\n"); 1164 } 1165 if (preen || reply("ADJUST") == 1) { 1166 dp->di_nlink -= lcnt; 1167 inodirty(); 1168 } 1169 } 1170 } 1171 1172 clri(s, flg) 1173 char *s; 1174 { 1175 register DINODE *dp; 1176 1177 if ((dp = ginode()) == NULL) 1178 return; 1179 if (flg == 1) { 1180 pwarn("%s %s", s, DIRCT?"DIR":"FILE"); 1181 pinode(); 1182 } 1183 if (preen || reply("CLEAR") == 1) { 1184 if (preen) 1185 printf(" (CLEARED)\n"); 1186 n_files--; 1187 pfunc = pass4; 1188 ckinode(dp, ADDR); 1189 zapino(dp); 1190 setstate(USTATE); 1191 inodirty(); 1192 inosumbad++; 1193 } 1194 } 1195 1196 setup(dev) 1197 char *dev; 1198 { 1199 dev_t rootdev; 1200 struct ostat statb; 1201 int super = bflag ? bflag : SBLOCK; 1202 1203 bflag = 0; 1204 if (stat("/", &statb) < 0) 1205 errexit("Can't stat root\n"); 1206 rootdev = statb.st_dev; 1207 if (stat(dev, &statb) < 0) { 1208 error("Can't stat %s\n", dev); 1209 return (0); 1210 } 1211 rawflg = 0; 1212 if ((statb.st_mode & S_IFMT) == S_IFBLK) 1213 ; 1214 else if ((statb.st_mode & S_IFMT) == S_IFCHR) 1215 rawflg++; 1216 else { 1217 if (reply("file is not a block or character device; OK") == 0) 1218 return (0); 1219 } 1220 if (rootdev == statb.st_rdev) 1221 hotroot++; 1222 if ((dfile.rfdes = open(dev, 0)) < 0) { 1223 error("Can't open %s\n", dev); 1224 return (0); 1225 } 1226 if (preen == 0) 1227 printf("** %s", dev); 1228 if (nflag || (dfile.wfdes = open(dev, 1)) < 0) { 1229 dfile.wfdes = -1; 1230 if (preen) 1231 pfatal("NO WRITE ACCESS"); 1232 printf(" (NO WRITE)"); 1233 } 1234 if (preen == 0) 1235 printf("\n"); 1236 fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; 1237 dfile.mod = 0; 1238 n_files = n_blks = n_ffree = n_bfree = 0; 1239 muldup = enddup = &duplist[0]; 1240 badlnp = &badlncnt[0]; 1241 lfdir = 0; 1242 rplyflag = 0; 1243 initbarea(&sblk); 1244 initbarea(&fileblk); 1245 initbarea(&inoblk); 1246 initbarea(&cgblk); 1247 if (bread(&dfile, &sblock, super, SBSIZE) == 0) 1248 return (0); 1249 sblk.b_bno = super; 1250 sblk.b_size = SBSIZE; 1251 /* 1252 * run a few consistency checks of the super block 1253 */ 1254 if (sblock.fs_magic != FS_MAGIC) 1255 { badsb("MAGIC NUMBER WRONG"); return (0); } 1256 if (sblock.fs_ncg < 1) 1257 { badsb("NCG OUT OF RANGE"); return (0); } 1258 if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) 1259 { badsb("CPG OUT OF RANGE"); return (0); } 1260 if (sblock.fs_nsect < 1) 1261 { badsb("NSECT < 1"); return (0); } 1262 if (sblock.fs_ntrak < 1) 1263 { badsb("NTRAK < 1"); return (0); } 1264 if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak) 1265 { badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); } 1266 if (sblock.fs_ipg % INOPB(&sblock)) 1267 { badsb("INODES NOT MULTIPLE OF A BLOCK"); return (0); } 1268 if (cgdmin(&sblock, 0) >= sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock)) 1269 { badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); return (0); } 1270 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl || 1271 (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) 1272 { badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); } 1273 if (sblock.fs_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock)) 1274 { badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); } 1275 if (sblock.fs_size * NSPF(&sblock) <= 1276 (sblock.fs_ncyl - 1) * sblock.fs_spc) 1277 { badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); } 1278 if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) 1279 { badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); } 1280 /* rest we COULD repair... */ 1281 if (sblock.fs_sblkno != SBLOCK) 1282 { badsb("SBLKNO CORRUPTED"); return (0); } 1283 if (sblock.fs_cblkno != 1284 roundup(howmany(BBSIZE + SBSIZE, sblock.fs_fsize), sblock.fs_frag)) 1285 { badsb("CBLKNO CORRUPTED"); return (0); } 1286 if (sblock.fs_iblkno != sblock.fs_cblkno + sblock.fs_frag) 1287 { badsb("IBLKNO CORRUPTED"); return (0); } 1288 if (sblock.fs_dblkno != 1289 sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock)) 1290 { badsb("DBLKNO CORRUPTED"); return (0); } 1291 if (sblock.fs_cgsize != fragroundup(&sblock, 1292 sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY))) 1293 { badsb("CGSIZE INCORRECT"); return (0); } 1294 if (sblock.fs_cssize != sblock.fs_ncg * sizeof(struct csum)) 1295 { badsb("CSSIZE INCORRECT"); return (0); } 1296 fmax = sblock.fs_size; 1297 imax = sblock.fs_ncg * sblock.fs_ipg; 1298 /* 1299 * allocate the necessary maps 1300 */ 1301 bmapsz = roundup(howmany(fmax, NBBY), sizeof(short)); 1302 blkmap = (char *)calloc(bmapsz, sizeof (char)); 1303 freemap = (char *)calloc(bmapsz, sizeof (char)); 1304 statemap = (char *)calloc(imax+1, sizeof(char)); 1305 lncntp = (short *)calloc(imax+1, sizeof(short)); 1306 1307 startinum = imax + 1; 1308 return (1); 1309 1310 badsb: 1311 ckfini(); 1312 return (0); 1313 } 1314 1315 badsb(s) 1316 char *s; 1317 { 1318 1319 if (preen) 1320 printf("%s: ", devname); 1321 printf("BAD SUPER BLOCK: %s\n", s); 1322 pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n"); 1323 pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n"); 1324 } 1325 1326 DINODE * 1327 ginode() 1328 { 1329 daddr_t iblk; 1330 1331 if (inum < ROOTINO || inum > imax) 1332 return (NULL); 1333 if (inum < startinum || inum >= startinum + INOPB(&sblock)) { 1334 iblk = itod(&sblock, inum); 1335 if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) { 1336 return (NULL); 1337 } 1338 startinum = (inum / INOPB(&sblock)) * INOPB(&sblock); 1339 } 1340 return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]); 1341 } 1342 1343 ftypeok(dp) 1344 DINODE *dp; 1345 { 1346 switch (dp->di_mode & IFMT) { 1347 1348 case IFDIR: 1349 case IFREG: 1350 case IFBLK: 1351 case IFCHR: 1352 case IFMPC: 1353 case IFMPB: 1354 return (1); 1355 1356 default: 1357 return (0); 1358 } 1359 } 1360 1361 reply(s) 1362 char *s; 1363 { 1364 char line[80]; 1365 1366 if (preen) 1367 pfatal("INTERNAL ERROR: GOT TO reply()"); 1368 rplyflag = 1; 1369 printf("\n%s? ", s); 1370 if (nflag || dfile.wfdes < 0) { 1371 printf(" no\n\n"); 1372 return (0); 1373 } 1374 if (yflag) { 1375 printf(" yes\n\n"); 1376 return (1); 1377 } 1378 if (getline(stdin, line, sizeof(line)) == EOF) 1379 errexit("\n"); 1380 printf("\n"); 1381 if (line[0] == 'y' || line[0] == 'Y') 1382 return (1); 1383 else 1384 return (0); 1385 } 1386 1387 getline(fp, loc, maxlen) 1388 FILE *fp; 1389 char *loc; 1390 { 1391 register n; 1392 register char *p, *lastloc; 1393 1394 p = loc; 1395 lastloc = &p[maxlen-1]; 1396 while ((n = getc(fp)) != '\n') { 1397 if (n == EOF) 1398 return (EOF); 1399 if (!isspace(n) && p < lastloc) 1400 *p++ = n; 1401 } 1402 *p = 0; 1403 return (p - loc); 1404 } 1405 1406 BUFAREA * 1407 getblk(bp, blk, size) 1408 daddr_t blk; 1409 register BUFAREA *bp; 1410 int size; 1411 { 1412 register struct filecntl *fcp; 1413 daddr_t dblk; 1414 1415 fcp = &dfile; 1416 dblk = fsbtodb(&sblock, blk); 1417 if (bp->b_bno == dblk) 1418 return (bp); 1419 flush(fcp, bp); 1420 if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) { 1421 bp->b_bno = dblk; 1422 bp->b_size = size; 1423 return (bp); 1424 } 1425 bp->b_bno = (daddr_t)-1; 1426 return (NULL); 1427 } 1428 1429 flush(fcp, bp) 1430 struct filecntl *fcp; 1431 register BUFAREA *bp; 1432 { 1433 1434 if (bp->b_dirty) 1435 bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size); 1436 bp->b_dirty = 0; 1437 } 1438 1439 rwerr(s, blk) 1440 char *s; 1441 daddr_t blk; 1442 { 1443 1444 if (preen == 0) 1445 printf("\n"); 1446 pfatal("CANNOT %s: BLK %ld", s, blk); 1447 if (reply("CONTINUE") == 0) 1448 errexit("Program terminated\n"); 1449 } 1450 1451 ckfini() 1452 { 1453 1454 flush(&dfile, &fileblk); 1455 flush(&dfile, &sblk); 1456 if (sblk.b_bno != SBLOCK) { 1457 sblk.b_bno = SBLOCK; 1458 sbdirty(); 1459 flush(&dfile, &sblk); 1460 } 1461 flush(&dfile, &inoblk); 1462 close(dfile.rfdes); 1463 close(dfile.wfdes); 1464 } 1465 1466 pinode() 1467 { 1468 register DINODE *dp; 1469 register char *p; 1470 char uidbuf[BUFSIZ]; 1471 char *ctime(); 1472 1473 printf(" I=%u ", inum); 1474 if ((dp = ginode()) == NULL) 1475 return; 1476 printf(" OWNER="); 1477 if (getpw((int)dp->di_uid, uidbuf) == 0) { 1478 for (p = uidbuf; *p != ':'; p++); 1479 *p = 0; 1480 printf("%s ", uidbuf); 1481 } 1482 else { 1483 printf("%d ", dp->di_uid); 1484 } 1485 printf("MODE=%o\n", dp->di_mode); 1486 if (preen) 1487 printf("%s: ", devname); 1488 printf("SIZE=%ld ", dp->di_size); 1489 p = ctime(&dp->di_mtime); 1490 printf("MTIME=%12.12s %4.4s ", p+4, p+20); 1491 } 1492 1493 copy(fp, tp, size) 1494 register char *tp, *fp; 1495 unsigned size; 1496 { 1497 1498 while (size--) 1499 *tp++ = *fp++; 1500 } 1501 1502 makecg() 1503 { 1504 int c, blk; 1505 daddr_t dbase, d, dmin, dmax; 1506 long i, j, s; 1507 register struct csum *cs; 1508 register DINODE *dp; 1509 1510 sblock.fs_cstotal.cs_nbfree = 0; 1511 sblock.fs_cstotal.cs_nffree = 0; 1512 sblock.fs_cstotal.cs_nifree = 0; 1513 sblock.fs_cstotal.cs_ndir = 0; 1514 for (i = 0; i < howmany(sblock.fs_cssize, sblock.fs_bsize); i++) { 1515 sblock.fs_csp[i] = (struct csum *)calloc(1, sblock.fs_bsize); 1516 getblk((char *)sblock.fs_csp[i], 1517 sblock.fs_csaddr + (i * sblock.fs_frag), sblock.fs_bsize); 1518 } 1519 for (c = 0; c < sblock.fs_ncg; c++) { 1520 dbase = cgbase(&sblock, c); 1521 dmax = dbase + sblock.fs_fpg; 1522 if (dmax > sblock.fs_size) { 1523 for ( ; dmax >= sblock.fs_size; dmax--) 1524 clrbit(cgrp.cg_free, dmax - dbase); 1525 dmax++; 1526 } 1527 dmin = sblock.fs_dblkno; 1528 cs = &sblock.fs_cs(&sblock, c); 1529 cgrp.cg_time = time(0); 1530 cgrp.cg_magic = CG_MAGIC; 1531 cgrp.cg_cgx = c; 1532 cgrp.cg_ncyl = sblock.fs_cpg; 1533 cgrp.cg_niblk = sblock.fs_ipg; 1534 cgrp.cg_ndblk = dmax - dbase; 1535 cgrp.cg_cs.cs_ndir = 0; 1536 cgrp.cg_cs.cs_nffree = 0; 1537 cgrp.cg_cs.cs_nbfree = 0; 1538 cgrp.cg_cs.cs_nifree = 0; 1539 cgrp.cg_rotor = dmin; 1540 cgrp.cg_frotor = dmin; 1541 cgrp.cg_irotor = 0; 1542 for (i = 0; i < sblock.fs_frag; i++) 1543 cgrp.cg_frsum[i] = 0; 1544 inum = sblock.fs_ipg * c; 1545 for (i = 0; i < sblock.fs_ipg; inum++, i++) { 1546 cgrp.cg_cs.cs_nifree++; 1547 clrbit(cgrp.cg_iused, i); 1548 dp = ginode(); 1549 if (dp == NULL) 1550 continue; 1551 if (ALLOC) { 1552 if (DIRCT) 1553 cgrp.cg_cs.cs_ndir++; 1554 cgrp.cg_cs.cs_nifree--; 1555 setbit(cgrp.cg_iused, i); 1556 continue; 1557 } 1558 } 1559 while (i < MAXIPG) { 1560 clrbit(cgrp.cg_iused, i); 1561 i++; 1562 } 1563 if (c == 0) 1564 for (i = 0; i < ROOTINO; i++) { 1565 setbit(cgrp.cg_iused, i); 1566 cgrp.cg_cs.cs_nifree--; 1567 } 1568 for (s = 0; s < MAXCPG; s++) { 1569 cgrp.cg_btot[s] = 0; 1570 for (i = 0; i < NRPOS; i++) 1571 cgrp.cg_b[s][i] = 0; 1572 } 1573 if (c == 0) { 1574 dmin += howmany(sblock.fs_cssize, sblock.fs_bsize) * 1575 sblock.fs_frag; 1576 } 1577 for (d = 0; d < dmin; d++) 1578 clrbit(cgrp.cg_free, d); 1579 for (; (d + sblock.fs_frag) <= dmax - dbase; d += sblock.fs_frag) { 1580 j = 0; 1581 for (i = 0; i < sblock.fs_frag; i++) { 1582 if (!getbmap(dbase+d+i)) { 1583 setbit(cgrp.cg_free, d+i); 1584 j++; 1585 } else 1586 clrbit(cgrp.cg_free, d+i); 1587 } 1588 if (j == sblock.fs_frag) { 1589 cgrp.cg_cs.cs_nbfree++; 1590 cgrp.cg_btot[cbtocylno(&sblock, d)]++; 1591 cgrp.cg_b[cbtocylno(&sblock, d)] 1592 [cbtorpos(&sblock, d)]++; 1593 } else if (j > 0) { 1594 cgrp.cg_cs.cs_nffree += j; 1595 blk = ((cgrp.cg_free[d / NBBY] >> (d % NBBY)) & 1596 (0xff >> (NBBY - sblock.fs_frag))); 1597 fragacct(&sblock, blk, cgrp.cg_frsum, 1); 1598 } 1599 } 1600 for (j = d; d < dmax - dbase; d++) { 1601 if (!getbmap(dbase+d)) { 1602 setbit(cgrp.cg_free, d); 1603 cgrp.cg_cs.cs_nffree++; 1604 } else 1605 clrbit(cgrp.cg_free, d); 1606 } 1607 if (j != d) { 1608 blk = ((cgrp.cg_free[j / NBBY] >> (j % NBBY)) & 1609 (0xff >> (NBBY - sblock.fs_frag))); 1610 fragacct(&sblock, blk, cgrp.cg_frsum, 1); 1611 } 1612 for (; d < MAXBPG(&sblock); d++) 1613 clrbit(cgrp.cg_free, d); 1614 sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree; 1615 sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree; 1616 sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree; 1617 sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir; 1618 *cs = cgrp.cg_cs; 1619 bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)), 1620 sblock.fs_cgsize); 1621 } 1622 for (i = 0; i < howmany(sblock.fs_cssize, sblock.fs_bsize); i++) { 1623 bwrite(&dfile, (char *)sblock.fs_csp[i], 1624 fsbtodb(&sblock, sblock.fs_csaddr + (i * sblock.fs_frag)), 1625 sblock.fs_bsize); 1626 } 1627 sblock.fs_ronly = 0; 1628 sblock.fs_fmod = 0; 1629 sbdirty(); 1630 } 1631 1632 /* 1633 * update the frsum fields to reflect addition or deletion 1634 * of some frags 1635 */ 1636 fragacct(fs, fragmap, fraglist, cnt) 1637 struct fs *fs; 1638 int fragmap; 1639 long fraglist[]; 1640 int cnt; 1641 { 1642 int inblk; 1643 register int field, subfield; 1644 register int siz, pos; 1645 1646 inblk = (int)(fragtbl[fs->fs_frag][fragmap] << 1); 1647 fragmap <<= 1; 1648 for (siz = 1; siz < fs->fs_frag; siz++) { 1649 if (((1 << siz) & inblk) == 0) 1650 continue; 1651 field = around[siz]; 1652 subfield = inside[siz]; 1653 for (pos = siz; pos <= fs->fs_frag; pos++) { 1654 if ((fragmap & field) == subfield) { 1655 fraglist[siz] += cnt; 1656 pos += siz; 1657 field <<= siz; 1658 subfield <<= siz; 1659 } 1660 field <<= 1; 1661 subfield <<= 1; 1662 } 1663 } 1664 } 1665 1666 findino(dirp) 1667 register DIRECT *dirp; 1668 { 1669 if (dirp->d_ino == 0) 1670 return (KEEPON); 1671 if (!strcmp(dirp->d_name, srchname)) { 1672 if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax) 1673 parentdir = dirp->d_ino; 1674 return (STOP); 1675 } 1676 return (KEEPON); 1677 } 1678 1679 mkentry(dirp) 1680 register DIRECT *dirp; 1681 { 1682 register ino_t in; 1683 register char *p; 1684 DIRECT newent; 1685 int newlen, oldlen; 1686 1687 newent.d_namlen = 11; 1688 newlen = DIRSIZ(&newent); 1689 if (dirp->d_ino != 0) 1690 oldlen = DIRSIZ(dirp); 1691 else 1692 oldlen = 0; 1693 if (dirp->d_reclen - oldlen < newlen) 1694 return (KEEPON); 1695 newent.d_reclen = dirp->d_reclen - oldlen; 1696 dirp->d_reclen = oldlen; 1697 dirp = (struct direct *)(((char *)dirp) + oldlen); 1698 dirp->d_ino = orphan; 1699 dirp->d_reclen = newent.d_reclen; 1700 p = &dirp->d_name[2]; 1701 for (in = imax; in > 0; in /= 10) 1702 p++; 1703 *--p = 0; 1704 dirp->d_namlen = p - dirp->d_name; 1705 in = orphan; 1706 while (p > dirp->d_name) { 1707 *--p = (in % 10) + '0'; 1708 in /= 10; 1709 } 1710 *p = '#'; 1711 return (ALTERD|STOP); 1712 } 1713 1714 chgdd(dirp) 1715 register DIRECT *dirp; 1716 { 1717 if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' && 1718 dirp->d_name[2] == 0) { 1719 dirp->d_ino = lfdir; 1720 return (ALTERD|STOP); 1721 } 1722 return (KEEPON); 1723 } 1724 1725 linkup() 1726 { 1727 register DINODE *dp; 1728 register lostdir; 1729 register ino_t pdir; 1730 1731 if ((dp = ginode()) == NULL) 1732 return (0); 1733 lostdir = DIRCT; 1734 pdir = parentdir; 1735 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); 1736 pinode(); 1737 if (preen && dp->di_size == 0) 1738 return (0); 1739 if (preen) 1740 printf(" (RECONNECTED)\n"); 1741 else 1742 if (reply("RECONNECT") == 0) 1743 return (0); 1744 orphan = inum; 1745 if (lfdir == 0) { 1746 inum = ROOTINO; 1747 if ((dp = ginode()) == NULL) { 1748 inum = orphan; 1749 return (0); 1750 } 1751 pfunc = findino; 1752 srchname = lfname; 1753 filsize = dp->di_size; 1754 parentdir = 0; 1755 ckinode(dp, DATA); 1756 inum = orphan; 1757 if ((lfdir = parentdir) == 0) { 1758 pfatal("SORRY. NO lost+found DIRECTORY"); 1759 printf("\n\n"); 1760 return (0); 1761 } 1762 } 1763 inum = lfdir; 1764 if ((dp = ginode()) == NULL || !DIRCT || getstate() != FSTATE) { 1765 inum = orphan; 1766 pfatal("SORRY. NO lost+found DIRECTORY"); 1767 printf("\n\n"); 1768 return (0); 1769 } 1770 if (fragoff(&sblock, dp->di_size)) { 1771 dp->di_size = fragroundup(&sblock, dp->di_size); 1772 inodirty(); 1773 } 1774 filsize = dp->di_size; 1775 inum = orphan; 1776 pfunc = mkentry; 1777 if ((ckinode(dp, DATA) & ALTERD) == 0) { 1778 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY"); 1779 printf("\n\n"); 1780 return (0); 1781 } 1782 declncnt(); 1783 if (lostdir) { 1784 pfunc = chgdd; 1785 dp = ginode(); 1786 filsize = dp->di_size; 1787 ckinode(dp, DATA); 1788 inum = lfdir; 1789 if ((dp = ginode()) != NULL) { 1790 dp->di_nlink++; 1791 inodirty(); 1792 setlncnt(getlncnt()+1); 1793 } 1794 inum = orphan; 1795 pwarn("DIR I=%u CONNECTED. ", orphan); 1796 printf("PARENT WAS I=%u\n", pdir); 1797 if (preen == 0) 1798 printf("\n"); 1799 } 1800 return (1); 1801 } 1802 1803 bread(fcp, buf, blk, size) 1804 daddr_t blk; 1805 register struct filecntl *fcp; 1806 register size; 1807 char *buf; 1808 { 1809 if (lseek(fcp->rfdes, blk * DEV_BSIZE, 0) < 0) 1810 rwerr("SEEK", blk); 1811 else if (read(fcp->rfdes, buf, size) == size) 1812 return (1); 1813 rwerr("READ", blk); 1814 return (0); 1815 } 1816 1817 bwrite(fcp, buf, blk, size) 1818 daddr_t blk; 1819 register struct filecntl *fcp; 1820 register size; 1821 char *buf; 1822 { 1823 1824 if (fcp->wfdes < 0) 1825 return (0); 1826 if (lseek(fcp->wfdes, blk * DEV_BSIZE, 0) < 0) 1827 rwerr("SEEK", blk); 1828 else if (write(fcp->wfdes, buf, size) == size) { 1829 fcp->mod = 1; 1830 return (1); 1831 } 1832 rwerr("WRITE", blk); 1833 return (0); 1834 } 1835 1836 catch() 1837 { 1838 1839 ckfini(); 1840 exit(12); 1841 } 1842 1843 /* 1844 * block operations 1845 */ 1846 1847 isblock(fs, cp, h) 1848 struct fs *fs; 1849 unsigned char *cp; 1850 int h; 1851 { 1852 unsigned char mask; 1853 1854 switch (fs->fs_frag) { 1855 case 8: 1856 return (cp[h] == 0xff); 1857 case 4: 1858 mask = 0x0f << ((h & 0x1) << 2); 1859 return ((cp[h >> 1] & mask) == mask); 1860 case 2: 1861 mask = 0x03 << ((h & 0x3) << 1); 1862 return ((cp[h >> 2] & mask) == mask); 1863 case 1: 1864 mask = 0x01 << (h & 0x7); 1865 return ((cp[h >> 3] & mask) == mask); 1866 default: 1867 error("isblock bad fs_frag %d\n", fs->fs_frag); 1868 return (0); 1869 } 1870 } 1871