1*9561Ssam /* tty_pty.c 4.29 82/12/05 */ 22283Stoy 32281Stoy /* 42281Stoy * Pseudo-teletype Driver 52281Stoy * (Actually two drivers, requiring two entries in 'cdevsw') 62281Stoy */ 72314Stoy #include "pty.h" 82314Stoy 93206Swnj #if NPTY > 0 102281Stoy #include "../h/param.h" 112281Stoy #include "../h/systm.h" 12*9561Ssam #include "../h/ioctl.h" 132281Stoy #include "../h/tty.h" 142281Stoy #include "../h/dir.h" 152281Stoy #include "../h/user.h" 162281Stoy #include "../h/conf.h" 172427Swnj #include "../h/file.h" 184484Swnj #include "../h/proc.h" 197823Sroot #include "../h/uio.h" 208155Sroot #include "../h/kernel.h" 216239Sroot 227475Ssam #if NPTY == 1 235408Swnj #undef NPTY 246239Sroot #define NPTY 32 /* crude XXX */ 257475Ssam #endif 262281Stoy 272427Swnj #define BUFSIZ 100 /* Chunk size iomoved from user */ 284484Swnj 292281Stoy /* 304484Swnj * pts == /dev/tty[pP]? 314484Swnj * ptc == /dev/ptp[pP]? 322281Stoy */ 334484Swnj struct tty pt_tty[NPTY]; 344484Swnj struct pt_ioctl { 355427Swnj int pt_flags; 365427Swnj int pt_gensym; 375427Swnj struct proc *pt_selr, *pt_selw; 385427Swnj int pt_send; 394484Swnj } pt_ioctl[NPTY]; 402281Stoy 415427Swnj #define PF_RCOLL 0x01 425427Swnj #define PF_WCOLL 0x02 435427Swnj #define PF_NBIO 0x04 445427Swnj #define PF_PKT 0x08 /* packet mode */ 455574Swnj #define PF_STOPPED 0x10 /* user told stopped */ 465894Swnj #define PF_REMOTE 0x20 /* remote and flow controlled input */ 476119Swnj #define PF_NOSTOP 0x40 482281Stoy 492281Stoy /*ARGSUSED*/ 502281Stoy ptsopen(dev, flag) 515396Sroot dev_t dev; 524484Swnj { 532281Stoy register struct tty *tp; 542281Stoy 558563Sroot if (minor(dev) >= NPTY) 568563Sroot return (ENXIO); 572281Stoy tp = &pt_tty[minor(dev)]; 585408Swnj if ((tp->t_state & TS_ISOPEN) == 0) { 592427Swnj ttychars(tp); /* Set up default chars */ 602427Swnj tp->t_flags = 0; /* No features (nor raw mode) */ 618563Sroot } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 628563Sroot return (EBUSY); 634484Swnj if (tp->t_oproc) /* Ctrlr still around. */ 645408Swnj tp->t_state |= TS_CARR_ON; 655408Swnj while ((tp->t_state & TS_CARR_ON) == 0) { 665408Swnj tp->t_state |= TS_WOPEN; 672281Stoy sleep((caddr_t)&tp->t_rawq, TTIPRI); 682281Stoy } 698563Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 702281Stoy } 712281Stoy 722281Stoy ptsclose(dev) 735396Sroot dev_t dev; 745408Swnj { 752281Stoy register struct tty *tp; 762281Stoy 772281Stoy tp = &pt_tty[minor(dev)]; 782281Stoy (*linesw[tp->t_line].l_close)(tp); 796299Swnj ttyclose(tp); 802281Stoy } 812281Stoy 827823Sroot ptsread(dev, uio) 835396Sroot dev_t dev; 847823Sroot struct uio *uio; 854484Swnj { 865894Swnj register struct tty *tp = &pt_tty[minor(dev)]; 875894Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 888521Sroot int error = 0; 892281Stoy 905894Swnj again: 915894Swnj if (pti->pt_flags & PF_REMOTE) { 925894Swnj while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 935894Swnj if (u.u_signal[SIGTTIN] == SIG_IGN || 945894Swnj u.u_signal[SIGTTIN] == SIG_HOLD || 955894Swnj /* 965894Swnj (u.u_procp->p_flag&SDETACH) || 975894Swnj */ 985894Swnj u.u_procp->p_flag&SVFORK) 998521Sroot return (EIO); 1005894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 1015894Swnj sleep((caddr_t)&lbolt, TTIPRI); 1025408Swnj } 1035894Swnj if (tp->t_rawq.c_cc == 0) { 1048521Sroot if (tp->t_state & TS_NBIO) 1058521Sroot return (EWOULDBLOCK); 1065894Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 1075894Swnj goto again; 1085894Swnj } 1097823Sroot while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0) 1107823Sroot if (ureadc(getc(&tp->t_rawq), uio) < 0) { 1118521Sroot error = EFAULT; 1127823Sroot break; 1137823Sroot } 1145894Swnj if (tp->t_rawq.c_cc == 1) 1155894Swnj (void) getc(&tp->t_rawq); 1165894Swnj if (tp->t_rawq.c_cc) 1178521Sroot return (error); 1185894Swnj } else 1195894Swnj if (tp->t_oproc) 1208521Sroot error = (*linesw[tp->t_line].l_read)(tp, uio); 1215894Swnj wakeup((caddr_t)&tp->t_rawq.c_cf); 1225894Swnj if (pti->pt_selw) { 1235894Swnj selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 1245894Swnj pti->pt_selw = 0; 1255894Swnj pti->pt_flags &= ~PF_WCOLL; 1262281Stoy } 1278521Sroot return (error); 1282281Stoy } 1292281Stoy 1305408Swnj /* 1315408Swnj * Write to pseudo-tty. 1325408Swnj * Wakeups of controlling tty will happen 1335408Swnj * indirectly, when tty driver calls ptsstart. 1345408Swnj */ 1357823Sroot ptswrite(dev, uio) 1365396Sroot dev_t dev; 1377823Sroot struct uio *uio; 1384484Swnj { 1392281Stoy register struct tty *tp; 1402281Stoy 1412281Stoy tp = &pt_tty[minor(dev)]; 1428521Sroot if (tp->t_oproc == 0) 1438521Sroot return (EIO); 1448521Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 1452281Stoy } 1462281Stoy 1475408Swnj /* 1485408Swnj * Start output on pseudo-tty. 1495408Swnj * Wake up process selecting or sleeping for input from controlling tty. 1505408Swnj */ 1512281Stoy ptsstart(tp) 1524484Swnj struct tty *tp; 1534484Swnj { 1545574Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1554484Swnj 1565408Swnj if (tp->t_state & TS_TTSTOP) 1572281Stoy return; 1585574Swnj if (pti->pt_flags & PF_STOPPED) { 1595574Swnj pti->pt_flags &= ~PF_STOPPED; 1605574Swnj pti->pt_send = TIOCPKT_START; 1615574Swnj } 1625430Swnj ptcwakeup(tp); 1635430Swnj } 1645430Swnj 1655430Swnj ptcwakeup(tp) 1665430Swnj struct tty *tp; 1675430Swnj { 1685430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1695430Swnj 1705427Swnj if (pti->pt_selr) { 1715427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1725427Swnj pti->pt_selr = 0; 1735427Swnj pti->pt_flags &= ~PF_RCOLL; 1744484Swnj } 1752281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1762281Stoy } 1772281Stoy 1782281Stoy /*ARGSUSED*/ 1792281Stoy ptcopen(dev, flag) 1804484Swnj dev_t dev; 1814484Swnj int flag; 1824484Swnj { 1832281Stoy register struct tty *tp; 1845427Swnj struct pt_ioctl *pti; 1852281Stoy 1868563Sroot if (minor(dev) >= NPTY) 1878563Sroot return (ENXIO); 1882281Stoy tp = &pt_tty[minor(dev)]; 1898563Sroot if (tp->t_oproc) 1908563Sroot return (EIO); 1914484Swnj tp->t_oproc = ptsstart; 1925408Swnj if (tp->t_state & TS_WOPEN) 1932281Stoy wakeup((caddr_t)&tp->t_rawq); 1945408Swnj tp->t_state |= TS_CARR_ON; 1955427Swnj pti = &pt_ioctl[minor(dev)]; 1965427Swnj pti->pt_flags = 0; 1975427Swnj pti->pt_send = 0; 1988563Sroot return (0); 1992281Stoy } 2002281Stoy 2012281Stoy ptcclose(dev) 2024484Swnj dev_t dev; 2034484Swnj { 2042281Stoy register struct tty *tp; 2052281Stoy 2062281Stoy tp = &pt_tty[minor(dev)]; 2075408Swnj if (tp->t_state & TS_ISOPEN) 2082281Stoy gsignal(tp->t_pgrp, SIGHUP); 2095408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 2104484Swnj flushtty(tp, FREAD|FWRITE); 2114484Swnj tp->t_oproc = 0; /* mark closed */ 2122281Stoy } 2132281Stoy 2147823Sroot ptcread(dev, uio) 2155427Swnj dev_t dev; 2167823Sroot struct uio *uio; 2174484Swnj { 2188521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 2195427Swnj struct pt_ioctl *pti; 2208521Sroot int error = 0; 2212281Stoy 2225408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2238590Sroot return (EIO); 2245427Swnj pti = &pt_ioctl[minor(dev)]; 2255427Swnj if (pti->pt_flags & PF_PKT) { 2265427Swnj if (pti->pt_send) { 2278521Sroot error = ureadc(pti->pt_send, uio); 2288521Sroot if (error) 2298521Sroot return (error); 2305427Swnj pti->pt_send = 0; 2318521Sroot return (0); 2325427Swnj } 2338521Sroot error = ureadc(0, uio); 2345427Swnj } 2355411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 2368521Sroot if (pti->pt_flags&PF_NBIO) 2378521Sroot return (EWOULDBLOCK); 2382281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2395411Swnj } 2407823Sroot while (tp->t_outq.c_cc && uio->uio_resid > 0) 2417823Sroot if (ureadc(getc(&tp->t_outq), uio) < 0) { 2428521Sroot error = EFAULT; 2437823Sroot break; 2447823Sroot } 2455408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2465408Swnj if (tp->t_state&TS_ASLEEP) { 2475408Swnj tp->t_state &= ~TS_ASLEEP; 2485408Swnj wakeup((caddr_t)&tp->t_outq); 2495408Swnj } 2505408Swnj if (tp->t_wsel) { 2515408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2525408Swnj tp->t_wsel = 0; 2535408Swnj tp->t_state &= ~TS_WCOLL; 2545408Swnj } 2552281Stoy } 2568521Sroot return (error); 2572281Stoy } 2582281Stoy 2595427Swnj ptsstop(tp, flush) 2605427Swnj register struct tty *tp; 2615427Swnj int flush; 2625427Swnj { 2635427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2645427Swnj 2655574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 2665574Swnj if (flush == 0) { 2675574Swnj flush = TIOCPKT_STOP; 2685574Swnj pti->pt_flags |= PF_STOPPED; 2695574Swnj } else { 2705574Swnj pti->pt_flags &= ~PF_STOPPED; 2715574Swnj } 2726119Swnj pti->pt_send |= flush; 2735430Swnj ptcwakeup(tp); 2745427Swnj } 2755427Swnj 2765408Swnj ptcselect(dev, rw) 2774484Swnj dev_t dev; 2785408Swnj int rw; 2794484Swnj { 2804484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2815894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 2824484Swnj struct proc *p; 2835430Swnj int s; 2844484Swnj 2855408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2864484Swnj return (1); 2875430Swnj s = spl5(); 2885408Swnj switch (rw) { 2895408Swnj 2905408Swnj case FREAD: 2915430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 2925430Swnj splx(s); 2935408Swnj return (1); 2945430Swnj } 2955427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 2965427Swnj pti->pt_flags |= PF_RCOLL; 2975408Swnj else 2985427Swnj pti->pt_selr = u.u_procp; 2995430Swnj break; 3005408Swnj 3015408Swnj case FWRITE: 3025894Swnj if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 3035430Swnj splx(s); 3045408Swnj return (1); 3055430Swnj } 3065427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 3075427Swnj pti->pt_flags |= PF_WCOLL; 3085408Swnj else 3095427Swnj pti->pt_selw = u.u_procp; 3105430Swnj break; 3115408Swnj } 3125430Swnj splx(s); 3135430Swnj return (0); 3145396Sroot } 3154484Swnj 3167823Sroot ptcwrite(dev, uio) 3175408Swnj dev_t dev; 3187823Sroot struct uio *uio; 3194484Swnj { 3208521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 3212281Stoy register char *cp, *ce; 3222281Stoy register int cc; 3232281Stoy char locbuf[BUFSIZ]; 3245408Swnj int cnt = 0; 3255894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3268521Sroot int error = 0; 3272281Stoy 3285408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 3298521Sroot return (EIO); 3305894Swnj do { 3317823Sroot register struct iovec *iov; 3327823Sroot 3337823Sroot if (uio->uio_iovcnt == 0) 3347823Sroot break; 3357823Sroot iov = uio->uio_iov; 3367823Sroot if (iov->iov_len == 0) { 3377823Sroot uio->uio_iovcnt--; 3387823Sroot uio->uio_iov++; 3397823Sroot if (uio->uio_iovcnt < 0) 3407823Sroot panic("ptcwrite"); 3417823Sroot continue; 3427823Sroot } 3437823Sroot cc = MIN(iov->iov_len, BUFSIZ); 3442281Stoy cp = locbuf; 3458521Sroot error = uiomove(cp, cc, UIO_WRITE, uio); 3468521Sroot if (error) 3472281Stoy break; 3482281Stoy ce = cp + cc; 3495894Swnj again: 3505894Swnj if (pti->pt_flags & PF_REMOTE) { 3515894Swnj if (tp->t_rawq.c_cc) { 3525894Swnj if (pti->pt_flags & PF_NBIO) { 3537823Sroot iov->iov_base -= ce - cp; 3547823Sroot iov->iov_len += ce - cp; 3557823Sroot uio->uio_resid += ce - cp; 3567823Sroot uio->uio_offset -= ce - cp; 3578521Sroot return (EWOULDBLOCK); 3585894Swnj } 3595894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3605894Swnj goto again; 3615894Swnj } 3626158Ssam (void) b_to_q(cp, cc, &tp->t_rawq); 3636158Ssam (void) putc(0, &tp->t_rawq); 3645894Swnj wakeup((caddr_t)&tp->t_rawq); 3658521Sroot return (0); 3665894Swnj } 3674484Swnj while (cp < ce) { 3684484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 3692281Stoy wakeup((caddr_t)&tp->t_rawq); 3705408Swnj if (tp->t_state & TS_NBIO) { 3717823Sroot iov->iov_base -= ce - cp; 3727823Sroot iov->iov_len += ce - cp; 3737823Sroot uio->uio_resid += ce - cp; 3747823Sroot uio->uio_offset -= ce - cp; 3755408Swnj if (cnt == 0) 3768521Sroot return (EWOULDBLOCK); 3778521Sroot return (0); 3785408Swnj } 3792281Stoy /* Better than just flushing it! */ 3802281Stoy /* Wait for something to be read */ 3812281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3825894Swnj goto again; 3832281Stoy } 3844141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3855408Swnj cnt++; 3862281Stoy } 3877823Sroot } while (uio->uio_resid); 3888521Sroot return (error); 3892281Stoy } 3902281Stoy 3912281Stoy /*ARGSUSED*/ 3927626Ssam ptyioctl(dev, cmd, data, flag) 3937626Ssam caddr_t data; 3944484Swnj dev_t dev; 3954484Swnj { 3966119Swnj register struct tty *tp = &pt_tty[minor(dev)]; 3976119Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3988563Sroot int error; 3992281Stoy 4004484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 4017626Ssam if (cdevsw[major(dev)].d_open == ptcopen) 4027626Ssam switch (cmd) { 4037626Ssam 4047626Ssam case TIOCPKT: 4057626Ssam if (*(int *)data) 4065427Swnj pti->pt_flags |= PF_PKT; 4075427Swnj else 4085427Swnj pti->pt_flags &= ~PF_PKT; 4098563Sroot return (0); 4107626Ssam 4117626Ssam case TIOCREMOTE: 4127626Ssam if (*(int *)data) 4135894Swnj pti->pt_flags |= PF_REMOTE; 4145894Swnj else 4155894Swnj pti->pt_flags &= ~PF_REMOTE; 4165894Swnj flushtty(tp, FREAD|FWRITE); 4178563Sroot return (0); 4187626Ssam 4197626Ssam case FIONBIO: 4207626Ssam if (*(int *)data) 4215427Swnj pti->pt_flags |= PF_NBIO; 4225411Swnj else 4235427Swnj pti->pt_flags &= ~PF_NBIO; 4248563Sroot return (0); 4257626Ssam 4267626Ssam case TIOCSETP: 4277626Ssam while (getc(&tp->t_outq) >= 0) 4287626Ssam ; 4297626Ssam break; 4305411Swnj } 4318563Sroot error = ttioctl(tp, cmd, data, dev); 4328563Sroot if (error < 0) 4338563Sroot error = ENOTTY; 434*9561Ssam { int stop = (tp->t_stopc == ('s'&037) && 435*9561Ssam tp->t_startc == ('q'&037)); 4366119Swnj if (pti->pt_flags & PF_NOSTOP) { 4376119Swnj if (stop) { 4386119Swnj pti->pt_send &= TIOCPKT_NOSTOP; 4396119Swnj pti->pt_send |= TIOCPKT_DOSTOP; 4406119Swnj pti->pt_flags &= ~PF_NOSTOP; 4416119Swnj ptcwakeup(tp); 4426119Swnj } 4436119Swnj } else { 4446119Swnj if (stop == 0) { 4456119Swnj pti->pt_send &= ~TIOCPKT_DOSTOP; 4466119Swnj pti->pt_send |= TIOCPKT_NOSTOP; 4476119Swnj pti->pt_flags |= PF_NOSTOP; 4486119Swnj ptcwakeup(tp); 4496119Swnj } 4506119Swnj } 4516119Swnj } 4528563Sroot return (error); 4532281Stoy } 4542313Stoy #endif 455