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