1*12642Ssam /* tty_pty.c 4.30 83/05/21 */ 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 */ 60*12642Ssam 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) { 945894Swnj if (u.u_signal[SIGTTIN] == SIG_IGN || 955894Swnj u.u_signal[SIGTTIN] == SIG_HOLD || 965894Swnj /* 975894Swnj (u.u_procp->p_flag&SDETACH) || 985894Swnj */ 995894Swnj u.u_procp->p_flag&SVFORK) 1008521Sroot return (EIO); 1015894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 1025894Swnj sleep((caddr_t)&lbolt, TTIPRI); 1035408Swnj } 1045894Swnj if (tp->t_rawq.c_cc == 0) { 1058521Sroot if (tp->t_state & TS_NBIO) 1068521Sroot return (EWOULDBLOCK); 1075894Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 1085894Swnj goto again; 1095894Swnj } 1107823Sroot while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0) 1117823Sroot if (ureadc(getc(&tp->t_rawq), uio) < 0) { 1128521Sroot error = EFAULT; 1137823Sroot break; 1147823Sroot } 1155894Swnj if (tp->t_rawq.c_cc == 1) 1165894Swnj (void) getc(&tp->t_rawq); 1175894Swnj if (tp->t_rawq.c_cc) 1188521Sroot return (error); 1195894Swnj } else 1205894Swnj if (tp->t_oproc) 1218521Sroot error = (*linesw[tp->t_line].l_read)(tp, uio); 1225894Swnj wakeup((caddr_t)&tp->t_rawq.c_cf); 1235894Swnj if (pti->pt_selw) { 1245894Swnj selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 1255894Swnj pti->pt_selw = 0; 1265894Swnj pti->pt_flags &= ~PF_WCOLL; 1272281Stoy } 1288521Sroot return (error); 1292281Stoy } 1302281Stoy 1315408Swnj /* 1325408Swnj * Write to pseudo-tty. 1335408Swnj * Wakeups of controlling tty will happen 1345408Swnj * indirectly, when tty driver calls ptsstart. 1355408Swnj */ 1367823Sroot ptswrite(dev, uio) 1375396Sroot dev_t dev; 1387823Sroot struct uio *uio; 1394484Swnj { 1402281Stoy register struct tty *tp; 1412281Stoy 1422281Stoy tp = &pt_tty[minor(dev)]; 1438521Sroot if (tp->t_oproc == 0) 1448521Sroot return (EIO); 1458521Sroot return ((*linesw[tp->t_line].l_write)(tp, uio)); 1462281Stoy } 1472281Stoy 1485408Swnj /* 1495408Swnj * Start output on pseudo-tty. 1505408Swnj * Wake up process selecting or sleeping for input from controlling tty. 1515408Swnj */ 1522281Stoy ptsstart(tp) 1534484Swnj struct tty *tp; 1544484Swnj { 1555574Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1564484Swnj 1575408Swnj if (tp->t_state & TS_TTSTOP) 1582281Stoy return; 1595574Swnj if (pti->pt_flags & PF_STOPPED) { 1605574Swnj pti->pt_flags &= ~PF_STOPPED; 1615574Swnj pti->pt_send = TIOCPKT_START; 1625574Swnj } 1635430Swnj ptcwakeup(tp); 1645430Swnj } 1655430Swnj 1665430Swnj ptcwakeup(tp) 1675430Swnj struct tty *tp; 1685430Swnj { 1695430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1705430Swnj 1715427Swnj if (pti->pt_selr) { 1725427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1735427Swnj pti->pt_selr = 0; 1745427Swnj pti->pt_flags &= ~PF_RCOLL; 1754484Swnj } 1762281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1772281Stoy } 1782281Stoy 1792281Stoy /*ARGSUSED*/ 1802281Stoy ptcopen(dev, flag) 1814484Swnj dev_t dev; 1824484Swnj int flag; 1834484Swnj { 1842281Stoy register struct tty *tp; 1855427Swnj struct pt_ioctl *pti; 1862281Stoy 1878563Sroot if (minor(dev) >= NPTY) 1888563Sroot return (ENXIO); 1892281Stoy tp = &pt_tty[minor(dev)]; 1908563Sroot if (tp->t_oproc) 1918563Sroot return (EIO); 1924484Swnj tp->t_oproc = ptsstart; 1935408Swnj if (tp->t_state & TS_WOPEN) 1942281Stoy wakeup((caddr_t)&tp->t_rawq); 1955408Swnj tp->t_state |= TS_CARR_ON; 1965427Swnj pti = &pt_ioctl[minor(dev)]; 1975427Swnj pti->pt_flags = 0; 1985427Swnj pti->pt_send = 0; 1998563Sroot return (0); 2002281Stoy } 2012281Stoy 2022281Stoy ptcclose(dev) 2034484Swnj dev_t dev; 2044484Swnj { 2052281Stoy register struct tty *tp; 2062281Stoy 2072281Stoy tp = &pt_tty[minor(dev)]; 2085408Swnj if (tp->t_state & TS_ISOPEN) 2092281Stoy gsignal(tp->t_pgrp, SIGHUP); 2105408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 2114484Swnj flushtty(tp, FREAD|FWRITE); 2124484Swnj tp->t_oproc = 0; /* mark closed */ 2132281Stoy } 2142281Stoy 2157823Sroot ptcread(dev, uio) 2165427Swnj dev_t dev; 2177823Sroot struct uio *uio; 2184484Swnj { 2198521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 2205427Swnj struct pt_ioctl *pti; 2218521Sroot int error = 0; 2222281Stoy 2235408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2248590Sroot return (EIO); 2255427Swnj pti = &pt_ioctl[minor(dev)]; 2265427Swnj if (pti->pt_flags & PF_PKT) { 2275427Swnj if (pti->pt_send) { 2288521Sroot error = ureadc(pti->pt_send, uio); 2298521Sroot if (error) 2308521Sroot return (error); 2315427Swnj pti->pt_send = 0; 2328521Sroot return (0); 2335427Swnj } 2348521Sroot error = ureadc(0, uio); 2355427Swnj } 2365411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 2378521Sroot if (pti->pt_flags&PF_NBIO) 2388521Sroot return (EWOULDBLOCK); 2392281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2405411Swnj } 2417823Sroot while (tp->t_outq.c_cc && uio->uio_resid > 0) 2427823Sroot if (ureadc(getc(&tp->t_outq), uio) < 0) { 2438521Sroot error = EFAULT; 2447823Sroot break; 2457823Sroot } 2465408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2475408Swnj if (tp->t_state&TS_ASLEEP) { 2485408Swnj tp->t_state &= ~TS_ASLEEP; 2495408Swnj wakeup((caddr_t)&tp->t_outq); 2505408Swnj } 2515408Swnj if (tp->t_wsel) { 2525408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2535408Swnj tp->t_wsel = 0; 2545408Swnj tp->t_state &= ~TS_WCOLL; 2555408Swnj } 2562281Stoy } 2578521Sroot return (error); 2582281Stoy } 2592281Stoy 2605427Swnj ptsstop(tp, flush) 2615427Swnj register struct tty *tp; 2625427Swnj int flush; 2635427Swnj { 2645427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2655427Swnj 2665574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 2675574Swnj if (flush == 0) { 2685574Swnj flush = TIOCPKT_STOP; 2695574Swnj pti->pt_flags |= PF_STOPPED; 2705574Swnj } else { 2715574Swnj pti->pt_flags &= ~PF_STOPPED; 2725574Swnj } 2736119Swnj pti->pt_send |= flush; 2745430Swnj ptcwakeup(tp); 2755427Swnj } 2765427Swnj 2775408Swnj ptcselect(dev, rw) 2784484Swnj dev_t dev; 2795408Swnj int rw; 2804484Swnj { 2814484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2825894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 2834484Swnj struct proc *p; 2845430Swnj int s; 2854484Swnj 2865408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2874484Swnj return (1); 2885430Swnj s = spl5(); 2895408Swnj switch (rw) { 2905408Swnj 2915408Swnj case FREAD: 2925430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 2935430Swnj splx(s); 2945408Swnj return (1); 2955430Swnj } 2965427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 2975427Swnj pti->pt_flags |= PF_RCOLL; 2985408Swnj else 2995427Swnj pti->pt_selr = u.u_procp; 3005430Swnj break; 3015408Swnj 3025408Swnj case FWRITE: 3035894Swnj if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 3045430Swnj splx(s); 3055408Swnj return (1); 3065430Swnj } 3075427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 3085427Swnj pti->pt_flags |= PF_WCOLL; 3095408Swnj else 3105427Swnj pti->pt_selw = u.u_procp; 3115430Swnj break; 3125408Swnj } 3135430Swnj splx(s); 3145430Swnj return (0); 3155396Sroot } 3164484Swnj 3177823Sroot ptcwrite(dev, uio) 3185408Swnj dev_t dev; 3197823Sroot struct uio *uio; 3204484Swnj { 3218521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 3222281Stoy register char *cp, *ce; 3232281Stoy register int cc; 3242281Stoy char locbuf[BUFSIZ]; 3255408Swnj int cnt = 0; 3265894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3278521Sroot int error = 0; 3282281Stoy 3295408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 3308521Sroot return (EIO); 3315894Swnj do { 3327823Sroot register struct iovec *iov; 3337823Sroot 3347823Sroot if (uio->uio_iovcnt == 0) 3357823Sroot break; 3367823Sroot iov = uio->uio_iov; 3377823Sroot if (iov->iov_len == 0) { 3387823Sroot uio->uio_iovcnt--; 3397823Sroot uio->uio_iov++; 3407823Sroot if (uio->uio_iovcnt < 0) 3417823Sroot panic("ptcwrite"); 3427823Sroot continue; 3437823Sroot } 3447823Sroot cc = MIN(iov->iov_len, BUFSIZ); 3452281Stoy cp = locbuf; 3468521Sroot error = uiomove(cp, cc, UIO_WRITE, uio); 3478521Sroot if (error) 3482281Stoy break; 3492281Stoy ce = cp + cc; 3505894Swnj again: 3515894Swnj if (pti->pt_flags & PF_REMOTE) { 3525894Swnj if (tp->t_rawq.c_cc) { 3535894Swnj if (pti->pt_flags & PF_NBIO) { 3547823Sroot iov->iov_base -= ce - cp; 3557823Sroot iov->iov_len += ce - cp; 3567823Sroot uio->uio_resid += ce - cp; 3577823Sroot uio->uio_offset -= ce - cp; 3588521Sroot return (EWOULDBLOCK); 3595894Swnj } 3605894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3615894Swnj goto again; 3625894Swnj } 3636158Ssam (void) b_to_q(cp, cc, &tp->t_rawq); 3646158Ssam (void) putc(0, &tp->t_rawq); 3655894Swnj wakeup((caddr_t)&tp->t_rawq); 3668521Sroot return (0); 3675894Swnj } 3684484Swnj while (cp < ce) { 3694484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 3702281Stoy wakeup((caddr_t)&tp->t_rawq); 3715408Swnj if (tp->t_state & TS_NBIO) { 3727823Sroot iov->iov_base -= ce - cp; 3737823Sroot iov->iov_len += ce - cp; 3747823Sroot uio->uio_resid += ce - cp; 3757823Sroot uio->uio_offset -= ce - cp; 3765408Swnj if (cnt == 0) 3778521Sroot return (EWOULDBLOCK); 3788521Sroot return (0); 3795408Swnj } 3802281Stoy /* Better than just flushing it! */ 3812281Stoy /* Wait for something to be read */ 3822281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3835894Swnj goto again; 3842281Stoy } 3854141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3865408Swnj cnt++; 3872281Stoy } 3887823Sroot } while (uio->uio_resid); 3898521Sroot return (error); 3902281Stoy } 3912281Stoy 3922281Stoy /*ARGSUSED*/ 3937626Ssam ptyioctl(dev, cmd, data, flag) 3947626Ssam caddr_t data; 3954484Swnj dev_t dev; 3964484Swnj { 3976119Swnj register struct tty *tp = &pt_tty[minor(dev)]; 3986119Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3998563Sroot int error; 4002281Stoy 4014484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 4027626Ssam if (cdevsw[major(dev)].d_open == ptcopen) 4037626Ssam switch (cmd) { 4047626Ssam 4057626Ssam case TIOCPKT: 4067626Ssam if (*(int *)data) 4075427Swnj pti->pt_flags |= PF_PKT; 4085427Swnj else 4095427Swnj pti->pt_flags &= ~PF_PKT; 4108563Sroot return (0); 4117626Ssam 4127626Ssam case TIOCREMOTE: 4137626Ssam if (*(int *)data) 4145894Swnj pti->pt_flags |= PF_REMOTE; 4155894Swnj else 4165894Swnj pti->pt_flags &= ~PF_REMOTE; 4175894Swnj flushtty(tp, FREAD|FWRITE); 4188563Sroot return (0); 4197626Ssam 4207626Ssam case FIONBIO: 4217626Ssam if (*(int *)data) 4225427Swnj pti->pt_flags |= PF_NBIO; 4235411Swnj else 4245427Swnj pti->pt_flags &= ~PF_NBIO; 4258563Sroot return (0); 4267626Ssam 4277626Ssam case TIOCSETP: 4287626Ssam while (getc(&tp->t_outq) >= 0) 4297626Ssam ; 4307626Ssam break; 4315411Swnj } 4328563Sroot error = ttioctl(tp, cmd, data, dev); 4338563Sroot if (error < 0) 4348563Sroot error = ENOTTY; 4359561Ssam { int stop = (tp->t_stopc == ('s'&037) && 4369561Ssam tp->t_startc == ('q'&037)); 4376119Swnj if (pti->pt_flags & PF_NOSTOP) { 4386119Swnj if (stop) { 4396119Swnj pti->pt_send &= TIOCPKT_NOSTOP; 4406119Swnj pti->pt_send |= TIOCPKT_DOSTOP; 4416119Swnj pti->pt_flags &= ~PF_NOSTOP; 4426119Swnj ptcwakeup(tp); 4436119Swnj } 4446119Swnj } else { 4456119Swnj if (stop == 0) { 4466119Swnj pti->pt_send &= ~TIOCPKT_DOSTOP; 4476119Swnj pti->pt_send |= TIOCPKT_NOSTOP; 4486119Swnj pti->pt_flags |= PF_NOSTOP; 4496119Swnj ptcwakeup(tp); 4506119Swnj } 4516119Swnj } 4526119Swnj } 4538563Sroot return (error); 4542281Stoy } 4552313Stoy #endif 456