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.12 (Berkeley) 06/05/90 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 if (error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 100 ttopen, 0)) 101 return (error); 102 } 103 error = (*linesw[tp->t_line].l_open)(dev, tp, flag); 104 ptcwakeup(tp, FREAD|FWRITE); 105 return (error); 106 } 107 108 ptsclose(dev) 109 dev_t dev; 110 { 111 register struct tty *tp; 112 113 tp = &pt_tty[minor(dev)]; 114 (*linesw[tp->t_line].l_close)(tp); 115 ttyclose(tp); 116 ptcwakeup(tp, FREAD|FWRITE); 117 } 118 119 ptsread(dev, uio, flag) 120 dev_t dev; 121 struct uio *uio; 122 { 123 register struct tty *tp = &pt_tty[minor(dev)]; 124 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 125 int error = 0; 126 127 again: 128 if (pti->pt_flags & PF_REMOTE) { 129 while (isbackground(u.u_procp, tp)) { 130 if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 131 (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 132 u.u_procp->p_pgrp->pg_jobc == 0 || 133 u.u_procp->p_flag&SVFORK) 134 return (EIO); 135 pgsignal(u.u_procp->p_pgrp, SIGTTIN, 1); 136 if (error = tsleep((caddr_t)&lbolt, TTIPRI | PCATCH, 137 ttybg, 0)) 138 return (error); 139 } 140 if (tp->t_canq.c_cc == 0) { 141 if (flag & IO_NDELAY) 142 return (EWOULDBLOCK); 143 if (error = tsleep((caddr_t)&tp->t_canq, 144 TTIPRI | PCATCH, ttyin, 0)) 145 return (error); 146 goto again; 147 } 148 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) 149 if (ureadc(getc(&tp->t_canq), uio) < 0) { 150 error = EFAULT; 151 break; 152 } 153 if (tp->t_canq.c_cc == 1) 154 (void) getc(&tp->t_canq); 155 if (tp->t_canq.c_cc) 156 return (error); 157 } else 158 if (tp->t_oproc) 159 error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 160 ptcwakeup(tp, FWRITE); 161 return (error); 162 } 163 164 /* 165 * Write to pseudo-tty. 166 * Wakeups of controlling tty will happen 167 * indirectly, when tty driver calls ptsstart. 168 */ 169 ptswrite(dev, uio, flag) 170 dev_t dev; 171 struct uio *uio; 172 { 173 register struct tty *tp; 174 175 tp = &pt_tty[minor(dev)]; 176 if (tp->t_oproc == 0) 177 return (EIO); 178 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 179 } 180 181 /* 182 * Start output on pseudo-tty. 183 * Wake up process selecting or sleeping for input from controlling tty. 184 */ 185 ptsstart(tp) 186 struct tty *tp; 187 { 188 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 189 190 if (tp->t_state & TS_TTSTOP) 191 return; 192 if (pti->pt_flags & PF_STOPPED) { 193 pti->pt_flags &= ~PF_STOPPED; 194 pti->pt_send = TIOCPKT_START; 195 } 196 ptcwakeup(tp, FREAD); 197 } 198 199 ptcwakeup(tp, flag) 200 struct tty *tp; 201 { 202 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 203 204 if (flag & FREAD) { 205 if (pti->pt_selr) { 206 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 207 pti->pt_selr = 0; 208 pti->pt_flags &= ~PF_RCOLL; 209 } 210 wakeup((caddr_t)&tp->t_outq.c_cf); 211 } 212 if (flag & FWRITE) { 213 if (pti->pt_selw) { 214 selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 215 pti->pt_selw = 0; 216 pti->pt_flags &= ~PF_WCOLL; 217 } 218 if (ptydebug) printf("WAKEUP c_cf %d\n", u.u_procp->p_pid); 219 wakeup((caddr_t)&tp->t_rawq.c_cf); 220 } 221 } 222 223 /*ARGSUSED*/ 224 ptcopen(dev, flag) 225 dev_t dev; 226 int flag; 227 { 228 register struct tty *tp; 229 struct pt_ioctl *pti; 230 231 if (minor(dev) >= NPTY) 232 return (ENXIO); 233 tp = &pt_tty[minor(dev)]; 234 if (tp->t_oproc) 235 return (EIO); 236 tp->t_oproc = ptsstart; 237 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 238 tp->t_lflag &= ~EXTPROC; 239 pti = &pt_ioctl[minor(dev)]; 240 pti->pt_flags = 0; 241 pti->pt_send = 0; 242 pti->pt_ucntl = 0; 243 return (0); 244 } 245 246 ptcclose(dev) 247 dev_t dev; 248 { 249 register struct tty *tp; 250 251 tp = &pt_tty[minor(dev)]; 252 (void)(*linesw[tp->t_line].l_modem)(tp, 0); 253 tp->t_state &= ~TS_CARR_ON; 254 tp->t_oproc = 0; /* mark closed */ 255 tp->t_session = 0; 256 } 257 258 ptcread(dev, uio, flag) 259 dev_t dev; 260 struct uio *uio; 261 { 262 register struct tty *tp = &pt_tty[minor(dev)]; 263 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 264 char buf[BUFSIZ]; 265 int error = 0, cc; 266 267 /* 268 * We want to block until the slave 269 * is open, and there's something to read; 270 * but if we lost the slave or we're NBIO, 271 * then return the appropriate error instead. 272 */ 273 for (;;) { 274 if (tp->t_state&TS_ISOPEN) { 275 if (pti->pt_flags&PF_PKT && pti->pt_send) { 276 error = ureadc((int)pti->pt_send, uio); 277 if (error) 278 return (error); 279 if (pti->pt_send & TIOCPKT_IOCTL) { 280 cc = MIN(uio->uio_resid, 281 sizeof(tp->t_termios)); 282 uiomove(&tp->t_termios, cc, uio); 283 } 284 pti->pt_send = 0; 285 return (0); 286 } 287 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 288 error = ureadc((int)pti->pt_ucntl, uio); 289 if (error) 290 return (error); 291 pti->pt_ucntl = 0; 292 return (0); 293 } 294 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 295 break; 296 } 297 if ((tp->t_state&TS_CARR_ON) == 0) 298 return (0); /* EOF */ 299 if (flag & IO_NDELAY) 300 return (EWOULDBLOCK); 301 if (ptydebug) printf("SLEEP(1) c_cf %d\n", u.u_procp->p_pid); /* XXX */ 302 if (error = tsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH, 303 ttyin, 0)) 304 return (error); 305 } 306 if (pti->pt_flags & (PF_PKT|PF_UCNTL)) 307 error = ureadc(0, uio); 308 while (uio->uio_resid > 0 && error == 0) { 309 cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); 310 if (cc <= 0) 311 break; 312 error = uiomove(buf, cc, uio); 313 } 314 if (tp->t_outq.c_cc <= tp->t_lowat) { 315 if (tp->t_state&TS_ASLEEP) { 316 tp->t_state &= ~TS_ASLEEP; 317 wakeup((caddr_t)&tp->t_outq); 318 } 319 if (tp->t_wsel) { 320 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 321 tp->t_wsel = 0; 322 tp->t_state &= ~TS_WCOLL; 323 } 324 } 325 return (error); 326 } 327 328 ptsstop(tp, flush) 329 register struct tty *tp; 330 int flush; 331 { 332 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 333 int flag; 334 335 /* note: FLUSHREAD and FLUSHWRITE already ok */ 336 if (flush == 0) { 337 flush = TIOCPKT_STOP; 338 pti->pt_flags |= PF_STOPPED; 339 } else 340 pti->pt_flags &= ~PF_STOPPED; 341 pti->pt_send |= flush; 342 /* change of perspective */ 343 flag = 0; 344 if (flush & FREAD) 345 flag |= FWRITE; 346 if (flush & FWRITE) 347 flag |= FREAD; 348 ptcwakeup(tp, flag); 349 } 350 351 ptcselect(dev, rw) 352 dev_t dev; 353 int rw; 354 { 355 register struct tty *tp = &pt_tty[minor(dev)]; 356 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 357 struct proc *p; 358 int s; 359 360 if ((tp->t_state&TS_CARR_ON) == 0) 361 return (1); 362 switch (rw) { 363 364 case FREAD: 365 /* 366 * Need to block timeouts (ttrstart). 367 */ 368 s = spltty(); 369 if ((tp->t_state&TS_ISOPEN) && 370 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 371 splx(s); 372 return (1); 373 } 374 splx(s); 375 /* FALLTHROUGH */ 376 377 case 0: /* exceptional */ 378 if ((tp->t_state&TS_ISOPEN) && 379 (pti->pt_flags&PF_PKT && pti->pt_send || 380 pti->pt_flags&PF_UCNTL && pti->pt_ucntl)) 381 return (1); 382 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 383 pti->pt_flags |= PF_RCOLL; 384 else 385 pti->pt_selr = u.u_procp; 386 break; 387 388 389 case FWRITE: 390 if (tp->t_state&TS_ISOPEN) { 391 if (pti->pt_flags & PF_REMOTE) { 392 if (tp->t_canq.c_cc == 0) 393 return (1); 394 } else { 395 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) 396 return (1); 397 if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON)) 398 return (1); 399 } 400 } 401 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 402 pti->pt_flags |= PF_WCOLL; 403 else 404 pti->pt_selw = u.u_procp; 405 break; 406 407 } 408 return (0); 409 } 410 411 ptcwrite(dev, uio, flag) 412 dev_t dev; 413 register struct uio *uio; 414 { 415 register struct tty *tp = &pt_tty[minor(dev)]; 416 register struct iovec *iov; 417 register char *cp; 418 register int cc = 0; 419 char locbuf[BUFSIZ]; 420 int cnt = 0; 421 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 422 int error = 0; 423 424 again: 425 if ((tp->t_state&TS_ISOPEN) == 0) 426 goto block; 427 if (pti->pt_flags & PF_REMOTE) { 428 if (tp->t_canq.c_cc) 429 goto block; 430 while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) { 431 iov = uio->uio_iov; 432 if (iov->iov_len == 0) { 433 uio->uio_iovcnt--; 434 uio->uio_iov++; 435 continue; 436 } 437 if (cc == 0) { 438 cc = MIN(iov->iov_len, BUFSIZ); 439 cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc); 440 cp = locbuf; 441 error = uiomove(cp, cc, uio); 442 if (error) 443 return (error); 444 /* check again for safety */ 445 if ((tp->t_state&TS_ISOPEN) == 0) 446 return (EIO); 447 } 448 if (cc) 449 (void) b_to_q(cp, cc, &tp->t_canq); 450 cc = 0; 451 } 452 (void) putc(0, &tp->t_canq); 453 ttwakeup(tp); 454 wakeup((caddr_t)&tp->t_canq); 455 return (0); 456 } 457 while (uio->uio_iovcnt > 0) { 458 iov = uio->uio_iov; 459 if (cc == 0) { 460 if (iov->iov_len == 0) { 461 uio->uio_iovcnt--; 462 uio->uio_iov++; 463 continue; 464 } 465 cc = MIN(iov->iov_len, BUFSIZ); 466 cp = locbuf; 467 error = uiomove(cp, cc, uio); 468 if (error) 469 return (error); 470 /* check again for safety */ 471 if ((tp->t_state&TS_ISOPEN) == 0) 472 return (EIO); 473 } 474 while (cc > 0) { 475 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 476 (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) { 477 wakeup((caddr_t)&tp->t_rawq); 478 goto block; 479 } 480 (*linesw[tp->t_line].l_rint)(*cp++&0377, tp); 481 cnt++; 482 cc--; 483 } 484 cc = 0; 485 } 486 return (0); 487 block: 488 /* 489 * Come here to wait for slave to open, for space 490 * in outq, or space in rawq. 491 */ 492 if ((tp->t_state&TS_CARR_ON) == 0) 493 return (EIO); 494 if ((pti->pt_flags & PF_NBIO) || (flag & IO_NDELAY)) { 495 iov->iov_base -= cc; 496 iov->iov_len += cc; 497 uio->uio_resid += cc; 498 uio->uio_offset -= cc; 499 if (cnt == 0) 500 return (EWOULDBLOCK); 501 return (0); 502 } 503 if (ptydebug) printf("SLEEP(2) c_cf %d\n", u.u_procp->p_pid); 504 if (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH, 505 ttyout, 0)) 506 return (error); 507 goto again; 508 } 509 510 /*ARGSUSED*/ 511 ptyioctl(dev, cmd, data, flag) 512 caddr_t data; 513 dev_t dev; 514 { 515 register struct tty *tp = &pt_tty[minor(dev)]; 516 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 517 register u_char *cc = tp->t_cc; 518 int stop, error; 519 extern ttyinput(); 520 521 /* 522 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 523 * ttywflush(tp) will hang if there are characters in the outq. 524 */ 525 if (cmd == TIOCEXT) { 526 /* 527 * When the EXTPROC bit is being toggled, we need 528 * to send an TIOCPKT_IOCTL if the packet driver 529 * is turned on. 530 */ 531 if (*(int *)data) { 532 if (pti->pt_flags & PF_PKT) { 533 pti->pt_send |= TIOCPKT_IOCTL; 534 ptcwakeup(tp); 535 } 536 tp->t_lflag |= EXTPROC; 537 } else { 538 if ((tp->t_state & EXTPROC) && 539 (pti->pt_flags & PF_PKT)) { 540 pti->pt_send |= TIOCPKT_IOCTL; 541 ptcwakeup(tp); 542 } 543 tp->t_lflag &= ~EXTPROC; 544 } 545 return(0); 546 } else 547 if (cdevsw[major(dev)].d_open == ptcopen) 548 switch (cmd) { 549 550 case TIOCPKT: 551 if (*(int *)data) { 552 if (pti->pt_flags & PF_UCNTL) 553 return (EINVAL); 554 pti->pt_flags |= PF_PKT; 555 } else 556 pti->pt_flags &= ~PF_PKT; 557 return (0); 558 559 case TIOCUCNTL: 560 if (*(int *)data) { 561 if (pti->pt_flags & PF_PKT) 562 return (EINVAL); 563 pti->pt_flags |= PF_UCNTL; 564 } else 565 pti->pt_flags &= ~PF_UCNTL; 566 return (0); 567 568 case TIOCREMOTE: 569 if (*(int *)data) 570 pti->pt_flags |= PF_REMOTE; 571 else 572 pti->pt_flags &= ~PF_REMOTE; 573 ttyflush(tp, FREAD|FWRITE); 574 return (0); 575 576 case FIONBIO: 577 if (*(int *)data) 578 pti->pt_flags |= PF_NBIO; 579 else 580 pti->pt_flags &= ~PF_NBIO; 581 return (0); 582 583 case TIOCSETP: 584 case TIOCSETN: 585 case TIOCSETD: 586 case TIOCSETA: 587 case TIOCSETAW: 588 case TIOCSETAF: 589 case JUNK_TIOCSETAS: 590 case JUNK_TIOCSETAWS: 591 case JUNK_TIOCSETAFS: 592 while (getc(&tp->t_outq) >= 0) 593 ; 594 break; 595 596 case TIOCSIG: 597 if (*(unsigned int *)data >= NSIG) 598 return(EINVAL); 599 if ((tp->t_lflag&NOFLSH) == 0) 600 ttyflush(tp, FREAD|FWRITE); 601 pgsignal(tp->t_pgrp, *(unsigned int *)data); 602 return(0); 603 } 604 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 605 if (error < 0) 606 error = ttioctl(tp, cmd, data, flag); 607 /* 608 * Since we use the tty queues internally, 609 * pty's can't be switched to disciplines which overwrite 610 * the queues. We can't tell anything about the discipline 611 * from here... 612 */ 613 if (linesw[tp->t_line].l_rint != ttyinput) { 614 (*linesw[tp->t_line].l_close)(tp); 615 tp->t_line = 0; 616 (void)(*linesw[tp->t_line].l_open)(dev, tp, flag); 617 error = ENOTTY; 618 } 619 if (error < 0) { 620 if (pti->pt_flags & PF_UCNTL && 621 (cmd & ~0xff) == UIOCCMD(0)) { 622 if (cmd & 0xff) { 623 pti->pt_ucntl = (u_char)cmd; 624 ptcwakeup(tp, FREAD); 625 } 626 return (0); 627 } 628 error = ENOTTY; 629 } 630 /* 631 * If external processing and packet mode send ioctl packet. 632 */ 633 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) { 634 switch(cmd) { 635 case TIOCSETA: 636 case TIOCSETAW: 637 case TIOCSETAF: 638 case JUNK_TIOCSETAS: 639 case JUNK_TIOCSETAWS: 640 case JUNK_TIOCSETAFS: 641 case TIOCSETP: 642 case TIOCSETN: 643 #ifdef COMPAT_43 644 case TIOCSETC: 645 case TIOCSLTC: 646 case TIOCLBIS: 647 case TIOCLBIC: 648 case TIOCLSET: 649 #endif 650 pti->pt_send |= TIOCPKT_IOCTL; 651 default: 652 break; 653 } 654 } 655 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 656 && CCEQ(cc[VSTART], CTRL('q')); 657 if (pti->pt_flags & PF_NOSTOP) { 658 if (stop) { 659 pti->pt_send &= ~TIOCPKT_NOSTOP; 660 pti->pt_send |= TIOCPKT_DOSTOP; 661 pti->pt_flags &= ~PF_NOSTOP; 662 ptcwakeup(tp, FREAD); 663 } 664 } else { 665 if (!stop) { 666 pti->pt_send &= ~TIOCPKT_DOSTOP; 667 pti->pt_send |= TIOCPKT_NOSTOP; 668 pti->pt_flags |= PF_NOSTOP; 669 ptcwakeup(tp, FREAD); 670 } 671 } 672 return (error); 673 } 674 #endif 675