1 /* $NetBSD: sys_bsd.c,v 1.31 2004/03/20 23:26:05 heas Exp $ */
4 * Copyright (c) 1988, 1990, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 from
: static char sccsid
[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95";
37 __RCSID("$NetBSD: sys_bsd.c,v 1.31 2004/03/20 23:26:05 heas Exp $");
42 * The following routines try to encapsulate what is system dependent
43 * (at least between 4.x and dos) which is used in telnet.c.
48 #include <sys/types.h>
50 #include <sys/socket.h>
56 #include <arpa/telnet.h>
63 #define SIG_FUNC_RET void
65 SIG_FUNC_RET
susp(int);
66 SIG_FUNC_RET
ayt(int);
68 SIG_FUNC_RET
intr(int);
69 SIG_FUNC_RET
intr2(int);
70 SIG_FUNC_RET
sendwin(int);
74 tout
, /* Output file descriptor */
75 tin
, /* Input file descriptor */
78 struct termios old_tc
= { 0 };
79 extern struct termios new_tc
;
83 # define TCSANOW TCSETS
84 # define TCSADRAIN TCSETSW
85 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
88 # define TCSANOW TCSETA
89 # define TCSADRAIN TCSETAW
90 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
92 # define TCSANOW TIOCSETA
93 # define TCSADRAIN TIOCSETAW
94 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
97 # define tcsetattr(f, a, t) ioctl(f, a, (char *)t)
98 # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD)
100 # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
102 # define cfgetispeed(ptr) cfgetospeed(ptr)
104 # endif /* TCSANOW */
110 tout
= fileno(stdout
);
118 TerminalWrite(char *buf
, int n
)
120 return write(tout
, buf
, n
);
124 TerminalRead(unsigned char *buf
, int n
)
126 return read(tin
, buf
, n
);
134 TerminalAutoFlush(void)
139 #ifdef KLUDGELINEMODE
140 extern int kludgelinemode
;
143 * TerminalSpecialChars()
145 * Look at an input character to see if it is a special character
146 * and decide what to do.
150 * 0 Don't add this character.
151 * 1 Do add this character
155 TerminalSpecialChars(int c
)
157 if (c
== termIntChar
) {
160 } else if (c
== termQuitChar
) {
161 #ifdef KLUDGELINEMODE
168 } else if (c
== termEofChar
) {
169 if (my_want_state_is_will(TELOPT_LINEMODE
)) {
174 } else if (c
== termSuspChar
) {
177 } else if (c
== termFlushChar
) {
178 xmitAO(); /* Transmit Abort Output */
180 } else if (!MODE_LOCAL_CHARS(globalmode
)) {
181 if (c
== termKillChar
) {
184 } else if (c
== termEraseChar
) {
185 xmitEC(); /* Transmit Erase Character */
194 * Flush output to the terminal
198 TerminalFlushOutput(void)
201 (void) ioctl(fileno(stdout
), TIOCFLUSH
, &com
);
205 TerminalSaveState(void)
207 tcgetattr(0, &old_tc
);
216 case SLC_IP
: return(&termIntChar
);
217 case SLC_ABORT
: return(&termQuitChar
);
218 case SLC_EOF
: return(&termEofChar
);
219 case SLC_EC
: return(&termEraseChar
);
220 case SLC_EL
: return(&termKillChar
);
221 case SLC_XON
: return(&termStartChar
);
222 case SLC_XOFF
: return(&termStopChar
);
223 case SLC_FORW1
: return(&termForw1Char
);
224 case SLC_FORW2
: return(&termForw2Char
);
225 case SLC_AO
: return(&termFlushChar
);
226 case SLC_SUSP
: return(&termSuspChar
);
227 case SLC_EW
: return(&termWerasChar
);
228 case SLC_RP
: return(&termRprntChar
);
229 case SLC_LNEXT
: return(&termLiteralNextChar
);
230 case SLC_AYT
: return(&termAytChar
);
241 TerminalDefaultChars(void)
243 memmove(new_tc
.c_cc
, old_tc
.c_cc
, sizeof(old_tc
.c_cc
));
248 TerminalRestoreState(void)
254 * TerminalNewMode - set up terminal to a specific mode.
255 * MODE_ECHO: do local terminal echo
256 * MODE_FLOW: do local flow control
257 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
258 * MODE_EDIT: do local line editing
261 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
265 * local signal mapping
269 * Both Linemode and Single Character mode:
272 * local/no signal mapping
277 TerminalNewMode(int f
)
279 static int prevmode
= 0;
280 struct termios tmp_tc
;
285 globalmode
= f
&~MODE_FORCE
;
290 * Write any outstanding data before switching modes
291 * ttyflush() returns 0 only when there is no more data
292 * left to write out, it returns -1 if it couldn't do
293 * anything at all, otherwise it returns 1 + the number
294 * of characters left to write.
296 * We would really like to ask the kernel to wait for the output
297 * to drain, like we can do with the TCSADRAIN, but we don't have
298 * that option. The only ioctl that waits for the output to
299 * drain, TIOCSETP, also flushes the input queue, which is NOT
300 * what we want (TIOCSETP is like TCSADFLUSH).
303 old
= ttyflush(SYNCHing
|flushout
);
304 if (old
< 0 || old
> 1) {
305 tcgetattr(tin
, &tmp_tc
);
308 * Wait for data to drain, then flush again.
310 tcsetattr(tin
, TCSADRAIN
, &tmp_tc
);
311 old
= ttyflush(SYNCHing
|flushout
);
312 } while (old
< 0 || old
> 1);
316 prevmode
= f
&~MODE_FORCE
;
320 tmp_tc
.c_lflag
|= ECHO
;
321 tmp_tc
.c_oflag
|= ONLCR
;
323 tmp_tc
.c_iflag
|= ICRNL
;
325 tmp_tc
.c_lflag
&= ~ECHO
;
326 tmp_tc
.c_oflag
&= ~ONLCR
;
329 tmp_tc
.c_iflag
&= ~ICRNL
;
333 if ((f
&MODE_FLOW
) == 0) {
334 tmp_tc
.c_iflag
&= ~(IXOFF
|IXON
); /* Leave the IXANY bit alone */
336 if (restartany
< 0) {
337 tmp_tc
.c_iflag
|= IXOFF
|IXON
; /* Leave the IXANY bit alone */
338 } else if (restartany
> 0) {
339 tmp_tc
.c_iflag
|= IXOFF
|IXON
|IXANY
;
341 tmp_tc
.c_iflag
|= IXOFF
|IXON
;
342 tmp_tc
.c_iflag
&= ~IXANY
;
346 if ((f
&MODE_TRAPSIG
) == 0) {
347 tmp_tc
.c_lflag
&= ~ISIG
;
350 tmp_tc
.c_lflag
|= ISIG
;
355 tmp_tc
.c_lflag
|= ICANON
;
357 tmp_tc
.c_lflag
&= ~ICANON
;
358 tmp_tc
.c_iflag
&= ~ICRNL
;
359 tmp_tc
.c_cc
[VMIN
] = 1;
360 tmp_tc
.c_cc
[VTIME
] = 0;
363 if ((f
&(MODE_EDIT
|MODE_TRAPSIG
)) == 0) {
364 tmp_tc
.c_lflag
&= ~IEXTEN
;
367 if (f
&MODE_SOFT_TAB
) {
369 tmp_tc
.c_oflag
|= OXTABS
;
372 tmp_tc
.c_oflag
&= ~TABDLY
;
373 tmp_tc
.c_oflag
|= TAB3
;
377 tmp_tc
.c_oflag
&= ~OXTABS
;
380 tmp_tc
.c_oflag
&= ~TABDLY
;
384 if (f
&MODE_LIT_ECHO
) {
386 tmp_tc
.c_lflag
&= ~ECHOCTL
;
390 tmp_tc
.c_lflag
|= ECHOCTL
;
398 tmp_tc
.c_iflag
&= ~ISTRIP
;
400 tmp_tc
.c_iflag
|= ISTRIP
;
401 if (f
& MODE_OUTBIN
) {
402 tmp_tc
.c_cflag
&= ~(CSIZE
|PARENB
);
403 tmp_tc
.c_cflag
|= CS8
;
404 tmp_tc
.c_oflag
&= ~OPOST
;
406 tmp_tc
.c_cflag
&= ~(CSIZE
|PARENB
);
407 tmp_tc
.c_cflag
|= old_tc
.c_cflag
& (CSIZE
|PARENB
);
408 tmp_tc
.c_oflag
|= OPOST
;
414 (void) signal(SIGTSTP
, susp
);
415 (void) signal(SIGINFO
, ayt
);
416 #if defined(USE_TERMIO) && defined(NOKERNINFO)
417 tmp_tc
.c_lflag
|= NOKERNINFO
;
420 * We don't want to process ^Y here. It's just another
421 * character that we'll pass on to the back end. It has
422 * to process it because it will be processed when the
423 * user attempts to read it, not when we send it.
426 tmp_tc
.c_cc
[VDSUSP
] = (cc_t
)(_POSIX_VDISABLE
);
429 * If the VEOL character is already set, then use VEOL2,
430 * otherwise use VEOL.
432 esc
= (rlogin
!= _POSIX_VDISABLE
) ? rlogin
: escape
;
433 if ((tmp_tc
.c_cc
[VEOL
] != esc
)
435 && (tmp_tc
.c_cc
[VEOL2
] != esc
)
438 if (tmp_tc
.c_cc
[VEOL
] == (cc_t
)(_POSIX_VDISABLE
))
439 tmp_tc
.c_cc
[VEOL
] = esc
;
441 else if (tmp_tc
.c_cc
[VEOL2
] == (cc_t
)(_POSIX_VDISABLE
))
442 tmp_tc
.c_cc
[VEOL2
] = esc
;
446 (void) signal(SIGINFO
, (void (*)(int)) ayt_status
);
447 (void) signal(SIGTSTP
, SIG_DFL
);
448 (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP
-1)));
451 if (tcsetattr(tin
, TCSADRAIN
, &tmp_tc
) < 0)
452 tcsetattr(tin
, TCSANOW
, &tmp_tc
);
454 ioctl(tin
, FIONBIO
, (char *)&onoff
);
455 ioctl(tout
, FIONBIO
, (char *)&onoff
);
457 if (noasynchtty
== 0) {
458 ioctl(tin
, FIOASYNC
, (char *)&onoff
);
460 #endif /* defined(TN3270) */
465 TerminalSpeeds(long *ispeed
, long *ospeed
)
469 out
= cfgetospeed(&old_tc
);
470 in
= cfgetispeed(&old_tc
);
479 TerminalWindowSize(long *rows
, long *cols
)
483 if (ioctl(fileno(stdin
), TIOCGWINSZ
, (char *)&ws
) >= 0) {
499 NetNonblockingIO(int fd
, int onoff
)
501 ioctl(fd
, FIONBIO
, (char *)&onoff
);
506 NetSigIO(int fd
, int onoff
)
508 ioctl(fd
, FIOASYNC
, (char *)&onoff
); /* hear about input */
517 fcntl(fd
, F_SETOWN
, myPid
);
519 #endif /*defined(TN3270)*/
522 * Various signal handling routines.
534 longjmp(toplevel
, -1);
542 #ifdef KLUDGELINEMODE
556 if ((rlogin
!= _POSIX_VDISABLE
) && rlogin_susp())
583 sys_telnet_init(void)
585 (void) signal(SIGINT
, intr
);
586 (void) signal(SIGQUIT
, intr2
);
587 (void) signal(SIGPIPE
, SIG_IGN
);
588 (void) signal(SIGWINCH
, sendwin
);
589 (void) signal(SIGTSTP
, susp
);
590 (void) signal(SIGINFO
, ayt
);
594 NetNonblockingIO(net
, 1);
597 if (noasynchnet
== 0) { /* DBX can't handle! */
601 #endif /* defined(TN3270) */
603 if (SetSockOpt(net
, SOL_SOCKET
, SO_OOBINLINE
, 1) == -1) {
604 perror("SetSockOpt");
611 * This routine tries to fill up/empty our various rings.
613 * The parameter specifies whether this is a poll operation,
614 * or a block-until-something-happens operation.
616 * The return value is 1 if something happened, 0 if not, < 0 if an
621 process_rings(int netin
, int netout
, int netex
, int ttyin
, int ttyout
,
622 int dopoll
) /* If 0, then block until something to do */
624 struct pollfd set
[3];
626 /* One wants to be a bit careful about setting returnValue
627 * to one, since a one implies we did some useful work,
628 * and therefore probably won't be called to block next
629 * time (TN3270 mode only).
634 set
[0].events
= (netout
? POLLOUT
: 0) | (netin
? POLLIN
: 0) |
635 (netex
? POLLPRI
: 0);
637 set
[1].events
= ttyout
? POLLOUT
: 0;
639 set
[2].events
= ttyin
? POLLIN
: 0;
641 if ((c
= poll(set
, 3, dopoll
? 0 : INFTIM
)) < 0) {
644 * we can get EINTR if we are in line mode,
645 * and the user does an escape (TSTP), or
646 * some other signal generator.
648 if (errno
== EINTR
) {
653 * we can get EBADF if we were in transparent
654 * mode, and the transcom process died.
658 #endif /* defined(TN3270) */
659 /* I don't like this, does it ever happen? */
660 printf("sleep(5) from telnet, after poll\r\n");
669 if (set
[0].revents
& POLLPRI
) {
671 (void) ttyflush(1); /* flush already enqueued data */
675 * Something to read from the network...
677 if (set
[0].revents
& POLLIN
) {
680 canread
= ring_empty_consecutive(&netiring
);
681 c
= recv(net
, (char *)netiring
.supply
, canread
, 0);
682 if (c
< 0 && errno
== EWOULDBLOCK
) {
688 Dump('<', netiring
.supply
, c
);
691 ring_supplied(&netiring
, c
);
696 * Something to read from the tty...
698 if (set
[2].revents
& POLLIN
) {
699 c
= TerminalRead(ttyiring
.supply
, ring_empty_consecutive(&ttyiring
));
700 if (c
< 0 && errno
== EIO
)
702 if (c
< 0 && errno
== EWOULDBLOCK
) {
709 /* must be an EOF... */
710 if (MODE_LOCAL_CHARS(globalmode
) && isatty(tin
)) {
711 *ttyiring
.supply
= termEofChar
;
720 Dump('<', ttyiring
.supply
, c
);
722 ring_supplied(&ttyiring
, c
);
724 returnValue
= 1; /* did something useful */
727 if (set
[0].revents
& POLLOUT
) {
728 returnValue
|= netflush();
731 if (set
[1].revents
& (POLLHUP
|POLLNVAL
))
734 if (set
[1].revents
& POLLOUT
) {
735 returnValue
|= (ttyflush(SYNCHing
|flushout
) > 0);