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