Annotation of src/usr.bin/telnet/sys_bsd.c, Revision 1.13
1.13 ! mpech 1: /* $OpenBSD: sys_bsd.c,v 1.12 2002/03/25 10:52:32 hin 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.8 millert 38: #include <err.h>
1.1 deraadt 39:
40: /*
41: * The following routines try to encapsulate what is system dependent
42: * (at least between 4.x and dos) which is used in telnet.c.
43: */
44:
45: int
46: tout, /* Output file descriptor */
47: tin, /* Input file descriptor */
48: net;
49:
50: #ifndef USE_TERMIO
51: struct tchars otc = { 0 }, ntc = { 0 };
52: struct ltchars oltc = { 0 }, nltc = { 0 };
53: struct sgttyb ottyb = { 0 }, nttyb = { 0 };
54: int olmode = 0;
55: # define cfgetispeed(ptr) (ptr)->sg_ispeed
56: # define cfgetospeed(ptr) (ptr)->sg_ospeed
57: # define old_tc ottyb
58:
59: #else /* USE_TERMIO */
1.5 art 60: struct termios old_tc = { 0 };
61: extern struct termios new_tc;
1.1 deraadt 62:
63: # ifndef TCSANOW
64: # ifdef TCSETS
65: # define TCSANOW TCSETS
66: # define TCSADRAIN TCSETSW
67: # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
68: # else
69: # ifdef TCSETA
70: # define TCSANOW TCSETA
71: # define TCSADRAIN TCSETAW
72: # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
73: # else
74: # define TCSANOW TIOCSETA
75: # define TCSADRAIN TIOCSETAW
76: # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
77: # endif
78: # endif
79: # define tcsetattr(f, a, t) ioctl(f, a, (char *)t)
80: # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD)
81: # ifdef CIBAUD
82: # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
83: # else
84: # define cfgetispeed(ptr) cfgetospeed(ptr)
85: # endif
86: # endif /* TCSANOW */
87: # ifdef sysV88
88: # define TIOCFLUSH TC_PX_DRAIN
89: # endif
90: #endif /* USE_TERMIO */
91:
1.6 deraadt 92: fd_set *ibitsp, *obitsp, *xbitsp;
93: int fdsn;
1.1 deraadt 94:
95: void
96: init_sys()
97: {
98: tout = fileno(stdout);
99: tin = fileno(stdin);
100:
101: errno = 0;
102: }
103:
104:
105: int
106: TerminalWrite(buf, n)
107: char *buf;
108: int n;
109: {
110: return write(tout, buf, n);
111: }
112:
113: int
114: TerminalRead(buf, n)
1.3 niklas 115: unsigned char *buf;
1.1 deraadt 116: int n;
117: {
118: return read(tin, buf, n);
119: }
120:
121: /*
122: *
123: */
124:
125: int
126: TerminalAutoFlush()
127: {
128: #if defined(LNOFLSH)
129: int flush;
130:
131: ioctl(0, TIOCLGET, (char *)&flush);
132: return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */
133: #else /* LNOFLSH */
134: return 1;
135: #endif /* LNOFLSH */
136: }
137:
138: #ifdef KLUDGELINEMODE
139: extern int kludgelinemode;
140: #endif
141: /*
142: * TerminalSpecialChars()
143: *
144: * Look at an input character to see if it is a special character
145: * and decide what to do.
146: *
147: * Output:
148: *
149: * 0 Don't add this character.
150: * 1 Do add this character
151: */
152:
153: extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
154:
155: int
156: TerminalSpecialChars(c)
157: int c;
158: {
159: if (c == termIntChar) {
160: intp();
161: return 0;
162: } else if (c == termQuitChar) {
163: #ifdef KLUDGELINEMODE
164: if (kludgelinemode)
165: sendbrk();
166: else
167: #endif
168: sendabort();
169: return 0;
170: } else if (c == termEofChar) {
171: if (my_want_state_is_will(TELOPT_LINEMODE)) {
172: sendeof();
173: return 0;
174: }
175: return 1;
176: } else if (c == termSuspChar) {
177: sendsusp();
178: return(0);
179: } else if (c == termFlushChar) {
180: xmitAO(); /* Transmit Abort Output */
181: return 0;
182: } else if (!MODE_LOCAL_CHARS(globalmode)) {
183: if (c == termKillChar) {
184: xmitEL();
185: return 0;
186: } else if (c == termEraseChar) {
187: xmitEC(); /* Transmit Erase Character */
188: return 0;
189: }
190: }
191: return 1;
192: }
193:
194:
195: /*
196: * Flush output to the terminal
197: */
1.3 niklas 198:
1.1 deraadt 199: void
200: TerminalFlushOutput()
201: {
202: #ifdef TIOCFLUSH
1.7 deraadt 203: int com = FWRITE;
204: (void) ioctl(fileno(stdout), TIOCFLUSH, (int *) &com);
1.1 deraadt 205: #else
1.7 deraadt 206: (void) ioctl(fileno(stdout), TCFLSH, (int *) 0);
1.1 deraadt 207: #endif
208: }
209:
210: void
211: TerminalSaveState()
212: {
213: #ifndef USE_TERMIO
214: ioctl(0, TIOCGETP, (char *)&ottyb);
215: ioctl(0, TIOCGETC, (char *)&otc);
216: ioctl(0, TIOCGLTC, (char *)&oltc);
217: ioctl(0, TIOCLGET, (char *)&olmode);
218:
219: ntc = otc;
220: nltc = oltc;
221: nttyb = ottyb;
222:
223: #else /* USE_TERMIO */
224: tcgetattr(0, &old_tc);
225:
226: new_tc = old_tc;
227:
228: #ifndef VDISCARD
229: termFlushChar = CONTROL('O');
230: #endif
231: #ifndef VWERASE
232: termWerasChar = CONTROL('W');
233: #endif
234: #ifndef VREPRINT
235: termRprntChar = CONTROL('R');
236: #endif
237: #ifndef VLNEXT
238: termLiteralNextChar = CONTROL('V');
239: #endif
240: #ifndef VSTART
241: termStartChar = CONTROL('Q');
242: #endif
243: #ifndef VSTOP
244: termStopChar = CONTROL('S');
245: #endif
246: #ifndef VSTATUS
247: termAytChar = CONTROL('T');
248: #endif
249: #endif /* USE_TERMIO */
250: }
251:
252: cc_t *
253: tcval(func)
1.10 mpech 254: int func;
1.1 deraadt 255: {
256: switch(func) {
257: case SLC_IP: return(&termIntChar);
258: case SLC_ABORT: return(&termQuitChar);
259: case SLC_EOF: return(&termEofChar);
260: case SLC_EC: return(&termEraseChar);
261: case SLC_EL: return(&termKillChar);
262: case SLC_XON: return(&termStartChar);
263: case SLC_XOFF: return(&termStopChar);
264: case SLC_FORW1: return(&termForw1Char);
265: #ifdef USE_TERMIO
266: case SLC_FORW2: return(&termForw2Char);
267: # ifdef VDISCARD
268: case SLC_AO: return(&termFlushChar);
269: # endif
270: # ifdef VSUSP
271: case SLC_SUSP: return(&termSuspChar);
272: # endif
273: # ifdef VWERASE
274: case SLC_EW: return(&termWerasChar);
275: # endif
276: # ifdef VREPRINT
277: case SLC_RP: return(&termRprntChar);
278: # endif
279: # ifdef VLNEXT
280: case SLC_LNEXT: return(&termLiteralNextChar);
281: # endif
282: # ifdef VSTATUS
283: case SLC_AYT: return(&termAytChar);
284: # endif
285: #endif
286:
287: case SLC_SYNCH:
288: case SLC_BRK:
289: case SLC_EOR:
290: default:
291: return((cc_t *)0);
292: }
293: }
294:
295: void
296: TerminalDefaultChars()
297: {
298: #ifndef USE_TERMIO
299: ntc = otc;
300: nltc = oltc;
301: nttyb.sg_kill = ottyb.sg_kill;
302: nttyb.sg_erase = ottyb.sg_erase;
303: #else /* USE_TERMIO */
1.3 niklas 304: memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
1.1 deraadt 305: # ifndef VDISCARD
306: termFlushChar = CONTROL('O');
307: # endif
308: # ifndef VWERASE
309: termWerasChar = CONTROL('W');
310: # endif
311: # ifndef VREPRINT
312: termRprntChar = CONTROL('R');
313: # endif
314: # ifndef VLNEXT
315: termLiteralNextChar = CONTROL('V');
316: # endif
317: # ifndef VSTART
318: termStartChar = CONTROL('Q');
319: # endif
320: # ifndef VSTOP
321: termStopChar = CONTROL('S');
322: # endif
323: # ifndef VSTATUS
324: termAytChar = CONTROL('T');
325: # endif
326: #endif /* USE_TERMIO */
327: }
328:
329: #ifdef notdef
330: void
331: TerminalRestoreState()
332: {
333: }
334: #endif
335:
336: /*
337: * TerminalNewMode - set up terminal to a specific mode.
338: * MODE_ECHO: do local terminal echo
339: * MODE_FLOW: do local flow control
340: * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
341: * MODE_EDIT: do local line editing
342: *
343: * Command mode:
344: * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
345: * local echo
346: * local editing
347: * local xon/xoff
348: * local signal mapping
349: *
350: * Linemode:
351: * local/no editing
352: * Both Linemode and Single Character mode:
353: * local/remote echo
354: * local/no xon/xoff
355: * local/no signal mapping
356: */
357:
1.5 art 358: #ifdef SIGTSTP
359: static void susp();
360: #endif /* SIGTSTP */
361: #ifdef SIGINFO
362: static void ayt();
363: #endif
1.1 deraadt 364:
365: void
366: TerminalNewMode(f)
1.10 mpech 367: int f;
1.1 deraadt 368: {
369: static int prevmode = 0;
370: #ifndef USE_TERMIO
371: struct tchars tc;
372: struct ltchars ltc;
373: struct sgttyb sb;
374: int lmode;
375: #else /* USE_TERMIO */
1.5 art 376: struct termios tmp_tc;
1.1 deraadt 377: #endif /* USE_TERMIO */
378: int onoff;
379: int old;
380: cc_t esc;
381:
382: globalmode = f&~MODE_FORCE;
383: if (prevmode == f)
384: return;
385:
386: /*
387: * Write any outstanding data before switching modes
388: * ttyflush() returns 0 only when there is no more data
389: * left to write out, it returns -1 if it couldn't do
390: * anything at all, otherwise it returns 1 + the number
391: * of characters left to write.
392: #ifndef USE_TERMIO
393: * We would really like ask the kernel to wait for the output
394: * to drain, like we can do with the TCSADRAIN, but we don't have
395: * that option. The only ioctl that waits for the output to
396: * drain, TIOCSETP, also flushes the input queue, which is NOT
397: * what we want (TIOCSETP is like TCSADFLUSH).
398: #endif
399: */
400: old = ttyflush(SYNCHing|flushout);
401: if (old < 0 || old > 1) {
402: #ifdef USE_TERMIO
403: tcgetattr(tin, &tmp_tc);
404: #endif /* USE_TERMIO */
405: do {
406: /*
407: * Wait for data to drain, then flush again.
408: */
409: #ifdef USE_TERMIO
410: tcsetattr(tin, TCSADRAIN, &tmp_tc);
411: #endif /* USE_TERMIO */
412: old = ttyflush(SYNCHing|flushout);
413: } while (old < 0 || old > 1);
414: }
415:
416: old = prevmode;
417: prevmode = f&~MODE_FORCE;
418: #ifndef USE_TERMIO
419: sb = nttyb;
420: tc = ntc;
421: ltc = nltc;
422: lmode = olmode;
423: #else
424: tmp_tc = new_tc;
425: #endif
426:
427: if (f&MODE_ECHO) {
428: #ifndef USE_TERMIO
429: sb.sg_flags |= ECHO;
430: #else
431: tmp_tc.c_lflag |= ECHO;
432: tmp_tc.c_oflag |= ONLCR;
433: if (crlf)
434: tmp_tc.c_iflag |= ICRNL;
435: #endif
436: } else {
437: #ifndef USE_TERMIO
438: sb.sg_flags &= ~ECHO;
439: #else
440: tmp_tc.c_lflag &= ~ECHO;
441: tmp_tc.c_oflag &= ~ONLCR;
442: # ifdef notdef
443: if (crlf)
444: tmp_tc.c_iflag &= ~ICRNL;
445: # endif
446: #endif
447: }
448:
449: if ((f&MODE_FLOW) == 0) {
450: #ifndef USE_TERMIO
451: tc.t_startc = _POSIX_VDISABLE;
452: tc.t_stopc = _POSIX_VDISABLE;
453: #else
454: tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */
455: } else {
456: if (restartany < 0) {
457: tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */
458: } else if (restartany > 0) {
459: tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
460: } else {
461: tmp_tc.c_iflag |= IXOFF|IXON;
462: tmp_tc.c_iflag &= ~IXANY;
463: }
464: #endif
465: }
466:
467: if ((f&MODE_TRAPSIG) == 0) {
468: #ifndef USE_TERMIO
469: tc.t_intrc = _POSIX_VDISABLE;
470: tc.t_quitc = _POSIX_VDISABLE;
471: tc.t_eofc = _POSIX_VDISABLE;
472: ltc.t_suspc = _POSIX_VDISABLE;
473: ltc.t_dsuspc = _POSIX_VDISABLE;
474: #else
475: tmp_tc.c_lflag &= ~ISIG;
476: #endif
477: localchars = 0;
478: } else {
479: #ifdef USE_TERMIO
480: tmp_tc.c_lflag |= ISIG;
481: #endif
482: localchars = 1;
483: }
484:
485: if (f&MODE_EDIT) {
486: #ifndef USE_TERMIO
487: sb.sg_flags &= ~CBREAK;
488: sb.sg_flags |= CRMOD;
489: #else
490: tmp_tc.c_lflag |= ICANON;
491: #endif
492: } else {
493: #ifndef USE_TERMIO
494: sb.sg_flags |= CBREAK;
495: if (f&MODE_ECHO)
496: sb.sg_flags |= CRMOD;
497: else
498: sb.sg_flags &= ~CRMOD;
499: #else
500: tmp_tc.c_lflag &= ~ICANON;
501: tmp_tc.c_iflag &= ~ICRNL;
502: tmp_tc.c_cc[VMIN] = 1;
503: tmp_tc.c_cc[VTIME] = 0;
504: #endif
505: }
506:
507: if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
508: #ifndef USE_TERMIO
509: ltc.t_lnextc = _POSIX_VDISABLE;
510: #else
1.2 niklas 511: tmp_tc.c_lflag &= ~IEXTEN;
1.1 deraadt 512: #endif
513: }
514:
515: if (f&MODE_SOFT_TAB) {
516: #ifndef USE_TERMIO
517: sb.sg_flags |= XTABS;
518: #else
519: # ifdef OXTABS
520: tmp_tc.c_oflag |= OXTABS;
521: # endif
522: # ifdef TABDLY
523: tmp_tc.c_oflag &= ~TABDLY;
524: tmp_tc.c_oflag |= TAB3;
525: # endif
526: #endif
527: } else {
528: #ifndef USE_TERMIO
529: sb.sg_flags &= ~XTABS;
530: #else
531: # ifdef OXTABS
532: tmp_tc.c_oflag &= ~OXTABS;
533: # endif
534: # ifdef TABDLY
535: tmp_tc.c_oflag &= ~TABDLY;
536: # endif
537: #endif
538: }
539:
540: if (f&MODE_LIT_ECHO) {
541: #ifndef USE_TERMIO
542: lmode &= ~LCTLECH;
543: #else
544: # ifdef ECHOCTL
545: tmp_tc.c_lflag &= ~ECHOCTL;
546: # endif
547: #endif
548: } else {
549: #ifndef USE_TERMIO
550: lmode |= LCTLECH;
551: #else
552: # ifdef ECHOCTL
553: tmp_tc.c_lflag |= ECHOCTL;
554: # endif
555: #endif
556: }
557:
558: if (f == -1) {
559: onoff = 0;
560: } else {
561: #ifndef USE_TERMIO
562: if (f & MODE_OUTBIN)
563: lmode |= LLITOUT;
564: else
565: lmode &= ~LLITOUT;
566:
567: if (f & MODE_INBIN)
568: lmode |= LPASS8;
569: else
570: lmode &= ~LPASS8;
571: #else
572: if (f & MODE_INBIN)
573: tmp_tc.c_iflag &= ~ISTRIP;
574: else
575: tmp_tc.c_iflag |= ISTRIP;
1.5 art 576: if ((f & MODE_OUTBIN) || (f & MODE_OUT8)) {
1.1 deraadt 577: tmp_tc.c_cflag &= ~(CSIZE|PARENB);
578: tmp_tc.c_cflag |= CS8;
1.5 art 579: if(f & MODE_OUTBIN)
580: tmp_tc.c_oflag &= ~OPOST;
581: else
582: tmp_tc.c_oflag |= OPOST;
583:
1.1 deraadt 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 SIGTSTP
595: (void) signal(SIGTSTP, susp);
596: #endif /* SIGTSTP */
597: #ifdef SIGINFO
598: (void) signal(SIGINFO, ayt);
599: #endif
600: #if defined(USE_TERMIO) && defined(NOKERNINFO)
601: tmp_tc.c_lflag |= NOKERNINFO;
602: #endif
603: /*
604: * We don't want to process ^Y here. It's just another
605: * character that we'll pass on to the back end. It has
606: * to process it because it will be processed when the
607: * user attempts to read it, not when we send it.
608: */
609: #ifndef USE_TERMIO
610: ltc.t_dsuspc = _POSIX_VDISABLE;
611: #else
612: # ifdef VDSUSP
613: tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
614: # endif
615: #endif
616: #ifdef USE_TERMIO
617: /*
618: * If the VEOL character is already set, then use VEOL2,
619: * otherwise use VEOL.
620: */
621: esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
622: if ((tmp_tc.c_cc[VEOL] != esc)
623: # ifdef VEOL2
624: && (tmp_tc.c_cc[VEOL2] != esc)
625: # endif
626: ) {
627: if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
628: tmp_tc.c_cc[VEOL] = esc;
629: # ifdef VEOL2
630: else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
631: tmp_tc.c_cc[VEOL2] = esc;
632: # endif
633: }
634: #else
635: if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
636: tc.t_brkc = esc;
637: #endif
638: } else {
1.9 millert 639: #ifdef SIGTSTP
640: sigset_t mask;
641: #endif /* SIGTSTP */
1.1 deraadt 642: #ifdef SIGINFO
1.5 art 643: void ayt_status();
1.1 deraadt 644:
1.5 art 645: (void) signal(SIGINFO, (void (*)(int))ayt_status);
1.1 deraadt 646: #endif
647: #ifdef SIGTSTP
648: (void) signal(SIGTSTP, SIG_DFL);
1.9 millert 649: sigemptyset(&mask);
650: sigaddset(&mask, SIGTSTP);
651: sigprocmask(SIG_UNBLOCK, &mask, NULL);
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.10 mpech 757: struct termspeeds *tp;
1.3 niklas 758: #endif /* DECODE_BAUD */
1.10 mpech 759: long in, out;
1.1 deraadt 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: {
1.13 ! mpech 827: pid_t myPid;
1.1 deraadt 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:
1.12 hin 847: volatile sig_atomic_t intr_happened = 0;
848: volatile sig_atomic_t intr_waiting = 0;
1.11 hin 849:
1.1 deraadt 850: /* ARGSUSED */
1.5 art 851: void
1.1 deraadt 852: intr(sig)
853: int sig;
854: {
1.11 hin 855: if (intr_waiting) {
856: intr_happened = 1;
857: return;
858: }
1.1 deraadt 859: if (localchars) {
860: intp();
861: return;
862: }
863: setcommandmode();
864: longjmp(toplevel, -1);
865: }
866:
867: /* ARGSUSED */
1.5 art 868: void
1.1 deraadt 869: intr2(sig)
870: int sig;
871: {
872: if (localchars) {
873: #ifdef KLUDGELINEMODE
874: if (kludgelinemode)
875: sendbrk();
876: else
877: #endif
878: sendabort();
879: return;
880: }
881: }
882:
883: #ifdef SIGTSTP
884: /* ARGSUSED */
1.5 art 885: void
1.1 deraadt 886: susp(sig)
887: int sig;
888: {
889: if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
890: return;
891: if (localchars)
892: sendsusp();
893: }
894: #endif
895:
896: #ifdef SIGWINCH
897: /* ARGSUSED */
1.5 art 898: void
1.1 deraadt 899: sendwin(sig)
900: int sig;
901: {
902: if (connected) {
903: sendnaws();
904: }
905: }
906: #endif
907:
908: #ifdef SIGINFO
909: /* ARGSUSED */
1.5 art 910: void
1.1 deraadt 911: ayt(sig)
912: int sig;
913: {
914: if (connected)
915: sendayt();
916: else
917: ayt_status();
918: }
919: #endif
920:
921:
922: void
923: sys_telnet_init()
924: {
925: (void) signal(SIGINT, intr);
926: (void) signal(SIGQUIT, intr2);
927: (void) signal(SIGPIPE, deadpeer);
928: #ifdef SIGWINCH
929: (void) signal(SIGWINCH, sendwin);
930: #endif
931: #ifdef SIGTSTP
932: (void) signal(SIGTSTP, susp);
933: #endif
934: #ifdef SIGINFO
935: (void) signal(SIGINFO, ayt);
936: #endif
937:
938: setconnmode(0);
939:
940: NetNonblockingIO(net, 1);
941:
942: #if defined(TN3270)
943: if (noasynchnet == 0) { /* DBX can't handle! */
944: NetSigIO(net, 1);
945: NetSetPgrp(net);
946: }
947: #endif /* defined(TN3270) */
948:
949: #if defined(SO_OOBINLINE)
950: if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
951: perror("SetSockOpt");
952: }
953: #endif /* defined(SO_OOBINLINE) */
954: }
955:
956: /*
957: * Process rings -
958: *
959: * This routine tries to fill up/empty our various rings.
960: *
961: * The parameter specifies whether this is a poll operation,
962: * or a block-until-something-happens operation.
963: *
964: * The return value is 1 if something happened, 0 if not.
965: */
966:
967: int
968: process_rings(netin, netout, netex, ttyin, ttyout, poll)
969: int poll; /* If 0, then block until something to do */
970: {
1.10 mpech 971: int c;
1.1 deraadt 972: /* One wants to be a bit careful about setting returnValue
973: * to one, since a one implies we did some useful work,
974: * and therefore probably won't be called to block next
975: * time (TN3270 mode only).
976: */
977: int returnValue = 0;
978: static struct timeval TimeValue = { 0 };
1.6 deraadt 979: int maxfd = -1;
980: int tmp;
981:
982: if ((netout || netin || netex) && net > maxfd)
983: maxfd = net;
984: if (ttyout && tout > maxfd)
985: maxfd = tout;
986: if (ttyin && tin > maxfd)
987: maxfd = tin;
988: tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
989: if (tmp > fdsn) {
990: if (ibitsp)
991: free(ibitsp);
992: if (obitsp)
993: free(obitsp);
994: if (xbitsp)
995: free(xbitsp);
996: fdsn = tmp;
997: if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL)
998: err(1, "malloc");
999: if ((obitsp = (fd_set *)malloc(fdsn)) == NULL)
1000: err(1, "malloc");
1001: if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL)
1002: err(1, "malloc");
1003: memset(ibitsp, 0, fdsn);
1004: memset(obitsp, 0, fdsn);
1005: memset(xbitsp, 0, fdsn);
1006: }
1007:
1008: if (netout)
1009: FD_SET(net, obitsp);
1010: if (ttyout)
1011: FD_SET(tout, obitsp);
1012: if (ttyin)
1013: FD_SET(tin, ibitsp);
1014: if (netin)
1015: FD_SET(net, ibitsp);
1016: if (netex)
1017: FD_SET(net, xbitsp);
1.1 deraadt 1018:
1.6 deraadt 1019: if ((c = select(maxfd+1, ibitsp, obitsp, xbitsp,
1020: (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
1.1 deraadt 1021: if (c == -1) {
1022: /*
1023: * we can get EINTR if we are in line mode,
1024: * and the user does an escape (TSTP), or
1025: * some other signal generator.
1026: */
1027: if (errno == EINTR) {
1028: return 0;
1029: }
1030: # if defined(TN3270)
1031: /*
1032: * we can get EBADF if we were in transparent
1033: * mode, and the transcom process died.
1034: */
1035: if (errno == EBADF) {
1036: /*
1037: * zero the bits (even though kernel does it)
1038: * to make sure we are selecting on the right
1039: * ones.
1040: */
1.6 deraadt 1041: memset(ibitsp, 0, fdsn);
1042: memset(obitsp, 0, fdsn);
1043: memset(xbitsp, 0, fdsn);
1.1 deraadt 1044: return 0;
1045: }
1046: # endif /* defined(TN3270) */
1047: /* I don't like this, does it ever happen? */
1048: printf("sleep(5) from telnet, after select\r\n");
1049: sleep(5);
1050: }
1051: return 0;
1052: }
1053:
1054: /*
1055: * Any urgent data?
1056: */
1.6 deraadt 1057: if (FD_ISSET(net, xbitsp)) {
1058: FD_CLR(net, xbitsp);
1.1 deraadt 1059: SYNCHing = 1;
1060: (void) ttyflush(1); /* flush already enqueued data */
1061: }
1062:
1063: /*
1064: * Something to read from the network...
1065: */
1.6 deraadt 1066: if (FD_ISSET(net, ibitsp)) {
1.1 deraadt 1067: int canread;
1068:
1.6 deraadt 1069: FD_CLR(net, ibitsp);
1.1 deraadt 1070: canread = ring_empty_consecutive(&netiring);
1071: #if !defined(SO_OOBINLINE)
1072: /*
1073: * In 4.2 (and some early 4.3) systems, the
1074: * OOB indication and data handling in the kernel
1075: * is such that if two separate TCP Urgent requests
1076: * come in, one byte of TCP data will be overlaid.
1077: * This is fatal for Telnet, but we try to live
1078: * with it.
1079: *
1080: * In addition, in 4.2 (and...), a special protocol
1081: * is needed to pick up the TCP Urgent data in
1082: * the correct sequence.
1083: *
1084: * What we do is: if we think we are in urgent
1085: * mode, we look to see if we are "at the mark".
1086: * If we are, we do an OOB receive. If we run
1087: * this twice, we will do the OOB receive twice,
1088: * but the second will fail, since the second
1089: * time we were "at the mark", but there wasn't
1090: * any data there (the kernel doesn't reset
1091: * "at the mark" until we do a normal read).
1092: * Once we've read the OOB data, we go ahead
1093: * and do normal reads.
1094: *
1095: * There is also another problem, which is that
1096: * since the OOB byte we read doesn't put us
1097: * out of OOB state, and since that byte is most
1098: * likely the TELNET DM (data mark), we would
1099: * stay in the TELNET SYNCH (SYNCHing) state.
1100: * So, clocks to the rescue. If we've "just"
1101: * received a DM, then we test for the
1102: * presence of OOB data when the receive OOB
1103: * fails (and AFTER we did the normal mode read
1104: * to clear "at the mark").
1105: */
1106: if (SYNCHing) {
1107: int atmark;
1108: static int bogus_oob = 0, first = 1;
1109:
1110: ioctl(net, SIOCATMARK, (char *)&atmark);
1111: if (atmark) {
1112: c = recv(net, netiring.supply, canread, MSG_OOB);
1113: if ((c == -1) && (errno == EINVAL)) {
1114: c = recv(net, netiring.supply, canread, 0);
1115: if (clocks.didnetreceive < clocks.gotDM) {
1116: SYNCHing = stilloob(net);
1117: }
1118: } else if (first && c > 0) {
1119: /*
1120: * Bogosity check. Systems based on 4.2BSD
1121: * do not return an error if you do a second
1122: * recv(MSG_OOB). So, we do one. If it
1123: * succeeds and returns exactly the same
1124: * data, then assume that we are running
1125: * on a broken system and set the bogus_oob
1126: * flag. (If the data was different, then
1127: * we probably got some valid new data, so
1128: * increment the count...)
1129: */
1130: int i;
1131: i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
1132: if (i == c &&
1.3 niklas 1133: memcmp(netiring.supply, netiring.supply + c, i) == 0) {
1.1 deraadt 1134: bogus_oob = 1;
1135: first = 0;
1136: } else if (i < 0) {
1137: bogus_oob = 0;
1138: first = 0;
1139: } else
1140: c += i;
1141: }
1142: if (bogus_oob && c > 0) {
1143: int i;
1144: /*
1145: * Bogosity. We have to do the read
1146: * to clear the atmark to get out of
1147: * an infinate loop.
1148: */
1149: i = read(net, netiring.supply + c, canread - c);
1150: if (i > 0)
1151: c += i;
1152: }
1153: } else {
1154: c = recv(net, netiring.supply, canread, 0);
1155: }
1156: } else {
1157: c = recv(net, netiring.supply, canread, 0);
1158: }
1159: settimer(didnetreceive);
1160: #else /* !defined(SO_OOBINLINE) */
1161: c = recv(net, (char *)netiring.supply, canread, 0);
1162: #endif /* !defined(SO_OOBINLINE) */
1163: if (c < 0 && errno == EWOULDBLOCK) {
1164: c = 0;
1165: } else if (c <= 0) {
1166: return -1;
1167: }
1168: if (netdata) {
1169: Dump('<', netiring.supply, c);
1170: }
1171: if (c)
1172: ring_supplied(&netiring, c);
1173: returnValue = 1;
1174: }
1175:
1176: /*
1177: * Something to read from the tty...
1178: */
1.6 deraadt 1179: if (FD_ISSET(tin, ibitsp)) {
1180: FD_CLR(tin, ibitsp);
1.1 deraadt 1181: c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
1.3 niklas 1182: if (c < 0 && errno == EIO)
1183: c = 0;
1.1 deraadt 1184: if (c < 0 && errno == EWOULDBLOCK) {
1185: c = 0;
1186: } else {
1.5 art 1187: /* EOF detection for line mode!!!! */
1188: if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
1189: /* must be an EOF... */
1190: *ttyiring.supply = termEofChar;
1191: c = 1;
1192: }
1193: if (c <= 0) {
1.1 deraadt 1194: return -1;
1195: }
1196: if (termdata) {
1197: Dump('<', ttyiring.supply, c);
1198: }
1199: ring_supplied(&ttyiring, c);
1200: }
1201: returnValue = 1; /* did something useful */
1202: }
1203:
1.6 deraadt 1204: if (FD_ISSET(net, obitsp)) {
1205: FD_CLR(net, obitsp);
1.1 deraadt 1206: returnValue |= netflush();
1207: }
1.6 deraadt 1208: if (FD_ISSET(tout, obitsp)) {
1209: FD_CLR(tout, obitsp);
1.1 deraadt 1210: returnValue |= (ttyflush(SYNCHing|flushout) > 0);
1211: }
1212:
1213: return returnValue;
1214: }