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