1: /* Copyright (c) 1979 Regents of the University of California */
   2: #include "ex.h"
   3: #include "ex_temp.h"
   4: #include "ex_tty.h"
   5: #include "local/uparm.h"
   6: 
   7: #undef  BUFSIZ
   8: #undef  EOF
   9: #undef  NULL
  10: 
  11: #include <stdio.h>
  12: #include <sys/dir.h>
  13: 
  14: /*
  15:  * Ex recovery program
  16:  *	exrecover dir name
  17:  *	exrecover -r
  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();
 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:     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);
 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, 504l, 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) | 7;
 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 = 504 >> 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) != 512)
 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: }

Defined functions

Ignore defined in line 605; never used
Ignorf defined in line 612; never used
Ignorl defined in line 598; never used
blkio defined in line 739; used 3 times
clrstats defined in line 674; used 2 times
enter defined in line 300; used 1 times
findtmp defined in line 369; used 1 times
  • in line 86
getblock defined in line 707; used 2 times
getline defined in line 687; used 1 times
ignorl defined in line 619; never used
listfiles defined in line 202; used 1 times
  • in line 75
main defined in line 55; never used
preserve defined in line 501; used 1 times
  • in line 43
putfile defined in line 631; used 2 times
qucmp defined in line 345; used 2 times
scrapbad defined in line 520; used 1 times
searchdir defined in line 422; used 2 times
syserror defined in line 750; used 2 times
wrerror defined in line 668; used 2 times
yeah defined in line 475; used 1 times

Defined variables

bestfd defined in line 362; used 5 times
bestnb defined in line 360; used 3 times
besttime defined in line 361; used 2 times
cntch defined in line 627; used 3 times
cntln defined in line 627; used 3 times
cntnull defined in line 627; used 1 times
cntodd defined in line 627; used 1 times
mydir defined in line 43; used 3 times
nb defined in line 52; used 7 times
vercnt defined in line 53; used 3 times

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 684; used 3 times
WRITE defined in line 685; never used
ignorl defined in line 36; used 4 times
Last modified: 1980-09-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1829
Valid CSS Valid XHTML 1.0 Strict