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