static void ptsstop(struct tty *tp, int flush) { struct pt_ioctl *pti = tp->t_dev->si_drv1; int flag; lwkt_gettoken(&tty_token); /* note: FLUSHREAD and FLUSHWRITE already ok */ if (pti) { if (flush == 0) { flush = TIOCPKT_STOP; pti->pt_flags |= PF_STOPPED; } else { pti->pt_flags &= ~PF_STOPPED; } pti->pt_send |= flush; /* change of perspective */ } flag = 0; if (flush & FREAD) flag |= FWRITE; if (flush & FWRITE) flag |= FREAD; ptcwakeup(tp, flag); lwkt_reltoken(&tty_token); }
int ptsclose(dev_t dev, int flag, int mode, struct proc *p) { struct pt_softc *pti = pt_softc[minor(dev)]; struct tty *tp = pti->pt_tty; int error; error = (*linesw[tp->t_line].l_close)(tp, flag); error |= ttyclose(tp); ptcwakeup(tp, FREAD|FWRITE); return (error); }
/* * Start output on pseudo-tty. * Wake up process polling or sleeping for input from controlling tty. */ void ptsstart(struct tty *tp) { struct pt_softc *pti = pt_softc[minor(tp->t_dev)]; if (tp->t_state & TS_TTSTOP) return; if (pti->pt_flags & PF_STOPPED) { pti->pt_flags &= ~PF_STOPPED; pti->pt_send = TIOCPKT_START; } ptcwakeup(tp, FREAD); }
int ptsread(dev_t dev, struct uio *uio, int flag) { struct proc *p = curproc; struct process *pr = p->p_p; struct pt_softc *pti = pt_softc[minor(dev)]; struct tty *tp = pti->pt_tty; int error = 0; again: if (pti->pt_flags & PF_REMOTE) { while (isbackground(pr, tp)) { if ((p->p_sigacts->ps_sigignore & sigmask(SIGTTIN)) || (p->p_sigmask & sigmask(SIGTTIN)) || pr->ps_pgrp->pg_jobc == 0 || pr->ps_flags & PS_PPWAIT) return (EIO); pgsignal(pr->ps_pgrp, SIGTTIN, 1); error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0); if (error) return (error); } if (tp->t_canq.c_cc == 0) { if (flag & IO_NDELAY) return (EWOULDBLOCK); error = ttysleep(tp, &tp->t_canq, TTIPRI | PCATCH, ttyin, 0); if (error) return (error); goto again; } while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) if (ureadc(getc(&tp->t_canq), uio) < 0) { error = EFAULT; break; } if (tp->t_canq.c_cc == 1) (void) getc(&tp->t_canq); if (tp->t_canq.c_cc) return (error); } else if (tp->t_oproc) error = (*linesw[tp->t_line].l_read)(tp, uio, flag); ptcwakeup(tp, FWRITE); return (error); }
/* * Start output on pseudo-tty. * Wake up process selecting or sleeping for input from controlling tty. */ static void ptsstart(struct tty *tp) { lwkt_gettoken(&tty_token); struct pt_ioctl *pti = tp->t_dev->si_drv1; if (tp->t_state & TS_TTSTOP) { lwkt_reltoken(&tty_token); return; } if (pti) { if (pti->pt_flags & PF_STOPPED) { pti->pt_flags &= ~PF_STOPPED; pti->pt_send = TIOCPKT_START; } } ptcwakeup(tp, FREAD); lwkt_reltoken(&tty_token); }
/*ARGSUSED*/ int ptsopen(dev_t dev, int flag, int devtype, struct proc *p) { struct pt_softc *pti; struct tty *tp; int error; if ((error = check_pty(minor(dev)))) return (error); pti = pt_softc[minor(dev)]; if (!pti->pt_tty) { tp = pti->pt_tty = ttymalloc(); } else tp = pti->pt_tty; if ((tp->t_state & TS_ISOPEN) == 0) { tp->t_state |= TS_WOPEN; ttychars(tp); /* Set up default chars */ tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; ttsetwater(tp); /* would be done in xxparam() */ } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) return (EBUSY); if (tp->t_oproc) /* Ctrlr still around. */ tp->t_state |= TS_CARR_ON; while ((tp->t_state & TS_CARR_ON) == 0) { tp->t_state |= TS_WOPEN; if (flag&FNONBLOCK) break; error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, ttopen, 0); if (error) return (error); } error = (*linesw[tp->t_line].l_open)(dev, tp); ptcwakeup(tp, FREAD|FWRITE); return (error); }
int ptsstop(struct tty *tp, int flush) { struct pt_softc *pti = pt_softc[minor(tp->t_dev)]; int flag; /* note: FLUSHREAD and FLUSHWRITE already ok */ if (flush == 0) { flush = TIOCPKT_STOP; pti->pt_flags |= PF_STOPPED; } else pti->pt_flags &= ~PF_STOPPED; pti->pt_send |= flush; /* change of perspective */ flag = 0; if (flush & FREAD) flag |= FWRITE; if (flush & FWRITE) flag |= FREAD; ptcwakeup(tp, flag); return 0; }
static int ptsclose(struct dev_close_args *ap) { cdev_t dev = ap->a_head.a_dev; struct tty *tp; struct pt_ioctl *pti = dev->si_drv1; int err; lwkt_gettoken(&tty_token); if (pti_hold(pti)) panic("ptsclose on terminated pti"); /* * Disconnect the slave side */ tp = dev->si_tty; err = (*linesw[tp->t_line].l_close)(tp, ap->a_fflag); ptsstop(tp, FREAD|FWRITE); ttyclose(tp); /* clears t_state */ /* * Mark the pts side closed and signal the ptc. Do not mark the * tty a zombie... that is, allow the tty to be re-opened as long * as the ptc is still open. The ptc will read() EOFs until the * pts side is reopened or the ptc is closed. * * xterm() depends on this behavior as it will revoke() the pts * and then reopen it after the (unnecessary old code) chmod. */ pti->pt_flags &= ~PF_SOPEN; pti->pt_flags |= PF_SCLOSED; if (tp->t_oproc) ptcwakeup(tp, FREAD); pti_done(pti); lwkt_reltoken(&tty_token); return (err); }
/*ARGSUSED*/ int ptyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { struct pt_softc *pti = pt_softc[minor(dev)]; struct tty *tp = pti->pt_tty; u_char *cc = tp->t_cc; int stop, error; /* * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. * ttywflush(tp) will hang if there are characters in the outq. */ if (cmd == TIOCEXT) { /* * When the EXTPROC bit is being toggled, we need * to send an TIOCPKT_IOCTL if the packet driver * is turned on. */ if (*(int *)data) { if (pti->pt_flags & PF_PKT) { pti->pt_send |= TIOCPKT_IOCTL; ptcwakeup(tp, FREAD); } tp->t_lflag |= EXTPROC; } else { if ((tp->t_lflag & EXTPROC) && (pti->pt_flags & PF_PKT)) { pti->pt_send |= TIOCPKT_IOCTL; ptcwakeup(tp, FREAD); } tp->t_lflag &= ~EXTPROC; } return(0); } else if (cdevsw[major(dev)].d_open == ptcopen) switch (cmd) { case TIOCGPGRP: #ifdef COMPAT_SUNOS { /* * I'm not sure about SunOS TIOCGPGRP semantics * on PTYs, but it's something like this: */ extern struct emul emul_sunos; if (p->p_emul == &emul_sunos) { if (tp->t_pgrp == 0) return (EIO); *(int *)data = tp->t_pgrp->pg_id; return (0); } } #endif /* * We avoid calling ttioctl on the controller since, * in that case, tp must be the controlling terminal. */ *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; return (0); case TIOCPKT: if (*(int *)data) { if (pti->pt_flags & PF_UCNTL) return (EINVAL); pti->pt_flags |= PF_PKT; } else pti->pt_flags &= ~PF_PKT; return (0); case TIOCUCNTL: if (*(int *)data) { if (pti->pt_flags & PF_PKT) return (EINVAL); pti->pt_flags |= PF_UCNTL; } else pti->pt_flags &= ~PF_UCNTL; return (0); case TIOCREMOTE: if (*(int *)data) pti->pt_flags |= PF_REMOTE; else pti->pt_flags &= ~PF_REMOTE; ttyflush(tp, FREAD|FWRITE); return (0); #ifdef COMPAT_OLDTTY case TIOCSETP: case TIOCSETN: #endif case TIOCSETD: case TIOCSETA: case TIOCSETAW: case TIOCSETAF: ndflush(&tp->t_outq, tp->t_outq.c_cc); break; case TIOCSIG: if (*(unsigned int *)data >= NSIG || *(unsigned int *)data == 0) return(EINVAL); if ((tp->t_lflag&NOFLSH) == 0) ttyflush(tp, FREAD|FWRITE); pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); if ((*(unsigned int *)data == SIGINFO) && ((tp->t_lflag&NOKERNINFO) == 0)) ttyinfo(tp); return(0); } error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); if (error < 0) error = ttioctl(tp, cmd, data, flag, p); if (error < 0) { if (pti->pt_flags & PF_UCNTL && (cmd & ~0xff) == UIOCCMD(0)) { if (cmd & 0xff) { pti->pt_ucntl = (u_char)cmd; ptcwakeup(tp, FREAD); } return (0); } error = ENOTTY; } /* * If external processing and packet mode send ioctl packet. */ if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) { switch (cmd) { case TIOCSETA: case TIOCSETAW: case TIOCSETAF: #ifdef COMPAT_OLDTTY case TIOCSETP: case TIOCSETN: case TIOCSETC: case TIOCSLTC: case TIOCLBIS: case TIOCLBIC: case TIOCLSET: #endif pti->pt_send |= TIOCPKT_IOCTL; ptcwakeup(tp, FREAD); default: break; } } stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) && CCEQ(cc[VSTART], CTRL('q')); if (pti->pt_flags & PF_NOSTOP) { if (stop) { pti->pt_send &= ~TIOCPKT_NOSTOP; pti->pt_send |= TIOCPKT_DOSTOP; pti->pt_flags &= ~PF_NOSTOP; ptcwakeup(tp, FREAD); } } else { if (!stop) { pti->pt_send &= ~TIOCPKT_DOSTOP; pti->pt_send |= TIOCPKT_NOSTOP; pti->pt_flags |= PF_NOSTOP; ptcwakeup(tp, FREAD); } } return (error); }
static int ptsread(struct dev_read_args *ap) { cdev_t dev = ap->a_head.a_dev; struct proc *p = curproc; struct tty *tp = dev->si_tty; struct pt_ioctl *pti = dev->si_drv1; struct lwp *lp; int error = 0; lp = curthread->td_lwp; lwkt_gettoken(&tty_token); again: if (pti->pt_flags & PF_REMOTE) { while (isbackground(p, tp)) { if (SIGISMEMBER(p->p_sigignore, SIGTTIN) || SIGISMEMBER(lp->lwp_sigmask, SIGTTIN) || p->p_pgrp->pg_jobc == 0 || (p->p_flags & P_PPWAIT)) { lwkt_reltoken(&tty_token); return (EIO); } pgsignal(p->p_pgrp, SIGTTIN, 1); error = ttysleep(tp, &lbolt, PCATCH, "ptsbg", 0); if (error) { lwkt_reltoken(&tty_token); return (error); } } if (tp->t_canq.c_cc == 0) { if (ap->a_ioflag & IO_NDELAY) { lwkt_reltoken(&tty_token); return (EWOULDBLOCK); } error = ttysleep(tp, TSA_PTS_READ(tp), PCATCH, "ptsin", 0); if (error) { lwkt_reltoken(&tty_token); return (error); } goto again; } while (tp->t_canq.c_cc > 1 && ap->a_uio->uio_resid > 0) if (ureadc(clist_getc(&tp->t_canq), ap->a_uio) < 0) { error = EFAULT; break; } if (tp->t_canq.c_cc == 1) clist_getc(&tp->t_canq); if (tp->t_canq.c_cc) { lwkt_reltoken(&tty_token); return (error); } } else if (tp->t_oproc) error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag); ptcwakeup(tp, FWRITE); lwkt_reltoken(&tty_token); return (error); }
/*ARGSUSED*/ static int ptsopen(struct dev_open_args *ap) { cdev_t dev = ap->a_head.a_dev; struct tty *tp; int error; struct pt_ioctl *pti; /* * The pti will already be assigned by the clone code or * pre-created if a non-unix 98 pty. If si_drv1 is NULL * we are somehow racing a unix98 termination. */ if (dev->si_drv1 == NULL) return(ENXIO); pti = dev->si_drv1; lwkt_gettoken(&tty_token); if (pti_hold(pti)) { lwkt_reltoken(&tty_token); return(ENXIO); } tp = dev->si_tty; /* * Reinit most of the tty state if it isn't open. Handle * exclusive access. */ if ((tp->t_state & TS_ISOPEN) == 0) { ttychars(tp); /* Set up default chars */ tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; } else if ((tp->t_state & TS_XCLUDE) && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) { pti_done(pti); lwkt_reltoken(&tty_token); return (EBUSY); } else if (pti->pt_prison != ap->a_cred->cr_prison) { pti_done(pti); lwkt_reltoken(&tty_token); return (EBUSY); } /* * If the ptc is already present this will connect us up. It * is unclear if this is actually needed. * * If neither side is open be sure to clear any left over * ZOMBIE state before continuing. */ if (tp->t_oproc) (void)(*linesw[tp->t_line].l_modem)(tp, 1); else if ((pti->pt_flags & PF_SOPEN) == 0) tp->t_state &= ~TS_ZOMBIE; /* * Wait for the carrier (ptc side) */ while ((tp->t_state & TS_CARR_ON) == 0) { if (ap->a_oflags & FNONBLOCK) break; error = ttysleep(tp, TSA_CARR_ON(tp), PCATCH, "ptsopn", 0); if (error) { pti_done(pti); lwkt_reltoken(&tty_token); return (error); } } /* * Mark the tty open and mark the slave side as being open. */ error = (*linesw[tp->t_line].l_open)(dev, tp); if (error == 0) { pti->pt_flags |= PF_SOPEN; pti->pt_flags &= ~PF_SCLOSED; ptcwakeup(tp, FREAD|FWRITE); } pti_done(pti); lwkt_reltoken(&tty_token); return (error); }
/*ARGSUSED*/ static int ptyioctl(struct dev_ioctl_args *ap) { cdev_t dev = ap->a_head.a_dev; struct tty *tp = dev->si_tty; struct pt_ioctl *pti = dev->si_drv1; u_char *cc = tp->t_cc; int stop, error; lwkt_gettoken(&tty_token); if (dev_dflags(dev) & D_MASTER) { switch (ap->a_cmd) { case TIOCGPGRP: /* * We avoid calling ttioctl on the controller since, * in that case, tp must be the controlling terminal. */ *(int *)ap->a_data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0; lwkt_reltoken(&tty_token); return (0); case TIOCPKT: if (*(int *)ap->a_data) { if (pti->pt_flags & PF_UCNTL) { lwkt_reltoken(&tty_token); return (EINVAL); } pti->pt_flags |= PF_PKT; } else { pti->pt_flags &= ~PF_PKT; } lwkt_reltoken(&tty_token); return (0); case TIOCUCNTL: if (*(int *)ap->a_data) { if (pti->pt_flags & PF_PKT) { lwkt_reltoken(&tty_token); return (EINVAL); } pti->pt_flags |= PF_UCNTL; } else { pti->pt_flags &= ~PF_UCNTL; } lwkt_reltoken(&tty_token); return (0); case TIOCREMOTE: if (*(int *)ap->a_data) pti->pt_flags |= PF_REMOTE; else pti->pt_flags &= ~PF_REMOTE; ttyflush(tp, FREAD|FWRITE); lwkt_reltoken(&tty_token); return (0); #ifdef UNIX98_PTYS case TIOCISPTMASTER: if ((pti->pt_flags & PF_UNIX98) && (pti->devc == dev)) { lwkt_reltoken(&tty_token); return (0); } else { lwkt_reltoken(&tty_token); return (EINVAL); } } #endif /* * The rest of the ioctls shouldn't be called until * the slave is open. */ if ((tp->t_state & TS_ISOPEN) == 0) { lwkt_reltoken(&tty_token); return (EAGAIN); } switch (ap->a_cmd) { #ifdef COMPAT_43 case TIOCSETP: case TIOCSETN: #endif case TIOCSETD: case TIOCSETA: case TIOCSETAW: case TIOCSETAF: /* * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. * ttywflush(tp) will hang if there are characters in * the outq. */ ndflush(&tp->t_outq, tp->t_outq.c_cc); break; case TIOCSIG: if (*(unsigned int *)ap->a_data >= NSIG || *(unsigned int *)ap->a_data == 0) { lwkt_reltoken(&tty_token); return(EINVAL); } if ((tp->t_lflag&NOFLSH) == 0) ttyflush(tp, FREAD|FWRITE); pgsignal(tp->t_pgrp, *(unsigned int *)ap->a_data, 1); if ((*(unsigned int *)ap->a_data == SIGINFO) && ((tp->t_lflag&NOKERNINFO) == 0)) ttyinfo(tp); lwkt_reltoken(&tty_token); return(0); } } if (ap->a_cmd == TIOCEXT) { /* * When the EXTPROC bit is being toggled, we need * to send an TIOCPKT_IOCTL if the packet driver * is turned on. */ if (*(int *)ap->a_data) { if (pti->pt_flags & PF_PKT) { pti->pt_send |= TIOCPKT_IOCTL; ptcwakeup(tp, FREAD); } tp->t_lflag |= EXTPROC; } else { if ((tp->t_lflag & EXTPROC) && (pti->pt_flags & PF_PKT)) { pti->pt_send |= TIOCPKT_IOCTL; ptcwakeup(tp, FREAD); } tp->t_lflag &= ~EXTPROC; } lwkt_reltoken(&tty_token); return(0); } error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data, ap->a_fflag, ap->a_cred); if (error == ENOIOCTL) error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag); if (error == ENOIOCTL) { if (pti->pt_flags & PF_UCNTL && (ap->a_cmd & ~0xff) == UIOCCMD(0)) { if (ap->a_cmd & 0xff) { pti->pt_ucntl = (u_char)ap->a_cmd; ptcwakeup(tp, FREAD); } lwkt_reltoken(&tty_token); return (0); } error = ENOTTY; } /* * If external processing and packet mode send ioctl packet. */ if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) { switch(ap->a_cmd) { case TIOCSETA: case TIOCSETAW: case TIOCSETAF: #ifdef COMPAT_43 case TIOCSETP: case TIOCSETN: #endif #if defined(COMPAT_43) || defined(COMPAT_SUNOS) case TIOCSETC: case TIOCSLTC: case TIOCLBIS: case TIOCLBIC: case TIOCLSET: #endif pti->pt_send |= TIOCPKT_IOCTL; ptcwakeup(tp, FREAD); default: break; } } stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) && CCEQ(cc[VSTART], CTRL('q')); if (pti->pt_flags & PF_NOSTOP) { if (stop) { pti->pt_send &= ~TIOCPKT_NOSTOP; pti->pt_send |= TIOCPKT_DOSTOP; pti->pt_flags &= ~PF_NOSTOP; ptcwakeup(tp, FREAD); } } else { if (!stop) { pti->pt_send &= ~TIOCPKT_DOSTOP; pti->pt_send |= TIOCPKT_NOSTOP; pti->pt_flags |= PF_NOSTOP; ptcwakeup(tp, FREAD); } } lwkt_reltoken(&tty_token); return (error); }