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