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