1*15144Skarels /* tty_pty.c 6.3 83/10/01 */ 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" 129561Ssam #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 */ 6012642Ssam tp->t_ispeed = tp->t_ospeed = EXTB; 612427Swnj tp->t_flags = 0; /* No features (nor raw mode) */ 628563Sroot } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 638563Sroot return (EBUSY); 644484Swnj if (tp->t_oproc) /* Ctrlr still around. */ 655408Swnj tp->t_state |= TS_CARR_ON; 665408Swnj while ((tp->t_state & TS_CARR_ON) == 0) { 675408Swnj tp->t_state |= TS_WOPEN; 682281Stoy sleep((caddr_t)&tp->t_rawq, TTIPRI); 692281Stoy } 708563Sroot return ((*linesw[tp->t_line].l_open)(dev, tp)); 712281Stoy } 722281Stoy 732281Stoy ptsclose(dev) 745396Sroot dev_t dev; 755408Swnj { 762281Stoy register struct tty *tp; 772281Stoy 782281Stoy tp = &pt_tty[minor(dev)]; 792281Stoy (*linesw[tp->t_line].l_close)(tp); 806299Swnj ttyclose(tp); 812281Stoy } 822281Stoy 837823Sroot ptsread(dev, uio) 845396Sroot dev_t dev; 857823Sroot struct uio *uio; 864484Swnj { 875894Swnj register struct tty *tp = &pt_tty[minor(dev)]; 885894Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 898521Sroot int error = 0; 902281Stoy 915894Swnj again: 925894Swnj if (pti->pt_flags & PF_REMOTE) { 935894Swnj while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 94*15144Skarels #define bit(a) (1<<(a-1)) 95*15144Skarels if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 96*15144Skarels (u.u_procp->p_sigmask & bit(SIGTTIN)) || 975894Swnj /* 985894Swnj (u.u_procp->p_flag&SDETACH) || 995894Swnj */ 1005894Swnj u.u_procp->p_flag&SVFORK) 1018521Sroot return (EIO); 1025894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 1035894Swnj sleep((caddr_t)&lbolt, TTIPRI); 1045408Swnj } 105*15144Skarels #undef bit 1065894Swnj if (tp->t_rawq.c_cc == 0) { 1078521Sroot if (tp->t_state & TS_NBIO) 1088521Sroot return (EWOULDBLOCK); 1095894Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 1105894Swnj goto again; 1115894Swnj } 1127823Sroot while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0) 1137823Sroot if (ureadc(getc(&tp->t_rawq), uio) < 0) { 1148521Sroot error = EFAULT; 1157823Sroot break; 1167823Sroot } 1175894Swnj if (tp->t_rawq.c_cc == 1) 1185894Swnj (void) getc(&tp->t_rawq); 1195894Swnj if (tp->t_rawq.c_cc) 1208521Sroot return (error); 1215894Swnj } else 1225894Swnj if (tp->t_oproc) 1238521Sroot error = (*linesw[tp->t_line].l_read)(tp, uio); 1245894Swnj wakeup((caddr_t)&tp->t_rawq.c_cf); 1255894Swnj if (pti->pt_selw) { 1265894Swnj selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 1275894Swnj pti->pt_selw = 0; 1285894Swnj pti->pt_flags &= ~PF_WCOLL; 1292281Stoy } 1308521Sroot return (error); 1312281Stoy } 1322281Stoy 1335408Swnj /* 1345408Swnj * Write to pseudo-tty. 1355408Swnj * Wakeups of controlling tty will happen 1365408Swnj * indirectly, when tty driver calls ptsstart. 1375408Swnj */ 1387823Sroot ptswrite(dev, uio) 1395396Sroot dev_t dev; 1407823Sroot struct uio *uio; 1414484Swnj { 1422281Stoy register struct tty *tp; 1432281Stoy 1442281Stoy tp = &pt_tty[minor(dev)]; 1458521Sroot if (tp->t_oproc == 0) 1468521Sroot return (EIO); 1478521Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 1482281Stoy } 1492281Stoy 1505408Swnj /* 1515408Swnj * Start output on pseudo-tty. 1525408Swnj * Wake up process selecting or sleeping for input from controlling tty. 1535408Swnj */ 1542281Stoy ptsstart(tp) 1554484Swnj struct tty *tp; 1564484Swnj { 1575574Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1584484Swnj 1595408Swnj if (tp->t_state & TS_TTSTOP) 1602281Stoy return; 1615574Swnj if (pti->pt_flags & PF_STOPPED) { 1625574Swnj pti->pt_flags &= ~PF_STOPPED; 1635574Swnj pti->pt_send = TIOCPKT_START; 1645574Swnj } 1655430Swnj ptcwakeup(tp); 1665430Swnj } 1675430Swnj 1685430Swnj ptcwakeup(tp) 1695430Swnj struct tty *tp; 1705430Swnj { 1715430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1725430Swnj 1735427Swnj if (pti->pt_selr) { 1745427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1755427Swnj pti->pt_selr = 0; 1765427Swnj pti->pt_flags &= ~PF_RCOLL; 1774484Swnj } 1782281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1792281Stoy } 1802281Stoy 1812281Stoy /*ARGSUSED*/ 1822281Stoy ptcopen(dev, flag) 1834484Swnj dev_t dev; 1844484Swnj int flag; 1854484Swnj { 1862281Stoy register struct tty *tp; 1875427Swnj struct pt_ioctl *pti; 1882281Stoy 1898563Sroot if (minor(dev) >= NPTY) 1908563Sroot return (ENXIO); 1912281Stoy tp = &pt_tty[minor(dev)]; 1928563Sroot if (tp->t_oproc) 1938563Sroot return (EIO); 1944484Swnj tp->t_oproc = ptsstart; 1955408Swnj if (tp->t_state & TS_WOPEN) 1962281Stoy wakeup((caddr_t)&tp->t_rawq); 1975408Swnj tp->t_state |= TS_CARR_ON; 1985427Swnj pti = &pt_ioctl[minor(dev)]; 1995427Swnj pti->pt_flags = 0; 2005427Swnj pti->pt_send = 0; 2018563Sroot return (0); 2022281Stoy } 2032281Stoy 2042281Stoy ptcclose(dev) 2054484Swnj dev_t dev; 2064484Swnj { 2072281Stoy register struct tty *tp; 2082281Stoy 2092281Stoy tp = &pt_tty[minor(dev)]; 2105408Swnj if (tp->t_state & TS_ISOPEN) 2112281Stoy gsignal(tp->t_pgrp, SIGHUP); 2125408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 21312753Ssam ttyflush(tp, FREAD|FWRITE); 2144484Swnj tp->t_oproc = 0; /* mark closed */ 2152281Stoy } 2162281Stoy 2177823Sroot ptcread(dev, uio) 2185427Swnj dev_t dev; 2197823Sroot struct uio *uio; 2204484Swnj { 2218521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 2225427Swnj struct pt_ioctl *pti; 2238521Sroot int error = 0; 2242281Stoy 2255408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2268590Sroot return (EIO); 2275427Swnj pti = &pt_ioctl[minor(dev)]; 2285427Swnj if (pti->pt_flags & PF_PKT) { 2295427Swnj if (pti->pt_send) { 2308521Sroot error = ureadc(pti->pt_send, uio); 2318521Sroot if (error) 2328521Sroot return (error); 2335427Swnj pti->pt_send = 0; 2348521Sroot return (0); 2355427Swnj } 2368521Sroot error = ureadc(0, uio); 2375427Swnj } 2385411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 2398521Sroot if (pti->pt_flags&PF_NBIO) 2408521Sroot return (EWOULDBLOCK); 2412281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2425411Swnj } 2437823Sroot while (tp->t_outq.c_cc && uio->uio_resid > 0) 2447823Sroot if (ureadc(getc(&tp->t_outq), uio) < 0) { 2458521Sroot error = EFAULT; 2467823Sroot break; 2477823Sroot } 2485408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2495408Swnj if (tp->t_state&TS_ASLEEP) { 2505408Swnj tp->t_state &= ~TS_ASLEEP; 2515408Swnj wakeup((caddr_t)&tp->t_outq); 2525408Swnj } 2535408Swnj if (tp->t_wsel) { 2545408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2555408Swnj tp->t_wsel = 0; 2565408Swnj tp->t_state &= ~TS_WCOLL; 2575408Swnj } 2582281Stoy } 2598521Sroot return (error); 2602281Stoy } 2612281Stoy 2625427Swnj ptsstop(tp, flush) 2635427Swnj register struct tty *tp; 2645427Swnj int flush; 2655427Swnj { 2665427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2675427Swnj 2685574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 2695574Swnj if (flush == 0) { 2705574Swnj flush = TIOCPKT_STOP; 2715574Swnj pti->pt_flags |= PF_STOPPED; 2725574Swnj } else { 2735574Swnj pti->pt_flags &= ~PF_STOPPED; 2745574Swnj } 2756119Swnj pti->pt_send |= flush; 2765430Swnj ptcwakeup(tp); 2775427Swnj } 2785427Swnj 2795408Swnj ptcselect(dev, rw) 2804484Swnj dev_t dev; 2815408Swnj int rw; 2824484Swnj { 2834484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2845894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 2854484Swnj struct proc *p; 2865430Swnj int s; 2874484Swnj 2885408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2894484Swnj return (1); 2905430Swnj s = spl5(); 2915408Swnj switch (rw) { 2925408Swnj 2935408Swnj case FREAD: 2945430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 2955430Swnj splx(s); 2965408Swnj return (1); 2975430Swnj } 2985427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 2995427Swnj pti->pt_flags |= PF_RCOLL; 3005408Swnj else 3015427Swnj pti->pt_selr = u.u_procp; 3025430Swnj break; 3035408Swnj 3045408Swnj case FWRITE: 3055894Swnj if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 3065430Swnj splx(s); 3075408Swnj return (1); 3085430Swnj } 3095427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 3105427Swnj pti->pt_flags |= PF_WCOLL; 3115408Swnj else 3125427Swnj pti->pt_selw = u.u_procp; 3135430Swnj break; 3145408Swnj } 3155430Swnj splx(s); 3165430Swnj return (0); 3175396Sroot } 3184484Swnj 3197823Sroot ptcwrite(dev, uio) 3205408Swnj dev_t dev; 3217823Sroot struct uio *uio; 3224484Swnj { 3238521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 3242281Stoy register char *cp, *ce; 3252281Stoy register int cc; 3262281Stoy char locbuf[BUFSIZ]; 3275408Swnj int cnt = 0; 3285894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3298521Sroot int error = 0; 3302281Stoy 3315408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 3328521Sroot return (EIO); 3335894Swnj do { 3347823Sroot register struct iovec *iov; 3357823Sroot 3367823Sroot if (uio->uio_iovcnt == 0) 3377823Sroot break; 3387823Sroot iov = uio->uio_iov; 3397823Sroot if (iov->iov_len == 0) { 3407823Sroot uio->uio_iovcnt--; 3417823Sroot uio->uio_iov++; 3427823Sroot if (uio->uio_iovcnt < 0) 3437823Sroot panic("ptcwrite"); 3447823Sroot continue; 3457823Sroot } 3467823Sroot cc = MIN(iov->iov_len, BUFSIZ); 3472281Stoy cp = locbuf; 3488521Sroot error = uiomove(cp, cc, UIO_WRITE, uio); 3498521Sroot if (error) 3502281Stoy break; 3512281Stoy ce = cp + cc; 3525894Swnj again: 3535894Swnj if (pti->pt_flags & PF_REMOTE) { 3545894Swnj if (tp->t_rawq.c_cc) { 3555894Swnj if (pti->pt_flags & PF_NBIO) { 3567823Sroot iov->iov_base -= ce - cp; 3577823Sroot iov->iov_len += ce - cp; 3587823Sroot uio->uio_resid += ce - cp; 3597823Sroot uio->uio_offset -= ce - cp; 3608521Sroot return (EWOULDBLOCK); 3615894Swnj } 3625894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3635894Swnj goto again; 3645894Swnj } 3656158Ssam (void) b_to_q(cp, cc, &tp->t_rawq); 3666158Ssam (void) putc(0, &tp->t_rawq); 3675894Swnj wakeup((caddr_t)&tp->t_rawq); 3688521Sroot return (0); 3695894Swnj } 3704484Swnj while (cp < ce) { 37115104Skarels while ((tp->t_delct || tp->t_canq.c_cc) 37215104Skarels && (tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2) { 3732281Stoy wakeup((caddr_t)&tp->t_rawq); 3745408Swnj if (tp->t_state & TS_NBIO) { 3757823Sroot iov->iov_base -= ce - cp; 3767823Sroot iov->iov_len += ce - cp; 3777823Sroot uio->uio_resid += ce - cp; 3787823Sroot uio->uio_offset -= ce - cp; 3795408Swnj if (cnt == 0) 3808521Sroot return (EWOULDBLOCK); 3818521Sroot return (0); 3825408Swnj } 3832281Stoy /* Better than just flushing it! */ 3842281Stoy /* Wait for something to be read */ 3852281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3865894Swnj goto again; 3872281Stoy } 3884141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3895408Swnj cnt++; 3902281Stoy } 3917823Sroot } while (uio->uio_resid); 3928521Sroot return (error); 3932281Stoy } 3942281Stoy 3952281Stoy /*ARGSUSED*/ 3967626Ssam ptyioctl(dev, cmd, data, flag) 3977626Ssam caddr_t data; 3984484Swnj dev_t dev; 3994484Swnj { 4006119Swnj register struct tty *tp = &pt_tty[minor(dev)]; 4016119Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 4028563Sroot int error; 4032281Stoy 4044484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 4057626Ssam if (cdevsw[major(dev)].d_open == ptcopen) 4067626Ssam switch (cmd) { 4077626Ssam 4087626Ssam case TIOCPKT: 4097626Ssam if (*(int *)data) 4105427Swnj pti->pt_flags |= PF_PKT; 4115427Swnj else 4125427Swnj pti->pt_flags &= ~PF_PKT; 4138563Sroot return (0); 4147626Ssam 4157626Ssam case TIOCREMOTE: 4167626Ssam if (*(int *)data) 4175894Swnj pti->pt_flags |= PF_REMOTE; 4185894Swnj else 4195894Swnj pti->pt_flags &= ~PF_REMOTE; 42012753Ssam ttyflush(tp, FREAD|FWRITE); 4218563Sroot return (0); 4227626Ssam 4237626Ssam case FIONBIO: 4247626Ssam if (*(int *)data) 4255427Swnj pti->pt_flags |= PF_NBIO; 4265411Swnj else 4275427Swnj pti->pt_flags &= ~PF_NBIO; 4288563Sroot return (0); 4297626Ssam 4307626Ssam case TIOCSETP: 4317626Ssam while (getc(&tp->t_outq) >= 0) 4327626Ssam ; 4337626Ssam break; 4345411Swnj } 4358563Sroot error = ttioctl(tp, cmd, data, dev); 4368563Sroot if (error < 0) 4378563Sroot error = ENOTTY; 4389561Ssam { int stop = (tp->t_stopc == ('s'&037) && 4399561Ssam tp->t_startc == ('q'&037)); 4406119Swnj if (pti->pt_flags & PF_NOSTOP) { 4416119Swnj if (stop) { 4426119Swnj pti->pt_send &= TIOCPKT_NOSTOP; 4436119Swnj pti->pt_send |= TIOCPKT_DOSTOP; 4446119Swnj pti->pt_flags &= ~PF_NOSTOP; 4456119Swnj ptcwakeup(tp); 4466119Swnj } 4476119Swnj } else { 4486119Swnj if (stop == 0) { 4496119Swnj pti->pt_send &= ~TIOCPKT_DOSTOP; 4506119Swnj pti->pt_send |= TIOCPKT_NOSTOP; 4516119Swnj pti->pt_flags |= PF_NOSTOP; 4526119Swnj ptcwakeup(tp); 4536119Swnj } 4546119Swnj } 4556119Swnj } 4568563Sroot return (error); 4572281Stoy } 4582313Stoy #endif 459