1 /*
2 * Copyright (c) 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #if 0
31 #ifndef lint
32 static const char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95";
33 #endif
34 #endif
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 #include <sys/param.h>
42 #include <sys/socket.h>
43 #include <sys/time.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <signal.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <arpa/telnet.h>
51
52 #include "ring.h"
53 #include "fdset.h"
54 #include "defines.h"
55 #include "externs.h"
56 #include "types.h"
57 #include "baud.h"
58
59 int
60 tout, /* Output file descriptor */
61 tin, /* Input file descriptor */
62 net;
63
64 #ifndef USE_TERMIO
65 struct tchars otc = { 0 }, ntc = { 0 };
66 struct ltchars oltc = { 0 }, nltc = { 0 };
67 struct sgttyb ottyb = { 0 }, nttyb = { 0 };
68 int olmode = 0;
69 # define cfgetispeed(ptr) (ptr)->sg_ispeed
70 # define cfgetospeed(ptr) (ptr)->sg_ospeed
71 # define old_tc ottyb
72
73 #else /* USE_TERMIO */
74 struct termio old_tc = { 0, 0, 0, 0, {}, 0, 0 };
75
76 # ifndef TCSANOW
77 # ifdef TCSETS
78 # define TCSANOW TCSETS
79 # define TCSADRAIN TCSETSW
80 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
81 # else
82 # ifdef TCSETA
83 # define TCSANOW TCSETA
84 # define TCSADRAIN TCSETAW
85 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
86 # else
87 # define TCSANOW TIOCSETA
88 # define TCSADRAIN TIOCSETAW
89 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
90 # endif
91 # endif
92 # define tcsetattr(f, a, t) ioctl(f, a, (char *)t)
93 # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD)
94 # ifdef CIBAUD
95 # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
96 # else
97 # define cfgetispeed(ptr) cfgetospeed(ptr)
98 # endif
99 # endif /* TCSANOW */
100 # ifdef sysV88
101 # define TIOCFLUSH TC_PX_DRAIN
102 # endif
103 #endif /* USE_TERMIO */
104
105 static fd_set *ibitsp, *obitsp, *xbitsp;
106 int fdsn;
107
108 #ifdef SIGINT
109 static SIG_FUNC_RET intr(int);
110 #endif /* SIGINT */
111 #ifdef SIGQUIT
112 static SIG_FUNC_RET intr2(int);
113 #endif /* SIGQUIT */
114 #ifdef SIGTSTP
115 static SIG_FUNC_RET susp(int);
116 #endif /* SIGTSTP */
117 #ifdef SIGINFO
118 static SIG_FUNC_RET ayt(int);
119 #endif
120
121 void
init_sys(void)122 init_sys(void)
123 {
124 tout = fileno(stdout);
125 tin = fileno(stdin);
126 errno = 0;
127 }
128
129 int
TerminalWrite(char * buf,int n)130 TerminalWrite(char *buf, int n)
131 {
132 return write(tout, buf, n);
133 }
134
135 int
TerminalRead(char * buf,int n)136 TerminalRead(char *buf, int n)
137 {
138 return read(tin, buf, n);
139 }
140
141 /*
142 *
143 */
144
145 int
TerminalAutoFlush(void)146 TerminalAutoFlush(void)
147 {
148 #if defined(LNOFLSH)
149 int flush;
150
151 ioctl(0, TIOCLGET, (char *)&flush);
152 return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */
153 #else /* LNOFLSH */
154 return 1;
155 #endif /* LNOFLSH */
156 }
157
158 #ifdef KLUDGELINEMODE
159 extern int kludgelinemode;
160 #endif
161 /*
162 * TerminalSpecialChars()
163 *
164 * Look at an input character to see if it is a special character
165 * and decide what to do.
166 *
167 * Output:
168 *
169 * 0 Don't add this character.
170 * 1 Do add this character
171 */
172
173 int
TerminalSpecialChars(int c)174 TerminalSpecialChars(int c)
175 {
176 if (c == termIntChar) {
177 intp();
178 return 0;
179 } else if (c == termQuitChar) {
180 #ifdef KLUDGELINEMODE
181 if (kludgelinemode)
182 sendbrk();
183 else
184 #endif
185 sendabort();
186 return 0;
187 } else if (c == termEofChar) {
188 if (my_want_state_is_will(TELOPT_LINEMODE)) {
189 sendeof();
190 return 0;
191 }
192 return 1;
193 } else if (c == termSuspChar) {
194 sendsusp();
195 return(0);
196 } else if (c == termFlushChar) {
197 xmitAO(); /* Transmit Abort Output */
198 return 0;
199 } else if (!MODE_LOCAL_CHARS(globalmode)) {
200 if (c == termKillChar) {
201 xmitEL();
202 return 0;
203 } else if (c == termEraseChar) {
204 xmitEC(); /* Transmit Erase Character */
205 return 0;
206 }
207 }
208 return 1;
209 }
210
211
212 /*
213 * Flush output to the terminal
214 */
215
216 void
TerminalFlushOutput(void)217 TerminalFlushOutput(void)
218 {
219 #ifdef TIOCFLUSH
220 (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
221 #else
222 (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
223 #endif
224 }
225
226 void
TerminalSaveState(void)227 TerminalSaveState(void)
228 {
229 #ifndef USE_TERMIO
230 ioctl(0, TIOCGETP, (char *)&ottyb);
231 ioctl(0, TIOCGETC, (char *)&otc);
232 ioctl(0, TIOCGLTC, (char *)&oltc);
233 ioctl(0, TIOCLGET, (char *)&olmode);
234
235 ntc = otc;
236 nltc = oltc;
237 nttyb = ottyb;
238
239 #else /* USE_TERMIO */
240 tcgetattr(0, &old_tc);
241
242 new_tc = old_tc;
243
244 #ifndef VDISCARD
245 termFlushChar = CONTROL('O');
246 #endif
247 #ifndef VWERASE
248 termWerasChar = CONTROL('W');
249 #endif
250 #ifndef VREPRINT
251 termRprntChar = CONTROL('R');
252 #endif
253 #ifndef VLNEXT
254 termLiteralNextChar = CONTROL('V');
255 #endif
256 #ifndef VSTART
257 termStartChar = CONTROL('Q');
258 #endif
259 #ifndef VSTOP
260 termStopChar = CONTROL('S');
261 #endif
262 #ifndef VSTATUS
263 termAytChar = CONTROL('T');
264 #endif
265 #endif /* USE_TERMIO */
266 }
267
268 cc_t *
tcval(int func)269 tcval(int func)
270 {
271 switch(func) {
272 case SLC_IP: return(&termIntChar);
273 case SLC_ABORT: return(&termQuitChar);
274 case SLC_EOF: return(&termEofChar);
275 case SLC_EC: return(&termEraseChar);
276 case SLC_EL: return(&termKillChar);
277 case SLC_XON: return(&termStartChar);
278 case SLC_XOFF: return(&termStopChar);
279 case SLC_FORW1: return(&termForw1Char);
280 #ifdef USE_TERMIO
281 case SLC_FORW2: return(&termForw2Char);
282 # ifdef VDISCARD
283 case SLC_AO: return(&termFlushChar);
284 # endif
285 # ifdef VSUSP
286 case SLC_SUSP: return(&termSuspChar);
287 # endif
288 # ifdef VWERASE
289 case SLC_EW: return(&termWerasChar);
290 # endif
291 # ifdef VREPRINT
292 case SLC_RP: return(&termRprntChar);
293 # endif
294 # ifdef VLNEXT
295 case SLC_LNEXT: return(&termLiteralNextChar);
296 # endif
297 # ifdef VSTATUS
298 case SLC_AYT: return(&termAytChar);
299 # endif
300 #endif
301
302 case SLC_SYNCH:
303 case SLC_BRK:
304 case SLC_EOR:
305 default:
306 return((cc_t *)0);
307 }
308 }
309
310 void
TerminalDefaultChars(void)311 TerminalDefaultChars(void)
312 {
313 #ifndef USE_TERMIO
314 ntc = otc;
315 nltc = oltc;
316 nttyb.sg_kill = ottyb.sg_kill;
317 nttyb.sg_erase = ottyb.sg_erase;
318 #else /* USE_TERMIO */
319 memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
320 # ifndef VDISCARD
321 termFlushChar = CONTROL('O');
322 # endif
323 # ifndef VWERASE
324 termWerasChar = CONTROL('W');
325 # endif
326 # ifndef VREPRINT
327 termRprntChar = CONTROL('R');
328 # endif
329 # ifndef VLNEXT
330 termLiteralNextChar = CONTROL('V');
331 # endif
332 # ifndef VSTART
333 termStartChar = CONTROL('Q');
334 # endif
335 # ifndef VSTOP
336 termStopChar = CONTROL('S');
337 # endif
338 # ifndef VSTATUS
339 termAytChar = CONTROL('T');
340 # endif
341 #endif /* USE_TERMIO */
342 }
343
344 /*
345 * TerminalNewMode - set up terminal to a specific mode.
346 * MODE_ECHO: do local terminal echo
347 * MODE_FLOW: do local flow control
348 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
349 * MODE_EDIT: do local line editing
350 *
351 * Command mode:
352 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
353 * local echo
354 * local editing
355 * local xon/xoff
356 * local signal mapping
357 *
358 * Linemode:
359 * local/no editing
360 * Both Linemode and Single Character mode:
361 * local/remote echo
362 * local/no xon/xoff
363 * local/no signal mapping
364 */
365
366 void
TerminalNewMode(int f)367 TerminalNewMode(int f)
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 */
376 struct termio tmp_tc;
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 #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
507 # ifdef VLNEXT
508 tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
509 # endif
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) {
575 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
576 tmp_tc.c_cflag |= CS8;
577 tmp_tc.c_oflag &= ~OPOST;
578 } else {
579 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
580 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
581 tmp_tc.c_oflag |= OPOST;
582 }
583 #endif
584 onoff = 1;
585 }
586
587 if (f != -1) {
588 #ifdef SIGINT
589 (void) signal(SIGINT, intr);
590 #endif
591 #ifdef SIGQUIT
592 (void) signal(SIGQUIT, intr2);
593 #endif
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 {
639 #ifdef SIGINFO
640 (void) signal(SIGINFO, (void (*)(int))ayt_status);
641 #endif
642 #ifdef SIGINT
643 (void) signal(SIGINT, SIG_DFL);
644 #endif
645 #ifdef SIGQUIT
646 (void) signal(SIGQUIT, SIG_DFL);
647 #endif
648 #ifdef SIGTSTP
649 (void) signal(SIGTSTP, SIG_DFL);
650 # ifndef SOLARIS
651 (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
652 # else /* SOLARIS */
653 (void) sigrelse(SIGTSTP);
654 # endif /* SOLARIS */
655 #endif /* SIGTSTP */
656 #ifndef USE_TERMIO
657 ltc = oltc;
658 tc = otc;
659 sb = ottyb;
660 lmode = olmode;
661 #else
662 tmp_tc = old_tc;
663 #endif
664 }
665 #ifndef USE_TERMIO
666 ioctl(tin, TIOCLSET, (char *)&lmode);
667 ioctl(tin, TIOCSLTC, (char *)<c);
668 ioctl(tin, TIOCSETC, (char *)&tc);
669 ioctl(tin, TIOCSETN, (char *)&sb);
670 #else
671 if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
672 tcsetattr(tin, TCSANOW, &tmp_tc);
673 #endif
674
675 ioctl(tin, FIONBIO, (char *)&onoff);
676 ioctl(tout, FIONBIO, (char *)&onoff);
677
678 }
679
680 void
TerminalSpeeds(long * ispeed,long * ospeed)681 TerminalSpeeds(long *ispeed, long *ospeed)
682 {
683 #ifdef DECODE_BAUD
684 struct termspeeds *tp;
685 #endif /* DECODE_BAUD */
686 long in, out;
687
688 out = cfgetospeed(&old_tc);
689 in = cfgetispeed(&old_tc);
690 if (in == 0)
691 in = out;
692
693 #ifdef DECODE_BAUD
694 tp = termspeeds;
695 while ((tp->speed != -1) && (tp->value < in))
696 tp++;
697 *ispeed = tp->speed;
698
699 tp = termspeeds;
700 while ((tp->speed != -1) && (tp->value < out))
701 tp++;
702 *ospeed = tp->speed;
703 #else /* DECODE_BAUD */
704 *ispeed = in;
705 *ospeed = out;
706 #endif /* DECODE_BAUD */
707 }
708
709 int
TerminalWindowSize(long * rows,long * cols)710 TerminalWindowSize(long *rows, long *cols)
711 {
712 #ifdef TIOCGWINSZ
713 struct winsize ws;
714
715 if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
716 *rows = ws.ws_row;
717 *cols = ws.ws_col;
718 return 1;
719 }
720 #endif /* TIOCGWINSZ */
721 return 0;
722 }
723
724 int
NetClose(int fd)725 NetClose(int fd)
726 {
727 return close(fd);
728 }
729
730 static void
NetNonblockingIO(int fd,int onoff)731 NetNonblockingIO(int fd, int onoff)
732 {
733 ioctl(fd, FIONBIO, (char *)&onoff);
734 }
735
736
737 /*
738 * Various signal handling routines.
739 */
740
741 /* ARGSUSED */
742 SIG_FUNC_RET
intr(int sig __unused)743 intr(int sig __unused)
744 {
745 if (localchars) {
746 intp();
747 return;
748 }
749 setcommandmode();
750 longjmp(toplevel, -1);
751 }
752
753 /* ARGSUSED */
754 SIG_FUNC_RET
intr2(int sig __unused)755 intr2(int sig __unused)
756 {
757 if (localchars) {
758 #ifdef KLUDGELINEMODE
759 if (kludgelinemode)
760 sendbrk();
761 else
762 #endif
763 sendabort();
764 return;
765 }
766 }
767
768 #ifdef SIGTSTP
769 /* ARGSUSED */
770 SIG_FUNC_RET
susp(int sig __unused)771 susp(int sig __unused)
772 {
773 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
774 return;
775 if (localchars)
776 sendsusp();
777 }
778 #endif
779
780 #ifdef SIGWINCH
781 /* ARGSUSED */
782 static SIG_FUNC_RET
sendwin(int sig __unused)783 sendwin(int sig __unused)
784 {
785 if (connected) {
786 sendnaws();
787 }
788 }
789 #endif
790
791 #ifdef SIGINFO
792 /* ARGSUSED */
793 SIG_FUNC_RET
ayt(int sig __unused)794 ayt(int sig __unused)
795 {
796 if (connected)
797 sendayt();
798 else
799 ayt_status();
800 }
801 #endif
802
803
804 void
sys_telnet_init(void)805 sys_telnet_init(void)
806 {
807 (void) signal(SIGINT, intr);
808 (void) signal(SIGQUIT, intr2);
809 (void) signal(SIGPIPE, SIG_IGN);
810 #ifdef SIGWINCH
811 (void) signal(SIGWINCH, sendwin);
812 #endif
813 #ifdef SIGTSTP
814 (void) signal(SIGTSTP, susp);
815 #endif
816 #ifdef SIGINFO
817 (void) signal(SIGINFO, ayt);
818 #endif
819
820 setconnmode(0);
821
822 NetNonblockingIO(net, 1);
823
824 #if defined(SO_OOBINLINE)
825 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
826 perror("SetSockOpt");
827 }
828 #endif /* defined(SO_OOBINLINE) */
829 }
830
831 /*
832 * Process rings -
833 *
834 * This routine tries to fill up/empty our various rings.
835 *
836 * The parameter specifies whether this is a poll operation,
837 * or a block-until-something-happens operation.
838 *
839 * The return value is 1 if something happened, 0 if not.
840 */
841
842 int
process_rings(int netin,int netout,int netex,int ttyin,int ttyout,int poll)843 process_rings(int netin, int netout, int netex, int ttyin, int ttyout, int poll)
844 {
845 int c;
846 int returnValue = 0;
847 static struct timeval TimeValue = { 0, 0 };
848 int maxfd = -1;
849 int tmp;
850
851 if ((netout || netin || netex) && net > maxfd)
852 maxfd = net;
853
854 if (ttyout && tout > maxfd)
855 maxfd = tout;
856 if (ttyin && tin > maxfd)
857 maxfd = tin;
858 tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
859 if (tmp > fdsn) {
860 if (ibitsp)
861 free(ibitsp);
862 if (obitsp)
863 free(obitsp);
864 if (xbitsp)
865 free(xbitsp);
866
867 fdsn = tmp;
868 if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL)
869 err(1, "malloc");
870 if ((obitsp = (fd_set *)malloc(fdsn)) == NULL)
871 err(1, "malloc");
872 if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL)
873 err(1, "malloc");
874 memset(ibitsp, 0, fdsn);
875 memset(obitsp, 0, fdsn);
876 memset(xbitsp, 0, fdsn);
877 }
878
879 if (netout)
880 FD_SET(net, obitsp);
881 if (ttyout)
882 FD_SET(tout, obitsp);
883 if (ttyin)
884 FD_SET(tin, ibitsp);
885 if (netin)
886 FD_SET(net, ibitsp);
887 if (netex)
888 FD_SET(net, xbitsp);
889 if ((c = select(maxfd + 1, ibitsp, obitsp, xbitsp,
890 (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
891 if (c == -1) {
892 /*
893 * we can get EINTR if we are in line mode,
894 * and the user does an escape (TSTP), or
895 * some other signal generator.
896 */
897 if (errno == EINTR) {
898 return 0;
899 }
900 /* I don't like this, does it ever happen? */
901 printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno));
902 sleep(5);
903 }
904 return 0;
905 }
906
907 /*
908 * Any urgent data?
909 */
910 if (FD_ISSET(net, xbitsp)) {
911 FD_CLR(net, xbitsp);
912 SYNCHing = 1;
913 (void) ttyflush(1); /* flush already enqueued data */
914 }
915
916 /*
917 * Something to read from the network...
918 */
919 if (FD_ISSET(net, ibitsp)) {
920 int canread;
921
922 FD_CLR(net, ibitsp);
923 canread = ring_empty_consecutive(&netiring);
924 #if !defined(SO_OOBINLINE)
925 /*
926 * In 4.2 (and some early 4.3) systems, the
927 * OOB indication and data handling in the kernel
928 * is such that if two separate TCP Urgent requests
929 * come in, one byte of TCP data will be overlaid.
930 * This is fatal for Telnet, but we try to live
931 * with it.
932 *
933 * In addition, in 4.2 (and...), a special protocol
934 * is needed to pick up the TCP Urgent data in
935 * the correct sequence.
936 *
937 * What we do is: if we think we are in urgent
938 * mode, we look to see if we are "at the mark".
939 * If we are, we do an OOB receive. If we run
940 * this twice, we will do the OOB receive twice,
941 * but the second will fail, since the second
942 * time we were "at the mark", but there wasn't
943 * any data there (the kernel doesn't reset
944 * "at the mark" until we do a normal read).
945 * Once we've read the OOB data, we go ahead
946 * and do normal reads.
947 *
948 * There is also another problem, which is that
949 * since the OOB byte we read doesn't put us
950 * out of OOB state, and since that byte is most
951 * likely the TELNET DM (data mark), we would
952 * stay in the TELNET SYNCH (SYNCHing) state.
953 * So, clocks to the rescue. If we've "just"
954 * received a DM, then we test for the
955 * presence of OOB data when the receive OOB
956 * fails (and AFTER we did the normal mode read
957 * to clear "at the mark").
958 */
959 if (SYNCHing) {
960 int atmark;
961 static int bogus_oob = 0, first = 1;
962
963 ioctl(net, SIOCATMARK, (char *)&atmark);
964 if (atmark) {
965 c = recv(net, netiring.supply, canread, MSG_OOB);
966 if ((c == -1) && (errno == EINVAL)) {
967 c = recv(net, netiring.supply, canread, 0);
968 if (clocks.didnetreceive < clocks.gotDM) {
969 SYNCHing = stilloob(net);
970 }
971 } else if (first && c > 0) {
972 /*
973 * Bogosity check. Systems based on 4.2BSD
974 * do not return an error if you do a second
975 * recv(MSG_OOB). So, we do one. If it
976 * succeeds and returns exactly the same
977 * data, then assume that we are running
978 * on a broken system and set the bogus_oob
979 * flag. (If the data was different, then
980 * we probably got some valid new data, so
981 * increment the count...)
982 */
983 int i;
984 i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
985 if (i == c &&
986 memcmp(netiring.supply, netiring.supply + c, i) == 0) {
987 bogus_oob = 1;
988 first = 0;
989 } else if (i < 0) {
990 bogus_oob = 0;
991 first = 0;
992 } else
993 c += i;
994 }
995 if (bogus_oob && c > 0) {
996 int i;
997 /*
998 * Bogosity. We have to do the read
999 * to clear the atmark to get out of
1000 * an infinate loop.
1001 */
1002 i = read(net, netiring.supply + c, canread - c);
1003 if (i > 0)
1004 c += i;
1005 }
1006 } else {
1007 c = recv(net, netiring.supply, canread, 0);
1008 }
1009 } else {
1010 c = recv(net, netiring.supply, canread, 0);
1011 }
1012 settimer(didnetreceive);
1013 #else /* !defined(SO_OOBINLINE) */
1014 c = recv(net, (char *)netiring.supply, canread, 0);
1015 #endif /* !defined(SO_OOBINLINE) */
1016 if (c < 0 && errno == EWOULDBLOCK) {
1017 c = 0;
1018 } else if (c <= 0) {
1019 return -1;
1020 }
1021 if (netdata) {
1022 Dump('<', netiring.supply, c);
1023 }
1024 if (c)
1025 ring_supplied(&netiring, c);
1026 returnValue = 1;
1027 }
1028
1029 /*
1030 * Something to read from the tty...
1031 */
1032 if (FD_ISSET(tin, ibitsp)) {
1033 FD_CLR(tin, ibitsp);
1034 c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
1035 if (c < 0 && errno == EIO)
1036 c = 0;
1037 if (c < 0 && errno == EWOULDBLOCK) {
1038 c = 0;
1039 } else {
1040 /* EOF detection for line mode!!!! */
1041 if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
1042 /* must be an EOF... */
1043 *ttyiring.supply = termEofChar;
1044 c = 1;
1045 }
1046 if (c <= 0) {
1047 return -1;
1048 }
1049 if (termdata) {
1050 Dump('<', ttyiring.supply, c);
1051 }
1052 ring_supplied(&ttyiring, c);
1053 }
1054 returnValue = 1; /* did something useful */
1055 }
1056
1057 if (FD_ISSET(net, obitsp)) {
1058 FD_CLR(net, obitsp);
1059 returnValue |= netflush();
1060 }
1061 if (FD_ISSET(tout, obitsp)) {
1062 FD_CLR(tout, obitsp);
1063 returnValue |= (ttyflush(SYNCHing|flushout) > 0);
1064 }
1065
1066 return returnValue;
1067 }
1068