|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980, 1986 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)utilities.c 5.29 (Berkeley) 7/27/90"; ! 22: #endif /* not lint */ ! 23: ! 24: #include <sys/param.h> ! 25: #include <ufs/dinode.h> ! 26: #include <ufs/fs.h> ! 27: #include <ufs/dir.h> ! 28: #include <stdio.h> ! 29: #include <stdlib.h> ! 30: #include <string.h> ! 31: #include <ctype.h> ! 32: #include "fsck.h" ! 33: ! 34: long diskreads, totalreads; /* Disk cache statistics */ ! 35: long lseek(); ! 36: ! 37: ftypeok(dp) ! 38: struct dinode *dp; ! 39: { ! 40: switch (dp->di_mode & IFMT) { ! 41: ! 42: case IFDIR: ! 43: case IFREG: ! 44: case IFBLK: ! 45: case IFCHR: ! 46: case IFLNK: ! 47: case IFSOCK: ! 48: case IFIFO: ! 49: return (1); ! 50: ! 51: default: ! 52: if (debug) ! 53: printf("bad file type 0%o\n", dp->di_mode); ! 54: return (0); ! 55: } ! 56: } ! 57: ! 58: reply(question) ! 59: char *question; ! 60: { ! 61: int persevere; ! 62: char c; ! 63: ! 64: if (preen) ! 65: pfatal("INTERNAL ERROR: GOT TO reply()"); ! 66: persevere = !strcmp(question, "CONTINUE"); ! 67: printf("\n"); ! 68: if (!persevere && (nflag || fswritefd < 0)) { ! 69: printf("%s? no\n\n", question); ! 70: return (0); ! 71: } ! 72: if (yflag || (persevere && nflag)) { ! 73: printf("%s? yes\n\n", question); ! 74: return (1); ! 75: } ! 76: do { ! 77: printf("%s? [yn] ", question); ! 78: (void) fflush(stdout); ! 79: c = getc(stdin); ! 80: while (c != '\n' && getc(stdin) != '\n') ! 81: if (feof(stdin)) ! 82: return (0); ! 83: } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); ! 84: printf("\n"); ! 85: if (c == 'y' || c == 'Y') ! 86: return (1); ! 87: return (0); ! 88: } ! 89: ! 90: /* ! 91: * Malloc buffers and set up cache. ! 92: */ ! 93: bufinit() ! 94: { ! 95: register struct bufarea *bp; ! 96: long bufcnt, i; ! 97: char *bufp; ! 98: ! 99: pbp = pdirbp = (struct bufarea *)0; ! 100: bufp = malloc((unsigned int)sblock.fs_bsize); ! 101: if (bufp == 0) ! 102: errexit("cannot allocate buffer pool\n"); ! 103: cgblk.b_un.b_buf = bufp; ! 104: initbarea(&cgblk); ! 105: bufhead.b_next = bufhead.b_prev = &bufhead; ! 106: bufcnt = MAXBUFSPACE / sblock.fs_bsize; ! 107: if (bufcnt < MINBUFS) ! 108: bufcnt = MINBUFS; ! 109: for (i = 0; i < bufcnt; i++) { ! 110: bp = (struct bufarea *)malloc(sizeof(struct bufarea)); ! 111: bufp = malloc((unsigned int)sblock.fs_bsize); ! 112: if (bp == NULL || bufp == NULL) { ! 113: if (i >= MINBUFS) ! 114: break; ! 115: errexit("cannot allocate buffer pool\n"); ! 116: } ! 117: bp->b_un.b_buf = bufp; ! 118: bp->b_prev = &bufhead; ! 119: bp->b_next = bufhead.b_next; ! 120: bufhead.b_next->b_prev = bp; ! 121: bufhead.b_next = bp; ! 122: initbarea(bp); ! 123: } ! 124: bufhead.b_size = i; /* save number of buffers */ ! 125: } ! 126: ! 127: /* ! 128: * Manage a cache of directory blocks. ! 129: */ ! 130: struct bufarea * ! 131: getdatablk(blkno, size) ! 132: daddr_t blkno; ! 133: long size; ! 134: { ! 135: register struct bufarea *bp; ! 136: ! 137: for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) ! 138: if (bp->b_bno == fsbtodb(&sblock, blkno)) ! 139: goto foundit; ! 140: for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) ! 141: if ((bp->b_flags & B_INUSE) == 0) ! 142: break; ! 143: if (bp == &bufhead) ! 144: errexit("deadlocked buffer pool\n"); ! 145: getblk(bp, blkno, size); ! 146: /* fall through */ ! 147: foundit: ! 148: totalreads++; ! 149: bp->b_prev->b_next = bp->b_next; ! 150: bp->b_next->b_prev = bp->b_prev; ! 151: bp->b_prev = &bufhead; ! 152: bp->b_next = bufhead.b_next; ! 153: bufhead.b_next->b_prev = bp; ! 154: bufhead.b_next = bp; ! 155: bp->b_flags |= B_INUSE; ! 156: return (bp); ! 157: } ! 158: ! 159: void ! 160: getblk(bp, blk, size) ! 161: register struct bufarea *bp; ! 162: daddr_t blk; ! 163: long size; ! 164: { ! 165: daddr_t dblk; ! 166: ! 167: dblk = fsbtodb(&sblock, blk); ! 168: if (bp->b_bno != dblk) { ! 169: flush(fswritefd, bp); ! 170: diskreads++; ! 171: bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); ! 172: bp->b_bno = dblk; ! 173: bp->b_size = size; ! 174: } ! 175: } ! 176: ! 177: flush(fd, bp) ! 178: int fd; ! 179: register struct bufarea *bp; ! 180: { ! 181: register int i, j; ! 182: ! 183: if (!bp->b_dirty) ! 184: return; ! 185: if (bp->b_errs != 0) ! 186: pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", ! 187: (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", ! 188: bp->b_bno); ! 189: bp->b_dirty = 0; ! 190: bp->b_errs = 0; ! 191: bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); ! 192: if (bp != &sblk) ! 193: return; ! 194: for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { ! 195: bwrite(fswritefd, (char *)sblock.fs_csp[j], ! 196: fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), ! 197: sblock.fs_cssize - i < sblock.fs_bsize ? ! 198: sblock.fs_cssize - i : sblock.fs_bsize); ! 199: } ! 200: } ! 201: ! 202: rwerror(mesg, blk) ! 203: char *mesg; ! 204: daddr_t blk; ! 205: { ! 206: ! 207: if (preen == 0) ! 208: printf("\n"); ! 209: pfatal("CANNOT %s: BLK %ld", mesg, blk); ! 210: if (reply("CONTINUE") == 0) ! 211: errexit("Program terminated\n"); ! 212: } ! 213: ! 214: ckfini() ! 215: { ! 216: register struct bufarea *bp, *nbp; ! 217: int cnt = 0; ! 218: ! 219: flush(fswritefd, &sblk); ! 220: if (havesb && sblk.b_bno != SBOFF / dev_bsize && ! 221: !preen && reply("UPDATE STANDARD SUPERBLOCK")) { ! 222: sblk.b_bno = SBOFF / dev_bsize; ! 223: sbdirty(); ! 224: flush(fswritefd, &sblk); ! 225: } ! 226: flush(fswritefd, &cgblk); ! 227: free(cgblk.b_un.b_buf); ! 228: for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) { ! 229: cnt++; ! 230: flush(fswritefd, bp); ! 231: nbp = bp->b_prev; ! 232: free(bp->b_un.b_buf); ! 233: free((char *)bp); ! 234: } ! 235: if (bufhead.b_size != cnt) ! 236: errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); ! 237: pbp = pdirbp = (struct bufarea *)0; ! 238: if (debug) ! 239: printf("cache missed %ld of %ld (%d%%)\n", diskreads, ! 240: totalreads, (int)(diskreads * 100 / totalreads)); ! 241: (void)close(fsreadfd); ! 242: (void)close(fswritefd); ! 243: } ! 244: ! 245: bread(fd, buf, blk, size) ! 246: int fd; ! 247: char *buf; ! 248: daddr_t blk; ! 249: long size; ! 250: { ! 251: char *cp; ! 252: int i, errs; ! 253: ! 254: if (lseek(fd, blk * dev_bsize, 0) < 0) ! 255: rwerror("SEEK", blk); ! 256: else if (read(fd, buf, (int)size) == size) ! 257: return (0); ! 258: rwerror("READ", blk); ! 259: if (lseek(fd, blk * dev_bsize, 0) < 0) ! 260: rwerror("SEEK", blk); ! 261: errs = 0; ! 262: bzero(buf, (size_t)size); ! 263: printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); ! 264: for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { ! 265: if (read(fd, cp, (int)secsize) != secsize) { ! 266: (void)lseek(fd, blk * dev_bsize + i + secsize, 0); ! 267: if (secsize != dev_bsize && dev_bsize != 1) ! 268: printf(" %ld (%ld),", ! 269: (blk * dev_bsize + i) / secsize, ! 270: blk + i / dev_bsize); ! 271: else ! 272: printf(" %ld,", blk + i / dev_bsize); ! 273: errs++; ! 274: } ! 275: } ! 276: printf("\n"); ! 277: return (errs); ! 278: } ! 279: ! 280: bwrite(fd, buf, blk, size) ! 281: int fd; ! 282: char *buf; ! 283: daddr_t blk; ! 284: long size; ! 285: { ! 286: int i; ! 287: char *cp; ! 288: ! 289: if (fd < 0) ! 290: return; ! 291: if (lseek(fd, blk * dev_bsize, 0) < 0) ! 292: rwerror("SEEK", blk); ! 293: else if (write(fd, buf, (int)size) == size) { ! 294: fsmodified = 1; ! 295: return; ! 296: } ! 297: rwerror("WRITE", blk); ! 298: if (lseek(fd, blk * dev_bsize, 0) < 0) ! 299: rwerror("SEEK", blk); ! 300: printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); ! 301: for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) ! 302: if (write(fd, cp, (int)dev_bsize) != dev_bsize) { ! 303: (void)lseek(fd, blk * dev_bsize + i + dev_bsize, 0); ! 304: printf(" %ld,", blk + i / dev_bsize); ! 305: } ! 306: printf("\n"); ! 307: return; ! 308: } ! 309: ! 310: /* ! 311: * allocate a data block with the specified number of fragments ! 312: */ ! 313: allocblk(frags) ! 314: long frags; ! 315: { ! 316: register int i, j, k; ! 317: ! 318: if (frags <= 0 || frags > sblock.fs_frag) ! 319: return (0); ! 320: for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { ! 321: for (j = 0; j <= sblock.fs_frag - frags; j++) { ! 322: if (testbmap(i + j)) ! 323: continue; ! 324: for (k = 1; k < frags; k++) ! 325: if (testbmap(i + j + k)) ! 326: break; ! 327: if (k < frags) { ! 328: j += k; ! 329: continue; ! 330: } ! 331: for (k = 0; k < frags; k++) ! 332: setbmap(i + j + k); ! 333: n_blks += frags; ! 334: return (i + j); ! 335: } ! 336: } ! 337: return (0); ! 338: } ! 339: ! 340: /* ! 341: * Free a previously allocated block ! 342: */ ! 343: freeblk(blkno, frags) ! 344: daddr_t blkno; ! 345: long frags; ! 346: { ! 347: struct inodesc idesc; ! 348: ! 349: idesc.id_blkno = blkno; ! 350: idesc.id_numfrags = frags; ! 351: (void)pass4check(&idesc); ! 352: } ! 353: ! 354: /* ! 355: * Find a pathname ! 356: */ ! 357: getpathname(namebuf, curdir, ino) ! 358: char *namebuf; ! 359: ino_t curdir, ino; ! 360: { ! 361: int len; ! 362: register char *cp; ! 363: struct inodesc idesc; ! 364: static int busy = 0; ! 365: extern int findname(); ! 366: ! 367: if (busy || ! 368: (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) { ! 369: (void)strcpy(namebuf, "?"); ! 370: return; ! 371: } ! 372: busy = 1; ! 373: bzero((char *)&idesc, sizeof(struct inodesc)); ! 374: idesc.id_type = DATA; ! 375: idesc.id_fix = IGNORE; ! 376: cp = &namebuf[MAXPATHLEN - 1]; ! 377: *cp = '\0'; ! 378: if (curdir != ino) { ! 379: idesc.id_parent = curdir; ! 380: goto namelookup; ! 381: } ! 382: while (ino != ROOTINO) { ! 383: idesc.id_number = ino; ! 384: idesc.id_func = findino; ! 385: idesc.id_name = ".."; ! 386: if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) ! 387: break; ! 388: namelookup: ! 389: idesc.id_number = idesc.id_parent; ! 390: idesc.id_parent = ino; ! 391: idesc.id_func = findname; ! 392: idesc.id_name = namebuf; ! 393: if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) ! 394: break; ! 395: len = strlen(namebuf); ! 396: cp -= len; ! 397: if (cp < &namebuf[MAXNAMLEN]) ! 398: break; ! 399: bcopy(namebuf, cp, (size_t)len); ! 400: *--cp = '/'; ! 401: ino = idesc.id_number; ! 402: } ! 403: busy = 0; ! 404: if (ino != ROOTINO) { ! 405: (void)strcpy(namebuf, "?"); ! 406: return; ! 407: } ! 408: bcopy(cp, namebuf, (size_t)(&namebuf[MAXPATHLEN] - cp)); ! 409: } ! 410: ! 411: void ! 412: catch() ! 413: { ! 414: ckfini(); ! 415: exit(12); ! 416: } ! 417: ! 418: /* ! 419: * When preening, allow a single quit to signal ! 420: * a special exit after filesystem checks complete ! 421: * so that reboot sequence may be interrupted. ! 422: */ ! 423: void ! 424: catchquit() ! 425: { ! 426: extern returntosingle; ! 427: ! 428: printf("returning to single-user after filesystem check\n"); ! 429: returntosingle = 1; ! 430: (void)signal(SIGQUIT, SIG_DFL); ! 431: } ! 432: ! 433: /* ! 434: * Ignore a single quit signal; wait and flush just in case. ! 435: * Used by child processes in preen. ! 436: */ ! 437: void ! 438: voidquit() ! 439: { ! 440: ! 441: sleep(1); ! 442: (void)signal(SIGQUIT, SIG_IGN); ! 443: (void)signal(SIGQUIT, SIG_DFL); ! 444: } ! 445: ! 446: /* ! 447: * determine whether an inode should be fixed. ! 448: */ ! 449: dofix(idesc, msg) ! 450: register struct inodesc *idesc; ! 451: char *msg; ! 452: { ! 453: ! 454: switch (idesc->id_fix) { ! 455: ! 456: case DONTKNOW: ! 457: if (idesc->id_type == DATA) ! 458: direrror(idesc->id_number, msg); ! 459: else ! 460: pwarn(msg); ! 461: if (preen) { ! 462: printf(" (SALVAGED)\n"); ! 463: idesc->id_fix = FIX; ! 464: return (ALTERED); ! 465: } ! 466: if (reply("SALVAGE") == 0) { ! 467: idesc->id_fix = NOFIX; ! 468: return (0); ! 469: } ! 470: idesc->id_fix = FIX; ! 471: return (ALTERED); ! 472: ! 473: case FIX: ! 474: return (ALTERED); ! 475: ! 476: case NOFIX: ! 477: case IGNORE: ! 478: return (0); ! 479: ! 480: default: ! 481: errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); ! 482: } ! 483: /* NOTREACHED */ ! 484: } ! 485: ! 486: /* VARARGS1 */ ! 487: errexit(s1, s2, s3, s4) ! 488: char *s1; ! 489: { ! 490: printf(s1, s2, s3, s4); ! 491: exit(8); ! 492: } ! 493: ! 494: /* ! 495: * An unexpected inconsistency occured. ! 496: * Die if preening, otherwise just print message and continue. ! 497: */ ! 498: /* VARARGS1 */ ! 499: pfatal(s, a1, a2, a3) ! 500: char *s; ! 501: { ! 502: ! 503: if (preen) { ! 504: printf("%s: ", devname); ! 505: printf(s, a1, a2, a3); ! 506: printf("\n"); ! 507: printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", ! 508: devname); ! 509: exit(8); ! 510: } ! 511: printf(s, a1, a2, a3); ! 512: } ! 513: ! 514: /* ! 515: * Pwarn just prints a message when not preening, ! 516: * or a warning (preceded by filename) when preening. ! 517: */ ! 518: /* VARARGS1 */ ! 519: pwarn(s, a1, a2, a3, a4, a5, a6) ! 520: char *s; ! 521: { ! 522: ! 523: if (preen) ! 524: printf("%s: ", devname); ! 525: printf(s, a1, a2, a3, a4, a5, a6); ! 526: } ! 527: ! 528: #ifndef lint ! 529: /* ! 530: * Stub for routines from kernel. ! 531: */ ! 532: panic(s) ! 533: char *s; ! 534: { ! 535: ! 536: pfatal("INTERNAL INCONSISTENCY:"); ! 537: errexit(s); ! 538: } ! 539: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.