- /* 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;
- boolean_t funnel_state;
-
- funnel_state = thread_funnel_set(kernel_flock, TRUE);
- /*
- * 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 out;
- }
- 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 out;
- }
- } else
- tp = pt_tty[minor(dev)];
- 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;
- 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:
- (void) thread_funnel_set(kernel_flock, funnel_state);
- return (error);
-}
-
-__private_extern__ int
-ptsclose(dev_t dev, int flag, __unused int mode, __unused proc_t p)
-{
- struct tty *tp;
- int err;
- boolean_t funnel_state;
- /*
- * 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
- funnel_state = thread_funnel_set(kernel_flock, TRUE);
-
- tp = pt_tty[minor(dev)];
-#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
- (void) thread_funnel_set(kernel_flock, funnel_state);
- 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;
- boolean_t funnel_state;
- struct pgrp *pg;
-
- funnel_state = thread_funnel_set(kernel_flock, TRUE);
-
-
- 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;
- }
- if (pg->pg_jobc == 0) {
- pg_rele(pg);
- error = EIO;
- goto out;
- }
- pgsignal(pg, SIGTTIN, 1);
- pg_rele(pg);
-
- error = ttysleep(tp, &lbolt, TTIPRI | PCATCH | PTTYBLOCK, "ptsbg",
- 0);
- if (error)
- goto out;
- }
- if (tp->t_canq.c_cc == 0) {
- if (flag & IO_NDELAY)
- return (EWOULDBLOCK);
- 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:
- (void) thread_funnel_set(kernel_flock, funnel_state);
- 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;
- boolean_t funnel_state;
-
- funnel_state = thread_funnel_set(kernel_flock, TRUE);
-
- tp = pt_tty[minor(dev)];
- if (tp->t_oproc == 0)
- error = EIO;
- else
- error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
-
- (void) thread_funnel_set(kernel_flock, funnel_state);
- return (error);
-}
-
-/*
- * Start output on pseudo-tty.
- * Wake up process selecting or sleeping for input from controlling tty.
- */
-static void
-ptsstart(struct tty *tp)
-{
- struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
- boolean_t funnel_state;
-
- funnel_state = thread_funnel_set(kernel_flock, TRUE);
-
- 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:
- (void) thread_funnel_set(kernel_flock, funnel_state);
- return;
-}
-
-static void
-ptcwakeup(struct tty *tp, int flag)
-{
- struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
- boolean_t funnel_state;
-
- funnel_state = thread_funnel_set(kernel_flock, TRUE);
-
- if (flag & FREAD) {
- selwakeup(&pti->pt_selr);
- wakeup(TSA_PTC_READ(tp));
- }
- if (flag & FWRITE) {
- selwakeup(&pti->pt_selw);
- wakeup(TSA_PTC_WRITE(tp));
- }
- (void) thread_funnel_set(kernel_flock, funnel_state);
-}
-
-__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;
- boolean_t funnel_state;
-
- funnel_state = thread_funnel_set(kernel_flock, TRUE);
-
- 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)];
- /* If master is open OR slave is still draining, pty is still busy */
- if (tp->t_oproc || (tp->t_state & TS_ISOPEN)) {
- error = EBUSY;
- goto out;
- }
- tp->t_oproc = ptsstart;
- CLR(tp->t_state, TS_ZOMBIE);
-#ifdef sun4c
- tp->t_stop = ptsstop;
-#endif
- (void)(*linesw[tp->t_line].l_modem)(tp, 1);
- tp->t_lflag &= ~EXTPROC;
- pti = &pt_ioctl[minor(dev)];
- pti->pt_flags = 0;
- pti->pt_send = 0;
- pti->pt_ucntl = 0;
-out:
- (void) thread_funnel_set(kernel_flock, funnel_state);
- return (error);
-}