summaryrefslogtreecommitdiffstats
path: root/sys/kern/tty_pty.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/tty_pty.c')
-rw-r--r--sys/kern/tty_pty.c61
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);
}
OpenPOWER on IntegriCloud