1*6299Swnj /* tty_pty.c 4.21 82/03/23 */ 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" 162281Stoy #include "../h/buf.h" 172427Swnj #include "../h/file.h" 184484Swnj #include "../h/proc.h" 196239Sroot 205408Swnj #undef NPTY 216239Sroot #define NPTY 32 /* crude XXX */ 222281Stoy 232427Swnj #define BUFSIZ 100 /* Chunk size iomoved from user */ 244484Swnj 252281Stoy /* 264484Swnj * pts == /dev/tty[pP]? 274484Swnj * ptc == /dev/ptp[pP]? 282281Stoy */ 294484Swnj struct tty pt_tty[NPTY]; 304484Swnj struct pt_ioctl { 315427Swnj int pt_flags; 325427Swnj int pt_gensym; 335427Swnj struct proc *pt_selr, *pt_selw; 345427Swnj int pt_send; 354484Swnj } pt_ioctl[NPTY]; 362281Stoy 375427Swnj #define PF_RCOLL 0x01 385427Swnj #define PF_WCOLL 0x02 395427Swnj #define PF_NBIO 0x04 405427Swnj #define PF_PKT 0x08 /* packet mode */ 415574Swnj #define PF_STOPPED 0x10 /* user told stopped */ 425894Swnj #define PF_REMOTE 0x20 /* remote and flow controlled input */ 436119Swnj #define PF_NOSTOP 0x40 442281Stoy 452281Stoy /*ARGSUSED*/ 462281Stoy ptsopen(dev, flag) 475396Sroot dev_t dev; 484484Swnj { 492281Stoy register struct tty *tp; 502281Stoy 514484Swnj if (minor(dev) >= NPTY) { 522281Stoy u.u_error = ENXIO; 532281Stoy return; 542281Stoy } 552281Stoy tp = &pt_tty[minor(dev)]; 565408Swnj if ((tp->t_state & TS_ISOPEN) == 0) { 572427Swnj ttychars(tp); /* Set up default chars */ 582427Swnj tp->t_flags = 0; /* No features (nor raw mode) */ 595408Swnj } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) { 602281Stoy u.u_error = EBUSY; 612281Stoy return; 622281Stoy } 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 } 692281Stoy (*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); 79*6299Swnj ttyclose(tp); 802281Stoy } 812281Stoy 822281Stoy ptsread(dev) 835396Sroot dev_t dev; 844484Swnj { 855894Swnj register struct tty *tp = &pt_tty[minor(dev)]; 865894Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 872281Stoy 885894Swnj again: 895894Swnj if (pti->pt_flags & PF_REMOTE) { 905894Swnj while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 915894Swnj if (u.u_signal[SIGTTIN] == SIG_IGN || 925894Swnj u.u_signal[SIGTTIN] == SIG_HOLD || 935894Swnj /* 945894Swnj (u.u_procp->p_flag&SDETACH) || 955894Swnj */ 965894Swnj u.u_procp->p_flag&SVFORK) 975894Swnj return; 985894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 995894Swnj sleep((caddr_t)&lbolt, TTIPRI); 1005408Swnj } 1015894Swnj if (tp->t_rawq.c_cc == 0) { 1025894Swnj if (tp->t_state & TS_NBIO) { 1035894Swnj u.u_error = EWOULDBLOCK; 1045894Swnj return; 1055894Swnj } 1065894Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 1075894Swnj goto again; 1085894Swnj } 1095894Swnj while (tp->t_rawq.c_cc > 1 && passc(getc(&tp->t_rawq)) >= 0) 1105894Swnj ; 1115894Swnj if (tp->t_rawq.c_cc == 1) 1125894Swnj (void) getc(&tp->t_rawq); 1135894Swnj if (tp->t_rawq.c_cc) 1145894Swnj return; 1155894Swnj } else 1165894Swnj if (tp->t_oproc) 1175894Swnj (*linesw[tp->t_line].l_read)(tp); 1185894Swnj wakeup((caddr_t)&tp->t_rawq.c_cf); 1195894Swnj if (pti->pt_selw) { 1205894Swnj selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 1215894Swnj pti->pt_selw = 0; 1225894Swnj pti->pt_flags &= ~PF_WCOLL; 1232281Stoy } 1242281Stoy } 1252281Stoy 1265408Swnj /* 1275408Swnj * Write to pseudo-tty. 1285408Swnj * Wakeups of controlling tty will happen 1295408Swnj * indirectly, when tty driver calls ptsstart. 1305408Swnj */ 1312281Stoy ptswrite(dev) 1325396Sroot dev_t dev; 1334484Swnj { 1342281Stoy register struct tty *tp; 1352281Stoy 1362281Stoy tp = &pt_tty[minor(dev)]; 1374484Swnj if (tp->t_oproc) 1382281Stoy (*linesw[tp->t_line].l_write)(tp); 1392281Stoy } 1402281Stoy 1415408Swnj /* 1425408Swnj * Start output on pseudo-tty. 1435408Swnj * Wake up process selecting or sleeping for input from controlling tty. 1445408Swnj */ 1452281Stoy ptsstart(tp) 1464484Swnj struct tty *tp; 1474484Swnj { 1485574Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1494484Swnj 1505408Swnj if (tp->t_state & TS_TTSTOP) 1512281Stoy return; 1525574Swnj if (pti->pt_flags & PF_STOPPED) { 1535574Swnj pti->pt_flags &= ~PF_STOPPED; 1545574Swnj pti->pt_send = TIOCPKT_START; 1555574Swnj } 1565430Swnj ptcwakeup(tp); 1575430Swnj } 1585430Swnj 1595430Swnj ptcwakeup(tp) 1605430Swnj struct tty *tp; 1615430Swnj { 1625430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1635430Swnj 1645427Swnj if (pti->pt_selr) { 1655427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1665427Swnj pti->pt_selr = 0; 1675427Swnj pti->pt_flags &= ~PF_RCOLL; 1684484Swnj } 1692281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1702281Stoy } 1712281Stoy 1722281Stoy /*ARGSUSED*/ 1732281Stoy ptcopen(dev, flag) 1744484Swnj dev_t dev; 1754484Swnj int flag; 1764484Swnj { 1772281Stoy register struct tty *tp; 1785427Swnj struct pt_ioctl *pti; 1792281Stoy 1804484Swnj if (minor(dev) >= NPTY) { 1812281Stoy u.u_error = ENXIO; 1822281Stoy return; 1832281Stoy } 1842281Stoy tp = &pt_tty[minor(dev)]; 1854484Swnj if (tp->t_oproc) { 1862281Stoy u.u_error = EIO; 1872281Stoy return; 1882281Stoy } 1894484Swnj tp->t_oproc = ptsstart; 1905408Swnj if (tp->t_state & TS_WOPEN) 1912281Stoy wakeup((caddr_t)&tp->t_rawq); 1925408Swnj tp->t_state |= TS_CARR_ON; 1935427Swnj pti = &pt_ioctl[minor(dev)]; 1945427Swnj pti->pt_flags = 0; 1955427Swnj pti->pt_send = 0; 1962281Stoy } 1972281Stoy 1982281Stoy ptcclose(dev) 1994484Swnj dev_t dev; 2004484Swnj { 2012281Stoy register struct tty *tp; 2022281Stoy 2032281Stoy tp = &pt_tty[minor(dev)]; 2045408Swnj if (tp->t_state & TS_ISOPEN) 2052281Stoy gsignal(tp->t_pgrp, SIGHUP); 2065408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 2074484Swnj flushtty(tp, FREAD|FWRITE); 2084484Swnj tp->t_oproc = 0; /* mark closed */ 2092281Stoy } 2102281Stoy 2112281Stoy ptcread(dev) 2125427Swnj dev_t dev; 2134484Swnj { 2142281Stoy register struct tty *tp; 2155427Swnj struct pt_ioctl *pti; 2162281Stoy 2172281Stoy tp = &pt_tty[minor(dev)]; 2185408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2192281Stoy return; 2205427Swnj pti = &pt_ioctl[minor(dev)]; 2215427Swnj if (pti->pt_flags & PF_PKT) { 2225427Swnj if (pti->pt_send) { 2236158Ssam (void) passc(pti->pt_send); 2245427Swnj pti->pt_send = 0; 2255427Swnj return; 2265427Swnj } 2276158Ssam (void) passc(0); 2285427Swnj } 2295411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 2305427Swnj if (pti->pt_flags&PF_NBIO) { 2315411Swnj u.u_error = EWOULDBLOCK; 2325411Swnj return; 2335411Swnj } 2342281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2355411Swnj } 2365408Swnj while (tp->t_outq.c_cc && passc(getc(&tp->t_outq)) >= 0) 2375408Swnj ; 2385408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2395408Swnj if (tp->t_state&TS_ASLEEP) { 2405408Swnj tp->t_state &= ~TS_ASLEEP; 2415408Swnj wakeup((caddr_t)&tp->t_outq); 2425408Swnj } 2435408Swnj if (tp->t_wsel) { 2445408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2455408Swnj tp->t_wsel = 0; 2465408Swnj tp->t_state &= ~TS_WCOLL; 2475408Swnj } 2482281Stoy } 2492281Stoy } 2502281Stoy 2515427Swnj ptsstop(tp, flush) 2525427Swnj register struct tty *tp; 2535427Swnj int flush; 2545427Swnj { 2555427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2565427Swnj 2575574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 2585574Swnj if (flush == 0) { 2595574Swnj flush = TIOCPKT_STOP; 2605574Swnj pti->pt_flags |= PF_STOPPED; 2615574Swnj } else { 2625574Swnj pti->pt_flags &= ~PF_STOPPED; 2635574Swnj } 2646119Swnj pti->pt_send |= flush; 2655430Swnj ptcwakeup(tp); 2665427Swnj } 2675427Swnj 2685408Swnj ptcselect(dev, rw) 2694484Swnj dev_t dev; 2705408Swnj int rw; 2714484Swnj { 2724484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2735894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 2744484Swnj struct proc *p; 2755430Swnj int s; 2764484Swnj 2775408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2784484Swnj return (1); 2795430Swnj s = spl5(); 2805408Swnj switch (rw) { 2815408Swnj 2825408Swnj case FREAD: 2835430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 2845430Swnj splx(s); 2855408Swnj return (1); 2865430Swnj } 2875427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 2885427Swnj pti->pt_flags |= PF_RCOLL; 2895408Swnj else 2905427Swnj pti->pt_selr = u.u_procp; 2915430Swnj break; 2925408Swnj 2935408Swnj case FWRITE: 2945894Swnj if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 2955430Swnj splx(s); 2965408Swnj return (1); 2975430Swnj } 2985427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 2995427Swnj pti->pt_flags |= PF_WCOLL; 3005408Swnj else 3015427Swnj pti->pt_selw = u.u_procp; 3025430Swnj break; 3035408Swnj } 3045430Swnj splx(s); 3055430Swnj return (0); 3065396Sroot } 3074484Swnj 3082281Stoy ptcwrite(dev) 3095408Swnj dev_t dev; 3104484Swnj { 3112281Stoy register struct tty *tp; 3122281Stoy register char *cp, *ce; 3132281Stoy register int cc; 3142281Stoy char locbuf[BUFSIZ]; 3155408Swnj int cnt = 0; 3165894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3172281Stoy 3182281Stoy tp = &pt_tty[minor(dev)]; 3195408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 3202281Stoy return; 3215894Swnj do { 3222281Stoy cc = MIN(u.u_count, BUFSIZ); 3232281Stoy cp = locbuf; 3242281Stoy iomove(cp, (unsigned)cc, B_WRITE); 3254484Swnj if (u.u_error) 3262281Stoy break; 3272281Stoy ce = cp + cc; 3285894Swnj again: 3295894Swnj if (pti->pt_flags & PF_REMOTE) { 3305894Swnj if (tp->t_rawq.c_cc) { 3315894Swnj if (pti->pt_flags & PF_NBIO) { 3325894Swnj u.u_count += ce - cp; 3335894Swnj u.u_error = EWOULDBLOCK; 3345894Swnj return; 3355894Swnj } 3365894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3375894Swnj goto again; 3385894Swnj } 3396158Ssam (void) b_to_q(cp, cc, &tp->t_rawq); 3406158Ssam (void) putc(0, &tp->t_rawq); 3415894Swnj wakeup((caddr_t)&tp->t_rawq); 3425894Swnj return; 3435894Swnj } 3444484Swnj while (cp < ce) { 3454484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 3462281Stoy wakeup((caddr_t)&tp->t_rawq); 3475408Swnj if (tp->t_state & TS_NBIO) { 3485408Swnj u.u_count += ce - cp; 3495408Swnj if (cnt == 0) 3505408Swnj u.u_error = EWOULDBLOCK; 3515408Swnj return; 3525408Swnj } 3532281Stoy /* Better than just flushing it! */ 3542281Stoy /* Wait for something to be read */ 3552281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3565894Swnj goto again; 3572281Stoy } 3584141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3595408Swnj cnt++; 3602281Stoy } 3615894Swnj } while (u.u_count); 3622281Stoy } 3632281Stoy 3642281Stoy /*ARGSUSED*/ 3652281Stoy ptyioctl(dev, cmd, addr, flag) 3664484Swnj caddr_t addr; 3674484Swnj dev_t dev; 3684484Swnj { 3696119Swnj register struct tty *tp = &pt_tty[minor(dev)]; 3706119Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3712281Stoy 3724484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 3735411Swnj if (cdevsw[major(dev)].d_open == ptcopen) { 3745427Swnj if (cmd == TIOCPKT) { 3755427Swnj int packet; 3766158Ssam if (copyin((caddr_t)addr, (caddr_t)&packet, sizeof (packet))) { 3775427Swnj u.u_error = EFAULT; 3785427Swnj return; 3795427Swnj } 3805427Swnj if (packet) 3815427Swnj pti->pt_flags |= PF_PKT; 3825427Swnj else 3835427Swnj pti->pt_flags &= ~PF_PKT; 3845427Swnj return; 3855427Swnj } 3865894Swnj if (cmd == TIOCREMOTE) { 3875894Swnj int remote; 3886158Ssam if (copyin((caddr_t)addr, (caddr_t)&remote, sizeof (remote))) { 3895894Swnj u.u_error = EFAULT; 3905894Swnj return; 3915894Swnj } 3925894Swnj if (remote) 3935894Swnj pti->pt_flags |= PF_REMOTE; 3945894Swnj else 3955894Swnj pti->pt_flags &= ~PF_REMOTE; 3965894Swnj flushtty(tp, FREAD|FWRITE); 3975894Swnj return; 3985894Swnj } 3995411Swnj if (cmd == FIONBIO) { 4005411Swnj int nbio; 4016158Ssam if (copyin((caddr_t)addr, (caddr_t)&nbio, sizeof (nbio))) { 4025411Swnj u.u_error = EFAULT; 4035411Swnj return; 4045411Swnj } 4055411Swnj if (nbio) 4065427Swnj pti->pt_flags |= PF_NBIO; 4075411Swnj else 4085427Swnj pti->pt_flags &= ~PF_NBIO; 4095411Swnj return; 4105411Swnj } 4115411Swnj if (cmd == TIOCSETP) 4125411Swnj while (getc(&tp->t_outq) >= 0); 4135411Swnj } 4144484Swnj if (ttioctl(tp, cmd, addr, dev) == 0) 4152281Stoy u.u_error = ENOTTY; 4166119Swnj { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && 4176119Swnj tp->t_un.t_chr.t_startc == ('q'&037)); 4186119Swnj if (pti->pt_flags & PF_NOSTOP) { 4196119Swnj if (stop) { 4206119Swnj pti->pt_send &= TIOCPKT_NOSTOP; 4216119Swnj pti->pt_send |= TIOCPKT_DOSTOP; 4226119Swnj pti->pt_flags &= ~PF_NOSTOP; 4236119Swnj ptcwakeup(tp); 4246119Swnj } 4256119Swnj } else { 4266119Swnj if (stop == 0) { 4276119Swnj pti->pt_send &= ~TIOCPKT_DOSTOP; 4286119Swnj pti->pt_send |= TIOCPKT_NOSTOP; 4296119Swnj pti->pt_flags |= PF_NOSTOP; 4306119Swnj ptcwakeup(tp); 4316119Swnj } 4326119Swnj } 4336119Swnj } 4342281Stoy } 4352313Stoy #endif 436