2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 1988, 1990, 1993
8 * The Regents of the University of California. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 static char sccsid
[] = "@(#)sys_bsd.c 8.1 (Berkeley) 6/6/93";
43 * The following routines try to encapsulate what is system dependent
44 * (at least between 4.x and dos) which is used in telnet.c.
49 #include <sys/types.h>
51 #include <sys/socket.h>
55 #include <arpa/telnet.h>
63 #define SIG_FUNC_RET void
65 int tout
; /* Output file descriptor */
66 static int tin
; /* Input file descriptor */
71 struct tchars otc
= { 0 }, ntc
= { 0 };
72 struct ltchars oltc
= { 0 }, nltc
= { 0 };
73 struct sgttyb ottyb
= { 0 }, nttyb
= { 0 };
75 #define cfgetispeed(ptr) (ptr)->sg_ispeed
76 #define cfgetospeed(ptr) (ptr)->sg_ospeed
79 #else /* USE_TERMIO */
80 static struct termio old_tc
= { 0 };
81 extern struct termio new_tc
;
82 #endif /* USE_TERMIO */
84 static fd_set ibits
, obits
, xbits
;
86 static SIG_FUNC_RET
susp(int);
87 void fatal_tty_error(char *doing_what
);
93 tout
= fileno(stdout
);
104 TerminalWrite(buf
, n
)
108 return (write(tout
, buf
, n
));
116 return (read(tin
, buf
, n
));
119 #ifdef KLUDGELINEMODE
120 extern int kludgelinemode
;
123 * TerminalSpecialChars()
125 * Look at an input character to see if it is a special character
126 * and decide what to do.
130 * 0 Don't add this character.
131 * 1 Do add this character
134 TerminalSpecialChars(c
)
138 * Don't check for signal characters here. If MODE_TRAPSIG is on,
139 * then the various signal handlers will catch the characters. If
140 * the character in question gets here, then it must have been LNEXTed
142 if (c
== termQuitChar
) {
143 #ifdef KLUDGELINEMODE
144 if (kludgelinemode
) {
145 if (sendbrk() == -1) {
146 /* This won't return. */
147 fatal_tty_error("write");
152 } else if (c
== termFlushChar
) {
153 /* Transmit Abort Output */
154 if (xmitAO() == -1) {
155 /* This won't return. */
156 fatal_tty_error("write");
159 } else if (!MODE_LOCAL_CHARS(globalmode
)) {
160 if (c
== termKillChar
) {
163 } else if (c
== termEraseChar
) {
164 xmitEC(); /* Transmit Erase Character */
173 * Flush output to the terminal
177 TerminalFlushOutput()
179 if (isatty(fileno(stdout
))) {
180 (void) ioctl(fileno(stdout
), TIOCFLUSH
, NULL
);
188 (void) ioctl(0, TIOCGETP
, &ottyb
);
189 (void) ioctl(0, TIOCGETC
, &otc
);
190 (void) ioctl(0, TIOCGLTC
, &oltc
);
191 (void) ioctl(0, TIOCLGET
, &olmode
);
197 #else /* USE_TERMIO */
198 (void) tcgetattr(0, &old_tc
);
201 termAytChar
= CONTROL('T');
202 #endif /* USE_TERMIO */
210 case SLC_IP
: return (&termIntChar
);
211 case SLC_ABORT
: return (&termQuitChar
);
212 case SLC_EOF
: return (&termEofChar
);
213 case SLC_EC
: return (&termEraseChar
);
214 case SLC_EL
: return (&termKillChar
);
215 case SLC_XON
: return (&termStartChar
);
216 case SLC_XOFF
: return (&termStopChar
);
217 case SLC_FORW1
: return (&termForw1Char
);
219 case SLC_FORW2
: return (&termForw2Char
);
220 case SLC_AO
: return (&termFlushChar
);
221 case SLC_SUSP
: return (&termSuspChar
);
222 case SLC_EW
: return (&termWerasChar
);
223 case SLC_RP
: return (&termRprntChar
);
224 case SLC_LNEXT
: return (&termLiteralNextChar
);
236 TerminalDefaultChars()
241 nttyb
.sg_kill
= ottyb
.sg_kill
;
242 nttyb
.sg_erase
= ottyb
.sg_erase
;
243 #else /* USE_TERMIO */
244 (void) memcpy(new_tc
.c_cc
, old_tc
.c_cc
, sizeof (old_tc
.c_cc
));
245 termAytChar
= CONTROL('T');
246 #endif /* USE_TERMIO */
250 * TerminalNewMode - set up terminal to a specific mode.
251 * MODE_ECHO: do local terminal echo
252 * MODE_FLOW: do local flow control
253 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
254 * MODE_EDIT: do local line editing
257 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
261 * local signal mapping
265 * Both Linemode and Single Character mode:
268 * local/no signal mapping
276 static int prevmode
= -2; /* guaranteed unique */
282 #else /* USE_TERMIO */
283 struct termio tmp_tc
;
284 #endif /* USE_TERMIO */
290 globalmode
= f
&~MODE_FORCE
;
295 * Write any outstanding data before switching modes
296 * ttyflush() returns 0 only when there was no data
297 * to write out; it returns -1 if it couldn't do
298 * anything at all, returns -2 if there was a write
299 * error (other than EWOULDBLOCK), and otherwise it
300 * returns 1 + the number of characters left to write.
304 * We would really like ask the kernel to wait for the output
305 * to drain, like we can do with the TCSADRAIN, but we don't have
306 * that option. The only ioctl that waits for the output to
307 * drain, TIOCSETP, also flushes the input queue, which is NOT
308 * what we want(TIOCSETP is like TCSADFLUSH).
311 old
= ttyflush(SYNCHing
|flushout
);
312 if (old
== -1 || old
> 1) {
314 (void) tcgetattr(tin
, &tmp_tc
);
315 #endif /* USE_TERMIO */
318 * Wait for data to drain, then flush again.
321 (void) tcsetattr(tin
, TCSADRAIN
, &tmp_tc
);
322 #endif /* USE_TERMIO */
323 old
= ttyflush(SYNCHing
|flushout
);
324 } while (old
== -1 || old
> 1);
328 prevmode
= f
&~MODE_FORCE
;
342 tmp_tc
.c_lflag
|= ECHO
;
343 tmp_tc
.c_oflag
|= ONLCR
;
345 tmp_tc
.c_iflag
|= ICRNL
;
349 sb
.sg_flags
&= ~ECHO
;
351 tmp_tc
.c_lflag
&= ~ECHO
;
352 tmp_tc
.c_oflag
&= ~ONLCR
;
355 tmp_tc
.c_iflag
&= ~ICRNL
;
360 if ((f
&MODE_FLOW
) == 0) {
362 tc
.t_startc
= _POSIX_VDISABLE
;
363 tc
.t_stopc
= _POSIX_VDISABLE
;
365 tmp_tc
.c_iflag
&= ~(IXOFF
|IXON
); /* Leave the IXANY bit alone */
367 if (restartany
< 0) {
368 /* Leave the IXANY bit alone */
369 tmp_tc
.c_iflag
|= IXOFF
|IXON
;
370 } else if (restartany
> 0) {
371 tmp_tc
.c_iflag
|= IXOFF
|IXON
|IXANY
;
373 tmp_tc
.c_iflag
|= IXOFF
|IXON
;
374 tmp_tc
.c_iflag
&= ~IXANY
;
379 if ((f
&MODE_TRAPSIG
) == 0) {
381 tc
.t_intrc
= _POSIX_VDISABLE
;
382 tc
.t_quitc
= _POSIX_VDISABLE
;
383 tc
.t_eofc
= _POSIX_VDISABLE
;
384 ltc
.t_suspc
= _POSIX_VDISABLE
;
385 ltc
.t_dsuspc
= _POSIX_VDISABLE
;
387 tmp_tc
.c_lflag
&= ~ISIG
;
392 tmp_tc
.c_lflag
|= ISIG
;
399 sb
.sg_flags
&= ~CBREAK
;
400 sb
.sg_flags
|= CRMOD
;
402 tmp_tc
.c_lflag
|= ICANON
;
406 sb
.sg_flags
|= CBREAK
;
408 sb
.sg_flags
|= CRMOD
;
410 sb
.sg_flags
&= ~CRMOD
;
412 tmp_tc
.c_lflag
&= ~ICANON
;
413 tmp_tc
.c_iflag
&= ~ICRNL
;
414 tmp_tc
.c_cc
[VMIN
] = 1;
415 tmp_tc
.c_cc
[VTIME
] = 0;
419 if ((f
&(MODE_EDIT
|MODE_TRAPSIG
)) == 0) {
421 ltc
.t_lnextc
= _POSIX_VDISABLE
;
423 tmp_tc
.c_cc
[VLNEXT
] = (cc_t
)(_POSIX_VDISABLE
);
427 if (f
&MODE_SOFT_TAB
) {
429 sb
.sg_flags
|= XTABS
;
431 tmp_tc
.c_oflag
&= ~TABDLY
;
432 tmp_tc
.c_oflag
|= TAB3
;
436 sb
.sg_flags
&= ~XTABS
;
438 tmp_tc
.c_oflag
&= ~TABDLY
;
442 if (f
&MODE_LIT_ECHO
) {
446 tmp_tc
.c_lflag
&= ~ECHOCTL
;
452 tmp_tc
.c_lflag
|= ECHOCTL
;
465 if (f
& MODE_OUTBIN
) {
466 tmp_tc
.c_cflag
&= ~(CSIZE
|PARENB
);
467 tmp_tc
.c_cflag
|= CS8
;
468 tmp_tc
.c_oflag
&= ~OPOST
;
470 tmp_tc
.c_cflag
&= ~(CSIZE
|PARENB
);
471 tmp_tc
.c_cflag
|= old_tc
.c_cflag
& (CSIZE
|PARENB
);
472 tmp_tc
.c_oflag
|= OPOST
;
480 (void) signal(SIGTSTP
, susp
);
482 #if defined(USE_TERMIO) && defined(NOKERNINFO)
483 tmp_tc
.c_lflag
|= NOKERNINFO
;
486 * We don't want to process ^Y here. It's just another
487 * character that we'll pass on to the back end. It has
488 * to process it because it will be processed when the
489 * user attempts to read it, not when we send it.
492 ltc
.t_dsuspc
= _POSIX_VDISABLE
;
494 tmp_tc
.c_cc
[VDSUSP
] = (cc_t
)(_POSIX_VDISABLE
);
498 * If the VEOL character is already set, then use VEOL2,
499 * otherwise use VEOL.
501 esc
= (rlogin
!= _POSIX_VDISABLE
) ? rlogin
: escape
;
502 if ((tmp_tc
.c_cc
[VEOL
] != esc
)
504 (tmp_tc
.c_cc
[VEOL2
] != esc
)
506 if (tmp_tc
.c_cc
[VEOL
] == (cc_t
)(_POSIX_VDISABLE
))
507 tmp_tc
.c_cc
[VEOL
] = esc
;
508 else if (tmp_tc
.c_cc
[VEOL2
] == (cc_t
)(_POSIX_VDISABLE
))
509 tmp_tc
.c_cc
[VEOL2
] = esc
;
512 if (tc
.t_brkc
== (cc_t
)(_POSIX_VDISABLE
))
516 (void) signal(SIGTSTP
, SIG_DFL
);
517 (void) sigemptyset(&nset
);
518 (void) sigaddset(&nset
, SIGTSTP
);
519 (void) sigprocmask(SIG_UNBLOCK
, &nset
, 0);
531 (void) ioctl(tin
, TIOCLSET
, &lmode
);
532 (void) ioctl(tin
, TIOCSLTC
, <c
);
533 (void) ioctl(tin
, TIOCSETC
, &tc
);
534 (void) ioctl(tin
, TIOCSETN
, &sb
);
536 if (tcsetattr(tin
, TCSADRAIN
, &tmp_tc
) < 0)
537 (void) tcsetattr(tin
, TCSANOW
, &tmp_tc
);
539 (void) ioctl(tin
, FIONBIO
, &onoff
);
540 (void) ioctl(tout
, FIONBIO
, &onoff
);
546 * This code assumes that the values B0, B50, B75...
547 * are in ascending order. They do not have to be
550 static struct termspeeds
{
554 { 0, B0
}, { 50, B50
}, { 75, B75
},
555 { 110, B110
}, { 134, B134
}, { 150, B150
},
556 { 200, B200
}, { 300, B300
}, { 600, B600
},
557 { 1200, B1200
}, { 1800, B1800
}, { 2400, B2400
},
558 { 4800, B4800
}, { 9600, B9600
}, { 19200, B19200
},
559 { 38400, B38400
}, { 57600, B57600
}, { 76800, B76800
},
560 { 115200, B115200
}, { 153600, B153600
}, { 230400, B230400
},
561 { 307200, B307200
}, { 460800, B460800
}, { 921600, B921600
},
566 TerminalSpeeds(ispeed
, ospeed
)
570 register struct termspeeds
*tp
;
571 register int in
, out
;
573 out
= cfgetospeed(&old_tc
);
574 in
= cfgetispeed(&old_tc
);
579 while ((tp
->speed
!= -1) && (tp
->value
< in
)) {
583 tp
--; /* back up to fastest defined speed */
587 while ((tp
->speed
!= -1) && (tp
->value
< out
)) {
596 TerminalWindowSize(rows
, cols
)
597 unsigned short *rows
, *cols
;
601 if (ioctl(fileno(stdin
), TIOCGWINSZ
, &ws
) >= 0) {
610 NetNonblockingIO(fd
, onoff
)
614 (void) ioctl(fd
, FIONBIO
, &onoff
);
618 * Various signal handling routines.
627 * Once is all we should catch SIGPIPE. If we get it again,
628 * it means we tried to put still more data out to a pipe
629 * which has disappeared. In that case, telnet will exit.
631 (void) signal(SIGPIPE
, SIG_IGN
);
634 longjmp(peerdied
, -1);
637 boolean_t intr_happened
= B_FALSE
;
638 boolean_t intr_waiting
= B_FALSE
;
649 (void) signal(SIGINT
, intr
);
655 longjmp(toplevel
, -1);
663 (void) signal(SIGQUIT
, intr2
);
666 * Ignore return to the next two function calls
667 * since we're doing SIGQUIT
669 #ifdef KLUDGELINEMODE
670 if (kludgelinemode
) {
685 (void) signal(SIGTSTP
, susp
);
686 if ((rlogin
!= _POSIX_VDISABLE
) && rlogin_susp())
697 (void) signal(SIGWINCH
, sendwin
);
706 (void) signal(SIGINT
, intr
);
707 (void) signal(SIGQUIT
, intr2
);
708 (void) signal(SIGPIPE
, deadpeer
);
709 (void) signal(SIGWINCH
, sendwin
);
710 (void) signal(SIGTSTP
, susp
);
714 NetNonblockingIO(net
, 1);
716 if (SetSockOpt(net
, SOL_SOCKET
, SO_OOBINLINE
, 1) == -1) {
717 perror("SetSockOpt");
724 * Handle case where there is an unrecoverable error on the tty
725 * connections. Print an error, reset the terminal settings
726 * and get out as painlessly as possible.
729 fatal_tty_error(char *doing_what
)
732 (void) fprintf(stderr
, "Error processing %s: %s\n", doing_what
,
741 * This routine tries to fill up/empty our various rings.
743 * The parameter specifies whether this is a poll operation,
744 * or a block-until-something-happens operation.
746 * The return value is 1 if something happened, 0 if not.
750 process_rings(netin
, netout
, netex
, ttyin
, ttyout
, poll
)
751 int poll
; /* If 0, then block until something to do */
755 * One wants to be a bit careful about setting returnValue
756 * to one, since a one implies we did some useful work,
757 * and therefore probably won't be called to block next
758 * time (TN3270 mode only).
761 static struct timeval TimeValue
= { 0 };
768 FD_SET(tout
, &obits
);
779 if ((c
= select(16, &ibits
, &obits
, &xbits
,
780 (poll
== 0) ? NULL
: &TimeValue
)) < 0) {
783 * we can get EINTR if we are in line mode,
784 * and the user does an escape (TSTP), or
785 * some other signal generator.
787 if (errno
== EINTR
) {
790 /* I don't like this, does it ever happen? */
791 (void) printf("sleep(5) from telnet, after select\r\n");
800 if (FD_ISSET(net
, &xbits
)) {
804 /* flush any data that is already enqueued */
807 /* This will not return. */
808 fatal_tty_error("write");
813 * Something to read from the network...
815 if (FD_ISSET(net
, &ibits
)) {
819 canread
= ring_empty_consecutive(&netiring
);
820 c
= recv(net
, netiring
.supply
, canread
, 0);
821 if (c
< 0 && errno
== EWOULDBLOCK
) {
827 Dump('<', netiring
.supply
, c
);
830 ring_supplied(&netiring
, c
);
835 * Something to read from the tty...
837 if (FD_ISSET(tin
, &ibits
)) {
839 c
= TerminalRead((char *)ttyiring
.supply
,
840 ring_empty_consecutive(&ttyiring
));
842 if (errno
!= EWOULDBLOCK
) {
843 /* This will not return. */
844 fatal_tty_error("read");
848 /* EOF detection for line mode!!!! */
849 if ((c
== 0) && MODE_LOCAL_CHARS(globalmode
) &&
851 /* must be an EOF... */
860 Dump('<', ttyiring
.supply
, c
);
862 ring_supplied(&ttyiring
, c
);
864 returnValue
= 1; /* did something useful */
868 if (FD_ISSET(net
, &obits
)) {
870 returnValue
|= netflush();
872 if (FD_ISSET(tout
, &obits
)) {
873 FD_CLR(tout
, &obits
);
874 i
= ttyflush(SYNCHing
|flushout
);
876 /* This will not return. */
877 fatal_tty_error("write");
879 returnValue
|= (i
> 0);
882 return (returnValue
);