132147Sminshall /* 233685Sbostic * Copyright (c) 1988 Regents of the University of California. 333685Sbostic * All rights reserved. 433685Sbostic * 542770Sbostic * %sccs.include.redist.c% 633685Sbostic */ 733685Sbostic 833685Sbostic #ifndef lint 9*44361Sborman static char sccsid[] = "@(#)sys_bsd.c 1.27 (Berkeley) 06/28/90"; 1033685Sbostic #endif /* not lint */ 1133685Sbostic 1233685Sbostic /* 1332147Sminshall * The following routines try to encapsulate what is system dependent 1432147Sminshall * (at least between 4.x and dos) which is used in telnet.c. 1532147Sminshall */ 1632147Sminshall 1732147Sminshall 1836274Sminshall #include <fcntl.h> 1932381Sminshall #include <sys/types.h> 2032147Sminshall #include <sys/time.h> 2132531Sminshall #include <sys/socket.h> 2232147Sminshall #include <signal.h> 2332531Sminshall #include <errno.h> 2438689Sborman #include <arpa/telnet.h> 2532147Sminshall 2632381Sminshall #include "ring.h" 2732381Sminshall 2832657Sminshall #include "fdset.h" 2932657Sminshall 3032147Sminshall #include "defines.h" 3132147Sminshall #include "externs.h" 3232147Sminshall #include "types.h" 3332147Sminshall 3440245Sborman #if defined(CRAY) 3540245Sborman #define SIG_FUNC_RET void 3640245Sborman #else 3740245Sborman #define SIG_FUNC_RET int 3840245Sborman #endif 3940245Sborman 4032147Sminshall int 4132531Sminshall tout, /* Output file descriptor */ 4232531Sminshall tin, /* Input file descriptor */ 4336242Sminshall net; 4432147Sminshall 4538689Sborman #ifndef USE_TERMIO 4638689Sborman struct tchars otc = { 0 }, ntc = { 0 }; 4738689Sborman struct ltchars oltc = { 0 }, nltc = { 0 }; 4838689Sborman struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 4938909Sborman int olmode = 0; 5032147Sminshall 5138689Sborman #else /* USE_TERMIO */ 5238689Sborman struct termio old_tc = { 0 }; 5338689Sborman extern struct termio new_tc; 5438689Sborman 5540245Sborman #ifndef TCGETA 56*44361Sborman # ifdef TCGETS 57*44361Sborman # define TCGETA TCGETS 58*44361Sborman # define TCSETA TCSETS 59*44361Sborman # define TCSETAW TCSETSW 60*44361Sborman # else 61*44361Sborman # define TCGETA TIOCGETA 62*44361Sborman # define TCSETA TIOCSETA 63*44361Sborman # define TCSETAW TIOCSETAW 64*44361Sborman # endif 6540245Sborman #endif /* TCGETA */ 6638689Sborman #endif /* USE_TERMIO */ 6738689Sborman 6832531Sminshall static fd_set ibits, obits, xbits; 6932147Sminshall 7032531Sminshall 7132531Sminshall init_sys() 7232531Sminshall { 7332531Sminshall tout = fileno(stdout); 7432531Sminshall tin = fileno(stdin); 7532531Sminshall FD_ZERO(&ibits); 7632531Sminshall FD_ZERO(&obits); 7732531Sminshall FD_ZERO(&xbits); 7832531Sminshall 7932531Sminshall errno = 0; 8032531Sminshall } 8132531Sminshall 8232531Sminshall 8333286Sminshall TerminalWrite(buf, n) 8432147Sminshall char *buf; 8532147Sminshall int n; 8632147Sminshall { 8733286Sminshall return write(tout, buf, n); 8832147Sminshall } 8932147Sminshall 9033286Sminshall TerminalRead(buf, n) 9132147Sminshall char *buf; 9232147Sminshall int n; 9332147Sminshall { 9433286Sminshall return read(tin, buf, n); 9532147Sminshall } 9632147Sminshall 9732147Sminshall /* 9832147Sminshall * 9932147Sminshall */ 10032147Sminshall 10132147Sminshall int 10232553Sminshall TerminalAutoFlush() 10332147Sminshall { 10432147Sminshall #if defined(LNOFLSH) 10532147Sminshall int flush; 10632147Sminshall 10732147Sminshall ioctl(0, TIOCLGET, (char *)&flush); 10832147Sminshall return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ 10932147Sminshall #else /* LNOFLSH */ 11032147Sminshall return 1; 11132147Sminshall #endif /* LNOFLSH */ 11232147Sminshall } 11332147Sminshall 11438689Sborman #ifdef KLUDGELINEMODE 11538689Sborman extern int kludgelinemode; 11638689Sborman #endif 11732147Sminshall /* 11832147Sminshall * TerminalSpecialChars() 11932147Sminshall * 12032147Sminshall * Look at an input character to see if it is a special character 12132147Sminshall * and decide what to do. 12232147Sminshall * 12332147Sminshall * Output: 12432147Sminshall * 12532147Sminshall * 0 Don't add this character. 12632147Sminshall * 1 Do add this character 12732147Sminshall */ 12832147Sminshall 12932147Sminshall int 13032553Sminshall TerminalSpecialChars(c) 13132147Sminshall int c; 13232147Sminshall { 13332553Sminshall void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); 13432147Sminshall 13538689Sborman if (c == termIntChar) { 13632147Sminshall intp(); 13732147Sminshall return 0; 13838689Sborman } else if (c == termQuitChar) { 13938689Sborman #ifdef KLUDGELINEMODE 14038689Sborman if (kludgelinemode) 14138689Sborman sendbrk(); 14238689Sborman else 14338689Sborman #endif 14438689Sborman sendabort(); 14532147Sminshall return 0; 14638689Sborman } else if (c == termEofChar) { 14738689Sborman if (my_want_state_is_will(TELOPT_LINEMODE)) { 14838689Sborman sendeof(); 14938689Sborman return 0; 15038689Sborman } 15138689Sborman return 1; 15238689Sborman } else if (c == termSuspChar) { 15338689Sborman sendsusp(); 15438689Sborman return(0); 15538689Sborman } else if (c == termFlushChar) { 15632147Sminshall xmitAO(); /* Transmit Abort Output */ 15732147Sminshall return 0; 15832147Sminshall } else if (!MODE_LOCAL_CHARS(globalmode)) { 15938689Sborman if (c == termKillChar) { 16032147Sminshall xmitEL(); 16132147Sminshall return 0; 16238689Sborman } else if (c == termEraseChar) { 16332147Sminshall xmitEC(); /* Transmit Erase Character */ 16432147Sminshall return 0; 16532147Sminshall } 16632147Sminshall } 16732147Sminshall return 1; 16832147Sminshall } 16932147Sminshall 17032147Sminshall 17132147Sminshall /* 17232147Sminshall * Flush output to the terminal 17332147Sminshall */ 17432147Sminshall 17532147Sminshall void 17632553Sminshall TerminalFlushOutput() 17732147Sminshall { 17839529Sborman #ifdef TIOCFLUSH 17932147Sminshall (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); 18038689Sborman #else 18138689Sborman (void) ioctl(fileno(stdout), TCFLSH, (char *) 0); 18238689Sborman #endif 18332147Sminshall } 18432147Sminshall 18532147Sminshall void 18632553Sminshall TerminalSaveState() 18732147Sminshall { 18838689Sborman #ifndef USE_TERMIO 18932147Sminshall ioctl(0, TIOCGETP, (char *)&ottyb); 19032147Sminshall ioctl(0, TIOCGETC, (char *)&otc); 19132147Sminshall ioctl(0, TIOCGLTC, (char *)&oltc); 19238909Sborman ioctl(0, TIOCLGET, (char *)&olmode); 19332147Sminshall 19432147Sminshall ntc = otc; 19532147Sminshall nltc = oltc; 19632147Sminshall nttyb = ottyb; 19732254Sminshall 19838689Sborman #else /* USE_TERMIO */ 19938689Sborman ioctl(0, TCGETA, &old_tc); 20038689Sborman 20138689Sborman new_tc = old_tc; 20238689Sborman 203*44361Sborman termFlushChar = CONTROL('O'); 204*44361Sborman termWerasChar = CONTROL('W'); 205*44361Sborman termRprntChar = CONTROL('R'); 206*44361Sborman termLiteralNextChar = CONTROL('V'); 207*44361Sborman termStartChar = CONTROL('Q'); 208*44361Sborman termStopChar = CONTROL('S'); 20938689Sborman #endif /* USE_TERMIO */ 21032147Sminshall } 21132147Sminshall 21240245Sborman cc_t * 21338689Sborman tcval(func) 21438689Sborman register int func; 21538689Sborman { 21638689Sborman switch(func) { 21740245Sborman case SLC_IP: return(&termIntChar); 21840245Sborman case SLC_ABORT: return(&termQuitChar); 21940245Sborman case SLC_EOF: return(&termEofChar); 22040245Sborman case SLC_EC: return(&termEraseChar); 22140245Sborman case SLC_EL: return(&termKillChar); 22240245Sborman case SLC_XON: return(&termStartChar); 22340245Sborman case SLC_XOFF: return(&termStopChar); 224*44361Sborman case SLC_FORW1: return(&termForw1Char); 22539529Sborman #ifndef SYSV_TERMIO 22640245Sborman case SLC_AO: return(&termFlushChar); 22740245Sborman case SLC_SUSP: return(&termSuspChar); 22840245Sborman case SLC_EW: return(&termWerasChar); 22940245Sborman case SLC_RP: return(&termRprntChar); 23040245Sborman case SLC_LNEXT: return(&termLiteralNextChar); 23139529Sborman #endif /* SYSV_TERMIO */ 232*44361Sborman #ifdef USE_TERMIO 233*44361Sborman case SLC_FORW2: return(&termForw2Char); 234*44361Sborman #endif 23538689Sborman 23638689Sborman case SLC_SYNCH: 23738689Sborman case SLC_BRK: 23838689Sborman case SLC_AYT: 23938689Sborman case SLC_EOR: 24038689Sborman default: 24140245Sborman return((cc_t *)0); 24238689Sborman } 24338689Sborman } 24438689Sborman 24532147Sminshall void 24638689Sborman TerminalDefaultChars() 24738689Sborman { 24838689Sborman #ifndef USE_TERMIO 24938689Sborman ntc = otc; 25038689Sborman nltc = oltc; 25138689Sborman nttyb.sg_kill = ottyb.sg_kill; 25238689Sborman nttyb.sg_erase = ottyb.sg_erase; 25338689Sborman #else /* USE_TERMIO */ 25438689Sborman memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); 255*44361Sborman # ifndef VFLUSHO 256*44361Sborman termFlushChar = CONTROL('O'); 25739529Sborman # endif 25839529Sborman # ifndef VWERASE 259*44361Sborman termWerasChar = CONTROL('W'); 26039529Sborman # endif 26139529Sborman # ifndef VREPRINT 262*44361Sborman termRprntChar = CONTROL('R'); 26339529Sborman # endif 26439529Sborman # ifndef VLNEXT 265*44361Sborman termLiteralNextChar = CONTROL('V'); 26639529Sborman # endif 26739529Sborman # ifndef VSTART 268*44361Sborman termStartChar = CONTROL('Q'); 26939529Sborman # endif 27039529Sborman # ifndef VSTOP 271*44361Sborman termStopChar = CONTROL('S'); 27239529Sborman # endif 27338689Sborman #endif /* USE_TERMIO */ 27438689Sborman } 27538689Sborman 276*44361Sborman #ifdef notdef 27738689Sborman void 27832553Sminshall TerminalRestoreState() 27932147Sminshall { 28032147Sminshall } 281*44361Sborman #endif 28232147Sminshall 28332147Sminshall /* 28432147Sminshall * TerminalNewMode - set up terminal to a specific mode. 28538689Sborman * MODE_ECHO: do local terminal echo 28638689Sborman * MODE_FLOW: do local flow control 28738689Sborman * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 28838689Sborman * MODE_EDIT: do local line editing 28938689Sborman * 29038689Sborman * Command mode: 29138689Sborman * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 29238689Sborman * local echo 29338689Sborman * local editing 29438689Sborman * local xon/xoff 29538689Sborman * local signal mapping 29638689Sborman * 29738689Sborman * Linemode: 29838689Sborman * local/no editing 29938689Sborman * Both Linemode and Single Character mode: 30038689Sborman * local/remote echo 30138689Sborman * local/no xon/xoff 30238689Sborman * local/no signal mapping 30332147Sminshall */ 30432147Sminshall 30532147Sminshall 30632147Sminshall void 30733286Sminshall TerminalNewMode(f) 30832147Sminshall register int f; 30932147Sminshall { 31032147Sminshall static int prevmode = 0; 31138689Sborman #ifndef USE_TERMIO 31238689Sborman struct tchars tc; 31338689Sborman struct ltchars ltc; 31432147Sminshall struct sgttyb sb; 31538909Sborman int lmode; 31638689Sborman #else /* USE_TERMIO */ 31738689Sborman struct termio tmp_tc; 31838689Sborman #endif /* USE_TERMIO */ 31932147Sminshall int onoff; 32032147Sminshall int old; 32132147Sminshall 32238689Sborman globalmode = f&~MODE_FORCE; 32332147Sminshall if (prevmode == f) 32432147Sminshall return; 32538689Sborman 32638689Sborman /* 32738689Sborman * Write any outstanding data before switching modes 32838689Sborman * ttyflush() returns 0 only when there is no more data 32938689Sborman * left to write out, it returns -1 if it couldn't do 33038689Sborman * anything at all, otherwise it returns 1 + the number 33138689Sborman * of characters left to write. 33238689Sborman */ 33338689Sborman old = ttyflush(SYNCHing|flushout); 33438689Sborman if (old < 0 || old > 1) { 33538689Sborman #ifndef USE_TERMIO 33638689Sborman ioctl(tin, TIOCGETP, (char *)&sb); 33738689Sborman #else /* USE_TERMIO */ 33838689Sborman ioctl(tin, TCGETA, (char *)&tmp_tc); 33938689Sborman #endif /* USE_TERMIO */ 34038689Sborman do { 34138689Sborman /* 34238689Sborman * Wait for data to drain, then flush again. 34338689Sborman */ 34438689Sborman #ifndef USE_TERMIO 34538689Sborman ioctl(tin, TIOCSETP, (char *)&sb); 34638689Sborman #else /* USE_TERMIO */ 34738689Sborman ioctl(tin, TCSETAW, (char *)&tmp_tc); 34838689Sborman #endif /* USE_TERMIO */ 34938689Sborman old = ttyflush(SYNCHing|flushout); 35038689Sborman } while (old < 0 || old > 1); 35138689Sborman } 35238689Sborman 35332147Sminshall old = prevmode; 35438689Sborman prevmode = f&~MODE_FORCE; 35538689Sborman #ifndef USE_TERMIO 35632147Sminshall sb = nttyb; 35738689Sborman tc = ntc; 35838689Sborman ltc = nltc; 35938909Sborman lmode = olmode; 36038689Sborman #else 36138689Sborman tmp_tc = new_tc; 36238689Sborman #endif 36332147Sminshall 36438689Sborman if (f&MODE_ECHO) { 36538689Sborman #ifndef USE_TERMIO 36638689Sborman sb.sg_flags |= ECHO; 36738689Sborman #else 36838689Sborman tmp_tc.c_lflag |= ECHO; 36938689Sborman tmp_tc.c_oflag |= ONLCR; 37039529Sborman # ifdef notdef 37138689Sborman tmp_tc.c_iflag |= ICRNL; 37239529Sborman # endif 37338689Sborman #endif 37438689Sborman } else { 37538689Sborman #ifndef USE_TERMIO 37638689Sborman sb.sg_flags &= ~ECHO; 37738689Sborman #else 37838689Sborman tmp_tc.c_lflag &= ~ECHO; 37938689Sborman tmp_tc.c_oflag &= ~ONLCR; 38039529Sborman # ifdef notdef 38138689Sborman tmp_tc.c_iflag &= ~ICRNL; 38239529Sborman # endif 38338689Sborman #endif 38438689Sborman } 38532147Sminshall 38638689Sborman if ((f&MODE_FLOW) == 0) { 38738689Sborman #ifndef USE_TERMIO 38838689Sborman tc.t_startc = -1; 38938689Sborman tc.t_stopc = -1; 39038689Sborman #else 39138689Sborman tmp_tc.c_iflag &= ~(IXANY|IXOFF|IXON); 39238689Sborman } else { 39338689Sborman tmp_tc.c_iflag |= IXANY|IXOFF|IXON; 39438689Sborman #endif 39538689Sborman } 39632147Sminshall 39738689Sborman if ((f&MODE_TRAPSIG) == 0) { 39838689Sborman #ifndef USE_TERMIO 39938689Sborman tc.t_intrc = -1; 40038689Sborman tc.t_quitc = -1; 40138689Sborman tc.t_eofc = -1; 40238689Sborman ltc.t_suspc = -1; 40338689Sborman ltc.t_dsuspc = -1; 40438689Sborman #else 40538689Sborman tmp_tc.c_lflag &= ~ISIG; 40638689Sborman #endif 40738689Sborman localchars = 0; 40838689Sborman } else { 40938689Sborman #ifdef USE_TERMIO 41038689Sborman tmp_tc.c_lflag |= ISIG; 41138689Sborman #endif 41238689Sborman localchars = 1; 41338689Sborman } 41438689Sborman 41538689Sborman if (f&MODE_EDIT) { 41638689Sborman #ifndef USE_TERMIO 41738689Sborman sb.sg_flags &= ~CBREAK; 41838689Sborman sb.sg_flags |= CRMOD; 41938689Sborman #else 42038689Sborman tmp_tc.c_lflag |= ICANON; 42138689Sborman #endif 42238689Sborman } else { 42338689Sborman #ifndef USE_TERMIO 42438689Sborman sb.sg_flags |= CBREAK; 42538689Sborman if (f&MODE_ECHO) 42632147Sminshall sb.sg_flags |= CRMOD; 42738689Sborman else 42838689Sborman sb.sg_flags &= ~CRMOD; 42938689Sborman #else 43038689Sborman tmp_tc.c_lflag &= ~ICANON; 43138689Sborman tmp_tc.c_iflag &= ~ICRNL; 43238689Sborman tmp_tc.c_cc[VMIN] = 1; 43338689Sborman tmp_tc.c_cc[VTIME] = 0; 43438689Sborman #endif 43538689Sborman } 43632147Sminshall 437*44361Sborman if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { 438*44361Sborman #ifndef USE_TERMIO 439*44361Sborman ltc.t_lnextc = -1; 440*44361Sborman #else 441*44361Sborman # ifdef VLNEXT 442*44361Sborman tmp_tc.c_cc[VLNEXT] = (cc_t)(-1); 443*44361Sborman # endif 444*44361Sborman #endif 445*44361Sborman } 446*44361Sborman 447*44361Sborman if (f&MODE_SOFT_TAB) { 448*44361Sborman #ifndef USE_TERMIO 449*44361Sborman sb.sg_flags |= XTABS; 450*44361Sborman #else 451*44361Sborman # ifdef OXTABS 452*44361Sborman tmp_tc.c_oflag |= OXTABS; 453*44361Sborman # endif 454*44361Sborman # ifdef TABDLY 455*44361Sborman tmp_tc.c_oflag &= ~TABDLY; 456*44361Sborman tmp_tc.c_oflag |= TAB3; 457*44361Sborman # endif 458*44361Sborman #endif 459*44361Sborman } else { 460*44361Sborman #ifndef USE_TERMIO 461*44361Sborman sb.sg_flags &= ~XTABS; 462*44361Sborman #else 463*44361Sborman # ifdef OXTABS 464*44361Sborman tmp_tc.c_oflag &= ~OXTABS; 465*44361Sborman # endif 466*44361Sborman # ifdef TABDLY 467*44361Sborman tmp_tc.c_oflag &= ~TABDLY; 468*44361Sborman # endif 469*44361Sborman #endif 470*44361Sborman } 471*44361Sborman 472*44361Sborman if (f&MODE_LIT_ECHO) { 473*44361Sborman #ifndef USE_TERMIO 474*44361Sborman sb.sg_flags &= ~CTLECH; 475*44361Sborman #else 476*44361Sborman # ifdef ECHOCTL 477*44361Sborman tmp_tc.c_lflag &= ~ECHOCTL; 478*44361Sborman # endif 479*44361Sborman #endif 480*44361Sborman } else { 481*44361Sborman #ifndef USE_TERMIO 482*44361Sborman sb.sg_flags |= CTLECH; 483*44361Sborman #else 484*44361Sborman # ifdef ECHOCTL 485*44361Sborman tmp_tc.c_lflag |= ECHOCTL; 486*44361Sborman # endif 487*44361Sborman #endif 488*44361Sborman } 489*44361Sborman 49038689Sborman if (f == -1) { 49138689Sborman onoff = 0; 49238689Sborman } else { 49338909Sborman #ifndef USE_TERMIO 49439529Sborman if (f & MODE_OUTBIN) 49538909Sborman lmode |= LLITOUT; 49638909Sborman else 49738909Sborman lmode &= ~LLITOUT; 49839529Sborman 49939529Sborman if (f & MODE_INBIN) 50038909Sborman lmode |= LPASS8; 50138909Sborman else 50238909Sborman lmode &= ~LPASS8; 50338909Sborman #else 50439529Sborman if (f & MODE_OUTBIN) 50539529Sborman tmp_tc.c_lflag &= ~ISTRIP; 50638909Sborman else 50739529Sborman tmp_tc.c_lflag |= ISTRIP; 50839529Sborman if (f & MODE_INBIN) { 50939529Sborman tmp_tc.c_cflag &= ~(CSIZE|PARENB); 51039529Sborman tmp_tc.c_cflag |= CS8; 51139529Sborman tmp_tc.c_cflag &= ~OPOST; 51239529Sborman } else { 51339529Sborman tmp_tc.c_cflag &= ~CSIZE; 51439529Sborman tmp_tc.c_cflag |= CS7|PARENB; 51539529Sborman tmp_tc.c_cflag |= OPOST; 51639529Sborman } 51738909Sborman #endif 51838689Sborman onoff = 1; 51932147Sminshall } 52038689Sborman 52138689Sborman if (f != -1) { 52239529Sborman #ifdef SIGTSTP 523*44361Sborman static void susp(); 52438689Sborman 52540245Sborman (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp); 52639529Sborman #endif /* SIGTSTP */ 527*44361Sborman /* 528*44361Sborman * We don't want to process ^Y here. It's just another 529*44361Sborman * character that we'll pass on to the back end. It has 530*44361Sborman * to process it because it will be processed when the 531*44361Sborman * user attempts to read it, not when we send it. 532*44361Sborman */ 533*44361Sborman #ifndef USE_TERMIO 534*44361Sborman ltc.t_dsuspc = -1; 535*44361Sborman #else 536*44361Sborman # ifdef VDSUSP 537*44361Sborman tmp_tc.c_cc[VDSUSP] = (cc_t)(-1); 538*44361Sborman # endif 539*44361Sborman #endif 54040245Sborman #ifdef USE_TERMIO 54140245Sborman /* 54240245Sborman * If the VEOL character is already set, then use VEOL2, 54340245Sborman * otherwise use VEOL. 54440245Sborman */ 545*44361Sborman if (tmp_tc.c_cc[VEOL] == (cc_t)(-1)) 546*44361Sborman tmp_tc.c_cc[VEOL] = escape; 547*44361Sborman # ifdef VEOL2 548*44361Sborman else if (tmp_tc.c_cc[VEOL2] == (cc_t)(-1)) 54940245Sborman tmp_tc.c_cc[VEOL2] = escape; 550*44361Sborman # endif 55140245Sborman #else 552*44361Sborman if (tc.t_brkc == (cc_t)(-1)) 553*44361Sborman tc.t_brkc = escape; 55440245Sborman #endif 55538689Sborman } else { 55639529Sborman #ifdef SIGTSTP 55738689Sborman (void) signal(SIGTSTP, SIG_DFL); 558*44361Sborman (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 55939529Sborman #endif /* SIGTSTP */ 56039529Sborman #ifndef USE_TERMIO 56139529Sborman ltc = oltc; 56239529Sborman tc = otc; 56339529Sborman sb = ottyb; 564*44361Sborman lmode = olmode; 565*44361Sborman #else 566*44361Sborman tmp_tc = old_tc; 56739529Sborman #endif 56838689Sborman } 56939529Sborman #ifndef USE_TERMIO 57039529Sborman ioctl(tin, TIOCLSET, (char *)&lmode); 57139529Sborman ioctl(tin, TIOCSLTC, (char *)<c); 57239529Sborman ioctl(tin, TIOCSETC, (char *)&tc); 57339529Sborman ioctl(tin, TIOCSETP, (char *)&sb); 57439529Sborman #else 57539529Sborman if (ioctl(tin, TCSETAW, &tmp_tc) < 0) 57639529Sborman ioctl(tin, TCSETA, &tmp_tc); 57739529Sborman #endif 57839529Sborman 57932147Sminshall #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) 58033286Sminshall ioctl(tin, FIONBIO, (char *)&onoff); 58133286Sminshall ioctl(tout, FIONBIO, (char *)&onoff); 58232147Sminshall #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ 58332147Sminshall #if defined(TN3270) 58436242Sminshall if (noasynchtty == 0) { 58533286Sminshall ioctl(tin, FIOASYNC, (char *)&onoff); 58632147Sminshall } 58732147Sminshall #endif /* defined(TN3270) */ 58832147Sminshall } 58932147Sminshall 59039529Sborman #ifndef B19200 59139529Sborman # define B19200 B9600 59239529Sborman #endif 59339529Sborman 59439529Sborman #ifndef B38400 59539529Sborman # define B38400 B19200 59639529Sborman #endif 59739529Sborman 59839529Sborman /* 59939529Sborman * This code assumes that the values B0, B50, B75... 60039529Sborman * are in ascending order. They do not have to be 60139529Sborman * contiguous. 60239529Sborman */ 60339529Sborman struct termspeeds { 60439529Sborman long speed; 60539529Sborman long value; 60639529Sborman } termspeeds[] = { 60739529Sborman { 0, B0 }, { 50, B50 }, { 75, B75 }, 60839529Sborman { 110, B110 }, { 134, B134 }, { 150, B150 }, 60939529Sborman { 200, B200 }, { 300, B300 }, { 600, B600 }, 61039529Sborman { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 61139529Sborman { 4800, B4800 }, { 9600, B9600 }, { 19200, B19200 }, 61239529Sborman { 38400, B38400 }, { -1, B38400 } 61339529Sborman }; 61439529Sborman 61539529Sborman #ifndef USE_TERMIO 61639529Sborman # define ISPEED ottyb.sg_ispeed 61739529Sborman # define OSPEED ottyb.sg_ospeed 61839529Sborman #else 619*44361Sborman # ifdef CBAUD 62039529Sborman # define ISPEED (old_tc.c_cflag&CBAUD) 62139529Sborman # define OSPEED ISPEED 62239529Sborman # else 62339529Sborman # define ISPEED old_tc.c_ispeed 62439529Sborman # define OSPEED old_tc.c_ospeed 62539529Sborman # endif 62639529Sborman #endif 62739529Sborman 62837219Sminshall void 62937219Sminshall TerminalSpeeds(ispeed, ospeed) 63037219Sminshall long *ispeed; 63137219Sminshall long *ospeed; 63237219Sminshall { 63339529Sborman register struct termspeeds *tp; 63432147Sminshall 63539529Sborman tp = termspeeds; 63639529Sborman while ((tp->speed != -1) && (tp->value < ISPEED)) 63739529Sborman tp++; 63839529Sborman *ispeed = tp->speed; 63939529Sborman 64039529Sborman tp = termspeeds; 64139529Sborman while ((tp->speed != -1) && (tp->value < OSPEED)) 64239529Sborman tp++; 64339529Sborman *ospeed = tp->speed; 64437219Sminshall } 64537219Sminshall 64632147Sminshall int 64737219Sminshall TerminalWindowSize(rows, cols) 64837219Sminshall long *rows, *cols; 64937219Sminshall { 65038689Sborman #ifdef TIOCGWINSZ 65137219Sminshall struct winsize ws; 65237219Sminshall 65338689Sborman if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 65438689Sborman *rows = ws.ws_row; 65538689Sborman *cols = ws.ws_col; 65638689Sborman return 1; 65737219Sminshall } 65838810Sborman #endif /* TIOCGWINSZ */ 65938689Sborman return 0; 66037219Sminshall } 66137219Sminshall 66237219Sminshall int 66335417Sminshall NetClose(fd) 66435417Sminshall int fd; 66532147Sminshall { 66635417Sminshall return close(fd); 66732147Sminshall } 66832147Sminshall 66932147Sminshall 67032147Sminshall void 67132553Sminshall NetNonblockingIO(fd, onoff) 67232147Sminshall int 67332147Sminshall fd, 67432147Sminshall onoff; 67532147Sminshall { 67632147Sminshall ioctl(fd, FIONBIO, (char *)&onoff); 67732147Sminshall } 67832147Sminshall 67934849Sminshall #if defined(TN3270) 68032147Sminshall void 68132553Sminshall NetSigIO(fd, onoff) 68232147Sminshall int 68332147Sminshall fd, 68432147Sminshall onoff; 68532147Sminshall { 68632147Sminshall ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ 68732147Sminshall } 68832147Sminshall 68932147Sminshall void 69032553Sminshall NetSetPgrp(fd) 69132147Sminshall int fd; 69232147Sminshall { 69332147Sminshall int myPid; 69432147Sminshall 69532147Sminshall myPid = getpid(); 69636274Sminshall fcntl(fd, F_SETOWN, myPid); 69732147Sminshall } 69834849Sminshall #endif /*defined(TN3270)*/ 69932553Sminshall 70032553Sminshall /* 70132553Sminshall * Various signal handling routines. 70232553Sminshall */ 70332147Sminshall 70433286Sminshall static void 70532553Sminshall deadpeer() 70632553Sminshall { 70732553Sminshall setcommandmode(); 70832553Sminshall longjmp(peerdied, -1); 70932553Sminshall } 71032147Sminshall 71133286Sminshall static void 71232553Sminshall intr() 71332553Sminshall { 71432553Sminshall if (localchars) { 71532553Sminshall intp(); 71632553Sminshall return; 71732553Sminshall } 71832553Sminshall setcommandmode(); 71932553Sminshall longjmp(toplevel, -1); 72032553Sminshall } 72132553Sminshall 72233286Sminshall static void 72332553Sminshall intr2() 72432553Sminshall { 72532553Sminshall if (localchars) { 72638689Sborman #ifdef KLUDGELINEMODE 72738689Sborman if (kludgelinemode) 72838689Sborman sendbrk(); 72938689Sborman else 73038689Sborman #endif 73138689Sborman sendabort(); 73232553Sminshall return; 73332553Sminshall } 73432553Sminshall } 73532553Sminshall 73633286Sminshall static void 73740245Sborman susp() 73840245Sborman { 73940245Sborman if (localchars) 74040245Sborman sendsusp(); 74140245Sborman } 74240245Sborman 74340245Sborman static void 74437219Sminshall sendwin() 74537219Sminshall { 74637219Sminshall if (connected) { 74737219Sminshall sendnaws(); 74837219Sminshall } 74937219Sminshall } 75037219Sminshall 75132553Sminshall 75232553Sminshall void 75332531Sminshall sys_telnet_init() 75432531Sminshall { 75540245Sborman (void) signal(SIGINT, (SIG_FUNC_RET (*)())intr); 75640245Sborman (void) signal(SIGQUIT, (SIG_FUNC_RET (*)())intr2); 75740245Sborman (void) signal(SIGPIPE, (SIG_FUNC_RET (*)())deadpeer); 75838689Sborman #ifdef SIGWINCH 75940245Sborman (void) signal(SIGWINCH, (SIG_FUNC_RET (*)())sendwin); 76038689Sborman #endif 76140245Sborman #ifdef SIGTSTP 76240245Sborman (void) signal(SIGTSTP, (SIG_FUNC_RET (*)())susp); 76340245Sborman #endif 76432553Sminshall 76538689Sborman setconnmode(0); 76632531Sminshall 76732531Sminshall NetNonblockingIO(net, 1); 76832531Sminshall 76932531Sminshall #if defined(TN3270) 77036242Sminshall if (noasynchnet == 0) { /* DBX can't handle! */ 77132531Sminshall NetSigIO(net, 1); 77232531Sminshall NetSetPgrp(net); 77332531Sminshall } 77432531Sminshall #endif /* defined(TN3270) */ 77532531Sminshall 77632531Sminshall #if defined(SO_OOBINLINE) 77734849Sminshall if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 77834849Sminshall perror("SetSockOpt"); 77934849Sminshall } 78032531Sminshall #endif /* defined(SO_OOBINLINE) */ 78132531Sminshall } 78232531Sminshall 78332531Sminshall /* 78432531Sminshall * Process rings - 78532531Sminshall * 78632531Sminshall * This routine tries to fill up/empty our various rings. 78732531Sminshall * 78832531Sminshall * The parameter specifies whether this is a poll operation, 78932531Sminshall * or a block-until-something-happens operation. 79032531Sminshall * 79132531Sminshall * The return value is 1 if something happened, 0 if not. 79232531Sminshall */ 79332531Sminshall 79432531Sminshall int 79532531Sminshall process_rings(netin, netout, netex, ttyin, ttyout, poll) 79632531Sminshall int poll; /* If 0, then block until something to do */ 79732531Sminshall { 79832531Sminshall register int c; 79932531Sminshall /* One wants to be a bit careful about setting returnValue 80032531Sminshall * to one, since a one implies we did some useful work, 80132531Sminshall * and therefore probably won't be called to block next 80232531Sminshall * time (TN3270 mode only). 80332531Sminshall */ 80432531Sminshall int returnValue = 0; 80532531Sminshall static struct timeval TimeValue = { 0 }; 80632531Sminshall 80732531Sminshall if (netout) { 80832531Sminshall FD_SET(net, &obits); 80932531Sminshall } 81032531Sminshall if (ttyout) { 81132531Sminshall FD_SET(tout, &obits); 81232531Sminshall } 81332531Sminshall #if defined(TN3270) 81432531Sminshall if (ttyin) { 81532531Sminshall FD_SET(tin, &ibits); 81632531Sminshall } 81732531Sminshall #else /* defined(TN3270) */ 81832531Sminshall if (ttyin) { 81932531Sminshall FD_SET(tin, &ibits); 82032531Sminshall } 82132531Sminshall #endif /* defined(TN3270) */ 82232531Sminshall #if defined(TN3270) 82332531Sminshall if (netin) { 82432531Sminshall FD_SET(net, &ibits); 82532531Sminshall } 82632531Sminshall # else /* !defined(TN3270) */ 82732531Sminshall if (netin) { 82832531Sminshall FD_SET(net, &ibits); 82932531Sminshall } 83032531Sminshall # endif /* !defined(TN3270) */ 83132531Sminshall if (netex) { 83232531Sminshall FD_SET(net, &xbits); 83332531Sminshall } 83432531Sminshall if ((c = select(16, &ibits, &obits, &xbits, 83532531Sminshall (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { 83632531Sminshall if (c == -1) { 83732531Sminshall /* 83832531Sminshall * we can get EINTR if we are in line mode, 83932531Sminshall * and the user does an escape (TSTP), or 84032531Sminshall * some other signal generator. 84132531Sminshall */ 84232531Sminshall if (errno == EINTR) { 84332531Sminshall return 0; 84432531Sminshall } 84532531Sminshall # if defined(TN3270) 84632531Sminshall /* 84732531Sminshall * we can get EBADF if we were in transparent 84832531Sminshall * mode, and the transcom process died. 84932531Sminshall */ 85032531Sminshall if (errno == EBADF) { 85132531Sminshall /* 85232531Sminshall * zero the bits (even though kernel does it) 85332531Sminshall * to make sure we are selecting on the right 85432531Sminshall * ones. 85532531Sminshall */ 85632531Sminshall FD_ZERO(&ibits); 85732531Sminshall FD_ZERO(&obits); 85832531Sminshall FD_ZERO(&xbits); 85932531Sminshall return 0; 86032531Sminshall } 86132531Sminshall # endif /* defined(TN3270) */ 86232531Sminshall /* I don't like this, does it ever happen? */ 86332531Sminshall printf("sleep(5) from telnet, after select\r\n"); 86432531Sminshall sleep(5); 86532531Sminshall } 86632531Sminshall return 0; 86732531Sminshall } 86832531Sminshall 86932531Sminshall /* 87032531Sminshall * Any urgent data? 87132531Sminshall */ 87232531Sminshall if (FD_ISSET(net, &xbits)) { 87332531Sminshall FD_CLR(net, &xbits); 87432531Sminshall SYNCHing = 1; 875*44361Sborman (void) ttyflush(1); /* flush already enqueued data */ 87632531Sminshall } 87732531Sminshall 87832531Sminshall /* 87932531Sminshall * Something to read from the network... 88032531Sminshall */ 88132531Sminshall if (FD_ISSET(net, &ibits)) { 88232531Sminshall int canread; 88332531Sminshall 88432531Sminshall FD_CLR(net, &ibits); 88532531Sminshall canread = ring_empty_consecutive(&netiring); 88632531Sminshall #if !defined(SO_OOBINLINE) 88732531Sminshall /* 88832531Sminshall * In 4.2 (and some early 4.3) systems, the 88932531Sminshall * OOB indication and data handling in the kernel 89032531Sminshall * is such that if two separate TCP Urgent requests 89132531Sminshall * come in, one byte of TCP data will be overlaid. 89232531Sminshall * This is fatal for Telnet, but we try to live 89332531Sminshall * with it. 89432531Sminshall * 89532531Sminshall * In addition, in 4.2 (and...), a special protocol 89632531Sminshall * is needed to pick up the TCP Urgent data in 89732531Sminshall * the correct sequence. 89832531Sminshall * 89932531Sminshall * What we do is: if we think we are in urgent 90032531Sminshall * mode, we look to see if we are "at the mark". 90132531Sminshall * If we are, we do an OOB receive. If we run 90232531Sminshall * this twice, we will do the OOB receive twice, 90332531Sminshall * but the second will fail, since the second 90432531Sminshall * time we were "at the mark", but there wasn't 90532531Sminshall * any data there (the kernel doesn't reset 90632531Sminshall * "at the mark" until we do a normal read). 90732531Sminshall * Once we've read the OOB data, we go ahead 90832531Sminshall * and do normal reads. 90932531Sminshall * 91032531Sminshall * There is also another problem, which is that 91132531Sminshall * since the OOB byte we read doesn't put us 91232531Sminshall * out of OOB state, and since that byte is most 91332531Sminshall * likely the TELNET DM (data mark), we would 91432531Sminshall * stay in the TELNET SYNCH (SYNCHing) state. 91532531Sminshall * So, clocks to the rescue. If we've "just" 91632531Sminshall * received a DM, then we test for the 91732531Sminshall * presence of OOB data when the receive OOB 91832531Sminshall * fails (and AFTER we did the normal mode read 91932531Sminshall * to clear "at the mark"). 92032531Sminshall */ 92132531Sminshall if (SYNCHing) { 92232531Sminshall int atmark; 92339652Sborman static int bogus_oob = 0, first = 1; 92432531Sminshall 92532531Sminshall ioctl(net, SIOCATMARK, (char *)&atmark); 92632531Sminshall if (atmark) { 92732531Sminshall c = recv(net, netiring.supply, canread, MSG_OOB); 92832531Sminshall if ((c == -1) && (errno == EINVAL)) { 92932531Sminshall c = recv(net, netiring.supply, canread, 0); 93032531Sminshall if (clocks.didnetreceive < clocks.gotDM) { 93132531Sminshall SYNCHing = stilloob(net); 93232531Sminshall } 93339652Sborman } else if (first && c > 0) { 93439652Sborman /* 93539652Sborman * Bogosity check. Systems based on 4.2BSD 93639652Sborman * do not return an error if you do a second 93739652Sborman * recv(MSG_OOB). So, we do one. If it 93839652Sborman * succeeds and returns exactly the same 93939652Sborman * data, then assume that we are running 94039652Sborman * on a broken system and set the bogus_oob 94139652Sborman * flag. (If the data was different, then 94239652Sborman * we probably got some valid new data, so 94339652Sborman * increment the count...) 94439652Sborman */ 94539652Sborman int i; 94639652Sborman i = recv(net, netiring.supply + c, canread - c, MSG_OOB); 94739652Sborman if (i == c && 94839652Sborman bcmp(netiring.supply, netiring.supply + c, i) == 0) { 94939652Sborman bogus_oob = 1; 95039652Sborman first = 0; 95139652Sborman } else if (i < 0) { 95239652Sborman bogus_oob = 0; 95339652Sborman first = 0; 95439652Sborman } else 95539652Sborman c += i; 95632531Sminshall } 95739652Sborman if (bogus_oob && c > 0) { 95839652Sborman int i; 95939652Sborman /* 96039652Sborman * Bogosity. We have to do the read 96139652Sborman * to clear the atmark to get out of 96239652Sborman * an infinate loop. 96339652Sborman */ 96439652Sborman i = read(net, netiring.supply + c, canread - c); 96539652Sborman if (i > 0) 96639652Sborman c += i; 96739652Sborman } 96832531Sminshall } else { 96932531Sminshall c = recv(net, netiring.supply, canread, 0); 97032531Sminshall } 97132531Sminshall } else { 97232531Sminshall c = recv(net, netiring.supply, canread, 0); 97332531Sminshall } 97432531Sminshall settimer(didnetreceive); 97532531Sminshall #else /* !defined(SO_OOBINLINE) */ 97632531Sminshall c = recv(net, netiring.supply, canread, 0); 97732531Sminshall #endif /* !defined(SO_OOBINLINE) */ 97832531Sminshall if (c < 0 && errno == EWOULDBLOCK) { 97932531Sminshall c = 0; 98032531Sminshall } else if (c <= 0) { 98132531Sminshall return -1; 98232531Sminshall } 98332531Sminshall if (netdata) { 98432531Sminshall Dump('<', netiring.supply, c); 98532531Sminshall } 98632667Sminshall if (c) 98732667Sminshall ring_supplied(&netiring, c); 98832531Sminshall returnValue = 1; 98932531Sminshall } 99032531Sminshall 99132531Sminshall /* 99232531Sminshall * Something to read from the tty... 99332531Sminshall */ 99432531Sminshall if (FD_ISSET(tin, &ibits)) { 99532531Sminshall FD_CLR(tin, &ibits); 99633286Sminshall c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 99732531Sminshall if (c < 0 && errno == EWOULDBLOCK) { 99832531Sminshall c = 0; 99932531Sminshall } else { 100032531Sminshall /* EOF detection for line mode!!!! */ 100133281Sminshall if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 100232531Sminshall /* must be an EOF... */ 100332531Sminshall *ttyiring.supply = termEofChar; 100432531Sminshall c = 1; 100532531Sminshall } 100632531Sminshall if (c <= 0) { 100732531Sminshall return -1; 100832531Sminshall } 100938208Sminshall if (termdata) { 101038208Sminshall Dump('<', ttyiring.supply, c); 101138208Sminshall } 101232667Sminshall ring_supplied(&ttyiring, c); 101332531Sminshall } 101432531Sminshall returnValue = 1; /* did something useful */ 101532531Sminshall } 101632531Sminshall 101732531Sminshall if (FD_ISSET(net, &obits)) { 101832531Sminshall FD_CLR(net, &obits); 101932531Sminshall returnValue |= netflush(); 102032531Sminshall } 102132531Sminshall if (FD_ISSET(tout, &obits)) { 102232531Sminshall FD_CLR(tout, &obits); 102338689Sborman returnValue |= (ttyflush(SYNCHing|flushout) > 0); 102432531Sminshall } 102532531Sminshall 102632531Sminshall return returnValue; 102732531Sminshall } 1028