1 /* 2 * Copyright (c) 1980, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 #if 0 36 static const char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95"; 37 #endif 38 static const char rcsid[] = 39 "$FreeBSD$"; 40 #endif /* not lint */ 41 42 #include <sys/param.h> 43 44 #include <ufs/ufs/dinode.h> 45 #include <ufs/ufs/dir.h> 46 #include <ufs/ffs/fs.h> 47 48 #include <err.h> 49 #include <string.h> 50 51 #include "fsck.h" 52 53 long diskreads, totalreads; /* Disk cache statistics */ 54 55 static void rwerror __P((char *mesg, ufs_daddr_t blk)); 56 57 int 58 ftypeok(dp) 59 struct dinode *dp; 60 { 61 switch (dp->di_mode & IFMT) { 62 63 case IFDIR: 64 case IFREG: 65 case IFBLK: 66 case IFCHR: 67 case IFLNK: 68 case IFSOCK: 69 case IFIFO: 70 return (1); 71 72 default: 73 if (debug) 74 printf("bad file type 0%o\n", dp->di_mode); 75 return (0); 76 } 77 } 78 79 int 80 reply(question) 81 char *question; 82 { 83 int persevere; 84 char c; 85 86 if (preen) 87 pfatal("INTERNAL ERROR: GOT TO reply()"); 88 persevere = !strcmp(question, "CONTINUE"); 89 printf("\n"); 90 if (!persevere && (nflag || fswritefd < 0)) { 91 printf("%s? no\n\n", question); 92 resolved = 0; 93 return (0); 94 } 95 if (yflag || (persevere && nflag)) { 96 printf("%s? yes\n\n", question); 97 return (1); 98 } 99 do { 100 printf("%s? [yn] ", question); 101 (void) fflush(stdout); 102 c = getc(stdin); 103 while (c != '\n' && getc(stdin) != '\n') { 104 if (feof(stdin)) { 105 resolved = 0; 106 return (0); 107 } 108 } 109 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 110 printf("\n"); 111 if (c == 'y' || c == 'Y') 112 return (1); 113 resolved = 0; 114 return (0); 115 } 116 117 /* 118 * Look up state information for an inode. 119 */ 120 struct inostat * 121 inoinfo(inum) 122 ino_t inum; 123 { 124 static struct inostat unallocated = { USTATE, 0, 0 }; 125 struct inostatlist *ilp; 126 int iloff; 127 128 if (inum > maxino) 129 errx(EEXIT, "inoinfo: inumber %d out of range", inum); 130 ilp = &inostathead[inum / sblock.fs_ipg]; 131 iloff = inum % sblock.fs_ipg; 132 if (iloff >= ilp->il_numalloced) 133 return (&unallocated); 134 return (&ilp->il_stat[iloff]); 135 } 136 137 /* 138 * Malloc buffers and set up cache. 139 */ 140 void 141 bufinit() 142 { 143 register struct bufarea *bp; 144 long bufcnt, i; 145 char *bufp; 146 147 pbp = pdirbp = (struct bufarea *)0; 148 bufp = malloc((unsigned int)sblock.fs_bsize); 149 if (bufp == 0) 150 errx(EEXIT, "cannot allocate buffer pool"); 151 cgblk.b_un.b_buf = bufp; 152 initbarea(&cgblk); 153 bufhead.b_next = bufhead.b_prev = &bufhead; 154 bufcnt = MAXBUFSPACE / sblock.fs_bsize; 155 if (bufcnt < MINBUFS) 156 bufcnt = MINBUFS; 157 for (i = 0; i < bufcnt; i++) { 158 bp = (struct bufarea *)malloc(sizeof(struct bufarea)); 159 bufp = malloc((unsigned int)sblock.fs_bsize); 160 if (bp == NULL || bufp == NULL) { 161 if (i >= MINBUFS) 162 break; 163 errx(EEXIT, "cannot allocate buffer pool"); 164 } 165 bp->b_un.b_buf = bufp; 166 bp->b_prev = &bufhead; 167 bp->b_next = bufhead.b_next; 168 bufhead.b_next->b_prev = bp; 169 bufhead.b_next = bp; 170 initbarea(bp); 171 } 172 bufhead.b_size = i; /* save number of buffers */ 173 } 174 175 /* 176 * Manage a cache of directory blocks. 177 */ 178 struct bufarea * 179 getdatablk(blkno, size) 180 ufs_daddr_t blkno; 181 long size; 182 { 183 register struct bufarea *bp; 184 185 for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 186 if (bp->b_bno == fsbtodb(&sblock, blkno)) 187 goto foundit; 188 for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 189 if ((bp->b_flags & B_INUSE) == 0) 190 break; 191 if (bp == &bufhead) 192 errx(EEXIT, "deadlocked buffer pool"); 193 getblk(bp, blkno, size); 194 /* fall through */ 195 foundit: 196 totalreads++; 197 bp->b_prev->b_next = bp->b_next; 198 bp->b_next->b_prev = bp->b_prev; 199 bp->b_prev = &bufhead; 200 bp->b_next = bufhead.b_next; 201 bufhead.b_next->b_prev = bp; 202 bufhead.b_next = bp; 203 bp->b_flags |= B_INUSE; 204 return (bp); 205 } 206 207 void 208 getblk(bp, blk, size) 209 register struct bufarea *bp; 210 ufs_daddr_t blk; 211 long size; 212 { 213 ufs_daddr_t dblk; 214 215 dblk = fsbtodb(&sblock, blk); 216 if (bp->b_bno != dblk) { 217 flush(fswritefd, bp); 218 diskreads++; 219 bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 220 bp->b_bno = dblk; 221 bp->b_size = size; 222 } 223 } 224 225 void 226 flush(fd, bp) 227 int fd; 228 register struct bufarea *bp; 229 { 230 register int i, j; 231 232 if (!bp->b_dirty) 233 return; 234 if (bp->b_errs != 0) 235 pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 236 (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 237 bp->b_bno); 238 bp->b_dirty = 0; 239 bp->b_errs = 0; 240 bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 241 if (bp != &sblk) 242 return; 243 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 244 bwrite(fswritefd, (char *)sblock.fs_csp[j], 245 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 246 sblock.fs_cssize - i < sblock.fs_bsize ? 247 sblock.fs_cssize - i : sblock.fs_bsize); 248 } 249 } 250 251 static void 252 rwerror(mesg, blk) 253 char *mesg; 254 ufs_daddr_t blk; 255 { 256 257 if (preen == 0) 258 printf("\n"); 259 pfatal("CANNOT %s: BLK %ld", mesg, blk); 260 if (reply("CONTINUE") == 0) 261 exit(EEXIT); 262 } 263 264 void 265 ckfini(markclean) 266 int markclean; 267 { 268 register struct bufarea *bp, *nbp; 269 int ofsmodified, cnt = 0; 270 271 if (fswritefd < 0) { 272 (void)close(fsreadfd); 273 return; 274 } 275 flush(fswritefd, &sblk); 276 if (havesb && sblk.b_bno != SBOFF / dev_bsize && 277 !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 278 sblk.b_bno = SBOFF / dev_bsize; 279 sbdirty(); 280 flush(fswritefd, &sblk); 281 } 282 flush(fswritefd, &cgblk); 283 free(cgblk.b_un.b_buf); 284 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 285 cnt++; 286 flush(fswritefd, bp); 287 nbp = bp->b_prev; 288 free(bp->b_un.b_buf); 289 free((char *)bp); 290 } 291 if (bufhead.b_size != cnt) 292 errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt); 293 pbp = pdirbp = (struct bufarea *)0; 294 if (sblock.fs_clean != markclean) { 295 sblock.fs_clean = markclean; 296 sbdirty(); 297 ofsmodified = fsmodified; 298 flush(fswritefd, &sblk); 299 fsmodified = ofsmodified; 300 if (!preen) { 301 printf("\n***** FILE SYSTEM MARKED %s *****\n", 302 markclean ? "CLEAN" : "DIRTY"); 303 if (!markclean) 304 rerun = 1; 305 } 306 } else if (!preen && !markclean) { 307 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 308 rerun = 1; 309 } 310 if (debug) 311 printf("cache missed %ld of %ld (%d%%)\n", diskreads, 312 totalreads, (int)(diskreads * 100 / totalreads)); 313 (void)close(fsreadfd); 314 (void)close(fswritefd); 315 } 316 317 int 318 bread(fd, buf, blk, size) 319 int fd; 320 char *buf; 321 ufs_daddr_t blk; 322 long size; 323 { 324 char *cp; 325 int i, errs; 326 off_t offset; 327 328 offset = blk; 329 offset *= dev_bsize; 330 if (lseek(fd, offset, 0) < 0) 331 rwerror("SEEK", blk); 332 else if (read(fd, buf, (int)size) == size) 333 return (0); 334 rwerror("READ", blk); 335 if (lseek(fd, offset, 0) < 0) 336 rwerror("SEEK", blk); 337 errs = 0; 338 memset(buf, 0, (size_t)size); 339 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 340 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 341 if (read(fd, cp, (int)secsize) != secsize) { 342 (void)lseek(fd, offset + i + secsize, 0); 343 if (secsize != dev_bsize && dev_bsize != 1) 344 printf(" %ld (%ld),", 345 (blk * dev_bsize + i) / secsize, 346 blk + i / dev_bsize); 347 else 348 printf(" %ld,", blk + i / dev_bsize); 349 errs++; 350 } 351 } 352 printf("\n"); 353 if (errs) 354 resolved = 0; 355 return (errs); 356 } 357 358 void 359 bwrite(fd, buf, blk, size) 360 int fd; 361 char *buf; 362 ufs_daddr_t blk; 363 long size; 364 { 365 int i; 366 char *cp; 367 off_t offset; 368 369 if (fd < 0) 370 return; 371 offset = blk; 372 offset *= dev_bsize; 373 if (lseek(fd, offset, 0) < 0) 374 rwerror("SEEK", blk); 375 else if (write(fd, buf, (int)size) == size) { 376 fsmodified = 1; 377 return; 378 } 379 resolved = 0; 380 rwerror("WRITE", blk); 381 if (lseek(fd, offset, 0) < 0) 382 rwerror("SEEK", blk); 383 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 384 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 385 if (write(fd, cp, (int)dev_bsize) != dev_bsize) { 386 (void)lseek(fd, offset + i + dev_bsize, 0); 387 printf(" %ld,", blk + i / dev_bsize); 388 } 389 printf("\n"); 390 return; 391 } 392 393 /* 394 * allocate a data block with the specified number of fragments 395 */ 396 ufs_daddr_t 397 allocblk(frags) 398 long frags; 399 { 400 int i, j, k, cg, baseblk; 401 struct cg *cgp = &cgrp; 402 403 if (frags <= 0 || frags > sblock.fs_frag) 404 return (0); 405 for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 406 for (j = 0; j <= sblock.fs_frag - frags; j++) { 407 if (testbmap(i + j)) 408 continue; 409 for (k = 1; k < frags; k++) 410 if (testbmap(i + j + k)) 411 break; 412 if (k < frags) { 413 j += k; 414 continue; 415 } 416 cg = dtog(&sblock, i + j); 417 getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 418 if (!cg_chkmagic(cgp)) 419 pfatal("CG %d: BAD MAGIC NUMBER\n", cg); 420 baseblk = dtogd(&sblock, i + j); 421 for (k = 0; k < frags; k++) { 422 setbmap(i + j + k); 423 clrbit(cg_blksfree(cgp), baseblk + k); 424 } 425 n_blks += frags; 426 if (frags == sblock.fs_frag) 427 cgp->cg_cs.cs_nbfree--; 428 else 429 cgp->cg_cs.cs_nffree -= frags; 430 cgdirty(); 431 return (i + j); 432 } 433 } 434 return (0); 435 } 436 437 /* 438 * Free a previously allocated block 439 */ 440 void 441 freeblk(blkno, frags) 442 ufs_daddr_t blkno; 443 long frags; 444 { 445 struct inodesc idesc; 446 447 idesc.id_blkno = blkno; 448 idesc.id_numfrags = frags; 449 (void)pass4check(&idesc); 450 } 451 452 /* 453 * Find a pathname 454 */ 455 void 456 getpathname(namebuf, curdir, ino) 457 char *namebuf; 458 ino_t curdir, ino; 459 { 460 int len; 461 register char *cp; 462 struct inodesc idesc; 463 static int busy = 0; 464 465 if (curdir == ino && ino == ROOTINO) { 466 (void)strcpy(namebuf, "/"); 467 return; 468 } 469 if (busy || 470 (inoinfo(curdir)->ino_state != DSTATE && 471 inoinfo(curdir)->ino_state != DFOUND)) { 472 (void)strcpy(namebuf, "?"); 473 return; 474 } 475 busy = 1; 476 memset(&idesc, 0, sizeof(struct inodesc)); 477 idesc.id_type = DATA; 478 idesc.id_fix = IGNORE; 479 cp = &namebuf[MAXPATHLEN - 1]; 480 *cp = '\0'; 481 if (curdir != ino) { 482 idesc.id_parent = curdir; 483 goto namelookup; 484 } 485 while (ino != ROOTINO) { 486 idesc.id_number = ino; 487 idesc.id_func = findino; 488 idesc.id_name = ".."; 489 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 490 break; 491 namelookup: 492 idesc.id_number = idesc.id_parent; 493 idesc.id_parent = ino; 494 idesc.id_func = findname; 495 idesc.id_name = namebuf; 496 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 497 break; 498 len = strlen(namebuf); 499 cp -= len; 500 memmove(cp, namebuf, (size_t)len); 501 *--cp = '/'; 502 if (cp < &namebuf[MAXNAMLEN]) 503 break; 504 ino = idesc.id_number; 505 } 506 busy = 0; 507 if (ino != ROOTINO) 508 *--cp = '?'; 509 memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 510 } 511 512 void 513 catch(sig) 514 int sig; 515 { 516 if (!doinglevel2) 517 ckfini(0); 518 exit(12); 519 } 520 521 /* 522 * When preening, allow a single quit to signal 523 * a special exit after filesystem checks complete 524 * so that reboot sequence may be interrupted. 525 */ 526 void 527 catchquit(sig) 528 int sig; 529 { 530 printf("returning to single-user after filesystem check\n"); 531 returntosingle = 1; 532 (void)signal(SIGQUIT, SIG_DFL); 533 } 534 535 /* 536 * Ignore a single quit signal; wait and flush just in case. 537 * Used by child processes in preen. 538 */ 539 void 540 voidquit(sig) 541 int sig; 542 { 543 544 sleep(1); 545 (void)signal(SIGQUIT, SIG_IGN); 546 (void)signal(SIGQUIT, SIG_DFL); 547 } 548 549 /* 550 * determine whether an inode should be fixed. 551 */ 552 int 553 dofix(idesc, msg) 554 register struct inodesc *idesc; 555 char *msg; 556 { 557 558 switch (idesc->id_fix) { 559 560 case DONTKNOW: 561 if (idesc->id_type == DATA) 562 direrror(idesc->id_number, msg); 563 else 564 pwarn("%s", msg); 565 if (preen) { 566 printf(" (SALVAGED)\n"); 567 idesc->id_fix = FIX; 568 return (ALTERED); 569 } 570 if (reply("SALVAGE") == 0) { 571 idesc->id_fix = NOFIX; 572 return (0); 573 } 574 idesc->id_fix = FIX; 575 return (ALTERED); 576 577 case FIX: 578 return (ALTERED); 579 580 case NOFIX: 581 case IGNORE: 582 return (0); 583 584 default: 585 errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 586 } 587 /* NOTREACHED */ 588 return (0); 589 } 590 591 #if __STDC__ 592 #include <stdarg.h> 593 #else 594 #include <varargs.h> 595 #endif 596 597 /* 598 * An unexpected inconsistency occured. 599 * Die if preening or filesystem is running with soft dependency protocol, 600 * otherwise just print message and continue. 601 */ 602 void 603 #if __STDC__ 604 pfatal(const char *fmt, ...) 605 #else 606 pfatal(fmt, va_alist) 607 char *fmt; 608 va_dcl 609 #endif 610 { 611 va_list ap; 612 #if __STDC__ 613 va_start(ap, fmt); 614 #else 615 va_start(ap); 616 #endif 617 if (!preen) { 618 (void)vfprintf(stderr, fmt, ap); 619 va_end(ap); 620 if (usedsoftdep) 621 (void)fprintf(stderr, 622 "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n"); 623 return; 624 } 625 if (cdevname == NULL) 626 cdevname = "fsck"; 627 (void)fprintf(stderr, "%s: ", cdevname); 628 (void)vfprintf(stderr, fmt, ap); 629 (void)fprintf(stderr, 630 "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n", 631 cdevname, usedsoftdep ? " SOFT UPDATE " : " "); 632 ckfini(0); 633 exit(EEXIT); 634 } 635 636 /* 637 * Pwarn just prints a message when not preening or running soft dependency 638 * protocol, or a warning (preceded by filename) when preening. 639 */ 640 void 641 #if __STDC__ 642 pwarn(const char *fmt, ...) 643 #else 644 pwarn(fmt, va_alist) 645 char *fmt; 646 va_dcl 647 #endif 648 { 649 va_list ap; 650 #if __STDC__ 651 va_start(ap, fmt); 652 #else 653 va_start(ap); 654 #endif 655 if (preen) 656 (void)fprintf(stderr, "%s: ", cdevname); 657 (void)vfprintf(stderr, fmt, ap); 658 va_end(ap); 659 } 660 661 /* 662 * Stub for routines from kernel. 663 */ 664 void 665 #if __STDC__ 666 panic(const char *fmt, ...) 667 #else 668 panic(fmt, va_alist) 669 char *fmt; 670 va_dcl 671 #endif 672 { 673 va_list ap; 674 #if __STDC__ 675 va_start(ap, fmt); 676 #else 677 va_start(ap); 678 #endif 679 pfatal("INTERNAL INCONSISTENCY:"); 680 (void)vfprintf(stderr, fmt, ap); 681 va_end(ap); 682 exit(EEXIT); 683 } 684