1*17096Sbloom /* tty_pty.c 6.6 84/08/29 */ 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 10*17096Sbloom #include "param.h" 11*17096Sbloom #include "systm.h" 12*17096Sbloom #include "ioctl.h" 13*17096Sbloom #include "tty.h" 14*17096Sbloom #include "dir.h" 15*17096Sbloom #include "user.h" 16*17096Sbloom #include "conf.h" 17*17096Sbloom #include "file.h" 18*17096Sbloom #include "proc.h" 19*17096Sbloom #include "uio.h" 20*17096Sbloom #include "kernel.h" 216239Sroot 227475Ssam #if NPTY == 1 235408Swnj #undef NPTY 246239Sroot #define NPTY 32 /* crude XXX */ 257475Ssam #endif 262281Stoy 2716788Ssam #define BUFSIZ 100 /* Chunk size iomoved to/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); 8116788Ssam ptcwakeup(tp); 822281Stoy } 832281Stoy 847823Sroot ptsread(dev, uio) 855396Sroot dev_t dev; 867823Sroot struct uio *uio; 874484Swnj { 885894Swnj register struct tty *tp = &pt_tty[minor(dev)]; 895894Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 908521Sroot int error = 0; 912281Stoy 925894Swnj again: 935894Swnj if (pti->pt_flags & PF_REMOTE) { 945894Swnj while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 9515144Skarels #define bit(a) (1<<(a-1)) 9615144Skarels if ((u.u_procp->p_sigignore & bit(SIGTTIN)) || 9715144Skarels (u.u_procp->p_sigmask & bit(SIGTTIN)) || 985894Swnj /* 995894Swnj (u.u_procp->p_flag&SDETACH) || 1005894Swnj */ 1015894Swnj u.u_procp->p_flag&SVFORK) 1028521Sroot return (EIO); 1035894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 1045894Swnj sleep((caddr_t)&lbolt, TTIPRI); 1055408Swnj } 10615144Skarels #undef bit 1075894Swnj if (tp->t_rawq.c_cc == 0) { 1088521Sroot if (tp->t_state & TS_NBIO) 1098521Sroot return (EWOULDBLOCK); 1105894Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 1115894Swnj goto again; 1125894Swnj } 1137823Sroot while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0) 1147823Sroot if (ureadc(getc(&tp->t_rawq), uio) < 0) { 1158521Sroot error = EFAULT; 1167823Sroot break; 1177823Sroot } 1185894Swnj if (tp->t_rawq.c_cc == 1) 1195894Swnj (void) getc(&tp->t_rawq); 1205894Swnj if (tp->t_rawq.c_cc) 1218521Sroot return (error); 1225894Swnj } else 1235894Swnj if (tp->t_oproc) 1248521Sroot error = (*linesw[tp->t_line].l_read)(tp, uio); 1255894Swnj wakeup((caddr_t)&tp->t_rawq.c_cf); 1265894Swnj if (pti->pt_selw) { 1275894Swnj selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 1285894Swnj pti->pt_selw = 0; 1295894Swnj pti->pt_flags &= ~PF_WCOLL; 1302281Stoy } 1318521Sroot return (error); 1322281Stoy } 1332281Stoy 1345408Swnj /* 1355408Swnj * Write to pseudo-tty. 1365408Swnj * Wakeups of controlling tty will happen 1375408Swnj * indirectly, when tty driver calls ptsstart. 1385408Swnj */ 1397823Sroot ptswrite(dev, uio) 1405396Sroot dev_t dev; 1417823Sroot struct uio *uio; 1424484Swnj { 1432281Stoy register struct tty *tp; 1442281Stoy 1452281Stoy tp = &pt_tty[minor(dev)]; 1468521Sroot if (tp->t_oproc == 0) 1478521Sroot return (EIO); 1488521Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 1492281Stoy } 1502281Stoy 1515408Swnj /* 1525408Swnj * Start output on pseudo-tty. 1535408Swnj * Wake up process selecting or sleeping for input from controlling tty. 1545408Swnj */ 1552281Stoy ptsstart(tp) 1564484Swnj struct tty *tp; 1574484Swnj { 1585574Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1594484Swnj 1605408Swnj if (tp->t_state & TS_TTSTOP) 1612281Stoy return; 1625574Swnj if (pti->pt_flags & PF_STOPPED) { 1635574Swnj pti->pt_flags &= ~PF_STOPPED; 1645574Swnj pti->pt_send = TIOCPKT_START; 1655574Swnj } 1665430Swnj ptcwakeup(tp); 1675430Swnj } 1685430Swnj 1695430Swnj ptcwakeup(tp) 1705430Swnj struct tty *tp; 1715430Swnj { 1725430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1735430Swnj 1745427Swnj if (pti->pt_selr) { 1755427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1765427Swnj pti->pt_selr = 0; 1775427Swnj pti->pt_flags &= ~PF_RCOLL; 1784484Swnj } 1792281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1802281Stoy } 1812281Stoy 1822281Stoy /*ARGSUSED*/ 1832281Stoy ptcopen(dev, flag) 1844484Swnj dev_t dev; 1854484Swnj int flag; 1864484Swnj { 1872281Stoy register struct tty *tp; 1885427Swnj struct pt_ioctl *pti; 1892281Stoy 1908563Sroot if (minor(dev) >= NPTY) 1918563Sroot return (ENXIO); 1922281Stoy tp = &pt_tty[minor(dev)]; 1938563Sroot if (tp->t_oproc) 1948563Sroot return (EIO); 1954484Swnj tp->t_oproc = ptsstart; 1965408Swnj if (tp->t_state & TS_WOPEN) 1972281Stoy wakeup((caddr_t)&tp->t_rawq); 1985408Swnj tp->t_state |= TS_CARR_ON; 1995427Swnj pti = &pt_ioctl[minor(dev)]; 2005427Swnj pti->pt_flags = 0; 2015427Swnj pti->pt_send = 0; 2028563Sroot return (0); 2032281Stoy } 2042281Stoy 2052281Stoy ptcclose(dev) 2064484Swnj dev_t dev; 2074484Swnj { 2082281Stoy register struct tty *tp; 2092281Stoy 2102281Stoy tp = &pt_tty[minor(dev)]; 2115408Swnj if (tp->t_state & TS_ISOPEN) 2122281Stoy gsignal(tp->t_pgrp, SIGHUP); 2135408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 21412753Ssam ttyflush(tp, FREAD|FWRITE); 2154484Swnj tp->t_oproc = 0; /* mark closed */ 2162281Stoy } 2172281Stoy 2187823Sroot ptcread(dev, uio) 2195427Swnj dev_t dev; 2207823Sroot struct uio *uio; 2214484Swnj { 2228521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 2235427Swnj struct pt_ioctl *pti; 22416788Ssam char buf[BUFSIZ]; 22516788Ssam int error = 0, cc; 2262281Stoy 2275408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2288590Sroot return (EIO); 2295427Swnj pti = &pt_ioctl[minor(dev)]; 2305427Swnj if (pti->pt_flags & PF_PKT) { 2315427Swnj if (pti->pt_send) { 2328521Sroot error = ureadc(pti->pt_send, uio); 2338521Sroot if (error) 2348521Sroot return (error); 2355427Swnj pti->pt_send = 0; 2368521Sroot return (0); 2375427Swnj } 2388521Sroot error = ureadc(0, uio); 2395427Swnj } 2405411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 24116788Ssam if ((tp->t_state&TS_CARR_ON) == 0) 24216788Ssam return (EIO); 2438521Sroot if (pti->pt_flags&PF_NBIO) 2448521Sroot return (EWOULDBLOCK); 2452281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2465411Swnj } 24716788Ssam while (uio->uio_resid > 0 && error == 0) { 24816788Ssam cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); 24916788Ssam if (cc <= 0) 2507823Sroot break; 25116788Ssam error = uiomove(buf, cc, UIO_READ, uio); 25216788Ssam } 2535408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2545408Swnj if (tp->t_state&TS_ASLEEP) { 2555408Swnj tp->t_state &= ~TS_ASLEEP; 2565408Swnj wakeup((caddr_t)&tp->t_outq); 2575408Swnj } 2585408Swnj if (tp->t_wsel) { 2595408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2605408Swnj tp->t_wsel = 0; 2615408Swnj tp->t_state &= ~TS_WCOLL; 2625408Swnj } 2632281Stoy } 2648521Sroot return (error); 2652281Stoy } 2662281Stoy 2675427Swnj ptsstop(tp, flush) 2685427Swnj register struct tty *tp; 2695427Swnj int flush; 2705427Swnj { 2715427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2725427Swnj 2735574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 2745574Swnj if (flush == 0) { 2755574Swnj flush = TIOCPKT_STOP; 2765574Swnj pti->pt_flags |= PF_STOPPED; 2775574Swnj } else { 2785574Swnj pti->pt_flags &= ~PF_STOPPED; 2795574Swnj } 2806119Swnj pti->pt_send |= flush; 2815430Swnj ptcwakeup(tp); 2825427Swnj } 2835427Swnj 2845408Swnj ptcselect(dev, rw) 2854484Swnj dev_t dev; 2865408Swnj int rw; 2874484Swnj { 2884484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2895894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 2904484Swnj struct proc *p; 2915430Swnj int s; 2924484Swnj 2935408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2944484Swnj return (1); 2955430Swnj s = spl5(); 2965408Swnj switch (rw) { 2975408Swnj 2985408Swnj case FREAD: 2995430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 3005430Swnj splx(s); 3015408Swnj return (1); 3025430Swnj } 3035427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 3045427Swnj pti->pt_flags |= PF_RCOLL; 3055408Swnj else 3065427Swnj pti->pt_selr = u.u_procp; 3075430Swnj break; 3085408Swnj 3095408Swnj case FWRITE: 3105894Swnj if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 3115430Swnj splx(s); 3125408Swnj return (1); 3135430Swnj } 3145427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 3155427Swnj pti->pt_flags |= PF_WCOLL; 3165408Swnj else 3175427Swnj pti->pt_selw = u.u_procp; 3185430Swnj break; 3195408Swnj } 3205430Swnj splx(s); 3215430Swnj return (0); 3225396Sroot } 3234484Swnj 3247823Sroot ptcwrite(dev, uio) 3255408Swnj dev_t dev; 3267823Sroot struct uio *uio; 3274484Swnj { 3288521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 3292281Stoy register char *cp, *ce; 3302281Stoy register int cc; 3312281Stoy char locbuf[BUFSIZ]; 3325408Swnj int cnt = 0; 3335894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3348521Sroot int error = 0; 3352281Stoy 3365408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 3378521Sroot return (EIO); 3385894Swnj do { 3397823Sroot register struct iovec *iov; 3407823Sroot 3417823Sroot if (uio->uio_iovcnt == 0) 3427823Sroot break; 3437823Sroot iov = uio->uio_iov; 3447823Sroot if (iov->iov_len == 0) { 34516788Ssam while (pti->pt_flags&PF_REMOTE && tp->t_rawq.c_cc != 0) 34616788Ssam sleep((caddr_t)&tp->t_rawq.c_cf, TTIPRI); 34716788Ssam if (pti->pt_flags&PF_REMOTE) { 34816788Ssam (void) putc(0, &tp->t_rawq); 34916788Ssam wakeup((caddr_t)&tp->t_rawq); 35016788Ssam } 3517823Sroot uio->uio_iovcnt--; 3527823Sroot uio->uio_iov++; 3537823Sroot if (uio->uio_iovcnt < 0) 3547823Sroot panic("ptcwrite"); 3557823Sroot continue; 3567823Sroot } 3577823Sroot cc = MIN(iov->iov_len, BUFSIZ); 3582281Stoy cp = locbuf; 3598521Sroot error = uiomove(cp, cc, UIO_WRITE, uio); 3608521Sroot if (error) 3612281Stoy break; 3622281Stoy ce = cp + cc; 3635894Swnj again: 3645894Swnj if (pti->pt_flags & PF_REMOTE) { 3655894Swnj if (tp->t_rawq.c_cc) { 3665894Swnj if (pti->pt_flags & PF_NBIO) { 3677823Sroot iov->iov_base -= ce - cp; 3687823Sroot iov->iov_len += ce - cp; 3697823Sroot uio->uio_resid += ce - cp; 3707823Sroot uio->uio_offset -= ce - cp; 3718521Sroot return (EWOULDBLOCK); 3725894Swnj } 3735894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3745894Swnj goto again; 3755894Swnj } 3766158Ssam (void) b_to_q(cp, cc, &tp->t_rawq); 3776158Ssam (void) putc(0, &tp->t_rawq); 3785894Swnj wakeup((caddr_t)&tp->t_rawq); 3798521Sroot return (0); 3805894Swnj } 3814484Swnj while (cp < ce) { 38216056Skarels if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 38316056Skarels (tp->t_canq.c_cc > 0)) { 3842281Stoy wakeup((caddr_t)&tp->t_rawq); 3855408Swnj if (tp->t_state & TS_NBIO) { 3867823Sroot iov->iov_base -= ce - cp; 3877823Sroot iov->iov_len += ce - cp; 3887823Sroot uio->uio_resid += ce - cp; 3897823Sroot uio->uio_offset -= ce - cp; 3905408Swnj if (cnt == 0) 3918521Sroot return (EWOULDBLOCK); 3928521Sroot return (0); 3935408Swnj } 3942281Stoy /* Better than just flushing it! */ 3952281Stoy /* Wait for something to be read */ 3962281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3975894Swnj goto again; 3982281Stoy } 3994141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 4005408Swnj cnt++; 4012281Stoy } 4027823Sroot } while (uio->uio_resid); 4038521Sroot return (error); 4042281Stoy } 4052281Stoy 4062281Stoy /*ARGSUSED*/ 4077626Ssam ptyioctl(dev, cmd, data, flag) 4087626Ssam caddr_t data; 4094484Swnj dev_t dev; 4104484Swnj { 4116119Swnj register struct tty *tp = &pt_tty[minor(dev)]; 4126119Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 4138563Sroot int error; 4142281Stoy 4154484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 4167626Ssam if (cdevsw[major(dev)].d_open == ptcopen) 4177626Ssam switch (cmd) { 4187626Ssam 4197626Ssam case TIOCPKT: 4207626Ssam if (*(int *)data) 4215427Swnj pti->pt_flags |= PF_PKT; 4225427Swnj else 4235427Swnj pti->pt_flags &= ~PF_PKT; 4248563Sroot return (0); 4257626Ssam 4267626Ssam case TIOCREMOTE: 4277626Ssam if (*(int *)data) 4285894Swnj pti->pt_flags |= PF_REMOTE; 4295894Swnj else 4305894Swnj pti->pt_flags &= ~PF_REMOTE; 43112753Ssam ttyflush(tp, FREAD|FWRITE); 4328563Sroot return (0); 4337626Ssam 4347626Ssam case FIONBIO: 4357626Ssam if (*(int *)data) 4365427Swnj pti->pt_flags |= PF_NBIO; 4375411Swnj else 4385427Swnj pti->pt_flags &= ~PF_NBIO; 4398563Sroot return (0); 4407626Ssam 4417626Ssam case TIOCSETP: 4427626Ssam while (getc(&tp->t_outq) >= 0) 4437626Ssam ; 4447626Ssam break; 4455411Swnj } 4468563Sroot error = ttioctl(tp, cmd, data, dev); 4478563Sroot if (error < 0) 4488563Sroot error = ENOTTY; 4499561Ssam { int stop = (tp->t_stopc == ('s'&037) && 4509561Ssam tp->t_startc == ('q'&037)); 4516119Swnj if (pti->pt_flags & PF_NOSTOP) { 4526119Swnj if (stop) { 4536119Swnj pti->pt_send &= TIOCPKT_NOSTOP; 4546119Swnj pti->pt_send |= TIOCPKT_DOSTOP; 4556119Swnj pti->pt_flags &= ~PF_NOSTOP; 4566119Swnj ptcwakeup(tp); 4576119Swnj } 4586119Swnj } else { 4596119Swnj if (stop == 0) { 4606119Swnj pti->pt_send &= ~TIOCPKT_DOSTOP; 4616119Swnj pti->pt_send |= TIOCPKT_NOSTOP; 4626119Swnj pti->pt_flags |= PF_NOSTOP; 4636119Swnj ptcwakeup(tp); 4646119Swnj } 4656119Swnj } 4666119Swnj } 4678563Sroot return (error); 4682281Stoy } 4692313Stoy #endif 470