diff options
Diffstat (limited to 'sys/kern/tty_pty.c')
-rw-r--r-- | sys/kern/tty_pty.c | 810 |
1 files changed, 59 insertions, 751 deletions
diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c index 3827e82..e2edd21 100644 --- a/sys/kern/tty_pty.c +++ b/sys/kern/tty_pty.c @@ -1,6 +1,9 @@ /*- - * Copyright (c) 1982, 1986, 1989, 1993 - * The Regents of the University of California. All rights reserved. + * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Portions of this software were developed under sponsorship from Snow + * B.V., the Netherlands. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,14 +13,11 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -25,793 +25,101 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95 */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/* - * Pseudo-teletype Driver - * (Actually two drivers, requiring two entries in 'cdevsw') - */ -#include "opt_compat.h" -#include "opt_tty.h" #include <sys/param.h> -#include <sys/systm.h> -#include <sys/libkern.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/sx.h> -#if defined(COMPAT_43TTY) -#include <sys/ioctl_compat.h> -#endif -#include <sys/priv.h> -#include <sys/proc.h> -#include <sys/tty.h> #include <sys/conf.h> +#include <sys/eventhandler.h> #include <sys/fcntl.h> -#include <sys/poll.h> #include <sys/kernel.h> -#include <sys/uio.h> -#include <sys/signalvar.h> -#include <sys/malloc.h> - -static MALLOC_DEFINE(M_PTY, "ptys", "pty data structures"); - -static void ptsstart(struct tty *tp); -static void ptsstop(struct tty *tp, int rw); -static void ptcwakeup(struct tty *tp, int flag); -static struct cdev *ptyinit(struct cdev *cdev, struct thread *td); - -static d_open_t ptsopen; -static d_close_t ptsclose; -static d_read_t ptsread; -static d_write_t ptswrite; -static d_ioctl_t ptsioctl; -static d_open_t ptcopen; -static d_close_t ptcclose; -static d_read_t ptcread; -static d_ioctl_t ptcioctl; -static d_write_t ptcwrite; -static d_poll_t ptcpoll; - -static struct cdevsw pts_cdevsw = { - .d_version = D_VERSION, - .d_open = ptsopen, - .d_close = ptsclose, - .d_read = ptsread, - .d_write = ptswrite, - .d_ioctl = ptsioctl, - .d_name = "pts", - .d_flags = D_TTY | D_NEEDGIANT, -}; - -static struct cdevsw ptc_cdevsw = { - .d_version = D_VERSION, - .d_open = ptcopen, - .d_close = ptcclose, - .d_read = ptcread, - .d_write = ptcwrite, - .d_ioctl = ptcioctl, - .d_poll = ptcpoll, - .d_name = "ptc", - .d_flags = D_TTY | D_NEEDGIANT, -}; - -static struct mtx ptyinit_lock; -MTX_SYSINIT(ptyinit_lock, &ptyinit_lock, "ptyinit", MTX_DEF); - -#define BUFSIZ 100 /* Chunk size iomoved to/from user */ - -struct ptsc { - int pt_flags; - struct selinfo pt_selr, pt_selw; - u_char pt_send; - u_char pt_ucntl; - struct tty *pt_tty; - struct cdev *devs, *devc; - int pt_devs_open, pt_devc_open; - struct prison *pt_prison; -}; - -#define PF_PKT 0x08 /* packet mode */ -#define PF_STOPPED 0x10 /* user told stopped */ -#define PF_NOSTOP 0x40 -#define PF_UCNTL 0x80 /* user control mode */ - -#define TSA_PTC_READ(tp) ((void *)&(tp)->t_outq.c_cf) -#define TSA_PTC_WRITE(tp) ((void *)&(tp)->t_rawq.c_cl) -#define TSA_PTS_READ(tp) ((void *)&(tp)->t_canq) +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/tty.h> -static const char names[] = "pqrsPQRSlmnoLMNO"; /* - * This function creates and initializes a pts/ptc pair - * - * pts == /dev/tty[pqrsPQRSlmnoLMNO][0123456789abcdefghijklmnopqrstuv] - * ptc == /dev/pty[pqrsPQRSlmnoLMNO][0123456789abcdefghijklmnopqrstuv] + * This driver implements a BSD-style compatibility naming scheme for + * the pts(4) driver. We just call into pts(4) to create the actual PTY. + * To make sure we don't use the same PTY multiple times, we abuse + * si_drv1 inside the cdev to mark whether the PTY is in use. */ -static struct cdev * -ptyinit(struct cdev *devc, struct thread *td) -{ - struct ptsc *pt; - int n; - n = minor2unit(minor(devc)); +static int pty_warningcnt = 10; - /* We only allow for up to 32 ptys per char in "names". */ - if (n >= 32 * (sizeof(names) - 1)) - return (NULL); - - devc->si_flags &= ~SI_CHEAPCLONE; - - /* - * Initially do not create a slave endpoint. - */ - pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO); - pt->devc = devc; - - pt->pt_tty = ttyalloc(); - pt->pt_tty->t_sc = pt; - mtx_lock(&ptyinit_lock); - if (devc->si_drv1 == NULL) { - devc->si_drv1 = pt; - devc->si_tty = pt->pt_tty; - mtx_unlock(&ptyinit_lock); - } else { - mtx_unlock(&ptyinit_lock); - ttyrel(pt->pt_tty); - free(pt, M_PTY); - } - return (devc); -} - -static void -pty_create_slave(struct ucred *cred, struct ptsc *pt, int m) +static int +ptydev_fdopen(struct cdev *dev, int fflags, struct thread *td, struct file *fp) { - int n; + int u, error; + char name[] = "ttyXX"; - n = minor2unit(m); - KASSERT(n >= 0 && n / 32 < sizeof(names), - ("pty_create_slave: n %d ptsc %p", n, pt)); - pt->devs = make_dev_cred(&pts_cdevsw, m, cred, UID_ROOT, GID_WHEEL, - 0666, "tty%c%r", names[n / 32], n % 32); - pt->devs->si_drv1 = pt; - pt->devs->si_tty = pt->pt_tty; - pt->pt_tty->t_dev = pt->devs; -} - -static void -pty_destroy_slave(struct ptsc *pt) -{ - - if (pt->pt_tty->t_refcnt > 1) - return; - pt->pt_tty->t_dev = NULL; - ttyrel(pt->pt_tty); - pt->pt_tty = NULL; - destroy_dev(pt->devs); - pt->devs = NULL; -} - -static void -pty_maybe_destroy_slave(struct ptsc *pt) -{ - - /* - * vfs bugs and complications near revoke() make - * it currently impossible to destroy struct cdev - */ - if (0 && pt->pt_devc_open == 0 && pt->pt_devs_open == 0) - pty_destroy_slave(pt); -} - -/*ARGSUSED*/ -static int -ptsopen(struct cdev *dev, int flag, int devtype, struct thread *td) -{ - struct tty *tp; - int error; - struct ptsc *pt; - - if (!dev->si_drv1) - return(ENXIO); - pt = dev->si_drv1; - tp = dev->si_tty; - - if ((tp->t_state & TS_ISOPEN) == 0) { - ttyinitmode(tp, 1, 0); - } else if (tp->t_state & TS_XCLUDE && priv_check(td, - PRIV_TTY_EXCLUSIVE)) - return (EBUSY); - else if (pt->pt_prison != td->td_ucred->cr_prison && - priv_check(td, PRIV_TTY_PRISON)) + if (!atomic_cmpset_ptr((uintptr_t *)&dev->si_drv1, 0, 1)) return (EBUSY); - if (tp->t_oproc) /* Ctrlr still around. */ - (void)ttyld_modem(tp, 1); - while ((tp->t_state & TS_CARR_ON) == 0) { - if (flag&FNONBLOCK) - break; - error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH, - "ptsopn", 0); - if (error) - return (error); - } - error = ttyld_open(tp, dev); - if (error == 0) { - ptcwakeup(tp, FREAD|FWRITE); - pt->pt_devs_open = 1; - } else - pty_maybe_destroy_slave(pt); - return (error); -} - -static int -ptsclose(struct cdev *dev, int flag, int mode, struct thread *td) -{ - struct ptsc *pti; - struct tty *tp; - int err; - - tp = dev->si_tty; - pti = dev->si_drv1; - - KASSERT(dev == pti->devs, ("ptsclose: dev != pti->devs")); - - err = ttyld_close(tp, flag); - (void) tty_close(tp); - - pti->pt_devs_open = 0; - pty_maybe_destroy_slave(pti); - - return (err); -} - -static int -ptsread(struct cdev *dev, struct uio *uio, int flag) -{ - struct tty *tp = dev->si_tty; - int error = 0; - - if (tp->t_oproc) - error = ttyld_read(tp, uio, flag); - ptcwakeup(tp, FWRITE); - return (error); -} - -/* - * Write to pseudo-tty. - * Wakeups of controlling tty will happen - * indirectly, when tty driver calls ptsstart. - */ -static int -ptswrite(struct cdev *dev, struct uio *uio, int flag) -{ - struct tty *tp; - - tp = dev->si_tty; - if (tp->t_oproc == 0) - return (EIO); - return (ttyld_write(tp, uio, flag)); -} - -/* - * Start output on pseudo-tty. - * Wake up process selecting or sleeping for input from controlling tty. - */ -static void -ptsstart(struct tty *tp) -{ - struct ptsc *pt = tp->t_sc; - - if (tp->t_state & TS_TTSTOP) - return; - if (pt->pt_flags & PF_STOPPED) { - pt->pt_flags &= ~PF_STOPPED; - pt->pt_send = TIOCPKT_START; - } - ptcwakeup(tp, FREAD); -} - -static void -ptcwakeup(struct tty *tp, int flag) -{ - struct ptsc *pt = tp->t_sc; - - if (flag & FREAD) { - selwakeuppri(&pt->pt_selr, TTIPRI); - wakeup(TSA_PTC_READ(tp)); - } - if (flag & FWRITE) { - selwakeuppri(&pt->pt_selw, TTOPRI); - wakeup(TSA_PTC_WRITE(tp)); - } -} - -static int -ptcopen(struct cdev *dev, int flag, int devtype, struct thread *td) -{ - struct tty *tp; - struct ptsc *pt; - - if (!dev->si_drv1) - ptyinit(dev, td); - if (!dev->si_drv1) - return(ENXIO); - - pt = dev->si_drv1; - /* - * In case we have destroyed the struct tty at the last connect time, - * we need to recreate it. - */ - if (pt->pt_tty == NULL) { - tp = ttyalloc(); - mtx_lock(&ptyinit_lock); - if (pt->pt_tty == NULL) { - pt->pt_tty = tp; - pt->pt_tty->t_sc = pt; - dev->si_tty = pt->pt_tty; - mtx_unlock(&ptyinit_lock); - } else { - mtx_unlock(&ptyinit_lock); - ttyrel(tp); - } - } - tp = dev->si_tty; - - if (tp->t_oproc) - return (EIO); - tp->t_timeout = -1; - tp->t_oproc = ptsstart; - tp->t_stop = ptsstop; - (void)ttyld_modem(tp, 1); - tp->t_lflag &= ~EXTPROC; - pt->pt_prison = td->td_ucred->cr_prison; - pt->pt_flags = 0; - pt->pt_send = 0; - pt->pt_ucntl = 0; - - if (!pt->devs) - pty_create_slave(td->td_ucred, pt, minor(dev)); - pt->pt_devc_open = 1; - - return (0); -} - -static int -ptcclose(struct cdev *dev, int flags, int fmt, struct thread *td) -{ - struct ptsc *pti = dev->si_drv1; - struct tty *tp; - - tp = dev->si_tty; - (void)ttyld_modem(tp, 0); - - /* - * XXX MDMBUF makes no sense for ptys but would inhibit the above - * l_modem(). CLOCAL makes sense but isn't supported. Special - * l_modem()s that ignore carrier drop make no sense for ptys but - * may be in use because other parts of the line discipline make - * sense for ptys. Recover by doing everything that a normal - * ttymodem() would have done except for sending a SIGHUP. - */ - if (tp->t_state & TS_ISOPEN) { - tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED); - tp->t_state |= TS_ZOMBIE; - ttyflush(tp, FREAD | FWRITE); - } - - tp->t_oproc = 0; /* mark closed */ - pti->pt_devc_open = 0; - pty_maybe_destroy_slave(pti); - return (0); -} - -static int -ptcread(struct cdev *dev, struct uio *uio, int flag) -{ - struct tty *tp = dev->si_tty; - struct ptsc *pt = dev->si_drv1; - char buf[BUFSIZ]; - int error = 0, cc; - - /* - * We want to block until the slave - * is open, and there's something to read; - * but if we lost the slave or we're NBIO, - * then return the appropriate error instead. - */ - for (;;) { - if (tp->t_state&TS_ISOPEN) { - if (pt->pt_flags&PF_PKT && pt->pt_send) { - error = ureadc((int)pt->pt_send, uio); - if (error) - return (error); - if (pt->pt_send & TIOCPKT_IOCTL) { - cc = min(uio->uio_resid, - sizeof(tp->t_termios)); - uiomove(&tp->t_termios, cc, uio); - } - pt->pt_send = 0; - return (0); - } - if (pt->pt_flags&PF_UCNTL && pt->pt_ucntl) { - error = ureadc((int)pt->pt_ucntl, uio); - if (error) - return (error); - pt->pt_ucntl = 0; - return (0); - } - if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) - break; - } - if ((tp->t_state & TS_CONNECTED) == 0) - return (0); /* EOF */ - if (flag & O_NONBLOCK) - return (EWOULDBLOCK); - error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0); - if (error) - return (error); - } - if (pt->pt_flags & (PF_PKT|PF_UCNTL)) - error = ureadc(0, uio); - while (uio->uio_resid > 0 && error == 0) { - cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ)); - if (cc <= 0) - break; - error = uiomove(buf, cc, uio); - } - ttwwakeup(tp); - return (error); -} - -static void -ptsstop(struct tty *tp, int flush) -{ - struct ptsc *pt = tp->t_sc; - int flag; - - /* note: FLUSHREAD and FLUSHWRITE already ok */ - if (flush == 0) { - flush = TIOCPKT_STOP; - pt->pt_flags |= PF_STOPPED; - } else - pt->pt_flags &= ~PF_STOPPED; - pt->pt_send |= flush; - /* change of perspective */ - flag = 0; - if (flush & FREAD) - flag |= FWRITE; - if (flush & FWRITE) - flag |= FREAD; - ptcwakeup(tp, flag); -} - -static int -ptcpoll(struct cdev *dev, int events, struct thread *td) -{ - struct tty *tp = dev->si_tty; - struct ptsc *pt = dev->si_drv1; - int revents = 0; - int s; - - if ((tp->t_state & TS_CONNECTED) == 0) - return (events & - (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)); - /* - * Need to block timeouts (ttrstart). - */ - s = spltty(); + /* Generate device name and create PTY. */ + u = dev2unit(dev); + name[3] = u >> 8; + name[4] = u; - if (events & (POLLIN | POLLRDNORM)) - if ((tp->t_state & TS_ISOPEN) && - ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) || - ((pt->pt_flags & PF_PKT) && pt->pt_send) || - ((pt->pt_flags & PF_UCNTL) && pt->pt_ucntl))) - revents |= events & (POLLIN | POLLRDNORM); - - if (events & (POLLOUT | POLLWRNORM)) - if (tp->t_state & TS_ISOPEN && - (((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) || - (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON))))) - revents |= events & (POLLOUT | POLLWRNORM); - - if (events & POLLHUP) - if ((tp->t_state & TS_CARR_ON) == 0) - revents |= POLLHUP; - - if (revents == 0) { - if (events & (POLLIN | POLLRDNORM)) - selrecord(td, &pt->pt_selr); - - if (events & (POLLOUT | POLLWRNORM)) - selrecord(td, &pt->pt_selw); - } - splx(s); - - return (revents); -} - -static int -ptcwrite(struct cdev *dev, struct uio *uio, int flag) -{ - struct tty *tp = dev->si_tty; - u_char *cp = 0; - int cc = 0; - u_char locbuf[BUFSIZ]; - int cnt = 0; - int error = 0; - -again: - if ((tp->t_state&TS_ISOPEN) == 0) - goto block; - while (uio->uio_resid > 0 || cc > 0) { - if (cc == 0) { - cc = min(uio->uio_resid, BUFSIZ); - cp = locbuf; - error = uiomove(cp, cc, uio); - if (error) - return (error); - /* check again for safety */ - if ((tp->t_state & TS_ISOPEN) == 0) { - /* adjust for data copied in but not written */ - uio->uio_resid += cc; - return (EIO); - } - } - while (cc > 0) { - if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && - (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) { - wakeup(TSA_HUP_OR_INPUT(tp)); - goto block; - } - ttyld_rint(tp, *cp++); - cnt++; - cc--; - } - cc = 0; - } - return (0); -block: - /* - * Come here to wait for slave to open, for space - * in outq, or space in rawq, or an empty canq. - */ - if ((tp->t_state & TS_CONNECTED) == 0) { - /* adjust for data copied in but not written */ - uio->uio_resid += cc; - return (EIO); - } - if (flag & O_NONBLOCK) { - /* adjust for data copied in but not written */ - uio->uio_resid += cc; - if (cnt == 0) - return (EWOULDBLOCK); - return (0); - } - error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0); - if (error) { - /* adjust for data copied in but not written */ - uio->uio_resid += cc; + error = pts_alloc_external(fflags & (FREAD|FWRITE), td, fp, dev, name); + if (error != 0) { + destroy_dev_sched(dev); return (error); } - goto again; -} - -/*ARGSUSED*/ -static int -ptcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) -{ - struct tty *tp = dev->si_tty; - struct ptsc *pt = dev->si_drv1; -#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ - defined(COMPAT_FREEBSD4) || defined(COMPAT_43) - int ival; -#endif - - switch (cmd) { - - case TIOCGPGRP: - /* - * 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 (pt->pt_flags & PF_UCNTL) - return (EINVAL); - pt->pt_flags |= PF_PKT; - } else - pt->pt_flags &= ~PF_PKT; - return (0); - - case TIOCUCNTL: - if (*(int *)data) { - if (pt->pt_flags & PF_PKT) - return (EINVAL); - pt->pt_flags |= PF_UCNTL; - } else - pt->pt_flags &= ~PF_UCNTL; - return (0); - } - - /* - * The rest of the ioctls shouldn't be called until - * the slave is open. - */ - if ((tp->t_state & TS_ISOPEN) == 0) - return (EAGAIN); - - switch (cmd) { -#ifdef COMPAT_43TTY - 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; -#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ - defined(COMPAT_FREEBSD4) || defined(COMPAT_43) - case _IO('t', 95): - ival = IOCPARM_IVAL(data); - data = (caddr_t)&ival; - /* FALLTHROUGH */ -#endif - case TIOCSIG: - if (*(unsigned int *)data >= NSIG || - *(unsigned int *)data == 0) - return(EINVAL); - if ((tp->t_lflag&NOFLSH) == 0) - ttyflush(tp, FREAD|FWRITE); - if (tp->t_pgrp != NULL) { - PGRP_LOCK(tp->t_pgrp); - pgsignal(tp->t_pgrp, *(unsigned int *)data, 1); - PGRP_UNLOCK(tp->t_pgrp); - } - if ((*(unsigned int *)data == SIGINFO) && - ((tp->t_lflag&NOKERNINFO) == 0)) - ttyinfo(tp); - return(0); + /* Raise a warning when a legacy PTY has been allocated. */ + if (pty_warningcnt > 0) { + pty_warningcnt--; + printf("pid %d (%s) is using legacy pty devices%s\n", + td->td_proc->p_pid, td->td_name, + pty_warningcnt ? "" : " - not logging anymore"); } - return (ptsioctl(dev, cmd, data, flag, td)); + return (0); } -/*ARGSUSED*/ -static int -ptsioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) -{ - struct tty *tp = dev->si_tty; - struct ptsc *pt = dev->si_drv1; - u_char *cc = tp->t_cc; - int stop, error; - - 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 (pt->pt_flags & PF_PKT) { - pt->pt_send |= TIOCPKT_IOCTL; - ptcwakeup(tp, FREAD); - } - tp->t_lflag |= EXTPROC; - } else { - if ((tp->t_lflag & EXTPROC) && - (pt->pt_flags & PF_PKT)) { - pt->pt_send |= TIOCPKT_IOCTL; - ptcwakeup(tp, FREAD); - } - tp->t_lflag &= ~EXTPROC; - } - return(0); - } - error = ttyioctl(dev, cmd, data, flag, td); - if (error == ENOTTY) { - if (pt->pt_flags & PF_UCNTL && - (cmd & ~0xff) == UIOCCMD(0)) { - if (cmd & 0xff) { - pt->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) && (pt->pt_flags & PF_PKT)) { - switch(cmd) { - case TIOCSETA: - case TIOCSETAW: - case TIOCSETAF: -#ifdef COMPAT_43TTY - case TIOCSETP: - case TIOCSETN: - case TIOCSETC: - case TIOCSLTC: - case TIOCLBIS: - case TIOCLBIC: - case TIOCLSET: -#endif - pt->pt_send |= TIOCPKT_IOCTL; - ptcwakeup(tp, FREAD); - break; - default: - break; - } - } - stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) - && CCEQ(cc[VSTART], CTRL('q')); - if (pt->pt_flags & PF_NOSTOP) { - if (stop) { - pt->pt_send &= ~TIOCPKT_NOSTOP; - pt->pt_send |= TIOCPKT_DOSTOP; - pt->pt_flags &= ~PF_NOSTOP; - ptcwakeup(tp, FREAD); - } - } else { - if (!stop) { - pt->pt_send &= ~TIOCPKT_DOSTOP; - pt->pt_send |= TIOCPKT_NOSTOP; - pt->pt_flags |= PF_NOSTOP; - ptcwakeup(tp, FREAD); - } - } - return (error); -} +static struct cdevsw ptydev_cdevsw = { + .d_version = D_VERSION, + .d_fdopen = ptydev_fdopen, + .d_name = "ptydev", +}; static void pty_clone(void *arg, struct ucred *cr, char *name, int namelen, struct cdev **dev) { - char *cp; int u; + /* Cloning is already satisfied. */ if (*dev != NULL) return; - if (bcmp(name, "pty", 3) != 0) - return; - if (name[5] != '\0' || name[3] == '\0') + + /* Only catch /dev/ptyXX. */ + if (namelen != 5 || bcmp(name, "pty", 3) != 0) return; - cp = index(names, name[3]); - if (cp == NULL) + + /* Only catch /dev/pty[l-sL-S]X. */ + if (!(name[3] >= 'l' && name[3] <= 's') && + !(name[3] >= 'L' && name[3] <= 'S')) return; - u = (cp - names) * 32; - if (name[4] >= '0' && name[4] <= '9') - u += name[4] - '0'; - else if (name[4] >= 'a' && name[4] <= 'v') - u += name[4] - 'a' + 10; - else + + /* Only catch /dev/pty[l-sL-S][0-9a-v]. */ + if (!(name[4] >= '0' && name[4] <= '9') && + !(name[4] >= 'a' && name[4] <= 'v')) return; - *dev = make_dev_credf(MAKEDEV_REF, &ptc_cdevsw, unit2minor(u), cr, - UID_ROOT, GID_WHEEL, 0666, "pty%c%r", names[u / 32], u % 32); - (*dev)->si_flags |= SI_CHEAPCLONE; - return; + + /* Create the controller device node. */ + u = (unsigned int)name[3] << 8 | name[4]; + *dev = make_dev_credf(MAKEDEV_REF, &ptydev_cdevsw, u, + NULL, UID_ROOT, GID_WHEEL, 0666, name); } static void -ptc_drvinit(void *unused) +pty_init(void *unused) { EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000); } -SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,ptc_drvinit,NULL); +SYSINIT(pty, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, pty_init, NULL); |