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
main(int argc,char * argv[])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
error(str,inf)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
listfiles(unsigned char * dirname)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
enter(struct svfile * fp,unsigned char * fname,int count)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
qucmp(struct svfile * p1,struct svfile * p2)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
findtmp(unsigned char * dir)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
searchdir(unsigned char * dirname)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
yeah(unsigned char * name)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
scrapbad(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
rputfile(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
wrerror(void)737 wrerror(void)
738 {
739
740 rsyserror();
741 }
742
743 void
clrstats(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
getaline(line tl)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 *
getblock(atl)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
blkio(short b,unsigned char * buf,int (* iofcn)())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
rsyserror(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 *
mypass(prompt)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
catch()868 catch()
869 {
870 ++intrupt;
871 }
872