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: }

Defined functions

Ignore defined in line 614; never used
Ignorf defined in line 621; never used
Ignorl defined in line 607; never used
blkio defined in line 748; used 3 times
clrstats defined in line 683; used 2 times
enter defined in line 312; used 1 times
findtmp defined in line 381; used 1 times
getblock defined in line 716; used 2 times
getline defined in line 696; used 1 times
ignorl defined in line 628; never used
listfiles defined in line 216; used 1 times
  • in line 89
main defined in line 69; never used
preserve defined in line 510; used 1 times
  • in line 57
putfile defined in line 640; used 2 times
qucmp defined in line 357; used 2 times
scrapbad defined in line 529; used 1 times
searchdir defined in line 434; used 2 times
syserror defined in line 759; used 2 times
wrerror defined in line 677; used 2 times
yeah defined in line 484; used 1 times

Defined variables

bestfd defined in line 374; used 5 times
bestnb defined in line 372; used 3 times
besttime defined in line 373; used 2 times
cntch defined in line 636; used 3 times
cntln defined in line 636; used 3 times
cntnull defined in line 636; used 1 times
cntodd defined in line 636; used 1 times
copyright defined in line 8; never used
mydir defined in line 57; used 3 times
nb defined in line 66; used 7 times
sccsid defined in line 14; never used
tfile defined in line 29; used 18 times
vercnt defined in line 67; used 3 times
xstr defined in line 28; never used

Defined struct's

svfile defined in line 209; used 8 times

Defined macros

NENTRY defined in line 63; used 3 times
READ defined in line 693; used 3 times
WRITE defined in line 694; never used
ignorl defined in line 50; used 4 times
Last modified: 1985-06-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2381
Valid CSS Valid XHTML 1.0 Strict