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