|
|
1.1 ! root 1: /* Copyright (c) 1981 Regents of the University of California */ ! 2: static char *sccsid = "@(#)exrecover.c 7.4 10/16/81"; ! 3: #include <stdio.h> /* mjm: BUFSIZ: stdio = 512, VMUNIX = 1024 */ ! 4: #undef BUFSIZ /* mjm: BUFSIZ different */ ! 5: #undef EOF /* mjm: EOF and NULL effectively the same */ ! 6: #undef NULL ! 7: ! 8: #include "ex.h" ! 9: #include "ex_temp.h" ! 10: #include "ex_tty.h" ! 11: #include "local/uparm.h" ! 12: #include "sys/dir.h" ! 13: ! 14: char xstr[1]; /* make loader happy */ ! 15: short tfile = -1; /* ditto */ ! 16: ! 17: /* ! 18: * ! 19: * This program searches through the specified directory and then ! 20: * the directory usrpath(preserve) looking for an instance of the specified ! 21: * file from a crashed editor or a crashed system. ! 22: * If this file is found, it is unscrambled and written to ! 23: * the standard output. ! 24: * ! 25: * If this program terminates without a "broken pipe" diagnostic ! 26: * (i.e. the editor doesn't die right away) then the buffer we are ! 27: * writing from is removed when we finish. This is potentially a mistake ! 28: * as there is not enough handshaking to guarantee that the file has actually ! 29: * been recovered, but should suffice for most cases. ! 30: */ ! 31: ! 32: /* ! 33: * For lint's sake... ! 34: */ ! 35: #ifndef lint ! 36: #define ignorl(a) a ! 37: #endif ! 38: ! 39: /* ! 40: * This directory definition also appears (obviously) in expreserve.c. ! 41: * Change both if you change either. ! 42: */ ! 43: char mydir[] = usrpath(preserve); ! 44: ! 45: /* ! 46: * Limit on the number of printed entries ! 47: * when an, e.g. ``ex -r'' command is given. ! 48: */ ! 49: #define NENTRY 50 ! 50: ! 51: char *ctime(); ! 52: char nb[BUFSIZ]; ! 53: int vercnt; /* Count number of versions of file found */ ! 54: ! 55: main(argc, argv) ! 56: int argc; ! 57: char *argv[]; ! 58: { ! 59: register char *cp; ! 60: register int b, i; ! 61: ! 62: /* ! 63: * Initialize as though the editor had just started. ! 64: */ ! 65: fendcore = (line *) sbrk(0); ! 66: dot = zero = dol = fendcore; ! 67: one = zero + 1; ! 68: endcore = fendcore - 2; ! 69: iblock = oblock = -1; ! 70: ! 71: /* ! 72: * If given only a -r argument, then list the saved files. ! 73: */ ! 74: if (argc == 2 && eq(argv[1], "-r")) { ! 75: listfiles(mydir); ! 76: exit(0); ! 77: } ! 78: if (argc != 3) ! 79: error(" Wrong number of arguments to exrecover", 0); ! 80: ! 81: CP(file, argv[2]); ! 82: ! 83: /* ! 84: * Search for this file. ! 85: */ ! 86: findtmp(argv[1]); ! 87: ! 88: /* ! 89: * Got (one of the versions of) it, write it back to the editor. ! 90: */ ! 91: cp = ctime(&H.Time); ! 92: cp[19] = 0; ! 93: fprintf(stderr, " [Dated: %s", cp); ! 94: fprintf(stderr, vercnt > 1 ? ", newest of %d saved]" : "]", vercnt); ! 95: H.Flines++; ! 96: ! 97: /* ! 98: * Allocate space for the line pointers from the temp file. ! 99: */ ! 100: if ((int) sbrk((int) (H.Flines * sizeof (line))) == -1) ! 101: /* ! 102: * Good grief. ! 103: */ ! 104: error(" Not enough core for lines", 0); ! 105: #ifdef DEBUG ! 106: fprintf(stderr, "%d lines\n", H.Flines); ! 107: #endif ! 108: ! 109: /* ! 110: * Now go get the blocks of seek pointers which are scattered ! 111: * throughout the temp file, reconstructing the incore ! 112: * line pointers at point of crash. ! 113: */ ! 114: b = 0; ! 115: while (H.Flines > 0) { ! 116: ignorl(lseek(tfile, (long) blocks[b] * BUFSIZ, 0)); ! 117: i = H.Flines < BUFSIZ / sizeof (line) ? ! 118: H.Flines * sizeof (line) : BUFSIZ; ! 119: if (read(tfile, (char *) dot, i) != i) { ! 120: perror(nb); ! 121: exit(1); ! 122: } ! 123: dot += i / sizeof (line); ! 124: H.Flines -= i / sizeof (line); ! 125: b++; ! 126: } ! 127: dot--; dol = dot; ! 128: ! 129: /* ! 130: * Sigh... due to sandbagging some lines may really not be there. ! 131: * Find and discard such. This shouldn't happen much. ! 132: */ ! 133: scrapbad(); ! 134: ! 135: /* ! 136: * Now if there were any lines in the recovered file ! 137: * write them to the standard output. ! 138: */ ! 139: if (dol > zero) { ! 140: addr1 = one; addr2 = dol; io = 1; ! 141: putfile(0); ! 142: } ! 143: ! 144: /* ! 145: * Trash the saved buffer. ! 146: * Hopefully the system won't crash before the editor ! 147: * syncs the new recovered buffer; i.e. for an instant here ! 148: * you may lose if the system crashes because this file ! 149: * is gone, but the editor hasn't completed reading the recovered ! 150: * file from the pipe from us to it. ! 151: * ! 152: * This doesn't work if we are coming from an non-absolute path ! 153: * name since we may have chdir'ed but what the hay, noone really ! 154: * ever edits with temporaries in "." anyways. ! 155: */ ! 156: if (nb[0] == '/') ! 157: ignore(unlink(nb)); ! 158: ! 159: /* ! 160: * Adieu. ! 161: */ ! 162: exit(0); ! 163: } ! 164: ! 165: /* ! 166: * Print an error message (notably not in error ! 167: * message file). If terminal is in RAW mode, then ! 168: * we should be writing output for "vi", so don't print ! 169: * a newline which would screw up the screen. ! 170: */ ! 171: /*VARARGS2*/ ! 172: error(str, inf) ! 173: char *str; ! 174: int inf; ! 175: { ! 176: ! 177: fprintf(stderr, str, inf); ! 178: #ifndef USG3TTY ! 179: ioctl(2, TIOCGETP, &tty); ! 180: if ((tty.sg_flags & RAW) == 0) ! 181: #else ! 182: ioctl(2, TCGETA, &tty); ! 183: if (tty.c_lflag & ICANON) ! 184: #endif ! 185: fprintf(stderr, "\n"); ! 186: exit(1); ! 187: } ! 188: ! 189: /* ! 190: * Here we save the information about files, when ! 191: * you ask us what files we have saved for you. ! 192: * We buffer file name, number of lines, and the time ! 193: * at which the file was saved. ! 194: */ ! 195: struct svfile { ! 196: char sf_name[FNSIZE + 1]; ! 197: int sf_lines; ! 198: char sf_entry[DIRSIZ + 1]; ! 199: time_t sf_time; ! 200: }; ! 201: ! 202: listfiles(dirname) ! 203: char *dirname; ! 204: { ! 205: register FILE *dir; ! 206: struct direct dirent; ! 207: int ecount, qucmp(); ! 208: register int f; ! 209: char *cp; ! 210: struct svfile *fp, svbuf[NENTRY]; ! 211: ! 212: /* ! 213: * Open usrpath(preserve), and go there to make things quick. ! 214: */ ! 215: dir = fopen(dirname, "r"); ! 216: if (dir == NULL) { ! 217: perror(dirname); ! 218: return; ! 219: } ! 220: if (chdir(dirname) < 0) { ! 221: perror(dirname); ! 222: return; ! 223: } ! 224: ! 225: /* ! 226: * Look at the candidate files in usrpath(preserve). ! 227: */ ! 228: fp = &svbuf[0]; ! 229: ecount = 0; ! 230: while (fread((char *) &dirent, sizeof dirent, 1, dir) == 1) { ! 231: if (dirent.d_ino == 0) ! 232: continue; ! 233: if (dirent.d_name[0] != 'E') ! 234: continue; ! 235: #ifdef DEBUG ! 236: fprintf(stderr, "considering %s\n", dirent.d_name); ! 237: #endif ! 238: /* ! 239: * Name begins with E; open it and ! 240: * make sure the uid in the header is our uid. ! 241: * If not, then don't bother with this file, it can't ! 242: * be ours. ! 243: */ ! 244: f = open(dirent.d_name, 0); ! 245: if (f < 0) { ! 246: #ifdef DEBUG ! 247: fprintf(stderr, "open failed\n"); ! 248: #endif ! 249: continue; ! 250: } ! 251: if (read(f, (char *) &H, sizeof H) != sizeof H) { ! 252: #ifdef DEBUG ! 253: fprintf(stderr, "culdnt read hedr\n"); ! 254: #endif ! 255: ignore(close(f)); ! 256: continue; ! 257: } ! 258: ignore(close(f)); ! 259: if (getuid() != H.Uid) { ! 260: #ifdef DEBUG ! 261: fprintf(stderr, "uid wrong\n"); ! 262: #endif ! 263: continue; ! 264: } ! 265: ! 266: /* ! 267: * Saved the day! ! 268: */ ! 269: enter(fp++, dirent.d_name, ecount); ! 270: ecount++; ! 271: #ifdef DEBUG ! 272: fprintf(stderr, "entered file %s\n", dirent.d_name); ! 273: #endif ! 274: } ! 275: ignore(fclose(dir)); ! 276: ! 277: /* ! 278: * If any files were saved, then sort them and print ! 279: * them out. ! 280: */ ! 281: if (ecount == 0) { ! 282: fprintf(stderr, "No files saved.\n"); ! 283: return; ! 284: } ! 285: qsort(&svbuf[0], ecount, sizeof svbuf[0], qucmp); ! 286: for (fp = &svbuf[0]; fp < &svbuf[ecount]; fp++) { ! 287: cp = ctime(&fp->sf_time); ! 288: cp[10] = 0; ! 289: fprintf(stderr, "On %s at ", cp); ! 290: cp[16] = 0; ! 291: fprintf(stderr, &cp[11]); ! 292: fprintf(stderr, " saved %d lines of file \"%s\"\n", ! 293: fp->sf_lines, fp->sf_name); ! 294: } ! 295: } ! 296: ! 297: /* ! 298: * Enter a new file into the saved file information. ! 299: */ ! 300: enter(fp, fname, count) ! 301: struct svfile *fp; ! 302: char *fname; ! 303: { ! 304: register char *cp, *cp2; ! 305: register struct svfile *f, *fl; ! 306: time_t curtime, itol(); ! 307: ! 308: f = 0; ! 309: if (count >= NENTRY) { ! 310: /* ! 311: * My god, a huge number of saved files. ! 312: * Would you work on a system that crashed this ! 313: * often? Hope not. So lets trash the oldest ! 314: * as the most useless. ! 315: * ! 316: * (I wonder if this code has ever run?) ! 317: */ ! 318: fl = fp - count + NENTRY - 1; ! 319: curtime = fl->sf_time; ! 320: for (f = fl; --f > fp-count; ) ! 321: if (f->sf_time < curtime) ! 322: curtime = f->sf_time; ! 323: for (f = fl; --f > fp-count; ) ! 324: if (f->sf_time == curtime) ! 325: break; ! 326: fp = f; ! 327: } ! 328: ! 329: /* ! 330: * Gotcha. ! 331: */ ! 332: fp->sf_time = H.Time; ! 333: fp->sf_lines = H.Flines; ! 334: for (cp2 = fp->sf_name, cp = savedfile; *cp;) ! 335: *cp2++ = *cp++; ! 336: for (cp2 = fp->sf_entry, cp = fname; *cp && cp-fname < 14;) ! 337: *cp2++ = *cp++; ! 338: *cp2++ = 0; ! 339: } ! 340: ! 341: /* ! 342: * Do the qsort compare to sort the entries first by file name, ! 343: * then by modify time. ! 344: */ ! 345: qucmp(p1, p2) ! 346: struct svfile *p1, *p2; ! 347: { ! 348: register int t; ! 349: ! 350: if (t = strcmp(p1->sf_name, p2->sf_name)) ! 351: return(t); ! 352: if (p1->sf_time > p2->sf_time) ! 353: return(-1); ! 354: return(p1->sf_time < p2->sf_time); ! 355: } ! 356: ! 357: /* ! 358: * Scratch for search. ! 359: */ ! 360: char bestnb[BUFSIZ]; /* Name of the best one */ ! 361: long besttime; /* Time at which the best file was saved */ ! 362: int bestfd; /* Keep best file open so it dont vanish */ ! 363: ! 364: /* ! 365: * Look for a file, both in the users directory option value ! 366: * (i.e. usually /tmp) and in usrpath(preserve). ! 367: * Want to find the newest so we search on and on. ! 368: */ ! 369: findtmp(dir) ! 370: char *dir; ! 371: { ! 372: ! 373: /* ! 374: * No name or file so far. ! 375: */ ! 376: bestnb[0] = 0; ! 377: bestfd = -1; ! 378: ! 379: /* ! 380: * Search usrpath(preserve) and, if we can get there, /tmp ! 381: * (actually the users "directory" option). ! 382: */ ! 383: searchdir(dir); ! 384: if (chdir(mydir) == 0) ! 385: searchdir(mydir); ! 386: if (bestfd != -1) { ! 387: /* ! 388: * Gotcha. ! 389: * Put the file (which is already open) in the file ! 390: * used by the temp file routines, and save its ! 391: * name for later unlinking. ! 392: */ ! 393: tfile = bestfd; ! 394: CP(nb, bestnb); ! 395: ignorl(lseek(tfile, 0l, 0)); ! 396: ! 397: /* ! 398: * Gotta be able to read the header or fall through ! 399: * to lossage. ! 400: */ ! 401: if (read(tfile, (char *) &H, sizeof H) == sizeof H) ! 402: return; ! 403: } ! 404: ! 405: /* ! 406: * Extreme lossage... ! 407: */ ! 408: error(" File not found", 0); ! 409: } ! 410: ! 411: /* ! 412: * Search for the file in directory dirname. ! 413: * ! 414: * Don't chdir here, because the users directory ! 415: * may be ".", and we would move away before we searched it. ! 416: * Note that we actually chdir elsewhere (because it is too slow ! 417: * to look around in usrpath(preserve) without chdir'ing there) so we ! 418: * can't win, because we don't know the name of '.' and if the path ! 419: * name of the file we want to unlink is relative, rather than absolute ! 420: * we won't be able to find it again. ! 421: */ ! 422: searchdir(dirname) ! 423: char *dirname; ! 424: { ! 425: struct direct dirent; ! 426: register FILE *dir; ! 427: char dbuf[BUFSIZ]; ! 428: ! 429: dir = fopen(dirname, "r"); ! 430: if (dir == NULL) ! 431: return; ! 432: /* setbuf(dir, dbuf); this breaks UNIX/370. */ ! 433: while (fread((char *) &dirent, sizeof dirent, 1, dir) == 1) { ! 434: if (dirent.d_ino == 0) ! 435: continue; ! 436: if (dirent.d_name[0] != 'E' || dirent.d_name[DIRSIZ - 1] != 0) ! 437: continue; ! 438: /* ! 439: * Got a file in the directory starting with E... ! 440: * Save a consed up name for the file to unlink ! 441: * later, and check that this is really a file ! 442: * we are looking for. ! 443: */ ! 444: ignore(strcat(strcat(strcpy(nb, dirname), "/"), dirent.d_name)); ! 445: if (yeah(nb)) { ! 446: /* ! 447: * Well, it is the file we are looking for. ! 448: * Is it more recent than any version we found before? ! 449: */ ! 450: if (H.Time > besttime) { ! 451: /* ! 452: * A winner. ! 453: */ ! 454: ignore(close(bestfd)); ! 455: bestfd = dup(tfile); ! 456: besttime = H.Time; ! 457: CP(bestnb, nb); ! 458: } ! 459: /* ! 460: * Count versions so user can be told there are ! 461: * ``yet more pages to be turned''. ! 462: */ ! 463: vercnt++; ! 464: } ! 465: ignore(close(tfile)); ! 466: } ! 467: ignore(fclose(dir)); ! 468: } ! 469: ! 470: /* ! 471: * Given a candidate file to be recovered, see ! 472: * if its really an editor temporary and of this ! 473: * user and the file specified. ! 474: */ ! 475: yeah(name) ! 476: char *name; ! 477: { ! 478: ! 479: tfile = open(name, 2); ! 480: if (tfile < 0) ! 481: return (0); ! 482: if (read(tfile, (char *) &H, sizeof H) != sizeof H) { ! 483: nope: ! 484: ignore(close(tfile)); ! 485: return (0); ! 486: } ! 487: if (!eq(savedfile, file)) ! 488: goto nope; ! 489: if (getuid() != H.Uid) ! 490: goto nope; ! 491: /* ! 492: * This is old and stupid code, which ! 493: * puts a word LOST in the header block, so that lost lines ! 494: * can be made to point at it. ! 495: */ ! 496: ignorl(lseek(tfile, (long)(BUFSIZ*HBLKS-8), 0)); ! 497: ignore(write(tfile, "LOST", 5)); ! 498: return (1); ! 499: } ! 500: ! 501: preserve() ! 502: { ! 503: ! 504: } ! 505: ! 506: /* ! 507: * Find the true end of the scratch file, and ``LOSE'' ! 508: * lines which point into thin air. This lossage occurs ! 509: * due to the sandbagging of i/o which can cause blocks to ! 510: * be written in a non-obvious order, different from the order ! 511: * in which the editor tried to write them. ! 512: * ! 513: * Lines which are lost are replaced with the text LOST so ! 514: * they are easy to find. We work hard at pretty formatting here ! 515: * as lines tend to be lost in blocks. ! 516: * ! 517: * This only seems to happen on very heavily loaded systems, and ! 518: * not very often. ! 519: */ ! 520: scrapbad() ! 521: { ! 522: register line *ip; ! 523: struct stat stbuf; ! 524: off_t size, maxt; ! 525: int bno, cnt, bad, was; ! 526: char bk[BUFSIZ]; ! 527: ! 528: ignore(fstat(tfile, &stbuf)); ! 529: size = stbuf.st_size; ! 530: maxt = (size >> SHFT) | (BNDRY-1); ! 531: bno = (maxt >> OFFBTS) & BLKMSK; ! 532: #ifdef DEBUG ! 533: fprintf(stderr, "size %ld, maxt %o, bno %d\n", size, maxt, bno); ! 534: #endif ! 535: ! 536: /* ! 537: * Look for a null separating two lines in the temp file; ! 538: * if last line was split across blocks, then it is lost ! 539: * if the last block is. ! 540: */ ! 541: while (bno > 0) { ! 542: ignorl(lseek(tfile, (long) BUFSIZ * bno, 0)); ! 543: cnt = read(tfile, (char *) bk, BUFSIZ); ! 544: while (cnt > 0) ! 545: if (bk[--cnt] == 0) ! 546: goto null; ! 547: bno--; ! 548: } ! 549: null: ! 550: ! 551: /* ! 552: * Magically calculate the largest valid pointer in the temp file, ! 553: * consing it up from the block number and the count. ! 554: */ ! 555: maxt = ((bno << OFFBTS) | (cnt >> SHFT)) & ~1; ! 556: #ifdef DEBUG ! 557: fprintf(stderr, "bno %d, cnt %d, maxt %o\n", bno, cnt, maxt); ! 558: #endif ! 559: ! 560: /* ! 561: * Now cycle through the line pointers, ! 562: * trashing the Lusers. ! 563: */ ! 564: was = bad = 0; ! 565: for (ip = one; ip <= dol; ip++) ! 566: if (*ip > maxt) { ! 567: #ifdef DEBUG ! 568: fprintf(stderr, "%d bad, %o > %o\n", ip - zero, *ip, maxt); ! 569: #endif ! 570: if (was == 0) ! 571: was = ip - zero; ! 572: *ip = ((HBLKS*BUFSIZ)-8) >> SHFT; ! 573: } else if (was) { ! 574: if (bad == 0) ! 575: fprintf(stderr, " [Lost line(s):"); ! 576: fprintf(stderr, " %d", was); ! 577: if ((ip - 1) - zero > was) ! 578: fprintf(stderr, "-%d", (ip - 1) - zero); ! 579: bad++; ! 580: was = 0; ! 581: } ! 582: if (was != 0) { ! 583: if (bad == 0) ! 584: fprintf(stderr, " [Lost line(s):"); ! 585: fprintf(stderr, " %d", was); ! 586: if (dol - zero != was) ! 587: fprintf(stderr, "-%d", dol - zero); ! 588: bad++; ! 589: } ! 590: if (bad) ! 591: fprintf(stderr, "]"); ! 592: } ! 593: ! 594: /* ! 595: * Aw shucks, if we only had a (void) cast. ! 596: */ ! 597: #ifdef lint ! 598: Ignorl(a) ! 599: long a; ! 600: { ! 601: ! 602: a = a; ! 603: } ! 604: ! 605: Ignore(a) ! 606: char *a; ! 607: { ! 608: ! 609: a = a; ! 610: } ! 611: ! 612: Ignorf(a) ! 613: int (*a)(); ! 614: { ! 615: ! 616: a = a; ! 617: } ! 618: ! 619: ignorl(a) ! 620: long a; ! 621: { ! 622: ! 623: a = a; ! 624: } ! 625: #endif ! 626: ! 627: int cntch, cntln, cntodd, cntnull; ! 628: /* ! 629: * Following routines stolen mercilessly from ex. ! 630: */ ! 631: putfile() ! 632: { ! 633: line *a1; ! 634: register char *fp, *lp; ! 635: register int nib; ! 636: ! 637: a1 = addr1; ! 638: clrstats(); ! 639: cntln = addr2 - a1 + 1; ! 640: if (cntln == 0) ! 641: return; ! 642: nib = BUFSIZ; ! 643: fp = genbuf; ! 644: do { ! 645: getline(*a1++); ! 646: lp = linebuf; ! 647: for (;;) { ! 648: if (--nib < 0) { ! 649: nib = fp - genbuf; ! 650: if (write(io, genbuf, nib) != nib) ! 651: wrerror(); ! 652: cntch += nib; ! 653: nib = 511; ! 654: fp = genbuf; ! 655: } ! 656: if ((*fp++ = *lp++) == 0) { ! 657: fp[-1] = '\n'; ! 658: break; ! 659: } ! 660: } ! 661: } while (a1 <= addr2); ! 662: nib = fp - genbuf; ! 663: if (write(io, genbuf, nib) != nib) ! 664: wrerror(); ! 665: cntch += nib; ! 666: } ! 667: ! 668: wrerror() ! 669: { ! 670: ! 671: syserror(); ! 672: } ! 673: ! 674: clrstats() ! 675: { ! 676: ! 677: ninbuf = 0; ! 678: cntch = 0; ! 679: cntln = 0; ! 680: cntnull = 0; ! 681: cntodd = 0; ! 682: } ! 683: ! 684: #define READ 0 ! 685: #define WRITE 1 ! 686: ! 687: getline(tl) ! 688: line tl; ! 689: { ! 690: register char *bp, *lp; ! 691: register int nl; ! 692: ! 693: lp = linebuf; ! 694: bp = getblock(tl, READ); ! 695: nl = nleft; ! 696: tl &= ~OFFMSK; ! 697: while (*lp++ = *bp++) ! 698: if (--nl == 0) { ! 699: bp = getblock(tl += INCRMT, READ); ! 700: nl = nleft; ! 701: } ! 702: } ! 703: ! 704: int read(); ! 705: int write(); ! 706: ! 707: char * ! 708: getblock(atl, iof) ! 709: line atl; ! 710: int iof; ! 711: { ! 712: register int bno, off; ! 713: ! 714: bno = (atl >> OFFBTS) & BLKMSK; ! 715: off = (atl << SHFT) & LBTMSK; ! 716: if (bno >= NMBLKS) ! 717: error(" Tmp file too large"); ! 718: nleft = BUFSIZ - off; ! 719: if (bno == iblock) { ! 720: ichanged |= iof; ! 721: return (ibuff + off); ! 722: } ! 723: if (bno == oblock) ! 724: return (obuff + off); ! 725: if (iof == READ) { ! 726: if (ichanged) ! 727: blkio(iblock, ibuff, write); ! 728: ichanged = 0; ! 729: iblock = bno; ! 730: blkio(bno, ibuff, read); ! 731: return (ibuff + off); ! 732: } ! 733: if (oblock >= 0) ! 734: blkio(oblock, obuff, write); ! 735: oblock = bno; ! 736: return (obuff + off); ! 737: } ! 738: ! 739: blkio(b, buf, iofcn) ! 740: short b; ! 741: char *buf; ! 742: int (*iofcn)(); ! 743: { ! 744: ! 745: lseek(tfile, (long) (unsigned) b * BUFSIZ, 0); ! 746: if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ) ! 747: syserror(); ! 748: } ! 749: ! 750: syserror() ! 751: { ! 752: extern int sys_nerr; ! 753: extern char *sys_errlist[]; ! 754: ! 755: dirtcnt = 0; ! 756: write(2, " ", 1); ! 757: if (errno >= 0 && errno <= sys_nerr) ! 758: error(sys_errlist[errno]); ! 759: else ! 760: error("System error %d", errno); ! 761: exit(1); ! 762: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.