1 /* tty_pty.c 6.11 85/06/07 */ 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) == 0 || tp->t_canq.c_cc == 0)) { 347 splx(s); 348 return (1); 349 } 350 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 351 pti->pt_flags |= PF_WCOLL; 352 else 353 pti->pt_selw = u.u_procp; 354 break; 355 } 356 splx(s); 357 return (0); 358 } 359 360 ptcwrite(dev, uio) 361 dev_t dev; 362 register struct uio *uio; 363 { 364 register struct tty *tp = &pt_tty[minor(dev)]; 365 register struct iovec *iov; 366 register char *cp; 367 register int cc = 0; 368 char locbuf[BUFSIZ]; 369 int cnt = 0; 370 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 371 int error = 0; 372 373 again: 374 if ((tp->t_state&TS_ISOPEN) == 0) 375 goto block; 376 if (cnt == 0 && pti->pt_flags & PF_REMOTE) { 377 if (uio->uio_iovcnt <= 0) 378 return (0); 379 if (tp->t_canq.c_cc) 380 goto block; 381 iov = uio->uio_iov; 382 if (cc == 0 && iov->iov_len) { 383 cc = MIN(iov->iov_len, BUFSIZ); 384 cp = locbuf; 385 error = uiomove(cp, cc, UIO_WRITE, uio); 386 if (error) 387 return (error); 388 /* check again for safety */ 389 if ((tp->t_state&TS_ISOPEN) == 0) 390 return (EIO); 391 if (tp->t_canq.c_cc) 392 goto block; 393 } 394 if (cc) 395 (void) b_to_q(cp, cc, &tp->t_canq); 396 (void) putc(0, &tp->t_canq); 397 ttwakeup(tp); 398 wakeup((caddr_t)&tp->t_canq); 399 return (0); 400 } 401 while (uio->uio_iovcnt > 0) { 402 iov = uio->uio_iov; 403 if (cc == 0) { 404 if (iov->iov_len == 0) { 405 uio->uio_iovcnt--; 406 uio->uio_iov++; 407 continue; 408 } 409 cc = MIN(iov->iov_len, BUFSIZ); 410 cp = locbuf; 411 error = uiomove(cp, cc, UIO_WRITE, uio); 412 if (error) 413 return (error); 414 /* check again for safety */ 415 if ((tp->t_state&TS_ISOPEN) == 0) 416 return (EIO); 417 } 418 while (--cc >= 0) { 419 (*linesw[tp->t_line].l_rint)(*cp++, tp); 420 cnt++; 421 } 422 cc = 0; 423 } 424 return (0); 425 block: 426 /* 427 * Come here to wait for slave to open or for space 428 * in outq. 429 */ 430 if ((tp->t_state&TS_CARR_ON) == 0) 431 return (EIO); 432 if (pti->pt_flags & PF_NBIO) { 433 if (cnt == 0) 434 return (EWOULDBLOCK); 435 iov->iov_base -= cc; 436 iov->iov_len += cc; 437 uio->uio_resid += cc; 438 uio->uio_offset -= cc; 439 return (0); 440 } 441 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 442 goto again; 443 } 444 445 /*ARGSUSED*/ 446 ptyioctl(dev, cmd, data, flag) 447 caddr_t data; 448 dev_t dev; 449 { 450 register struct tty *tp = &pt_tty[minor(dev)]; 451 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 452 int stop, error; 453 454 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ 455 if (cdevsw[major(dev)].d_open == ptcopen) 456 switch (cmd) { 457 458 case TIOCPKT: 459 if (*(int *)data) { 460 if (pti->pt_flags & PF_UCNTL) 461 return (EINVAL); 462 pti->pt_flags |= PF_PKT; 463 } else 464 pti->pt_flags &= ~PF_PKT; 465 return (0); 466 467 case TIOCUCNTL: 468 if (*(int *)data) { 469 if (pti->pt_flags & PF_PKT) 470 return (EINVAL); 471 pti->pt_flags |= PF_UCNTL; 472 } else 473 pti->pt_flags &= ~PF_UCNTL; 474 return (0); 475 476 case TIOCREMOTE: 477 if (*(int *)data) 478 pti->pt_flags |= PF_REMOTE; 479 else 480 pti->pt_flags &= ~PF_REMOTE; 481 ttyflush(tp, FREAD|FWRITE); 482 return (0); 483 484 case FIONBIO: 485 if (*(int *)data) 486 pti->pt_flags |= PF_NBIO; 487 else 488 pti->pt_flags &= ~PF_NBIO; 489 return (0); 490 491 case TIOCSETP: 492 while (getc(&tp->t_outq) >= 0) 493 ; 494 break; 495 } 496 error = ttioctl(tp, cmd, data, flag); 497 if (error < 0) { 498 if (pti->pt_flags & PF_UCNTL && 499 (cmd & ~0xff) == _IO(u,0)) { 500 if (cmd & 0xff) { 501 pti->pt_ucntl = (u_char)cmd; 502 ptcwakeup(tp, FREAD); 503 } 504 return (0); 505 } 506 error = ENOTTY; 507 } 508 stop = (tp->t_flags & RAW) == 0 && 509 tp->t_stopc == CTRL(s) && tp->t_startc == CTRL(q); 510 if (pti->pt_flags & PF_NOSTOP) { 511 if (stop) { 512 pti->pt_send &= TIOCPKT_NOSTOP; 513 pti->pt_send |= TIOCPKT_DOSTOP; 514 pti->pt_flags &= ~PF_NOSTOP; 515 ptcwakeup(tp, FREAD); 516 } 517 } else { 518 if (!stop) { 519 pti->pt_send &= ~TIOCPKT_DOSTOP; 520 pti->pt_send |= TIOCPKT_NOSTOP; 521 pti->pt_flags |= PF_NOSTOP; 522 ptcwakeup(tp, FREAD); 523 } 524 } 525 return (error); 526 } 527 #endif 528