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 %ju out of range", 141 (uintmax_t)inum); 142 ilp = &inostathead[inum / sblock.fs_ipg]; 143 iloff = inum % sblock.fs_ipg; 144 if (iloff >= ilp->il_numalloced) 145 return (&unallocated); 146 return (&ilp->il_stat[iloff]); 147 } 148 149 /* 150 * Malloc buffers and set up cache. 151 */ 152 void 153 bufinit(void) 154 { 155 struct bufarea *bp; 156 long bufcnt, i; 157 char *bufp; 158 159 pbp = pdirbp = (struct bufarea *)0; 160 bufp = malloc((unsigned int)sblock.fs_bsize); 161 if (bufp == 0) 162 errx(EEXIT, "cannot allocate buffer pool"); 163 cgblk.b_un.b_buf = bufp; 164 initbarea(&cgblk); 165 bufhead.b_next = bufhead.b_prev = &bufhead; 166 bufcnt = MAXBUFSPACE / sblock.fs_bsize; 167 if (bufcnt < MINBUFS) 168 bufcnt = MINBUFS; 169 for (i = 0; i < bufcnt; i++) { 170 bp = (struct bufarea *)malloc(sizeof(struct bufarea)); 171 bufp = malloc((unsigned int)sblock.fs_bsize); 172 if (bp == NULL || bufp == NULL) { 173 if (i >= MINBUFS) 174 break; 175 errx(EEXIT, "cannot allocate buffer pool"); 176 } 177 bp->b_un.b_buf = bufp; 178 bp->b_prev = &bufhead; 179 bp->b_next = bufhead.b_next; 180 bufhead.b_next->b_prev = bp; 181 bufhead.b_next = bp; 182 initbarea(bp); 183 } 184 bufhead.b_size = i; /* save number of buffers */ 185 } 186 187 /* 188 * Manage a cache of directory blocks. 189 */ 190 struct bufarea * 191 getdatablk(ufs2_daddr_t blkno, long size) 192 { 193 struct bufarea *bp; 194 195 for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 196 if (bp->b_bno == fsbtodb(&sblock, blkno)) 197 goto foundit; 198 for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 199 if ((bp->b_flags & B_INUSE) == 0) 200 break; 201 if (bp == &bufhead) 202 errx(EEXIT, "deadlocked buffer pool"); 203 getblk(bp, blkno, size); 204 /* fall through */ 205 foundit: 206 bp->b_prev->b_next = bp->b_next; 207 bp->b_next->b_prev = bp->b_prev; 208 bp->b_prev = &bufhead; 209 bp->b_next = bufhead.b_next; 210 bufhead.b_next->b_prev = bp; 211 bufhead.b_next = bp; 212 bp->b_flags |= B_INUSE; 213 return (bp); 214 } 215 216 void 217 getblk(struct bufarea *bp, ufs2_daddr_t blk, long size) 218 { 219 ufs2_daddr_t dblk; 220 221 totalreads++; 222 dblk = fsbtodb(&sblock, blk); 223 if (bp->b_bno != dblk) { 224 flush(fswritefd, bp); 225 diskreads++; 226 bp->b_errs = blread(fsreadfd, bp->b_un.b_buf, dblk, size); 227 bp->b_bno = dblk; 228 bp->b_size = size; 229 } 230 } 231 232 void 233 flush(int fd, struct bufarea *bp) 234 { 235 int i, j; 236 237 if (!bp->b_dirty) 238 return; 239 bp->b_dirty = 0; 240 if (fswritefd < 0) { 241 pfatal("WRITING IN READ_ONLY MODE.\n"); 242 return; 243 } 244 if (bp->b_errs != 0) 245 pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", 246 (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 247 (long long)bp->b_bno); 248 bp->b_errs = 0; 249 blwrite(fd, bp->b_un.b_buf, bp->b_bno, bp->b_size); 250 if (bp != &sblk) 251 return; 252 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 253 blwrite(fswritefd, (char *)sblock.fs_csp + i, 254 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 255 sblock.fs_cssize - i < sblock.fs_bsize ? 256 sblock.fs_cssize - i : sblock.fs_bsize); 257 } 258 } 259 260 void 261 rwerror(const char *mesg, ufs2_daddr_t blk) 262 { 263 264 if (bkgrdcheck) 265 exit(EEXIT); 266 if (preen == 0) 267 printf("\n"); 268 pfatal("CANNOT %s: %ld", mesg, (long)blk); 269 if (reply("CONTINUE") == 0) 270 exit(EEXIT); 271 } 272 273 void 274 ckfini(int markclean) 275 { 276 struct bufarea *bp, *nbp; 277 int ofsmodified, cnt = 0; 278 279 if (bkgrdflag) { 280 unlink(snapname); 281 if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) { 282 cmd.value = FS_UNCLEAN; 283 cmd.size = markclean ? -1 : 1; 284 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 285 &cmd, sizeof cmd) == -1) 286 rwerror("SET FILE SYSTEM FLAGS", FS_UNCLEAN); 287 if (!preen) { 288 printf("\n***** FILE SYSTEM MARKED %s *****\n", 289 markclean ? "CLEAN" : "DIRTY"); 290 if (!markclean) 291 rerun = 1; 292 } 293 } else if (!preen && !markclean) { 294 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 295 rerun = 1; 296 } 297 } 298 if (fswritefd < 0) { 299 (void)close(fsreadfd); 300 return; 301 } 302 flush(fswritefd, &sblk); 303 if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC && 304 sblk.b_bno != sblock.fs_sblockloc / dev_bsize && 305 !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 306 sblk.b_bno = sblock.fs_sblockloc / dev_bsize; 307 sbdirty(); 308 flush(fswritefd, &sblk); 309 } 310 flush(fswritefd, &cgblk); 311 free(cgblk.b_un.b_buf); 312 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 313 cnt++; 314 flush(fswritefd, bp); 315 nbp = bp->b_prev; 316 free(bp->b_un.b_buf); 317 free((char *)bp); 318 } 319 if (bufhead.b_size != cnt) 320 errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt); 321 pbp = pdirbp = (struct bufarea *)0; 322 if (cursnapshot == 0 && sblock.fs_clean != markclean) { 323 if ((sblock.fs_clean = markclean) != 0) { 324 sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK); 325 sblock.fs_pendingblocks = 0; 326 sblock.fs_pendinginodes = 0; 327 } 328 sbdirty(); 329 ofsmodified = fsmodified; 330 flush(fswritefd, &sblk); 331 fsmodified = ofsmodified; 332 if (!preen) { 333 printf("\n***** FILE SYSTEM MARKED %s *****\n", 334 markclean ? "CLEAN" : "DIRTY"); 335 if (!markclean) 336 rerun = 1; 337 } 338 } else if (!preen) { 339 if (markclean) { 340 printf("\n***** FILE SYSTEM IS CLEAN *****\n"); 341 } else { 342 printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 343 rerun = 1; 344 } 345 } 346 if (debug && totalreads > 0) 347 printf("cache missed %ld of %ld (%d%%)\n", diskreads, 348 totalreads, (int)(diskreads * 100 / totalreads)); 349 (void)close(fsreadfd); 350 (void)close(fswritefd); 351 } 352 353 int 354 blread(int fd, char *buf, ufs2_daddr_t blk, long size) 355 { 356 char *cp; 357 int i, errs; 358 off_t offset; 359 360 offset = blk; 361 offset *= dev_bsize; 362 if (bkgrdflag) 363 slowio_start(); 364 if (lseek(fd, offset, 0) < 0) 365 rwerror("SEEK BLK", blk); 366 else if (read(fd, buf, (int)size) == size) { 367 if (bkgrdflag) 368 slowio_end(); 369 return (0); 370 } 371 rwerror("READ BLK", blk); 372 if (lseek(fd, offset, 0) < 0) 373 rwerror("SEEK BLK", blk); 374 errs = 0; 375 memset(buf, 0, (size_t)size); 376 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 377 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 378 if (read(fd, cp, (int)secsize) != secsize) { 379 (void)lseek(fd, offset + i + secsize, 0); 380 if (secsize != dev_bsize && dev_bsize != 1) 381 printf(" %jd (%jd),", 382 (intmax_t)(blk * dev_bsize + i) / secsize, 383 (intmax_t)blk + i / dev_bsize); 384 else 385 printf(" %jd,", (intmax_t)blk + i / dev_bsize); 386 errs++; 387 } 388 } 389 printf("\n"); 390 if (errs) 391 resolved = 0; 392 return (errs); 393 } 394 395 void 396 blwrite(int fd, char *buf, ufs2_daddr_t blk, ssize_t size) 397 { 398 int i; 399 char *cp; 400 off_t offset; 401 402 if (fd < 0) 403 return; 404 offset = blk; 405 offset *= dev_bsize; 406 if (lseek(fd, offset, 0) < 0) 407 rwerror("SEEK BLK", blk); 408 else if (write(fd, buf, size) == size) { 409 fsmodified = 1; 410 return; 411 } 412 resolved = 0; 413 rwerror("WRITE BLK", blk); 414 if (lseek(fd, offset, 0) < 0) 415 rwerror("SEEK BLK", blk); 416 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 417 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 418 if (write(fd, cp, dev_bsize) != dev_bsize) { 419 (void)lseek(fd, offset + i + dev_bsize, 0); 420 printf(" %jd,", (intmax_t)blk + i / dev_bsize); 421 } 422 printf("\n"); 423 return; 424 } 425 426 void 427 blerase(int fd, ufs2_daddr_t blk, long size) 428 { 429 off_t ioarg[2]; 430 431 if (fd < 0) 432 return; 433 ioarg[0] = blk * dev_bsize; 434 ioarg[1] = size; 435 ioctl(fd, DIOCGDELETE, ioarg); 436 /* we don't really care if we succeed or not */ 437 return; 438 } 439 440 /* 441 * Verify cylinder group's magic number and other parameters. If the 442 * test fails, offer an option to rebuild the whole cylinder group. 443 */ 444 int 445 check_cgmagic(int cg, struct cg *cgp) 446 { 447 448 /* 449 * Extended cylinder group checks. 450 */ 451 if (cg_chkmagic(cgp) && 452 ((sblock.fs_magic == FS_UFS1_MAGIC && 453 cgp->cg_old_niblk == sblock.fs_ipg && 454 cgp->cg_ndblk <= sblock.fs_fpg && 455 cgp->cg_old_ncyl <= sblock.fs_old_cpg) || 456 (sblock.fs_magic == FS_UFS2_MAGIC && 457 cgp->cg_niblk == sblock.fs_ipg && 458 cgp->cg_ndblk <= sblock.fs_fpg && 459 cgp->cg_initediblk <= sblock.fs_ipg))) { 460 return (1); 461 } 462 pfatal("CYLINDER GROUP %d: BAD MAGIC NUMBER", cg); 463 if (!reply("REBUILD CYLINDER GROUP")) { 464 printf("YOU WILL NEED TO RERUN FSCK.\n"); 465 rerun = 1; 466 return (1); 467 } 468 /* 469 * Zero out the cylinder group and then initialize critical fields. 470 * Bit maps and summaries will be recalculated by later passes. 471 */ 472 memset(cgp, 0, (size_t)sblock.fs_cgsize); 473 cgp->cg_magic = CG_MAGIC; 474 cgp->cg_cgx = cg; 475 cgp->cg_niblk = sblock.fs_ipg; 476 cgp->cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ? 477 sblock.fs_ipg : 2 * INOPB(&sblock); 478 if (cgbase(&sblock, cg) + sblock.fs_fpg < sblock.fs_size) 479 cgp->cg_ndblk = sblock.fs_fpg; 480 else 481 cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg); 482 cgp->cg_iusedoff = &cgp->cg_space[0] - (u_char *)(&cgp->cg_firstfield); 483 if (sblock.fs_magic == FS_UFS1_MAGIC) { 484 cgp->cg_niblk = 0; 485 cgp->cg_initediblk = 0; 486 cgp->cg_old_ncyl = sblock.fs_old_cpg; 487 cgp->cg_old_niblk = sblock.fs_ipg; 488 cgp->cg_old_btotoff = cgp->cg_iusedoff; 489 cgp->cg_old_boff = cgp->cg_old_btotoff + 490 sblock.fs_old_cpg * sizeof(int32_t); 491 cgp->cg_iusedoff = cgp->cg_old_boff + 492 sblock.fs_old_cpg * sizeof(u_int16_t); 493 } 494 cgp->cg_freeoff = cgp->cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); 495 cgp->cg_nextfreeoff = cgp->cg_freeoff + howmany(sblock.fs_fpg,CHAR_BIT); 496 if (sblock.fs_contigsumsize > 0) { 497 cgp->cg_nclusterblks = cgp->cg_ndblk / sblock.fs_frag; 498 cgp->cg_clustersumoff = 499 roundup(cgp->cg_nextfreeoff, sizeof(u_int32_t)); 500 cgp->cg_clustersumoff -= sizeof(u_int32_t); 501 cgp->cg_clusteroff = cgp->cg_clustersumoff + 502 (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t); 503 cgp->cg_nextfreeoff = cgp->cg_clusteroff + 504 howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); 505 } 506 cgdirty(); 507 return (0); 508 } 509 510 /* 511 * allocate a data block with the specified number of fragments 512 */ 513 ufs2_daddr_t 514 allocblk(long frags) 515 { 516 int i, j, k, cg, baseblk; 517 struct cg *cgp = &cgrp; 518 519 if (frags <= 0 || frags > sblock.fs_frag) 520 return (0); 521 for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 522 for (j = 0; j <= sblock.fs_frag - frags; j++) { 523 if (testbmap(i + j)) 524 continue; 525 for (k = 1; k < frags; k++) 526 if (testbmap(i + j + k)) 527 break; 528 if (k < frags) { 529 j += k; 530 continue; 531 } 532 cg = dtog(&sblock, i + j); 533 getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 534 if (!check_cgmagic(cg, cgp)) 535 return (0); 536 baseblk = dtogd(&sblock, i + j); 537 for (k = 0; k < frags; k++) { 538 setbmap(i + j + k); 539 clrbit(cg_blksfree(cgp), baseblk + k); 540 } 541 n_blks += frags; 542 if (frags == sblock.fs_frag) 543 cgp->cg_cs.cs_nbfree--; 544 else 545 cgp->cg_cs.cs_nffree -= frags; 546 cgdirty(); 547 return (i + j); 548 } 549 } 550 return (0); 551 } 552 553 /* 554 * Free a previously allocated block 555 */ 556 void 557 freeblk(ufs2_daddr_t blkno, long frags) 558 { 559 struct inodesc idesc; 560 561 idesc.id_blkno = blkno; 562 idesc.id_numfrags = frags; 563 (void)pass4check(&idesc); 564 } 565 566 /* Slow down IO so as to leave some disk bandwidth for other processes */ 567 void 568 slowio_start() 569 { 570 571 /* Delay one in every 8 operations */ 572 slowio_pollcnt = (slowio_pollcnt + 1) & 7; 573 if (slowio_pollcnt == 0) { 574 gettimeofday(&slowio_starttime, NULL); 575 } 576 } 577 578 void 579 slowio_end() 580 { 581 struct timeval tv; 582 int delay_usec; 583 584 if (slowio_pollcnt != 0) 585 return; 586 587 /* Update the slowdown interval. */ 588 gettimeofday(&tv, NULL); 589 delay_usec = (tv.tv_sec - slowio_starttime.tv_sec) * 1000000 + 590 (tv.tv_usec - slowio_starttime.tv_usec); 591 if (delay_usec < 64) 592 delay_usec = 64; 593 if (delay_usec > 2500000) 594 delay_usec = 2500000; 595 slowio_delay_usec = (slowio_delay_usec * 63 + delay_usec) >> 6; 596 /* delay by 8 times the average IO delay */ 597 if (slowio_delay_usec > 64) 598 usleep(slowio_delay_usec * 8); 599 } 600 601 /* 602 * Find a pathname 603 */ 604 void 605 getpathname(char *namebuf, ino_t curdir, ino_t ino) 606 { 607 int len; 608 char *cp; 609 struct inodesc idesc; 610 static int busy = 0; 611 612 if (curdir == ino && ino == ROOTINO) { 613 (void)strcpy(namebuf, "/"); 614 return; 615 } 616 if (busy || !INO_IS_DVALID(curdir)) { 617 (void)strcpy(namebuf, "?"); 618 return; 619 } 620 busy = 1; 621 memset(&idesc, 0, sizeof(struct inodesc)); 622 idesc.id_type = DATA; 623 idesc.id_fix = IGNORE; 624 cp = &namebuf[MAXPATHLEN - 1]; 625 *cp = '\0'; 626 if (curdir != ino) { 627 idesc.id_parent = curdir; 628 goto namelookup; 629 } 630 while (ino != ROOTINO) { 631 idesc.id_number = ino; 632 idesc.id_func = findino; 633 idesc.id_name = strdup(".."); 634 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 635 break; 636 namelookup: 637 idesc.id_number = idesc.id_parent; 638 idesc.id_parent = ino; 639 idesc.id_func = findname; 640 idesc.id_name = namebuf; 641 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 642 break; 643 len = strlen(namebuf); 644 cp -= len; 645 memmove(cp, namebuf, (size_t)len); 646 *--cp = '/'; 647 if (cp < &namebuf[MAXNAMLEN]) 648 break; 649 ino = idesc.id_number; 650 } 651 busy = 0; 652 if (ino != ROOTINO) 653 *--cp = '?'; 654 memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 655 } 656 657 void 658 catch(int sig __unused) 659 { 660 661 ckfini(0); 662 exit(12); 663 } 664 665 /* 666 * When preening, allow a single quit to signal 667 * a special exit after file system checks complete 668 * so that reboot sequence may be interrupted. 669 */ 670 void 671 catchquit(int sig __unused) 672 { 673 printf("returning to single-user after file system check\n"); 674 returntosingle = 1; 675 (void)signal(SIGQUIT, SIG_DFL); 676 } 677 678 /* 679 * determine whether an inode should be fixed. 680 */ 681 int 682 dofix(struct inodesc *idesc, const char *msg) 683 { 684 685 switch (idesc->id_fix) { 686 687 case DONTKNOW: 688 if (idesc->id_type == DATA) 689 direrror(idesc->id_number, msg); 690 else 691 pwarn("%s", msg); 692 if (preen) { 693 printf(" (SALVAGED)\n"); 694 idesc->id_fix = FIX; 695 return (ALTERED); 696 } 697 if (reply("SALVAGE") == 0) { 698 idesc->id_fix = NOFIX; 699 return (0); 700 } 701 idesc->id_fix = FIX; 702 return (ALTERED); 703 704 case FIX: 705 return (ALTERED); 706 707 case NOFIX: 708 case IGNORE: 709 return (0); 710 711 default: 712 errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 713 } 714 /* NOTREACHED */ 715 return (0); 716 } 717 718 #include <stdarg.h> 719 720 /* 721 * An unexpected inconsistency occurred. 722 * Die if preening or file system is running with soft dependency protocol, 723 * otherwise just print message and continue. 724 */ 725 void 726 pfatal(const char *fmt, ...) 727 { 728 va_list ap; 729 va_start(ap, fmt); 730 if (!preen) { 731 (void)vfprintf(stdout, fmt, ap); 732 va_end(ap); 733 if (usedsoftdep) 734 (void)fprintf(stdout, 735 "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n"); 736 /* 737 * Force foreground fsck to clean up inconsistency. 738 */ 739 if (bkgrdflag) { 740 cmd.value = FS_NEEDSFSCK; 741 cmd.size = 1; 742 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 743 &cmd, sizeof cmd) == -1) 744 pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 745 fprintf(stdout, "CANNOT RUN IN BACKGROUND\n"); 746 ckfini(0); 747 exit(EEXIT); 748 } 749 return; 750 } 751 if (cdevname == NULL) 752 cdevname = strdup("fsck"); 753 (void)fprintf(stdout, "%s: ", cdevname); 754 (void)vfprintf(stdout, fmt, ap); 755 (void)fprintf(stdout, 756 "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n", 757 cdevname, usedsoftdep ? " SOFT UPDATE " : " "); 758 /* 759 * Force foreground fsck to clean up inconsistency. 760 */ 761 if (bkgrdflag) { 762 cmd.value = FS_NEEDSFSCK; 763 cmd.size = 1; 764 if (sysctlbyname("vfs.ffs.setflags", 0, 0, 765 &cmd, sizeof cmd) == -1) 766 pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n"); 767 } 768 ckfini(0); 769 exit(EEXIT); 770 } 771 772 /* 773 * Pwarn just prints a message when not preening or running soft dependency 774 * protocol, or a warning (preceded by filename) when preening. 775 */ 776 void 777 pwarn(const char *fmt, ...) 778 { 779 va_list ap; 780 va_start(ap, fmt); 781 if (preen) 782 (void)fprintf(stdout, "%s: ", cdevname); 783 (void)vfprintf(stdout, fmt, ap); 784 va_end(ap); 785 } 786 787 /* 788 * Stub for routines from kernel. 789 */ 790 void 791 panic(const char *fmt, ...) 792 { 793 va_list ap; 794 va_start(ap, fmt); 795 pfatal("INTERNAL INCONSISTENCY:"); 796 (void)vfprintf(stdout, fmt, ap); 797 va_end(ap); 798 exit(EEXIT); 799 } 800