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