1*8155Sroot /* tty_pty.c 4.25 82/09/12 */ 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" 19*8155Sroot #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)]; 912281Stoy 925894Swnj again: 935894Swnj if (pti->pt_flags & PF_REMOTE) { 945894Swnj while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 955894Swnj if (u.u_signal[SIGTTIN] == SIG_IGN || 965894Swnj u.u_signal[SIGTTIN] == SIG_HOLD || 975894Swnj /* 985894Swnj (u.u_procp->p_flag&SDETACH) || 995894Swnj */ 1005894Swnj u.u_procp->p_flag&SVFORK) 1015894Swnj return; 1025894Swnj gsignal(u.u_procp->p_pgrp, SIGTTIN); 1035894Swnj sleep((caddr_t)&lbolt, TTIPRI); 1045408Swnj } 1055894Swnj if (tp->t_rawq.c_cc == 0) { 1065894Swnj if (tp->t_state & TS_NBIO) { 1075894Swnj u.u_error = EWOULDBLOCK; 1085894Swnj return; 1095894Swnj } 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) { 1157823Sroot u.u_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) 1215894Swnj return; 1225894Swnj } else 1235894Swnj if (tp->t_oproc) 1247823Sroot (*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 } 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)]; 1454484Swnj if (tp->t_oproc) 1467823Sroot (*linesw[tp->t_line].l_write)(tp, uio); 1472281Stoy } 1482281Stoy 1495408Swnj /* 1505408Swnj * Start output on pseudo-tty. 1515408Swnj * Wake up process selecting or sleeping for input from controlling tty. 1525408Swnj */ 1532281Stoy ptsstart(tp) 1544484Swnj struct tty *tp; 1554484Swnj { 1565574Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1574484Swnj 1585408Swnj if (tp->t_state & TS_TTSTOP) 1592281Stoy return; 1605574Swnj if (pti->pt_flags & PF_STOPPED) { 1615574Swnj pti->pt_flags &= ~PF_STOPPED; 1625574Swnj pti->pt_send = TIOCPKT_START; 1635574Swnj } 1645430Swnj ptcwakeup(tp); 1655430Swnj } 1665430Swnj 1675430Swnj ptcwakeup(tp) 1685430Swnj struct tty *tp; 1695430Swnj { 1705430Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 1715430Swnj 1725427Swnj if (pti->pt_selr) { 1735427Swnj selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 1745427Swnj pti->pt_selr = 0; 1755427Swnj pti->pt_flags &= ~PF_RCOLL; 1764484Swnj } 1772281Stoy wakeup((caddr_t)&tp->t_outq.c_cf); 1782281Stoy } 1792281Stoy 1802281Stoy /*ARGSUSED*/ 1812281Stoy ptcopen(dev, flag) 1824484Swnj dev_t dev; 1834484Swnj int flag; 1844484Swnj { 1852281Stoy register struct tty *tp; 1865427Swnj struct pt_ioctl *pti; 1872281Stoy 1884484Swnj if (minor(dev) >= NPTY) { 1892281Stoy u.u_error = ENXIO; 1902281Stoy return; 1912281Stoy } 1922281Stoy tp = &pt_tty[minor(dev)]; 1934484Swnj if (tp->t_oproc) { 1942281Stoy u.u_error = EIO; 1952281Stoy return; 1962281Stoy } 1974484Swnj tp->t_oproc = ptsstart; 1985408Swnj if (tp->t_state & TS_WOPEN) 1992281Stoy wakeup((caddr_t)&tp->t_rawq); 2005408Swnj tp->t_state |= TS_CARR_ON; 2015427Swnj pti = &pt_ioctl[minor(dev)]; 2025427Swnj pti->pt_flags = 0; 2035427Swnj pti->pt_send = 0; 2042281Stoy } 2052281Stoy 2062281Stoy ptcclose(dev) 2074484Swnj dev_t dev; 2084484Swnj { 2092281Stoy register struct tty *tp; 2102281Stoy 2112281Stoy tp = &pt_tty[minor(dev)]; 2125408Swnj if (tp->t_state & TS_ISOPEN) 2132281Stoy gsignal(tp->t_pgrp, SIGHUP); 2145408Swnj tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ 2154484Swnj flushtty(tp, FREAD|FWRITE); 2164484Swnj tp->t_oproc = 0; /* mark closed */ 2172281Stoy } 2182281Stoy 2197823Sroot ptcread(dev, uio) 2205427Swnj dev_t dev; 2217823Sroot struct uio *uio; 2224484Swnj { 2232281Stoy register struct tty *tp; 2245427Swnj struct pt_ioctl *pti; 2252281Stoy 2262281Stoy tp = &pt_tty[minor(dev)]; 2275408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2282281Stoy return; 2295427Swnj pti = &pt_ioctl[minor(dev)]; 2305427Swnj if (pti->pt_flags & PF_PKT) { 2315427Swnj if (pti->pt_send) { 2327823Sroot (void) ureadc(pti->pt_send, uio); 2335427Swnj pti->pt_send = 0; 2345427Swnj return; 2355427Swnj } 2367823Sroot (void) ureadc(0, uio); 2375427Swnj } 2385411Swnj while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { 2395427Swnj if (pti->pt_flags&PF_NBIO) { 2405411Swnj u.u_error = EWOULDBLOCK; 2415411Swnj return; 2425411Swnj } 2432281Stoy sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 2445411Swnj } 2457823Sroot while (tp->t_outq.c_cc && uio->uio_resid > 0) 2467823Sroot if (ureadc(getc(&tp->t_outq), uio) < 0) { 2477823Sroot u.u_error = EFAULT; 2487823Sroot break; 2497823Sroot } 2505408Swnj if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 2515408Swnj if (tp->t_state&TS_ASLEEP) { 2525408Swnj tp->t_state &= ~TS_ASLEEP; 2535408Swnj wakeup((caddr_t)&tp->t_outq); 2545408Swnj } 2555408Swnj if (tp->t_wsel) { 2565408Swnj selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 2575408Swnj tp->t_wsel = 0; 2585408Swnj tp->t_state &= ~TS_WCOLL; 2595408Swnj } 2602281Stoy } 2612281Stoy } 2622281Stoy 2635427Swnj ptsstop(tp, flush) 2645427Swnj register struct tty *tp; 2655427Swnj int flush; 2665427Swnj { 2675427Swnj struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 2685427Swnj 2695574Swnj /* note: FLUSHREAD and FLUSHWRITE already ok */ 2705574Swnj if (flush == 0) { 2715574Swnj flush = TIOCPKT_STOP; 2725574Swnj pti->pt_flags |= PF_STOPPED; 2735574Swnj } else { 2745574Swnj pti->pt_flags &= ~PF_STOPPED; 2755574Swnj } 2766119Swnj pti->pt_send |= flush; 2775430Swnj ptcwakeup(tp); 2785427Swnj } 2795427Swnj 2805408Swnj ptcselect(dev, rw) 2814484Swnj dev_t dev; 2825408Swnj int rw; 2834484Swnj { 2844484Swnj register struct tty *tp = &pt_tty[minor(dev)]; 2855894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 2864484Swnj struct proc *p; 2875430Swnj int s; 2884484Swnj 2895408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 2904484Swnj return (1); 2915430Swnj s = spl5(); 2925408Swnj switch (rw) { 2935408Swnj 2945408Swnj case FREAD: 2955430Swnj if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 2965430Swnj splx(s); 2975408Swnj return (1); 2985430Swnj } 2995427Swnj if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 3005427Swnj pti->pt_flags |= PF_RCOLL; 3015408Swnj else 3025427Swnj pti->pt_selr = u.u_procp; 3035430Swnj break; 3045408Swnj 3055408Swnj case FWRITE: 3065894Swnj if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { 3075430Swnj splx(s); 3085408Swnj return (1); 3095430Swnj } 3105427Swnj if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 3115427Swnj pti->pt_flags |= PF_WCOLL; 3125408Swnj else 3135427Swnj pti->pt_selw = u.u_procp; 3145430Swnj break; 3155408Swnj } 3165430Swnj splx(s); 3175430Swnj return (0); 3185396Sroot } 3194484Swnj 3207823Sroot ptcwrite(dev, uio) 3215408Swnj dev_t dev; 3227823Sroot struct uio *uio; 3234484Swnj { 3242281Stoy register struct tty *tp; 3252281Stoy register char *cp, *ce; 3262281Stoy register int cc; 3272281Stoy char locbuf[BUFSIZ]; 3285408Swnj int cnt = 0; 3295894Swnj struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 3302281Stoy 3312281Stoy tp = &pt_tty[minor(dev)]; 3325408Swnj if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) 3332281Stoy return; 3345894Swnj do { 3357823Sroot register struct iovec *iov; 3367823Sroot 3377823Sroot if (uio->uio_iovcnt == 0) 3387823Sroot break; 3397823Sroot iov = uio->uio_iov; 3407823Sroot if (iov->iov_len == 0) { 3417823Sroot uio->uio_iovcnt--; 3427823Sroot uio->uio_iov++; 3437823Sroot if (uio->uio_iovcnt < 0) 3447823Sroot panic("ptcwrite"); 3457823Sroot continue; 3467823Sroot } 3477823Sroot cc = MIN(iov->iov_len, BUFSIZ); 3482281Stoy cp = locbuf; 3497823Sroot u.u_error = uiomove(cp, cc, UIO_WRITE, uio); 3504484Swnj if (u.u_error) 3512281Stoy break; 3522281Stoy ce = cp + cc; 3535894Swnj again: 3545894Swnj if (pti->pt_flags & PF_REMOTE) { 3555894Swnj if (tp->t_rawq.c_cc) { 3565894Swnj if (pti->pt_flags & PF_NBIO) { 3577823Sroot iov->iov_base -= ce - cp; 3587823Sroot iov->iov_len += ce - cp; 3597823Sroot uio->uio_resid += ce - cp; 3607823Sroot uio->uio_offset -= ce - cp; 3615894Swnj u.u_error = EWOULDBLOCK; 3625894Swnj return; 3635894Swnj } 3645894Swnj sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3655894Swnj goto again; 3665894Swnj } 3676158Ssam (void) b_to_q(cp, cc, &tp->t_rawq); 3686158Ssam (void) putc(0, &tp->t_rawq); 3695894Swnj wakeup((caddr_t)&tp->t_rawq); 3705894Swnj return; 3715894Swnj } 3724484Swnj while (cp < ce) { 3734484Swnj while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { 3742281Stoy wakeup((caddr_t)&tp->t_rawq); 3755408Swnj if (tp->t_state & TS_NBIO) { 3767823Sroot iov->iov_base -= ce - cp; 3777823Sroot iov->iov_len += ce - cp; 3787823Sroot uio->uio_resid += ce - cp; 3797823Sroot uio->uio_offset -= ce - cp; 3805408Swnj if (cnt == 0) 3815408Swnj u.u_error = EWOULDBLOCK; 3825408Swnj return; 3835408Swnj } 3842281Stoy /* Better than just flushing it! */ 3852281Stoy /* Wait for something to be read */ 3862281Stoy sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 3875894Swnj goto again; 3882281Stoy } 3894141Secc (*linesw[tp->t_line].l_rint)(*cp++, tp); 3905408Swnj cnt++; 3912281Stoy } 3927823Sroot } while (uio->uio_resid); 3932281Stoy } 3942281Stoy 3952281Stoy /*ARGSUSED*/ 3967626Ssam ptyioctl(dev, cmd, data, flag) 3977626Ssam caddr_t data; 3984484Swnj dev_t dev; 3994484Swnj { 4006119Swnj register struct tty *tp = &pt_tty[minor(dev)]; 4016119Swnj register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 4022281Stoy 4034484Swnj /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 4047626Ssam if (cdevsw[major(dev)].d_open == ptcopen) 4057626Ssam switch (cmd) { 4067626Ssam 4077626Ssam case TIOCPKT: 4087626Ssam if (*(int *)data) 4095427Swnj pti->pt_flags |= PF_PKT; 4105427Swnj else 4115427Swnj pti->pt_flags &= ~PF_PKT; 4125427Swnj return; 4137626Ssam 4147626Ssam case TIOCREMOTE: 4157626Ssam if (*(int *)data) 4165894Swnj pti->pt_flags |= PF_REMOTE; 4175894Swnj else 4185894Swnj pti->pt_flags &= ~PF_REMOTE; 4195894Swnj flushtty(tp, FREAD|FWRITE); 4205894Swnj return; 4217626Ssam 4227626Ssam case FIONBIO: 4237626Ssam if (*(int *)data) 4245427Swnj pti->pt_flags |= PF_NBIO; 4255411Swnj else 4265427Swnj pti->pt_flags &= ~PF_NBIO; 4275411Swnj return; 4287626Ssam 4297626Ssam case TIOCSETP: 4307626Ssam while (getc(&tp->t_outq) >= 0) 4317626Ssam ; 4327626Ssam break; 4335411Swnj } 4347626Ssam if (ttioctl(tp, cmd, data, dev) == 0) 4352281Stoy u.u_error = ENOTTY; 4366119Swnj { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && 4376119Swnj tp->t_un.t_chr.t_startc == ('q'&037)); 4386119Swnj if (pti->pt_flags & PF_NOSTOP) { 4396119Swnj if (stop) { 4406119Swnj pti->pt_send &= TIOCPKT_NOSTOP; 4416119Swnj pti->pt_send |= TIOCPKT_DOSTOP; 4426119Swnj pti->pt_flags &= ~PF_NOSTOP; 4436119Swnj ptcwakeup(tp); 4446119Swnj } 4456119Swnj } else { 4466119Swnj if (stop == 0) { 4476119Swnj pti->pt_send &= ~TIOCPKT_DOSTOP; 4486119Swnj pti->pt_send |= TIOCPKT_NOSTOP; 4496119Swnj pti->pt_flags |= PF_NOSTOP; 4506119Swnj ptcwakeup(tp); 4516119Swnj } 4526119Swnj } 4536119Swnj } 4542281Stoy } 4552313Stoy #endif 456