mirror of
https://git.savannah.gnu.org/git/inetutils.git
synced 2026-01-12 00:19:39 +08:00
775 lines
13 KiB
C
775 lines
13 KiB
C
/*
|
|
Copyright (C) 2002-2025 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Inetutils.
|
|
|
|
GNU Inetutils is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or (at
|
|
your option) any later version.
|
|
|
|
GNU Inetutils is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see `http://www.gnu.org/licenses/'. */
|
|
|
|
#include <config.h>
|
|
|
|
#include <telnetd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
typedef struct termios TERMDESC;
|
|
#define _term_getattr tcgetattr
|
|
#define _term_setattr(fd, tp) tcsetattr (fd, TCSANOW, tp)
|
|
|
|
TERMDESC termbuf, termbuf2;
|
|
|
|
#ifdef IOCTL_INTERFACE
|
|
|
|
void
|
|
_term_setattr (int fd, TERMDESC *tp)
|
|
{
|
|
ioctl (fd, TIOCSETN, (char *) &tp->sg);
|
|
ioctl (fd, TIOCSETC, (char *) &tp->tc);
|
|
ioctl (fd, TIOCSLTC, (char *) &tp->ltc);
|
|
ioctl (fd, TIOCLSET, &tp->lflags);
|
|
}
|
|
|
|
void
|
|
term_send_eof (void)
|
|
{
|
|
/*nothing */
|
|
}
|
|
|
|
int
|
|
term_change_eof (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
tty_linemode (void)
|
|
{
|
|
return termbuf.state & TS_EXTPROC;
|
|
}
|
|
|
|
void
|
|
tty_setlinemode (int on)
|
|
{
|
|
# ifdef TIOCEXT
|
|
set_termbuf ();
|
|
ioctl (pty, TIOCEXT, (char *) &on);
|
|
init_termbuf ();
|
|
# else/* !TIOCEXT */
|
|
# ifdef EXTPROC
|
|
if (on)
|
|
termbuf.c_lflag |= EXTPROC;
|
|
else
|
|
termbuf.c_lflag &= ~EXTPROC;
|
|
# endif
|
|
# endif/* TIOCEXT */
|
|
}
|
|
|
|
int
|
|
tty_isecho (void)
|
|
{
|
|
return termbuf.sg.sg_flags & ECHO;
|
|
}
|
|
|
|
int
|
|
tty_flowmode (void)
|
|
{
|
|
return ((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0;
|
|
}
|
|
|
|
int
|
|
tty_restartany (void)
|
|
{
|
|
# ifdef DECCTQ
|
|
return (termbuf.lflags & DECCTQ) ? 0 : 1;
|
|
# else
|
|
return -1;
|
|
# endif
|
|
}
|
|
|
|
void
|
|
tty_setecho (int on)
|
|
{
|
|
if (on)
|
|
termbuf.sg.sg_flags |= ECHO | CRMOD;
|
|
else
|
|
termbuf.sg.sg_flags &= ~(ECHO | CRMOD);
|
|
}
|
|
|
|
int
|
|
tty_israw (void)
|
|
{
|
|
return termbuf.sg.sg_flags & RAW;
|
|
}
|
|
|
|
# if defined AUTHENTICATION && defined NO_LOGIN_F && defined LOGIN_R
|
|
int
|
|
tty_setraw (int on)
|
|
{
|
|
if (on)
|
|
termbuf.sg.sg_flags |= RAW;
|
|
else
|
|
termbuf.sg.sg_flags &= ~RAW;
|
|
}
|
|
# endif
|
|
|
|
void
|
|
tty_binaryin (int on)
|
|
{
|
|
if (on)
|
|
termbuf.lflags |= LPASS8;
|
|
else
|
|
termbuf.lflags &= ~LPASS8;
|
|
}
|
|
|
|
void
|
|
tty_binaryout (int on)
|
|
{
|
|
if (on)
|
|
termbuf.lflags |= LLITOUT;
|
|
else
|
|
termbuf.lflags &= ~LLITOUT;
|
|
}
|
|
|
|
int
|
|
tty_isbinaryin (void)
|
|
{
|
|
return termbuf.lflags & LPASS8;
|
|
}
|
|
|
|
int
|
|
tty_isbinaryout (void)
|
|
{
|
|
return termbuf.lflags & LLITOUT;
|
|
}
|
|
|
|
int
|
|
tty_isediting (void)
|
|
{
|
|
return !(termbuf.sg.sg_flags & (CBREAK | RAW));
|
|
}
|
|
|
|
int
|
|
tty_istrapsig (void)
|
|
{
|
|
return !(termbuf.sg.sg_flags & RAW);
|
|
}
|
|
|
|
void
|
|
tty_setedit (int on)
|
|
{
|
|
if (on)
|
|
termbuf.sg.sg_flags &= ~CBREAK;
|
|
else
|
|
termbuf.sg.sg_flags |= CBREAK;
|
|
}
|
|
|
|
void
|
|
tty_setsig (int on)
|
|
{
|
|
}
|
|
|
|
int
|
|
tty_issofttab (void)
|
|
{
|
|
return termbuf.sg.sg_flags & XTABS;
|
|
}
|
|
|
|
void
|
|
tty_setsofttab (int on)
|
|
{
|
|
if (on)
|
|
termbuf.sg.sg_flags |= XTABS;
|
|
else
|
|
termbuf.sg.sg_flags &= ~XTABS;
|
|
}
|
|
|
|
int
|
|
tty_islitecho (void)
|
|
{
|
|
return !(termbuf.lflags & LCTLECH);
|
|
}
|
|
|
|
void
|
|
tty_setlitecho (int on)
|
|
{
|
|
if (on)
|
|
termbuf.lflags &= ~LCTLECH;
|
|
else
|
|
termbuf.lflags |= LCTLECH;
|
|
}
|
|
|
|
int
|
|
tty_iscrnl (void)
|
|
{
|
|
return termbuf.sg.sg_flags & CRMOD;
|
|
}
|
|
|
|
#else /* !IOCTL_INTERFACE */
|
|
|
|
# define termdesc_eofc c_cc[VEOF]
|
|
# define termdesc_erase c_cc[VERASE]
|
|
# define termdesc_kill c_cc[VKILL]
|
|
# define termdesc_ip c_cc[VINTR]
|
|
# define termdesc_abort c_cc[VQUIT]
|
|
# ifdef VSTART
|
|
# define termdesc_xon c_cc[VSTART]
|
|
# endif
|
|
# ifdef VSTOP
|
|
# define termdesc_xoff c_cc[VSTOP]
|
|
# endif
|
|
|
|
# if !defined VDISCARD && defined VFLUSHO
|
|
# define VDISCARD VFLUSHO
|
|
# endif
|
|
# ifdef VDISCARD
|
|
# define termdesc_ao c_cc[VDISCARD]
|
|
# endif
|
|
|
|
# ifdef VSUSP
|
|
# define termdesc_susp c_cc[VSUSP]
|
|
# endif
|
|
# ifdef VWERASE
|
|
# define termdesc_ew c_cc[VWERASE]
|
|
# endif
|
|
# ifdef VREPRINT
|
|
# define termdesc_rp c_cc[VREPRINT]
|
|
# endif
|
|
# ifdef VLNEXT
|
|
# define termdesc_lnext c_cc[VLNEXT]
|
|
# endif
|
|
# ifdef VEOL
|
|
# define termdesc_forw1 c_cc[VEOL]
|
|
# endif
|
|
# ifdef VEOL2
|
|
# define termdesc_forw2 c_cc[VEOL2]
|
|
# endif
|
|
# ifdef VSTATUS
|
|
# define termdesc_status c_cc[VSTATUS]
|
|
# endif
|
|
|
|
# if VEOF == VMIN
|
|
static cc_t oldeofc = '\004';
|
|
# endif
|
|
|
|
void
|
|
term_send_eof (void)
|
|
{
|
|
# if VEOF == VMIN
|
|
if (!tty_isediting ())
|
|
pty_output_byte (oldeofc);
|
|
# endif
|
|
}
|
|
|
|
int
|
|
term_change_eof (void)
|
|
{
|
|
# if VEOF == VMIN
|
|
if (!tty_isediting ())
|
|
return 1;
|
|
if (slctab[SLC_EOF].sptr)
|
|
oldeofc = *slctab[SLC_EOF].sptr;
|
|
# endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
tty_linemode (void)
|
|
{
|
|
# ifdef EXTPROC
|
|
return (termbuf.c_lflag & EXTPROC);
|
|
# else
|
|
return 0; /* Can't ever set it either. */
|
|
# endif/* EXTPROC */
|
|
}
|
|
|
|
void
|
|
tty_setlinemode (int on)
|
|
{
|
|
# ifdef TIOCEXT
|
|
set_termbuf ();
|
|
ioctl (pty, TIOCEXT, (char *) &on);
|
|
init_termbuf ();
|
|
# else/* !TIOCEXT */
|
|
# ifdef EXTPROC
|
|
if (on)
|
|
termbuf.c_lflag |= EXTPROC;
|
|
else
|
|
termbuf.c_lflag &= ~EXTPROC;
|
|
# else
|
|
/* !EXTPROC */
|
|
(void) on; /* Silence warnings. */
|
|
# endif
|
|
# endif/* TIOCEXT */
|
|
}
|
|
|
|
int
|
|
tty_isecho (void)
|
|
{
|
|
return termbuf.c_lflag & ECHO;
|
|
}
|
|
|
|
int
|
|
tty_flowmode (void)
|
|
{
|
|
return (termbuf.c_iflag & IXON) ? 1 : 0;
|
|
}
|
|
|
|
int
|
|
tty_restartany (void)
|
|
{
|
|
return (termbuf.c_iflag & IXANY) ? 1 : 0;
|
|
}
|
|
|
|
void
|
|
tty_setecho (int on)
|
|
{
|
|
if (on)
|
|
termbuf.c_lflag |= ECHO;
|
|
else
|
|
termbuf.c_lflag &= ~ECHO;
|
|
}
|
|
|
|
int
|
|
tty_israw (void)
|
|
{
|
|
return !(termbuf.c_lflag & ICANON);
|
|
}
|
|
|
|
# if defined AUTHENTICATION && defined NO_LOGIN_F && defined LOGIN_R
|
|
int
|
|
tty_setraw (int on)
|
|
{
|
|
if (on)
|
|
termbuf.c_lflag &= ~ICANON;
|
|
else
|
|
termbuf.c_lflag |= ICANON;
|
|
}
|
|
# endif
|
|
|
|
void
|
|
tty_binaryin (int on)
|
|
{
|
|
if (on)
|
|
termbuf.c_iflag &= ~ISTRIP;
|
|
else
|
|
termbuf.c_iflag |= ISTRIP;
|
|
}
|
|
|
|
void
|
|
tty_binaryout (int on)
|
|
{
|
|
if (on)
|
|
{
|
|
termbuf.c_cflag &= ~(CSIZE | PARENB);
|
|
termbuf.c_cflag |= CS8;
|
|
termbuf.c_oflag &= ~OPOST;
|
|
}
|
|
else
|
|
{
|
|
termbuf.c_cflag &= ~CSIZE;
|
|
termbuf.c_cflag |= CS7 | PARENB;
|
|
termbuf.c_oflag |= OPOST;
|
|
}
|
|
}
|
|
|
|
int
|
|
tty_isbinaryin (void)
|
|
{
|
|
return !(termbuf.c_iflag & ISTRIP);
|
|
}
|
|
|
|
int
|
|
tty_isbinaryout (void)
|
|
{
|
|
return !(termbuf.c_oflag & OPOST);
|
|
}
|
|
|
|
int
|
|
tty_isediting (void)
|
|
{
|
|
return termbuf.c_lflag & ICANON;
|
|
}
|
|
|
|
int
|
|
tty_istrapsig (void)
|
|
{
|
|
return termbuf.c_lflag & ISIG;
|
|
}
|
|
|
|
void
|
|
tty_setedit (int on)
|
|
{
|
|
if (on)
|
|
termbuf.c_lflag |= ICANON;
|
|
else
|
|
termbuf.c_lflag &= ~ICANON;
|
|
}
|
|
|
|
void
|
|
tty_setsig (int on)
|
|
{
|
|
if (on)
|
|
termbuf.c_lflag |= ISIG;
|
|
else
|
|
termbuf.c_lflag &= ~ISIG;
|
|
}
|
|
|
|
int
|
|
tty_issofttab (void)
|
|
{
|
|
# ifdef OXTABS
|
|
return termbuf.c_oflag & OXTABS;
|
|
# endif
|
|
# ifdef TABDLY
|
|
return (termbuf.c_oflag & TABDLY) == TAB3;
|
|
# endif
|
|
}
|
|
|
|
void
|
|
tty_setsofttab (int on)
|
|
{
|
|
if (on)
|
|
{
|
|
# ifdef OXTABS
|
|
termbuf.c_oflag |= OXTABS;
|
|
# endif
|
|
# ifdef TABDLY
|
|
termbuf.c_oflag &= ~TABDLY;
|
|
termbuf.c_oflag |= TAB3;
|
|
# endif
|
|
}
|
|
else
|
|
{
|
|
# ifdef OXTABS
|
|
termbuf.c_oflag &= ~OXTABS;
|
|
# endif
|
|
# ifdef TABDLY
|
|
termbuf.c_oflag &= ~TABDLY;
|
|
termbuf.c_oflag |= TAB0;
|
|
# endif
|
|
}
|
|
}
|
|
|
|
int
|
|
tty_islitecho (void)
|
|
{
|
|
# ifdef ECHOCTL
|
|
return !(termbuf.c_lflag & ECHOCTL);
|
|
# endif
|
|
# ifdef TCTLECH
|
|
return !(termbuf.c_lflag & TCTLECH);
|
|
# endif
|
|
# if !defined ECHOCTL && !defined TCTLECH
|
|
return 0; /* assumes ctl chars are echoed '^x' */
|
|
# endif
|
|
}
|
|
|
|
void
|
|
tty_setlitecho (int on)
|
|
{
|
|
# ifdef ECHOCTL
|
|
if (on)
|
|
termbuf.c_lflag &= ~ECHOCTL;
|
|
else
|
|
termbuf.c_lflag |= ECHOCTL;
|
|
# endif
|
|
# ifdef TCTLECH
|
|
if (on)
|
|
termbuf.c_lflag &= ~TCTLECH;
|
|
else
|
|
termbuf.c_lflag |= TCTLECH;
|
|
# endif
|
|
}
|
|
|
|
int
|
|
tty_iscrnl (void)
|
|
{
|
|
return termbuf.c_iflag & ICRNL;
|
|
}
|
|
|
|
#endif /* !IOCTL_INTERFACE */
|
|
|
|
void
|
|
init_termbuf (void)
|
|
{
|
|
#if !defined SOLARIS10 && !defined SOLARIS
|
|
_term_getattr (pty, &termbuf);
|
|
#else /* SOLARIS || SOLARIS10 */
|
|
/* On Solaris the master PTY is not able to report terminal
|
|
* settings about the slave TTY, since it is only the slave
|
|
* that is working with an designated line discipline.
|
|
* Therefore we must determine the slave descriptor, which
|
|
* exists only if ptsname() returns a non-empty string.
|
|
* This happens for the parent process. The child process
|
|
* sees an empty name, so undergoes minimal processing.
|
|
*/
|
|
int tty = pty;
|
|
char *name = ptsname (pty);
|
|
|
|
if (name)
|
|
/* Minimal access means read only! */
|
|
tty = open (name, O_RDONLY | O_NONBLOCK);
|
|
|
|
_term_getattr (tty, &termbuf);
|
|
|
|
if (name)
|
|
close (tty);
|
|
#endif /* SOLARIS || SOLARIS10 */
|
|
|
|
termbuf2 = termbuf;
|
|
}
|
|
|
|
#if defined TIOCPKT_IOCTL
|
|
/*FIXME: Hardly needed?
|
|
* Built by OpenSolaris and BSD, though. */
|
|
void
|
|
copy_termbuf (void)
|
|
{
|
|
size_t len = 0;
|
|
char *cp = (char *) &termbuf;
|
|
|
|
while (pty_input_level () > 0)
|
|
{
|
|
if (len >= sizeof (termbuf))
|
|
break;
|
|
*cp++ = pty_get_char (0);
|
|
len++;
|
|
}
|
|
termbuf2 = termbuf;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
set_termbuf (void)
|
|
{
|
|
if (memcmp (&termbuf, &termbuf2, sizeof (termbuf)))
|
|
#if !defined SOLARIS10 && !defined SOLARIS
|
|
_term_setattr (pty, &termbuf);
|
|
#else /* SOLARIS || SOLARIS10 */
|
|
{
|
|
/* Same reason as with _term_getattr. */
|
|
int tty = pty;
|
|
char *name = ptsname (pty);
|
|
|
|
if (name)
|
|
tty = open (name, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
|
|
|
_term_setattr (tty, &termbuf);
|
|
|
|
if (name)
|
|
close (tty);
|
|
}
|
|
#endif /* SOLARIS || SOLARIS10 */
|
|
}
|
|
|
|
/* spcset(func, valp, valpp)
|
|
|
|
This function takes various special characters (func), and
|
|
sets *valp to the current value of that character, and
|
|
*valpp to point to where in the "termbuf" structure that
|
|
value is kept.
|
|
|
|
It returns the SLC_ level of support for this function. */
|
|
|
|
#define setval(a, b) *valp = termbuf.a ; \
|
|
*valpp = &termbuf.a ; \
|
|
return b;
|
|
#define defval(a) *valp = ((cc_t)a); \
|
|
*valpp = (cc_t *)0; \
|
|
return SLC_DEFAULT;
|
|
|
|
int
|
|
spcset (int func, cc_t *valp, cc_t **valpp)
|
|
{
|
|
switch (func)
|
|
{
|
|
case SLC_EOF:
|
|
setval (termdesc_eofc, SLC_VARIABLE);
|
|
|
|
case SLC_EC:
|
|
setval (termdesc_erase, SLC_VARIABLE);
|
|
|
|
case SLC_EL:
|
|
setval (termdesc_kill, SLC_VARIABLE);
|
|
|
|
case SLC_IP:
|
|
setval (termdesc_ip, SLC_VARIABLE | SLC_FLUSHIN | SLC_FLUSHOUT);
|
|
|
|
case SLC_ABORT:
|
|
setval (termdesc_abort, SLC_VARIABLE | SLC_FLUSHIN | SLC_FLUSHOUT);
|
|
|
|
case SLC_XON:
|
|
#ifdef termdesc_xon
|
|
setval (termdesc_xon, SLC_VARIABLE);
|
|
#else
|
|
defval (0x13);
|
|
#endif
|
|
|
|
case SLC_XOFF:
|
|
#ifdef termdesc_xoff
|
|
setval (termdesc_xoff, SLC_VARIABLE);
|
|
#else
|
|
defval (0x11);
|
|
#endif
|
|
|
|
case SLC_EW:
|
|
#ifdef termdesc_ew
|
|
setval (termdesc_ew, SLC_VARIABLE);
|
|
#else
|
|
defval (0);
|
|
#endif
|
|
|
|
case SLC_RP:
|
|
#ifdef termdesc_rp
|
|
setval (termdesc_rp, SLC_VARIABLE);
|
|
#else
|
|
defval (0);
|
|
#endif
|
|
|
|
case SLC_LNEXT:
|
|
#ifdef termdesc_lnext
|
|
setval (termdesc_lnext, SLC_VARIABLE);
|
|
#else
|
|
defval (0);
|
|
#endif
|
|
|
|
case SLC_AO:
|
|
#ifdef termdesc_ao
|
|
setval (termdesc_ao, SLC_VARIABLE | SLC_FLUSHOUT);
|
|
#else
|
|
defval (0);
|
|
#endif
|
|
|
|
case SLC_SUSP:
|
|
#ifdef termdesc_susp
|
|
setval (termdesc_susp, SLC_VARIABLE | SLC_FLUSHIN);
|
|
#else
|
|
defval (0);
|
|
#endif
|
|
|
|
#ifdef termdesc_forw1
|
|
case SLC_FORW1:
|
|
setval (termdesc_forw1, SLC_VARIABLE);
|
|
#endif
|
|
|
|
#ifdef termdesc_forw2
|
|
case SLC_FORW2:
|
|
setval (termdesc_forw2, SLC_VARIABLE);
|
|
#endif
|
|
|
|
case SLC_AYT:
|
|
#ifdef termdesc_status
|
|
setval (termdesc_status, SLC_VARIABLE);
|
|
#else
|
|
defval (0);
|
|
#endif
|
|
|
|
case SLC_BRK:
|
|
case SLC_SYNCH:
|
|
case SLC_EOR:
|
|
defval (0);
|
|
|
|
default:
|
|
*valp = 0;
|
|
*valpp = 0;
|
|
return SLC_NOSUPPORT;
|
|
}
|
|
}
|
|
|
|
#if B4800 != 4800
|
|
# define DECODE_BAUD
|
|
#endif
|
|
|
|
#ifdef DECODE_BAUD
|
|
|
|
/*
|
|
* A table of available terminal speeds
|
|
*/
|
|
struct termspeeds
|
|
{
|
|
int speed;
|
|
int value;
|
|
} termspeeds[] = {
|
|
{0, B0},
|
|
{50, B50},
|
|
{75, B75},
|
|
{110, B110},
|
|
{134, B134},
|
|
{150, B150},
|
|
{200, B200},
|
|
{300, B300},
|
|
{600, B600},
|
|
{1200, B1200},
|
|
{1800, B1800},
|
|
{2400, B2400},
|
|
{4800, B4800},
|
|
# ifdef B7200
|
|
{7200, B7200},
|
|
# endif
|
|
{9600, B9600},
|
|
# ifdef B14400
|
|
{14400, B14400},
|
|
# endif
|
|
# ifdef B19200
|
|
{19200, B19200},
|
|
# endif
|
|
# ifdef B28800
|
|
{28800, B28800},
|
|
# endif
|
|
# ifdef B38400
|
|
{38400, B38400},
|
|
# endif
|
|
# ifdef B57600
|
|
{57600, B57600},
|
|
# endif
|
|
# ifdef B115200
|
|
{115200, B115200},
|
|
# endif
|
|
# ifdef B230400
|
|
{230400, B230400},
|
|
# endif
|
|
{-1, 0}
|
|
};
|
|
#endif /* DECODE_BAUD */
|
|
|
|
void
|
|
tty_tspeed (int val)
|
|
{
|
|
#ifdef DECODE_BAUD
|
|
struct termspeeds *tp;
|
|
|
|
for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
|
|
;
|
|
if (tp->speed == -1) /* back up to last valid value */
|
|
--tp;
|
|
val = tp->value;
|
|
#endif
|
|
cfsetospeed (&termbuf, val);
|
|
}
|
|
|
|
void
|
|
tty_rspeed (int val)
|
|
{
|
|
#ifdef DECODE_BAUD
|
|
struct termspeeds *tp;
|
|
|
|
for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
|
|
;
|
|
if (tp->speed == -1) /* back up to last valid value */
|
|
--tp;
|
|
val = tp->value;
|
|
#endif
|
|
cfsetispeed (&termbuf, val);
|
|
}
|