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