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