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.2 (Berkeley) 9/10/85"; 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 lseek(); 20: 21: ftypeok(dp) 22: DINODE *dp; 23: { 24: switch (dp->di_mode & IFMT) { 25: 26: case IFDIR: 27: case IFREG: 28: case IFBLK: 29: case IFCHR: 30: case IFLNK: 31: case IFSOCK: 32: return (1); 33: 34: default: 35: if (debug) 36: printf("bad file type 0%o\n", dp->di_mode); 37: return (0); 38: } 39: } 40: 41: reply(s) 42: char *s; 43: { 44: char line[80]; 45: 46: if (preen) 47: pfatal("INTERNAL ERROR: GOT TO reply()"); 48: printf("\n%s? ", s); 49: if (nflag || dfile.wfdes < 0) { 50: printf(" no\n\n"); 51: return (0); 52: } 53: if (yflag) { 54: printf(" yes\n\n"); 55: return (1); 56: } 57: if (getline(stdin, line, sizeof(line)) == EOF) 58: errexit("\n"); 59: printf("\n"); 60: if (line[0] == 'y' || line[0] == 'Y') 61: return (1); 62: else 63: return (0); 64: } 65: 66: getline(fp, loc, maxlen) 67: FILE *fp; 68: char *loc; 69: { 70: register n; 71: register char *p, *lastloc; 72: 73: p = loc; 74: lastloc = &p[maxlen-1]; 75: while ((n = getc(fp)) != '\n') { 76: if (n == EOF) 77: return (EOF); 78: if (!isspace(n) && p < lastloc) 79: *p++ = n; 80: } 81: *p = 0; 82: return (p - loc); 83: } 84: 85: BUFAREA * 86: getblk(bp, blk, size) 87: register BUFAREA *bp; 88: daddr_t blk; 89: long size; 90: { 91: register struct filecntl *fcp; 92: daddr_t dblk; 93: 94: fcp = &dfile; 95: dblk = fsbtodb(&sblock, blk); 96: if (bp->b_bno == dblk) 97: return (bp); 98: flush(fcp, bp); 99: bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size); 100: bp->b_bno = dblk; 101: bp->b_size = size; 102: return (bp); 103: } 104: 105: flush(fcp, bp) 106: struct filecntl *fcp; 107: register BUFAREA *bp; 108: { 109: register int i, j; 110: 111: if (!bp->b_dirty) 112: return; 113: if (bp->b_errs != 0) 114: pfatal("WRITING ZERO'ED BLOCK %d TO DISK\n", bp->b_bno); 115: bp->b_dirty = 0; 116: bp->b_errs = 0; 117: bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 118: if (bp != &sblk) 119: return; 120: for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 121: bwrite(&dfile, (char *)sblock.fs_csp[j], 122: fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 123: sblock.fs_cssize - i < sblock.fs_bsize ? 124: sblock.fs_cssize - i : sblock.fs_bsize); 125: } 126: } 127: 128: rwerr(s, blk) 129: char *s; 130: daddr_t blk; 131: { 132: 133: if (preen == 0) 134: printf("\n"); 135: pfatal("CANNOT %s: BLK %ld", s, blk); 136: if (reply("CONTINUE") == 0) 137: errexit("Program terminated\n"); 138: } 139: 140: ckfini() 141: { 142: 143: flush(&dfile, &fileblk); 144: flush(&dfile, &sblk); 145: if (sblk.b_bno != SBLOCK) { 146: sblk.b_bno = SBLOCK; 147: sbdirty(); 148: flush(&dfile, &sblk); 149: } 150: flush(&dfile, &inoblk); 151: flush(&dfile, &cgblk); 152: (void)close(dfile.rfdes); 153: (void)close(dfile.wfdes); 154: } 155: 156: bread(fcp, buf, blk, size) 157: register struct filecntl *fcp; 158: char *buf; 159: daddr_t blk; 160: long size; 161: { 162: char *cp; 163: int i, errs; 164: 165: if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0) 166: rwerr("SEEK", blk); 167: else if (read(fcp->rfdes, buf, (int)size) == size) 168: return (0); 169: rwerr("READ", blk); 170: if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0) 171: rwerr("SEEK", blk); 172: errs = 0; 173: pfatal("THE FOLLOWING SECTORS COULD NOT BE READ:"); 174: for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE) { 175: if (read(fcp->rfdes, cp, DEV_BSIZE) < 0) { 176: printf(" %d,", blk + i / DEV_BSIZE); 177: bzero(cp, DEV_BSIZE); 178: errs++; 179: } 180: } 181: printf("\n"); 182: return (errs); 183: } 184: 185: bwrite(fcp, buf, blk, size) 186: register struct filecntl *fcp; 187: char *buf; 188: daddr_t blk; 189: long size; 190: { 191: int i; 192: char *cp; 193: 194: if (fcp->wfdes < 0) 195: return; 196: if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0) 197: rwerr("SEEK", blk); 198: else if (write(fcp->wfdes, buf, (int)size) == size) { 199: fcp->mod = 1; 200: return; 201: } 202: rwerr("WRITE", blk); 203: if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0) 204: rwerr("SEEK", blk); 205: pfatal("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 206: for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE) 207: if (write(fcp->wfdes, cp, DEV_BSIZE) < 0) 208: printf(" %d,", blk + i / DEV_BSIZE); 209: printf("\n"); 210: return; 211: } 212: 213: /* 214: * allocate a data block with the specified number of fragments 215: */ 216: allocblk(frags) 217: int frags; 218: { 219: register int i, j, k; 220: 221: if (frags <= 0 || frags > sblock.fs_frag) 222: return (0); 223: for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) { 224: for (j = 0; j <= sblock.fs_frag - frags; j++) { 225: if (getbmap(i + j)) 226: continue; 227: for (k = 1; k < frags; k++) 228: if (getbmap(i + j + k)) 229: break; 230: if (k < frags) { 231: j += k; 232: continue; 233: } 234: for (k = 0; k < frags; k++) 235: setbmap(i + j + k); 236: n_blks += frags; 237: return (i + j); 238: } 239: } 240: return (0); 241: } 242: 243: /* 244: * Free a previously allocated block 245: */ 246: freeblk(blkno, frags) 247: daddr_t blkno; 248: int frags; 249: { 250: struct inodesc idesc; 251: 252: idesc.id_blkno = blkno; 253: idesc.id_numfrags = frags; 254: pass4check(&idesc); 255: } 256: 257: /* 258: * Find a pathname 259: */ 260: getpathname(namebuf, curdir, ino) 261: char *namebuf; 262: ino_t curdir, ino; 263: { 264: int len; 265: register char *cp; 266: struct inodesc idesc; 267: extern int findname(); 268: 269: if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { 270: strcpy(namebuf, "?"); 271: return; 272: } 273: bzero(&idesc, sizeof(struct inodesc)); 274: idesc.id_type = DATA; 275: cp = &namebuf[BUFSIZ - 1]; 276: *cp-- = '\0'; 277: if (curdir != ino) { 278: idesc.id_parent = curdir; 279: goto namelookup; 280: } 281: while (ino != ROOTINO) { 282: idesc.id_number = ino; 283: idesc.id_func = findino; 284: idesc.id_name = ".."; 285: if ((ckinode(ginode(ino), &idesc) & STOP) == 0) 286: break; 287: namelookup: 288: idesc.id_number = idesc.id_parent; 289: idesc.id_parent = ino; 290: idesc.id_func = findname; 291: idesc.id_name = namebuf; 292: if ((ckinode(ginode(idesc.id_number), &idesc) & STOP) == 0) 293: break; 294: len = strlen(namebuf); 295: cp -= len; 296: if (cp < &namebuf[MAXNAMLEN]) 297: break; 298: bcopy(namebuf, cp, len); 299: *--cp = '/'; 300: ino = idesc.id_number; 301: } 302: if (ino != ROOTINO) { 303: strcpy(namebuf, "?"); 304: return; 305: } 306: bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); 307: } 308: 309: catch() 310: { 311: 312: ckfini(); 313: exit(12); 314: } 315: 316: /* 317: * When preening, allow a single quit to signal 318: * a special exit after filesystem checks complete 319: * so that reboot sequence may be interrupted. 320: */ 321: catchquit() 322: { 323: extern returntosingle; 324: 325: printf("returning to single-user after filesystem check\n"); 326: returntosingle = 1; 327: (void)signal(SIGQUIT, SIG_DFL); 328: } 329: 330: /* 331: * Ignore a single quit signal; wait and flush just in case. 332: * Used by child processes in preen. 333: */ 334: voidquit() 335: { 336: 337: sleep(1); 338: (void)signal(SIGQUIT, SIG_IGN); 339: (void)signal(SIGQUIT, SIG_DFL); 340: } 341: 342: /* 343: * determine whether an inode should be fixed. 344: */ 345: dofix(idesc, msg) 346: register struct inodesc *idesc; 347: char *msg; 348: { 349: 350: switch (idesc->id_fix) { 351: 352: case DONTKNOW: 353: if (idesc->id_type == DATA) 354: direrr(idesc->id_number, msg); 355: else 356: pwarn(msg); 357: if (preen) { 358: printf(" (SALVAGED)\n"); 359: idesc->id_fix = FIX; 360: return (ALTERED); 361: } 362: if (reply("SALVAGE") == 0) { 363: idesc->id_fix = NOFIX; 364: return (0); 365: } 366: idesc->id_fix = FIX; 367: return (ALTERED); 368: 369: case FIX: 370: return (ALTERED); 371: 372: case NOFIX: 373: return (0); 374: 375: default: 376: errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 377: } 378: /* NOTREACHED */ 379: } 380: 381: /* VARARGS1 */ 382: errexit(s1, s2, s3, s4) 383: char *s1; 384: { 385: printf(s1, s2, s3, s4); 386: exit(8); 387: } 388: 389: /* 390: * An inconsistency occured which shouldn't during normal operations. 391: * Die if preening, otherwise just printf. 392: */ 393: /* VARARGS1 */ 394: pfatal(s, a1, a2, a3) 395: char *s; 396: { 397: 398: if (preen) { 399: printf("%s: ", devname); 400: printf(s, a1, a2, a3); 401: printf("\n"); 402: printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 403: devname); 404: exit(8); 405: } 406: printf(s, a1, a2, a3); 407: } 408: 409: /* 410: * Pwarn is like printf when not preening, 411: * or a warning (preceded by filename) when preening. 412: */ 413: /* VARARGS1 */ 414: pwarn(s, a1, a2, a3, a4, a5, a6) 415: char *s; 416: { 417: 418: if (preen) 419: printf("%s: ", devname); 420: printf(s, a1, a2, a3, a4, a5, a6); 421: } 422: 423: #ifndef lint 424: /* 425: * Stub for routines from kernel. 426: */ 427: panic(s) 428: char *s; 429: { 430: 431: pfatal("INTERNAL INCONSISTENCY:"); 432: errexit(s); 433: } 434: #endif