diff options
Diffstat (limited to 'sys/kern/tty_pty.c')
-rw-r--r-- | sys/kern/tty_pty.c | 61 |
1 files changed, 54 insertions, 7 deletions
diff --git a/sys/kern/tty_pty.c b/sys/kern/tty_pty.c index 2fdab73..643f0c4 100644 --- a/sys/kern/tty_pty.c +++ b/sys/kern/tty_pty.c @@ -107,6 +107,7 @@ struct ptsc { u_char pt_ucntl; struct tty *pt_tty; struct cdev *devs, *devc; + int pt_devs_open, pt_devc_open; struct prison *pt_prison; }; @@ -132,7 +133,6 @@ static char *names = "pqrsPQRS"; static struct cdev * ptyinit(struct cdev *devc, struct thread *td) { - struct cdev *devs; struct ptsc *pt; int n; @@ -143,19 +143,47 @@ ptyinit(struct cdev *devc, struct thread *td) devc->si_flags &= ~SI_CHEAPCLONE; + /* + * Initially do not create a slave endpoint. + */ pt = malloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO); - pt->devs = devs = make_dev_cred(&pts_cdevsw, n, td->td_ucred, - UID_ROOT, GID_WHEEL, 0666, "tty%c%r", names[n / 32], n % 32); pt->devc = devc; pt->pt_tty = ttyalloc(); pt->pt_tty->t_sc = pt; - devs->si_drv1 = devc->si_drv1 = pt; - devs->si_tty = devc->si_tty = pt->pt_tty; - pt->pt_tty->t_dev = devs; + devc->si_drv1 = pt; + devc->si_tty = pt->pt_tty; return (devc); } +static void +pty_create_slave(struct ucred *cred, struct ptsc *pt, int n) +{ + + pt->devs = make_dev_cred(&pts_cdevsw, n, 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) +{ + + pt->pt_tty->t_dev = NULL; + destroy_dev(pt->devs); + pt->devs = NULL; +} + +static void +pty_maybe_destroy_slave(struct ptsc *pt) +{ + + if (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) @@ -185,20 +213,32 @@ ptsopen(struct cdev *dev, int flag, int devtype, struct thread *td) return (error); } error = ttyld_open(tp, dev); - if (error == 0) + 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); } @@ -286,12 +326,17 @@ ptcopen(struct cdev *dev, int flag, int devtype, struct thread *td) pt->pt_flags = 0; pt->pt_send = 0; pt->pt_ucntl = 0; + + 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; @@ -312,6 +357,8 @@ ptcclose(struct cdev *dev, int flags, int fmt, struct thread *td) } tp->t_oproc = 0; /* mark closed */ + pti->pt_devc_open = 0; + pty_maybe_destroy_slave(pti); return (0); } |