1 /* $OpenBSD: sys_bsd.c,v 1.14 2003/06/03 02:56:18 millert Exp $ */ 2 /* $NetBSD: sys_bsd.c,v 1.11 1996/02/28 21:04:10 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1988, 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include "telnet_locl.h" 34 #include <err.h> 35 36 /* 37 * The following routines try to encapsulate what is system dependent 38 * (at least between 4.x and dos) which is used in telnet.c. 39 */ 40 41 int 42 tout, /* Output file descriptor */ 43 tin, /* Input file descriptor */ 44 net; 45 46 #ifndef USE_TERMIO 47 struct tchars otc = { 0 }, ntc = { 0 }; 48 struct ltchars oltc = { 0 }, nltc = { 0 }; 49 struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 50 int olmode = 0; 51 # define cfgetispeed(ptr) (ptr)->sg_ispeed 52 # define cfgetospeed(ptr) (ptr)->sg_ospeed 53 # define old_tc ottyb 54 55 #else /* USE_TERMIO */ 56 struct termios old_tc = { 0 }; 57 extern struct termios new_tc; 58 59 # ifndef TCSANOW 60 # ifdef TCSETS 61 # define TCSANOW TCSETS 62 # define TCSADRAIN TCSETSW 63 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) 64 # else 65 # ifdef TCSETA 66 # define TCSANOW TCSETA 67 # define TCSADRAIN TCSETAW 68 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) 69 # else 70 # define TCSANOW TIOCSETA 71 # define TCSADRAIN TIOCSETAW 72 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) 73 # endif 74 # endif 75 # define tcsetattr(f, a, t) ioctl(f, a, (char *)t) 76 # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD) 77 # ifdef CIBAUD 78 # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT) 79 # else 80 # define cfgetispeed(ptr) cfgetospeed(ptr) 81 # endif 82 # endif /* TCSANOW */ 83 # ifdef sysV88 84 # define TIOCFLUSH TC_PX_DRAIN 85 # endif 86 #endif /* USE_TERMIO */ 87 88 fd_set *ibitsp, *obitsp, *xbitsp; 89 int fdsn; 90 91 void 92 init_sys() 93 { 94 tout = fileno(stdout); 95 tin = fileno(stdin); 96 97 errno = 0; 98 } 99 100 101 int 102 TerminalWrite(buf, n) 103 char *buf; 104 int n; 105 { 106 return write(tout, buf, n); 107 } 108 109 int 110 TerminalRead(buf, n) 111 unsigned char *buf; 112 int n; 113 { 114 return read(tin, buf, n); 115 } 116 117 /* 118 * 119 */ 120 121 int 122 TerminalAutoFlush() 123 { 124 #if defined(LNOFLSH) 125 int flush; 126 127 ioctl(0, TIOCLGET, (char *)&flush); 128 return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ 129 #else /* LNOFLSH */ 130 return 1; 131 #endif /* LNOFLSH */ 132 } 133 134 #ifdef KLUDGELINEMODE 135 extern int kludgelinemode; 136 #endif 137 /* 138 * TerminalSpecialChars() 139 * 140 * Look at an input character to see if it is a special character 141 * and decide what to do. 142 * 143 * Output: 144 * 145 * 0 Don't add this character. 146 * 1 Do add this character 147 */ 148 149 extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); 150 151 int 152 TerminalSpecialChars(c) 153 int c; 154 { 155 if (c == termIntChar) { 156 intp(); 157 return 0; 158 } else if (c == termQuitChar) { 159 #ifdef KLUDGELINEMODE 160 if (kludgelinemode) 161 sendbrk(); 162 else 163 #endif 164 sendabort(); 165 return 0; 166 } else if (c == termEofChar) { 167 if (my_want_state_is_will(TELOPT_LINEMODE)) { 168 sendeof(); 169 return 0; 170 } 171 return 1; 172 } else if (c == termSuspChar) { 173 sendsusp(); 174 return(0); 175 } else if (c == termFlushChar) { 176 xmitAO(); /* Transmit Abort Output */ 177 return 0; 178 } else if (!MODE_LOCAL_CHARS(globalmode)) { 179 if (c == termKillChar) { 180 xmitEL(); 181 return 0; 182 } else if (c == termEraseChar) { 183 xmitEC(); /* Transmit Erase Character */ 184 return 0; 185 } 186 } 187 return 1; 188 } 189 190 191 /* 192 * Flush output to the terminal 193 */ 194 195 void 196 TerminalFlushOutput() 197 { 198 #ifdef TIOCFLUSH 199 int com = FWRITE; 200 (void) ioctl(fileno(stdout), TIOCFLUSH, (int *) &com); 201 #else 202 (void) ioctl(fileno(stdout), TCFLSH, (int *) 0); 203 #endif 204 } 205 206 void 207 TerminalSaveState() 208 { 209 #ifndef USE_TERMIO 210 ioctl(0, TIOCGETP, (char *)&ottyb); 211 ioctl(0, TIOCGETC, (char *)&otc); 212 ioctl(0, TIOCGLTC, (char *)&oltc); 213 ioctl(0, TIOCLGET, (char *)&olmode); 214 215 ntc = otc; 216 nltc = oltc; 217 nttyb = ottyb; 218 219 #else /* USE_TERMIO */ 220 tcgetattr(0, &old_tc); 221 222 new_tc = old_tc; 223 224 #ifndef VDISCARD 225 termFlushChar = CONTROL('O'); 226 #endif 227 #ifndef VWERASE 228 termWerasChar = CONTROL('W'); 229 #endif 230 #ifndef VREPRINT 231 termRprntChar = CONTROL('R'); 232 #endif 233 #ifndef VLNEXT 234 termLiteralNextChar = CONTROL('V'); 235 #endif 236 #ifndef VSTART 237 termStartChar = CONTROL('Q'); 238 #endif 239 #ifndef VSTOP 240 termStopChar = CONTROL('S'); 241 #endif 242 #ifndef VSTATUS 243 termAytChar = CONTROL('T'); 244 #endif 245 #endif /* USE_TERMIO */ 246 } 247 248 cc_t * 249 tcval(func) 250 int func; 251 { 252 switch(func) { 253 case SLC_IP: return(&termIntChar); 254 case SLC_ABORT: return(&termQuitChar); 255 case SLC_EOF: return(&termEofChar); 256 case SLC_EC: return(&termEraseChar); 257 case SLC_EL: return(&termKillChar); 258 case SLC_XON: return(&termStartChar); 259 case SLC_XOFF: return(&termStopChar); 260 case SLC_FORW1: return(&termForw1Char); 261 #ifdef USE_TERMIO 262 case SLC_FORW2: return(&termForw2Char); 263 # ifdef VDISCARD 264 case SLC_AO: return(&termFlushChar); 265 # endif 266 # ifdef VSUSP 267 case SLC_SUSP: return(&termSuspChar); 268 # endif 269 # ifdef VWERASE 270 case SLC_EW: return(&termWerasChar); 271 # endif 272 # ifdef VREPRINT 273 case SLC_RP: return(&termRprntChar); 274 # endif 275 # ifdef VLNEXT 276 case SLC_LNEXT: return(&termLiteralNextChar); 277 # endif 278 # ifdef VSTATUS 279 case SLC_AYT: return(&termAytChar); 280 # endif 281 #endif 282 283 case SLC_SYNCH: 284 case SLC_BRK: 285 case SLC_EOR: 286 default: 287 return((cc_t *)0); 288 } 289 } 290 291 void 292 TerminalDefaultChars() 293 { 294 #ifndef USE_TERMIO 295 ntc = otc; 296 nltc = oltc; 297 nttyb.sg_kill = ottyb.sg_kill; 298 nttyb.sg_erase = ottyb.sg_erase; 299 #else /* USE_TERMIO */ 300 memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); 301 # ifndef VDISCARD 302 termFlushChar = CONTROL('O'); 303 # endif 304 # ifndef VWERASE 305 termWerasChar = CONTROL('W'); 306 # endif 307 # ifndef VREPRINT 308 termRprntChar = CONTROL('R'); 309 # endif 310 # ifndef VLNEXT 311 termLiteralNextChar = CONTROL('V'); 312 # endif 313 # ifndef VSTART 314 termStartChar = CONTROL('Q'); 315 # endif 316 # ifndef VSTOP 317 termStopChar = CONTROL('S'); 318 # endif 319 # ifndef VSTATUS 320 termAytChar = CONTROL('T'); 321 # endif 322 #endif /* USE_TERMIO */ 323 } 324 325 #ifdef notdef 326 void 327 TerminalRestoreState() 328 { 329 } 330 #endif 331 332 /* 333 * TerminalNewMode - set up terminal to a specific mode. 334 * MODE_ECHO: do local terminal echo 335 * MODE_FLOW: do local flow control 336 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 337 * MODE_EDIT: do local line editing 338 * 339 * Command mode: 340 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 341 * local echo 342 * local editing 343 * local xon/xoff 344 * local signal mapping 345 * 346 * Linemode: 347 * local/no editing 348 * Both Linemode and Single Character mode: 349 * local/remote echo 350 * local/no xon/xoff 351 * local/no signal mapping 352 */ 353 354 #ifdef SIGTSTP 355 static void susp(); 356 #endif /* SIGTSTP */ 357 #ifdef SIGINFO 358 static void ayt(); 359 #endif 360 361 void 362 TerminalNewMode(f) 363 int f; 364 { 365 static int prevmode = 0; 366 #ifndef USE_TERMIO 367 struct tchars tc; 368 struct ltchars ltc; 369 struct sgttyb sb; 370 int lmode; 371 #else /* USE_TERMIO */ 372 struct termios tmp_tc; 373 #endif /* USE_TERMIO */ 374 int onoff; 375 int old; 376 cc_t esc; 377 378 globalmode = f&~MODE_FORCE; 379 if (prevmode == f) 380 return; 381 382 /* 383 * Write any outstanding data before switching modes 384 * ttyflush() returns 0 only when there is no more data 385 * left to write out, it returns -1 if it couldn't do 386 * anything at all, otherwise it returns 1 + the number 387 * of characters left to write. 388 #ifndef USE_TERMIO 389 * We would really like ask the kernel to wait for the output 390 * to drain, like we can do with the TCSADRAIN, but we don't have 391 * that option. The only ioctl that waits for the output to 392 * drain, TIOCSETP, also flushes the input queue, which is NOT 393 * what we want (TIOCSETP is like TCSADFLUSH). 394 #endif 395 */ 396 old = ttyflush(SYNCHing|flushout); 397 if (old < 0 || old > 1) { 398 #ifdef USE_TERMIO 399 tcgetattr(tin, &tmp_tc); 400 #endif /* USE_TERMIO */ 401 do { 402 /* 403 * Wait for data to drain, then flush again. 404 */ 405 #ifdef USE_TERMIO 406 tcsetattr(tin, TCSADRAIN, &tmp_tc); 407 #endif /* USE_TERMIO */ 408 old = ttyflush(SYNCHing|flushout); 409 } while (old < 0 || old > 1); 410 } 411 412 old = prevmode; 413 prevmode = f&~MODE_FORCE; 414 #ifndef USE_TERMIO 415 sb = nttyb; 416 tc = ntc; 417 ltc = nltc; 418 lmode = olmode; 419 #else 420 tmp_tc = new_tc; 421 #endif 422 423 if (f&MODE_ECHO) { 424 #ifndef USE_TERMIO 425 sb.sg_flags |= ECHO; 426 #else 427 tmp_tc.c_lflag |= ECHO; 428 tmp_tc.c_oflag |= ONLCR; 429 if (crlf) 430 tmp_tc.c_iflag |= ICRNL; 431 #endif 432 } else { 433 #ifndef USE_TERMIO 434 sb.sg_flags &= ~ECHO; 435 #else 436 tmp_tc.c_lflag &= ~ECHO; 437 tmp_tc.c_oflag &= ~ONLCR; 438 # ifdef notdef 439 if (crlf) 440 tmp_tc.c_iflag &= ~ICRNL; 441 # endif 442 #endif 443 } 444 445 if ((f&MODE_FLOW) == 0) { 446 #ifndef USE_TERMIO 447 tc.t_startc = _POSIX_VDISABLE; 448 tc.t_stopc = _POSIX_VDISABLE; 449 #else 450 tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */ 451 } else { 452 if (restartany < 0) { 453 tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */ 454 } else if (restartany > 0) { 455 tmp_tc.c_iflag |= IXOFF|IXON|IXANY; 456 } else { 457 tmp_tc.c_iflag |= IXOFF|IXON; 458 tmp_tc.c_iflag &= ~IXANY; 459 } 460 #endif 461 } 462 463 if ((f&MODE_TRAPSIG) == 0) { 464 #ifndef USE_TERMIO 465 tc.t_intrc = _POSIX_VDISABLE; 466 tc.t_quitc = _POSIX_VDISABLE; 467 tc.t_eofc = _POSIX_VDISABLE; 468 ltc.t_suspc = _POSIX_VDISABLE; 469 ltc.t_dsuspc = _POSIX_VDISABLE; 470 #else 471 tmp_tc.c_lflag &= ~ISIG; 472 #endif 473 localchars = 0; 474 } else { 475 #ifdef USE_TERMIO 476 tmp_tc.c_lflag |= ISIG; 477 #endif 478 localchars = 1; 479 } 480 481 if (f&MODE_EDIT) { 482 #ifndef USE_TERMIO 483 sb.sg_flags &= ~CBREAK; 484 sb.sg_flags |= CRMOD; 485 #else 486 tmp_tc.c_lflag |= ICANON; 487 #endif 488 } else { 489 #ifndef USE_TERMIO 490 sb.sg_flags |= CBREAK; 491 if (f&MODE_ECHO) 492 sb.sg_flags |= CRMOD; 493 else 494 sb.sg_flags &= ~CRMOD; 495 #else 496 tmp_tc.c_lflag &= ~ICANON; 497 tmp_tc.c_iflag &= ~ICRNL; 498 tmp_tc.c_cc[VMIN] = 1; 499 tmp_tc.c_cc[VTIME] = 0; 500 #endif 501 } 502 503 if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { 504 #ifndef USE_TERMIO 505 ltc.t_lnextc = _POSIX_VDISABLE; 506 #else 507 tmp_tc.c_lflag &= ~IEXTEN; 508 #endif 509 } 510 511 if (f&MODE_SOFT_TAB) { 512 #ifndef USE_TERMIO 513 sb.sg_flags |= XTABS; 514 #else 515 # ifdef OXTABS 516 tmp_tc.c_oflag |= OXTABS; 517 # endif 518 # ifdef TABDLY 519 tmp_tc.c_oflag &= ~TABDLY; 520 tmp_tc.c_oflag |= TAB3; 521 # endif 522 #endif 523 } else { 524 #ifndef USE_TERMIO 525 sb.sg_flags &= ~XTABS; 526 #else 527 # ifdef OXTABS 528 tmp_tc.c_oflag &= ~OXTABS; 529 # endif 530 # ifdef TABDLY 531 tmp_tc.c_oflag &= ~TABDLY; 532 # endif 533 #endif 534 } 535 536 if (f&MODE_LIT_ECHO) { 537 #ifndef USE_TERMIO 538 lmode &= ~LCTLECH; 539 #else 540 # ifdef ECHOCTL 541 tmp_tc.c_lflag &= ~ECHOCTL; 542 # endif 543 #endif 544 } else { 545 #ifndef USE_TERMIO 546 lmode |= LCTLECH; 547 #else 548 # ifdef ECHOCTL 549 tmp_tc.c_lflag |= ECHOCTL; 550 # endif 551 #endif 552 } 553 554 if (f == -1) { 555 onoff = 0; 556 } else { 557 #ifndef USE_TERMIO 558 if (f & MODE_OUTBIN) 559 lmode |= LLITOUT; 560 else 561 lmode &= ~LLITOUT; 562 563 if (f & MODE_INBIN) 564 lmode |= LPASS8; 565 else 566 lmode &= ~LPASS8; 567 #else 568 if (f & MODE_INBIN) 569 tmp_tc.c_iflag &= ~ISTRIP; 570 else 571 tmp_tc.c_iflag |= ISTRIP; 572 if ((f & MODE_OUTBIN) || (f & MODE_OUT8)) { 573 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 574 tmp_tc.c_cflag |= CS8; 575 if(f & MODE_OUTBIN) 576 tmp_tc.c_oflag &= ~OPOST; 577 else 578 tmp_tc.c_oflag |= OPOST; 579 580 } else { 581 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 582 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB); 583 tmp_tc.c_oflag |= OPOST; 584 } 585 #endif 586 onoff = 1; 587 } 588 589 if (f != -1) { 590 #ifdef SIGTSTP 591 (void) signal(SIGTSTP, susp); 592 #endif /* SIGTSTP */ 593 #ifdef SIGINFO 594 (void) signal(SIGINFO, ayt); 595 #endif 596 #if defined(USE_TERMIO) && defined(NOKERNINFO) 597 tmp_tc.c_lflag |= NOKERNINFO; 598 #endif 599 /* 600 * We don't want to process ^Y here. It's just another 601 * character that we'll pass on to the back end. It has 602 * to process it because it will be processed when the 603 * user attempts to read it, not when we send it. 604 */ 605 #ifndef USE_TERMIO 606 ltc.t_dsuspc = _POSIX_VDISABLE; 607 #else 608 # ifdef VDSUSP 609 tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE); 610 # endif 611 #endif 612 #ifdef USE_TERMIO 613 /* 614 * If the VEOL character is already set, then use VEOL2, 615 * otherwise use VEOL. 616 */ 617 esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape; 618 if ((tmp_tc.c_cc[VEOL] != esc) 619 # ifdef VEOL2 620 && (tmp_tc.c_cc[VEOL2] != esc) 621 # endif 622 ) { 623 if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE)) 624 tmp_tc.c_cc[VEOL] = esc; 625 # ifdef VEOL2 626 else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE)) 627 tmp_tc.c_cc[VEOL2] = esc; 628 # endif 629 } 630 #else 631 if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE)) 632 tc.t_brkc = esc; 633 #endif 634 } else { 635 #ifdef SIGTSTP 636 sigset_t mask; 637 #endif /* SIGTSTP */ 638 #ifdef SIGINFO 639 void ayt_status(); 640 641 (void) signal(SIGINFO, (void (*)(int))ayt_status); 642 #endif 643 #ifdef SIGTSTP 644 (void) signal(SIGTSTP, SIG_DFL); 645 sigemptyset(&mask); 646 sigaddset(&mask, SIGTSTP); 647 sigprocmask(SIG_UNBLOCK, &mask, NULL); 648 #endif /* SIGTSTP */ 649 #ifndef USE_TERMIO 650 ltc = oltc; 651 tc = otc; 652 sb = ottyb; 653 lmode = olmode; 654 #else 655 tmp_tc = old_tc; 656 #endif 657 } 658 #ifndef USE_TERMIO 659 ioctl(tin, TIOCLSET, (char *)&lmode); 660 ioctl(tin, TIOCSLTC, (char *)<c); 661 ioctl(tin, TIOCSETC, (char *)&tc); 662 ioctl(tin, TIOCSETN, (char *)&sb); 663 #else 664 if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) 665 tcsetattr(tin, TCSANOW, &tmp_tc); 666 #endif 667 668 #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 669 # if !defined(sysV88) 670 ioctl(tin, FIONBIO, (char *)&onoff); 671 ioctl(tout, FIONBIO, (char *)&onoff); 672 # endif 673 #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 674 #if defined(TN3270) 675 if (noasynchtty == 0) { 676 ioctl(tin, FIOASYNC, (char *)&onoff); 677 } 678 #endif /* defined(TN3270) */ 679 680 } 681 682 /* 683 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). 684 */ 685 #if B4800 != 4800 686 #define DECODE_BAUD 687 #endif 688 689 #ifdef DECODE_BAUD 690 #ifndef B7200 691 #define B7200 B4800 692 #endif 693 694 #ifndef B14400 695 #define B14400 B9600 696 #endif 697 698 #ifndef B19200 699 # define B19200 B14400 700 #endif 701 702 #ifndef B28800 703 #define B28800 B19200 704 #endif 705 706 #ifndef B38400 707 # define B38400 B28800 708 #endif 709 710 #ifndef B57600 711 #define B57600 B38400 712 #endif 713 714 #ifndef B76800 715 #define B76800 B57600 716 #endif 717 718 #ifndef B115200 719 #define B115200 B76800 720 #endif 721 722 #ifndef B230400 723 #define B230400 B115200 724 #endif 725 726 727 /* 728 * This code assumes that the values B0, B50, B75... 729 * are in ascending order. They do not have to be 730 * contiguous. 731 */ 732 struct termspeeds { 733 long speed; 734 long value; 735 } termspeeds[] = { 736 { 0, B0 }, { 50, B50 }, { 75, B75 }, 737 { 110, B110 }, { 134, B134 }, { 150, B150 }, 738 { 200, B200 }, { 300, B300 }, { 600, B600 }, 739 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 740 { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 }, 741 { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 }, 742 { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 }, 743 { 230400, B230400 }, { -1, B230400 } 744 }; 745 #endif /* DECODE_BAUD */ 746 747 void 748 TerminalSpeeds(ispeed, ospeed) 749 long *ispeed; 750 long *ospeed; 751 { 752 #ifdef DECODE_BAUD 753 struct termspeeds *tp; 754 #endif /* DECODE_BAUD */ 755 long in, out; 756 757 out = cfgetospeed(&old_tc); 758 in = cfgetispeed(&old_tc); 759 if (in == 0) 760 in = out; 761 762 #ifdef DECODE_BAUD 763 tp = termspeeds; 764 while ((tp->speed != -1) && (tp->value < in)) 765 tp++; 766 *ispeed = tp->speed; 767 768 tp = termspeeds; 769 while ((tp->speed != -1) && (tp->value < out)) 770 tp++; 771 *ospeed = tp->speed; 772 #else /* DECODE_BAUD */ 773 *ispeed = in; 774 *ospeed = out; 775 #endif /* DECODE_BAUD */ 776 } 777 778 int 779 TerminalWindowSize(rows, cols) 780 long *rows, *cols; 781 { 782 #ifdef TIOCGWINSZ 783 struct winsize ws; 784 785 if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 786 *rows = ws.ws_row; 787 *cols = ws.ws_col; 788 return 1; 789 } 790 #endif /* TIOCGWINSZ */ 791 return 0; 792 } 793 794 int 795 NetClose(fd) 796 int fd; 797 { 798 return close(fd); 799 } 800 801 802 void 803 NetNonblockingIO(fd, onoff) 804 int fd; 805 int onoff; 806 { 807 ioctl(fd, FIONBIO, (char *)&onoff); 808 } 809 810 #if defined(TN3270) 811 void 812 NetSigIO(fd, onoff) 813 int fd; 814 int onoff; 815 { 816 ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ 817 } 818 819 void 820 NetSetPgrp(fd) 821 int fd; 822 { 823 pid_t myPid; 824 825 myPid = getpid(); 826 fcntl(fd, F_SETOWN, myPid); 827 } 828 #endif /*defined(TN3270)*/ 829 830 /* 831 * Various signal handling routines. 832 */ 833 834 /* ARGSUSED */ 835 void 836 deadpeer(sig) 837 int sig; 838 { 839 setcommandmode(); 840 longjmp(peerdied, -1); 841 } 842 843 volatile sig_atomic_t intr_happened = 0; 844 volatile sig_atomic_t intr_waiting = 0; 845 846 /* ARGSUSED */ 847 void 848 intr(sig) 849 int sig; 850 { 851 if (intr_waiting) { 852 intr_happened = 1; 853 return; 854 } 855 if (localchars) { 856 intp(); 857 return; 858 } 859 setcommandmode(); 860 longjmp(toplevel, -1); 861 } 862 863 /* ARGSUSED */ 864 void 865 intr2(sig) 866 int sig; 867 { 868 if (localchars) { 869 #ifdef KLUDGELINEMODE 870 if (kludgelinemode) 871 sendbrk(); 872 else 873 #endif 874 sendabort(); 875 return; 876 } 877 } 878 879 #ifdef SIGTSTP 880 /* ARGSUSED */ 881 void 882 susp(sig) 883 int sig; 884 { 885 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) 886 return; 887 if (localchars) 888 sendsusp(); 889 } 890 #endif 891 892 #ifdef SIGWINCH 893 /* ARGSUSED */ 894 void 895 sendwin(sig) 896 int sig; 897 { 898 if (connected) { 899 sendnaws(); 900 } 901 } 902 #endif 903 904 #ifdef SIGINFO 905 /* ARGSUSED */ 906 void 907 ayt(sig) 908 int sig; 909 { 910 if (connected) 911 sendayt(); 912 else 913 ayt_status(); 914 } 915 #endif 916 917 918 void 919 sys_telnet_init() 920 { 921 (void) signal(SIGINT, intr); 922 (void) signal(SIGQUIT, intr2); 923 (void) signal(SIGPIPE, deadpeer); 924 #ifdef SIGWINCH 925 (void) signal(SIGWINCH, sendwin); 926 #endif 927 #ifdef SIGTSTP 928 (void) signal(SIGTSTP, susp); 929 #endif 930 #ifdef SIGINFO 931 (void) signal(SIGINFO, ayt); 932 #endif 933 934 setconnmode(0); 935 936 NetNonblockingIO(net, 1); 937 938 #if defined(TN3270) 939 if (noasynchnet == 0) { /* DBX can't handle! */ 940 NetSigIO(net, 1); 941 NetSetPgrp(net); 942 } 943 #endif /* defined(TN3270) */ 944 945 #if defined(SO_OOBINLINE) 946 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 947 perror("SetSockOpt"); 948 } 949 #endif /* defined(SO_OOBINLINE) */ 950 } 951 952 /* 953 * Process rings - 954 * 955 * This routine tries to fill up/empty our various rings. 956 * 957 * The parameter specifies whether this is a poll operation, 958 * or a block-until-something-happens operation. 959 * 960 * The return value is 1 if something happened, 0 if not. 961 */ 962 963 int 964 process_rings(netin, netout, netex, ttyin, ttyout, poll) 965 int poll; /* If 0, then block until something to do */ 966 { 967 int c; 968 /* One wants to be a bit careful about setting returnValue 969 * to one, since a one implies we did some useful work, 970 * and therefore probably won't be called to block next 971 * time (TN3270 mode only). 972 */ 973 int returnValue = 0; 974 static struct timeval TimeValue = { 0 }; 975 int maxfd = -1; 976 int tmp; 977 978 if ((netout || netin || netex) && net > maxfd) 979 maxfd = net; 980 if (ttyout && tout > maxfd) 981 maxfd = tout; 982 if (ttyin && tin > maxfd) 983 maxfd = tin; 984 tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask); 985 if (tmp > fdsn) { 986 if (ibitsp) 987 free(ibitsp); 988 if (obitsp) 989 free(obitsp); 990 if (xbitsp) 991 free(xbitsp); 992 fdsn = tmp; 993 if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL) 994 err(1, "malloc"); 995 if ((obitsp = (fd_set *)malloc(fdsn)) == NULL) 996 err(1, "malloc"); 997 if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL) 998 err(1, "malloc"); 999 memset(ibitsp, 0, fdsn); 1000 memset(obitsp, 0, fdsn); 1001 memset(xbitsp, 0, fdsn); 1002 } 1003 1004 if (netout) 1005 FD_SET(net, obitsp); 1006 if (ttyout) 1007 FD_SET(tout, obitsp); 1008 if (ttyin) 1009 FD_SET(tin, ibitsp); 1010 if (netin) 1011 FD_SET(net, ibitsp); 1012 if (netex) 1013 FD_SET(net, xbitsp); 1014 1015 if ((c = select(maxfd+1, ibitsp, obitsp, xbitsp, 1016 (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { 1017 if (c == -1) { 1018 /* 1019 * we can get EINTR if we are in line mode, 1020 * and the user does an escape (TSTP), or 1021 * some other signal generator. 1022 */ 1023 if (errno == EINTR) { 1024 return 0; 1025 } 1026 # if defined(TN3270) 1027 /* 1028 * we can get EBADF if we were in transparent 1029 * mode, and the transcom process died. 1030 */ 1031 if (errno == EBADF) { 1032 /* 1033 * zero the bits (even though kernel does it) 1034 * to make sure we are selecting on the right 1035 * ones. 1036 */ 1037 memset(ibitsp, 0, fdsn); 1038 memset(obitsp, 0, fdsn); 1039 memset(xbitsp, 0, fdsn); 1040 return 0; 1041 } 1042 # endif /* defined(TN3270) */ 1043 /* I don't like this, does it ever happen? */ 1044 printf("sleep(5) from telnet, after select\r\n"); 1045 sleep(5); 1046 } 1047 return 0; 1048 } 1049 1050 /* 1051 * Any urgent data? 1052 */ 1053 if (FD_ISSET(net, xbitsp)) { 1054 FD_CLR(net, xbitsp); 1055 SYNCHing = 1; 1056 (void) ttyflush(1); /* flush already enqueued data */ 1057 } 1058 1059 /* 1060 * Something to read from the network... 1061 */ 1062 if (FD_ISSET(net, ibitsp)) { 1063 int canread; 1064 1065 FD_CLR(net, ibitsp); 1066 canread = ring_empty_consecutive(&netiring); 1067 #if !defined(SO_OOBINLINE) 1068 /* 1069 * In 4.2 (and some early 4.3) systems, the 1070 * OOB indication and data handling in the kernel 1071 * is such that if two separate TCP Urgent requests 1072 * come in, one byte of TCP data will be overlaid. 1073 * This is fatal for Telnet, but we try to live 1074 * with it. 1075 * 1076 * In addition, in 4.2 (and...), a special protocol 1077 * is needed to pick up the TCP Urgent data in 1078 * the correct sequence. 1079 * 1080 * What we do is: if we think we are in urgent 1081 * mode, we look to see if we are "at the mark". 1082 * If we are, we do an OOB receive. If we run 1083 * this twice, we will do the OOB receive twice, 1084 * but the second will fail, since the second 1085 * time we were "at the mark", but there wasn't 1086 * any data there (the kernel doesn't reset 1087 * "at the mark" until we do a normal read). 1088 * Once we've read the OOB data, we go ahead 1089 * and do normal reads. 1090 * 1091 * There is also another problem, which is that 1092 * since the OOB byte we read doesn't put us 1093 * out of OOB state, and since that byte is most 1094 * likely the TELNET DM (data mark), we would 1095 * stay in the TELNET SYNCH (SYNCHing) state. 1096 * So, clocks to the rescue. If we've "just" 1097 * received a DM, then we test for the 1098 * presence of OOB data when the receive OOB 1099 * fails (and AFTER we did the normal mode read 1100 * to clear "at the mark"). 1101 */ 1102 if (SYNCHing) { 1103 int atmark; 1104 static int bogus_oob = 0, first = 1; 1105 1106 ioctl(net, SIOCATMARK, (char *)&atmark); 1107 if (atmark) { 1108 c = recv(net, netiring.supply, canread, MSG_OOB); 1109 if ((c == -1) && (errno == EINVAL)) { 1110 c = recv(net, netiring.supply, canread, 0); 1111 if (clocks.didnetreceive < clocks.gotDM) { 1112 SYNCHing = stilloob(net); 1113 } 1114 } else if (first && c > 0) { 1115 /* 1116 * Bogosity check. Systems based on 4.2BSD 1117 * do not return an error if you do a second 1118 * recv(MSG_OOB). So, we do one. If it 1119 * succeeds and returns exactly the same 1120 * data, then assume that we are running 1121 * on a broken system and set the bogus_oob 1122 * flag. (If the data was different, then 1123 * we probably got some valid new data, so 1124 * increment the count...) 1125 */ 1126 int i; 1127 i = recv(net, netiring.supply + c, canread - c, MSG_OOB); 1128 if (i == c && 1129 memcmp(netiring.supply, netiring.supply + c, i) == 0) { 1130 bogus_oob = 1; 1131 first = 0; 1132 } else if (i < 0) { 1133 bogus_oob = 0; 1134 first = 0; 1135 } else 1136 c += i; 1137 } 1138 if (bogus_oob && c > 0) { 1139 int i; 1140 /* 1141 * Bogosity. We have to do the read 1142 * to clear the atmark to get out of 1143 * an infinate loop. 1144 */ 1145 i = read(net, netiring.supply + c, canread - c); 1146 if (i > 0) 1147 c += i; 1148 } 1149 } else { 1150 c = recv(net, netiring.supply, canread, 0); 1151 } 1152 } else { 1153 c = recv(net, netiring.supply, canread, 0); 1154 } 1155 settimer(didnetreceive); 1156 #else /* !defined(SO_OOBINLINE) */ 1157 c = recv(net, (char *)netiring.supply, canread, 0); 1158 #endif /* !defined(SO_OOBINLINE) */ 1159 if (c < 0 && errno == EWOULDBLOCK) { 1160 c = 0; 1161 } else if (c <= 0) { 1162 return -1; 1163 } 1164 if (netdata) { 1165 Dump('<', netiring.supply, c); 1166 } 1167 if (c) 1168 ring_supplied(&netiring, c); 1169 returnValue = 1; 1170 } 1171 1172 /* 1173 * Something to read from the tty... 1174 */ 1175 if (FD_ISSET(tin, ibitsp)) { 1176 FD_CLR(tin, ibitsp); 1177 c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 1178 if (c < 0 && errno == EIO) 1179 c = 0; 1180 if (c < 0 && errno == EWOULDBLOCK) { 1181 c = 0; 1182 } else { 1183 /* EOF detection for line mode!!!! */ 1184 if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 1185 /* must be an EOF... */ 1186 *ttyiring.supply = termEofChar; 1187 c = 1; 1188 } 1189 if (c <= 0) { 1190 return -1; 1191 } 1192 if (termdata) { 1193 Dump('<', ttyiring.supply, c); 1194 } 1195 ring_supplied(&ttyiring, c); 1196 } 1197 returnValue = 1; /* did something useful */ 1198 } 1199 1200 if (FD_ISSET(net, obitsp)) { 1201 FD_CLR(net, obitsp); 1202 returnValue |= netflush(); 1203 } 1204 if (FD_ISSET(tout, obitsp)) { 1205 FD_CLR(tout, obitsp); 1206 returnValue |= (ttyflush(SYNCHing|flushout) > 0); 1207 } 1208 1209 return returnValue; 1210 } 1211