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