/* * Message must be of type M_IOCTL or M_IOCDATA for this routine to be called. */ static void ptioc(queue_t *q, mblk_t *mp, int qside) { struct ptem *tp; struct iocblk *iocp; struct winsize *wb; struct jwinsize *jwb; mblk_t *tmp; mblk_t *pckt_msgp; /* message sent to the PCKT module */ int error; iocp = (struct iocblk *)mp->b_rptr; tp = (struct ptem *)q->q_ptr; switch (iocp->ioc_cmd) { case JWINSIZE: /* * For compatibility: If all zeros, NAK the message for dumb * terminals. */ if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) && (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) { miocnak(q, mp, 0, EINVAL); return; } tmp = allocb(sizeof (struct jwinsize), BPRI_MED); if (tmp == NULL) { miocnak(q, mp, 0, EAGAIN); return; } if (iocp->ioc_count == TRANSPARENT) mcopyout(mp, NULL, sizeof (struct jwinsize), NULL, tmp); else mioc2ack(mp, tmp, sizeof (struct jwinsize), 0); jwb = (struct jwinsize *)mp->b_cont->b_rptr; jwb->bytesx = tp->wsz.ws_col; jwb->bytesy = tp->wsz.ws_row; jwb->bitsx = tp->wsz.ws_xpixel; jwb->bitsy = tp->wsz.ws_ypixel; qreply(q, mp); return; case TIOCGWINSZ: /* * If all zeros NAK the message for dumb terminals. */ if ((tp->wsz.ws_row == 0) && (tp->wsz.ws_col == 0) && (tp->wsz.ws_xpixel == 0) && (tp->wsz.ws_ypixel == 0)) { miocnak(q, mp, 0, EINVAL); return; } tmp = allocb(sizeof (struct winsize), BPRI_MED); if (tmp == NULL) { miocnak(q, mp, 0, EAGAIN); return; } mioc2ack(mp, tmp, sizeof (struct winsize), 0); wb = (struct winsize *)mp->b_cont->b_rptr; wb->ws_row = tp->wsz.ws_row; wb->ws_col = tp->wsz.ws_col; wb->ws_xpixel = tp->wsz.ws_xpixel; wb->ws_ypixel = tp->wsz.ws_ypixel; qreply(q, mp); return; case TIOCSWINSZ: error = miocpullup(mp, sizeof (struct winsize)); if (error != 0) { miocnak(q, mp, 0, error); return; } wb = (struct winsize *)mp->b_cont->b_rptr; /* * Send a SIGWINCH signal if the row/col information has * changed. */ if ((tp->wsz.ws_row != wb->ws_row) || (tp->wsz.ws_col != wb->ws_col) || (tp->wsz.ws_xpixel != wb->ws_xpixel) || (tp->wsz.ws_ypixel != wb->ws_xpixel)) { /* * SIGWINCH is always sent upstream. */ if (qside == WRSIDE) (void) putnextctl1(RD(q), M_SIG, SIGWINCH); else if (qside == RDSIDE) (void) putnextctl1(q, M_SIG, SIGWINCH); /* * Message may have come in as an M_IOCDATA; pass it * to the master side as an M_IOCTL. */ mp->b_datap->db_type = M_IOCTL; if (qside == WRSIDE) { /* * Need a copy of this message to pass on to * the PCKT module, only if the M_IOCTL * orginated from the slave side. */ if ((pckt_msgp = copymsg(mp)) == NULL) { miocnak(q, mp, 0, EAGAIN); return; } putnext(q, pckt_msgp); } tp->wsz.ws_row = wb->ws_row; tp->wsz.ws_col = wb->ws_col; tp->wsz.ws_xpixel = wb->ws_xpixel; tp->wsz.ws_ypixel = wb->ws_ypixel; } mioc2ack(mp, NULL, 0, 0); qreply(q, mp); return; case TIOCSIGNAL: { /* * This ioctl can emanate from the master side in remote * mode only. */ int sig; if (DB_TYPE(mp) == M_IOCTL && iocp->ioc_count != TRANSPARENT) { error = miocpullup(mp, sizeof (int)); if (error != 0) { miocnak(q, mp, 0, error); return; } } if (DB_TYPE(mp) == M_IOCDATA || iocp->ioc_count != TRANSPARENT) sig = *(int *)mp->b_cont->b_rptr; else sig = (int)*(intptr_t *)mp->b_cont->b_rptr; if (sig < 1 || sig >= NSIG) { miocnak(q, mp, 0, EINVAL); return; } /* * Send an M_PCSIG message up the slave's read side and * respond back to the master with an ACK or NAK as * appropriate. */ if (putnextctl1(q, M_PCSIG, sig) == 0) { miocnak(q, mp, 0, EAGAIN); return; } mioc2ack(mp, NULL, 0, 0); qreply(q, mp); return; } case TIOCREMOTE: { int onoff; mblk_t *mctlp; if (DB_TYPE(mp) == M_IOCTL) { error = miocpullup(mp, sizeof (int)); if (error != 0) { miocnak(q, mp, 0, error); return; } } onoff = *(int *)mp->b_cont->b_rptr; /* * Send M_CTL up using the iocblk format. */ mctlp = mkiocb(onoff ? MC_NO_CANON : MC_DO_CANON); if (mctlp == NULL) { miocnak(q, mp, 0, EAGAIN); return; } mctlp->b_datap->db_type = M_CTL; putnext(q, mctlp); /* * ACK the ioctl. */ mioc2ack(mp, NULL, 0, 0); qreply(q, mp); /* * Record state change. */ if (onoff) tp->state |= REMOTEMODE; else tp->state &= ~REMOTEMODE; return; } default: putnext(q, mp); return; } }
/* * This routine is called from both ptemwput and ptemwsrv to do the * actual work of dealing with mp. ptmewput will have already * dealt with high priority messages. * * Return 1 if the message was processed completely and 0 if not. */ static int ptemwmsg(queue_t *q, mblk_t *mp) { struct ptem *ntp = (struct ptem *)q->q_ptr; struct iocblk *iocp; /* outgoing ioctl structure */ struct termio *termiop; struct termios *termiosp; mblk_t *dack_ptr; /* disconnect message ACK block */ mblk_t *pckt_msgp; /* message sent to the PCKT module */ mblk_t *dp; /* ioctl reply data */ tcflag_t cflags; int error; switch (mp->b_datap->db_type) { case M_IOCTL: /* * Note: for each "set" type operation a copy * of the M_IOCTL message is made and passed * downstream. Eventually the PCKT module, if * it has been pushed, should pick up this message. * If the PCKT module has not been pushed the master * side stream head will free it. */ iocp = (struct iocblk *)mp->b_rptr; switch (iocp->ioc_cmd) { case TCSETAF: case TCSETSF: /* * Flush the read queue. */ if (putnextctl1(q, M_FLUSH, FLUSHR) == 0) { miocnak(q, mp, 0, EAGAIN); break; } /* FALLTHROUGH */ case TCSETA: case TCSETAW: case TCSETS: case TCSETSW: switch (iocp->ioc_cmd) { case TCSETAF: case TCSETA: case TCSETAW: error = miocpullup(mp, sizeof (struct termio)); if (error != 0) { miocnak(q, mp, 0, error); goto out; } cflags = ((struct termio *) mp->b_cont->b_rptr)->c_cflag; ntp->cflags = (ntp->cflags & 0xffff0000 | cflags); break; case TCSETSF: case TCSETS: case TCSETSW: error = miocpullup(mp, sizeof (struct termios)); if (error != 0) { miocnak(q, mp, 0, error); goto out; } cflags = ((struct termios *) mp->b_cont->b_rptr)->c_cflag; ntp->cflags = cflags; break; } if ((cflags & CBAUD) == B0) { /* * Hang-up: Send a zero length message. */ dack_ptr = ntp->dack_ptr; if (dack_ptr) { ntp->dack_ptr = NULL; /* * Send a zero length message * downstream. */ putnext(q, dack_ptr); } } else { /* * Make a copy of this message and pass it on * to the PCKT module. */ if ((pckt_msgp = copymsg(mp)) == NULL) { miocnak(q, mp, 0, EAGAIN); break; } putnext(q, pckt_msgp); } /* * Send ACK upstream. */ mioc2ack(mp, NULL, 0, 0); qreply(q, mp); out: break; case TCGETA: dp = allocb(sizeof (struct termio), BPRI_MED); if (dp == NULL) { miocnak(q, mp, 0, EAGAIN); break; } termiop = (struct termio *)dp->b_rptr; termiop->c_cflag = (ushort_t)ntp->cflags; mioc2ack(mp, dp, sizeof (struct termio), 0); qreply(q, mp); break; case TCGETS: dp = allocb(sizeof (struct termios), BPRI_MED); if (dp == NULL) { miocnak(q, mp, 0, EAGAIN); break; } termiosp = (struct termios *)dp->b_rptr; termiosp->c_cflag = ntp->cflags; mioc2ack(mp, dp, sizeof (struct termios), 0); qreply(q, mp); break; case TCSBRK: error = miocpullup(mp, sizeof (int)); if (error != 0) { miocnak(q, mp, 0, error); break; } /* * Need a copy of this message to pass it on to * the PCKT module. */ if ((pckt_msgp = copymsg(mp)) == NULL) { miocnak(q, mp, 0, EAGAIN); break; } /* * Send a copy of the M_IOCTL to the PCKT module. */ putnext(q, pckt_msgp); /* * TCSBRK meaningful if data part of message is 0 * cf. termio(7). */ if (!(*(int *)mp->b_cont->b_rptr)) (void) putnextctl(q, M_BREAK); /* * ACK the ioctl. */ mioc2ack(mp, NULL, 0, 0); qreply(q, mp); break; case JWINSIZE: case TIOCGWINSZ: case TIOCSWINSZ: ptioc(q, mp, WRSIDE); break; case TIOCSTI: /* * Simulate typing of a character at the terminal. In * all cases, we acknowledge the ioctl and pass a copy * of it along for the PCKT module to encapsulate. If * not in remote mode, we also process the ioctl * itself, looping the character given as its argument * back around to the read side. */ /* * Need a copy of this message to pass on to the PCKT * module. */ if ((pckt_msgp = copymsg(mp)) == NULL) { miocnak(q, mp, 0, EAGAIN); break; } if ((ntp->state & REMOTEMODE) == 0) { mblk_t *bp; error = miocpullup(mp, sizeof (char)); if (error != 0) { freemsg(pckt_msgp); miocnak(q, mp, 0, error); break; } /* * The permission checking has already been * done at the stream head, since it has to be * done in the context of the process doing * the call. */ if ((bp = allocb(1, BPRI_MED)) == NULL) { freemsg(pckt_msgp); miocnak(q, mp, 0, EAGAIN); break; } /* * XXX: Is EAGAIN really the right response to * flow control blockage? */ if (!bcanputnext(RD(q), mp->b_band)) { freemsg(bp); freemsg(pckt_msgp); miocnak(q, mp, 0, EAGAIN); break; } *bp->b_wptr++ = *mp->b_cont->b_rptr; qreply(q, bp); } putnext(q, pckt_msgp); mioc2ack(mp, NULL, 0, 0); qreply(q, mp); break; case PTSSTTY: if (ntp->state & IS_PTSTTY) { miocnak(q, mp, 0, EEXIST); } else { ntp->state |= IS_PTSTTY; mioc2ack(mp, NULL, 0, 0); qreply(q, mp); } break; default: /* * End of the line. The slave driver doesn't see any * ioctls that we don't explicitly pass along to it. */ miocnak(q, mp, 0, EINVAL); break; } break; case M_DELAY: /* tty delays not supported */ freemsg(mp); break; case M_DATA: if ((mp->b_wptr - mp->b_rptr) < 0) { /* * Free all bad length messages. */ freemsg(mp); break; } else if ((mp->b_wptr - mp->b_rptr) == 0) { if (!(ntp->state & IS_PTSTTY)) { freemsg(mp); break; } } if (ntp->state & OFLOW_CTL) return (0); default: putnext(q, mp); break; } return (1); }
/** * ptem_r_msg - process a message on the read side * @q: read queue * @mp: the message to process * * Returns 1 when the caller (putp or srvp) needs to queue or requeue the * message. Returns 0 when the message has been disposed and the caller must * release its reference to mp. * * Keep this away from the fast path. */ static streams_noinline __unlikely void ptem_r_msg(queue_t *q, mblk_t *mp) { struct iocblk *ioc = (typeof(ioc)) mp->b_rptr; int error = EINVAL; int count = 0; int rval = 0; mblk_t *bp; /* The Stream head is set to recognized all transparent terminal input-output controls and pass them downstream as though they were I_STR input-output controls. There is also the opportunity to register input-output controls with the Stream head using the TIOC_REPLY message. */ if (unlikely(ioc->ioc_count == TRANSPARENT)) { __swerr(); goto nak; } if (!(bp = mp->b_cont)) goto nak; switch (ioc->ioc_cmd) { case TCSBRK: /* When the ptem module receives an M_IOCTL message of type TCSBRK on its read-side queue, it sends an M_IOCACK message downstream and an M_BREAK message upstream. */ if (!pullupmsg(bp, sizeof(int))) goto nak; if (!putnextctl(q, M_BREAK)) { error = EAGAIN; goto nak; } goto ack; case TIOCGWINSZ: { /* Keeps track of the informaiton needed for teh TIOCSWINSZ, TIOCGWINSZ, JWINSIZE, input-output control commands. */ struct ptem *p = PTEM_PRIV(q); extern void __struct_winsize_is_too_large_for_fastbuf(void); if (!(p->flags & PTEM_HAVE_WINSIZE)) goto nak; if (FASTBUF < sizeof(struct winsize)) { __struct_winsize_is_too_large_for_fastbuf(); } /* always have room in a fastbuf */ count = sizeof(p->ws); bp->b_rptr = bp->b_datap->db_base; bp->b_wptr = bp->b_rptr + count; *(struct winsize *) bp->b_rptr = p->ws; goto ack; } #ifdef JWINSIZE case JWINSIZE: /* Keeps track of the informaiton needed for teh TIOCSWINSZ, TIOCGWINSZ, JWINSIZE, input-output control commands. */ { struct ptem *p = PTEM_PRIV(q); struct jwinsize *jws; if (!(p->flags & PTEM_HAVE_WINSIZE)) goto nak; if (FASTBUF < sizeof(struct jwinsize)) __undefined_call_makes_compile_fail(); /* always have room in a fastbuf */ count = sizeof(*jws); bp->b_rptr = bp->b_datap->db_base; bp->b_wptr = bp->b_rptr + count; jws = (typeof(jws)) bp->b_rptr; jws->bytesx = p->ws.ws_col; jws->bytesy = p->ws.ws_row; jws->bitsx = p->ws.ws_xpixel; jws->bitsy = p->ws.ws_ypixel; goto ack; } #endif /* JWINSIZE */ case TIOCSWINSZ: /* Keeps track of the informaiton needed for teh TIOCSWINSZ, TIOCGWINSZ, JWINSIZE, input-output control commands. */ { struct ptem *p = PTEM_PRIV(q); struct winsize *ws; int changed = 0; int zeroed = !(p->flags & PTEM_HAVE_WINSIZE); mblk_t *mb; if (!pullupmsg(bp, sizeof(*ws))) goto nak; if (!(mb = allocb(1, BPRI_MED))) { error = EAGAIN; goto nak; } ws = (typeof(ws)) bp->b_rptr; if (ws->ws_col != p->ws.ws_col) { if ((p->ws.ws_col = ws->ws_col)) zeroed = 0; changed = 1; } if (ws->ws_row != p->ws.ws_row) { if ((p->ws.ws_row = ws->ws_row)) zeroed = 0; changed = 1; } if (ws->ws_xpixel != p->ws.ws_xpixel) { if ((p->ws.ws_xpixel = ws->ws_xpixel)) zeroed = 0; changed = 1; } if (ws->ws_ypixel != p->ws.ws_ypixel) { if ((p->ws.ws_ypixel = ws->ws_ypixel)) zeroed = 0; changed = 1; } if (zeroed) p->flags &= ~PTEM_HAVE_WINSIZE; else p->flags |= PTEM_HAVE_WINSIZE; if (changed) { mb->b_datap->db_type = M_SIG; *mb->b_wptr++ = SIGWINCH; putnext(q, mb); } else freeb(mb); count = 0; goto ack; } #ifdef TIOCSIGNAL case TIOCSIGNAL: #endif /* TIOCSIGNAL */ #ifdef O_TIOCSIGNAL case O_TIOCSIGNAL: #endif /* O_TIOCSIGNAL */ { uint s; if (!pullupmsg(bp, sizeof(s))) goto nak; if ((s = *(uint *) bp->b_rptr) > _NSIG || s == 0) goto nak; if (!putnextctl1(q, M_PCSIG, s)) { error = EAGAIN; goto nak; } count = 0; goto ack; } #ifdef TIOCREMOTE case TIOCREMOTE: #endif /* TIOCREMOTE */ #ifdef O_TIOCREMOTE case O_TIOCREMOTE: #endif /* O_TIOCREMOTE */ { struct ptem *p = PTEM_PRIV(q); struct iocblk *ctl; mblk_t *mb; if (!pullupmsg(bp, sizeof(uint))) goto nak; if (!(mb = allocb(sizeof(*ctl), BPRI_MED))) { error = EAGAIN; goto nak; } mb->b_datap->db_type = M_CTL; ctl = (typeof(ctl)) mb->b_rptr; mb->b_wptr += sizeof(*ctl); bzero(ctl, sizeof(ctl)); if (*(uint *) bp->b_rptr) { ctl->ioc_cmd = MC_NO_CANON; p->flags |= PTEM_REMOTE_MODE; } else { ctl->ioc_cmd = MC_DO_CANON; p->flags &= ~PTEM_REMOTE_MODE; } putnext(q, mb); count = 0; goto ack; } default: break; } putnext(q, mp); return; ack: mp->b_datap->db_type = M_IOCNAK; ioc->ioc_error = error; ioc->ioc_rval = -1; ioc->ioc_count = 0; reply: qreply(q, mp); return; nak: mp->b_datap->db_type = M_IOCACK; ioc->ioc_error = error; ioc->ioc_rval = rval; ioc->ioc_count = count; goto reply; }
/* * cvc_win_resize() * cvc_win_resize will read winsize data from the CONC IOSRAM chunk and set * the console window size accordingly. If indicated by the caller, CONC's * data_valid flag will also be cleared. The flag isn't cleared in all * cases because we need to process winsize data at startup without waiting * for a command. */ static void cvc_win_resize(int clear_flag) { int rval; uint16_t rows; uint16_t cols; uint16_t xpixels; uint16_t ypixels; tty_common_t *tty; cvc_t *cp; struct winsize ws; /* * Start by reading the new window size out of the CONC chunk and, if * requested, clearing CONC's data_valid flag. If any of that fails, * return immediately. (Note that the rather bulky condition in the * two "if" statements takes advantage of C's short-circuit logic * evaluation) */ if (((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_rows), CVC_CTL_SIZE(winsize_rows), (caddr_t)&rows)) != 0) || ((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_cols), CVC_CTL_SIZE(winsize_cols), (caddr_t)&cols)) != 0) || ((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_xpixels), CVC_CTL_SIZE(winsize_xpixels), (caddr_t)&xpixels)) != 0) || ((rval = iosram_rd(IOSRAM_KEY_CONC, CVC_CTL_OFFSET(winsize_ypixels), CVC_CTL_SIZE(winsize_ypixels), (caddr_t)&ypixels)) != 0)) { if (rval != EAGAIN) { cmn_err(CE_WARN, "cvc_win_resize: read for ctlbuf ret %d", rval); } return; } if (clear_flag && ((rval = iosram_set_flag(IOSRAM_KEY_CONC, IOSRAM_DATA_INVALID, IOSRAM_INT_NONE)) != 0)) { if (rval != EAGAIN) { cmn_err(CE_WARN, "cvc_win_resize: set_flag for ctlbuf ret %d", rval); } return; } /* * Copy the parameters from IOSRAM to a winsize struct. */ ws.ws_row = rows; ws.ws_col = cols; ws.ws_xpixel = xpixels; ws.ws_ypixel = ypixels; /* * This code was taken from Starfire, and it appears to work correctly. * However, since the original developer felt it necessary to add the * following comment, it's probably worth preserving: * * XXX I hope this is safe... */ cp = cvcinput_q->q_ptr; tty = &cp->cvc_tty; mutex_enter(&tty->t_excl); if (bcmp((caddr_t)&tty->t_size, (caddr_t)&ws, sizeof (struct winsize))) { tty->t_size = ws; mutex_exit(&tty->t_excl); (void) putnextctl1(cvcinput_q, M_PCSIG, SIGWINCH); } else { mutex_exit(&tty->t_excl); } }
/** * ptem_w_msg - process a message on the write side * @q: write queue * @mp: message to process * * Returns 1 when the caller (putp or srvp) needs to queue or requeue the * message. Returns 0 when the message has been disposed and the caller must * release its reference to mp. * * Keep this function out of the way of the fastpath. */ static streams_noinline int ptem_w_msg(queue_t *q, mblk_t *mp) { struct ptem *p = PTEM_PRIV(q); /* fast path */ if (likely(mp->b_datap->db_type == M_DATA)) { m_data: if ((p->flags & PTEM_OUTPUT_STOPPED) || (q->q_first != NULL) || (q->q_flag & QSVCBUSY) || (!bcanputnext(q, mp->b_band))) return (1); putnext(q, mp); return (0); } switch (mp->b_datap->db_type) { case M_DATA: goto m_data; case M_IOCTL: { struct iocblk *ioc = (struct iocblk *) mp->b_rptr; int error = EINVAL; int rval = 0; int count = 0; mblk_t *bp, *cp; /* The Stream head is set to recognized all transparent terminal input-output controls and pass them downstream as though they were I_STR input-output controls. There is also the opportunity to register input-output controls with the Stream head using the TIOC_REPLY message. */ if (ioc->ioc_count == TRANSPARENT) { __swerr(); goto nak; } if ((bp = mp->b_cont) == NULL) goto nak; switch (ioc->ioc_cmd) { case TCSETAF: /* Note, if properly handled the M_FLUSH message will never be queued and upon successful return from this function, we have already processed the read-side flush along the entire Stream. */ if (!putnextctl1(q, M_FLUSH, FLUSHR)) { error = EAGAIN; goto nak; } /* fall through */ case TCSETAW: /* Note, output should have already drained. */ /* fall through */ case TCSETA: { struct termio *c; mblk_t *zp; if (!pullupmsg(bp, sizeof(struct termio))) goto nak; c = (typeof(c)) bp->b_rptr; if ((c->c_cflag & CBAUD) == B0) { /* slave hangup */ if ((zp = xchg(&p->zero, NULL))) putnext(q, zp); } else { if (!(cp = copymsg(mp))) { error = EAGAIN; goto nak; } p->c.c_iflag = (p->c.c_iflag & 0xffff0000) | c->c_iflag; p->c.c_oflag = (p->c.c_oflag & 0xffff0000) | c->c_oflag; p->c.c_cflag = (p->c.c_cflag & 0xffff0000) | c->c_cflag; p->c.c_lflag = (p->c.c_lflag & 0xffff0000) | c->c_lflag; p->c.c_line = c->c_line; bcopy(c->c_cc, p->c.c_cc, NCC); putnext(q, cp); } goto ack; } case TCSETSF: /* Note, if properly handled the M_FLUSH message will never be queued and upon successful return from this function, we have already processed the read-side flush along the entire Stream. */ if (!putnextctl1(q, M_FLUSH, FLUSHR)) { error = EAGAIN; goto nak; } /* fall through */ case TCSETSW: /* Note, output should have already drained. */ /* fall through */ case TCSETS: { struct termios *c; mblk_t *zp; if (!pullupmsg(bp, sizeof(struct termios))) goto nak; c = (typeof(c)) bp->b_rptr; if ((c->c_cflag & CBAUD) == B0) { /* slave hangup */ if ((zp = xchg(&p->zero, NULL))) putnext(q, zp); } else { if (!(cp = copymsg(mp))) { error = EAGAIN; goto nak; } p->c = *c; putnext(q, cp); } goto ack; } case TCGETA: { struct termio *c; extern void __struct_termio_is_too_large_for_fastbuf(void); if (FASTBUF < sizeof(struct termio)) __struct_termio_is_too_large_for_fastbuf(); count = sizeof(*c); bp->b_rptr = bp->b_datap->db_base; bp->b_wptr = bp->b_rptr + count; c = (typeof(c)) bp->b_rptr; c->c_iflag = p->c.c_iflag; c->c_oflag = p->c.c_oflag; c->c_cflag = p->c.c_cflag; c->c_lflag = p->c.c_lflag; c->c_line = p->c.c_line; bcopy(p->c.c_cc, p->c.c_cc, NCC); goto ack; } case TCGETS: { extern void __struct_termios_is_too_large_for_fastbuf(void); if (FASTBUF < sizeof(struct termios)) __struct_termios_is_too_large_for_fastbuf(); count = sizeof(p->c); bp->b_rptr = bp->b_datap->db_base; bp->b_wptr = bp->b_rptr + count; *((struct termios *) bp->b_rptr) = p->c; goto ack; } case TIOCGWINSZ: { extern void __struct_winsize_is_too_large_for_fastbuf(void); if (!(p->flags & PTEM_HAVE_WINSIZE)) goto nak; if (FASTBUF < sizeof(struct winsize)) __struct_winsize_is_too_large_for_fastbuf(); count = sizeof(p->ws); bp->b_rptr = bp->b_datap->db_base; bp->b_wptr = bp->b_rptr + count; *((struct winsize *) bp->b_rptr) = p->ws; goto ack; } #ifdef JWINSIZE case JWINSIZE: { struct jwinsize *jws; extern void __struct_jwinsize_is_too_large_for_fastbuf(void); if (!(p->flags & PTEM_HAVE_WINSIZE)) goto nak; if (FASTBUF < sizeof(struct jwinsize)) __struct_jwinsize_is_too_large_for_fastbuf(); /* always have room in a fastbuf */ count = sizeof(*jws); bp->b_rptr = bp->b_datap->db_base; bp->b_wptr = bp->b_rptr + count; jws = (typeof(jws)) bp->b_rptr; jws->bytesx = p->ws.ws_col; jws->bytesy = p->ws.ws_row; jws->bitsx = p->ws.ws_xpixel; jws->bitsy = p->ws.ws_ypixel; goto ack; } #endif /* JWINSIZE */ case TIOCSWINSZ: { struct winsize *ws; int changed = 0; int zeroed = !(p->flags & PTEM_HAVE_WINSIZE); mblk_t *mb; if (!pullupmsg(bp, sizeof(*ws))) goto nak; if (!(cp = copymsg(mp))) { error = EAGAIN; goto nak; } if (!(mb = allocb(1, BPRI_MED))) { freemsg(cp); error = EAGAIN; goto nak; } ws = (typeof(ws)) bp->b_rptr; if (ws->ws_col != p->ws.ws_col) { if ((p->ws.ws_col = ws->ws_col)) zeroed = 0; changed = 1; } if (ws->ws_row != p->ws.ws_row) { if ((p->ws.ws_row = ws->ws_row)) zeroed = 0; changed = 1; } if (ws->ws_xpixel != p->ws.ws_xpixel) { if ((p->ws.ws_xpixel = ws->ws_xpixel)) zeroed = 0; changed = 1; } if (ws->ws_ypixel != p->ws.ws_ypixel) { if ((p->ws.ws_ypixel = ws->ws_ypixel)) zeroed = 0; changed = 1; } if (zeroed) p->flags &= ~PTEM_HAVE_WINSIZE; else p->flags |= PTEM_HAVE_WINSIZE; if (changed) { mb->b_datap->db_type = M_SIG; *mb->b_wptr++ = SIGWINCH; qreply(q, mb); } else freeb(mb); putnext(q, cp); /* copy for pctk(4) */ count = 0; goto ack; } case TCSBRK: if (!(cp = copymsg(mp))) { error = EAGAIN; goto nak; } putnext(q, cp); count = 0; goto ack; default: goto nak; } break; ack: mp->b_datap->db_type = M_IOCACK; ioc->ioc_error = 0; ioc->ioc_rval = rval; ioc->ioc_count = count; goto reply; nak: mp->b_datap->db_type = M_IOCNAK; ioc->ioc_error = error; ioc->ioc_rval = -1; ioc->ioc_count = 0; reply: qreply(q, mp); break; } case M_FLUSH: if (mp->b_rptr[0] & FLUSHW) { if (mp->b_rptr[0] & FLUSHBAND) flushband(q, mp->b_rptr[1], FLUSHDATA); else flushq(q, FLUSHDATA); } putnext(q, mp); break; default: if (mp->b_datap->db_type < QPCTL) { if ((q->q_first != NULL) || (q->q_flag & QSVCBUSY) || (!bcanputnext(q, mp->b_band))) return (1); /* (re)queue */ } putnext(q, mp); break; } return (0); }