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 #pragma ident "%Z%%M% %I% %E% SMI" 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 #include <unistd.h> 47 #include <errno.h> 48 49 #define DIRSIZ MAXNAMLEN 50 51 short tfile = -1; /* ditto */ 52 53 /* 54 * 55 * This program searches through the specified directory and then 56 * the directory usrpath(preserve) looking for an instance of the specified 57 * file from a crashed editor or a crashed system. 58 * If this file is found, it is unscrambled and written to 59 * the standard output. 60 * 61 * If this program terminates without a "broken pipe" diagnostic 62 * (i.e. the editor doesn't die right away) then the buffer we are 63 * writing from is removed when we finish. This is potentially a mistake 64 * as there is not enough handshaking to guarantee that the file has actually 65 * been recovered, but should suffice for most cases. 66 */ 67 68 /* 69 * This directory definition also appears (obviously) in expreserve.c. 70 * Change both if you change either. 71 */ 72 unsigned char mydir[PATH_MAX+1]; 73 74 /* 75 * Limit on the number of printed entries 76 * when an, e.g. ``ex -r'' command is given. 77 */ 78 #define NENTRY 50 79 80 unsigned char nb[BUFSIZE]; 81 int vercnt; /* Count number of versions of file found */ 82 83 int 84 main(int argc, unsigned char *argv[]) 85 { 86 unsigned char string[50]; 87 register unsigned char *cp; 88 register int c, b, i; 89 register int rflg = 0, errflg = 0; 90 int label; 91 line *tmpadr; 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((const char *)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((const char *)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((const char *)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 int save_err = errno; 815 816 dirtcnt = 0; 817 write(2, " ", 1); 818 error(strerror(save_err)); 819 exit(1); 820 } 821 822 extern findiop(); 823 static int intrupt; 824 825 unsigned char * 826 mypass(prompt) 827 unsigned char *prompt; 828 { 829 struct termio ttyb; 830 unsigned short flags; 831 register unsigned char *p; 832 register int c; 833 static unsigned char pbuf[9]; 834 void (*sig)(); 835 static void catch(); 836 837 setbuf(stdin, (char*)NULL); 838 sig = signal(SIGINT, catch); 839 intrupt = 0; 840 (void) ioctl(fileno(stdin), TCGETA, &ttyb); 841 flags = ttyb.c_lflag; 842 ttyb.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); 843 (void) ioctl(fileno(stdin), TCSETAF, &ttyb); 844 (void) fputs((char *)prompt, stderr); 845 for(p=pbuf; !intrupt && (c = getc(stdin)) != '\n' && c!= '\r' && c != EOF; ) { 846 if(p < &pbuf[8]) 847 *p++ = c; 848 } 849 *p = '\0'; 850 (void) putc('\n', stderr); 851 ttyb.c_lflag = flags; 852 (void) ioctl(fileno(stdin), TCSETA, &ttyb); 853 (void) signal(SIGINT, sig); 854 if(intrupt) 855 (void) kill(getpid(), SIGINT); 856 return(pbuf); 857 } 858 859 static void 860 catch() 861 { 862 ++intrupt; 863 } 864