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.4 (Berkeley) 10/18/88 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_iflag = TTYDEF_IFLAG; 73 tp->t_oflag = TTYDEF_OFLAG; 74 tp->t_lflag = TTYDEF_LFLAG; 75 tp->t_cflag = TTYDEF_CFLAG; 76 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 77 ttsetwater(tp); /* would be done in xxparam() */ 78 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 79 return (EBUSY); 80 if (tp->t_oproc) /* Ctrlr still around. */ 81 tp->t_state |= TS_CARR_ON; 82 while ((tp->t_state & TS_CARR_ON) == 0) { 83 tp->t_state |= TS_WOPEN; 84 sleep((caddr_t)&tp->t_rawq, TTIPRI); 85 } 86 error = (*linesw[tp->t_line].l_open)(dev, tp); 87 ptcwakeup(tp, FREAD|FWRITE); 88 return (error); 89 } 90 91 ptsclose(dev) 92 dev_t dev; 93 { 94 register struct tty *tp; 95 96 tp = &pt_tty[minor(dev)]; 97 (*linesw[tp->t_line].l_close)(tp); 98 ttyclose(tp); 99 ptcwakeup(tp, FREAD|FWRITE); 100 } 101 102 ptsread(dev, uio) 103 dev_t dev; 104 struct uio *uio; 105 { 106 register struct tty *tp = &pt_tty[minor(dev)]; 107 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 108 int error = 0; 109 110 again: 111 if (pti->pt_flags & PF_REMOTE) { 112 while (tp == u.u_ttyp && 113 u.u_procp->p_pgrp->pg_id != tp->t_pgid){ 114 if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 115 (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 116 !u.u_procp->p_pgrp->pg_jobc || 117 u.u_procp->p_flag&SVFORK) 118 return (EIO); 119 pgsignal(u.u_procp->p_pgrp, SIGTTIN); 120 sleep((caddr_t)&lbolt, TTIPRI); 121 } 122 if (tp->t_canq.c_cc == 0) { 123 if (tp->t_state & TS_NBIO) 124 return (EWOULDBLOCK); 125 sleep((caddr_t)&tp->t_canq, TTIPRI); 126 goto again; 127 } 128 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) 129 if (ureadc(getc(&tp->t_canq), uio) < 0) { 130 error = EFAULT; 131 break; 132 } 133 if (tp->t_canq.c_cc == 1) 134 (void) getc(&tp->t_canq); 135 if (tp->t_canq.c_cc) 136 return (error); 137 } else 138 if (tp->t_oproc) 139 error = (*linesw[tp->t_line].l_read)(tp, uio); 140 ptcwakeup(tp, FWRITE); 141 return (error); 142 } 143 144 /* 145 * Write to pseudo-tty. 146 * Wakeups of controlling tty will happen 147 * indirectly, when tty driver calls ptsstart. 148 */ 149 ptswrite(dev, uio) 150 dev_t dev; 151 struct uio *uio; 152 { 153 register struct tty *tp; 154 155 tp = &pt_tty[minor(dev)]; 156 if (tp->t_oproc == 0) 157 return (EIO); 158 return ((*linesw[tp->t_line].l_write)(tp, uio)); 159 } 160 161 /* 162 * Start output on pseudo-tty. 163 * Wake up process selecting or sleeping for input from controlling tty. 164 */ 165 ptsstart(tp) 166 struct tty *tp; 167 { 168 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 169 170 if (tp->t_state & TS_TTSTOP) 171 return; 172 if (pti->pt_flags & PF_STOPPED) { 173 pti->pt_flags &= ~PF_STOPPED; 174 pti->pt_send = TIOCPKT_START; 175 } 176 ptcwakeup(tp, FREAD); 177 } 178 179 ptcwakeup(tp, flag) 180 struct tty *tp; 181 { 182 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 183 184 if (flag & FREAD) { 185 if (pti->pt_selr) { 186 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 187 pti->pt_selr = 0; 188 pti->pt_flags &= ~PF_RCOLL; 189 } 190 wakeup((caddr_t)&tp->t_outq.c_cf); 191 } 192 if (flag & FWRITE) { 193 if (pti->pt_selw) { 194 selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 195 pti->pt_selw = 0; 196 pti->pt_flags &= ~PF_WCOLL; 197 } 198 wakeup((caddr_t)&tp->t_rawq.c_cf); 199 } 200 } 201 202 /*ARGSUSED*/ 203 ptcopen(dev, flag) 204 dev_t dev; 205 int flag; 206 { 207 register struct tty *tp; 208 struct pt_ioctl *pti; 209 210 if (minor(dev) >= NPTY) 211 return (ENXIO); 212 tp = &pt_tty[minor(dev)]; 213 if (tp->t_oproc) 214 return (EIO); 215 tp->t_oproc = ptsstart; 216 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 217 pti = &pt_ioctl[minor(dev)]; 218 pti->pt_flags = 0; 219 pti->pt_send = 0; 220 pti->pt_ucntl = 0; 221 return (0); 222 } 223 224 ptcclose(dev) 225 dev_t dev; 226 { 227 register struct tty *tp; 228 229 tp = &pt_tty[minor(dev)]; 230 (void)(*linesw[tp->t_line].l_modem)(tp, 0); 231 tp->t_state &= ~TS_CARR_ON; 232 tp->t_oproc = 0; /* mark closed */ 233 } 234 235 ptcread(dev, uio) 236 dev_t dev; 237 struct uio *uio; 238 { 239 register struct tty *tp = &pt_tty[minor(dev)]; 240 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 241 char buf[BUFSIZ]; 242 int error = 0, cc; 243 244 /* 245 * We want to block until the slave 246 * is open, and there's something to read; 247 * but if we lost the slave or we're NBIO, 248 * then return the appropriate error instead. 249 */ 250 for (;;) { 251 if (tp->t_state&TS_ISOPEN) { 252 if (pti->pt_flags&PF_PKT && pti->pt_send) { 253 error = ureadc((int)pti->pt_send, uio); 254 if (error) 255 return (error); 256 pti->pt_send = 0; 257 return (0); 258 } 259 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 260 error = ureadc((int)pti->pt_ucntl, uio); 261 if (error) 262 return (error); 263 pti->pt_ucntl = 0; 264 return (0); 265 } 266 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 267 break; 268 } 269 if ((tp->t_state&TS_CARR_ON) == 0) 270 return (EIO); 271 if (pti->pt_flags&PF_NBIO) 272 return (EWOULDBLOCK); 273 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); 274 } 275 if (pti->pt_flags & (PF_PKT|PF_UCNTL)) 276 error = ureadc(0, uio); 277 while (uio->uio_resid > 0 && error == 0) { 278 cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); 279 if (cc <= 0) 280 break; 281 error = uiomove(buf, cc, UIO_READ, uio); 282 } 283 if (tp->t_outq.c_cc <= tp->t_lowat) { 284 if (tp->t_state&TS_ASLEEP) { 285 tp->t_state &= ~TS_ASLEEP; 286 wakeup((caddr_t)&tp->t_outq); 287 } 288 if (tp->t_wsel) { 289 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 290 tp->t_wsel = 0; 291 tp->t_state &= ~TS_WCOLL; 292 } 293 } 294 return (error); 295 } 296 297 ptsstop(tp, flush) 298 register struct tty *tp; 299 int flush; 300 { 301 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 302 int flag; 303 304 /* note: FLUSHREAD and FLUSHWRITE already ok */ 305 if (flush == 0) { 306 flush = TIOCPKT_STOP; 307 pti->pt_flags |= PF_STOPPED; 308 } else 309 pti->pt_flags &= ~PF_STOPPED; 310 pti->pt_send |= flush; 311 /* change of perspective */ 312 flag = 0; 313 if (flush & FREAD) 314 flag |= FWRITE; 315 if (flush & FWRITE) 316 flag |= FREAD; 317 ptcwakeup(tp, flag); 318 } 319 320 ptcselect(dev, rw) 321 dev_t dev; 322 int rw; 323 { 324 register struct tty *tp = &pt_tty[minor(dev)]; 325 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 326 struct proc *p; 327 int s; 328 329 if ((tp->t_state&TS_CARR_ON) == 0) 330 return (1); 331 switch (rw) { 332 333 case FREAD: 334 /* 335 * Need to block timeouts (ttrstart). 336 */ 337 s = spltty(); 338 if ((tp->t_state&TS_ISOPEN) && 339 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 340 splx(s); 341 return (1); 342 } 343 splx(s); 344 /* FALLTHROUGH */ 345 346 case 0: /* exceptional */ 347 if ((tp->t_state&TS_ISOPEN) && 348 (pti->pt_flags&PF_PKT && pti->pt_send || 349 pti->pt_flags&PF_UCNTL && pti->pt_ucntl)) 350 return (1); 351 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 352 pti->pt_flags |= PF_RCOLL; 353 else 354 pti->pt_selr = u.u_procp; 355 break; 356 357 358 case FWRITE: 359 if (tp->t_state&TS_ISOPEN) { 360 if (pti->pt_flags & PF_REMOTE) { 361 if (tp->t_canq.c_cc == 0) 362 return (1); 363 } else { 364 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) 365 return (1); 366 if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON)) 367 return (1); 368 } 369 } 370 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 371 pti->pt_flags |= PF_WCOLL; 372 else 373 pti->pt_selw = u.u_procp; 374 break; 375 376 } 377 return (0); 378 } 379 380 ptcwrite(dev, uio) 381 dev_t dev; 382 register struct uio *uio; 383 { 384 register struct tty *tp = &pt_tty[minor(dev)]; 385 register struct iovec *iov; 386 register char *cp; 387 register int cc = 0; 388 char locbuf[BUFSIZ]; 389 int cnt = 0; 390 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 391 int error = 0; 392 393 again: 394 if ((tp->t_state&TS_ISOPEN) == 0) 395 goto block; 396 if (pti->pt_flags & PF_REMOTE) { 397 if (tp->t_canq.c_cc) 398 goto block; 399 while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) { 400 iov = uio->uio_iov; 401 if (iov->iov_len == 0) { 402 uio->uio_iovcnt--; 403 uio->uio_iov++; 404 continue; 405 } 406 if (cc == 0) { 407 cc = MIN(iov->iov_len, BUFSIZ); 408 cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc); 409 cp = locbuf; 410 error = uiomove(cp, cc, UIO_WRITE, uio); 411 if (error) 412 return (error); 413 /* check again for safety */ 414 if ((tp->t_state&TS_ISOPEN) == 0) 415 return (EIO); 416 } 417 if (cc) 418 (void) b_to_q(cp, cc, &tp->t_canq); 419 cc = 0; 420 } 421 (void) putc(0, &tp->t_canq); 422 ttwakeup(tp); 423 wakeup((caddr_t)&tp->t_canq); 424 return (0); 425 } 426 while (uio->uio_iovcnt > 0) { 427 iov = uio->uio_iov; 428 if (cc == 0) { 429 if (iov->iov_len == 0) { 430 uio->uio_iovcnt--; 431 uio->uio_iov++; 432 continue; 433 } 434 cc = MIN(iov->iov_len, BUFSIZ); 435 cp = locbuf; 436 error = uiomove(cp, cc, UIO_WRITE, uio); 437 if (error) 438 return (error); 439 /* check again for safety */ 440 if ((tp->t_state&TS_ISOPEN) == 0) 441 return (EIO); 442 } 443 while (cc > 0) { 444 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 445 (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) { 446 wakeup((caddr_t)&tp->t_rawq); 447 goto block; 448 } 449 (*linesw[tp->t_line].l_rint)(*cp++, tp); 450 cnt++; 451 cc--; 452 } 453 cc = 0; 454 } 455 return (0); 456 block: 457 /* 458 * Come here to wait for slave to open, for space 459 * in outq, or space in rawq. 460 */ 461 if ((tp->t_state&TS_CARR_ON) == 0) 462 return (EIO); 463 if (pti->pt_flags & PF_NBIO) { 464 iov->iov_base -= cc; 465 iov->iov_len += cc; 466 uio->uio_resid += cc; 467 uio->uio_offset -= cc; 468 if (cnt == 0) 469 return (EWOULDBLOCK); 470 return (0); 471 } 472 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); 473 goto again; 474 } 475 476 /*ARGSUSED*/ 477 ptyioctl(dev, cmd, data, flag) 478 caddr_t data; 479 dev_t dev; 480 { 481 register struct tty *tp = &pt_tty[minor(dev)]; 482 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 483 register u_char *cc = tp->t_cc; 484 int stop, error; 485 extern ttyinput(); 486 487 /* 488 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 489 * ttywflush(tp) will hang if there are characters in the outq. 490 */ 491 if (cdevsw[major(dev)].d_open == ptcopen) 492 switch (cmd) { 493 494 case TIOCPKT: 495 if (*(int *)data) { 496 if (pti->pt_flags & PF_UCNTL) 497 return (EINVAL); 498 pti->pt_flags |= PF_PKT; 499 } else 500 pti->pt_flags &= ~PF_PKT; 501 return (0); 502 503 case TIOCUCNTL: 504 if (*(int *)data) { 505 if (pti->pt_flags & PF_PKT) 506 return (EINVAL); 507 pti->pt_flags |= PF_UCNTL; 508 } else 509 pti->pt_flags &= ~PF_UCNTL; 510 return (0); 511 512 case TIOCREMOTE: 513 if (*(int *)data) 514 pti->pt_flags |= PF_REMOTE; 515 else 516 pti->pt_flags &= ~PF_REMOTE; 517 ttyflush(tp, FREAD|FWRITE); 518 return (0); 519 520 case FIONBIO: 521 if (*(int *)data) 522 pti->pt_flags |= PF_NBIO; 523 else 524 pti->pt_flags &= ~PF_NBIO; 525 return (0); 526 527 case TIOCSETP: 528 case TIOCSETN: 529 case TIOCSETD: 530 case TIOCSETA: 531 case TIOCSETAW: 532 case TIOCSETAF: 533 case TIOCSETAS: 534 case TIOCSETAWS: 535 case TIOCSETAFS: 536 while (getc(&tp->t_outq) >= 0) 537 ; 538 break; 539 } 540 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 541 if (error < 0) 542 error = ttioctl(tp, cmd, data, flag); 543 /* 544 * Since we use the tty queues internally, 545 * pty's can't be switched to disciplines which overwrite 546 * the queues. We can't tell anything about the discipline 547 * from here... 548 */ 549 if (linesw[tp->t_line].l_rint != ttyinput) { 550 (*linesw[tp->t_line].l_close)(tp); 551 tp->t_line = 0; 552 (void)(*linesw[tp->t_line].l_open)(dev, tp); 553 error = ENOTTY; 554 } 555 if (error < 0) { 556 if (pti->pt_flags & PF_UCNTL && 557 (cmd & ~0xff) == UIOCCMD(0)) { 558 if (cmd & 0xff) { 559 pti->pt_ucntl = (u_char)cmd; 560 ptcwakeup(tp, FREAD); 561 } 562 return (0); 563 } 564 error = ENOTTY; 565 } 566 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 567 && CCEQ(cc[VSTART], CTRL('q')); 568 if (pti->pt_flags & PF_NOSTOP) { 569 if (stop) { 570 pti->pt_send &= ~TIOCPKT_NOSTOP; 571 pti->pt_send |= TIOCPKT_DOSTOP; 572 pti->pt_flags &= ~PF_NOSTOP; 573 ptcwakeup(tp, FREAD); 574 } 575 } else { 576 if (!stop) { 577 pti->pt_send &= ~TIOCPKT_DOSTOP; 578 pti->pt_send |= TIOCPKT_NOSTOP; 579 pti->pt_flags |= PF_NOSTOP; 580 ptcwakeup(tp, FREAD); 581 } 582 } 583 return (error); 584 } 585 #endif 586