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 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #if 0 31 #ifndef lint 32 static const char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95"; 33 #endif /* not lint */ 34 #endif 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <sys/param.h> 39 #include <sys/time.h> 40 #include <sys/types.h> 41 #include <sys/sysctl.h> 42 #include <sys/disk.h> 43 #include <sys/disklabel.h> 44 #include <sys/ioctl.h> 45 #include <sys/stat.h> 46 47 #include <ufs/ufs/dinode.h> 48 #include <ufs/ufs/dir.h> 49 #include <ufs/ffs/fs.h> 50 51 #include <err.h> 52 #include <errno.h> 53 #include <string.h> 54 #include <ctype.h> 55 #include <fstab.h> 56 #include <stdint.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <unistd.h> 60 61 #include "fsck.h" 62 63 static void slowio_start(void); 64 static void slowio_end(void); 65 66 long diskreads, totalreads; /* Disk cache statistics */ 67 struct timeval slowio_starttime; 68 int slowio_delay_usec = 10000; /* Initial IO delay for background fsck */ 69 int slowio_pollcnt; 70 71 int 72 ftypeok(union dinode *dp) 73 { 74 switch (DIP(dp, di_mode) & IFMT) { 75 76 case IFDIR: 77 case IFREG: 78 case IFBLK: 79 case IFCHR: 80 case IFLNK: 81 case IFSOCK: 82 case IFIFO: 83 return (1); 84 85 default: 86 if (debug) 87 printf("bad file type 0%o\n", DIP(dp, di_mode)); 88 return (0); 89 } 90 } 91 92 int 93 reply(const char *question) 94 { 95 int persevere; 96 char c; 97 98 if (preen) 99 pfatal("INTERNAL ERROR: GOT TO reply()"); 100 persevere = !strcmp(question, "CONTINUE"); 101 printf("\n"); 102 if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) { 103 printf("%s? no\n\n", question); 104 resolved = 0; 105 return (0); 106 } 107 if (yflag || (persevere && nflag)) { 108 printf("%s? yes\n\n", question); 109 return (1); 110 } 111 do { 112 printf("%s? [yn] ", question); 113 (void) fflush(stdout); 114 c = getc(stdin); 115 while (c != '\n' && getc(stdin) != '\n') { 116 if (feof(stdin)) { 117 resolved = 0; 118 return (0); 119 } 120 } 121 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 122 printf("\n"); 123 if (c == 'y' || c == 'Y') 124 return (1); 125 resolved = 0; 126 return (0); 127 } 128 129 /* 130 * Look up state information for an inode. 131 */ 132 struct inostat * 133 inoinfo(ino_t inum) 134 { 135 static struct inostat unallocated = { USTATE, 0, 0 }; 136 struct inostatlist *ilp; 137 int iloff; 138 139 if (inum > maxino) 140 errx(EEXIT, "inoinfo: inumber %d out of range", inum); 141 ilp = &inostathead[inum / sblock.fs_ipg]; 142 iloff = inum % sblock.fs_ipg; 143 if (iloff >= ilp->il_numalloced) 144 return (&unallocated); 145 return (&ilp->il_stat[iloff]); 146 } 147 148 /* 149 * Malloc buffers and set up cache. 150 */ 151 void 152 bufinit(void) 153 { 154 struct bufarea *bp; 155 long bufcnt, i; 156 char *bufp; 157 158 pbp = pdirbp = (struct bufarea *)0; 159 bufp = malloc((unsigned int)sblock.fs_bsize); 160 if (bufp == 0) 161 errx(EEXIT, "cannot allocate buffer pool"); 162 cgblk.b_un.b_buf = bufp; 163 initbarea(&cgblk); 164 bufhead.b_next = bufhead.b_prev = &bufhead; 165 bufcnt = MAXBUFSPACE / sblock.fs_bsize; 166 if (bufcnt < MINBUFS) 167 bufcnt = MINBUFS; 168 for (i = 0; i < bufcnt; i++) { 169 bp = (struct bufarea *)malloc(sizeof(struct bufarea)); 170 bufp = malloc((unsigned int)sblock.fs_bsize); 171 if (bp == NULL || bufp == NULL) { 172 if (i >= MINBUFS) 173 break; 174 errx(EEXIT, "cannot allocate buffer pool"); 175 } 176 bp->b_un.b_buf = bufp; 177 bp->b_prev = &bufhead; 178 bp->b_next = bufhead.b_next; 179 bufhead.b_next->b_prev = bp; 180 bufhead.b_next = bp; 181 initbarea(bp); 182 } 183 bufhead.b_size = i; /* save number of buffers */ 184 } 185 186 /* 187 * Manage a cache of directory blocks. 188 */ 189 struct bufarea * 190 getdatablk(ufs2_daddr_t blkno, long size) 191 { 192 struct bufarea *bp; 193 194 for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 195 if (bp->b_bno == fsbtodb(&sblock, blkno)) 196 goto foundit; 197 for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 198 if ((bp->b_flags & B_INUSE) == 0) 199 break; 200 if (bp == &bufhead) 201 errx(EEXIT, "deadlocked buffer pool"); 202 getblk(bp, blkno, size); 203 /* fall through */ 204 foundit: 205 bp->b_prev->b_next = bp->b_next; 206 bp->b_next->b_prev = bp->b_prev; 207 bp->b_prev = &bufhead; 208 bp->b_next = bufhead.b_next; 209 bufhead.b_next->b_prev = bp; 210 bufhead.b_next = bp; 211 bp->b_flags |= B_INUSE; 212 return (bp); 213 } 214 215 void 216 getblk(struct bufarea *bp, ufs2_daddr_t blk, long size) 217 { 218 ufs2_daddr_t dblk; 219 220 totalreads++; 221 dblk = fsbtodb(&sblock, blk); 222 if (bp->b_bno != dblk) { 223 flush(fswritefd, bp); 224 diskreads++; 225 bp->b_errs = blread(fsreadfd, bp->b_un.b_buf, dblk, size); 226 bp->b_bno = dblk; 227 bp->b_size = size; 228 } 229 } 230 231 void 232 flush(int fd, struct bufarea *bp) 233 { 234 int i, j; 235 236 if (!bp->b_dirty) 237 return; 238 bp->b_dirty = 0; 239 if (fswritefd < 0) { 240 pfatal("WRITING IN READ_ONLY MODE.\n"); 241 return; 242 } 243 if (bp->b_errs != 0) 244 pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", 245 (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 246 (long long)bp->b_bno); 247 bp->b_errs = 0; 248 blwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 249 if (bp != &sblk) 250 return; 251 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 252 blwrite(fswritefd, (char *)sblock.fs_csp + i, 253 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 254 sblock.fs_cssize - i < sblock.fs_bsize ? 255 sblock.fs_cssize - i : sblock.fs_bsize); 256 } 257 } 258 259 void 260 rwerror(const char *mesg, ufs2_daddr_t blk) 261 { 262 263 if (bkgrdcheck) 264 exit(EEXIT); 265 if (preen == 0) 266 printf("\n"); 267 pfatal("CANNOT %s: %ld", mesg, (long)blk); 268 if (reply("CONTINUE") == 0) 269 exit(EEXIT); 270 } 271 272 void 273 ckfini(int markclean) 274 { 275 struct bufarea *bp, *nbp; 276 int ofsmodified, cnt = 0; 277 278 if (bkgrdflag) { 279 unlink(snapname); 280 if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) { 281 cmd.value = FS_UNCLEAN; 282 cmd.size = markclean ? -1 : 1; 283 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 284 &cmd, sizeof cmd) == -1) 285 rwerror("SET FILE SYSTEM FLAGS", FS_UNCLEAN); 286 if (!preen) { 287 printf("\n***** FILE SYSTEM MARKED %s *****\n", 288 markclean ? "CLEAN" : "DIRTY"); 289 if (!markclean) 290 rerun = 1; 291 } 292 } else if (!preen && !markclean) { 293 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 294 rerun = 1; 295 } 296 } 297 if (fswritefd < 0) { 298 (void)close(fsreadfd); 299 return; 300 } 301 flush(fswritefd, &sblk); 302 if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC && 303 sblk.b_bno != sblock.fs_sblockloc / dev_bsize && 304 !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 305 sblk.b_bno = sblock.fs_sblockloc / dev_bsize; 306 sbdirty(); 307 flush(fswritefd, &sblk); 308 } 309 flush(fswritefd, &cgblk); 310 free(cgblk.b_un.b_buf); 311 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 312 cnt++; 313 flush(fswritefd, bp); 314 nbp = bp->b_prev; 315 free(bp->b_un.b_buf); 316 free((char *)bp); 317 } 318 if (bufhead.b_size != cnt) 319 errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt); 320 pbp = pdirbp = (struct bufarea *)0; 321 if (cursnapshot == 0 && sblock.fs_clean != markclean) { 322 if ((sblock.fs_clean = markclean) != 0) { 323 sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK); 324 sblock.fs_pendingblocks = 0; 325 sblock.fs_pendinginodes = 0; 326 } 327 sbdirty(); 328 ofsmodified = fsmodified; 329 flush(fswritefd, &sblk); 330 fsmodified = ofsmodified; 331 if (!preen) { 332 printf("\n***** FILE SYSTEM MARKED %s *****\n", 333 markclean ? "CLEAN" : "DIRTY"); 334 if (!markclean) 335 rerun = 1; 336 } 337 } else if (!preen) { 338 if (markclean) { 339 printf("\n***** FILE SYSTEM IS CLEAN *****\n"); 340 } else { 341 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 342 rerun = 1; 343 } 344 } 345 if (debug && totalreads > 0) 346 printf("cache missed %ld of %ld (%d%%)\n", diskreads, 347 totalreads, (int)(diskreads * 100 / totalreads)); 348 (void)close(fsreadfd); 349 (void)close(fswritefd); 350 } 351 352 int 353 blread(int fd, char *buf, ufs2_daddr_t blk, long size) 354 { 355 char *cp; 356 int i, errs; 357 off_t offset; 358 359 offset = blk; 360 offset *= dev_bsize; 361 if (bkgrdflag) 362 slowio_start(); 363 if (lseek(fd, offset, 0) < 0) 364 rwerror("SEEK BLK", blk); 365 else if (read(fd, buf, (int)size) == size) { 366 if (bkgrdflag) 367 slowio_end(); 368 return (0); 369 } 370 rwerror("READ BLK", blk); 371 if (lseek(fd, offset, 0) < 0) 372 rwerror("SEEK BLK", blk); 373 errs = 0; 374 memset(buf, 0, (size_t)size); 375 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 376 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 377 if (read(fd, cp, (int)secsize) != secsize) { 378 (void)lseek(fd, offset + i + secsize, 0); 379 if (secsize != dev_bsize && dev_bsize != 1) 380 printf(" %jd (%jd),", 381 (intmax_t)(blk * dev_bsize + i) / secsize, 382 (intmax_t)blk + i / dev_bsize); 383 else 384 printf(" %jd,", (intmax_t)blk + i / dev_bsize); 385 errs++; 386 } 387 } 388 printf("\n"); 389 if (errs) 390 resolved = 0; 391 return (errs); 392 } 393 394 void 395 blwrite(int fd, char *buf, ufs2_daddr_t blk, long size) 396 { 397 int i; 398 char *cp; 399 off_t offset; 400 401 if (fd < 0) 402 return; 403 offset = blk; 404 offset *= dev_bsize; 405 if (lseek(fd, offset, 0) < 0) 406 rwerror("SEEK BLK", blk); 407 else if (write(fd, buf, (int)size) == size) { 408 fsmodified = 1; 409 return; 410 } 411 resolved = 0; 412 rwerror("WRITE BLK", blk); 413 if (lseek(fd, offset, 0) < 0) 414 rwerror("SEEK BLK", blk); 415 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 416 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 417 if (write(fd, cp, (int)dev_bsize) != dev_bsize) { 418 (void)lseek(fd, offset + i + dev_bsize, 0); 419 printf(" %jd,", (intmax_t)blk + i / dev_bsize); 420 } 421 printf("\n"); 422 return; 423 } 424 425 void 426 blerase(int fd, ufs2_daddr_t blk, long size) 427 { 428 off_t ioarg[2]; 429 430 if (fd < 0) 431 return; 432 ioarg[0] = blk * dev_bsize; 433 ioarg[1] = size; 434 ioctl(fd, DIOCGDELETE, ioarg); 435 /* we don't really care if we succeed or not */ 436 return; 437 } 438 439 /* 440 * Verify cylinder group's magic number and other parameters. If the 441 * test fails, offer an option to rebuild the whole cylinder group. 442 */ 443 int 444 check_cgmagic(int cg, struct cg *cgp) 445 { 446 447 /* 448 * Extended cylinder group checks. 449 */ 450 if (cg_chkmagic(cgp) && 451 ((sblock.fs_magic == FS_UFS1_MAGIC && 452 cgp->cg_old_niblk == sblock.fs_ipg && 453 cgp->cg_ndblk <= sblock.fs_fpg && 454 cgp->cg_old_ncyl <= sblock.fs_old_cpg) || 455 (sblock.fs_magic == FS_UFS2_MAGIC && 456 cgp->cg_niblk == sblock.fs_ipg && 457 cgp->cg_ndblk <= sblock.fs_fpg && 458 cgp->cg_initediblk <= sblock.fs_ipg))) { 459 return (1); 460 } 461 pfatal("CYLINDER GROUP %d: BAD MAGIC NUMBER", cg); 462 if (!reply("REBUILD CYLINDER GROUP")) { 463 printf("YOU WILL NEED TO RERUN FSCK.\n"); 464 rerun = 1; 465 return (1); 466 } 467 /* 468 * Zero out the cylinder group and then initialize critical fields. 469 * Bit maps and summaries will be recalculated by later passes. 470 */ 471 memset(cgp, 0, (size_t)sblock.fs_cgsize); 472 cgp->cg_magic = CG_MAGIC; 473 cgp->cg_cgx = cg; 474 cgp->cg_niblk = sblock.fs_ipg; 475 cgp->cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ? 476 sblock.fs_ipg : 2 * INOPB(&sblock); 477 if (cgbase(&sblock, cg) + sblock.fs_fpg < sblock.fs_size) 478 cgp->cg_ndblk = sblock.fs_fpg; 479 else 480 cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg); 481 cgp->cg_iusedoff = &cgp->cg_space[0] - (u_char *)(&cgp->cg_firstfield); 482 if (sblock.fs_magic == FS_UFS1_MAGIC) { 483 cgp->cg_niblk = 0; 484 cgp->cg_initediblk = 0; 485 cgp->cg_old_ncyl = sblock.fs_old_cpg; 486 cgp->cg_old_niblk = sblock.fs_ipg; 487 cgp->cg_old_btotoff = cgp->cg_iusedoff; 488 cgp->cg_old_boff = cgp->cg_old_btotoff + 489 sblock.fs_old_cpg * sizeof(int32_t); 490 cgp->cg_iusedoff = cgp->cg_old_boff + 491 sblock.fs_old_cpg * sizeof(u_int16_t); 492 } 493 cgp->cg_freeoff = cgp->cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); 494 cgp->cg_nextfreeoff = cgp->cg_freeoff + howmany(sblock.fs_fpg,CHAR_BIT); 495 if (sblock.fs_contigsumsize > 0) { 496 cgp->cg_nclusterblks = cgp->cg_ndblk / sblock.fs_frag; 497 cgp->cg_clustersumoff = 498 roundup(cgp->cg_nextfreeoff, sizeof(u_int32_t)); 499 cgp->cg_clustersumoff -= sizeof(u_int32_t); 500 cgp->cg_clusteroff = cgp->cg_clustersumoff + 501 (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); 502 cgp->cg_nextfreeoff = cgp->cg_clusteroff + 503 howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); 504 } 505 cgdirty(); 506 return (0); 507 } 508 509 /* 510 * allocate a data block with the specified number of fragments 511 */ 512 ufs2_daddr_t 513 allocblk(long frags) 514 { 515 int i, j, k, cg, baseblk; 516 struct cg *cgp = &cgrp; 517 518 if (frags <= 0 || frags > sblock.fs_frag) 519 return (0); 520 for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 521 for (j = 0; j <= sblock.fs_frag - frags; j++) { 522 if (testbmap(i + j)) 523 continue; 524 for (k = 1; k < frags; k++) 525 if (testbmap(i + j + k)) 526 break; 527 if (k < frags) { 528 j += k; 529 continue; 530 } 531 cg = dtog(&sblock, i + j); 532 getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 533 if (!check_cgmagic(cg, cgp)) 534 return (0); 535 baseblk = dtogd(&sblock, i + j); 536 for (k = 0; k < frags; k++) { 537 setbmap(i + j + k); 538 clrbit(cg_blksfree(cgp), baseblk + k); 539 } 540 n_blks += frags; 541 if (frags == sblock.fs_frag) 542 cgp->cg_cs.cs_nbfree--; 543 else 544 cgp->cg_cs.cs_nffree -= frags; 545 cgdirty(); 546 return (i + j); 547 } 548 } 549 return (0); 550 } 551 552 /* 553 * Free a previously allocated block 554 */ 555 void 556 freeblk(ufs2_daddr_t blkno, long frags) 557 { 558 struct inodesc idesc; 559 560 idesc.id_blkno = blkno; 561 idesc.id_numfrags = frags; 562 (void)pass4check(&idesc); 563 } 564 565 /* Slow down IO so as to leave some disk bandwidth for other processes */ 566 void 567 slowio_start() 568 { 569 570 /* Delay one in every 8 operations */ 571 slowio_pollcnt = (slowio_pollcnt + 1) & 7; 572 if (slowio_pollcnt == 0) { 573 gettimeofday(&slowio_starttime, NULL); 574 } 575 } 576 577 void 578 slowio_end() 579 { 580 struct timeval tv; 581 int delay_usec; 582 583 if (slowio_pollcnt != 0) 584 return; 585 586 /* Update the slowdown interval. */ 587 gettimeofday(&tv, NULL); 588 delay_usec = (tv.tv_sec - slowio_starttime.tv_sec) * 1000000 + 589 (tv.tv_usec - slowio_starttime.tv_usec); 590 if (delay_usec < 64) 591 delay_usec = 64; 592 if (delay_usec > 2500000) 593 delay_usec = 2500000; 594 slowio_delay_usec = (slowio_delay_usec * 63 + delay_usec) >> 6; 595 /* delay by 8 times the average IO delay */ 596 if (slowio_delay_usec > 64) 597 usleep(slowio_delay_usec * 8); 598 } 599 600 /* 601 * Find a pathname 602 */ 603 void 604 getpathname(char *namebuf, ino_t curdir, ino_t ino) 605 { 606 int len; 607 char *cp; 608 struct inodesc idesc; 609 static int busy = 0; 610 611 if (curdir == ino && ino == ROOTINO) { 612 (void)strcpy(namebuf, "/"); 613 return; 614 } 615 if (busy || !INO_IS_DVALID(curdir)) { 616 (void)strcpy(namebuf, "?"); 617 return; 618 } 619 busy = 1; 620 memset(&idesc, 0, sizeof(struct inodesc)); 621 idesc.id_type = DATA; 622 idesc.id_fix = IGNORE; 623 cp = &namebuf[MAXPATHLEN - 1]; 624 *cp = '\0'; 625 if (curdir != ino) { 626 idesc.id_parent = curdir; 627 goto namelookup; 628 } 629 while (ino != ROOTINO) { 630 idesc.id_number = ino; 631 idesc.id_func = findino; 632 idesc.id_name = strdup(".."); 633 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 634 break; 635 namelookup: 636 idesc.id_number = idesc.id_parent; 637 idesc.id_parent = ino; 638 idesc.id_func = findname; 639 idesc.id_name = namebuf; 640 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 641 break; 642 len = strlen(namebuf); 643 cp -= len; 644 memmove(cp, namebuf, (size_t)len); 645 *--cp = '/'; 646 if (cp < &namebuf[MAXNAMLEN]) 647 break; 648 ino = idesc.id_number; 649 } 650 busy = 0; 651 if (ino != ROOTINO) 652 *--cp = '?'; 653 memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 654 } 655 656 void 657 catch(int sig __unused) 658 { 659 660 ckfini(0); 661 exit(12); 662 } 663 664 /* 665 * When preening, allow a single quit to signal 666 * a special exit after file system checks complete 667 * so that reboot sequence may be interrupted. 668 */ 669 void 670 catchquit(int sig __unused) 671 { 672 printf("returning to single-user after file system check\n"); 673 returntosingle = 1; 674 (void)signal(SIGQUIT, SIG_DFL); 675 } 676 677 /* 678 * determine whether an inode should be fixed. 679 */ 680 int 681 dofix(struct inodesc *idesc, const char *msg) 682 { 683 684 switch (idesc->id_fix) { 685 686 case DONTKNOW: 687 if (idesc->id_type == DATA) 688 direrror(idesc->id_number, msg); 689 else 690 pwarn("%s", msg); 691 if (preen) { 692 printf(" (SALVAGED)\n"); 693 idesc->id_fix = FIX; 694 return (ALTERED); 695 } 696 if (reply("SALVAGE") == 0) { 697 idesc->id_fix = NOFIX; 698 return (0); 699 } 700 idesc->id_fix = FIX; 701 return (ALTERED); 702 703 case FIX: 704 return (ALTERED); 705 706 case NOFIX: 707 case IGNORE: 708 return (0); 709 710 default: 711 errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 712 } 713 /* NOTREACHED */ 714 return (0); 715 } 716 717 #include <stdarg.h> 718 719 /* 720 * An unexpected inconsistency occured. 721 * Die if preening or file system is running with soft dependency protocol, 722 * otherwise just print message and continue. 723 */ 724 void 725 pfatal(const char *fmt, ...) 726 { 727 va_list ap; 728 va_start(ap, fmt); 729 if (!preen) { 730 (void)vfprintf(stdout, fmt, ap); 731 va_end(ap); 732 if (usedsoftdep) 733 (void)fprintf(stdout, 734 "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n"); 735 /* 736 * Force foreground fsck to clean up inconsistency. 737 */ 738 if (bkgrdflag) { 739 cmd.value = FS_NEEDSFSCK; 740 cmd.size = 1; 741 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 742 &cmd, sizeof cmd) == -1) 743 pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 744 fprintf(stdout, "CANNOT RUN IN BACKGROUND\n"); 745 ckfini(0); 746 exit(EEXIT); 747 } 748 return; 749 } 750 if (cdevname == NULL) 751 cdevname = strdup("fsck"); 752 (void)fprintf(stdout, "%s: ", cdevname); 753 (void)vfprintf(stdout, fmt, ap); 754 (void)fprintf(stdout, 755 "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n", 756 cdevname, usedsoftdep ? " SOFT UPDATE " : " "); 757 /* 758 * Force foreground fsck to clean up inconsistency. 759 */ 760 if (bkgrdflag) { 761 cmd.value = FS_NEEDSFSCK; 762 cmd.size = 1; 763 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 764 &cmd, sizeof cmd) == -1) 765 pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 766 } 767 ckfini(0); 768 exit(EEXIT); 769 } 770 771 /* 772 * Pwarn just prints a message when not preening or running soft dependency 773 * protocol, or a warning (preceded by filename) when preening. 774 */ 775 void 776 pwarn(const char *fmt, ...) 777 { 778 va_list ap; 779 va_start(ap, fmt); 780 if (preen) 781 (void)fprintf(stdout, "%s: ", cdevname); 782 (void)vfprintf(stdout, fmt, ap); 783 va_end(ap); 784 } 785 786 /* 787 * Stub for routines from kernel. 788 */ 789 void 790 panic(const char *fmt, ...) 791 { 792 va_list ap; 793 va_start(ap, fmt); 794 pfatal("INTERNAL INCONSISTENCY:"); 795 (void)vfprintf(stdout, fmt, ap); 796 va_end(ap); 797 exit(EEXIT); 798 } 799