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