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.10 (Berkeley) 04/03/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); 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 pti = &pt_ioctl[minor(dev)]; 239 pti->pt_flags = 0; 240 pti->pt_send = 0; 241 pti->pt_ucntl = 0; 242 return (0); 243 } 244 245 ptcclose(dev) 246 dev_t dev; 247 { 248 register struct tty *tp; 249 250 tp = &pt_tty[minor(dev)]; 251 (void)(*linesw[tp->t_line].l_modem)(tp, 0); 252 tp->t_state &= ~TS_CARR_ON; 253 tp->t_oproc = 0; /* mark closed */ 254 tp->t_session = 0; 255 } 256 257 ptcread(dev, uio, flag) 258 dev_t dev; 259 struct uio *uio; 260 { 261 register struct tty *tp = &pt_tty[minor(dev)]; 262 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 263 char buf[BUFSIZ]; 264 int error = 0, cc; 265 266 /* 267 * We want to block until the slave 268 * is open, and there's something to read; 269 * but if we lost the slave or we're NBIO, 270 * then return the appropriate error instead. 271 */ 272 for (;;) { 273 if (tp->t_state&TS_ISOPEN) { 274 if (pti->pt_flags&PF_PKT && pti->pt_send) { 275 error = ureadc((int)pti->pt_send, uio); 276 if (error) 277 return (error); 278 pti->pt_send = 0; 279 return (0); 280 } 281 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) { 282 error = ureadc((int)pti->pt_ucntl, uio); 283 if (error) 284 return (error); 285 pti->pt_ucntl = 0; 286 return (0); 287 } 288 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) 289 break; 290 } 291 if ((tp->t_state&TS_CARR_ON) == 0) 292 return (0); /* EOF */ 293 if (flag & IO_NDELAY) 294 return (EWOULDBLOCK); 295 if (ptydebug) printf("SLEEP(1) c_cf %d\n", u.u_procp->p_pid); /* XXX */ 296 if (error = tsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH, 297 ttyin, 0)) 298 return (error); 299 } 300 if (pti->pt_flags & (PF_PKT|PF_UCNTL)) 301 error = ureadc(0, uio); 302 while (uio->uio_resid > 0 && error == 0) { 303 cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ)); 304 if (cc <= 0) 305 break; 306 error = uiomove(buf, cc, uio); 307 } 308 if (tp->t_outq.c_cc <= tp->t_lowat) { 309 if (tp->t_state&TS_ASLEEP) { 310 tp->t_state &= ~TS_ASLEEP; 311 wakeup((caddr_t)&tp->t_outq); 312 } 313 if (tp->t_wsel) { 314 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 315 tp->t_wsel = 0; 316 tp->t_state &= ~TS_WCOLL; 317 } 318 } 319 return (error); 320 } 321 322 ptsstop(tp, flush) 323 register struct tty *tp; 324 int flush; 325 { 326 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; 327 int flag; 328 329 /* note: FLUSHREAD and FLUSHWRITE already ok */ 330 if (flush == 0) { 331 flush = TIOCPKT_STOP; 332 pti->pt_flags |= PF_STOPPED; 333 } else 334 pti->pt_flags &= ~PF_STOPPED; 335 pti->pt_send |= flush; 336 /* change of perspective */ 337 flag = 0; 338 if (flush & FREAD) 339 flag |= FWRITE; 340 if (flush & FWRITE) 341 flag |= FREAD; 342 ptcwakeup(tp, flag); 343 } 344 345 ptcselect(dev, rw) 346 dev_t dev; 347 int rw; 348 { 349 register struct tty *tp = &pt_tty[minor(dev)]; 350 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 351 struct proc *p; 352 int s; 353 354 if ((tp->t_state&TS_CARR_ON) == 0) 355 return (1); 356 switch (rw) { 357 358 case FREAD: 359 /* 360 * Need to block timeouts (ttrstart). 361 */ 362 s = spltty(); 363 if ((tp->t_state&TS_ISOPEN) && 364 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { 365 splx(s); 366 return (1); 367 } 368 splx(s); 369 /* FALLTHROUGH */ 370 371 case 0: /* exceptional */ 372 if ((tp->t_state&TS_ISOPEN) && 373 (pti->pt_flags&PF_PKT && pti->pt_send || 374 pti->pt_flags&PF_UCNTL && pti->pt_ucntl)) 375 return (1); 376 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) 377 pti->pt_flags |= PF_RCOLL; 378 else 379 pti->pt_selr = u.u_procp; 380 break; 381 382 383 case FWRITE: 384 if (tp->t_state&TS_ISOPEN) { 385 if (pti->pt_flags & PF_REMOTE) { 386 if (tp->t_canq.c_cc == 0) 387 return (1); 388 } else { 389 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2) 390 return (1); 391 if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON)) 392 return (1); 393 } 394 } 395 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) 396 pti->pt_flags |= PF_WCOLL; 397 else 398 pti->pt_selw = u.u_procp; 399 break; 400 401 } 402 return (0); 403 } 404 405 ptcwrite(dev, uio, flag) 406 dev_t dev; 407 register struct uio *uio; 408 { 409 register struct tty *tp = &pt_tty[minor(dev)]; 410 register struct iovec *iov; 411 register char *cp; 412 register int cc = 0; 413 char locbuf[BUFSIZ]; 414 int cnt = 0; 415 struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 416 int error = 0; 417 418 again: 419 if ((tp->t_state&TS_ISOPEN) == 0) 420 goto block; 421 if (pti->pt_flags & PF_REMOTE) { 422 if (tp->t_canq.c_cc) 423 goto block; 424 while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) { 425 iov = uio->uio_iov; 426 if (iov->iov_len == 0) { 427 uio->uio_iovcnt--; 428 uio->uio_iov++; 429 continue; 430 } 431 if (cc == 0) { 432 cc = MIN(iov->iov_len, BUFSIZ); 433 cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc); 434 cp = locbuf; 435 error = uiomove(cp, cc, uio); 436 if (error) 437 return (error); 438 /* check again for safety */ 439 if ((tp->t_state&TS_ISOPEN) == 0) 440 return (EIO); 441 } 442 if (cc) 443 (void) b_to_q(cp, cc, &tp->t_canq); 444 cc = 0; 445 } 446 (void) putc(0, &tp->t_canq); 447 ttwakeup(tp); 448 wakeup((caddr_t)&tp->t_canq); 449 return (0); 450 } 451 while (uio->uio_iovcnt > 0) { 452 iov = uio->uio_iov; 453 if (cc == 0) { 454 if (iov->iov_len == 0) { 455 uio->uio_iovcnt--; 456 uio->uio_iov++; 457 continue; 458 } 459 cc = MIN(iov->iov_len, BUFSIZ); 460 cp = locbuf; 461 error = uiomove(cp, cc, uio); 462 if (error) 463 return (error); 464 /* check again for safety */ 465 if ((tp->t_state&TS_ISOPEN) == 0) 466 return (EIO); 467 } 468 while (cc > 0) { 469 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && 470 (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) { 471 wakeup((caddr_t)&tp->t_rawq); 472 goto block; 473 } 474 (*linesw[tp->t_line].l_rint)(*cp++&0377, tp); 475 cnt++; 476 cc--; 477 } 478 cc = 0; 479 } 480 return (0); 481 block: 482 /* 483 * Come here to wait for slave to open, for space 484 * in outq, or space in rawq. 485 */ 486 if ((tp->t_state&TS_CARR_ON) == 0) 487 return (EIO); 488 if ((pti->pt_flags & PF_NBIO) || (flag & IO_NDELAY)) { 489 iov->iov_base -= cc; 490 iov->iov_len += cc; 491 uio->uio_resid += cc; 492 uio->uio_offset -= cc; 493 if (cnt == 0) 494 return (EWOULDBLOCK); 495 return (0); 496 } 497 if (ptydebug) printf("SLEEP(2) c_cf %d\n", u.u_procp->p_pid); 498 if (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH, 499 ttyout, 0)) 500 return (error); 501 goto again; 502 } 503 504 /*ARGSUSED*/ 505 ptyioctl(dev, cmd, data, flag) 506 caddr_t data; 507 dev_t dev; 508 { 509 register struct tty *tp = &pt_tty[minor(dev)]; 510 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; 511 register u_char *cc = tp->t_cc; 512 int stop, error; 513 extern ttyinput(); 514 515 /* 516 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG. 517 * ttywflush(tp) will hang if there are characters in the outq. 518 */ 519 if (cdevsw[major(dev)].d_open == ptcopen) 520 switch (cmd) { 521 522 case TIOCPKT: 523 if (*(int *)data) { 524 if (pti->pt_flags & PF_UCNTL) 525 return (EINVAL); 526 pti->pt_flags |= PF_PKT; 527 } else 528 pti->pt_flags &= ~PF_PKT; 529 return (0); 530 531 case TIOCUCNTL: 532 if (*(int *)data) { 533 if (pti->pt_flags & PF_PKT) 534 return (EINVAL); 535 pti->pt_flags |= PF_UCNTL; 536 } else 537 pti->pt_flags &= ~PF_UCNTL; 538 return (0); 539 540 case TIOCREMOTE: 541 if (*(int *)data) 542 pti->pt_flags |= PF_REMOTE; 543 else 544 pti->pt_flags &= ~PF_REMOTE; 545 ttyflush(tp, FREAD|FWRITE); 546 return (0); 547 548 case FIONBIO: 549 if (*(int *)data) 550 pti->pt_flags |= PF_NBIO; 551 else 552 pti->pt_flags &= ~PF_NBIO; 553 return (0); 554 555 case TIOCSETP: 556 case TIOCSETN: 557 case TIOCSETD: 558 case TIOCSETA: 559 case TIOCSETAW: 560 case TIOCSETAF: 561 case JUNK_TIOCSETAS: 562 case JUNK_TIOCSETAWS: 563 case JUNK_TIOCSETAFS: 564 while (getc(&tp->t_outq) >= 0) 565 ; 566 break; 567 } 568 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 569 if (error < 0) 570 error = ttioctl(tp, cmd, data, flag); 571 /* 572 * Since we use the tty queues internally, 573 * pty's can't be switched to disciplines which overwrite 574 * the queues. We can't tell anything about the discipline 575 * from here... 576 */ 577 if (linesw[tp->t_line].l_rint != ttyinput) { 578 (*linesw[tp->t_line].l_close)(tp); 579 tp->t_line = 0; 580 (void)(*linesw[tp->t_line].l_open)(dev, tp, flag); 581 error = ENOTTY; 582 } 583 if (error < 0) { 584 if (pti->pt_flags & PF_UCNTL && 585 (cmd & ~0xff) == UIOCCMD(0)) { 586 if (cmd & 0xff) { 587 pti->pt_ucntl = (u_char)cmd; 588 ptcwakeup(tp, FREAD); 589 } 590 return (0); 591 } 592 error = ENOTTY; 593 } 594 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s')) 595 && CCEQ(cc[VSTART], CTRL('q')); 596 if (pti->pt_flags & PF_NOSTOP) { 597 if (stop) { 598 pti->pt_send &= ~TIOCPKT_NOSTOP; 599 pti->pt_send |= TIOCPKT_DOSTOP; 600 pti->pt_flags &= ~PF_NOSTOP; 601 ptcwakeup(tp, FREAD); 602 } 603 } else { 604 if (!stop) { 605 pti->pt_send &= ~TIOCPKT_DOSTOP; 606 pti->pt_send |= TIOCPKT_NOSTOP; 607 pti->pt_flags |= PF_NOSTOP; 608 ptcwakeup(tp, FREAD); 609 } 610 } 611 return (error); 612 } 613 #endif 614