1*7823Sroot /* tty_pty.c 4.24 82/08/22 */ 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" 18*7823Sroot #include "../h/uio.h" 196239Sroot 207475Ssam #if NPTY == 1 215408Swnj #undef NPTY 226239Sroot #define NPTY 32 /* crude XXX */ 237475Ssam #endif 242281Stoy 252427Swnj #define BUFSIZ 100 /* Chunk size iomoved from user */ 264484Swnj 272281Stoy /* 284484Swnj * pts == /dev/tty[pP]? 294484Swnj * ptc == /dev/ptp[pP]? 302281Stoy */ 314484Swnj struct tty pt_tty[NPTY]; 324484Swnj struct pt_ioctl { 335427Swnj int pt_flags; 345427Swnj int pt_gensym; 355427Swnj struct proc *pt_selr, *pt_selw; 365427Swnj int pt_send; 374484Swnj } pt_ioctl[NPTY]; 382281Stoy 395427Swnj #define PF_RCOLL 0x01 405427Swnj #define PF_WCOLL 0x02 415427Swnj #define PF_NBIO 0x04 425427Swnj #define PF_PKT 0x08 /* packet mode */ 435574Swnj #define PF_STOPPED 0x10 /* user told stopped */ 445894Swnj #define PF_REMOTE 0x20 /* remote and flow controlled input */ 456119Swnj #define PF_NOSTOP 0x40 462281Stoy 472281Stoy /*ARGSUSED*/ 482281Stoy ptsopen(dev, flag) 495396Sroot dev_t dev; 504484Swnj { 512281Stoy register struct tty *tp; 522281Stoy 534484Swnj if (minor(dev) >= NPTY) { 542281Stoy u.u_error = ENXIO; 552281Stoy return; 562281Stoy } 572281Stoy tp = &pt_tty[minor(dev)]; 585408Swnj if ((tp->t_state & TS_ISOPEN) == 0) { 592427Swnj ttychars(tp); /* Set up default chars */ 602427Swnj tp->t_flags = 0; /* No features (nor raw mode) */ 615408Swnj } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) { 622281Stoy u.u_error = EBUSY; 632281Stoy return; 642281Stoy } 654484Swnj if (tp->t_oproc) /* Ctrlr still around. */ 665408Swnj tp->t_state |= TS_CARR_ON; 675408Swnj while ((tp->t_state & TS_CARR_ON) == 0) { 685408Swnj tp->t_state |= TS_WOPEN; 692281Stoy sleep((caddr_t)&tp->t_rawq, TTIPRI); 702281Stoy } 712281Stoy (*linesw[tp->t_line].l_open)(dev, tp); 722281Stoy } 732281Stoy 742281Stoy ptsclose(dev) 755396Sroot dev_t dev; 765408Swnj { 772281Stoy register struct tty *tp; 782281Stoy 792281Stoy tp = &pt_tty[minor(dev)]; 802281Stoy (*linesw[tp->t_line].l_close)(tp); 816299Swnj ttyclose(tp); 822281Stoy } 832281Stoy 84*7823Sroot ptsread(dev, uio) 855396Sroot dev_t dev; 86*7823Sroot struct uio *uio; 874484Swnj { 885894Swnj register struct tty *tp = &pt_tty[minor(dev)]; 895894Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 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) 1005894Swnj return; 1015894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 1025894Swnj sleep((caddr_t)&lbolt, TTIPRI); 1035408Swnj } 1045894Swnj if (tp->t_rawq.c_cc == 0) { 1055894Swnj if (tp->t_state & TS_NBIO) { 1065894Swnj u.u_error = EWOULDBLOCK; 1075894Swnj return; 1085894Swnj } 1095894Swnj sleep((caddr_t)&tp->t_rawq, TTIPRI); 1105894Swnj goto again; 1115894Swnj } 112*7823Sroot while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0) 113*7823Sroot if (ureadc(getc(&tp->t_rawq), uio) < 0) { 114*7823Sroot u.u_error = EFAULT; 115*7823Sroot break; 116*7823Sroot } 1175894Swnj if (tp->t_rawq.c_cc == 1) 1185894Swnj (void) getc(&tp->t_rawq); 1195894Swnj if (tp->t_rawq.c_cc) 1205894Swnj return; 1215894Swnj } else 1225894Swnj if (tp->t_oproc) 123*7823Sroot (*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 } 1302281Stoy } 1312281Stoy 1325408Swnj /* 1335408Swnj * Write to pseudo-tty. 1345408Swnj * Wakeups of controlling tty will happen 1355408Swnj * indirectly, when tty driver calls ptsstart. 1365408Swnj */ 137*7823Sroot ptswrite(dev, uio) 1385396Sroot dev_t dev; 139*7823Sroot struct uio *uio; 1404484Swnj { 1412281Stoy register struct tty *tp; 1422281Stoy 1432281Stoy tp = &pt_tty[minor(dev)]; 1444484Swnj if (tp->t_oproc) 145*7823Sroot (*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 1874484Swnj if (minor(dev) >= NPTY) { 1882281Stoy u.u_error = ENXIO; 1892281Stoy return; 1902281Stoy } 1912281Stoy tp = &pt_tty[minor(dev)]; 1924484Swnj if (tp->t_oproc) { 1932281Stoy u.u_error = EIO; 1942281Stoy return; 1952281Stoy } 1964484Swnj tp->t_oproc = ptsstart; 1975408Swnj if (tp->t_state & TS_WOPEN) 1982281Stoy wakeup((caddr_t)&tp->t_rawq); 1995408Swnj tp->t_state |= TS_CARR_ON; 2005427Swnj pti = &pt_ioctl[minor(dev)]; 2015427Swnj pti->pt_flags = 0; 2025427Swnj pti->pt_send = 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 */ 2144484Swnj flushtty(tp, FREAD|FWRITE); 2154484Swnj tp->t_oproc = 0; /* mark closed */ 2162281Stoy } 2172281Stoy 218*7823Sroot ptcread(dev, uio) 2195427Swnj dev_t dev; 220*7823Sroot struct uio *uio; 2214484Swnj { 2222281Stoy register struct tty *tp; 2235427Swnj struct pt_ioctl *pti; 2242281Stoy 2252281Stoy tp = &pt_tty[minor(dev)]; 2265408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2272281Stoy return; 2285427Swnj pti = &pt_ioctl[minor(dev)]; 2295427Swnj if (pti->pt_flags & PF_PKT) { 2305427Swnj if (pti->pt_send) { 231*7823Sroot (void) ureadc(pti->pt_send, uio); 2325427Swnj pti->pt_send = 0; 2335427Swnj return; 2345427Swnj } 235*7823Sroot (void) ureadc(0, uio); 2365427Swnj } 2375411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 2385427Swnj if (pti->pt_flags&PF_NBIO) { 2395411Swnj u.u_error = EWOULDBLOCK; 2405411Swnj return; 2415411Swnj } 2422281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2435411Swnj } 244*7823Sroot while (tp->t_outq.c_cc && uio->uio_resid > 0) 245*7823Sroot if (ureadc(getc(&tp->t_outq), uio) < 0) { 246*7823Sroot u.u_error = EFAULT; 247*7823Sroot break; 248*7823Sroot } 2495408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2505408Swnj if (tp->t_state&TS_ASLEEP) { 2515408Swnj tp->t_state &= ~TS_ASLEEP; 2525408Swnj wakeup((caddr_t)&tp->t_outq); 2535408Swnj } 2545408Swnj if (tp->t_wsel) { 2555408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2565408Swnj tp->t_wsel = 0; 2575408Swnj tp->t_state &= ~TS_WCOLL; 2585408Swnj } 2592281Stoy } 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 319*7823Sroot ptcwrite(dev, uio) 3205408Swnj dev_t dev; 321*7823Sroot struct uio *uio; 3224484Swnj { 3232281Stoy register struct tty *tp; 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)]; 3292281Stoy 3302281Stoy tp = &pt_tty[minor(dev)]; 3315408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 3322281Stoy return; 3335894Swnj do { 334*7823Sroot register struct iovec *iov; 335*7823Sroot 336*7823Sroot if (uio->uio_iovcnt == 0) 337*7823Sroot break; 338*7823Sroot iov = uio->uio_iov; 339*7823Sroot if (iov->iov_len == 0) { 340*7823Sroot uio->uio_iovcnt--; 341*7823Sroot uio->uio_iov++; 342*7823Sroot if (uio->uio_iovcnt < 0) 343*7823Sroot panic("ptcwrite"); 344*7823Sroot continue; 345*7823Sroot } 346*7823Sroot cc = MIN(iov->iov_len, BUFSIZ); 3472281Stoy cp = locbuf; 348*7823Sroot u.u_error = uiomove(cp, cc, UIO_WRITE, uio); 3494484Swnj if (u.u_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) { 356*7823Sroot iov->iov_base -= ce - cp; 357*7823Sroot iov->iov_len += ce - cp; 358*7823Sroot uio->uio_resid += ce - cp; 359*7823Sroot uio->uio_offset -= ce - cp; 3605894Swnj u.u_error = EWOULDBLOCK; 3615894Swnj return; 3625894Swnj } 3635894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3645894Swnj goto again; 3655894Swnj } 3666158Ssam (void) b_to_q(cp, cc, &tp->t_rawq); 3676158Ssam (void) putc(0, &tp->t_rawq); 3685894Swnj wakeup((caddr_t)&tp->t_rawq); 3695894Swnj return; 3705894Swnj } 3714484Swnj while (cp < ce) { 3724484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 3732281Stoy wakeup((caddr_t)&tp->t_rawq); 3745408Swnj if (tp->t_state & TS_NBIO) { 375*7823Sroot iov->iov_base -= ce - cp; 376*7823Sroot iov->iov_len += ce - cp; 377*7823Sroot uio->uio_resid += ce - cp; 378*7823Sroot uio->uio_offset -= ce - cp; 3795408Swnj if (cnt == 0) 3805408Swnj u.u_error = EWOULDBLOCK; 3815408Swnj return; 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 } 391*7823Sroot } while (uio->uio_resid); 3922281Stoy } 3932281Stoy 3942281Stoy /*ARGSUSED*/ 3957626Ssam ptyioctl(dev, cmd, data, flag) 3967626Ssam caddr_t data; 3974484Swnj dev_t dev; 3984484Swnj { 3996119Swnj register struct tty *tp = &pt_tty[minor(dev)]; 4006119Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 4012281Stoy 4024484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 4037626Ssam if (cdevsw[major(dev)].d_open == ptcopen) 4047626Ssam switch (cmd) { 4057626Ssam 4067626Ssam case TIOCPKT: 4077626Ssam if (*(int *)data) 4085427Swnj pti->pt_flags |= PF_PKT; 4095427Swnj else 4105427Swnj pti->pt_flags &= ~PF_PKT; 4115427Swnj return; 4127626Ssam 4137626Ssam case TIOCREMOTE: 4147626Ssam if (*(int *)data) 4155894Swnj pti->pt_flags |= PF_REMOTE; 4165894Swnj else 4175894Swnj pti->pt_flags &= ~PF_REMOTE; 4185894Swnj flushtty(tp, FREAD|FWRITE); 4195894Swnj return; 4207626Ssam 4217626Ssam case FIONBIO: 4227626Ssam if (*(int *)data) 4235427Swnj pti->pt_flags |= PF_NBIO; 4245411Swnj else 4255427Swnj pti->pt_flags &= ~PF_NBIO; 4265411Swnj return; 4277626Ssam 4287626Ssam case TIOCSETP: 4297626Ssam while (getc(&tp->t_outq) >= 0) 4307626Ssam ; 4317626Ssam break; 4325411Swnj } 4337626Ssam if (ttioctl(tp, cmd, data, dev) == 0) 4342281Stoy u.u_error = ENOTTY; 4356119Swnj { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && 4366119Swnj tp->t_un.t_chr.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 } 4532281Stoy } 4542313Stoy #endif 455