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