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:     gtty(2, &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:     *cp2++ = 0;
 337:     for (cp2 = fp->sf_entry, cp = fname; *cp && cp-fname < 14;)
 338:         *cp2++ = *cp++;
 339:     *cp2++ = 0;
 340: }
 341: 
 342: /*
 343:  * Do the qsort compare to sort the entries first by file name,
 344:  * then by modify time.
 345:  */
 346: qucmp(p1, p2)
 347:     struct svfile *p1, *p2;
 348: {
 349:     register int t;
 350: 
 351:     if (t = strcmp(p1->sf_name, p2->sf_name))
 352:         return(t);
 353:     if (p1->sf_time > p2->sf_time)
 354:         return(-1);
 355:     return(p1->sf_time < p2->sf_time);
 356: }
 357: 
 358: /*
 359:  * Scratch for search.
 360:  */
 361: char    bestnb[BUFSIZ];     /* Name of the best one */
 362: long    besttime;       /* Time at which the best file was saved */
 363: int bestfd;         /* Keep best file open so it dont vanish */
 364: 
 365: /*
 366:  * Look for a file, both in the users directory option value
 367:  * (i.e. usually /tmp) and in usrpath(preserve).
 368:  * Want to find the newest so we search on and on.
 369:  */
 370: findtmp(dir)
 371:     char *dir;
 372: {
 373: 
 374:     /*
 375: 	 * No name or file so far.
 376: 	 */
 377:     bestnb[0] = 0;
 378:     bestfd = -1;
 379: 
 380:     /*
 381: 	 * Search usrpath(preserve) and, if we can get there, /tmp
 382: 	 * (actually the users "directory" option).
 383: 	 */
 384:     searchdir(dir);
 385:     if (chdir(mydir) == 0)
 386:         searchdir(mydir);
 387:     if (bestfd != -1) {
 388:         /*
 389: 		 * Gotcha.
 390: 		 * Put the file (which is already open) in the file
 391: 		 * used by the temp file routines, and save its
 392: 		 * name for later unlinking.
 393: 		 */
 394:         tfile = bestfd;
 395:         CP(nb, bestnb);
 396:         ignorl(lseek(tfile, 0l, 0));
 397: 
 398:         /*
 399: 		 * Gotta be able to read the header or fall through
 400: 		 * to lossage.
 401: 		 */
 402:         if (read(tfile, (char *) &H, sizeof H) == sizeof H)
 403:             return;
 404:     }
 405: 
 406:     /*
 407: 	 * Extreme lossage...
 408: 	 */
 409:     error(" File not found", 0);
 410: }
 411: 
 412: /*
 413:  * Search for the file in directory dirname.
 414:  *
 415:  * Don't chdir here, because the users directory
 416:  * may be ".", and we would move away before we searched it.
 417:  * Note that we actually chdir elsewhere (because it is too slow
 418:  * to look around in usrpath(preserve) without chdir'ing there) so we
 419:  * can't win, because we don't know the name of '.' and if the path
 420:  * name of the file we want to unlink is relative, rather than absolute
 421:  * we won't be able to find it again.
 422:  */
 423: searchdir(dirname)
 424:     char *dirname;
 425: {
 426:     struct direct dirent;
 427:     register FILE *dir;
 428:     char dbuf[BUFSIZ];
 429: 
 430:     dir = fopen(dirname, "r");
 431:     if (dir == NULL)
 432:         return;
 433:     /* setbuf(dir, dbuf); this breaks UNIX/370. */
 434:     while (fread((char *) &dirent, sizeof dirent, 1, dir) == 1) {
 435:         if (dirent.d_ino == 0)
 436:             continue;
 437:         if (dirent.d_name[0] != 'E' || dirent.d_name[DIRSIZ - 1] != 0)
 438:             continue;
 439:         /*
 440: 		 * Got a file in the directory starting with E...
 441: 		 * Save a consed up name for the file to unlink
 442: 		 * later, and check that this is really a file
 443: 		 * we are looking for.
 444: 		 */
 445:         ignore(strcat(strcat(strcpy(nb, dirname), "/"), dirent.d_name));
 446:         if (yeah(nb)) {
 447:             /*
 448: 			 * Well, it is the file we are looking for.
 449: 			 * Is it more recent than any version we found before?
 450: 			 */
 451:             if (H.Time > besttime) {
 452:                 /*
 453: 				 * A winner.
 454: 				 */
 455:                 ignore(close(bestfd));
 456:                 bestfd = dup(tfile);
 457:                 besttime = H.Time;
 458:                 CP(bestnb, nb);
 459:             }
 460:             /*
 461: 			 * Count versions so user can be told there are
 462: 			 * ``yet more pages to be turned''.
 463: 			 */
 464:             vercnt++;
 465:         }
 466:         ignore(close(tfile));
 467:     }
 468:     ignore(fclose(dir));
 469: }
 470: 
 471: /*
 472:  * Given a candidate file to be recovered, see
 473:  * if its really an editor temporary and of this
 474:  * user and the file specified.
 475:  */
 476: yeah(name)
 477:     char *name;
 478: {
 479: 
 480:     tfile = open(name, 2);
 481:     if (tfile < 0)
 482:         return (0);
 483:     if (read(tfile, (char *) &H, sizeof H) != sizeof H) {
 484: nope:
 485:         ignore(close(tfile));
 486:         return (0);
 487:     }
 488:     if (!eq(savedfile, file))
 489:         goto nope;
 490:     if (getuid() != H.Uid)
 491:         goto nope;
 492:     /*
 493: 	 * This is old and stupid code, which
 494: 	 * puts a word LOST in the header block, so that lost lines
 495: 	 * can be made to point at it.
 496: 	 */
 497:     ignorl(lseek(tfile, (long)(BUFSIZ*HBLKS-8), 0));
 498:     ignore(write(tfile, "LOST", 5));
 499:     return (1);
 500: }
 501: 
 502: preserve()
 503: {
 504: 
 505: }
 506: 
 507: /*
 508:  * Find the true end of the scratch file, and ``LOSE''
 509:  * lines which point into thin air.  This lossage occurs
 510:  * due to the sandbagging of i/o which can cause blocks to
 511:  * be written in a non-obvious order, different from the order
 512:  * in which the editor tried to write them.
 513:  *
 514:  * Lines which are lost are replaced with the text LOST so
 515:  * they are easy to find.  We work hard at pretty formatting here
 516:  * as lines tend to be lost in blocks.
 517:  *
 518:  * This only seems to happen on very heavily loaded systems, and
 519:  * not very often.
 520:  */
 521: scrapbad()
 522: {
 523:     register line *ip;
 524:     struct stat stbuf;
 525:     off_t size, maxt;
 526:     int bno, cnt, bad, was;
 527:     char bk[BUFSIZ];
 528: 
 529:     ignore(fstat(tfile, &stbuf));
 530:     size = stbuf.st_size;
 531:     maxt = (size >> SHFT) | (BNDRY-1);
 532:     bno = (maxt >> OFFBTS) & BLKMSK;
 533: #ifdef DEBUG
 534:     fprintf(stderr, "size %ld, maxt %o, bno %d\n", size, maxt, bno);
 535: #endif
 536: 
 537:     /*
 538: 	 * Look for a null separating two lines in the temp file;
 539: 	 * if last line was split across blocks, then it is lost
 540: 	 * if the last block is.
 541: 	 */
 542:     while (bno > 0) {
 543:         ignorl(lseek(tfile, (long) BUFSIZ * bno, 0));
 544:         cnt = read(tfile, (char *) bk, BUFSIZ);
 545:         while (cnt > 0)
 546:             if (bk[--cnt] == 0)
 547:                 goto null;
 548:         bno--;
 549:     }
 550: null:
 551: 
 552:     /*
 553: 	 * Magically calculate the largest valid pointer in the temp file,
 554: 	 * consing it up from the block number and the count.
 555: 	 */
 556:     maxt = ((bno << OFFBTS) | (cnt >> SHFT)) & ~1;
 557: #ifdef DEBUG
 558:     fprintf(stderr, "bno %d, cnt %d, maxt %o\n", bno, cnt, maxt);
 559: #endif
 560: 
 561:     /*
 562: 	 * Now cycle through the line pointers,
 563: 	 * trashing the Lusers.
 564: 	 */
 565:     was = bad = 0;
 566:     for (ip = one; ip <= dol; ip++)
 567:         if (*ip > maxt) {
 568: #ifdef DEBUG
 569:             fprintf(stderr, "%d bad, %o > %o\n", ip - zero, *ip, maxt);
 570: #endif
 571:             if (was == 0)
 572:                 was = ip - zero;
 573:             *ip = ((HBLKS*BUFSIZ)-8) >> SHFT;
 574:         } else if (was) {
 575:             if (bad == 0)
 576:                 fprintf(stderr, " [Lost line(s):");
 577:             fprintf(stderr, " %d", was);
 578:             if ((ip - 1) - zero > was)
 579:                 fprintf(stderr, "-%d", (ip - 1) - zero);
 580:             bad++;
 581:             was = 0;
 582:         }
 583:     if (was != 0) {
 584:         if (bad == 0)
 585:             fprintf(stderr, " [Lost line(s):");
 586:         fprintf(stderr, " %d", was);
 587:         if (dol - zero != was)
 588:             fprintf(stderr, "-%d", dol - zero);
 589:         bad++;
 590:     }
 591:     if (bad)
 592:         fprintf(stderr, "]");
 593: }
 594: 
 595: /*
 596:  * Aw shucks, if we only had a (void) cast.
 597:  */
 598: #ifdef lint
 599: Ignorl(a)
 600:     long a;
 601: {
 602: 
 603:     a = a;
 604: }
 605: 
 606: Ignore(a)
 607:     char *a;
 608: {
 609: 
 610:     a = a;
 611: }
 612: 
 613: Ignorf(a)
 614:     int (*a)();
 615: {
 616: 
 617:     a = a;
 618: }
 619: 
 620: ignorl(a)
 621:     long a;
 622: {
 623: 
 624:     a = a;
 625: }
 626: #endif
 627: 
 628: int cntch, cntln, cntodd, cntnull;
 629: /*
 630:  * Following routines stolen mercilessly from ex.
 631:  */
 632: putfile()
 633: {
 634:     line *a1;
 635:     register char *fp, *lp;
 636:     register int nib;
 637: 
 638:     a1 = addr1;
 639:     clrstats();
 640:     cntln = addr2 - a1 + 1;
 641:     if (cntln == 0)
 642:         return;
 643:     nib = BUFSIZ;
 644:     fp = genbuf;
 645:     do {
 646:         getline(*a1++);
 647:         lp = linebuf;
 648:         for (;;) {
 649:             if (--nib < 0) {
 650:                 nib = fp - genbuf;
 651:                 if (write(io, genbuf, nib) != nib)
 652:                     wrerror();
 653:                 cntch += nib;
 654:                 nib = 511;
 655:                 fp = genbuf;
 656:             }
 657:             if ((*fp++ = *lp++) == 0) {
 658:                 fp[-1] = '\n';
 659:                 break;
 660:             }
 661:         }
 662:     } while (a1 <= addr2);
 663:     nib = fp - genbuf;
 664:     if (write(io, genbuf, nib) != nib)
 665:         wrerror();
 666:     cntch += nib;
 667: }
 668: 
 669: wrerror()
 670: {
 671: 
 672:     syserror();
 673: }
 674: 
 675: clrstats()
 676: {
 677: 
 678:     ninbuf = 0;
 679:     cntch = 0;
 680:     cntln = 0;
 681:     cntnull = 0;
 682:     cntodd = 0;
 683: }
 684: 
 685: #define READ    0
 686: #define WRITE   1
 687: 
 688: getline(tl)
 689:     line tl;
 690: {
 691:     register char *bp, *lp;
 692:     register int nl;
 693: 
 694:     lp = linebuf;
 695:     bp = getblock(tl, READ);
 696:     nl = nleft;
 697:     tl &= ~OFFMSK;
 698:     while (*lp++ = *bp++)
 699:         if (--nl == 0) {
 700:             bp = getblock(tl += INCRMT, READ);
 701:             nl = nleft;
 702:         }
 703: }
 704: 
 705: int read();
 706: int write();
 707: 
 708: char *
 709: getblock(atl, iof)
 710:     line atl;
 711:     int iof;
 712: {
 713:     register int bno, off;
 714: 
 715:     bno = (atl >> OFFBTS) & BLKMSK;
 716:     off = (atl << SHFT) & LBTMSK;
 717:     if (bno >= NMBLKS)
 718:         error(" Tmp file too large");
 719:     nleft = BUFSIZ - off;
 720:     if (bno == iblock) {
 721:         ichanged |= iof;
 722:         return (ibuff + off);
 723:     }
 724:     if (bno == oblock)
 725:         return (obuff + off);
 726:     if (iof == READ) {
 727:         if (ichanged)
 728:             blkio(iblock, ibuff, write);
 729:         ichanged = 0;
 730:         iblock = bno;
 731:         blkio(bno, ibuff, read);
 732:         return (ibuff + off);
 733:     }
 734:     if (oblock >= 0)
 735:         blkio(oblock, obuff, write);
 736:     oblock = bno;
 737:     return (obuff + off);
 738: }
 739: 
 740: blkio(b, buf, iofcn)
 741:     short b;
 742:     char *buf;
 743:     int (*iofcn)();
 744: {
 745: 
 746:     lseek(tfile, (long) (unsigned) b * BUFSIZ, 0);
 747:     if ((*iofcn)(tfile, buf, BUFSIZ) != BUFSIZ)
 748:         syserror();
 749: }
 750: 
 751: syserror()
 752: {
 753:     extern int sys_nerr;
 754:     extern char *sys_errlist[];
 755: 
 756:     dirtcnt = 0;
 757:     write(2, " ", 1);
 758:     if (errno >= 0 && errno <= sys_nerr)
 759:         error(sys_errlist[errno]);
 760:     else
 761:         error("System error %d", errno);
 762:     exit(1);
 763: }

Defined functions

Ignore defined in line 606; never used
Ignorf defined in line 613; used 2 times
Ignorl defined in line 599; never used
blkio defined in line 740; used 3 times
clrstats defined in line 675; used 2 times
enter defined in line 300; used 1 times
findtmp defined in line 370; used 1 times
  • in line 86
getblock defined in line 708; used 2 times
getline defined in line 688; used 1 times
ignorl defined in line 620; never used
listfiles defined in line 202; used 1 times
  • in line 75
main defined in line 55; never used
preserve defined in line 502; used 1 times
  • in line 43
putfile defined in line 632; used 2 times
qucmp defined in line 346; used 2 times
scrapbad defined in line 521; used 1 times
searchdir defined in line 423; used 2 times
syserror defined in line 751; used 10 times
wrerror defined in line 669; used 2 times
yeah defined in line 476; used 1 times

Defined variables

bestfd defined in line 363; used 5 times
bestnb defined in line 361; used 3 times
besttime defined in line 362; used 2 times
cntch defined in line 628; used 3 times
cntln defined in line 628; used 3 times
cntnull defined in line 628; used 1 times
cntodd defined in line 628; used 1 times
mydir defined in line 43; used 3 times
nb defined in line 52; used 7 times
sccsid defined in line 2; never used
tfile defined in line 15; used 18 times
vercnt defined in line 53; used 3 times
xstr defined in line 14; never used

Defined struct's

svfile defined in line 195; used 8 times

Defined macros

NENTRY defined in line 49; used 3 times
READ defined in line 685; used 3 times
WRITE defined in line 686; never used
ignorl defined in line 36; used 4 times
Last modified: 1982-07-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2057
Valid CSS Valid XHTML 1.0 Strict