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