Fix up mix of man(7)/mdoc(7).
[netbsd-mini2440.git] / usr.bin / telnet / sys_bsd.c
blob835b305e3a2be4e07ef1d3638980e8e248db7481
1 /* $NetBSD: sys_bsd.c,v 1.31 2004/03/20 23:26:05 heas Exp $ */
3 /*
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
9 * are met:
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
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 from: static char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95";
36 #else
37 __RCSID("$NetBSD: sys_bsd.c,v 1.31 2004/03/20 23:26:05 heas Exp $");
38 #endif
39 #endif /* not lint */
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.
47 #include <fcntl.h>
48 #include <sys/types.h>
49 #include <sys/time.h>
50 #include <sys/socket.h>
51 #include <signal.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <errno.h>
55 #include <poll.h>
56 #include <arpa/telnet.h>
58 #include "ring.h"
59 #include "defines.h"
60 #include "externs.h"
61 #include "types.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);
73 int
74 tout, /* Output file descriptor */
75 tin, /* Input file descriptor */
76 net;
78 struct termios old_tc = { 0 };
79 extern struct termios new_tc;
81 # ifndef TCSANOW
82 # ifdef TCSETS
83 # define TCSANOW TCSETS
84 # define TCSADRAIN TCSETSW
85 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
86 # else
87 # ifdef TCSETA
88 # define TCSANOW TCSETA
89 # define TCSADRAIN TCSETAW
90 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
91 # else
92 # define TCSANOW TIOCSETA
93 # define TCSADRAIN TIOCSETAW
94 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
95 # endif
96 # endif
97 # define tcsetattr(f, a, t) ioctl(f, a, (char *)t)
98 # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD)
99 # ifdef CIBAUD
100 # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
101 # else
102 # define cfgetispeed(ptr) cfgetospeed(ptr)
103 # endif
104 # endif /* TCSANOW */
107 void
108 init_sys(void)
110 tout = fileno(stdout);
111 tin = fileno(stdin);
113 errno = 0;
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)
136 return 1;
139 #ifdef KLUDGELINEMODE
140 extern int kludgelinemode;
141 #endif
143 * TerminalSpecialChars()
145 * Look at an input character to see if it is a special character
146 * and decide what to do.
148 * Output:
150 * 0 Don't add this character.
151 * 1 Do add this character
155 TerminalSpecialChars(int c)
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;
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;
189 return 1;
194 * Flush output to the terminal
197 void
198 TerminalFlushOutput(void)
200 int com = 0;
201 (void) ioctl(fileno(stdout), TIOCFLUSH, &com);
204 void
205 TerminalSaveState(void)
207 tcgetattr(0, &old_tc);
209 new_tc = old_tc;
212 cc_t *
213 tcval(int func)
215 switch(func) {
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);
232 case SLC_SYNCH:
233 case SLC_BRK:
234 case SLC_EOR:
235 default:
236 return((cc_t *)0);
240 void
241 TerminalDefaultChars(void)
243 memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
246 #ifdef notdef
247 void
248 TerminalRestoreState(void)
251 #endif
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
260 * Command mode:
261 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
262 * local echo
263 * local editing
264 * local xon/xoff
265 * local signal mapping
267 * Linemode:
268 * local/no editing
269 * Both Linemode and Single Character mode:
270 * local/remote echo
271 * local/no xon/xoff
272 * local/no signal mapping
276 void
277 TerminalNewMode(int f)
279 static int prevmode = 0;
280 struct termios tmp_tc;
281 int onoff;
282 int old;
283 cc_t esc;
285 globalmode = f&~MODE_FORCE;
286 if (prevmode == f)
287 return;
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.
295 #ifndef USE_TERMIO
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).
301 #endif
303 old = ttyflush(SYNCHing|flushout);
304 if (old < 0 || old > 1) {
305 tcgetattr(tin, &tmp_tc);
306 do {
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);
315 old = prevmode;
316 prevmode = f&~MODE_FORCE;
317 tmp_tc = new_tc;
319 if (f&MODE_ECHO) {
320 tmp_tc.c_lflag |= ECHO;
321 tmp_tc.c_oflag |= ONLCR;
322 if (crlf)
323 tmp_tc.c_iflag |= ICRNL;
324 } else {
325 tmp_tc.c_lflag &= ~ECHO;
326 tmp_tc.c_oflag &= ~ONLCR;
327 # ifdef notdef
328 if (crlf)
329 tmp_tc.c_iflag &= ~ICRNL;
330 # endif
333 if ((f&MODE_FLOW) == 0) {
334 tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */
335 } else {
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;
340 } else {
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;
348 localchars = 0;
349 } else {
350 tmp_tc.c_lflag |= ISIG;
351 localchars = 1;
354 if (f&MODE_EDIT) {
355 tmp_tc.c_lflag |= ICANON;
356 } else {
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) {
368 # ifdef OXTABS
369 tmp_tc.c_oflag |= OXTABS;
370 # endif
371 # ifdef TABDLY
372 tmp_tc.c_oflag &= ~TABDLY;
373 tmp_tc.c_oflag |= TAB3;
374 # endif
375 } else {
376 # ifdef OXTABS
377 tmp_tc.c_oflag &= ~OXTABS;
378 # endif
379 # ifdef TABDLY
380 tmp_tc.c_oflag &= ~TABDLY;
381 # endif
384 if (f&MODE_LIT_ECHO) {
385 # ifdef ECHOCTL
386 tmp_tc.c_lflag &= ~ECHOCTL;
387 # endif
388 } else {
389 # ifdef ECHOCTL
390 tmp_tc.c_lflag |= ECHOCTL;
391 # endif
394 if (f == -1) {
395 onoff = 0;
396 } else {
397 if (f & MODE_INBIN)
398 tmp_tc.c_iflag &= ~ISTRIP;
399 else
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;
405 } else {
406 tmp_tc.c_cflag &= ~(CSIZE|PARENB);
407 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
408 tmp_tc.c_oflag |= OPOST;
410 onoff = 1;
413 if (f != -1) {
414 (void) signal(SIGTSTP, susp);
415 (void) signal(SIGINFO, ayt);
416 #if defined(USE_TERMIO) && defined(NOKERNINFO)
417 tmp_tc.c_lflag |= NOKERNINFO;
418 #endif
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.
425 # ifdef VDSUSP
426 tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
427 # endif
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)
434 # ifdef VEOL2
435 && (tmp_tc.c_cc[VEOL2] != esc)
436 # endif
438 if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
439 tmp_tc.c_cc[VEOL] = esc;
440 # ifdef VEOL2
441 else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
442 tmp_tc.c_cc[VEOL2] = esc;
443 # endif
445 } else {
446 (void) signal(SIGINFO, (void (*)(int)) ayt_status);
447 (void) signal(SIGTSTP, SIG_DFL);
448 (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
449 tmp_tc = old_tc;
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);
456 #if defined(TN3270)
457 if (noasynchtty == 0) {
458 ioctl(tin, FIOASYNC, (char *)&onoff);
460 #endif /* defined(TN3270) */
464 void
465 TerminalSpeeds(long *ispeed, long *ospeed)
467 long in, out;
469 out = cfgetospeed(&old_tc);
470 in = cfgetispeed(&old_tc);
471 if (in == 0)
472 in = out;
474 *ispeed = in;
475 *ospeed = out;
479 TerminalWindowSize(long *rows, long *cols)
481 struct winsize ws;
483 if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
484 *rows = ws.ws_row;
485 *cols = ws.ws_col;
486 return 1;
488 return 0;
492 NetClose(int fd)
494 return close(fd);
498 void
499 NetNonblockingIO(int fd, int onoff)
501 ioctl(fd, FIONBIO, (char *)&onoff);
504 #ifdef TN3270
505 void
506 NetSigIO(int fd, int onoff)
508 ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */
511 void
512 NetSetPgrp(int fd)
514 int myPid;
516 myPid = getpid();
517 fcntl(fd, F_SETOWN, myPid);
519 #endif /*defined(TN3270)*/
522 * Various signal handling routines.
525 /* ARGSUSED */
526 SIG_FUNC_RET
527 intr(int sig)
529 if (localchars) {
530 intp();
531 return;
533 setcommandmode();
534 longjmp(toplevel, -1);
537 /* ARGSUSED */
538 SIG_FUNC_RET
539 intr2(int sig)
541 if (localchars) {
542 #ifdef KLUDGELINEMODE
543 if (kludgelinemode)
544 sendbrk();
545 else
546 #endif
547 sendabort();
548 return;
552 /* ARGSUSED */
553 SIG_FUNC_RET
554 susp(int sig)
556 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
557 return;
558 if (localchars)
559 sendsusp();
562 /* ARGSUSED */
563 SIG_FUNC_RET
564 sendwin(int sig)
566 if (connected) {
567 sendnaws();
571 /* ARGSUSED */
572 SIG_FUNC_RET
573 ayt(int sig)
575 if (connected)
576 sendayt();
577 else
578 ayt_status();
582 void
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);
592 setconnmode(0);
594 NetNonblockingIO(net, 1);
596 #ifdef TN3270
597 if (noasynchnet == 0) { /* DBX can't handle! */
598 NetSigIO(net, 1);
599 NetSetPgrp(net);
601 #endif /* defined(TN3270) */
603 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
604 perror("SetSockOpt");
609 * Process rings -
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
617 * error occurred.
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];
625 int c;
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).
631 int returnValue = 0;
633 set[0].fd = net;
634 set[0].events = (netout ? POLLOUT : 0) | (netin ? POLLIN : 0) |
635 (netex ? POLLPRI : 0);
636 set[1].fd = tout;
637 set[1].events = ttyout ? POLLOUT : 0;
638 set[2].fd = tin;
639 set[2].events = ttyin ? POLLIN : 0;
641 if ((c = poll(set, 3, dopoll ? 0 : INFTIM)) < 0) {
642 if (c == -1) {
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) {
649 return 0;
651 #ifdef TN3270
653 * we can get EBADF if we were in transparent
654 * mode, and the transcom process died.
656 if (errno == EBADF)
657 return 0;
658 #endif /* defined(TN3270) */
659 /* I don't like this, does it ever happen? */
660 printf("sleep(5) from telnet, after poll\r\n");
661 sleep(5);
663 return 0;
667 * Any urgent data?
669 if (set[0].revents & POLLPRI) {
670 SYNCHing = 1;
671 (void) ttyflush(1); /* flush already enqueued data */
675 * Something to read from the network...
677 if (set[0].revents & POLLIN) {
678 int canread;
680 canread = ring_empty_consecutive(&netiring);
681 c = recv(net, (char *)netiring.supply, canread, 0);
682 if (c < 0 && errno == EWOULDBLOCK) {
683 c = 0;
684 } else if (c <= 0) {
685 return -1;
687 if (netdata) {
688 Dump('<', netiring.supply, c);
690 if (c)
691 ring_supplied(&netiring, c);
692 returnValue = 1;
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)
701 c = 0;
702 if (c < 0 && errno == EWOULDBLOCK) {
703 c = 0;
704 } else {
705 if (c < 0) {
706 return -1;
708 if (c == 0) {
709 /* must be an EOF... */
710 if (MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
711 *ttyiring.supply = termEofChar;
712 c = 1;
713 } else {
714 clienteof = 1;
715 shutdown(net, 1);
716 return 0;
719 if (termdata) {
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))
732 return(-1);
734 if (set[1].revents & POLLOUT) {
735 returnValue |= (ttyflush(SYNCHing|flushout) > 0);
738 return returnValue;