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: #if !defined(lint) && defined(DOSCCS) 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) 87: register BUFAREA *bp; 88: daddr_t blk; 89: { 90: register struct filecntl *fcp; 91: extern BUFAREA *search(); 92: 93: if(bp == NULL) { 94: bp = search(blk); 95: fcp = &sfile; 96: } 97: else 98: fcp = &dfile; 99: if(bp->b_bno == blk) 100: return(bp); 101: flush(fcp,bp); 102: bp->b_errs = bread(fcp,bp->b_un.b_buf,blk,DEV_BSIZE); 103: bp->b_bno = blk; 104: bp->b_size = DEV_BSIZE; 105: return(bp); 106: } 107: 108: flush(fcp, bp) 109: struct filecntl *fcp; 110: register BUFAREA *bp; 111: { 112: 113: if (!bp->b_dirty) 114: return; 115: if (bp->b_errs != 0) 116: pfatal("WRITING ZERO'ED BLOCK %ld TO DISK\n", bp->b_bno); 117: bp->b_dirty = 0; 118: bp->b_errs = 0; 119: if (bp == &inoblk) 120: bwrite(fcp, inobuf, startib, NINOBLK * DEV_BSIZE); 121: else 122: bwrite(fcp, bp->b_un.b_buf, bp->b_bno, DEV_BSIZE); 123: } 124: 125: rwerr(s, blk) 126: char *s; 127: daddr_t blk; 128: { 129: 130: if (preen == 0) 131: printf("\n"); 132: pfatal("CANNOT %s: BLK %ld", s, blk); 133: if (reply("CONTINUE") == 0) 134: errexit("Program terminated\n"); 135: } 136: 137: ckfini() 138: { 139: 140: flush(&dfile, &fileblk); 141: flush(&dfile, &sblk); 142: if (sblk.b_bno != SBLOCK) { 143: sblk.b_bno = SBLOCK; 144: sbdirty(); 145: flush(&dfile, &sblk); 146: } 147: flush(&dfile, &inoblk); 148: if (dfile.rfdes) 149: (void)close(dfile.rfdes); 150: if (dfile.wfdes) 151: (void)close(dfile.wfdes); 152: if (sfile.rfdes) 153: (void)close(sfile.rfdes); 154: if (sfile.wfdes) 155: (void)close(sfile.wfdes); 156: } 157: 158: bread(fcp, buf, blk, size) 159: register struct filecntl *fcp; 160: char *buf; 161: daddr_t blk; 162: int size; 163: { 164: char *cp; 165: register int i, errs; 166: 167: if (lseek(fcp->rfdes, blk << DEV_BSHIFT, 0) < 0) 168: rwerr("SEEK", blk); 169: else if (read(fcp->rfdes, buf, size) == size) 170: return (0); 171: rwerr("READ", blk); 172: if (lseek(fcp->rfdes, blk << DEV_BSHIFT, 0) < 0) 173: rwerr("SEEK", blk); 174: errs = 0; 175: pfatal("THE FOLLOWING SECTORS COULD NOT BE READ:"); 176: for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE) { 177: if (read(fcp->rfdes, cp, DEV_BSIZE) < 0) { 178: printf(" %ld,", blk + i / DEV_BSIZE); 179: bzero(cp, DEV_BSIZE); 180: errs++; 181: } 182: } 183: printf("\n"); 184: return (errs); 185: } 186: 187: bwrite(fcp, buf, blk, size) 188: register struct filecntl *fcp; 189: char *buf; 190: daddr_t blk; 191: int size; 192: { 193: int i; 194: char *cp; 195: 196: if (fcp->wfdes < 0) 197: return; 198: if (lseek(fcp->wfdes, blk << DEV_BSHIFT, 0) < 0) 199: rwerr("SEEK", blk); 200: else if (write(fcp->wfdes, buf, size) == size) { 201: fcp->mod = 1; 202: return; 203: } 204: rwerr("WRITE", blk); 205: if (lseek(fcp->wfdes, blk << DEV_BSHIFT, 0) < 0) 206: rwerr("SEEK", blk); 207: pfatal("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 208: for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE) 209: if (write(fcp->wfdes, cp, DEV_BSIZE) < 0) 210: printf(" %ld,", blk + i / DEV_BSIZE); 211: printf("\n"); 212: return; 213: } 214: 215: /* 216: * allocate a data block 217: */ 218: daddr_t 219: allocblk() 220: { 221: daddr_t i; 222: 223: for (i = 0; i < fmax; i++) { 224: if (getbmap(i)) 225: continue; 226: setbmap(i); 227: n_blks++; 228: return (i); 229: } 230: return (0); 231: } 232: 233: /* 234: * Free a previously allocated block 235: */ 236: fr_blk(blkno) 237: daddr_t blkno; 238: { 239: struct inodesc idesc; 240: 241: idesc.id_blkno = blkno; 242: pass4check(&idesc); 243: } 244: 245: /* 246: * Find a pathname 247: */ 248: getpathname(namebuf, curdir, ino) 249: char *namebuf; 250: ino_t curdir, ino; 251: { 252: int len, st; 253: register char *cp; 254: struct inodesc idesc; 255: extern int findname(); 256: 257: st = getstate(ino); 258: if (st != DSTATE && st != DFOUND) { 259: strcpy(namebuf, "?"); 260: return; 261: } 262: bzero(&idesc, sizeof(struct inodesc)); 263: idesc.id_type = DATA; 264: cp = &namebuf[MAXPATHLEN - 1]; 265: *cp-- = '\0'; 266: if (curdir != ino) { 267: idesc.id_parent = curdir; 268: goto namelookup; 269: } 270: while (ino != ROOTINO) { 271: idesc.id_number = ino; 272: idesc.id_func = findino; 273: idesc.id_name = ".."; 274: if ((ckinode(ginode(ino), &idesc) & STOP) == 0) 275: break; 276: namelookup: 277: idesc.id_number = idesc.id_parent; 278: idesc.id_parent = ino; 279: idesc.id_func = findname; 280: idesc.id_name = namebuf; 281: if ((ckinode(ginode(idesc.id_number), &idesc) & STOP) == 0) 282: break; 283: len = strlen(namebuf); 284: cp -= len; 285: if (cp < &namebuf[MAXNAMLEN]) 286: break; 287: bcopy(namebuf, cp, len); 288: *--cp = '/'; 289: ino = idesc.id_number; 290: } 291: if (ino != ROOTINO) { 292: strcpy(namebuf, "?"); 293: return; 294: } 295: bcopy(cp, namebuf, &namebuf[MAXPATHLEN] - cp); 296: } 297: 298: catch() 299: { 300: 301: ckfini(); 302: exit(12); 303: } 304: 305: /* 306: * When preening, allow a single quit to signal 307: * a special exit after filesystem checks complete 308: * so that reboot sequence may be interrupted. 309: */ 310: catchquit() 311: { 312: extern returntosingle; 313: 314: printf("returning to single-user after filesystem check\n"); 315: returntosingle = 1; 316: (void)signal(SIGQUIT, SIG_DFL); 317: } 318: 319: /* 320: * Ignore a single quit signal; wait and flush just in case. 321: * Used by child processes in preen. 322: */ 323: voidquit() 324: { 325: 326: sleep(1); 327: (void)signal(SIGQUIT, SIG_IGN); 328: (void)signal(SIGQUIT, SIG_DFL); 329: } 330: 331: /* 332: * determine whether an inode should be fixed. 333: */ 334: dofix(idesc, msg) 335: register struct inodesc *idesc; 336: char *msg; 337: { 338: 339: switch (idesc->id_fix) { 340: 341: case DONTKNOW: 342: if (idesc->id_type == DATA) 343: direrr(idesc->id_number, msg); 344: else 345: pwarn(msg); 346: if (preen) { 347: printf(" (SALVAGED)\n"); 348: idesc->id_fix = FIX; 349: return (ALTERED); 350: } 351: if (reply("SALVAGE") == 0) { 352: idesc->id_fix = NOFIX; 353: return (0); 354: } 355: idesc->id_fix = FIX; 356: return (ALTERED); 357: 358: case FIX: 359: return (ALTERED); 360: 361: case NOFIX: 362: return (0); 363: 364: default: 365: errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 366: } 367: /* NOTREACHED */ 368: } 369: 370: /* VARARGS1 */ 371: errexit(s1, s2, s3, s4) 372: char *s1; 373: { 374: printf(s1, s2, s3, s4); 375: exit(8); 376: } 377: 378: /* 379: * An inconsistency occured which shouldn't during normal operations. 380: * Die if preening, otherwise just printf. 381: */ 382: /* VARARGS1 */ 383: pfatal(s, a1, a2, a3, a4) 384: char *s; 385: { 386: 387: if (preen) { 388: printf("%s: ", devname); 389: printf(s, a1, a2, a3, a4); 390: printf("\n"); 391: printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 392: devname); 393: exit(8); 394: } 395: printf(s, a1, a2, a3, a4); 396: } 397: 398: /* 399: * Pwarn is like printf when not preening, 400: * or a warning (preceded by filename) when preening. 401: */ 402: /* VARARGS1 */ 403: pwarn(s, a1, a2, a3, a4, a5, a6) 404: char *s; 405: { 406: 407: if (preen) 408: printf("%s: ", devname); 409: printf(s, a1, a2, a3, a4, a5, a6); 410: } 411: 412: stype(p) 413: register char *p; 414: { 415: if(*p == 0) 416: return; 417: if (*(p+1) == 0) { 418: if (*p == '3') { 419: cylsize = 200; 420: stepsize = 5; 421: return; 422: } 423: if (*p == '4') { 424: cylsize = 418; 425: stepsize = 9; 426: return; 427: } 428: } 429: cylsize = atoi(p); 430: while(*p && *p != ':') 431: p++; 432: if(*p) 433: p++; 434: stepsize = atoi(p); 435: if(stepsize <= 0 || stepsize > cylsize || 436: cylsize <= 0 || cylsize > MAXCYL) { 437: printf("Invalid -s argument, defaults assumed\n"); 438: cylsize = stepsize = 0; 439: } 440: } 441: 442: dostate(ino, s,flg) 443: ino_t ino; 444: int s, flg; 445: { 446: register char *p; 447: register unsigned byte, shift; 448: BUFAREA *bp; 449: 450: byte = ino / STATEPB; 451: shift = LSTATE * (ino % STATEPB); 452: if(statemap != NULL) { 453: bp = NULL; 454: p = &statemap[byte]; 455: } 456: else { 457: bp = getblk(NULL,(daddr_t)(smapblk+(byte/DEV_BSIZE))); 458: if (bp->b_errs) 459: errexit("Fatal I/O error\n"); 460: else 461: p = &bp->b_un.b_buf[byte%DEV_BSIZE]; 462: } 463: switch(flg) { 464: case 0: 465: *p &= ~(SMASK<<(shift)); 466: *p |= s << shift; 467: if(bp != NULL) 468: dirty(bp); 469: return(s); 470: case 1: 471: return((*p >> shift) & SMASK); 472: } 473: return(USTATE); 474: } 475: 476: domap(blk,flg) 477: daddr_t blk; 478: int flg; 479: { 480: register char *p; 481: register unsigned n; 482: register BUFAREA *bp; 483: off_t byte; 484: 485: byte = blk >> BITSHIFT; 486: n = 1<<((unsigned)(blk & BITMASK)); 487: if(flg & 04) { 488: p = freemap; 489: blk = fmapblk; 490: } 491: else { 492: p = blockmap; 493: blk = bmapblk; 494: } 495: if(p != NULL) { 496: bp = NULL; 497: p += (unsigned)byte; 498: } 499: else { 500: bp = getblk((BUFAREA *)NULL,blk+(byte>>DEV_BSHIFT)); 501: if (bp->b_errs) 502: errexit("Fatal I/O error\n"); 503: else 504: p = &bp->b_un.b_buf[(unsigned)(byte&DEV_BMASK)]; 505: } 506: switch(flg&03) { 507: case 0: 508: *p |= n; 509: break; 510: case 1: 511: n &= *p; 512: bp = NULL; 513: break; 514: case 2: 515: *p &= ~n; 516: } 517: if(bp != NULL) 518: dirty(bp); 519: return(n); 520: } 521: 522: dolncnt(ino, flg, val) 523: ino_t ino; 524: short val, flg; 525: { 526: register short *sp; 527: register BUFAREA *bp; 528: 529: if(lncntp != NULL) { 530: bp = NULL; 531: sp = &lncntp[ino]; 532: } 533: else { 534: bp = getblk((BUFAREA *)NULL,(daddr_t)(lncntblk+(ino/SPERB))); 535: if (bp->b_errs) 536: errexit("Fatal I/O error\n"); 537: else 538: sp = &bp->b_un.b_lnks[ino%SPERB]; 539: } 540: switch(flg) { 541: case 0: 542: *sp = val; 543: break; 544: case 1: 545: bp = NULL; 546: break; 547: case 2: 548: (*sp)--; 549: break; 550: case 3: 551: (*sp)++; 552: break; 553: default: 554: abort(); 555: } 556: if(bp != NULL) 557: dirty(bp); 558: return(*sp); 559: } 560: 561: BUFAREA * 562: search(blk) 563: daddr_t blk; 564: { 565: register BUFAREA *pbp, *bp; 566: 567: for(bp = (BUFAREA *) &poolhead; bp->b_next; ) { 568: pbp = bp; 569: bp = pbp->b_next; 570: if(bp->b_bno == blk) 571: break; 572: } 573: pbp->b_next = bp->b_next; 574: bp->b_next = poolhead; 575: poolhead = bp; 576: return(bp); 577: }