Annotation of 43BSD/ucb/ex/exrecover.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.