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