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 #include <sys/types.h> 44 #include <sys/sysctl.h> 45 #include <sys/stat.h> 46 #include <sys/disklabel.h> 47 48 #include <ufs/ufs/dinode.h> 49 #include <ufs/ufs/dir.h> 50 #include <ufs/ffs/fs.h> 51 52 #include <err.h> 53 #include <errno.h> 54 #include <string.h> 55 #include <ctype.h> 56 #include <fstab.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <unistd.h> 60 61 #include "fsck.h" 62 63 long diskreads, totalreads; /* Disk cache statistics */ 64 65 int 66 ftypeok(struct dinode *dp) 67 { 68 switch (dp->di_mode & IFMT) { 69 70 case IFDIR: 71 case IFREG: 72 case IFBLK: 73 case IFCHR: 74 case IFLNK: 75 case IFSOCK: 76 case IFIFO: 77 return (1); 78 79 default: 80 if (debug) 81 printf("bad file type 0%o\n", dp->di_mode); 82 return (0); 83 } 84 } 85 86 int 87 reply(char *question) 88 { 89 int persevere; 90 char c; 91 92 if (preen) 93 pfatal("INTERNAL ERROR: GOT TO reply()"); 94 persevere = !strcmp(question, "CONTINUE"); 95 printf("\n"); 96 if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) { 97 printf("%s? no\n\n", question); 98 resolved = 0; 99 return (0); 100 } 101 if (yflag || (persevere && nflag)) { 102 printf("%s? yes\n\n", question); 103 return (1); 104 } 105 do { 106 printf("%s? [yn] ", question); 107 (void) fflush(stdout); 108 c = getc(stdin); 109 while (c != '\n' && getc(stdin) != '\n') { 110 if (feof(stdin)) { 111 resolved = 0; 112 return (0); 113 } 114 } 115 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 116 printf("\n"); 117 if (c == 'y' || c == 'Y') 118 return (1); 119 resolved = 0; 120 return (0); 121 } 122 123 /* 124 * Look up state information for an inode. 125 */ 126 struct inostat * 127 inoinfo(ino_t inum) 128 { 129 static struct inostat unallocated = { USTATE, 0, 0 }; 130 struct inostatlist *ilp; 131 int iloff; 132 133 if (inum > maxino) 134 errx(EEXIT, "inoinfo: inumber %d out of range", inum); 135 ilp = &inostathead[inum / sblock.fs_ipg]; 136 iloff = inum % sblock.fs_ipg; 137 if (iloff >= ilp->il_numalloced) 138 return (&unallocated); 139 return (&ilp->il_stat[iloff]); 140 } 141 142 /* 143 * Malloc buffers and set up cache. 144 */ 145 void 146 bufinit(void) 147 { 148 struct bufarea *bp; 149 long bufcnt, i; 150 char *bufp; 151 152 pbp = pdirbp = (struct bufarea *)0; 153 bufp = malloc((unsigned int)sblock.fs_bsize); 154 if (bufp == 0) 155 errx(EEXIT, "cannot allocate buffer pool"); 156 cgblk.b_un.b_buf = bufp; 157 initbarea(&cgblk); 158 bufhead.b_next = bufhead.b_prev = &bufhead; 159 bufcnt = MAXBUFSPACE / sblock.fs_bsize; 160 if (bufcnt < MINBUFS) 161 bufcnt = MINBUFS; 162 for (i = 0; i < bufcnt; i++) { 163 bp = (struct bufarea *)malloc(sizeof(struct bufarea)); 164 bufp = malloc((unsigned int)sblock.fs_bsize); 165 if (bp == NULL || bufp == NULL) { 166 if (i >= MINBUFS) 167 break; 168 errx(EEXIT, "cannot allocate buffer pool"); 169 } 170 bp->b_un.b_buf = bufp; 171 bp->b_prev = &bufhead; 172 bp->b_next = bufhead.b_next; 173 bufhead.b_next->b_prev = bp; 174 bufhead.b_next = bp; 175 initbarea(bp); 176 } 177 bufhead.b_size = i; /* save number of buffers */ 178 } 179 180 /* 181 * Manage a cache of directory blocks. 182 */ 183 struct bufarea * 184 getdatablk(ufs_daddr_t blkno, long size) 185 { 186 struct bufarea *bp; 187 188 for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 189 if (bp->b_bno == fsbtodb(&sblock, blkno)) 190 goto foundit; 191 for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 192 if ((bp->b_flags & B_INUSE) == 0) 193 break; 194 if (bp == &bufhead) 195 errx(EEXIT, "deadlocked buffer pool"); 196 getblk(bp, blkno, size); 197 /* fall through */ 198 foundit: 199 bp->b_prev->b_next = bp->b_next; 200 bp->b_next->b_prev = bp->b_prev; 201 bp->b_prev = &bufhead; 202 bp->b_next = bufhead.b_next; 203 bufhead.b_next->b_prev = bp; 204 bufhead.b_next = bp; 205 bp->b_flags |= B_INUSE; 206 return (bp); 207 } 208 209 void 210 getblk(struct bufarea *bp, ufs_daddr_t blk, long size) 211 { 212 ufs_daddr_t dblk; 213 214 totalreads++; 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(int fd, struct bufarea *bp) 227 { 228 int i, j; 229 230 if (!bp->b_dirty) 231 return; 232 bp->b_dirty = 0; 233 if (fswritefd < 0) { 234 pfatal("WRITING IN READ_ONLY MODE.\n"); 235 return; 236 } 237 if (bp->b_errs != 0) 238 pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 239 (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 240 bp->b_bno); 241 bp->b_errs = 0; 242 bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 243 if (bp != &sblk) 244 return; 245 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 246 bwrite(fswritefd, (char *)sblock.fs_csp + i, 247 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 248 sblock.fs_cssize - i < sblock.fs_bsize ? 249 sblock.fs_cssize - i : sblock.fs_bsize); 250 } 251 } 252 253 void 254 rwerror(char *mesg, ufs_daddr_t blk) 255 { 256 257 if (bkgrdcheck) 258 exit(EEXIT); 259 if (preen == 0) 260 printf("\n"); 261 pfatal("CANNOT %s: %ld", mesg, (long)blk); 262 if (reply("CONTINUE") == 0) 263 exit(EEXIT); 264 } 265 266 void 267 ckfini(int markclean) 268 { 269 struct bufarea *bp, *nbp; 270 int ofsmodified, cnt = 0; 271 272 if (bkgrdflag) { 273 unlink(snapname); 274 if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) { 275 cmd.value = FS_UNCLEAN; 276 cmd.size = markclean ? -1 : 1; 277 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 278 &cmd, sizeof cmd) == -1) 279 rwerror("SET FILESYSTEM FLAGS", FS_UNCLEAN); 280 if (!preen) { 281 printf("\n***** FILE SYSTEM MARKED %s *****\n", 282 markclean ? "CLEAN" : "DIRTY"); 283 if (!markclean) 284 rerun = 1; 285 } 286 } else if (!preen && !markclean) { 287 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 288 rerun = 1; 289 } 290 } 291 if (fswritefd < 0) { 292 (void)close(fsreadfd); 293 return; 294 } 295 flush(fswritefd, &sblk); 296 if (havesb && sblk.b_bno != SBOFF / dev_bsize && cursnapshot == 0 && 297 !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 298 sblk.b_bno = SBOFF / dev_bsize; 299 sbdirty(); 300 flush(fswritefd, &sblk); 301 } 302 flush(fswritefd, &cgblk); 303 free(cgblk.b_un.b_buf); 304 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 305 cnt++; 306 flush(fswritefd, bp); 307 nbp = bp->b_prev; 308 free(bp->b_un.b_buf); 309 free((char *)bp); 310 } 311 if (bufhead.b_size != cnt) 312 errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt); 313 pbp = pdirbp = (struct bufarea *)0; 314 if (cursnapshot == 0 && sblock.fs_clean != markclean) { 315 if ((sblock.fs_clean = markclean) != 0) 316 sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK); 317 sbdirty(); 318 ofsmodified = fsmodified; 319 flush(fswritefd, &sblk); 320 fsmodified = ofsmodified; 321 if (!preen) { 322 printf("\n***** FILE SYSTEM MARKED %s *****\n", 323 markclean ? "CLEAN" : "DIRTY"); 324 if (!markclean) 325 rerun = 1; 326 } 327 } else if (!preen && !markclean) { 328 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 329 rerun = 1; 330 } 331 if (debug && totalreads > 0) 332 printf("cache missed %ld of %ld (%d%%)\n", diskreads, 333 totalreads, (int)(diskreads * 100 / totalreads)); 334 (void)close(fsreadfd); 335 (void)close(fswritefd); 336 } 337 338 int 339 bread(int fd, char *buf, ufs_daddr_t blk, long size) 340 { 341 char *cp; 342 int i, errs; 343 off_t offset; 344 345 offset = blk; 346 offset *= dev_bsize; 347 if (lseek(fd, offset, 0) < 0) 348 rwerror("SEEK BLK", blk); 349 else if (read(fd, buf, (int)size) == size) 350 return (0); 351 rwerror("READ BLK", blk); 352 if (lseek(fd, offset, 0) < 0) 353 rwerror("SEEK BLK", blk); 354 errs = 0; 355 memset(buf, 0, (size_t)size); 356 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 357 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 358 if (read(fd, cp, (int)secsize) != secsize) { 359 (void)lseek(fd, offset + i + secsize, 0); 360 if (secsize != dev_bsize && dev_bsize != 1) 361 printf(" %ld (%ld),", 362 (blk * dev_bsize + i) / secsize, 363 blk + i / dev_bsize); 364 else 365 printf(" %ld,", blk + i / dev_bsize); 366 errs++; 367 } 368 } 369 printf("\n"); 370 if (errs) 371 resolved = 0; 372 return (errs); 373 } 374 375 void 376 bwrite(int fd, char *buf, ufs_daddr_t blk, long size) 377 { 378 int i; 379 char *cp; 380 off_t offset; 381 382 if (fd < 0) 383 return; 384 offset = blk; 385 offset *= dev_bsize; 386 if (lseek(fd, offset, 0) < 0) 387 rwerror("SEEK BLK", blk); 388 else if (write(fd, buf, (int)size) == size) { 389 fsmodified = 1; 390 return; 391 } 392 resolved = 0; 393 rwerror("WRITE BLK", blk); 394 if (lseek(fd, offset, 0) < 0) 395 rwerror("SEEK BLK", blk); 396 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 397 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 398 if (write(fd, cp, (int)dev_bsize) != dev_bsize) { 399 (void)lseek(fd, offset + i + dev_bsize, 0); 400 printf(" %ld,", blk + i / dev_bsize); 401 } 402 printf("\n"); 403 return; 404 } 405 406 /* 407 * allocate a data block with the specified number of fragments 408 */ 409 ufs_daddr_t 410 allocblk(long frags) 411 { 412 int i, j, k, cg, baseblk; 413 struct cg *cgp = &cgrp; 414 415 if (frags <= 0 || frags > sblock.fs_frag) 416 return (0); 417 for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 418 for (j = 0; j <= sblock.fs_frag - frags; j++) { 419 if (testbmap(i + j)) 420 continue; 421 for (k = 1; k < frags; k++) 422 if (testbmap(i + j + k)) 423 break; 424 if (k < frags) { 425 j += k; 426 continue; 427 } 428 cg = dtog(&sblock, i + j); 429 getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 430 if (!cg_chkmagic(cgp)) 431 pfatal("CG %d: BAD MAGIC NUMBER\n", cg); 432 baseblk = dtogd(&sblock, i + j); 433 for (k = 0; k < frags; k++) { 434 setbmap(i + j + k); 435 clrbit(cg_blksfree(cgp), baseblk + k); 436 } 437 n_blks += frags; 438 if (frags == sblock.fs_frag) 439 cgp->cg_cs.cs_nbfree--; 440 else 441 cgp->cg_cs.cs_nffree -= frags; 442 cgdirty(); 443 return (i + j); 444 } 445 } 446 return (0); 447 } 448 449 /* 450 * Free a previously allocated block 451 */ 452 void 453 freeblk(ufs_daddr_t blkno, long frags) 454 { 455 struct inodesc idesc; 456 457 idesc.id_blkno = blkno; 458 idesc.id_numfrags = frags; 459 (void)pass4check(&idesc); 460 } 461 462 /* 463 * Find a pathname 464 */ 465 void 466 getpathname(char *namebuf, ino_t curdir, ino_t ino) 467 { 468 int len; 469 char *cp; 470 struct inodesc idesc; 471 static int busy = 0; 472 473 if (curdir == ino && ino == ROOTINO) { 474 (void)strcpy(namebuf, "/"); 475 return; 476 } 477 if (busy || 478 (inoinfo(curdir)->ino_state != DSTATE && 479 inoinfo(curdir)->ino_state != DFOUND)) { 480 (void)strcpy(namebuf, "?"); 481 return; 482 } 483 busy = 1; 484 memset(&idesc, 0, sizeof(struct inodesc)); 485 idesc.id_type = DATA; 486 idesc.id_fix = IGNORE; 487 cp = &namebuf[MAXPATHLEN - 1]; 488 *cp = '\0'; 489 if (curdir != ino) { 490 idesc.id_parent = curdir; 491 goto namelookup; 492 } 493 while (ino != ROOTINO) { 494 idesc.id_number = ino; 495 idesc.id_func = findino; 496 idesc.id_name = ".."; 497 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 498 break; 499 namelookup: 500 idesc.id_number = idesc.id_parent; 501 idesc.id_parent = ino; 502 idesc.id_func = findname; 503 idesc.id_name = namebuf; 504 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 505 break; 506 len = strlen(namebuf); 507 cp -= len; 508 memmove(cp, namebuf, (size_t)len); 509 *--cp = '/'; 510 if (cp < &namebuf[MAXNAMLEN]) 511 break; 512 ino = idesc.id_number; 513 } 514 busy = 0; 515 if (ino != ROOTINO) 516 *--cp = '?'; 517 memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 518 } 519 520 void 521 catch(int sig) 522 { 523 524 ckfini(0); 525 exit(12); 526 } 527 528 /* 529 * When preening, allow a single quit to signal 530 * a special exit after filesystem checks complete 531 * so that reboot sequence may be interrupted. 532 */ 533 void 534 catchquit(int sig) 535 { 536 printf("returning to single-user after filesystem check\n"); 537 returntosingle = 1; 538 (void)signal(SIGQUIT, SIG_DFL); 539 } 540 541 /* 542 * determine whether an inode should be fixed. 543 */ 544 int 545 dofix(struct inodesc *idesc, char *msg) 546 { 547 548 switch (idesc->id_fix) { 549 550 case DONTKNOW: 551 if (idesc->id_type == DATA) 552 direrror(idesc->id_number, msg); 553 else 554 pwarn("%s", msg); 555 if (preen) { 556 printf(" (SALVAGED)\n"); 557 idesc->id_fix = FIX; 558 return (ALTERED); 559 } 560 if (reply("SALVAGE") == 0) { 561 idesc->id_fix = NOFIX; 562 return (0); 563 } 564 idesc->id_fix = FIX; 565 return (ALTERED); 566 567 case FIX: 568 return (ALTERED); 569 570 case NOFIX: 571 case IGNORE: 572 return (0); 573 574 default: 575 errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 576 } 577 /* NOTREACHED */ 578 return (0); 579 } 580 581 #include <stdarg.h> 582 583 /* 584 * An unexpected inconsistency occured. 585 * Die if preening or filesystem is running with soft dependency protocol, 586 * otherwise just print message and continue. 587 */ 588 void 589 pfatal(const char *fmt, ...) 590 { 591 va_list ap; 592 va_start(ap, fmt); 593 if (!preen) { 594 (void)vfprintf(stdout, fmt, ap); 595 va_end(ap); 596 if (usedsoftdep) 597 (void)fprintf(stdout, 598 "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n"); 599 /* 600 * Force foreground fsck to clean up inconsistency. 601 */ 602 if (bkgrdflag) { 603 cmd.value = FS_NEEDSFSCK; 604 cmd.size = 1; 605 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 606 &cmd, sizeof cmd) == -1) 607 pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 608 fprintf(stdout, "CANNOT RUN IN BACKGROUND\n"); 609 ckfini(0); 610 exit(EEXIT); 611 } 612 return; 613 } 614 if (cdevname == NULL) 615 cdevname = "fsck"; 616 (void)fprintf(stdout, "%s: ", cdevname); 617 (void)vfprintf(stdout, fmt, ap); 618 (void)fprintf(stdout, 619 "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n", 620 cdevname, usedsoftdep ? " SOFT UPDATE " : " "); 621 /* 622 * Force foreground fsck to clean up inconsistency. 623 */ 624 if (bkgrdflag) { 625 cmd.value = FS_NEEDSFSCK; 626 cmd.size = 1; 627 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 628 &cmd, sizeof cmd) == -1) 629 pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 630 } 631 ckfini(0); 632 exit(EEXIT); 633 } 634 635 /* 636 * Pwarn just prints a message when not preening or running soft dependency 637 * protocol, or a warning (preceded by filename) when preening. 638 */ 639 void 640 pwarn(const char *fmt, ...) 641 { 642 va_list ap; 643 va_start(ap, fmt); 644 if (preen) 645 (void)fprintf(stdout, "%s: ", cdevname); 646 (void)vfprintf(stdout, fmt, ap); 647 va_end(ap); 648 } 649 650 /* 651 * Stub for routines from kernel. 652 */ 653 void 654 panic(const char *fmt, ...) 655 { 656 va_list ap; 657 va_start(ap, fmt); 658 pfatal("INTERNAL INCONSISTENCY:"); 659 (void)vfprintf(stdout, fmt, ap); 660 va_end(ap); 661 exit(EEXIT); 662 } 663