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.13 (Berkeley) 06/26/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 tp->t_state |= TS_WOPEN; 85 ttychars(tp); /* Set up default chars */ 86 tp->t_iflag = TTYDEF_IFLAG; 87 tp->t_oflag = TTYDEF_OFLAG; 88 tp->t_lflag = TTYDEF_LFLAG; 89 tp->t_cflag = TTYDEF_CFLAG; 90 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 91 ttsetwater(tp); /* would be done in xxparam() */ 92 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 93 return (EBUSY); 94 if (tp->t_oproc) /* Ctrlr still around. */ 95 tp->t_state |= TS_CARR_ON; 96 while ((tp->t_state & TS_CARR_ON) == 0) { 97 tp->t_state |= TS_WOPEN; 98 if (flag&FNDELAY) 99 break; 100 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 101 ttopen, 0)) 102 return (error); 103 } 104 error = (*linesw[tp->t_line].l_open)(dev, tp, flag); 105 ptcwakeup(tp, FREAD|FWRITE); 106 return (error); 107 } 108 109 ptsclose(dev) 110 dev_t dev; 111 { 112 register struct tty *tp; 113 114 tp = &pt_tty[minor(dev)]; 115 (*linesw[tp->t_line].l_close)(tp); 116 ttyclose(tp); 117 ptcwakeup(tp, FREAD|FWRITE); 118 } 119 120 ptsread(dev, uio, flag) 121 dev_t dev; 122 struct uio *uio; 123 { 124 register struct tty *tp = &pt_tty[minor(dev)]; 125 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 126 int error = 0; 127 128 again: 129 if (pti->pt_flags & PF_REMOTE) { 130 while (isbackground(u.u_procp, tp)) { 131 if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) || 132 (u.u_procp->p_sigmask & sigmask(SIGTTIN)) || 133 u.u_procp->p_pgrp->pg_jobc == 0 || 134 u.u_procp->p_flag&SVFORK) 135 return (EIO); 136 pgsignal(u.u_procp->p_pgrp, SIGTTIN, 1); 137 if (error = ttysleep(tp, (caddr_t)&lbolt, 138 TTIPRI | PCATCH, ttybg, 0)) 139 return (error); 140 } 141 if (tp->t_canq.c_cc == 0) { 142 if (flag & IO_NDELAY) 143 return (EWOULDBLOCK); 144 if (error = ttysleep(tp, (caddr_t)&tp->t_canq, 145 TTIPRI | PCATCH, ttyin, 0)) 146 return (error); 147 goto again; 148 } 149 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0) 150 if (ureadc(getc(&tp->t_canq), uio) < 0) { 151 error = EFAULT; 152 break; 153 } 154 if (tp->t_canq.c_cc == 1) 155 (void) getc(&tp->t_canq); 156 if (tp->t_canq.c_cc) 157 return (error); 158 } else 159 if (tp->t_oproc) 160 error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 161 ptcwakeup(tp, FWRITE); 162 return (error); 163 } 164 165 /* 166 * Write to pseudo-tty. 167 * Wakeups of controlling tty will happen 168 * indirectly, when tty driver calls ptsstart. 169 */ 170 ptswrite(dev, uio, flag) 171 dev_t dev; 172 struct uio *uio; 173 { 174 register struct tty *tp; 175 176 tp = &pt_tty[minor(dev)]; 177 if (tp->t_oproc == 0) 178 return (EIO); 179 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 180 } 181 182 /* 183 * Start output on pseudo-tty. 184 * Wake up process selecting or sleeping for input from controlling tty. 185 */ 186 ptsstart(tp) 187 struct tty *tp; 188 { 189 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 190 191 if (tp->t_state & TS_TTSTOP) 192 return; 193 if (pti->pt_flags & PF_STOPPED) { 194 pti->pt_flags &= ~PF_STOPPED; 195 pti->pt_send = TIOCPKT_START; 196 } 197 ptcwakeup(tp, FREAD); 198 } 199 200 ptcwakeup(tp, flag) 201 struct tty *tp; 202 { 203 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 204 205 if (flag & FREAD) { 206 if (pti->pt_selr) { 207 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); 208 pti->pt_selr = 0; 209 pti->pt_flags &= ~PF_RCOLL; 210 } 211 wakeup((caddr_t)&tp->t_outq.c_cf); 212 } 213 if (flag & FWRITE) { 214 if (pti->pt_selw) { 215 selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); 216 pti->pt_selw = 0; 217 pti->pt_flags &= ~PF_WCOLL; 218 } 219 if (ptydebug) printf("WAKEUP c_cf %d\n", u.u_procp->p_pid); 220 wakeup((caddr_t)&tp->t_rawq.c_cf); 221 } 222 } 223 224 /*ARGSUSED*/ 225 ptcopen(dev, flag) 226 dev_t dev; 227 int flag; 228 { 229 register struct tty *tp; 230 struct pt_ioctl *pti; 231 232 if (minor(dev) >= NPTY) 233 return (ENXIO); 234 tp = &pt_tty[minor(dev)]; 235 if (tp->t_oproc) 236 return (EIO); 237 tp->t_oproc = ptsstart; 238 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 239 tp->t_lflag &= ~EXTPROC; 240 pti = &pt_ioctl[minor(dev)]; 241 pti->pt_flags = 0; 242 pti->pt_send = 0; 243 pti->pt_ucntl = 0; 244 return (0); 245 } 246 247 ptcclose(dev) 248 dev_t dev; 249 { 250 register struct tty *tp; 251 252 tp = &pt_tty[minor(dev)]; 253 (void)(*linesw[tp->t_line].l_modem)(tp, 0); 254 tp->t_state &= ~TS_CARR_ON; 255 tp->t_oproc = 0; /* mark closed */ 256 tp->t_session = 0; 257 } 258 259 ptcread(dev, uio, flag) 260 dev_t dev; 261 struct uio *uio; 262 { 263 register struct tty *tp = &pt_tty[minor(dev)]; 264 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 265 char buf[BUFSIZ]; 266 int error = 0, cc; 267 268 /* 269 * We want to block until the slave 270 * is open, and there's something to read; 271 * but if we lost the slave or we're NBIO, 272 * then return the appropriate error instead. 273 */ 274 for (;;) { 275 if (tp->t_state&TS_ISOPEN) { 276 if (pti->pt_flags&PF_PKT && pti->pt_send) { 277 error = ureadc((int)pti->pt_send, uio); 278 if (error) 279 return (error); 280 if (pti->pt_send & TIOCPKT_IOCTL) { 281 cc = MIN(uio->uio_resid, 282 sizeof(tp->t_termios)); 283 uiomove(&tp->t_termios, cc, uio); 284 } 285 pti->pt_send = 0; 286 return (0); 287 } 288 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 289 error = ureadc((int)pti->pt_ucntl, uio); 290 if (error) 291 return (error); 292 pti->pt_ucntl = 0; 293 return (0); 294 } 295 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 296 break; 297 } 298 if ((tp->t_state&TS_CARR_ON) == 0) 299 return (0); /* EOF */ 300 if (flag & IO_NDELAY) 301 return (EWOULDBLOCK); 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 (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH, 504 ttyout, 0)) 505 return (error); 506 goto again; 507 } 508 509 /*ARGSUSED*/ 510 ptyioctl(dev, cmd, data, flag) 511 caddr_t data; 512 dev_t dev; 513 { 514 register struct tty *tp = &pt_tty[minor(dev)]; 515 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 516 register u_char *cc = tp->t_cc; 517 int stop, error; 518 extern ttyinput(); 519 520 /* 521 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 522 * ttywflush(tp) will hang if there are characters in the outq. 523 */ 524 if (cmd == TIOCEXT) { 525 /* 526 * When the EXTPROC bit is being toggled, we need 527 * to send an TIOCPKT_IOCTL if the packet driver 528 * is turned on. 529 */ 530 if (*(int *)data) { 531 if (pti->pt_flags & PF_PKT) { 532 pti->pt_send |= TIOCPKT_IOCTL; 533 ptcwakeup(tp); 534 } 535 tp->t_lflag |= EXTPROC; 536 } else { 537 if ((tp->t_state & EXTPROC) && 538 (pti->pt_flags & PF_PKT)) { 539 pti->pt_send |= TIOCPKT_IOCTL; 540 ptcwakeup(tp); 541 } 542 tp->t_lflag &= ~EXTPROC; 543 } 544 return(0); 545 } else 546 if (cdevsw[major(dev)].d_open == ptcopen) 547 switch (cmd) { 548 549 case TIOCPKT: 550 if (*(int *)data) { 551 if (pti->pt_flags & PF_UCNTL) 552 return (EINVAL); 553 pti->pt_flags |= PF_PKT; 554 } else 555 pti->pt_flags &= ~PF_PKT; 556 return (0); 557 558 case TIOCUCNTL: 559 if (*(int *)data) { 560 if (pti->pt_flags & PF_PKT) 561 return (EINVAL); 562 pti->pt_flags |= PF_UCNTL; 563 } else 564 pti->pt_flags &= ~PF_UCNTL; 565 return (0); 566 567 case TIOCREMOTE: 568 if (*(int *)data) 569 pti->pt_flags |= PF_REMOTE; 570 else 571 pti->pt_flags &= ~PF_REMOTE; 572 ttyflush(tp, FREAD|FWRITE); 573 return (0); 574 575 case FIONBIO: 576 if (*(int *)data) 577 pti->pt_flags |= PF_NBIO; 578 else 579 pti->pt_flags &= ~PF_NBIO; 580 return (0); 581 582 case TIOCSETP: 583 case TIOCSETN: 584 case TIOCSETD: 585 case TIOCSETA: 586 case TIOCSETAW: 587 case TIOCSETAF: 588 case JUNK_TIOCSETAS: 589 case JUNK_TIOCSETAWS: 590 case JUNK_TIOCSETAFS: 591 while (getc(&tp->t_outq) >= 0) 592 ; 593 break; 594 595 case TIOCSIG: 596 if (*(unsigned int *)data >= NSIG) 597 return(EINVAL); 598 if ((tp->t_lflag&NOFLSH) == 0) 599 ttyflush(tp, FREAD|FWRITE); 600 pgsignal(tp->t_pgrp, *(unsigned int *)data); 601 return(0); 602 } 603 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 604 if (error < 0) 605 error = ttioctl(tp, cmd, data, flag); 606 /* 607 * Since we use the tty queues internally, 608 * pty's can't be switched to disciplines which overwrite 609 * the queues. We can't tell anything about the discipline 610 * from here... 611 */ 612 if (linesw[tp->t_line].l_rint != ttyinput) { 613 (*linesw[tp->t_line].l_close)(tp); 614 tp->t_line = 0; 615 (void)(*linesw[tp->t_line].l_open)(dev, tp, flag); 616 error = ENOTTY; 617 } 618 if (error < 0) { 619 if (pti->pt_flags & PF_UCNTL && 620 (cmd & ~0xff) == UIOCCMD(0)) { 621 if (cmd & 0xff) { 622 pti->pt_ucntl = (u_char)cmd; 623 ptcwakeup(tp, FREAD); 624 } 625 return (0); 626 } 627 error = ENOTTY; 628 } 629 /* 630 * If external processing and packet mode send ioctl packet. 631 */ 632 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) { 633 switch(cmd) { 634 case TIOCSETA: 635 case TIOCSETAW: 636 case TIOCSETAF: 637 case JUNK_TIOCSETAS: 638 case JUNK_TIOCSETAWS: 639 case JUNK_TIOCSETAFS: 640 case TIOCSETP: 641 case TIOCSETN: 642 #ifdef COMPAT_43 643 case TIOCSETC: 644 case TIOCSLTC: 645 case TIOCLBIS: 646 case TIOCLBIC: 647 case TIOCLSET: 648 #endif 649 pti->pt_send |= TIOCPKT_IOCTL; 650 default: 651 break; 652 } 653 } 654 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 655 && CCEQ(cc[VSTART], CTRL('q')); 656 if (pti->pt_flags & PF_NOSTOP) { 657 if (stop) { 658 pti->pt_send &= ~TIOCPKT_NOSTOP; 659 pti->pt_send |= TIOCPKT_DOSTOP; 660 pti->pt_flags &= ~PF_NOSTOP; 661 ptcwakeup(tp, FREAD); 662 } 663 } else { 664 if (!stop) { 665 pti->pt_send &= ~TIOCPKT_DOSTOP; 666 pti->pt_send |= TIOCPKT_NOSTOP; 667 pti->pt_flags |= PF_NOSTOP; 668 ptcwakeup(tp, FREAD); 669 } 670 } 671 return (error); 672 } 673 #endif 674