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