1*8521Sroot /* tty_pty.c 4.26 82/10/13 */ 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" 187823Sroot #include "../h/uio.h" 198155Sroot #include "../h/kernel.h" 206239Sroot 217475Ssam #if NPTY == 1 225408Swnj #undef NPTY 236239Sroot #define NPTY 32 /* crude XXX */ 247475Ssam #endif 252281Stoy 262427Swnj #define BUFSIZ 100 /* Chunk size iomoved from user */ 274484Swnj 282281Stoy /* 294484Swnj * pts == /dev/tty[pP]? 304484Swnj * ptc == /dev/ptp[pP]? 312281Stoy */ 324484Swnj struct tty pt_tty[NPTY]; 334484Swnj struct pt_ioctl { 345427Swnj int pt_flags; 355427Swnj int pt_gensym; 365427Swnj struct proc *pt_selr, *pt_selw; 375427Swnj int pt_send; 384484Swnj } pt_ioctl[NPTY]; 392281Stoy 405427Swnj #define PF_RCOLL 0x01 415427Swnj #define PF_WCOLL 0x02 425427Swnj #define PF_NBIO 0x04 435427Swnj #define PF_PKT 0x08 /* packet mode */ 445574Swnj #define PF_STOPPED 0x10 /* user told stopped */ 455894Swnj #define PF_REMOTE 0x20 /* remote and flow controlled input */ 466119Swnj #define PF_NOSTOP 0x40 472281Stoy 482281Stoy /*ARGSUSED*/ 492281Stoy ptsopen(dev, flag) 505396Sroot dev_t dev; 514484Swnj { 522281Stoy register struct tty *tp; 532281Stoy 544484Swnj if (minor(dev) >= NPTY) { 552281Stoy u.u_error = ENXIO; 562281Stoy return; 572281Stoy } 582281Stoy tp = &pt_tty[minor(dev)]; 595408Swnj if ((tp->t_state & TS_ISOPEN) == 0) { 602427Swnj ttychars(tp); /* Set up default chars */ 612427Swnj tp->t_flags = 0; /* No features (nor raw mode) */ 625408Swnj } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) { 632281Stoy u.u_error = EBUSY; 642281Stoy return; 652281Stoy } 664484Swnj if (tp->t_oproc) /* Ctrlr still around. */ 675408Swnj tp->t_state |= TS_CARR_ON; 685408Swnj while ((tp->t_state & TS_CARR_ON) == 0) { 695408Swnj tp->t_state |= TS_WOPEN; 702281Stoy sleep((caddr_t)&tp->t_rawq, TTIPRI); 712281Stoy } 722281Stoy (*linesw[tp->t_line].l_open)(dev, tp); 732281Stoy } 742281Stoy 752281Stoy ptsclose(dev) 765396Sroot dev_t dev; 775408Swnj { 782281Stoy register struct tty *tp; 792281Stoy 802281Stoy tp = &pt_tty[minor(dev)]; 812281Stoy (*linesw[tp->t_line].l_close)(tp); 826299Swnj ttyclose(tp); 832281Stoy } 842281Stoy 857823Sroot ptsread(dev, uio) 865396Sroot dev_t dev; 877823Sroot struct uio *uio; 884484Swnj { 895894Swnj register struct tty *tp = &pt_tty[minor(dev)]; 905894Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 91*8521Sroot int error = 0; 922281Stoy 935894Swnj again: 945894Swnj if (pti->pt_flags & PF_REMOTE) { 955894Swnj while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 965894Swnj if (u.u_signal[SIGTTIN] == SIG_IGN || 975894Swnj u.u_signal[SIGTTIN] == SIG_HOLD || 985894Swnj /* 995894Swnj (u.u_procp->p_flag&SDETACH) || 1005894Swnj */ 1015894Swnj u.u_procp->p_flag&SVFORK) 102*8521Sroot return (EIO); 1035894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 1045894Swnj sleep((caddr_t)&lbolt, TTIPRI); 1055408Swnj } 1065894Swnj if (tp->t_rawq.c_cc == 0) { 107*8521Sroot if (tp->t_state & TS_NBIO) 108*8521Sroot 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) { 114*8521Sroot 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) 120*8521Sroot return (error); 1215894Swnj } else 1225894Swnj if (tp->t_oproc) 123*8521Sroot 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 } 130*8521Sroot 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)]; 145*8521Sroot if (tp->t_oproc == 0) 146*8521Sroot return (EIO); 147*8521Sroot 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 1894484Swnj if (minor(dev) >= NPTY) { 1902281Stoy u.u_error = ENXIO; 1912281Stoy return; 1922281Stoy } 1932281Stoy tp = &pt_tty[minor(dev)]; 1944484Swnj if (tp->t_oproc) { 1952281Stoy u.u_error = EIO; 1962281Stoy return; 1972281Stoy } 1984484Swnj tp->t_oproc = ptsstart; 1995408Swnj if (tp->t_state & TS_WOPEN) 2002281Stoy wakeup((caddr_t)&tp->t_rawq); 2015408Swnj tp->t_state |= TS_CARR_ON; 2025427Swnj pti = &pt_ioctl[minor(dev)]; 2035427Swnj pti->pt_flags = 0; 2045427Swnj pti->pt_send = 0; 2052281Stoy } 2062281Stoy 2072281Stoy ptcclose(dev) 2084484Swnj dev_t dev; 2094484Swnj { 2102281Stoy register struct tty *tp; 2112281Stoy 2122281Stoy tp = &pt_tty[minor(dev)]; 2135408Swnj if (tp->t_state & TS_ISOPEN) 2142281Stoy gsignal(tp->t_pgrp, SIGHUP); 2155408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 2164484Swnj flushtty(tp, FREAD|FWRITE); 2174484Swnj tp->t_oproc = 0; /* mark closed */ 2182281Stoy } 2192281Stoy 2207823Sroot ptcread(dev, uio) 2215427Swnj dev_t dev; 2227823Sroot struct uio *uio; 2234484Swnj { 224*8521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 2255427Swnj struct pt_ioctl *pti; 226*8521Sroot int error = 0; 2272281Stoy 2285408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2292281Stoy return; 2305427Swnj pti = &pt_ioctl[minor(dev)]; 2315427Swnj if (pti->pt_flags & PF_PKT) { 2325427Swnj if (pti->pt_send) { 233*8521Sroot error = ureadc(pti->pt_send, uio); 234*8521Sroot if (error) 235*8521Sroot return (error); 2365427Swnj pti->pt_send = 0; 237*8521Sroot return (0); 2385427Swnj } 239*8521Sroot error = ureadc(0, uio); 2405427Swnj } 2415411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 242*8521Sroot if (pti->pt_flags&PF_NBIO) 243*8521Sroot return (EWOULDBLOCK); 2442281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2455411Swnj } 2467823Sroot while (tp->t_outq.c_cc && uio->uio_resid > 0) 2477823Sroot if (ureadc(getc(&tp->t_outq), uio) < 0) { 248*8521Sroot error = EFAULT; 2497823Sroot break; 2507823Sroot } 2515408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2525408Swnj if (tp->t_state&TS_ASLEEP) { 2535408Swnj tp->t_state &= ~TS_ASLEEP; 2545408Swnj wakeup((caddr_t)&tp->t_outq); 2555408Swnj } 2565408Swnj if (tp->t_wsel) { 2575408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2585408Swnj tp->t_wsel = 0; 2595408Swnj tp->t_state &= ~TS_WCOLL; 2605408Swnj } 2612281Stoy } 262*8521Sroot return (error); 2632281Stoy } 2642281Stoy 2655427Swnj ptsstop(tp, flush) 2665427Swnj register struct tty *tp; 2675427Swnj int flush; 2685427Swnj { 2695427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2705427Swnj 2715574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 2725574Swnj if (flush == 0) { 2735574Swnj flush = TIOCPKT_STOP; 2745574Swnj pti->pt_flags |= PF_STOPPED; 2755574Swnj } else { 2765574Swnj pti->pt_flags &= ~PF_STOPPED; 2775574Swnj } 2786119Swnj pti->pt_send |= flush; 2795430Swnj ptcwakeup(tp); 2805427Swnj } 2815427Swnj 2825408Swnj ptcselect(dev, rw) 2834484Swnj dev_t dev; 2845408Swnj int rw; 2854484Swnj { 2864484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2875894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 2884484Swnj struct proc *p; 2895430Swnj int s; 2904484Swnj 2915408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2924484Swnj return (1); 2935430Swnj s = spl5(); 2945408Swnj switch (rw) { 2955408Swnj 2965408Swnj case FREAD: 2975430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 2985430Swnj splx(s); 2995408Swnj return (1); 3005430Swnj } 3015427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 3025427Swnj pti->pt_flags |= PF_RCOLL; 3035408Swnj else 3045427Swnj pti->pt_selr = u.u_procp; 3055430Swnj break; 3065408Swnj 3075408Swnj case FWRITE: 3085894Swnj if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 3095430Swnj splx(s); 3105408Swnj return (1); 3115430Swnj } 3125427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 3135427Swnj pti->pt_flags |= PF_WCOLL; 3145408Swnj else 3155427Swnj pti->pt_selw = u.u_procp; 3165430Swnj break; 3175408Swnj } 3185430Swnj splx(s); 3195430Swnj return (0); 3205396Sroot } 3214484Swnj 3227823Sroot ptcwrite(dev, uio) 3235408Swnj dev_t dev; 3247823Sroot struct uio *uio; 3254484Swnj { 326*8521Sroot register struct tty *tp = &pt_tty[minor(dev)]; 3272281Stoy register char *cp, *ce; 3282281Stoy register int cc; 3292281Stoy char locbuf[BUFSIZ]; 3305408Swnj int cnt = 0; 3315894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 332*8521Sroot int error = 0; 3332281Stoy 3345408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 335*8521Sroot return (EIO); 3365894Swnj do { 3377823Sroot register struct iovec *iov; 3387823Sroot 3397823Sroot if (uio->uio_iovcnt == 0) 3407823Sroot break; 3417823Sroot iov = uio->uio_iov; 3427823Sroot if (iov->iov_len == 0) { 3437823Sroot uio->uio_iovcnt--; 3447823Sroot uio->uio_iov++; 3457823Sroot if (uio->uio_iovcnt < 0) 3467823Sroot panic("ptcwrite"); 3477823Sroot continue; 3487823Sroot } 3497823Sroot cc = MIN(iov->iov_len, BUFSIZ); 3502281Stoy cp = locbuf; 351*8521Sroot error = uiomove(cp, cc, UIO_WRITE, uio); 352*8521Sroot if (error) 3532281Stoy break; 3542281Stoy ce = cp + cc; 3555894Swnj again: 3565894Swnj if (pti->pt_flags & PF_REMOTE) { 3575894Swnj if (tp->t_rawq.c_cc) { 3585894Swnj if (pti->pt_flags & PF_NBIO) { 3597823Sroot iov->iov_base -= ce - cp; 3607823Sroot iov->iov_len += ce - cp; 3617823Sroot uio->uio_resid += ce - cp; 3627823Sroot uio->uio_offset -= ce - cp; 363*8521Sroot return (EWOULDBLOCK); 3645894Swnj } 3655894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3665894Swnj goto again; 3675894Swnj } 3686158Ssam (void) b_to_q(cp, cc, &tp->t_rawq); 3696158Ssam (void) putc(0, &tp->t_rawq); 3705894Swnj wakeup((caddr_t)&tp->t_rawq); 371*8521Sroot return (0); 3725894Swnj } 3734484Swnj while (cp < ce) { 3744484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 3752281Stoy wakeup((caddr_t)&tp->t_rawq); 3765408Swnj if (tp->t_state & TS_NBIO) { 3777823Sroot iov->iov_base -= ce - cp; 3787823Sroot iov->iov_len += ce - cp; 3797823Sroot uio->uio_resid += ce - cp; 3807823Sroot uio->uio_offset -= ce - cp; 3815408Swnj if (cnt == 0) 382*8521Sroot return (EWOULDBLOCK); 383*8521Sroot return (0); 3845408Swnj } 3852281Stoy /* Better than just flushing it! */ 3862281Stoy /* Wait for something to be read */ 3872281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3885894Swnj goto again; 3892281Stoy } 3904141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3915408Swnj cnt++; 3922281Stoy } 3937823Sroot } while (uio->uio_resid); 394*8521Sroot return (error); 3952281Stoy } 3962281Stoy 3972281Stoy /*ARGSUSED*/ 3987626Ssam ptyioctl(dev, cmd, data, flag) 3997626Ssam caddr_t data; 4004484Swnj dev_t dev; 4014484Swnj { 4026119Swnj register struct tty *tp = &pt_tty[minor(dev)]; 4036119Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 4042281Stoy 4054484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 4067626Ssam if (cdevsw[major(dev)].d_open == ptcopen) 4077626Ssam switch (cmd) { 4087626Ssam 4097626Ssam case TIOCPKT: 4107626Ssam if (*(int *)data) 4115427Swnj pti->pt_flags |= PF_PKT; 4125427Swnj else 4135427Swnj pti->pt_flags &= ~PF_PKT; 4145427Swnj return; 4157626Ssam 4167626Ssam case TIOCREMOTE: 4177626Ssam if (*(int *)data) 4185894Swnj pti->pt_flags |= PF_REMOTE; 4195894Swnj else 4205894Swnj pti->pt_flags &= ~PF_REMOTE; 4215894Swnj flushtty(tp, FREAD|FWRITE); 4225894Swnj return; 4237626Ssam 4247626Ssam case FIONBIO: 4257626Ssam if (*(int *)data) 4265427Swnj pti->pt_flags |= PF_NBIO; 4275411Swnj else 4285427Swnj pti->pt_flags &= ~PF_NBIO; 4295411Swnj return; 4307626Ssam 4317626Ssam case TIOCSETP: 4327626Ssam while (getc(&tp->t_outq) >= 0) 4337626Ssam ; 4347626Ssam break; 4355411Swnj } 4367626Ssam if (ttioctl(tp, cmd, data, dev) == 0) 4372281Stoy u.u_error = ENOTTY; 4386119Swnj { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && 4396119Swnj tp->t_un.t_chr.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 } 4562281Stoy } 4572313Stoy #endif 458