1 /* 2 * Copyright (c) 1982 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 6.18 (Berkeley) 01/22/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(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(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) == _IO(u,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 573