-int
-pty_init(int n_ptys)
-{
- int i;
- int j;
-
- /* create the pseudo tty device nodes */
- for (j = 0; j < 10; j++) {
- for (i = 0; i < HEX_BASE; i++) {
- int m = j * HEX_BASE + i;
- if (m == n_ptys)
- goto done;
- pt_ioctl[m].pt_devhandle = devfs_make_node(makedev(4, m),
- DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666,
- "tty%c%x", j + START_CHAR, i);
- (void)devfs_make_node(makedev(5, m),
- DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666,
- "pty%c%x", j + START_CHAR, i);
- }
- }
- done:
- return (0);
-}
-#endif /* DEVFS */
-
-__private_extern__ int
-ptsopen(dev_t dev, int flag, __unused int devtype, __unused struct proc *p)
-{
- struct tty *tp;
- int error;
-
- /*
- * You will see this sort of code coming up in diffs later both
- * the ttymalloc and the tp indirection.
- */
- if (minor(dev) >= npty) {
- error = ENXIO;
- goto err;
- }
- if (!pt_tty[minor(dev)]) {
- /*
- * If we can't allocate a new one, act as if we had run out
- * of device nodes.
- */
- if ((tp = pt_tty[minor(dev)] = ttymalloc()) == NULL) {
- error = ENXIO;
- goto err;
- }
- } else
- tp = pt_tty[minor(dev)];
-
- tty_lock(tp);
-
- if ((tp->t_state & TS_ISOPEN) == 0) {
- termioschars(&tp->t_termios); /* 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 && suser(kauth_cred_get(), NULL)) {
- error = EBUSY;
- goto out;
- }
- if (tp->t_oproc) /* Ctrlr still around. */
- (void)(*linesw[tp->t_line].l_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)
- goto out;
- }
- error = (*linesw[tp->t_line].l_open)(dev, tp);
- if (error == 0)
- ptcwakeup(tp, FREAD|FWRITE);
-
-out:
- tty_unlock(tp);
-err:
- return (error);
-}
-
-__private_extern__ int
-ptsclose(dev_t dev, int flag, __unused int mode, __unused proc_t p)
-{
- struct tty *tp;
- int err;
-
- /*
- * This is temporary until the VSX conformance tests
- * are fixed. They are hanging with a deadlock
- * where close(pts) will not complete without t_timeout set
- */
-#define FIX_VSX_HANG 1
-#ifdef FIX_VSX_HANG
- int save_timeout;
-#endif
-
- tp = pt_tty[minor(dev)];
- tty_lock(tp);
-#ifdef FIX_VSX_HANG
- save_timeout = tp->t_timeout;
- tp->t_timeout = 60;
-#endif
- err = (*linesw[tp->t_line].l_close)(tp, flag);
- ptsstop(tp, FREAD|FWRITE);
- (void) ttyclose(tp);
-#ifdef FIX_VSX_HANG
- tp->t_timeout = save_timeout;
-#endif
- tty_unlock(tp);
- return (err);
-}
-
-__private_extern__ int
-ptsread(dev_t dev, struct uio *uio, int flag)
-{
- struct proc *p = current_proc();
- struct tty *tp = pt_tty[minor(dev)];
- struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
- int error = 0;
- struct uthread *ut;
- struct pgrp *pg;
-
- tty_lock(tp);
-
- ut = (struct uthread *)get_bsdthread_info(current_thread());
-again:
- if (pti->pt_flags & PF_REMOTE) {
- while (isbackground(p, tp)) {
- if ((p->p_sigignore & sigmask(SIGTTIN)) ||
- (ut->uu_sigmask & sigmask(SIGTTIN)) ||
- p->p_lflag & P_LPPWAIT) {
- error = EIO;
- goto out;
- }
-
-
- pg = proc_pgrp(p);
- if (pg == PGRP_NULL) {
- error = EIO;
- goto out;
- }
- /*
- * SAFE: We about to drop the lock ourselves by
- * SAFE: erroring out or sleeping anyway.
- */
- tty_unlock(tp);
- if (pg->pg_jobc == 0) {
- pg_rele(pg);
- tty_lock(tp);
- error = EIO;
- goto out;
- }
- pgsignal(pg, SIGTTIN, 1);
- pg_rele(pg);
- tty_lock(tp);
-
- error = ttysleep(tp, &lbolt, TTIPRI | PCATCH | PTTYBLOCK, "ptsbg",
- 0);
- if (error)
- goto out;
- }
- if (tp->t_canq.c_cc == 0) {
- if (flag & IO_NDELAY) {
- error = EWOULDBLOCK;
- goto out;
- }
- error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH,
- "ptsin", 0);
- if (error)
- goto out;
- goto again;
- }
- while (tp->t_canq.c_cc > 1 && uio_resid(uio) > 0) {
- int cc;
- char buf[BUFSIZ];
-
- cc = min(uio_resid(uio), BUFSIZ);
- // Don't copy the very last byte
- cc = min(cc, tp->t_canq.c_cc - 1);
- cc = q_to_b(&tp->t_canq, (u_char *)buf, cc);
- error = uiomove(buf, cc, uio);
- if (error)
- break;
- }
- if (tp->t_canq.c_cc == 1)
- (void) getc(&tp->t_canq);
- if (tp->t_canq.c_cc)
- goto out;
- } else
- if (tp->t_oproc)
- error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
- ptcwakeup(tp, FWRITE);
-out:
- tty_unlock(tp);
- return (error);
-}
-
-/*
- * Write to pseudo-tty.
- * Wakeups of controlling tty will happen
- * indirectly, when tty driver calls ptsstart.
- */
-__private_extern__ int
-ptswrite(dev_t dev, struct uio *uio, int flag)
-{
- struct tty *tp;
- int error;
-
- tp = pt_tty[minor(dev)];
-
- tty_lock(tp);
-
- if (tp->t_oproc == 0)
- error = EIO;
- else
- error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
-
- tty_unlock(tp);
-
- return (error);
-}
-
-/*
- * Start output on pseudo-tty.
- * Wake up process selecting or sleeping for input from controlling tty.
- *
- * t_oproc for this driver; called from within the line discipline
- *
- * Locks: Assumes tp is locked on entry, remains locked on exit
- */
-static void
-ptsstart(struct tty *tp)
-{
- struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
-
- if (tp->t_state & TS_TTSTOP)
- goto out;
- if (pti->pt_flags & PF_STOPPED) {
- pti->pt_flags &= ~PF_STOPPED;
- pti->pt_send = TIOCPKT_START;
- }
- ptcwakeup(tp, FREAD);
-out:
- return;
-}
-
-/*
- * Locks: Assumes tty_lock() is held over this call.
- */
-static void
-ptcwakeup(struct tty *tp, int flag)
-{
- struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
-
- if (flag & FREAD) {
- selwakeup(&pti->pt_selr);
- wakeup(TSA_PTC_READ(tp));
- }
- if (flag & FWRITE) {
- selwakeup(&pti->pt_selw);
- wakeup(TSA_PTC_WRITE(tp));
- }
-}
-
-__private_extern__ int
-ptcopen(dev_t dev, __unused int flag, __unused int devtype, __unused proc_t p)
-{
- struct tty *tp;
- struct pt_ioctl *pti;
- int error = 0;
-
- if (minor(dev) >= npty) {
- error = ENXIO;
- goto out;
- }
- if(!pt_tty[minor(dev)]) {
- tp = pt_tty[minor(dev)] = ttymalloc();
- } else
- tp = pt_tty[minor(dev)];
-
- tty_lock(tp);