#include <sys/types.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/file.h>
#include <sys/termios.h>
#include <sys/ttold.h>
#include <sys/cmn_err.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/strsubr.h>
#include <sys/strsun.h>
#include <sys/errno.h>
#include <sys/debug.h>
#include <sys/ttcompat.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/kmem.h>
#include <sys/policy.h>
#include <sys/conf.h>
#include <sys/modctl.h>
extern int sgttyb_handling;
static struct streamtab ttcoinfo;
static struct fmodsw fsw = {
"ttcompat",
&ttcoinfo,
D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
};
static struct modlstrmod modlstrmod = {
&mod_strmodops,
"alt ioctl calls",
&fsw
};
static struct modlinkage modlinkage = {
MODREV_1, &modlstrmod, NULL
};
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_fini(void)
{
return (mod_remove(&modlinkage));
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
static int ttcompatopen(queue_t *, dev_t *, int, int, cred_t *);
static int ttcompatclose(queue_t *, int, cred_t *);
static int ttcompatrput(queue_t *, mblk_t *);
static int ttcompatwput(queue_t *, mblk_t *);
static struct module_info ttycompatmiinfo = {
0,
"ttcompat",
0,
INFPSZ,
2048,
128
};
static struct qinit ttycompatrinit = {
ttcompatrput,
NULL,
ttcompatopen,
ttcompatclose,
NULL,
&ttycompatmiinfo
};
static struct module_info ttycompatmoinfo = {
42,
"ttcompat",
0,
INFPSZ,
300,
200
};
static struct qinit ttycompatwinit = {
ttcompatwput,
NULL,
ttcompatopen,
ttcompatclose,
NULL,
&ttycompatmoinfo
};
static struct streamtab ttcoinfo = {
&ttycompatrinit,
&ttycompatwinit,
NULL,
NULL
};
static void ttcompat_do_ioctl(ttcompat_state_t *, queue_t *, mblk_t *);
static void ttcompat_ioctl_ack(queue_t *, mblk_t *);
static void ttcopyout(queue_t *, mblk_t *);
static void ttcompat_ioctl_nak(queue_t *, mblk_t *);
static void from_compat(compat_state_t *, struct termios *);
static void to_compat(struct termios *, compat_state_t *);
static int
ttcompatopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
{
ttcompat_state_t *tp;
if (q->q_ptr != NULL) {
tp = (ttcompat_state_t *)q->q_ptr;
if ((tp->t_new_lflags & XCLUDE) &&
secpolicy_excl_open(crp) != 0) {
return (EBUSY);
}
return (0);
}
tp = kmem_zalloc(sizeof (ttcompat_state_t), KM_SLEEP);
q->q_ptr = tp;
WR(q)->q_ptr = tp;
qprocson(q);
return (0);
}
static int
ttcompatclose(queue_t *q, int flag, cred_t *crp)
{
ttcompat_state_t *tp = (ttcompat_state_t *)q->q_ptr;
mblk_t *mp;
qprocsoff(q);
if (tp->t_bufcallid != 0) {
qunbufcall(q, tp->t_bufcallid);
tp->t_bufcallid = 0;
}
if ((mp = tp->t_iocpending) != NULL)
freemsg(mp);
kmem_free(tp, sizeof (ttcompat_state_t));
q->q_ptr = NULL;
return (0);
}
static int
ttcompatrput(queue_t *q, mblk_t *mp)
{
switch (mp->b_datap->db_type) {
case M_IOCACK:
ttcompat_ioctl_ack(q, mp);
break;
case M_IOCNAK:
ttcompat_ioctl_nak(q, mp);
break;
default:
putnext(q, mp);
break;
}
return (0);
}
static int
ttcompatwput(queue_t *q, mblk_t *mp)
{
ttcompat_state_t *tp;
struct copyreq *cqp;
struct copyresp *csp;
struct iocblk *iocbp;
tp = (ttcompat_state_t *)q->q_ptr;
switch (mp->b_datap->db_type) {
default:
putnext(q, mp);
return (0);
case M_IOCTL:
iocbp = (struct iocblk *)mp->b_rptr;
switch (iocbp->ioc_cmd) {
default:
ttcompat_do_ioctl(tp, q, mp);
return (0);
case TIOCSETN:
case TIOCSLTC:
case TIOCSETC:
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET:
case TIOCFLUSH:
if (iocbp->ioc_count != TRANSPARENT) {
putnext(q, mp);
return (0);
}
mp->b_datap->db_type = M_COPYIN;
cqp = (struct copyreq *)mp->b_rptr;
cqp->cq_addr = (caddr_t)*(intptr_t *)mp->b_cont->b_rptr;
switch (iocbp->ioc_cmd) {
case TIOCSETN:
cqp->cq_size = sizeof (struct sgttyb);
break;
case TIOCSLTC:
cqp->cq_size = sizeof (struct ltchars);
break;
case TIOCSETC:
cqp->cq_size = sizeof (struct tchars);
break;
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET:
case TIOCFLUSH:
cqp->cq_size = sizeof (int);
break;
default:
break;
}
cqp->cq_flag = 0;
cqp->cq_private = NULL;
freemsg(mp->b_cont);
mp->b_cont = NULL;
mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
tp->t_ioccmd = iocbp->ioc_cmd;
tp->t_state |= TS_W_IN;
qreply(q, mp);
return (0);
}
case M_IOCDATA:
csp = (struct copyresp *)mp->b_rptr;
switch (csp->cp_cmd) {
default:
putnext(q, mp);
return (0);
case TIOCSETN:
case TIOCSLTC:
case TIOCSETC:
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET:
case TIOCFLUSH:
tp->t_state &= ~TS_W_IN;
if (csp->cp_rval != 0) {
freemsg(mp);
return (0);
}
mp->b_datap->db_type = M_IOCTL;
mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
iocbp = (struct iocblk *)mp->b_rptr;
iocbp->ioc_count = MBLKL(mp->b_cont);
iocbp->ioc_error = 0;
iocbp->ioc_rval = 0;
ttcompat_do_ioctl(tp, q, mp);
return (0);
case TIOCGLTC:
case TIOCLGET:
case TIOCGETC:
tp->t_state &= ~TS_W_OUT;
if (csp->cp_rval != 0) {
freemsg(mp);
return (0);
}
iocbp = (struct iocblk *)mp->b_rptr;
iocbp->ioc_count = 0;
iocbp->ioc_error = 0;
iocbp->ioc_rval = 0;
mp->b_datap->db_type = M_IOCACK;
qreply(q, mp);
return (0);
}
}
return (0);
}
static void
ttcompat_reioctl(void *arg)
{
queue_t *q = arg;
ttcompat_state_t *tp;
mblk_t *mp;
tp = (ttcompat_state_t *)q->q_ptr;
tp->t_bufcallid = 0;
if ((mp = tp->t_iocpending) != NULL) {
tp->t_iocpending = NULL;
ttcompat_do_ioctl(tp, q, mp);
}
}
static void
ttcompat_do_ioctl(ttcompat_state_t *tp, queue_t *q, mblk_t *mp)
{
struct iocblk *iocp;
int error;
iocp = (struct iocblk *)mp->b_rptr;
switch (iocp->ioc_cmd) {
case TIOCGETC:
case TIOCLGET:
case TIOCGLTC:
if (iocp->ioc_count != TRANSPARENT) {
miocnak(q, mp, 0, EINVAL);
return;
}
ASSERT(mp->b_cont != NULL);
tp->t_arg = *(intptr_t *)mp->b_cont->b_rptr;
freemsg(mp->b_cont);
mp->b_cont = NULL;
iocp->ioc_count = 0;
case TIOCGETP:
goto dogets;
case TIOCSETP:
case TIOCSETN:
error = miocpullup(mp, sizeof (struct sgttyb));
if (error != 0) {
miocnak(q, mp, 0, error);
return;
}
tp->t_new_sgttyb = *((struct sgttyb *)mp->b_cont->b_rptr);
goto dogets;
case TIOCSETC:
error = miocpullup(mp, sizeof (struct tchars));
if (error != 0) {
miocnak(q, mp, 0, error);
return;
}
tp->t_new_tchars = *((struct tchars *)mp->b_cont->b_rptr);
goto dogets;
case TIOCSLTC:
error = miocpullup(mp, sizeof (struct ltchars));
if (error != 0) {
miocnak(q, mp, 0, error);
return;
}
tp->t_new_ltchars = *((struct ltchars *)mp->b_cont->b_rptr);
goto dogets;
case TIOCLBIS:
case TIOCLBIC:
case TIOCLSET:
error = miocpullup(mp, sizeof (int));
if (error != 0) {
miocnak(q, mp, 0, error);
return;
}
tp->t_new_lflags = *(int *)mp->b_cont->b_rptr;
goto dogets;
case TIOCHPCL:
dogets:
tp->t_ioccmd = iocp->ioc_cmd;
tp->t_iocid = iocp->ioc_id;
tp->t_state |= TS_IOCWAIT;
iocp->ioc_cmd = TCGETS;
iocp->ioc_count = 0;
break;
case TIOCSDTR: {
mblk_t *datap;
if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)
goto allocfailure;
*(int *)datap->b_wptr = TIOCM_DTR;
datap->b_wptr += sizeof (int);
iocp->ioc_cmd = TIOCMBIS;
if (mp->b_cont != NULL)
freemsg(mp->b_cont);
mp->b_cont = datap;
iocp->ioc_count = sizeof (int);
break;
}
case TIOCCDTR: {
mblk_t *datap;
if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)
goto allocfailure;
*(int *)datap->b_wptr = TIOCM_DTR;
datap->b_wptr += sizeof (int);
iocp->ioc_cmd = TIOCMBIC;
if (mp->b_cont != NULL)
freemsg(mp->b_cont);
mp->b_cont = datap;
iocp->ioc_count = sizeof (int);
break;
}
case TIOCFLUSH: {
int flags;
error = miocpullup(mp, sizeof (int));
if (error != 0) {
miocnak(q, mp, 0, error);
return;
}
flags = *(int *)mp->b_cont->b_rptr;
switch (flags&(FREAD|FWRITE)) {
case 0:
case FREAD|FWRITE:
flags = 2;
break;
case FREAD:
flags = 0;
break;
case FWRITE:
flags = 1;
break;
}
iocp->ioc_cmd = TCFLSH;
*(int *)mp->b_cont->b_rptr = flags;
break;
}
case TIOCSTOP: {
mblk_t *datap;
if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)
goto allocfailure;
*(int *)datap->b_wptr = 0;
datap->b_wptr += sizeof (int);
iocp->ioc_cmd = TCXONC;
iocp->ioc_count = sizeof (int);
if (mp->b_cont != NULL)
freemsg(mp->b_cont);
mp->b_cont = datap;
break;
}
case TIOCSTART: {
mblk_t *datap;
if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)
goto allocfailure;
*(int *)datap->b_wptr = 1;
datap->b_wptr += sizeof (int);
iocp->ioc_cmd = TCXONC;
iocp->ioc_count = sizeof (int);
if (mp->b_cont != NULL)
freemsg(mp->b_cont);
mp->b_cont = datap;
break;
}
case TIOCSETD:
case TIOCGETD:
case DIOCSETP:
case DIOCGETP:
case LDOPEN:
case LDCLOSE:
case LDCHG:
case LDSETT:
case LDGETT:
mp->b_datap->db_type = M_IOCACK;
if (iocp->ioc_cmd == TIOCSETD) {
iocp->ioc_error = miocpullup(mp, sizeof (uchar_t));
if (iocp->ioc_error == 0 && (*mp->b_cont->b_rptr != 0))
mp->b_datap->db_type = M_IOCNAK;
}
iocp->ioc_error = 0;
iocp->ioc_count = 0;
iocp->ioc_rval = 0;
qreply(q, mp);
return;
case IOCTYPE:
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_error = 0;
iocp->ioc_count = 0;
iocp->ioc_rval = TIOC;
qreply(q, mp);
return;
case TIOCEXCL:
tp->t_new_lflags |= XCLUDE;
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_error = 0;
iocp->ioc_count = 0;
iocp->ioc_rval = 0;
qreply(q, mp);
return;
case TIOCNXCL:
tp->t_new_lflags &= ~XCLUDE;
mp->b_datap->db_type = M_IOCACK;
iocp->ioc_error = 0;
iocp->ioc_count = 0;
iocp->ioc_rval = 0;
qreply(q, mp);
return;
}
putnext(q, mp);
return;
allocfailure:
if (tp->t_iocpending != NULL)
freemsg(tp->t_iocpending);
tp->t_iocpending = mp;
if (tp->t_bufcallid != 0)
qunbufcall(q, tp->t_bufcallid);
tp->t_bufcallid = qbufcall(q, sizeof (struct iocblk), BPRI_HI,
ttcompat_reioctl, q);
}
static void
ttcompat_ioctl_ack(queue_t *q, mblk_t *mp)
{
ttcompat_state_t *tp;
struct iocblk *iocp;
mblk_t *datap;
tp = (ttcompat_state_t *)q->q_ptr;
iocp = (struct iocblk *)mp->b_rptr;
if (!(tp->t_state&TS_IOCWAIT) || iocp->ioc_id != tp->t_iocid) {
putnext(q, mp);
return;
}
datap = mp->b_cont;
switch (tp->t_ioccmd) {
case TIOCGETP: {
struct sgttyb *cb;
to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
datap->b_rptr = datap->b_wptr = datap->b_datap->db_base;
cb = (struct sgttyb *)datap->b_wptr;
cb->sg_ispeed = tp->t_curstate.t_ispeed > B38400 ? B38400 :
tp->t_curstate.t_ispeed;
cb->sg_ospeed = tp->t_curstate.t_ospeed > B38400 ? B38400 :
tp->t_curstate.t_ospeed;
cb->sg_erase = tp->t_curstate.t_erase;
cb->sg_kill = tp->t_curstate.t_kill;
cb->sg_flags = tp->t_curstate.t_flags;
datap->b_wptr += sizeof (struct sgttyb);
iocp->ioc_count = sizeof (struct sgttyb);
tp->t_state &= ~TS_IOCWAIT;
iocp->ioc_rval = 0;
iocp->ioc_cmd = tp->t_ioccmd;
putnext(q, mp);
return;
}
case TIOCGETC:
to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
datap->b_rptr = datap->b_wptr = datap->b_datap->db_base;
bcopy(&tp->t_curstate.t_intrc, datap->b_wptr,
sizeof (struct tchars));
datap->b_wptr += sizeof (struct tchars);
break;
case TIOCGLTC:
to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
datap->b_rptr = datap->b_wptr = datap->b_datap->db_base;
bcopy(&tp->t_curstate.t_suspc, datap->b_wptr,
sizeof (struct ltchars));
datap->b_wptr += sizeof (struct ltchars);
break;
case TIOCLGET:
to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
datap->b_rptr = datap->b_wptr = datap->b_datap->db_base;
*(int *)datap->b_wptr =
((unsigned)tp->t_curstate.t_flags) >> 16;
datap->b_wptr += sizeof (int);
break;
case TIOCSETP:
case TIOCSETN:
to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
tp->t_curstate.t_erase = tp->t_new_sgttyb.sg_erase;
tp->t_curstate.t_kill = tp->t_new_sgttyb.sg_kill;
if (tp->t_new_sgttyb.sg_ispeed != B38400 ||
tp->t_curstate.t_ispeed <= B38400)
tp->t_curstate.t_ispeed = tp->t_new_sgttyb.sg_ispeed;
if (tp->t_new_sgttyb.sg_ospeed != B38400 ||
tp->t_curstate.t_ospeed <= B38400)
tp->t_curstate.t_ospeed = tp->t_new_sgttyb.sg_ospeed;
tp->t_curstate.t_flags =
(tp->t_curstate.t_flags & 0xffff0000) |
(tp->t_new_sgttyb.sg_flags & 0xffff);
from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
iocp->ioc_cmd = (tp->t_ioccmd == TIOCSETP) ? TCSETSF : TCSETS;
goto senddown;
case TIOCSETC:
to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
bcopy(&tp->t_new_tchars,
&tp->t_curstate.t_intrc, sizeof (struct tchars));
from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
iocp->ioc_cmd = TCSETS;
goto senddown;
case TIOCSLTC:
to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
bcopy(&tp->t_new_ltchars,
&tp->t_curstate.t_suspc, sizeof (struct ltchars));
from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
iocp->ioc_cmd = TCSETS;
goto senddown;
case TIOCLBIS:
to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
tp->t_curstate.t_flags |= (tp->t_new_lflags << 16);
from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
iocp->ioc_cmd = TCSETS;
goto senddown;
case TIOCLBIC:
to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
tp->t_curstate.t_flags &= ~(tp->t_new_lflags << 16);
from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
iocp->ioc_cmd = TCSETS;
goto senddown;
case TIOCLSET:
to_compat((struct termios *)datap->b_rptr, &tp->t_curstate);
tp->t_curstate.t_flags &= 0xffff;
tp->t_curstate.t_flags |= (tp->t_new_lflags << 16);
from_compat(&tp->t_curstate, (struct termios *)datap->b_rptr);
iocp->ioc_cmd = TCSETS;
goto senddown;
case TIOCHPCL:
((struct termios *)datap->b_rptr)->c_cflag |= HUPCL;
iocp->ioc_cmd = TCSETS;
goto senddown;
case TCSETSF:
tp->t_state &= ~(TS_IOCWAIT | TS_TIOCNAK);
freemsg(mp);
return;
default:
cmn_err(CE_WARN, "ttcompat: Unexpected ioctl acknowledgment\n");
}
tp->t_state &= ~TS_IOCWAIT;
iocp->ioc_rval = 0;
iocp->ioc_cmd = tp->t_ioccmd;
ttcopyout(q, mp);
return;
senddown:
tp->t_state &= ~TS_IOCWAIT;
mp->b_datap->db_type = M_IOCTL;
mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
putnext(WR(q), mp);
}
static void
ttcopyout(queue_t *q, mblk_t *mp)
{
struct copyreq *cqp;
ttcompat_state_t *tp;
tp = (ttcompat_state_t *)q->q_ptr;
mp->b_datap->db_type = M_COPYOUT;
cqp = (struct copyreq *)mp->b_rptr;
cqp->cq_addr = (caddr_t)tp->t_arg;
tp->t_arg = 0;
switch (tp->t_ioccmd) {
case TIOCGLTC:
cqp->cq_size = sizeof (struct ltchars);
break;
case TIOCGETC:
cqp->cq_size = sizeof (struct tchars);
break;
case TIOCLGET:
cqp->cq_size = sizeof (int);
break;
default:
cmn_err(CE_WARN,
"ttcompat: Unknown ioctl to copyout\n");
break;
}
cqp->cq_flag = 0;
cqp->cq_private = NULL;
tp->t_state |= TS_W_OUT;
putnext(q, mp);
}
static void
ttcompat_ioctl_nak(queue_t *q, mblk_t *mp)
{
ttcompat_state_t *tp;
struct iocblk *iocp;
iocp = (struct iocblk *)mp->b_rptr;
tp = (ttcompat_state_t *)q->q_ptr;
if (tp->t_state&TS_IOCWAIT && iocp->ioc_id == tp->t_iocid) {
tp->t_state &= ~TS_IOCWAIT;
tp->t_arg = 0;
}
putnext(q, mp);
}
#define FROM_COMPAT_CHAR(to, from) { if ((to = from) == 0377) to = 0; }
static void
from_compat(compat_state_t *csp, struct termios *termiosp)
{
termiosp->c_iflag = 0;
termiosp->c_oflag &= (ONLRET|ONOCR);
termiosp->c_cflag = (termiosp->c_cflag &
(CRTSCTS|CRTSXOFF|PAREXT|LOBLK|HUPCL)) | CREAD;
if (csp->t_ospeed > CBAUD) {
termiosp->c_cflag |= ((csp->t_ospeed - CBAUD - 1) & CBAUD) |
CBAUDEXT;
} else {
termiosp->c_cflag |= csp->t_ospeed & CBAUD;
}
if (csp->t_ospeed != csp->t_ispeed) {
if (csp->t_ispeed > (CIBAUD >> IBSHIFT)) {
termiosp->c_cflag |= CIBAUDEXT |
(((csp->t_ispeed - (CIBAUD >> IBSHIFT) - 1) <<
IBSHIFT) & CIBAUD);
} else {
termiosp->c_cflag |= (csp->t_ispeed << IBSHIFT) &
CIBAUD;
}
if (csp->t_ispeed == 0)
termiosp->c_cflag &= ~CBAUD & ~CBAUDEXT;
}
if (csp->t_ispeed == B110 || csp->t_xflags & STOPB)
termiosp->c_cflag |= CSTOPB;
termiosp->c_lflag = ECHOK;
FROM_COMPAT_CHAR(termiosp->c_cc[VERASE], csp->t_erase);
FROM_COMPAT_CHAR(termiosp->c_cc[VKILL], csp->t_kill);
FROM_COMPAT_CHAR(termiosp->c_cc[VINTR], csp->t_intrc);
FROM_COMPAT_CHAR(termiosp->c_cc[VQUIT], csp->t_quitc);
FROM_COMPAT_CHAR(termiosp->c_cc[VSTART], csp->t_startc);
FROM_COMPAT_CHAR(termiosp->c_cc[VSTOP], csp->t_stopc);
termiosp->c_cc[VEOL2] = 0;
FROM_COMPAT_CHAR(termiosp->c_cc[VSUSP], csp->t_suspc);
FROM_COMPAT_CHAR(termiosp->c_cc[VDSUSP], csp->t_dsuspc);
FROM_COMPAT_CHAR(termiosp->c_cc[VREPRINT], csp->t_rprntc);
FROM_COMPAT_CHAR(termiosp->c_cc[VDISCARD], csp->t_flushc);
FROM_COMPAT_CHAR(termiosp->c_cc[VWERASE], csp->t_werasc);
FROM_COMPAT_CHAR(termiosp->c_cc[VLNEXT], csp->t_lnextc);
termiosp->c_cc[VSTATUS] = 0;
if (csp->t_flags & O_TANDEM)
termiosp->c_iflag |= IXOFF;
if (csp->t_flags & O_LCASE) {
termiosp->c_iflag |= IUCLC;
termiosp->c_oflag |= OLCUC;
termiosp->c_lflag |= XCASE;
}
if (csp->t_flags & O_ECHO)
termiosp->c_lflag |= ECHO;
if (csp->t_flags & O_CRMOD) {
termiosp->c_iflag |= ICRNL;
termiosp->c_oflag |= ONLCR;
switch (csp->t_flags & O_CRDELAY) {
case O_CR1:
termiosp->c_oflag |= CR2;
break;
case O_CR2:
termiosp->c_oflag |= CR3;
break;
}
} else {
if ((csp->t_flags & O_NLDELAY) == O_NL1)
termiosp->c_oflag |= ONLRET|CR1;
}
if ((csp->t_flags & O_NLDELAY) == O_NL2)
termiosp->c_oflag |= NL1;
if (csp->t_flags & O_RAW) {
termiosp->c_cflag |= CS8;
termiosp->c_iflag &= ~(ICRNL|IUCLC);
termiosp->c_lflag &= ~(XCASE|IEXTEN);
} else {
termiosp->c_iflag |= IMAXBEL|BRKINT|IGNPAR;
if (termiosp->c_cc[VSTOP] != 0 && termiosp->c_cc[VSTART] != 0)
termiosp->c_iflag |= IXON;
if (csp->t_flags & O_LITOUT)
termiosp->c_cflag |= CS8;
else {
if (csp->t_flags & O_PASS8)
termiosp->c_cflag |= CS8;
else {
switch (csp->t_flags & (O_EVENP|O_ODDP)) {
case 0:
termiosp->c_iflag |= ISTRIP;
termiosp->c_cflag |= CS8;
break;
case O_EVENP:
termiosp->c_iflag |= INPCK|ISTRIP;
termiosp->c_cflag |= CS7|PARENB;
break;
case O_ODDP:
termiosp->c_iflag |= INPCK|ISTRIP;
termiosp->c_cflag |= CS7|PARENB|PARODD;
break;
case O_EVENP|O_ODDP:
termiosp->c_iflag |= ISTRIP;
termiosp->c_cflag |= CS7|PARENB;
break;
}
}
if (!(csp->t_xflags & NOPOST))
termiosp->c_oflag |= OPOST;
}
termiosp->c_lflag |= IEXTEN;
if (!(csp->t_xflags & NOISIG))
termiosp->c_lflag |= ISIG;
if (!(csp->t_flags & O_CBREAK))
termiosp->c_lflag |= ICANON;
if (csp->t_flags & O_CTLECH)
termiosp->c_lflag |= ECHOCTL;
}
switch (csp->t_flags & O_TBDELAY) {
case O_TAB1:
termiosp->c_oflag |= TAB1;
break;
case O_TAB2:
termiosp->c_oflag |= TAB2;
break;
case O_XTABS:
termiosp->c_oflag |= TAB3;
break;
}
if (csp->t_flags & O_VTDELAY)
termiosp->c_oflag |= FFDLY;
if (csp->t_flags & O_BSDELAY)
termiosp->c_oflag |= BSDLY;
if (csp->t_flags & O_PRTERA)
termiosp->c_lflag |= ECHOPRT;
if (csp->t_flags & O_CRTERA)
termiosp->c_lflag |= ECHOE;
if (csp->t_flags & O_TOSTOP)
termiosp->c_lflag |= TOSTOP;
if (csp->t_flags & O_FLUSHO)
termiosp->c_lflag |= FLUSHO;
if (csp->t_flags & O_NOHANG)
termiosp->c_cflag |= CLOCAL;
if (csp->t_flags & O_CRTKIL)
termiosp->c_lflag |= ECHOKE;
if (csp->t_flags & O_PENDIN)
termiosp->c_lflag |= PENDIN;
if (!(csp->t_flags & O_DECCTQ))
termiosp->c_iflag |= IXANY;
if (csp->t_flags & O_NOFLSH)
termiosp->c_lflag |= NOFLSH;
if (termiosp->c_lflag & ICANON) {
FROM_COMPAT_CHAR(termiosp->c_cc[VEOF], csp->t_eofc);
FROM_COMPAT_CHAR(termiosp->c_cc[VEOL], csp->t_brkc);
} else {
termiosp->c_cc[VMIN] = 1;
termiosp->c_cc[VTIME] = 0;
}
}
#define TO_COMPAT_CHAR(to, from) { if ((to = from) == 0) to = (uchar_t)0377; }
static void
to_compat(struct termios *termiosp, compat_state_t *csp)
{
csp->t_xflags &= (NOISIG|NOPOST);
csp->t_ospeed = termiosp->c_cflag & CBAUD;
csp->t_ispeed = (termiosp->c_cflag & CIBAUD) >> IBSHIFT;
if (sgttyb_handling > 0) {
if (termiosp->c_cflag & CBAUDEXT)
csp->t_ospeed += CBAUD + 1;
if (termiosp->c_cflag & CIBAUDEXT)
csp->t_ispeed += (CIBAUD >> IBSHIFT) + 1;
}
if (csp->t_ispeed == 0)
csp->t_ispeed = csp->t_ospeed;
if ((termiosp->c_cflag & CSTOPB) && csp->t_ispeed != B110)
csp->t_xflags |= STOPB;
TO_COMPAT_CHAR(csp->t_erase, termiosp->c_cc[VERASE]);
TO_COMPAT_CHAR(csp->t_kill, termiosp->c_cc[VKILL]);
TO_COMPAT_CHAR(csp->t_intrc, termiosp->c_cc[VINTR]);
TO_COMPAT_CHAR(csp->t_quitc, termiosp->c_cc[VQUIT]);
TO_COMPAT_CHAR(csp->t_startc, termiosp->c_cc[VSTART]);
TO_COMPAT_CHAR(csp->t_stopc, termiosp->c_cc[VSTOP]);
TO_COMPAT_CHAR(csp->t_suspc, termiosp->c_cc[VSUSP]);
TO_COMPAT_CHAR(csp->t_dsuspc, termiosp->c_cc[VDSUSP]);
TO_COMPAT_CHAR(csp->t_rprntc, termiosp->c_cc[VREPRINT]);
TO_COMPAT_CHAR(csp->t_flushc, termiosp->c_cc[VDISCARD]);
TO_COMPAT_CHAR(csp->t_werasc, termiosp->c_cc[VWERASE]);
TO_COMPAT_CHAR(csp->t_lnextc, termiosp->c_cc[VLNEXT]);
csp->t_flags &= (O_CTLECH|O_LITOUT|O_PASS8|O_ODDP|O_EVENP);
if (termiosp->c_iflag & IXOFF)
csp->t_flags |= O_TANDEM;
if (!(termiosp->c_iflag &
(IMAXBEL|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|
INLCR|IGNCR|ICRNL|IUCLC|IXON)) &&
!(termiosp->c_oflag & OPOST) &&
(termiosp->c_cflag & (CSIZE|PARENB)) == CS8 &&
!(termiosp->c_lflag & (ISIG|ICANON|XCASE|IEXTEN)))
csp->t_flags |= O_RAW;
else {
if (!(termiosp->c_iflag & IXON)) {
csp->t_startc = (uchar_t)0377;
csp->t_stopc = (uchar_t)0377;
}
if ((termiosp->c_cflag & (CSIZE|PARENB)) == CS8 &&
!(termiosp->c_oflag & OPOST))
csp->t_flags |= O_LITOUT;
else {
csp->t_flags &= ~O_LITOUT;
if ((termiosp->c_cflag & (CSIZE|PARENB)) == CS8) {
if (!(termiosp->c_iflag & ISTRIP))
csp->t_flags |= O_PASS8;
} else {
csp->t_flags &= ~(O_ODDP|O_EVENP|O_PASS8);
if (termiosp->c_cflag & PARODD)
csp->t_flags |= O_ODDP;
else if (termiosp->c_iflag & INPCK)
csp->t_flags |= O_EVENP;
else
csp->t_flags |= O_ODDP|O_EVENP;
}
if (!(termiosp->c_oflag & OPOST))
csp->t_xflags |= NOPOST;
else
csp->t_xflags &= ~NOPOST;
}
if (!(termiosp->c_lflag & ISIG))
csp->t_xflags |= NOISIG;
else
csp->t_xflags &= ~NOISIG;
if (!(termiosp->c_lflag & ICANON))
csp->t_flags |= O_CBREAK;
if (termiosp->c_lflag & ECHOCTL)
csp->t_flags |= O_CTLECH;
else
csp->t_flags &= ~O_CTLECH;
}
if (termiosp->c_oflag & OLCUC)
csp->t_flags |= O_LCASE;
if (termiosp->c_lflag&ECHO)
csp->t_flags |= O_ECHO;
if (termiosp->c_oflag & ONLCR) {
csp->t_flags |= O_CRMOD;
switch (termiosp->c_oflag & CRDLY) {
case CR2:
csp->t_flags |= O_CR1;
break;
case CR3:
csp->t_flags |= O_CR2;
break;
}
} else {
if ((termiosp->c_oflag & CR1) &&
(termiosp->c_oflag & ONLRET))
csp->t_flags |= O_NL1;
}
if ((termiosp->c_oflag & ONLRET) && (termiosp->c_oflag & NL1))
csp->t_flags |= O_NL2;
switch (termiosp->c_oflag & TABDLY) {
case TAB1:
csp->t_flags |= O_TAB1;
break;
case TAB2:
csp->t_flags |= O_TAB2;
break;
case XTABS:
csp->t_flags |= O_XTABS;
break;
}
if (termiosp->c_oflag & FFDLY)
csp->t_flags |= O_VTDELAY;
if (termiosp->c_oflag & BSDLY)
csp->t_flags |= O_BSDELAY;
if (termiosp->c_lflag & ECHOPRT)
csp->t_flags |= O_PRTERA;
if (termiosp->c_lflag & ECHOE)
csp->t_flags |= (O_CRTERA|O_CRTBS);
if (termiosp->c_lflag & TOSTOP)
csp->t_flags |= O_TOSTOP;
if (termiosp->c_lflag & FLUSHO)
csp->t_flags |= O_FLUSHO;
if (termiosp->c_cflag & CLOCAL)
csp->t_flags |= O_NOHANG;
if (termiosp->c_lflag & ECHOKE)
csp->t_flags |= O_CRTKIL;
if (termiosp->c_lflag & PENDIN)
csp->t_flags |= O_PENDIN;
if (!(termiosp->c_iflag & IXANY))
csp->t_flags |= O_DECCTQ;
if (termiosp->c_lflag & NOFLSH)
csp->t_flags |= O_NOFLSH;
if (termiosp->c_lflag & ICANON) {
TO_COMPAT_CHAR(csp->t_eofc, termiosp->c_cc[VEOF]);
TO_COMPAT_CHAR(csp->t_brkc, termiosp->c_cc[VEOL]);
} else {
termiosp->c_cc[VMIN] = 1;
termiosp->c_cc[VTIME] = 0;
}
}