#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#ifndef sgi
# include <sys/file.h>
#endif
#if !defined(sun) || defined(SUNOS3)
# include <sys/ioctl.h>
#else
# ifndef TIOCEXCL
# include <sys/ttold.h>
# endif
#endif
#ifdef __hpux
# include <sys/modem.h>
#endif
#ifdef ISC
# include <sys/tty.h>
# include <sys/sioctl.h>
# include <sys/pty.h>
#endif
#include "config.h"
#ifdef SVR4
#include <sys/stropts.h>
#endif
#include "screen.h"
#include "extern.h"
#if !defined(TIOCCONS) && defined(sun) && defined(SVR4)
# include <sys/strredir.h>
#endif
extern struct display *display, *displays;
extern int iflag;
#if (!defined(TIOCCONS) && defined(SRIOCSREDIR)) || defined(linux)
extern struct win *console_window;
static void consredir_readev_fn __P((struct event *, char *));
#endif
int separate_sids = 1;
static void DoSendBreak __P((int, int, int));
static sigret_t SigAlrmDummy __P(SIGPROTOARG);
#if !defined(VSTART) && defined(_VSTART)
#define VSTART _VSTART
#endif
#if !defined(VSTOP) && defined(_VSTOP)
#define VSTOP _VSTOP
#endif
#ifndef O_NOCTTY
# define O_NOCTTY 0
#endif
#ifndef TTYVMIN
# define TTYVMIN 1
#endif
#ifndef TTYVTIME
#define TTYVTIME 0
#endif
static sigret_t
SigAlrmDummy SIGDEFARG
{
debug("SigAlrmDummy()\n");
SIGRETURN;
}
int
OpenTTY(line, opt)
char *line, *opt;
{
int f;
struct mode Mode;
sigret_t (*sigalrm)__P(SIGPROTOARG);
sigalrm = signal(SIGALRM, SigAlrmDummy);
alarm(2);
if ((f = secopen(line, O_RDWR | O_NONBLOCK | O_NOCTTY, 0)) == -1)
{
if (errno == EINTR)
Msg(0, "Cannot open line '%s' for R/W: open() blocked, aborted.", line);
else
Msg(errno, "Cannot open line '%s' for R/W", line);
alarm(0);
signal(SIGALRM, sigalrm);
return -1;
}
if (!isatty(f))
{
Msg(0, "'%s' is not a tty", line);
alarm(0);
signal(SIGALRM, sigalrm);
close(f);
return -1;
}
#if defined(I_POP) && defined(POP_TTYMODULES)
debug("OpenTTY I_POP\n");
while (ioctl(f, I_POP, (char *)0) >= 0)
;
#endif
#ifdef TIOCEXCL
errno = 0;
if (ioctl(f, TIOCEXCL, (char *) 0) < 0)
Msg(errno, "%s: ioctl TIOCEXCL failed", line);
debug3("%d %d %d\n", getuid(), geteuid(), getpid());
debug2("%s TIOCEXCL errno %d\n", line, errno);
#endif
#if WE_REALLY_WANT_TO_COPY_THE_TTY_MODE
if (display)
{
debug1("OpenTTY: using mode of display for %s\n", line);
Mode = D_NewMode;
}
else
#endif
InitTTY(&Mode, W_TYPE_PLAIN);
SttyMode(&Mode, opt);
#ifdef DEBUG
DebugTTY(&Mode);
#endif
SetTTY(f, &Mode);
#if defined(linux) && defined(TIOCMSET)
{
int mcs = 0;
ioctl(f, TIOCMGET, &mcs);
mcs |= TIOCM_RTS;
ioctl(f, TIOCMSET, &mcs);
}
#endif
brktty(f);
alarm(0);
signal(SIGALRM, sigalrm);
debug2("'%s' CONNECT fd=%d.\n", line, f);
return f;
}
void
InitTTY(m, ttyflag)
struct mode *m;
int ttyflag;
{
bzero((char *)m, sizeof(*m));
#ifdef POSIX
debug1("InitTTY: POSIX: termios defaults based on SunOS 4.1.3, but better (%d)\n", ttyflag);
#if defined(BRKINT)
m->tio.c_iflag |= BRKINT;
#endif
#if defined(IGNPAR)
m->tio.c_iflag |= IGNPAR;
#endif
#if defined(IXON)
m->tio.c_iflag |= IXON;
#endif
if (!ttyflag)
{
#if defined(ICRNL)
m->tio.c_iflag |= ICRNL;
#endif
#if defined(ONLCR)
m->tio.c_oflag |= ONLCR;
#endif
#if defined(TAB3)
m->tio.c_oflag |= TAB3;
#endif
#if defined(OXTABS)
m->tio.c_oflag |= OXTABS;
#endif
#if defined(OPOST)
m->tio.c_oflag |= OPOST;
#endif
}
#if defined(B9600)
cfsetospeed(&m->tio, B9600);
#endif
#if defined(B9600)
cfsetispeed(&m->tio, B9600);
#endif
#if defined(CS8)
m->tio.c_cflag |= CS8;
#endif
#if defined(CREAD)
m->tio.c_cflag |= CREAD;
#endif
#if defined(CLOCAL)
m->tio.c_cflag |= CLOCAL;
#endif
#if defined(ECHOCTL)
m->tio.c_lflag |= ECHOCTL;
#endif
#if defined(ECHOKE)
m->tio.c_lflag |= ECHOKE;
#endif
if (!ttyflag)
{
#if defined(ISIG)
m->tio.c_lflag |= ISIG;
#endif
#if defined(ICANON)
m->tio.c_lflag |= ICANON;
#endif
#if defined(ECHO)
m->tio.c_lflag |= ECHO;
#endif
}
#if defined(ECHOE)
m->tio.c_lflag |= ECHOE;
#endif
#if defined(ECHOK)
m->tio.c_lflag |= ECHOK;
#endif
#if defined(IEXTEN)
m->tio.c_lflag |= IEXTEN;
#endif
#if defined(VINTR)
#if (VINTR < MAXCC)
m->tio.c_cc[VINTR] = Ctrl('C');
#endif
#endif
#if defined(VQUIT)
#if (VQUIT < MAXCC)
m->tio.c_cc[VQUIT] = Ctrl('\\');
#endif
#endif
#if defined(VERASE)
#if (VERASE < MAXCC)
m->tio.c_cc[VERASE] = 0x7f;
#endif
#endif
#if defined(VKILL)
#if (VKILL < MAXCC)
m->tio.c_cc[VKILL] = Ctrl('H');
#endif
#endif
#if defined(VEOF)
#if (VEOF < MAXCC)
m->tio.c_cc[VEOF] = Ctrl('D');
#endif
#endif
#if defined(VEOL)
#if (VEOL < MAXCC)
m->tio.c_cc[VEOL] = 0000;
#endif
#endif
#if defined(VEOL2)
#if (VEOL2 < MAXCC)
m->tio.c_cc[VEOL2] = 0000;
#endif
#endif
#if defined(VSWTCH)
#if (VSWTCH < MAXCC)
m->tio.c_cc[VSWTCH] = 0000;
#endif
#endif
#if defined(VSTART)
#if (VSTART < MAXCC)
m->tio.c_cc[VSTART] = Ctrl('Q');
#endif
#endif
#if defined(VSTOP)
#if (VSTOP < MAXCC)
m->tio.c_cc[VSTOP] = Ctrl('S');
#endif
#endif
#if defined(VSUSP)
#if (VSUSP < MAXCC)
m->tio.c_cc[VSUSP] = Ctrl('Z');
#endif
#endif
#if defined(VDSUSP)
#if (VDSUSP < MAXCC)
m->tio.c_cc[VDSUSP] = Ctrl('Y');
#endif
#endif
#if defined(VREPRINT)
#if (VREPRINT < MAXCC)
m->tio.c_cc[VREPRINT] = Ctrl('R');
#endif
#endif
#if defined(VDISCARD)
#if (VDISCARD < MAXCC)
m->tio.c_cc[VDISCARD] = Ctrl('O');
#endif
#endif
#if defined(VWERASE)
#if (VWERASE < MAXCC)
m->tio.c_cc[VWERASE] = Ctrl('W');
#endif
#endif
#if defined(VLNEXT)
#if (VLNEXT < MAXCC)
m->tio.c_cc[VLNEXT] = Ctrl('V');
#endif
#endif
#if defined(VSTATUS)
#if (VSTATUS < MAXCC)
m->tio.c_cc[VSTATUS] = Ctrl('T');
#endif
#endif
if (ttyflag)
{
m->tio.c_cc[VMIN] = TTYVMIN;
m->tio.c_cc[VTIME] = TTYVTIME;
}
# ifdef HPUX_LTCHARS_HACK
m->m_ltchars.t_suspc = Ctrl('Z');
m->m_ltchars.t_dsuspc = Ctrl('Y');
m->m_ltchars.t_rprntc = Ctrl('R');
m->m_ltchars.t_flushc = Ctrl('O');
m->m_ltchars.t_werasc = Ctrl('W');
m->m_ltchars.t_lnextc = Ctrl('V');
# endif
#else
# ifdef TERMIO
debug1("InitTTY: nonPOSIX, struct termio a la Motorola SYSV68 (%d)\n", ttyflag);
#if defined(ISTRIP)
m->tio.c_iflag |= ISTRIP;
#endif
#if defined(IXON)
m->tio.c_iflag |= IXON;
#endif
if (!ttyflag)
{
#if defined(OPOST)
m->tio.c_oflag |= OPOST;
#endif
#if defined(ICRNL)
m->tio.c_iflag |= ICRNL;
#endif
#if defined(ONLCR)
m->tio.c_oflag |= ONLCR;
#endif
#if defined(TAB3)
m->tio.c_oflag |= TAB3;
#endif
}
#ifdef __bsdi__
)-: cannot handle BSDI without POSIX
#else
#if defined(B9600)
m->tio.c_cflag = B9600;
#endif
#endif
#if defined(CS8)
m->tio.c_cflag |= CS8;
#endif
#if defined(CREAD)
m->tio.c_cflag |= CREAD;
#endif
if (!ttyflag)
{
#if defined(ISIG)
m->tio.c_lflag |= ISIG;
#endif
#if defined(ICANON)
m->tio.c_lflag |= ICANON;
#endif
#if defined(ECHO)
m->tio.c_lflag |= ECHO;
#endif
}
#if defined(ECHOE)
m->tio.c_lflag |= ECHOE;
#endif
#if defined(ECHOK)
m->tio.c_lflag |= ECHOK;
#endif
#if defined(VINTR)
#if (VINTR < MAXCC)
m->tio.c_cc[VINTR] = Ctrl('C');
#endif
#endif
#if defined(VQUIT)
#if (VQUIT < MAXCC)
m->tio.c_cc[VQUIT] = Ctrl('\\');
#endif
#endif
#if defined(VERASE)
#if (VERASE < MAXCC)
m->tio.c_cc[VERASE] = 0177;
#endif
#endif
#if defined(VKILL)
#if (VKILL < MAXCC)
m->tio.c_cc[VKILL] = Ctrl('H');
#endif
#endif
#if defined(VEOF)
#if (VEOF < MAXCC)
m->tio.c_cc[VEOF] = Ctrl('D');
#endif
#endif
#if defined(VEOL)
#if (VEOL < MAXCC)
m->tio.c_cc[VEOL] = 0377;
#endif
#endif
#if defined(VEOL2)
#if (VEOL2 < MAXCC)
m->tio.c_cc[VEOL2] = 0377;
#endif
#endif
#if defined(VSWTCH)
#if (VSWTCH < MAXCC)
m->tio.c_cc[VSWTCH] = 0000;
#endif
#endif
if (ttyflag)
{
m->tio.c_cc[VMIN] = TTYVMIN;
m->tio.c_cc[VTIME] = TTYVTIME;
}
# else
debug1("InitTTY: BSD: defaults a la SunOS 4.1.3 (%d)\n", ttyflag);
m->m_ttyb.sg_ispeed = B9600;
m->m_ttyb.sg_ospeed = B9600;
m->m_ttyb.sg_erase = 0177;
m->m_ttyb.sg_kill = Ctrl('H');
if (!ttyflag)
m->m_ttyb.sg_flags = CRMOD | ECHO
#if defined(ANYP)
| ANYP
#endif
;
else
m->m_ttyb.sg_flags = CBREAK
#if defined(ANYP)
| ANYP
#endif
;
m->m_tchars.t_intrc = Ctrl('C');
m->m_tchars.t_quitc = Ctrl('\\');
m->m_tchars.t_startc = Ctrl('Q');
m->m_tchars.t_stopc = Ctrl('S');
m->m_tchars.t_eofc = Ctrl('D');
m->m_tchars.t_brkc = -1;
m->m_ltchars.t_suspc = Ctrl('Z');
m->m_ltchars.t_dsuspc = Ctrl('Y');
m->m_ltchars.t_rprntc = Ctrl('R');
m->m_ltchars.t_flushc = Ctrl('O');
m->m_ltchars.t_werasc = Ctrl('W');
m->m_ltchars.t_lnextc = Ctrl('V');
#if defined(NTTYDISC)
m->m_ldisc = NTTYDISC;
#endif
m->m_lmode = 0
#if defined(LDECCTQ)
| LDECCTQ
#endif
#if defined(LCTLECH)
| LCTLECH
#endif
#if defined(LPASS8)
| LPASS8
#endif
#if defined(LCRTKIL)
| LCRTKIL
#endif
#if defined(LCRTERA)
| LCRTERA
#endif
#if defined(LCRTBS)
| LCRTBS
#endif
;
# endif
#endif
#if defined(ENCODINGS) && defined(TIOCKSET)
m->m_jtchars.t_ascii = 'J';
m->m_jtchars.t_kanji = 'B';
m->m_knjmode = KM_ASCII | KM_SYSSJIS;
#endif
}
void
SetTTY(fd, mp)
int fd;
struct mode *mp;
{
errno = 0;
#ifdef POSIX
tcsetattr(fd, TCSADRAIN, &mp->tio);
# ifdef HPUX_LTCHARS_HACK
ioctl(fd, TIOCSLTC, (char *)&mp->m_ltchars);
# endif
#else
# ifdef TERMIO
ioctl(fd, TCSETAW, (char *)&mp->tio);
# ifdef CYTERMIO
if (mp->tio.c_line == 3)
{
ioctl(fd, LDSETMAPKEY, (char *)&mp->m_mapkey);
ioctl(fd, LDSETMAPSCREEN, (char *)&mp->m_mapscreen);
ioctl(fd, LDSETBACKSPACE, (char *)&mp->m_backspace);
}
# endif
# else
ioctl(fd, TIOCSETC, (char *)&mp->m_tchars);
ioctl(fd, TIOCLSET, (char *)&mp->m_lmode);
ioctl(fd, TIOCSETD, (char *)&mp->m_ldisc);
ioctl(fd, TIOCSETP, (char *)&mp->m_ttyb);
ioctl(fd, TIOCSLTC, (char *)&mp->m_ltchars);
# endif
#endif
#if defined(ENCODINGS) && defined(TIOCKSET)
ioctl(fd, TIOCKSETC, &mp->m_jtchars);
ioctl(fd, TIOCKSET, &mp->m_knjmode);
#endif
if (errno)
Msg(errno, "SetTTY (fd %d): ioctl failed", fd);
}
void
GetTTY(fd, mp)
int fd;
struct mode *mp;
{
errno = 0;
#ifdef POSIX
tcgetattr(fd, &mp->tio);
# ifdef HPUX_LTCHARS_HACK
ioctl(fd, TIOCGLTC, (char *)&mp->m_ltchars);
# endif
#else
# ifdef TERMIO
ioctl(fd, TCGETA, (char *)&mp->tio);
# ifdef CYTERMIO
if (mp->tio.c_line == 3)
{
ioctl(fd, LDGETMAPKEY, (char *)&mp->m_mapkey);
ioctl(fd, LDGETMAPSCREEN, (char *)&mp->m_mapscreen);
ioctl(fd, LDGETBACKSPACE, (char *)&mp->m_backspace);
}
else
{
mp->m_mapkey = NOMAPKEY;
mp->m_mapscreen = NOMAPSCREEN;
mp->m_backspace = '\b';
}
# endif
# else
ioctl(fd, TIOCGETP, (char *)&mp->m_ttyb);
ioctl(fd, TIOCGETC, (char *)&mp->m_tchars);
ioctl(fd, TIOCGLTC, (char *)&mp->m_ltchars);
ioctl(fd, TIOCLGET, (char *)&mp->m_lmode);
ioctl(fd, TIOCGETD, (char *)&mp->m_ldisc);
# endif
#endif
#if defined(ENCODINGS) && defined(TIOCKSET)
ioctl(fd, TIOCKGETC, &mp->m_jtchars);
ioctl(fd, TIOCKGET, &mp->m_knjmode);
#endif
if (errno)
Msg(errno, "GetTTY (fd %d): ioctl failed", fd);
}
void
SetMode(op, np, flow, interrupt)
struct mode *op, *np;
int flow, interrupt;
{
*np = *op;
ASSERT(display);
#if defined(TERMIO) || defined(POSIX)
# ifdef CYTERMIO
np->m_mapkey = NOMAPKEY;
np->m_mapscreen = NOMAPSCREEN;
np->tio.c_line = 0;
# endif
#if defined(ICRNL)
np->tio.c_iflag &= ~ICRNL;
#endif
#if defined(ISTRIP)
np->tio.c_iflag &= ~ISTRIP;
#endif
#if defined(ONLCR)
np->tio.c_oflag &= ~ONLCR;
#endif
np->tio.c_lflag &= ~(ICANON | ECHO);
#if defined(IEXTEN)
np->tio.c_lflag &= ~IEXTEN;
#endif
if (interrupt)
np->tio.c_lflag |= ISIG;
else
np->tio.c_lflag &= ~ISIG;
np->tio.c_cc[VMIN] = 1;
np->tio.c_cc[VTIME] = 0;
if (!interrupt || !flow)
np->tio.c_cc[VINTR] = VDISABLE;
np->tio.c_cc[VQUIT] = VDISABLE;
if (flow == 0)
{
#if defined(VSTART)
#if (VSTART < MAXCC)
np->tio.c_cc[VSTART] = VDISABLE;
#endif
#endif
#if defined(VSTOP)
#if (VSTOP < MAXCC)
np->tio.c_cc[VSTOP] = VDISABLE;
#endif
#endif
np->tio.c_iflag &= ~IXON;
}
#if defined(VDISCARD)
#if (VDISCARD < MAXCC)
np->tio.c_cc[VDISCARD] = VDISABLE;
#endif
#endif
#if defined(VLNEXT)
#if (VLNEXT < MAXCC)
np->tio.c_cc[VLNEXT] = VDISABLE;
#endif
#endif
#if defined(VSTATUS)
#if (VSTATUS < MAXCC)
np->tio.c_cc[VSTATUS] = VDISABLE;
#endif
#endif
#if defined(VSUSP)
#if (VSUSP < MAXCC)
np->tio.c_cc[VSUSP] = VDISABLE;
#endif
#endif
#if defined(VERASE)
#if (VERASE < MAXCC)
np->tio.c_cc[VERASE] = VDISABLE;
#endif
#endif
#if defined(VKILL)
#if (VKILL < MAXCC)
np->tio.c_cc[VKILL] = VDISABLE;
#endif
#endif
# ifdef HPUX_LTCHARS_HACK
np->m_ltchars.t_suspc = VDISABLE;
np->m_ltchars.t_dsuspc = VDISABLE;
np->m_ltchars.t_rprntc = VDISABLE;
np->m_ltchars.t_flushc = VDISABLE;
np->m_ltchars.t_werasc = VDISABLE;
np->m_ltchars.t_lnextc = VDISABLE;
# else
#if defined(VDSUSP)
#if (VDSUSP < MAXCC)
np->tio.c_cc[VDSUSP] = VDISABLE;
#endif
#endif
#if defined(VREPRINT)
#if (VREPRINT < MAXCC)
np->tio.c_cc[VREPRINT] = VDISABLE;
#endif
#endif
#if defined(VWERASE)
#if (VWERASE < MAXCC)
np->tio.c_cc[VWERASE] = VDISABLE;
#endif
#endif
# endif
#else
if (!interrupt || !flow)
np->m_tchars.t_intrc = -1;
np->m_ttyb.sg_flags &= ~(CRMOD | ECHO);
np->m_ttyb.sg_flags |= CBREAK;
# if defined(CYRILL) && defined(CSTYLE) && defined(CS_8BITS)
np->m_ttyb.sg_flags &= ~CSTYLE;
np->m_ttyb.sg_flags |= CS_8BITS;
# endif
np->m_tchars.t_quitc = -1;
if (flow == 0)
{
np->m_tchars.t_startc = -1;
np->m_tchars.t_stopc = -1;
}
np->m_ltchars.t_suspc = -1;
np->m_ltchars.t_dsuspc = -1;
np->m_ltchars.t_flushc = -1;
np->m_ltchars.t_lnextc = -1;
#endif
}
void
SetFlow(on)
int on;
{
ASSERT(display);
if (D_flow == on)
return;
#if defined(TERMIO) || defined(POSIX)
if (on)
{
D_NewMode.tio.c_cc[VINTR] = iflag ? D_OldMode.tio.c_cc[VINTR] : VDISABLE;
#if defined(VSTART)
#if (VSTART < MAXCC)
D_NewMode.tio.c_cc[VSTART] = D_OldMode.tio.c_cc[VSTART];
#endif
#endif
#if defined(VSTOP)
#if (VSTOP < MAXCC)
D_NewMode.tio.c_cc[VSTOP] = D_OldMode.tio.c_cc[VSTOP];
#endif
#endif
D_NewMode.tio.c_iflag |= D_OldMode.tio.c_iflag & IXON;
}
else
{
D_NewMode.tio.c_cc[VINTR] = VDISABLE;
#if defined(VSTART)
#if (VSTART < MAXCC)
D_NewMode.tio.c_cc[VSTART] = VDISABLE;
#endif
#endif
#if defined(VSTOP)
#if (VSTOP < MAXCC)
D_NewMode.tio.c_cc[VSTOP] = VDISABLE;
#endif
#endif
D_NewMode.tio.c_iflag &= ~IXON;
}
# ifdef POSIX
if (tcsetattr(D_userfd, TCSANOW, &D_NewMode.tio))
# else
if (ioctl(D_userfd, TCSETAW, (char *)&D_NewMode.tio) != 0)
# endif
debug1("SetFlow: ioctl errno %d\n", errno);
#else
if (on)
{
D_NewMode.m_tchars.t_intrc = iflag ? D_OldMode.m_tchars.t_intrc : -1;
D_NewMode.m_tchars.t_startc = D_OldMode.m_tchars.t_startc;
D_NewMode.m_tchars.t_stopc = D_OldMode.m_tchars.t_stopc;
}
else
{
D_NewMode.m_tchars.t_intrc = -1;
D_NewMode.m_tchars.t_startc = -1;
D_NewMode.m_tchars.t_stopc = -1;
}
if (ioctl(D_userfd, TIOCSETC, (char *)&D_NewMode.m_tchars) != 0)
debug1("SetFlow: ioctl errno %d\n", errno);
#endif
D_flow = on;
}
int
SttyMode(m, opt)
struct mode *m;
char *opt;
{
static const char sep[] = " \t:;,";
if (!opt)
return 0;
while (*opt)
{
while (index(sep, *opt)) opt++;
if (*opt >= '0' && *opt <= '9')
{
if (SetBaud(m, atoi(opt), atoi(opt)))
return -1;
}
else if (!strncmp("cs7", opt, 3))
{
#if defined(POSIX) || defined(TERMIO)
m->tio.c_cflag &= ~CSIZE;
m->tio.c_cflag |= CS7;
#else
m->m_lmode &= ~LPASS8;
#endif
}
else if (!strncmp("cs8", opt, 3))
{
#if defined(POSIX) || defined(TERMIO)
m->tio.c_cflag &= ~CSIZE;
m->tio.c_cflag |= CS8;
#else
m->m_lmode |= LPASS8;
#endif
}
else if (!strncmp("istrip", opt, 6))
{
#if defined(POSIX) || defined(TERMIO)
m->tio.c_iflag |= ISTRIP;
#else
m->m_lmode &= ~LPASS8;
#endif
}
else if (!strncmp("-istrip", opt, 7))
{
#if defined(POSIX) || defined(TERMIO)
m->tio.c_iflag &= ~ISTRIP;
#else
m->m_lmode |= LPASS8;
#endif
}
else if (!strncmp("ixon", opt, 4))
{
#if defined(POSIX) || defined(TERMIO)
m->tio.c_iflag |= IXON;
#else
debug("SttyMode: no ixon in old bsd land.\n");
#endif
}
else if (!strncmp("-ixon", opt, 5))
{
#if defined(POSIX) || defined(TERMIO)
m->tio.c_iflag &= ~IXON;
#else
debug("SttyMode: no -ixon in old bsd land.\n");
#endif
}
else if (!strncmp("ixoff", opt, 5))
{
#if defined(POSIX) || defined(TERMIO)
m->tio.c_iflag |= IXOFF;
#else
m->m_ttyb.sg_flags |= TANDEM;
#endif
}
else if (!strncmp("-ixoff", opt, 6))
{
#if defined(POSIX) || defined(TERMIO)
m->tio.c_iflag &= ~IXOFF;
#else
m->m_ttyb.sg_flags &= ~TANDEM;
#endif
}
else if (!strncmp("crtscts", opt, 7))
{
#if (defined(POSIX) || defined(TERMIO)) && defined(CRTSCTS)
m->tio.c_cflag |= CRTSCTS;
#endif
}
else if (!strncmp("-crtscts", opt, 8))
{
#if (defined(POSIX) || defined(TERMIO)) && defined(CRTSCTS)
m->tio.c_cflag &= ~CRTSCTS;
#endif
}
else
return -1;
while (*opt && !index(sep, *opt)) opt++;
}
return 0;
}
void
brktty(fd)
int fd;
{
#if defined(POSIX) && !defined(ultrix)
if (separate_sids)
setsid();
# if defined(BSD) && defined(TIOCSCTTY) && !defined(__GNU__)
ioctl(fd, TIOCSCTTY, (char *)0);
# endif
#else
# ifdef SYSV
if (separate_sids)
setpgrp();
# else
# ifdef BSDJOBS
int devtty;
if ((devtty = open("/dev/tty", O_RDWR | O_NONBLOCK)) >= 0)
{
if (ioctl(devtty, TIOCNOTTY, (char *)0))
debug2("brktty: ioctl(devtty=%d, TIOCNOTTY, 0) = %d\n", devtty, errno);
close(devtty);
}
# endif
# endif
#endif
}
int
fgtty(fd)
int fd;
{
#ifdef BSDJOBS
int mypid;
mypid = getpid();
# if defined(__osf__) || (BSD >= 199103) || defined(ISC)
if (separate_sids)
setsid();
# ifdef TIOCSCTTY
ioctl(fd, TIOCSCTTY, (char *)0);
# endif
# endif
# ifdef POSIX
if (separate_sids)
if (tcsetpgrp(fd, mypid))
{
debug1("fgtty: tcsetpgrp: %d\n", errno);
return -1;
}
# else
if (ioctl(fd, TIOCSPGRP, (char *)&mypid) != 0)
debug1("fgtty: TIOSETPGRP: %d\n", errno);
# ifndef SYSV
if (separate_sids)
if (setpgrp(fd, mypid))
debug1("fgtty: setpgrp: %d\n", errno);
# endif
# endif
#endif
return 0;
}
#ifdef POSIX
int breaktype = 2;
#else
# ifdef TCSBRK
int breaktype = 1;
# else
int breaktype = 0;
# endif
#endif
#if defined(sun) && !defined(SVR4)
# define HAVE_SUPER_TCSENDBREAK
#endif
static void
DoSendBreak(fd, n, type)
int fd, n, type;
{
switch (type)
{
case 2:
#ifdef POSIX
# ifdef HAVE_SUPER_TCSENDBREAK
debug2("tcsendbreak(fd=%d, %d)\n", fd, n);
if (tcsendbreak(fd, n) < 0)
Msg(errno, "cannot send BREAK (tcsendbreak)");
# else
debug2("%d * tcsendbreak(fd=%d, 0)\n", n, fd);
{
int i;
if (!n)
n++;
for (i = 0; i < n; i++)
if (tcsendbreak(fd, 0) < 0)
{
Msg(errno, "cannot send BREAK (tcsendbreak SVR4)");
return;
}
}
# endif
#else
Msg(0, "tcsendbreak() not available, change breaktype");
#endif
break;
case 1:
#ifdef TCSBRK
if (!n)
n++;
debug2("%d * TCSBRK fd=%d\n", n, fd);
{
int i;
for (i = 0; i < n; i++)
if (ioctl(fd, TCSBRK, (char *)0) < 0)
{
Msg(errno, "Cannot send BREAK (TCSBRK)");
return;
}
}
#else
Msg(0, "TCSBRK not available, change breaktype");
#endif
break;
case 0:
#if defined(TIOCSBRK) && defined(TIOCCBRK)
debug("TIOCSBRK TIOCCBRK\n");
if (ioctl(fd, TIOCSBRK, (char *)0) < 0)
{
Msg(errno, "Can't send BREAK (TIOCSBRK)");
return;
}
sleep1000(n ? n * 250 : 250);
if (ioctl(fd, TIOCCBRK, (char *)0) < 0)
{
Msg(errno, "BREAK stuck!!! -- HELP! (TIOCCBRK)");
return;
}
#else
Msg(0, "TIOCSBRK/CBRK not available, change breaktype");
#endif
break;
default:
Msg(0, "Internal SendBreak error: method %d unknown", type);
}
}
void
SendBreak(wp, n, closeopen)
struct win *wp;
int n, closeopen;
{
sigret_t (*sigalrm)__P(SIGPROTOARG);
#ifdef BUILTIN_TELNET
if (wp->w_type == W_TYPE_TELNET)
{
TelBreak(wp);
return;
}
#endif
if (wp->w_type != W_TYPE_PLAIN)
return;
debug3("break(%d, %d) fd %d\n", n, closeopen, wp->w_ptyfd);
#ifdef POSIX
(void) tcflush(wp->w_ptyfd, TCIOFLUSH);
#else
# ifdef TIOCFLUSH
(void) ioctl(wp->w_ptyfd, TIOCFLUSH, (char *)0);
# endif
#endif
if (closeopen)
{
close(wp->w_ptyfd);
sleep1000(n ? n * 250 : 250);
if ((wp->w_ptyfd = OpenTTY(wp->w_tty, wp->w_cmdargs[1])) < 1)
{
Msg(0, "Ouch, cannot reopen line %s, please try harder", wp->w_tty);
return;
}
(void) fcntl(wp->w_ptyfd, F_SETFL, FNBLOCK);
}
else
{
sigalrm = signal(SIGALRM, SigAlrmDummy);
alarm(15);
DoSendBreak(wp->w_ptyfd, n, breaktype);
alarm(0);
signal(SIGALRM, sigalrm);
}
debug(" broken.\n");
}
#if (!defined(TIOCCONS) && defined(SRIOCSREDIR)) || defined(linux)
static struct event consredir_ev;
static int consredirfd[2] = {-1, -1};
static void
consredir_readev_fn(ev, data)
struct event *ev;
char *data;
{
char *p, *n, buf[256];
int l;
if (!console_window || (l = read(consredirfd[0], buf, sizeof(buf))) <= 0)
{
close(consredirfd[0]);
close(consredirfd[1]);
consredirfd[0] = consredirfd[1] = -1;
evdeq(ev);
return;
}
for (p = n = buf; l > 0; n++, l--)
if (*n == '\n')
{
if (n > p)
WriteString(console_window, p, n - p);
WriteString(console_window, "\r\n", 2);
p = n + 1;
}
if (n > p)
WriteString(console_window, p, n - p);
}
#endif
int
TtyGrabConsole(fd, on, rc_name)
int fd, on;
char *rc_name;
{
#if defined(TIOCCONS) && !defined(linux)
struct display *d;
int ret = 0;
int sfd = -1;
if (on < 0)
return 0;
if (on)
{
if (displays == 0)
{
Msg(0, "I need a display");
return -1;
}
for (d = displays; d; d = d->d_next)
if (strcmp(d->d_usertty, "/dev/console") == 0)
break;
if (d)
{
Msg(0, "too dangerous - screen is running on /dev/console");
return -1;
}
}
if (!on)
{
char *slave;
if ((fd = OpenPTY(&slave)) < 0)
{
Msg(errno, "%s: could not open detach pty master", rc_name);
return -1;
}
if ((sfd = open(slave, O_RDWR | O_NOCTTY)) < 0)
{
Msg(errno, "%s: could not open detach pty slave", rc_name);
close(fd);
return -1;
}
}
if (UserContext() == 1)
UserReturn(ioctl(fd, TIOCCONS, (char *)&on));
ret = UserStatus();
if (ret)
Msg(errno, "%s: ioctl TIOCCONS failed", rc_name);
if (!on)
{
close(sfd);
close(fd);
}
return ret;
#else
# if defined(SRIOCSREDIR) || defined(linux)
struct display *d;
# ifdef SRIOCSREDIR
int cfd;
# else
struct mode new1, new2;
char *slave;
# endif
if (on > 0)
{
if (displays == 0)
{
Msg(0, "I need a display");
return -1;
}
for (d = displays; d; d = d->d_next)
if (strcmp(d->d_usertty, "/dev/console") == 0)
break;
if (d)
{
Msg(0, "too dangerous - screen is running on /dev/console");
return -1;
}
}
if (consredirfd[0] >= 0)
{
evdeq(&consredir_ev);
close(consredirfd[0]);
close(consredirfd[1]);
consredirfd[0] = consredirfd[1] = -1;
}
if (on <= 0)
return 0;
# ifdef SRIOCSREDIR
if ((cfd = secopen("/dev/console", O_RDWR|O_NOCTTY, 0)) == -1)
{
Msg(errno, "/dev/console");
return -1;
}
if (pipe(consredirfd))
{
Msg(errno, "pipe");
close(cfd);
consredirfd[0] = consredirfd[1] = -1;
return -1;
}
if (ioctl(cfd, SRIOCSREDIR, consredirfd[1]))
{
Msg(errno, "SRIOCSREDIR ioctl");
close(cfd);
close(consredirfd[0]);
close(consredirfd[1]);
consredirfd[0] = consredirfd[1] = -1;
return -1;
}
close(cfd);
# else
if ((consredirfd[0] = OpenPTY(&slave)) < 0)
{
Msg(errno, "%s: could not open detach pty master", rc_name);
return -1;
}
if ((consredirfd[1] = open(slave, O_RDWR | O_NOCTTY)) < 0)
{
Msg(errno, "%s: could not open detach pty slave", rc_name);
close(consredirfd[0]);
return -1;
}
InitTTY(&new1, 0);
SetMode(&new1, &new2, 0, 0);
SetTTY(consredirfd[1], &new2);
if (UserContext() == 1)
UserReturn(ioctl(consredirfd[1], TIOCCONS, (char *)&on));
if (UserStatus())
{
Msg(errno, "%s: ioctl TIOCCONS failed", rc_name);
close(consredirfd[0]);
close(consredirfd[1]);
return -1;
}
# endif
consredir_ev.fd = consredirfd[0];
consredir_ev.type = EV_READ;
consredir_ev.handler = consredir_readev_fn;
evenq(&consredir_ev);
return 0;
# else
if (on > 0)
Msg(0, "%s: don't know how to grab the console", rc_name);
return -1;
# endif
#endif
}
char *
TtyGetModemStatus(fd, buf)
int fd;
char *buf;
{
char *p = buf;
#ifdef TIOCGSOFTCAR
unsigned int softcar;
#endif
#if defined(TIOCMGET) || defined(TIOCMODG)
unsigned int mflags;
#else
# ifdef MCGETA
mflag mflags;
#if defined(MDTR)
# define TIOCM_DTR MDTR
#endif
#if defined(MRTS)
# define TIOCM_RTS MRTS
#endif
#if defined(MDSR)
# define TIOCM_DSR MDSR
#endif
#if defined(MDCD)
# define TIOCM_CAR MDCD
#endif
#if defined(MRI)
# define TIOCM_RNG MRI
#endif
#if defined(MCTS)
# define TIOCM_CTS MCTS
#endif
# endif
#endif
#if defined(CLOCAL) || defined(CRTSCTS)
struct mode mtio;
#endif
#if defined(CRTSCTS) || defined(TIOCM_CTS)
int rtscts;
#endif
int clocal;
#if defined(CLOCAL) || defined(CRTSCTS)
GetTTY(fd, &mtio);
#endif
clocal = 0;
#ifdef CLOCAL
if (mtio.tio.c_cflag & CLOCAL)
{
clocal = 1;
*p++ = '{';
}
#endif
#ifdef TIOCM_CTS
# ifdef CRTSCTS
if (!(mtio.tio.c_cflag & CRTSCTS))
rtscts = 0;
else
# endif
rtscts = 1;
#endif
#ifdef TIOCGSOFTCAR
if (ioctl(fd, TIOCGSOFTCAR, (char *)&softcar) < 0)
softcar = 0;
#endif
#if defined(TIOCMGET) || defined(TIOCMODG) || defined(MCGETA)
# ifdef TIOCMGET
if (ioctl(fd, TIOCMGET, (char *)&mflags) < 0)
# else
# ifdef TIOCMODG
if (ioctl(fd, TIOCMODG, (char *)&mflags) < 0)
# else
if (ioctl(fd, MCGETA, &mflags) < 0)
# endif
# endif
{
#ifdef TIOCGSOFTCAR
sprintf(p, "NO-TTY? %s", softcar ? "(CD)" : "CD");
#else
sprintf(p, "NO-TTY?");
#endif
p += strlen(p);
}
else
{
char *s;
# ifdef FANCY_MODEM
# ifdef TIOCM_LE
if (!(mflags & TIOCM_LE))
for (s = "!LE "; *s; *p++ = *s++);
# endif
# endif
# ifdef TIOCM_RTS
s = "!RTS "; if (mflags & TIOCM_RTS) s++;
while (*s) *p++ = *s++;
# endif
# ifdef TIOCM_CTS
s = "!CTS ";
if (!rtscts)
{
*p++ = '(';
s = "!CTS) ";
}
if (mflags & TIOCM_CTS) s++;
while (*s) *p++ = *s++;
# endif
# ifdef TIOCM_DTR
s = "!DTR "; if (mflags & TIOCM_DTR) s++;
while (*s) *p++ = *s++;
# endif
# ifdef TIOCM_DSR
s = "!DSR "; if (mflags & TIOCM_DSR) s++;
while (*s) *p++ = *s++;
# endif
# if defined(TIOCM_CD) || defined(TIOCM_CAR)
s = "!CD ";
# ifdef TIOCGSOFTCAR
if (softcar)
{
*p++ = '(';
s = "!CD) ";
}
# endif
# ifdef TIOCM_CD
if (mflags & TIOCM_CD) s++;
# else
if (mflags & TIOCM_CAR) s++;
# endif
while (*s) *p++ = *s++;
# endif
# if defined(TIOCM_RI) || defined(TIOCM_RNG)
# ifdef TIOCM_RI
if (mflags & TIOCM_RI)
# else
if (mflags & TIOCM_RNG)
# endif
for (s = "RI "; *s; *p++ = *s++);
# endif
# ifdef FANCY_MODEM
# ifdef TIOCM_ST
s = "!ST "; if (mflags & TIOCM_ST) s++;
while (*s) *p++ = *s++;
# endif
# ifdef TIOCM_SR
s = "!SR "; if (mflags & TIOCM_SR) s++;
while (*s) *p++ = *s++;
# endif
# endif
if (p > buf && p[-1] == ' ')
p--;
*p = '\0';
}
#else
# ifdef TIOCGSOFTCAR
sprintf(p, " %s", softcar ? "(CD)", "CD");
p += strlen(p);
# endif
#endif
if (clocal)
*p++ = '}';
*p = '\0';
return buf;
}
#ifndef POSIX
# ifndef TERMIO
# if !defined(B9600) && !defined(B2400) && !defined(B1200) && !defined(B300)
#if !defined(B0)
#define B0 0
#endif
#if !defined(B50)
#define B50 1
#endif
#if !defined(B75)
#define B75 2
#endif
#if !defined(B110)
#define B110 3
#endif
#if !defined(B134)
#define B134 4
#endif
#if !defined(B150)
#define B150 5
#endif
#if !defined(B200)
#define B200 6
#endif
#if !defined(B300)
#define B300 7
#endif
#if !defined(B600)
#define B600 8
#endif
#if !defined(B1200)
#define B1200 9
#endif
#if !defined(B1800)
#define B1800 10
#endif
#if !defined(B2400)
#define B2400 11
#endif
#if !defined(B4800)
#define B4800 12
#endif
#if !defined(B9600)
#define B9600 13
#endif
#if !defined(EXTA)
#define EXTA 14
#endif
#if !defined(EXTB)
#define EXTB 15
#endif
# endif
# endif
#endif
static struct baud_values btable[] =
{
#if defined(B9600)
{ 13, 9600, B9600 },
#endif
#if defined(B19200)
{ 14, 19200, B19200 },
#endif
#if defined(EXTA)
{ 14, 19200, EXTA },
#endif
#if defined(B38400)
{ 15, 38400, B38400 },
#endif
#if defined(EXTB)
{ 15, 38400, EXTB },
#endif
#if defined(B57600)
{ 16, 57600, B57600 },
#endif
#if defined(B115200)
{ 17, 115200, B115200 },
#endif
#if defined(B230400)
{ 18, 230400, B230400 },
#endif
#if defined(B460800)
{ 19, 460800, B460800 },
#endif
#if defined(B7200)
{ 13, 7200, B7200 },
#endif
#if defined(B4800)
{ 12, 4800, B4800 },
#endif
#if defined(B3600)
{ 12, 3600, B3600 },
#endif
#if defined(B2400)
{ 11, 2400, B2400 },
#endif
#if defined(B1800)
{ 10, 1800, B1800 },
#endif
#if defined(B1200)
{ 9, 1200, B1200 },
#endif
#if defined(B900)
{ 9, 900, B900 },
#endif
#if defined(B600)
{ 8, 600, B600 },
#endif
#if defined(B300)
{ 7, 300, B300 },
#endif
#if defined(B200)
{ 6, 200, B200 },
#endif
#if defined(B150)
{ 5, 150, B150 },
#endif
#if defined(B134)
{ 4, 134, B134 },
#endif
#if defined(B110)
{ 3, 110, B110 },
#endif
#if defined(B75)
{ 2, 75, B75 },
#endif
#if defined(B50)
{ 1, 50, B50 },
#endif
#if defined(B0)
{ 0, 0, B0 },
#endif
{ -1, -1, -1 }
};
struct baud_values *
lookup_baud(baud)
int baud;
{
struct baud_values *p;
for (p = btable; p->idx >= 0; p++)
if (baud == p->bps || baud == p->sym)
return p;
return NULL;
}
int
SetBaud(m, ibaud, obaud)
struct mode *m;
int ibaud, obaud;
{
struct baud_values *ip, *op;
if ((!(ip = lookup_baud(ibaud)) && ibaud != -1) ||
(!(op = lookup_baud(obaud)) && obaud != -1))
return -1;
#ifdef POSIX
if (ip) cfsetispeed(&m->tio, ip->sym);
if (op) cfsetospeed(&m->tio, op->sym);
#else
# ifdef TERMIO
if (ip)
{
# ifdef IBSHIFT
m->tio.c_cflag &= ~(CBAUD << IBSHIFT);
m->tio.c_cflag |= (ip->sym & CBAUD) << IBSHIFT;
# else
if (ibaud != obaud)
return -1;
# endif
}
if (op)
{
m->tio.c_cflag &= ~CBAUD;
m->tio.c_cflag |= op->sym & CBAUD;
}
# else
if (ip) m->m_ttyb.sg_ispeed = ip->idx;
if (op) m->m_ttyb.sg_ospeed = op->idx;
# endif
#endif
return 0;
}
#ifdef DEBUG
void
DebugTTY(m)
struct mode *m;
{
int i;
#ifdef POSIX
debug("struct termios tio:\n");
debug1("c_iflag = %#x\n", (unsigned int)m->tio.c_iflag);
debug1("c_oflag = %#x\n", (unsigned int)m->tio.c_oflag);
debug1("c_cflag = %#x\n", (unsigned int)m->tio.c_cflag);
debug1("c_lflag = %#x\n", (unsigned int)m->tio.c_lflag);
debug1("cfgetospeed() = %d\n", (int)cfgetospeed(&m->tio));
debug1("cfgetispeed() = %d\n", (int)cfgetispeed(&m->tio));
for (i = 0; i < sizeof(m->tio.c_cc)/sizeof(*m->tio.c_cc); i++)
{
debug2("c_cc[%d] = %#x\n", i, m->tio.c_cc[i]);
}
# ifdef HPUX_LTCHARS_HACK
debug1("suspc = %#02x\n", m->m_ltchars.t_suspc);
debug1("dsuspc = %#02x\n", m->m_ltchars.t_dsuspc);
debug1("rprntc = %#02x\n", m->m_ltchars.t_rprntc);
debug1("flushc = %#02x\n", m->m_ltchars.t_flushc);
debug1("werasc = %#02x\n", m->m_ltchars.t_werasc);
debug1("lnextc = %#02x\n", m->m_ltchars.t_lnextc);
# endif
#else
# ifdef TERMIO
debug("struct termio tio:\n");
debug1("c_iflag = %04o\n", m->tio.c_iflag);
debug1("c_oflag = %04o\n", m->tio.c_oflag);
debug1("c_cflag = %04o\n", m->tio.c_cflag);
debug1("c_lflag = %04o\n", m->tio.c_lflag);
for (i = 0; i < sizeof(m->tio.c_cc)/sizeof(*m->tio.c_cc); i++)
{
debug2("c_cc[%d] = %04o\n", i, m->tio.c_cc[i]);
}
# else
debug1("sg_ispeed = %d\n", m->m_ttyb.sg_ispeed);
debug1("sg_ospeed = %d\n", m->m_ttyb.sg_ospeed);
debug1("sg_erase = %#02x\n", m->m_ttyb.sg_erase);
debug1("sg_kill = %#02x\n", m->m_ttyb.sg_kill);
debug1("sg_flags = %#04x\n", (unsigned short)m->m_ttyb.sg_flags);
debug1("intrc = %#02x\n", m->m_tchars.t_intrc);
debug1("quitc = %#02x\n", m->m_tchars.t_quitc);
debug1("startc = %#02x\n", m->m_tchars.t_startc);
debug1("stopc = %#02x\n", m->m_tchars.t_stopc);
debug1("eofc = %#02x\n", m->m_tchars.t_eofc);
debug1("brkc = %#02x\n", m->m_tchars.t_brkc);
debug1("suspc = %#02x\n", m->m_ltchars.t_suspc);
debug1("dsuspc = %#02x\n", m->m_ltchars.t_dsuspc);
debug1("rprntc = %#02x\n", m->m_ltchars.t_rprntc);
debug1("flushc = %#02x\n", m->m_ltchars.t_flushc);
debug1("werasc = %#02x\n", m->m_ltchars.t_werasc);
debug1("lnextc = %#02x\n", m->m_ltchars.t_lnextc);
debug1("ldisc = %d\n", m->m_ldisc);
debug1("lmode = %#x\n", m->m_lmode);
# endif
#endif
}
#endif