1*8563Sroot /* tty_pty.c 4.27 82/10/17 */ 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" 122281Stoy #include "../h/tty.h" 132281Stoy #include "../h/dir.h" 142281Stoy #include "../h/user.h" 152281Stoy #include "../h/conf.h" 162427Swnj #include "../h/file.h" 174484Swnj #include "../h/proc.h" 187823Sroot #include "../h/uio.h" 198155Sroot #include "../h/kernel.h" 206239Sroot 217475Ssam #if NPTY == 1 225408Swnj #undef NPTY 236239Sroot #define NPTY 32 /* crude XXX */ 247475Ssam #endif 252281Stoy 262427Swnj #define BUFSIZ 100 /* Chunk size iomoved from user */ 274484Swnj 282281Stoy /* 294484Swnj * pts == /dev/tty[pP]? 304484Swnj * ptc == /dev/ptp[pP]? 312281Stoy */ 324484Swnj struct tty pt_tty[NPTY]; 334484Swnj struct pt_ioctl { 345427Swnj int pt_flags; 355427Swnj int pt_gensym; 365427Swnj struct proc *pt_selr, *pt_selw; 375427Swnj int pt_send; 384484Swnj } pt_ioctl[NPTY]; 392281Stoy 405427Swnj #define PF_RCOLL 0x01 415427Swnj #define PF_WCOLL 0x02 425427Swnj #define PF_NBIO 0x04 435427Swnj #define PF_PKT 0x08 /* packet mode */ 445574Swnj #define PF_STOPPED 0x10 /* user told stopped */ 455894Swnj #define PF_REMOTE 0x20 /* remote and flow controlled input */ 466119Swnj #define PF_NOSTOP 0x40 472281Stoy 482281Stoy /*ARGSUSED*/ 492281Stoy ptsopen(dev, flag) 505396Sroot dev_t dev; 514484Swnj { 522281Stoy register struct tty *tp; 532281Stoy 54*8563Sroot if (minor(dev) >= NPTY) 55*8563Sroot return (ENXIO); 562281Stoy tp = &pt_tty[minor(dev)]; 575408Swnj if ((tp->t_state & TS_ISOPEN) == 0) { 582427Swnj ttychars(tp); /* Set up default chars */ 592427Swnj tp->t_flags = 0; /* No features (nor raw mode) */ 60*8563Sroot } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 61*8563Sroot return (EBUSY); 624484Swnj if (tp->t_oproc) /* Ctrlr still around. */ 635408Swnj tp->t_state |= TS_CARR_ON; 645408Swnj while ((tp->t_state & TS_CARR_ON) == 0) { 655408Swnj tp->t_state |= TS_WOPEN; 662281Stoy sleep((caddr_t)&tp->t_rawq, TTIPRI); 672281Stoy } 68*8563Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 692281Stoy } 702281Stoy 712281Stoy ptsclose(dev) 725396Sroot dev_t dev; 735408Swnj { 742281Stoy register struct tty *tp; 752281Stoy 762281Stoy tp = &pt_tty[minor(dev)]; 772281Stoy (*linesw[tp->t_line].l_close)(tp); 786299Swnj ttyclose(tp); 792281Stoy } 802281Stoy 817823Sroot ptsread(dev, uio) 825396Sroot dev_t dev; 837823Sroot struct uio *uio; 844484Swnj { 855894Swnj register struct tty *tp = &pt_tty[minor(dev)]; 865894Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 878521Sroot int error = 0; 882281Stoy 895894Swnj again: 905894Swnj if (pti->pt_flags & PF_REMOTE) { 915894Swnj while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 925894Swnj if (u.u_signal[SIGTTIN] == SIG_IGN || 935894Swnj u.u_signal[SIGTTIN] == SIG_HOLD || 945894Swnj /* 955894Swnj (u.u_procp->p_flag&SDETACH) || 965894Swnj */ 975894Swnj u.u_procp->p_flag&SVFORK) 988521Sroot return (EIO); 995894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 1005894Swnj sleep((caddr_t)&lbolt, TTIPRI); 1015408Swnj } 1025894Swnj if (tp->t_rawq.c_cc == 0) { 1038521Sroot if (tp->t_state & TS_NBIO) 1048521Sroot return (EWOULDBLOCK); 1055894Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 1065894Swnj goto again; 1075894Swnj } 1087823Sroot while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0) 1097823Sroot if (ureadc(getc(&tp->t_rawq), uio) < 0) { 1108521Sroot error = EFAULT; 1117823Sroot break; 1127823Sroot } 1135894Swnj if (tp->t_rawq.c_cc == 1) 1145894Swnj (void) getc(&tp->t_rawq); 1155894Swnj if (tp->t_rawq.c_cc) 1168521Sroot return (error); 1175894Swnj } else 1185894Swnj if (tp->t_oproc) 1198521Sroot error = (*linesw[tp->t_line].l_read)(tp, uio); 1205894Swnj wakeup((caddr_t)&tp->t_rawq.c_cf); 1215894Swnj if (pti->pt_selw) { 1225894Swnj selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 1235894Swnj pti->pt_selw = 0; 1245894Swnj pti->pt_flags &= ~PF_WCOLL; 1252281Stoy } 1268521Sroot return (error); 1272281Stoy } 1282281Stoy 1295408Swnj /* 1305408Swnj * Write to pseudo-tty. 1315408Swnj * Wakeups of controlling tty will happen 1325408Swnj * indirectly, when tty driver calls ptsstart. 1335408Swnj */ 1347823Sroot ptswrite(dev, uio) 1355396Sroot dev_t dev; 1367823Sroot struct uio *uio; 1374484Swnj { 1382281Stoy register struct tty *tp; 1392281Stoy 1402281Stoy tp = &pt_tty[minor(dev)]; 1418521Sroot if (tp->t_oproc == 0) 1428521Sroot return (EIO); 1438521Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 1442281Stoy } 1452281Stoy 1465408Swnj /* 1475408Swnj * Start output on pseudo-tty. 1485408Swnj * Wake up process selecting or sleeping for input from controlling tty. 1495408Swnj */ 1502281Stoy ptsstart(tp) 1514484Swnj struct tty *tp; 1524484Swnj { 1535574Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1544484Swnj 1555408Swnj if (tp->t_state & TS_TTSTOP) 1562281Stoy return; 1575574Swnj if (pti->pt_flags & PF_STOPPED) { 1585574Swnj pti->pt_flags &= ~PF_STOPPED; 1595574Swnj pti->pt_send = TIOCPKT_START; 1605574Swnj } 1615430Swnj ptcwakeup(tp); 1625430Swnj } 1635430Swnj 1645430Swnj ptcwakeup(tp) 1655430Swnj struct tty *tp; 1665430Swnj { 1675430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1685430Swnj 1695427Swnj if (pti->pt_selr) { 1705427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1715427Swnj pti->pt_selr = 0; 1725427Swnj pti->pt_flags &= ~PF_RCOLL; 1734484Swnj } 1742281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1752281Stoy } 1762281Stoy 1772281Stoy /*ARGSUSED*/ 1782281Stoy ptcopen(dev, flag) 1794484Swnj dev_t dev; 1804484Swnj int flag; 1814484Swnj { 1822281Stoy register struct tty *tp; 1835427Swnj struct pt_ioctl *pti; 1842281Stoy 185*8563Sroot if (minor(dev) >= NPTY) 186*8563Sroot return (ENXIO); 1872281Stoy tp = &pt_tty[minor(dev)]; 188*8563Sroot if (tp->t_oproc) 189*8563Sroot return (EIO); 1904484Swnj tp->t_oproc = ptsstart; 1915408Swnj if (tp->t_state & TS_WOPEN) 1922281Stoy wakeup((caddr_t)&tp->t_rawq); 1935408Swnj tp->t_state |= TS_CARR_ON; 1945427Swnj pti = &pt_ioctl[minor(dev)]; 1955427Swnj pti->pt_flags = 0; 1965427Swnj pti->pt_send = 0; 197*8563Sroot return (0); 1982281Stoy } 1992281Stoy 2002281Stoy ptcclose(dev) 2014484Swnj dev_t dev; 2024484Swnj { 2032281Stoy register struct tty *tp; 2042281Stoy 2052281Stoy tp = &pt_tty[minor(dev)]; 2065408Swnj if (tp->t_state & TS_ISOPEN) 2072281Stoy gsignal(tp->t_pgrp, SIGHUP); 2085408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 2094484Swnj flushtty(tp, FREAD|FWRITE); 2104484Swnj tp->t_oproc = 0; /* mark closed */ 2112281Stoy } 2122281Stoy 2137823Sroot ptcread(dev, uio) 2145427Swnj dev_t dev; 2157823Sroot struct uio *uio; 2164484Swnj { 2178521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 2185427Swnj struct pt_ioctl *pti; 2198521Sroot int error = 0; 2202281Stoy 2215408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2222281Stoy return; 2235427Swnj pti = &pt_ioctl[minor(dev)]; 2245427Swnj if (pti->pt_flags & PF_PKT) { 2255427Swnj if (pti->pt_send) { 2268521Sroot error = ureadc(pti->pt_send, uio); 2278521Sroot if (error) 2288521Sroot return (error); 2295427Swnj pti->pt_send = 0; 2308521Sroot return (0); 2315427Swnj } 2328521Sroot error = ureadc(0, uio); 2335427Swnj } 2345411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 2358521Sroot if (pti->pt_flags&PF_NBIO) 2368521Sroot return (EWOULDBLOCK); 2372281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2385411Swnj } 2397823Sroot while (tp->t_outq.c_cc && uio->uio_resid > 0) 2407823Sroot if (ureadc(getc(&tp->t_outq), uio) < 0) { 2418521Sroot error = EFAULT; 2427823Sroot break; 2437823Sroot } 2445408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2455408Swnj if (tp->t_state&TS_ASLEEP) { 2465408Swnj tp->t_state &= ~TS_ASLEEP; 2475408Swnj wakeup((caddr_t)&tp->t_outq); 2485408Swnj } 2495408Swnj if (tp->t_wsel) { 2505408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2515408Swnj tp->t_wsel = 0; 2525408Swnj tp->t_state &= ~TS_WCOLL; 2535408Swnj } 2542281Stoy } 2558521Sroot return (error); 2562281Stoy } 2572281Stoy 2585427Swnj ptsstop(tp, flush) 2595427Swnj register struct tty *tp; 2605427Swnj int flush; 2615427Swnj { 2625427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2635427Swnj 2645574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 2655574Swnj if (flush == 0) { 2665574Swnj flush = TIOCPKT_STOP; 2675574Swnj pti->pt_flags |= PF_STOPPED; 2685574Swnj } else { 2695574Swnj pti->pt_flags &= ~PF_STOPPED; 2705574Swnj } 2716119Swnj pti->pt_send |= flush; 2725430Swnj ptcwakeup(tp); 2735427Swnj } 2745427Swnj 2755408Swnj ptcselect(dev, rw) 2764484Swnj dev_t dev; 2775408Swnj int rw; 2784484Swnj { 2794484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2805894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 2814484Swnj struct proc *p; 2825430Swnj int s; 2834484Swnj 2845408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2854484Swnj return (1); 2865430Swnj s = spl5(); 2875408Swnj switch (rw) { 2885408Swnj 2895408Swnj case FREAD: 2905430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 2915430Swnj splx(s); 2925408Swnj return (1); 2935430Swnj } 2945427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 2955427Swnj pti->pt_flags |= PF_RCOLL; 2965408Swnj else 2975427Swnj pti->pt_selr = u.u_procp; 2985430Swnj break; 2995408Swnj 3005408Swnj case FWRITE: 3015894Swnj if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 3025430Swnj splx(s); 3035408Swnj return (1); 3045430Swnj } 3055427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 3065427Swnj pti->pt_flags |= PF_WCOLL; 3075408Swnj else 3085427Swnj pti->pt_selw = u.u_procp; 3095430Swnj break; 3105408Swnj } 3115430Swnj splx(s); 3125430Swnj return (0); 3135396Sroot } 3144484Swnj 3157823Sroot ptcwrite(dev, uio) 3165408Swnj dev_t dev; 3177823Sroot struct uio *uio; 3184484Swnj { 3198521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 3202281Stoy register char *cp, *ce; 3212281Stoy register int cc; 3222281Stoy char locbuf[BUFSIZ]; 3235408Swnj int cnt = 0; 3245894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3258521Sroot int error = 0; 3262281Stoy 3275408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 3288521Sroot return (EIO); 3295894Swnj do { 3307823Sroot register struct iovec *iov; 3317823Sroot 3327823Sroot if (uio->uio_iovcnt == 0) 3337823Sroot break; 3347823Sroot iov = uio->uio_iov; 3357823Sroot if (iov->iov_len == 0) { 3367823Sroot uio->uio_iovcnt--; 3377823Sroot uio->uio_iov++; 3387823Sroot if (uio->uio_iovcnt < 0) 3397823Sroot panic("ptcwrite"); 3407823Sroot continue; 3417823Sroot } 3427823Sroot cc = MIN(iov->iov_len, BUFSIZ); 3432281Stoy cp = locbuf; 3448521Sroot error = uiomove(cp, cc, UIO_WRITE, uio); 3458521Sroot if (error) 3462281Stoy break; 3472281Stoy ce = cp + cc; 3485894Swnj again: 3495894Swnj if (pti->pt_flags & PF_REMOTE) { 3505894Swnj if (tp->t_rawq.c_cc) { 3515894Swnj if (pti->pt_flags & PF_NBIO) { 3527823Sroot iov->iov_base -= ce - cp; 3537823Sroot iov->iov_len += ce - cp; 3547823Sroot uio->uio_resid += ce - cp; 3557823Sroot uio->uio_offset -= ce - cp; 3568521Sroot return (EWOULDBLOCK); 3575894Swnj } 3585894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3595894Swnj goto again; 3605894Swnj } 3616158Ssam (void) b_to_q(cp, cc, &tp->t_rawq); 3626158Ssam (void) putc(0, &tp->t_rawq); 3635894Swnj wakeup((caddr_t)&tp->t_rawq); 3648521Sroot return (0); 3655894Swnj } 3664484Swnj while (cp < ce) { 3674484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 3682281Stoy wakeup((caddr_t)&tp->t_rawq); 3695408Swnj if (tp->t_state & TS_NBIO) { 3707823Sroot iov->iov_base -= ce - cp; 3717823Sroot iov->iov_len += ce - cp; 3727823Sroot uio->uio_resid += ce - cp; 3737823Sroot uio->uio_offset -= ce - cp; 3745408Swnj if (cnt == 0) 3758521Sroot return (EWOULDBLOCK); 3768521Sroot return (0); 3775408Swnj } 3782281Stoy /* Better than just flushing it! */ 3792281Stoy /* Wait for something to be read */ 3802281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3815894Swnj goto again; 3822281Stoy } 3834141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3845408Swnj cnt++; 3852281Stoy } 3867823Sroot } while (uio->uio_resid); 3878521Sroot return (error); 3882281Stoy } 3892281Stoy 3902281Stoy /*ARGSUSED*/ 3917626Ssam ptyioctl(dev, cmd, data, flag) 3927626Ssam caddr_t data; 3934484Swnj dev_t dev; 3944484Swnj { 3956119Swnj register struct tty *tp = &pt_tty[minor(dev)]; 3966119Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 397*8563Sroot int error; 3982281Stoy 3994484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 4007626Ssam if (cdevsw[major(dev)].d_open == ptcopen) 4017626Ssam switch (cmd) { 4027626Ssam 4037626Ssam case TIOCPKT: 4047626Ssam if (*(int *)data) 4055427Swnj pti->pt_flags |= PF_PKT; 4065427Swnj else 4075427Swnj pti->pt_flags &= ~PF_PKT; 408*8563Sroot return (0); 4097626Ssam 4107626Ssam case TIOCREMOTE: 4117626Ssam if (*(int *)data) 4125894Swnj pti->pt_flags |= PF_REMOTE; 4135894Swnj else 4145894Swnj pti->pt_flags &= ~PF_REMOTE; 4155894Swnj flushtty(tp, FREAD|FWRITE); 416*8563Sroot return (0); 4177626Ssam 4187626Ssam case FIONBIO: 4197626Ssam if (*(int *)data) 4205427Swnj pti->pt_flags |= PF_NBIO; 4215411Swnj else 4225427Swnj pti->pt_flags &= ~PF_NBIO; 423*8563Sroot return (0); 4247626Ssam 4257626Ssam case TIOCSETP: 4267626Ssam while (getc(&tp->t_outq) >= 0) 4277626Ssam ; 4287626Ssam break; 4295411Swnj } 430*8563Sroot error = ttioctl(tp, cmd, data, dev); 431*8563Sroot if (error < 0) 432*8563Sroot error = ENOTTY; 4336119Swnj { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && 4346119Swnj tp->t_un.t_chr.t_startc == ('q'&037)); 4356119Swnj if (pti->pt_flags & PF_NOSTOP) { 4366119Swnj if (stop) { 4376119Swnj pti->pt_send &= TIOCPKT_NOSTOP; 4386119Swnj pti->pt_send |= TIOCPKT_DOSTOP; 4396119Swnj pti->pt_flags &= ~PF_NOSTOP; 4406119Swnj ptcwakeup(tp); 4416119Swnj } 4426119Swnj } else { 4436119Swnj if (stop == 0) { 4446119Swnj pti->pt_send &= ~TIOCPKT_DOSTOP; 4456119Swnj pti->pt_send |= TIOCPKT_NOSTOP; 4466119Swnj pti->pt_flags |= PF_NOSTOP; 4476119Swnj ptcwakeup(tp); 4486119Swnj } 4496119Swnj } 4506119Swnj } 451*8563Sroot return (error); 4522281Stoy } 4532313Stoy #endif 454