xref: /illumos-gate/usr/src/cmd/vi/port/exrecover.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25 */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 /* Copyright (c) 1981 Regents of the University of California */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 #include <stdio.h>	/* BUFSIZ: stdio = 1024, VMUNIX = 1024 */
36 #ifndef TRACE
37 #undef	NULL
38 #endif
39 
40 #include "ex.h"
41 #include "ex_temp.h"
42 #include "ex_tty.h"
43 #include "ex_tune.h"
44 #include <pwd.h>
45 #include <locale.h>
46 #include <dirent.h>
47 #include <unistd.h>
48 #include <errno.h>
49 
50 #define DIRSIZ	MAXNAMLEN
51 
52 short tfile = -1;	/* ditto */
53 
54 /*
55  *
56  * This program searches through the specified directory and then
57  * the directory usrpath(preserve) looking for an instance of the specified
58  * file from a crashed editor or a crashed system.
59  * If this file is found, it is unscrambled and written to
60  * the standard output.
61  *
62  * If this program terminates without a "broken pipe" diagnostic
63  * (i.e. the editor doesn't die right away) then the buffer we are
64  * writing from is removed when we finish.  This is potentially a mistake
65  * as there is not enough handshaking to guarantee that the file has actually
66  * been recovered, but should suffice for most cases.
67  */
68 
69 /*
70  * This directory definition also appears (obviously) in expreserve.c.
71  * Change both if you change either.
72  */
73 unsigned char	mydir[PATH_MAX+1];
74 
75 /*
76  * Limit on the number of printed entries
77  * when an, e.g. ``ex -r'' command is given.
78  */
79 #define	NENTRY	50
80 
81 unsigned char	nb[BUFSIZE];
82 int	vercnt;			/* Count number of versions of file found */
83 void rputfile(void);
84 void rsyserror(void);
85 void searchdir(unsigned char *);
86 void scrapbad(void);
87 void findtmp(unsigned char *);
88 void listfiles(unsigned char *);
89 
90 int
91 main(int argc, char *argv[])
92 {
93 	unsigned char string[50];
94 	unsigned char *cp;
95 	int c, b, i;
96 	int rflg = 0, errflg = 0;
97 	int label;
98 	line *tmpadr;
99 	extern unsigned char *mypass();
100 	struct passwd *pp = getpwuid(getuid());
101 	unsigned char rmcmd[PATH_MAX+1];
102 
103 	(void)setlocale(LC_ALL, "");
104 #if !defined(TEXT_DOMAIN)
105 #define TEXT_DOMAIN "SYS_TEST"
106 #endif
107 	(void)textdomain(TEXT_DOMAIN);
108 	cp = string;
109 	strcpy(mydir, USRPRESERVE);
110 	if (pp == NULL) {
111 		fprintf(stderr, gettext("Unable to get user's id\n"));
112 		exit(-1);
113 	}
114 	strcat(mydir, pp->pw_name);
115 
116 	/*
117 	 * Initialize as though the editor had just started.
118 	 */
119 	fendcore = (line *) sbrk(0);
120 	dot = zero = dol = fendcore;
121 	one = zero + 1;
122 	endcore = fendcore - 2;
123 	iblock = oblock = -1;
124 
125 	while ((c=getopt(argc, (char **)argv, "rx")) != EOF)
126 		switch (c) {
127 			case 'r':
128 				rflg++;
129 				break;
130 
131 			case 'x':
132 				xflag++;
133 				break;
134 
135 			case '?':
136 				errflg++;
137 				break;
138 		}
139 	argc -= optind;
140 	argv = &argv[optind];
141 
142 	if (errflg)
143 		exit(2);
144 
145 	/*
146 	 * If given only a -r argument, then list the saved files.
147 	 * (NOTE: single -r argument is scheduled to be replaced by -L).
148 	 */
149 	if (rflg && argc == 0) {
150 		fprintf(stderr,"%s:\n", mydir);
151 		listfiles(mydir);
152 		fprintf(stderr,"%s:\n", TMPDIR);
153 		listfiles((unsigned char *)TMPDIR);
154 		exit(0);
155 	}
156 
157 	if (argc != 2)
158 		error(gettext(" Wrong number of arguments to exrecover"), 0);
159 
160 	CP(file, argv[1]);
161 
162 	/*
163 	 * Search for this file.
164 	 */
165 	findtmp((unsigned char *)argv[0]);
166 
167 	/*
168 	 * Got (one of the versions of) it, write it back to the editor.
169 	 */
170 	(void)cftime((char *)cp, "%a %h %d %T", &H.Time);
171 	fprintf(stderr, vercnt > 1 ?
172 		gettext(" [Dated: %s, newest of %d saved]") :
173 		gettext(" [Dated: %s]"), cp, vercnt);
174 	fprintf(stderr, "\r\n");
175 
176 	if(H.encrypted) {
177 		if(xflag) {
178 			kflag = run_setkey(perm, (unsigned char *)getenv("CrYpTkEy"));
179 		} else
180 			kflag = run_setkey(perm, mypass("Enter key:"));
181 		if(kflag == -1) {
182 			kflag = 0;
183 			xflag = 0;
184 			fprintf(stderr,gettext("Encryption facility not available\n"));
185 			exit(-1);
186 		}
187                 xtflag = 1;
188                 if (makekey(tperm) != 0) {
189 			xtflag = 0;
190 			fprintf(stderr,gettext("Warning--Cannot encrypt temporary buffer\n"));
191 			exit(-1);
192         	}
193 	}
194 	fprintf(stderr,gettext("\r\n [Hit return to continue]"));
195 	fflush(stderr);
196 	setbuf(stdin, (char *)NULL);
197 	while((c = getchar()) != '\n' && c != '\r');
198 	H.Flines++;
199 
200 	/*
201 	 * Allocate space for the line pointers from the temp file.
202 	 */
203 	if ((int) sbrk((int) (H.Flines * sizeof (line))) == -1)
204 		error(gettext(" Not enough core for lines"), 0);
205 #ifdef DEBUG
206 	fprintf(stderr, "%d lines\n", H.Flines);
207 #endif
208 
209 	/*
210 	 * Now go get the blocks of seek pointers which are scattered
211 	 * throughout the temp file, reconstructing the incore
212 	 * line pointers at point of crash.
213 	 */
214 	b = 0;
215 	while (H.Flines > 0) {
216 		(void)lseek(tfile, (long) blocks[b] * BUFSIZE, 0);
217 		i = H.Flines < BUFSIZE / sizeof (line) ?
218 			H.Flines * sizeof (line) : BUFSIZE;
219 		if (read(tfile, (char *) dot, i) != i) {
220 			perror((char *)nb);
221 			exit(1);
222 		}
223 		dot += i / sizeof (line);
224 		H.Flines -= i / sizeof (line);
225 		b++;
226 	}
227 	dot--; dol = dot;
228 
229 	/*
230 	 * Due to sandbagging some lines may really not be there.
231 	 * Find and discard such.  This shouldn't happen often.
232 	 */
233 	scrapbad();
234 
235 
236 	/*
237 	 * Now if there were any lines in the recovered file
238 	 * write them to the standard output.
239 	 */
240 	if (dol > zero) {
241 		addr1 = one; addr2 = dol; io = 1;
242 		rputfile();
243 	}
244 	/*
245 	 * Trash the saved buffer.
246 	 * Hopefully the system won't crash before the editor
247 	 * syncs the new recovered buffer; i.e. for an instant here
248 	 * you may lose if the system crashes because this file
249 	 * is gone, but the editor hasn't completed reading the recovered
250 	 * file from the pipe from us to it.
251 	 *
252 	 * This doesn't work if we are coming from an non-absolute path
253 	 * name since we may have chdir'ed but what the hay, noone really
254 	 * ever edits with temporaries in "." anyways.
255 	 */
256 	if (nb[0] == '/') {
257 		(void)unlink((const char *)nb);
258 		sprintf((char *)rmcmd, "rmdir %s 2> /dev/null", (char *)mydir);
259 		system((char *)rmcmd);
260 	}
261 	return (0);
262 }
263 
264 /*
265  * Print an error message (notably not in error
266  * message file).  If terminal is in RAW mode, then
267  * we should be writing output for "vi", so don't print
268  * a newline which would mess up the screen.
269  */
270 /*VARARGS2*/
271 void
272 error(str, inf)
273 	unsigned char *str;
274 	int inf;
275 {
276 
277 	struct termio termio;
278 	if (inf)
279 		fprintf(stderr, (char *)str, inf);
280 	else
281 		fprintf(stderr, (char *)str);
282 
283 	ioctl(2, TCGETA, &termio);
284 	if (termio.c_lflag & ICANON)
285 		fprintf(stderr, "\n");
286 	exit(1);
287 }
288 
289 /*
290  * Here we save the information about files, when
291  * you ask us what files we have saved for you.
292  * We buffer file name, number of lines, and the time
293  * at which the file was saved.
294  */
295 struct svfile {
296 	unsigned char	sf_name[FNSIZE + 1];
297 	int	sf_lines;
298 	unsigned char	sf_entry[DIRSIZ + 1];
299 	time_t	sf_time;
300 	short	sf_encrypted;
301 };
302 void enter(struct svfile *, unsigned char *, int);
303 
304 void
305 listfiles(unsigned char *dirname)
306 {
307 	DIR *dir;
308 	struct dirent64 *direntry;
309 	int ecount, qucmp();
310 	int f;
311 	unsigned char cp[50];
312 	unsigned char cp2[50];
313 	unsigned char *filname;
314 	struct svfile *fp, svbuf[NENTRY];
315 
316 	/*
317 	 * Open usrpath(preserve), and go there to make things quick.
318 	 */
319 	if ((dir = opendir((char *)dirname)) == NULL)
320 	{
321 		fprintf(stderr,gettext("No files saved.\n"));
322 		return;
323 	}
324 	if (chdir((const char *)dirname) < 0) {
325 		perror((char *)dirname);
326 		return;
327 	}
328 
329 	/*
330 	 * Look at the candidate files in usrpath(preserve).
331 	 */
332 	fp = &svbuf[0];
333 	ecount = 0;
334 	while ((direntry = readdir64(dir)) != NULL)
335 	{
336 		filname = (unsigned char *)direntry->d_name;
337 		if (filname[0] != 'E')
338 			continue;
339 #ifdef DEBUG
340 		fprintf(stderr, "considering %s\n", filname);
341 #endif
342 		/*
343 		 * Name begins with E; open it and
344 		 * make sure the uid in the header is our uid.
345 		 * If not, then don't bother with this file, it can't
346 		 * be ours.
347 		 */
348 		f = open(filname, 0);
349 		if (f < 0) {
350 #ifdef DEBUG
351 			fprintf(stderr, "open failed\n");
352 #endif
353 			continue;
354 		}
355 		if (read(f, (char *) &H, sizeof H) != sizeof H) {
356 #ifdef DEBUG
357 			fprintf(stderr, "could not read header\n");
358 #endif
359 			(void)close(f);
360 			continue;
361 		}
362 		(void)close(f);
363 		if (getuid() != H.Uid) {
364 #ifdef DEBUG
365 			fprintf(stderr, "uid wrong\n");
366 #endif
367 			continue;
368 		}
369 
370 		/*
371 		 * Saved the day!
372 		 */
373 		enter(fp++, filname, ecount);
374 		ecount++;
375 #ifdef DEBUG
376 		fprintf(stderr, "entered file %s\n", filname);
377 #endif
378 	}
379 	(void)closedir(dir);
380 	/*
381 	 * If any files were saved, then sort them and print
382 	 * them out.
383 	 */
384 	if (ecount == 0) {
385 		fprintf(stderr, gettext("No files saved.\n"));
386 		return;
387 	}
388 	qsort(&svbuf[0], ecount, sizeof svbuf[0], qucmp);
389 	for (fp = &svbuf[0]; fp < &svbuf[ecount]; fp++) {
390 		(void)cftime((char *)cp, "%a %b %d", &fp->sf_time);
391 		(void)cftime((char *)cp2, "%R", &fp->sf_time);
392 		fprintf(stderr,
393 		    gettext("On %s at %s, saved %d lines of file \"%s\" "),
394 		    cp, cp2, fp->sf_lines, fp->sf_name);
395 		fprintf(stderr, "%s\n",
396 		    (fp->sf_encrypted) ? gettext("[ENCRYPTED]") : "");
397 	}
398 }
399 
400 /*
401  * Enter a new file into the saved file information.
402  */
403 void
404 enter(struct svfile *fp, unsigned char *fname, int count)
405 {
406 	unsigned char *cp, *cp2;
407 	struct svfile *f, *fl;
408 	time_t curtime;
409 
410 	f = 0;
411 	if (count >= NENTRY) {
412 	        /*
413 		 * Trash the oldest as the most useless.
414 		 */
415 		fl = fp - count + NENTRY - 1;
416 		curtime = fl->sf_time;
417 		for (f = fl; --f > fp-count; )
418 			if (f->sf_time < curtime)
419 				curtime = f->sf_time;
420 		for (f = fl; --f > fp-count; )
421 			if (f->sf_time == curtime)
422 				break;
423 		fp = f;
424 	}
425 
426 	/*
427 	 * Gotcha.
428 	 */
429 	fp->sf_time = H.Time;
430 	fp->sf_lines = H.Flines;
431 	fp->sf_encrypted = H.encrypted;
432 	for (cp2 = fp->sf_name, cp = savedfile; *cp;)
433 		*cp2++ = *cp++;
434 	*cp2++ = 0;
435 	for (cp2 = fp->sf_entry, cp = fname; *cp && cp-fname < 14;)
436 		*cp2++ = *cp++;
437 	*cp2++ = 0;
438 }
439 
440 /*
441  * Do the qsort compare to sort the entries first by file name,
442  * then by modify time.
443  */
444 int
445 qucmp(struct svfile *p1, struct svfile *p2)
446 {
447 	int t;
448 
449 	if (t = strcmp(p1->sf_name, p2->sf_name))
450 		return(t);
451 	if (p1->sf_time > p2->sf_time)
452 		return(-1);
453 	return(p1->sf_time < p2->sf_time);
454 }
455 
456 /*
457  * Scratch for search.
458  */
459 unsigned char	bestnb[BUFSIZE];		/* Name of the best one */
460 long	besttime = 0;		/* Time at which the best file was saved */
461 int	bestfd;			/* Keep best file open so it dont vanish */
462 
463 /*
464  * Look for a file, both in the users directory option value
465  * (i.e. usually /tmp) and in usrpath(preserve).
466  * Want to find the newest so we search on and on.
467  */
468 void
469 findtmp(unsigned char *dir)
470 {
471 
472 	/*
473 	 * No name or file so far.
474 	 */
475 	bestnb[0] = 0;
476 	bestfd = -1;
477 
478 	/*
479 	 * Search usrpath(preserve) and, if we can get there, /tmp
480 	 * (actually the user's "directory" option).
481 	 */
482 	searchdir(dir);
483 	if (chdir((const char *)mydir) == 0)
484 		searchdir(mydir);
485 	if (bestfd != -1) {
486 		/*
487 		 * Gotcha.
488 		 * Put the file (which is already open) in the file
489 		 * used by the temp file routines, and save its
490 		 * name for later unlinking.
491 		 */
492 		tfile = bestfd;
493 		CP(nb, bestnb);
494 		(void)lseek(tfile, 0l, 0);
495 
496 		/*
497 		 * Gotta be able to read the header or fall through
498 		 * to lossage.
499 		 */
500 		if (read(tfile, (char *) &H, sizeof H) == sizeof H)
501 			return;
502 	}
503 
504 	/*
505 	 * Extreme lossage...
506 	 */
507 	error((unsigned char *)gettext(" File not found"), 0);
508 }
509 
510 /*
511  * Search for the file in directory dirname.
512  *
513  * Don't chdir here, because the users directory
514  * may be ".", and we would move away before we searched it.
515  * Note that we actually chdir elsewhere (because it is too slow
516  * to look around in usrpath(preserve) without chdir'ing there) so we
517  * can't win, because we don't know the name of '.' and if the path
518  * name of the file we want to unlink is relative, rather than absolute
519  * we won't be able to find it again.
520  */
521 void
522 searchdir(unsigned char *dirname)
523 {
524 	struct dirent64 *direntry;
525 	DIR *dir;
526 	unsigned char dbuf[BUFSIZE];
527 	unsigned char *filname;
528 	if ((dir = opendir((char *)dirname)) == NULL)
529 		return;
530 	while ((direntry = readdir64(dir)) != NULL)
531 	{
532 		filname = (unsigned char *)direntry->d_name;
533 		if (filname[0] != 'E' || filname[1] != 'x')
534 			continue;
535 		/*
536 		 * Got a file in the directory starting with Ex...
537 		 * Save a consed up name for the file to unlink
538 		 * later, and check that this is really a file
539 		 * we are looking for.
540 		 */
541 		(void)strcat(strcat(strcpy(nb, dirname), "/"), filname);
542 		if (yeah(nb)) {
543 			/*
544 			 * Well, it is the file we are looking for.
545 			 * Is it more recent than any version we found before?
546 			 */
547 			if (H.Time > besttime) {
548 				/*
549 				 * A winner.
550 				 */
551 				(void)close(bestfd);
552 				bestfd = dup(tfile);
553 				besttime = H.Time;
554 				CP(bestnb, nb);
555 			}
556 			/*
557 			 * Count versions and tell user
558 			 */
559 			vercnt++;
560 		}
561 		(void)close(tfile);
562 	}
563 	(void)closedir(dir);
564 }
565 
566 /*
567  * Given a candidate file to be recovered, see
568  * if it's really an editor temporary and of this
569  * user and the file specified.
570  */
571 int
572 yeah(unsigned char *name)
573 {
574 
575 	tfile = open(name, 2);
576 	if (tfile < 0)
577 		return (0);
578 	if (read(tfile, (char *) &H, sizeof H) != sizeof H) {
579 nope:
580 		(void)close(tfile);
581 		return (0);
582 	}
583 	if (!eq(savedfile, file))
584 		goto nope;
585 	if (getuid() != H.Uid)
586 		goto nope;
587 	/*
588 	 * Old code: puts a word LOST in the header block, so that lost lines
589 	 * can be made to point at it.
590 	 */
591 	(void)lseek(tfile, (long)(BUFSIZE*HBLKS-8), 0);
592 	(void)write(tfile, "LOST", 5);
593 	return (1);
594 }
595 
596 /*
597  * Find the true end of the scratch file, and ``LOSE''
598  * lines which point into thin air.  This lossage occurs
599  * due to the sandbagging of i/o which can cause blocks to
600  * be written in a non-obvious order, different from the order
601  * in which the editor tried to write them.
602  *
603  * Lines which are lost are replaced with the text LOST so
604  * they are easy to find.  We work hard at pretty formatting here
605  * as lines tend to be lost in blocks.
606  *
607  * This only seems to happen on very heavily loaded systems, and
608  * not very often.
609  */
610 void
611 scrapbad(void)
612 {
613 	line *ip;
614 	struct stat64 stbuf;
615 	off_t size, maxt;
616 	int bno, cnt, bad, was;
617 	unsigned char bk[BUFSIZE];
618 
619 	(void)fstat64(tfile, &stbuf);
620 	size = (off_t)stbuf.st_size;
621 	maxt = (size >> SHFT) | (BNDRY-1);
622 	bno = (maxt >> OFFBTS) & BLKMSK;
623 #ifdef DEBUG
624 	fprintf(stderr, "size %ld, maxt %o, bno %d\n", size, maxt, bno);
625 #endif
626 
627 	/*
628 	 * Look for a null separating two lines in the temp file;
629 	 * if last line was split across blocks, then it is lost
630 	 * if the last block is.
631 	 */
632 	while (bno > 0) {
633 		(void)lseek(tfile, (long) BUFSIZE * bno, 0);
634 		cnt = read(tfile, (char *) bk, BUFSIZE);
635 	if(xtflag)
636 		if (run_crypt(0L, bk, CRSIZE, tperm) == -1)
637 		    rsyserror();
638 #ifdef DEBUG
639 	fprintf(stderr,"UNENCRYPTED: BLK %d\n",bno);
640 #endif
641 		while (cnt > 0)
642 			if (bk[--cnt] == 0)
643 				goto null;
644 		bno--;
645 	}
646 null:
647 
648 	/*
649 	 * Magically calculate the largest valid pointer in the temp file,
650 	 * consing it up from the block number and the count.
651 	 */
652 	maxt = ((bno << OFFBTS) | (cnt >> SHFT)) & ~1;
653 #ifdef DEBUG
654 	fprintf(stderr, "bno %d, cnt %d, maxt %o\n", bno, cnt, maxt);
655 #endif
656 
657 	/*
658 	 * Now cycle through the line pointers,
659 	 * trashing the Lusers.
660 	 */
661 	was = bad = 0;
662 	for (ip = one; ip <= dol; ip++)
663 		if (*ip > maxt) {
664 #ifdef DEBUG
665 			fprintf(stderr, "%d bad, %o > %o\n", ip - zero, *ip, maxt);
666 #endif
667 			if (was == 0)
668 				was = ip - zero;
669 			*ip = ((HBLKS*BUFSIZE)-8) >> SHFT;
670 		} else if (was) {
671 			if (bad == 0)
672 				fprintf(stderr, gettext(" [Lost line(s):"));
673 			fprintf(stderr, " %d", was);
674 			if ((ip - 1) - zero > was)
675 				fprintf(stderr, "-%d", (ip - 1) - zero);
676 			bad++;
677 			was = 0;
678 		}
679 	if (was != 0) {
680 		if (bad == 0)
681 			fprintf(stderr, " [Lost line(s):");
682 		fprintf(stderr, " %d", was);
683 		if (dol - zero != was)
684 			fprintf(stderr, "-%d", dol - zero);
685 		bad++;
686 	}
687 	if (bad)
688 		fprintf(stderr, "]");
689 }
690 
691 int	cntch, cntln, cntodd, cntnull;
692 /*
693  * Following routines stolen mercilessly from ex.
694  */
695 void
696 rputfile(void)
697 {
698 	line *a1;
699 	unsigned char *fp, *lp;
700 	int nib;
701 
702 	a1 = addr1;
703 	clrstats();
704 	cntln = addr2 - a1 + 1;
705 	if (cntln == 0)
706 		return;
707 	nib = BUFSIZE;
708 	fp = genbuf;
709 	do {
710 #ifdef DEBUG
711 		fprintf(stderr,"GETTING A LINE \n");
712 #endif
713 		getline(*a1++);
714 		lp = linebuf;
715 #ifdef DEBUG
716 		fprintf(stderr,"LINE:%s\n",linebuf);
717 #endif
718 		for (;;) {
719 			if (--nib < 0) {
720 				nib = fp - genbuf;
721 				if (write(io, genbuf, nib) != nib)
722 					wrerror();
723 				cntch += nib;
724 				nib = BUFSIZE;
725 				fp = genbuf;
726 			}
727 			if ((*fp++ = *lp++) == 0) {
728 				fp[-1] = '\n';
729 				break;
730 			}
731 		}
732 	} while (a1 <= addr2);
733 	nib = fp - genbuf;
734 	if (write(io, genbuf, nib) != nib)
735 		wrerror();
736 	cntch += nib;
737 }
738 
739 void
740 wrerror(void)
741 {
742 
743 	rsyserror();
744 }
745 
746 void
747 clrstats(void)
748 {
749 
750 	ninbuf = 0;
751 	cntch = 0;
752 	cntln = 0;
753 	cntnull = 0;
754 	cntodd = 0;
755 }
756 
757 #define	READ	0
758 #define	WRITE	1
759 
760 void
761 getline(line tl)
762 {
763 	unsigned char *bp, *lp;
764 	int nl;
765 
766 	lp = linebuf;
767 	bp = getblock(tl);
768 	nl = nleft;
769 	tl &= ~OFFMSK;
770 	while (*lp++ = *bp++)
771 		if (--nl == 0) {
772 			bp = getblock(tl += INCRMT);
773 			nl = nleft;
774 		}
775 }
776 
777 int	read();
778 int	write();
779 
780 unsigned char *
781 getblock(atl)
782 	line atl;
783 {
784 	int bno, off;
785         unsigned char *p1, *p2;
786         int n;
787 
788 	bno = (atl >> OFFBTS) & BLKMSK;
789 #ifdef DEBUG
790 	fprintf(stderr,"GETBLOCK: BLK %d\n",bno);
791 #endif
792 	off = (atl << SHFT) & LBTMSK;
793 	if (bno >= NMBLKS)
794 		error((unsigned char *)gettext(" Tmp file too large"));
795 	nleft = BUFSIZE - off;
796 	if (bno == iblock)
797 		return (ibuff + off);
798 	iblock = bno;
799 	blkio(bno, ibuff, read);
800 	if(xtflag)
801 		if (run_crypt(0L, ibuff, CRSIZE, tperm) == -1)
802 		    rsyserror();
803 #ifdef DEBUG
804 	fprintf(stderr,"UNENCRYPTED: BLK %d\n",bno);
805 #endif
806 	return (ibuff + off);
807 }
808 
809 void
810 blkio(short b, unsigned char *buf, int (*iofcn)())
811 {
812 
813 	int rc;
814 	lseek(tfile, (long) (unsigned) b * BUFSIZE, 0);
815 	if ((rc =(*iofcn)(tfile, buf, BUFSIZE)) != BUFSIZE) {
816 		(void)fprintf(stderr,gettext("Failed on BLK: %d with %d/%d\n"),b,rc,BUFSIZE);
817 		perror("");
818 		rsyserror();
819 	}
820 }
821 
822 void
823 rsyserror(void)
824 {
825 	int save_err = errno;
826 
827 	dirtcnt = 0;
828 	write(2, " ", 1);
829 	error(strerror(save_err));
830 	exit(1);
831 }
832 
833 static int intrupt;
834 
835 unsigned char *
836 mypass(prompt)
837 unsigned char	*prompt;
838 {
839 	struct termio ttyb;
840 	unsigned short flags;
841 	unsigned char *p;
842 	int c;
843 	static unsigned char pbuf[9];
844 	void	(*sig)();
845 	static void catch();
846 
847 	setbuf(stdin, (char*)NULL);
848 	sig = signal(SIGINT, catch);
849 	intrupt = 0;
850 	(void) ioctl(fileno(stdin), TCGETA, &ttyb);
851 	flags = ttyb.c_lflag;
852 	ttyb.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
853 	(void) ioctl(fileno(stdin), TCSETAF, &ttyb);
854 	(void) fputs((char *)prompt, stderr);
855 	for(p=pbuf; !intrupt && (c = getc(stdin)) != '\n' && c!= '\r' && c != EOF; ) {
856 		if(p < &pbuf[8])
857 			*p++ = c;
858 	}
859 	*p = '\0';
860 	(void) putc('\n', stderr);
861 	ttyb.c_lflag = flags;
862 	(void) ioctl(fileno(stdin), TCSETA, &ttyb);
863 	(void) signal(SIGINT, sig);
864 	if(intrupt)
865 		(void) kill(getpid(), SIGINT);
866 	return(pbuf);
867 }
868 
869 static void
870 catch()
871 {
872 	++intrupt;
873 }
874