1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)tty_pty.c 7.1 (Berkeley) 6/5/86 7: */ 8: 9: /* 10: * Pseudo-teletype Driver 11: * (Actually two drivers, requiring two entries in 'cdevsw') 12: */ 13: #include "pty.h" 14: 15: #if NPTY > 0 16: #include "param.h" 17: #include "systm.h" 18: #include "ioctl.h" 19: #include "tty.h" 20: #include "dir.h" 21: #include "user.h" 22: #include "conf.h" 23: #include "file.h" 24: #include "proc.h" 25: #include "uio.h" 26: #include "kernel.h" 27: 28: #if NPTY == 1 29: #undef NPTY 30: #define NPTY 32 /* crude XXX */ 31: #endif 32: 33: #define BUFSIZ 100 /* Chunk size iomoved to/from user */ 34: 35: /* 36: * pts == /dev/tty[pqrs]? 37: * ptc == /dev/pty[pqrs]? 38: */ 39: struct tty pt_tty[NPTY]; 40: struct pt_ioctl { 41: int pt_flags; 42: struct proc *pt_selr, *pt_selw; 43: u_char pt_send; 44: u_char pt_ucntl; 45: } pt_ioctl[NPTY]; 46: int npty = NPTY; /* for pstat -t */ 47: 48: #define PF_RCOLL 0x01 49: #define PF_WCOLL 0x02 50: #define PF_NBIO 0x04 51: #define PF_PKT 0x08 /* packet mode */ 52: #define PF_STOPPED 0x10 /* user told stopped */ 53: #define PF_REMOTE 0x20 /* remote and flow controlled input */ 54: #define PF_NOSTOP 0x40 55: #define PF_UCNTL 0x80 /* user control mode */ 56: 57: /*ARGSUSED*/ 58: ptsopen(dev, flag) 59: dev_t dev; 60: { 61: register struct tty *tp; 62: int error; 63: 64: #ifdef lint 65: npty = npty; 66: #endif 67: if (minor(dev) >= NPTY) 68: return (ENXIO); 69: tp = &pt_tty[minor(dev)]; 70: if ((tp->t_state & TS_ISOPEN) == 0) { 71: ttychars(tp); /* Set up default chars */ 72: tp->t_ispeed = tp->t_ospeed = EXTB; 73: tp->t_flags = 0; /* No features (nor raw mode) */ 74: } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 75: return (EBUSY); 76: if (tp->t_oproc) /* Ctrlr still around. */ 77: tp->t_state |= TS_CARR_ON; 78: while ((tp->t_state & TS_CARR_ON) == 0) { 79: tp->t_state |= TS_WOPEN; 80: sleep((caddr_t)&tp->t_rawq, TTIPRI); 81: } 82: error = (*linesw[tp->t_line].l_open)(dev, tp); 83: ptcwakeup(tp, FREAD|FWRITE); 84: return (error); 85: } 86: 87: ptsclose(dev) 88: dev_t dev; 89: { 90: register struct tty *tp; 91: 92: tp = &pt_tty[minor(dev)]; 93: (*linesw[tp->t_line].l_close)(tp); 94: ttyclose(tp); 95: ptcwakeup(tp, FREAD|FWRITE); 96: } 97: 98: ptsread(dev, uio) 99: dev_t dev; 100: struct uio *uio; 101: { 102: register struct tty *tp = &pt_tty[minor(dev)]; 103: register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 104: int error = 0; 105: 106: again: 107: if (pti->pt_flags & PF_REMOTE) { 108: while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { 109: if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 110: (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 111: u.u_procp->p_flag&SVFORK) 112: return (EIO); 113: gsignal(u.u_procp->p_pgrp, SIGTTIN); 114: sleep((caddr_t)&lbolt, TTIPRI); 115: } 116: if (tp->t_canq.c_cc == 0) { 117: if (tp->t_state & TS_NBIO) 118: return (EWOULDBLOCK); 119: sleep((caddr_t)&tp->t_canq, TTIPRI); 120: goto again; 121: } 122: while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) 123: if (ureadc(getc(&tp->t_canq), uio) < 0) { 124: error = EFAULT; 125: break; 126: } 127: if (tp->t_canq.c_cc == 1) 128: (void) getc(&tp->t_canq); 129: if (tp->t_canq.c_cc) 130: return (error); 131: } else 132: if (tp->t_oproc) 133: error = (*linesw[tp->t_line].l_read)(tp, uio); 134: ptcwakeup(tp, FWRITE); 135: return (error); 136: } 137: 138: /* 139: * Write to pseudo-tty. 140: * Wakeups of controlling tty will happen 141: * indirectly, when tty driver calls ptsstart. 142: */ 143: ptswrite(dev, uio) 144: dev_t dev; 145: struct uio *uio; 146: { 147: register struct tty *tp; 148: 149: tp = &pt_tty[minor(dev)]; 150: if (tp->t_oproc == 0) 151: return (EIO); 152: return ((*linesw[tp->t_line].l_write)(tp, uio)); 153: } 154: 155: /* 156: * Start output on pseudo-tty. 157: * Wake up process selecting or sleeping for input from controlling tty. 158: */ 159: ptsstart(tp) 160: struct tty *tp; 161: { 162: register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 163: 164: if (tp->t_state & TS_TTSTOP) 165: return; 166: if (pti->pt_flags & PF_STOPPED) { 167: pti->pt_flags &= ~PF_STOPPED; 168: pti->pt_send = TIOCPKT_START; 169: } 170: ptcwakeup(tp, FREAD); 171: } 172: 173: ptcwakeup(tp, flag) 174: struct tty *tp; 175: { 176: struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 177: 178: if (flag & FREAD) { 179: if (pti->pt_selr) { 180: selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 181: pti->pt_selr = 0; 182: pti->pt_flags &= ~PF_RCOLL; 183: } 184: wakeup((caddr_t)&tp->t_outq.c_cf); 185: } 186: if (flag & FWRITE) { 187: if (pti->pt_selw) { 188: selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 189: pti->pt_selw = 0; 190: pti->pt_flags &= ~PF_WCOLL; 191: } 192: wakeup((caddr_t)&tp->t_rawq.c_cf); 193: } 194: } 195: 196: /*ARGSUSED*/ 197: ptcopen(dev, flag) 198: dev_t dev; 199: int flag; 200: { 201: register struct tty *tp; 202: struct pt_ioctl *pti; 203: 204: if (minor(dev) >= NPTY) 205: return (ENXIO); 206: tp = &pt_tty[minor(dev)]; 207: if (tp->t_oproc) 208: return (EIO); 209: tp->t_oproc = ptsstart; 210: (void)(*linesw[tp->t_line].l_modem)(tp, 1); 211: tp->t_state |= TS_CARR_ON; 212: pti = &pt_ioctl[minor(dev)]; 213: pti->pt_flags = 0; 214: pti->pt_send = 0; 215: pti->pt_ucntl = 0; 216: return (0); 217: } 218: 219: ptcclose(dev) 220: dev_t dev; 221: { 222: register struct tty *tp; 223: 224: tp = &pt_tty[minor(dev)]; 225: (void)(*linesw[tp->t_line].l_modem)(tp, 0); 226: tp->t_oproc = 0; /* mark closed */ 227: } 228: 229: ptcread(dev, uio) 230: dev_t dev; 231: struct uio *uio; 232: { 233: register struct tty *tp = &pt_tty[minor(dev)]; 234: struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 235: char buf[BUFSIZ]; 236: int error = 0, cc; 237: 238: /* 239: * We want to block until the slave 240: * is open, and there's something to read; 241: * but if we lost the slave or we're NBIO, 242: * then return the appropriate error instead. 243: */ 244: for (;;) { 245: if (tp->t_state&TS_ISOPEN) { 246: if (pti->pt_flags&PF_PKT && pti->pt_send) { 247: error = ureadc((int)pti->pt_send, uio); 248: if (error) 249: return (error); 250: pti->pt_send = 0; 251: return (0); 252: } 253: if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 254: error = ureadc((int)pti->pt_ucntl, uio); 255: if (error) 256: return (error); 257: pti->pt_ucntl = 0; 258: return (0); 259: } 260: if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 261: break; 262: } 263: if ((tp->t_state&TS_CARR_ON) == 0) 264: return (EIO); 265: if (pti->pt_flags&PF_NBIO) 266: return (EWOULDBLOCK); 267: sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 268: } 269: if (pti->pt_flags & (PF_PKT|PF_UCNTL)) 270: error = ureadc(0, uio); 271: while (uio->uio_resid > 0 && error == 0) { 272: cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); 273: if (cc <= 0) 274: break; 275: error = uiomove(buf, cc, UIO_READ, uio); 276: } 277: if (tp->t_outq.c_cc <= TTLOWAT(tp)) { 278: if (tp->t_state&TS_ASLEEP) { 279: tp->t_state &= ~TS_ASLEEP; 280: wakeup((caddr_t)&tp->t_outq); 281: } 282: if (tp->t_wsel) { 283: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 284: tp->t_wsel = 0; 285: tp->t_state &= ~TS_WCOLL; 286: } 287: } 288: return (error); 289: } 290: 291: ptsstop(tp, flush) 292: register struct tty *tp; 293: int flush; 294: { 295: struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 296: int flag; 297: 298: /* note: FLUSHREAD and FLUSHWRITE already ok */ 299: if (flush == 0) { 300: flush = TIOCPKT_STOP; 301: pti->pt_flags |= PF_STOPPED; 302: } else 303: pti->pt_flags &= ~PF_STOPPED; 304: pti->pt_send |= flush; 305: /* change of perspective */ 306: flag = 0; 307: if (flush & FREAD) 308: flag |= FWRITE; 309: if (flush & FWRITE) 310: flag |= FREAD; 311: ptcwakeup(tp, flag); 312: } 313: 314: ptcselect(dev, rw) 315: dev_t dev; 316: int rw; 317: { 318: register struct tty *tp = &pt_tty[minor(dev)]; 319: struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 320: struct proc *p; 321: int s; 322: 323: if ((tp->t_state&TS_CARR_ON) == 0) 324: return (1); 325: switch (rw) { 326: 327: case FREAD: 328: /* 329: * Need to block timeouts (ttrstart). 330: */ 331: s = spltty(); 332: if ((tp->t_state&TS_ISOPEN) && 333: tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 334: splx(s); 335: return (1); 336: } 337: splx(s); 338: /* FALLTHROUGH */ 339: 340: case 0: /* exceptional */ 341: if ((tp->t_state&TS_ISOPEN) && 342: (pti->pt_flags&PF_PKT && pti->pt_send || 343: pti->pt_flags&PF_UCNTL && pti->pt_ucntl)) 344: return (1); 345: if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 346: pti->pt_flags |= PF_RCOLL; 347: else 348: pti->pt_selr = u.u_procp; 349: break; 350: 351: 352: case FWRITE: 353: if (tp->t_state&TS_ISOPEN) { 354: if (pti->pt_flags & PF_REMOTE) { 355: if (tp->t_canq.c_cc == 0) 356: return (1); 357: } else { 358: if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) 359: return (1); 360: if (tp->t_canq.c_cc == 0 && 361: (tp->t_flags & (RAW|CBREAK)) == 0) 362: return (1); 363: } 364: } 365: if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 366: pti->pt_flags |= PF_WCOLL; 367: else 368: pti->pt_selw = u.u_procp; 369: break; 370: 371: } 372: return (0); 373: } 374: 375: ptcwrite(dev, uio) 376: dev_t dev; 377: register struct uio *uio; 378: { 379: register struct tty *tp = &pt_tty[minor(dev)]; 380: register struct iovec *iov; 381: register char *cp; 382: register int cc = 0; 383: char locbuf[BUFSIZ]; 384: int cnt = 0; 385: struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 386: int error = 0; 387: 388: again: 389: if ((tp->t_state&TS_ISOPEN) == 0) 390: goto block; 391: if (pti->pt_flags & PF_REMOTE) { 392: if (tp->t_canq.c_cc) 393: goto block; 394: while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) { 395: iov = uio->uio_iov; 396: if (iov->iov_len == 0) { 397: uio->uio_iovcnt--; 398: uio->uio_iov++; 399: continue; 400: } 401: if (cc == 0) { 402: cc = MIN(iov->iov_len, BUFSIZ); 403: cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc); 404: cp = locbuf; 405: error = uiomove(cp, cc, UIO_WRITE, uio); 406: if (error) 407: return (error); 408: /* check again for safety */ 409: if ((tp->t_state&TS_ISOPEN) == 0) 410: return (EIO); 411: } 412: if (cc) 413: (void) b_to_q(cp, cc, &tp->t_canq); 414: cc = 0; 415: } 416: (void) putc(0, &tp->t_canq); 417: ttwakeup(tp); 418: wakeup((caddr_t)&tp->t_canq); 419: return (0); 420: } 421: while (uio->uio_iovcnt > 0) { 422: iov = uio->uio_iov; 423: if (cc == 0) { 424: if (iov->iov_len == 0) { 425: uio->uio_iovcnt--; 426: uio->uio_iov++; 427: continue; 428: } 429: cc = MIN(iov->iov_len, BUFSIZ); 430: cp = locbuf; 431: error = uiomove(cp, cc, UIO_WRITE, uio); 432: if (error) 433: return (error); 434: /* check again for safety */ 435: if ((tp->t_state&TS_ISOPEN) == 0) 436: return (EIO); 437: } 438: while (cc > 0) { 439: if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 440: (tp->t_canq.c_cc > 0 || 441: tp->t_flags & (RAW|CBREAK))) { 442: wakeup((caddr_t)&tp->t_rawq); 443: goto block; 444: } 445: (*linesw[tp->t_line].l_rint)(*cp++, tp); 446: cnt++; 447: cc--; 448: } 449: cc = 0; 450: } 451: return (0); 452: block: 453: /* 454: * Come here to wait for slave to open, for space 455: * in outq, or space in rawq. 456: */ 457: if ((tp->t_state&TS_CARR_ON) == 0) 458: return (EIO); 459: if (pti->pt_flags & PF_NBIO) { 460: iov->iov_base -= cc; 461: iov->iov_len += cc; 462: uio->uio_resid += cc; 463: uio->uio_offset -= cc; 464: if (cnt == 0) 465: return (EWOULDBLOCK); 466: return (0); 467: } 468: sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 469: goto again; 470: } 471: 472: /*ARGSUSED*/ 473: ptyioctl(dev, cmd, data, flag) 474: caddr_t data; 475: dev_t dev; 476: { 477: register struct tty *tp = &pt_tty[minor(dev)]; 478: register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 479: int stop, error; 480: extern ttyinput(); 481: 482: /* 483: * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 484: * ttywflush(tp) will hang if there are characters in the outq. 485: */ 486: if (cdevsw[major(dev)].d_open == ptcopen) 487: switch (cmd) { 488: 489: case TIOCPKT: 490: if (*(int *)data) { 491: if (pti->pt_flags & PF_UCNTL) 492: return (EINVAL); 493: pti->pt_flags |= PF_PKT; 494: } else 495: pti->pt_flags &= ~PF_PKT; 496: return (0); 497: 498: case TIOCUCNTL: 499: if (*(int *)data) { 500: if (pti->pt_flags & PF_PKT) 501: return (EINVAL); 502: pti->pt_flags |= PF_UCNTL; 503: } else 504: pti->pt_flags &= ~PF_UCNTL; 505: return (0); 506: 507: case TIOCREMOTE: 508: if (*(int *)data) 509: pti->pt_flags |= PF_REMOTE; 510: else 511: pti->pt_flags &= ~PF_REMOTE; 512: ttyflush(tp, FREAD|FWRITE); 513: return (0); 514: 515: case FIONBIO: 516: if (*(int *)data) 517: pti->pt_flags |= PF_NBIO; 518: else 519: pti->pt_flags &= ~PF_NBIO; 520: return (0); 521: 522: case TIOCSETP: 523: case TIOCSETN: 524: case TIOCSETD: 525: while (getc(&tp->t_outq) >= 0) 526: ; 527: break; 528: } 529: error = ttioctl(tp, cmd, data, flag); 530: /* 531: * Since we use the tty queues internally, 532: * pty's can't be switched to disciplines which overwrite 533: * the queues. We can't tell anything about the discipline 534: * from here... 535: */ 536: if (linesw[tp->t_line].l_rint != ttyinput) { 537: (*linesw[tp->t_line].l_close)(tp); 538: tp->t_line = 0; 539: (void)(*linesw[tp->t_line].l_open)(dev, tp); 540: error = ENOTTY; 541: } 542: if (error < 0) { 543: if (pti->pt_flags & PF_UCNTL && 544: (cmd & ~0xff) == UIOCCMD(0)) { 545: if (cmd & 0xff) { 546: pti->pt_ucntl = (u_char)cmd; 547: ptcwakeup(tp, FREAD); 548: } 549: return (0); 550: } 551: error = ENOTTY; 552: } 553: stop = (tp->t_flags & RAW) == 0 && 554: tp->t_stopc == CTRL(s) && tp->t_startc == CTRL(q); 555: if (pti->pt_flags & PF_NOSTOP) { 556: if (stop) { 557: pti->pt_send &= ~TIOCPKT_NOSTOP; 558: pti->pt_send |= TIOCPKT_DOSTOP; 559: pti->pt_flags &= ~PF_NOSTOP; 560: ptcwakeup(tp, FREAD); 561: } 562: } else { 563: if (!stop) { 564: pti->pt_send &= ~TIOCPKT_DOSTOP; 565: pti->pt_send |= TIOCPKT_NOSTOP; 566: pti->pt_flags |= PF_NOSTOP; 567: ptcwakeup(tp, FREAD); 568: } 569: } 570: return (error); 571: } 572: #endif